Adobe Illustrator CC Merge tocando puntos de anclaje

Tengo un archivo vectorial que contiene garabatos, donde las líneas no constan de varios puntos de anclaje, sino que cada segmento es una línea propia.

la linea azul en el centro de la imagen es un elemento propio por si mismo

Necesito conectar estas pequeñas líneas separadas para formar líneas individuales que contengan múltiples puntos de anclaje como suele ser. El problema es que hay demasiadas líneas en el archivo para conectarlas manualmente y la función "unir" siempre conecta líneas que no deberían estar conectadas.

¿Existe una secuencia de comandos que solo conecta líneas/puntos de anclaje que se encuentran exactamente en el mismo lugar en Illustrator?

Iba a hacer la misma pregunta... No puedo encontrar la respuesta en línea.

Respuestas (2)

UNIR RUTAS CON PUNTOS SUPERPUESTOS

Este script se actualizó el 7 de febrero de 2017 con algunas características nuevas.

Características:

  1. Se eliminan los puntos perdidos.
  2. Los puntos de división dentro de las rutas se fusionan.
  3. Los caminos abiertos con puntos superpuestos se unen.

Solo las rutas seleccionadas se ven afectadas.
Los grupos son compatibles, las rutas compuestas no lo son.
Para rutas superpuestas se aplica una tolerancia de superposición.

Cómo utilizar:

  • Copie el código siguiente en un editor de texto y guárdelo como un archivo .js (por ejemplo, join_paths_with_overlapping_points.js ).
  • En Illustrator, seleccione las rutas (o grupos) que desea limpiar.
  • Seleccione Archivo/Scripts/Otros scripts y abra el script.
  • Siga las instrucciones.

// JOIN PATHS WITH OVERLAPPING POINTS
// Copyright (c) 2017 Mads Wolff
// This script is distributed under the MIT License.

#target illustrator

