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.
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?
Este script se actualizó el 7 de febrero de 2017 con algunas características nuevas.
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.
// 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.";
})());
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();
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();
Micro máquina