alert((function () {

  alert(
    "JOIN PATHS WITH OVERLAPPING POINTS\n" +
    "Copyright (c) 2017 Mads Wolff\n" +
    "This script is distributed under the MIT License.\n" +
    "Use at your own risk.\n\n\n" +
    "FEATURES:\n\n" +
    "1. Stray points are removed.\n" +
    "2. Split points within paths are merged.\n" +
    "3. Open paths with overlapping points are joined.\n\n" +
    "Only selected paths are affected.\n" +
    "Groups are supported, compound paths are not.\n" +
    "For overlapping paths an overlap tolerance applies.\n\n\n" +
    "HOW TO USE:\n\n" +
    "Press OK, select an overlap tolerance (in points),\n" +
    "press OK again (or CANCEL).\n"
  );

  // ---

  var doc = app.activeDocument;

  // ---

  if (doc.selection.length === 0) return "JOIN PATHS WITH OVERLAPPING POINTS\n\nABORT: There is no selection.";
  var tolerance = prompt("JOIN PATHS WITH OVERLAPPING POINTS\n\nEnter overlap tolerance (in points):", 0);
  if (tolerance === null) return "JOIN PATHS WITH OVERLAPPING POINTS\n\nABORT: Script execution cancelled.";
  if (!(tolerance >= 0)) return "JOIN PATHS WITH OVERLAPPING POINTS\n\nABORT: The overlap tolerance must be a number of points equal to or larger than 0.";

  // ---

  var numberOfPoints = 0;
  var numberOfStrayPoints = 0;
  var numberOfOpenPaths = 0;
  var numberOfClosedPaths = 0;
  var numberOfSplitPointsMerged = 0;
  var numberOfOverlappingPathsJoined = 0;
  var numberOfResultingPaths = 0;

  // ---

  function execute(itemList) {

    itemList = Array.prototype.slice.call(itemList);

    var items = [];
    var overlapClusters = [];

    for (var i = 0; i < itemList.length; i++) {
      var item = itemList[i];
      if (item.typename === "GroupItem") {
        execute(item.pageItems);
      } else if (item.typename === "PathItem") {
        if (item.pathPoints.length > 1) {
          var points = Array.prototype.slice.call(item.pathPoints);
          for (var j = 0; j < points.length; j++) {
            var point = points[j];
            var nextPoint = points[j + ((!item.closed || (j + 1 < points.length)) ? 1 : 1 - points.length)];
            if (nextPoint) {
              if (
                point.anchor[0] === nextPoint.anchor[0] &&
                point.anchor[1] === nextPoint.anchor[1] &&
                point.rightDirection[0] === point.anchor[0] &&
                point.rightDirection[1] === point.anchor[1] &&
                nextPoint.leftDirection[0] === point.anchor[0] &&
                nextPoint.leftDirection[1] === point.anchor[1]
              ) {
                nextPoint.leftDirection = point.leftDirection;
                point.remove();
                numberOfSplitPointsMerged++;
              }
            }
            numberOfPoints++;
          }
        }
        if (item.pathPoints.length === 1) {
          item.remove();
          numberOfStrayPoints++;
          numberOfOpenPaths++;
        } else if (!item.closed) {
          items.push(item);
          numberOfOpenPaths++;
        } else {
          numberOfClosedPaths++;
        }
      }
    }

    numberOfOpenPaths += items.length;

    for (var i = 0; i < items.length; i++) {
      var itemA = items[i];
      var pointsA = itemA.pathPoints;
      for (var j = 0; j < pointsA.length; j++) {
        var pointA = pointsA[j];
        for (var k = i + 1; k < items.length; k++) {
          var itemB = items[k];
          var pointsB = itemB.pathPoints;
          for (var l = 0; l < pointsB.length; l++) {
            var pointB = pointsB[l];
            var overlap = tolerance === 0 ?
              (pointA.anchor[0] === pointB.anchor[0] && pointA.anchor[1] === pointB.anchor[1]) :
              (tolerance >= Math.sqrt(Math.pow(pointA.anchor[0] - pointB.anchor[0], 2) + Math.pow(pointA.anchor[1] - pointB.anchor[1], 2)));
            if (overlap) {
              if (tolerance > 0) {
                var d0 = (pointA.anchor[0] - pointB.anchor[0]) / 2;
                var d1 = (pointA.anchor[1] - pointB.anchor[1]) / 2;
                pointA.anchor = [pointA.anchor[0] - d0, pointA.anchor[1] - d1];
                pointA.leftDirection = [pointA.leftDirection[0] - d0, pointA.leftDirection[1] - d1];
                pointA.rightDirection = [pointA.rightDirection[0] - d0, pointA.rightDirection[1] - d1];
                pointB.anchor = [pointB.anchor[0] + d0, pointB.anchor[1] + d1];
                pointB.leftDirection = [pointB.leftDirection[0] + d0, pointB.leftDirection[1] + d1];
                pointB.rightDirection = [pointB.rightDirection[0] + d0, pointB.rightDirection[1] + d1];
              }
              if (itemA.overlapCluster === undefined) {
                if (itemB.overlapCluster === undefined) {
                  itemA.overlapCluster = [];
                  itemB.overlapCluster = itemA.overlapCluster;
                  itemA.overlapCluster.push(itemA);
                  itemA.overlapCluster.push(itemB);
                  overlapClusters.push(itemA.overlapCluster);
                } else {
                  itemA.overlapCluster = itemB.overlapCluster;
                  itemA.overlapCluster.push(itemA);
                }
              } else {
                itemB.overlapCluster = itemA.overlapCluster;
                itemA.overlapCluster.push(itemB);
              }
            }
          }
        }
      }
    }

    for (var i = 0; i < overlapClusters.length; i++) {
      var overlapCluster = overlapClusters[i];
      doc.selection = overlapCluster;
      numberOfOverlappingPathsJoined += doc.selection.length;
      numberOfResultingPaths++;
      app.executeMenuCommand("join");
      var joinedItem = doc.selection[0];
      delete joinedItem.overlapCluster;
    }

  }

  // ---

  execute(doc.selection);

  // ---

  doc.selection = [];

  // ---

  return "JOIN PATHS WITH OVERLAPPING POINTS\n\n" +
    numberOfPoints + " points in " + (numberOfOpenPaths + numberOfClosedPaths) + " paths ("+ numberOfOpenPaths +" open and " + numberOfClosedPaths + " closed) were processed.\n\n" +
    numberOfStrayPoints + " stray points were removed.\n" +
    numberOfSplitPointsMerged + " split points were merged.\n" +
    numberOfOverlappingPathsJoined + " paths with overlapping points were joined to " + numberOfResultingPaths + " paths.";

})());
¿Cómo uso esto en Illustrator? ¿Tengo que copiarlo y pegarlo o guardarlo como un archivo?
@Micro máquina. En realidad, debe copiarlo en un editor de texto y guardarlo como un archivo .js. Luego puede seleccionar sus rutas y ejecutar el script en Archivo/Scripts/Otro script (ctrl+f12).
Entonces, la secuencia de comandos funcionó para unir rutas con puntos de anclaje finales y iniciales superpuestos, pero no pude unir puntos de anclaje superpuestos que pertenecen a la misma curva con la secuencia de comandos, por ejemplo: imgur.com/a/mjXBZ
@MicroMachine hay una secuencia de comandos "Fusionar anclas superpuestas" (¡y muchas otras útiles!) en este paquete de secuencias de comandos que fusionarán anclas en la misma ruta.
@Micro máquina. No implementé esa característica porque no era parte de la pregunta. Martin solicitó un script que pudiera unir líneas individuales a rutas conectadas, no eliminar puntos duplicados. ¿Mi solución o la solución de Silly-V no responde la pregunta?
@Micro máquina. Veré si puedo implementar fácilmente la función "combinar anclas superpuestas". Tal vez también lo cambie para que los puntos que casi se superponen se muevan al punto medio entre ellos en lugar de simplemente conectarlos (como lo hace ahora la unión ).
@Micro máquina. Echa un vistazo a la nueva versión. ¿Esto hace el truco?
@MadsWolff ¡Es perfecto, en lo que a mí respecta! ¡Gran trabajo, gracias!
He seguido las instrucciones para la respuesta aprobada anterior y no importa cuántos puntos selecciono, se congela el ilustrador. ¿Hay una versión actualizada de esto para Illustrator CC en 2022?
@samseurynck, hizo una prueba rápida del script en Illustrator 2022 y parece funcionar según lo previsto. Debes estar haciendo algo que el guión no tiene en cuenta. Difícil saber qué es. Intente hacer un documento realmente simple con algunas rutas y vea si funciona.
@samseurynck, y verifique dos veces que haya copiado todo el script y no haya dejado por accidente algunos caracteres o haya incluido algo más de la respuesta además del código.

Pruebe este script, funciona uniendo rutas desde el punto final hasta el punto inicial, pero no con rutas que tienen los mismos puntos inicial y final. Sin embargo, debido a que unir rutas cambia el recuento de rutas porque fusiona dos rutas en una, los puntos de inicio/fin están sujetos a cambios durante este algoritmo de "conexión de puntos".

#target illustrator
function test(){
  function overlapPointExists(){
    var doc = app.activeDocument, thisPath, firstPt, lastPt, nextPath, firstPt_2, lastPt_2;
    for(var i=0; i < doc.pathItems.length; i++){
      thisPath = doc.pathItems[i];
      if(!thisPath.closed){
        firstPt = thisPath.pathPoints[0];
        lastPt = thisPath.pathPoints[thisPath.pathPoints.length - 1];
        for(var j=0; j < doc.pathItems.length; j++){
          if(i != j){
            nextPath = doc.pathItems[j];
            firstPt_2 = nextPath.pathPoints[0];
            lastPt_2 = nextPath.pathPoints[nextPath.pathPoints.length - 1];
            if(lastPt.anchor[0] == firstPt_2.anchor[0] && lastPt.anchor[1] == firstPt_2.anchor[1]){
              lastPt.selected = PathPointSelection.ANCHORPOINT;
              firstPt_2.selected = PathPointSelection.ANCHORPOINT;
              return true;
            }
          }
        };
      }
    };
    doc.selection = null;
    return false;
  };
  while(overlapPointExists()){
    app.executeMenuCommand("join");
    app.activeDocument.selection = null;
  }
  app.activeDocument.selection = null;
};
test();

ingrese la descripción de la imagen aquí

EDITAR : la secuencia de comandos era demasiado lenta cuando no había solo algunas rutas en el documento. Así que aquí hay uno que funcionará en función de una selección de rutas. Funciona seleccionando rutas separadas y desagrupadas al principio, luego las agrupa en un grupo temporal (el orden de apilamiento puede cambiar si los elementos no están en orden consecutivo) y usa ese grupo como un contenedor de aislamiento para actuar solo en los caminos del mismo. Después de que se ejecuta, el grupo se desagrupa y un cuadro de alerta le indica cuánto tiempo tomó todo. Comente o elimine esta alerta cuando se vuelva molesta.

#target illustrator
function test(){
  function overlapPointExists(pathCollection){
    var doc = app.activeDocument, thisPath, firstPt, lastPt, nextPath, firstPt_2, lastPt_2;
    for(var i=0; i < pathCollection.pathItems.length; i++){
      thisPath = pathCollection.pathItems[i];
      if(!thisPath.closed){
        firstPt = thisPath.pathPoints[0];
        lastPt = thisPath.pathPoints[thisPath.pathPoints.length - 1];
        for(var j=0; j < pathCollection.pathItems.length; j++){
          if(i != j){
            nextPath = pathCollection.pathItems[j];
            firstPt_2 = nextPath.pathPoints[0];
            lastPt_2 = nextPath.pathPoints[nextPath.pathPoints.length - 1];
            if(lastPt.anchor[0] == firstPt_2.anchor[0] && lastPt.anchor[1] == firstPt_2.anchor[1]){
              lastPt.selected = PathPointSelection.ANCHORPOINT;
              firstPt_2.selected = PathPointSelection.ANCHORPOINT;
              return true;
            }
          }
        };
      } else {
        return false;
      }
    };
    doc.selection = null;
    return false;
  };
  if(app.activeDocument.selection == null || app.activeDocument.selection.length == 0){
    alert("Please select something first.");
    return;
  }
  var doc = app.activeDocument;
  var start = (new Date().getTime());
  var sel = doc.selection;
  app.executeMenuCommand("group");
  var pathGroup = sel[0].parent;
  pathGroup.selected = false;

  while(overlapPointExists(pathGroup)){
    app.redraw();
    app.executeMenuCommand("join");
    doc.selection = null;
  }
  pathGroup.selected = true;
  app.executeMenuCommand("ungroup");
  doc.selection = null;
  var end = (new Date().getTime());
  alert("Process took " + (end - start) / 1000 + " seconds.");
};
test();
Aunque puede tomar un tiempo: en mi máquina Win7 con solo 82 rutas, "no respondió" durante aproximadamente 20 segundos antes de volver a la vida con todas las rutas unidas.