-
-
Save shspage/daf5b265a01b97171aa3f8f83c2c2ada to your computer and use it in GitHub Desktop.
[Illustrator] 寻找不规则形状中心点(find visual center of an irregularly shaped polygon with Illustrator)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
var doc = app.activeDocument, | |
lays = doc.layers, | |
WORK_LAY = lays.add(), | |
NUM_LAY = lays.add(), | |
i = lays.length - 1, | |
lay; | |
// main working loop | |
for (; i > 1; i--) { | |
//process each layer | |
lay = lays[i]; | |
lay.name = lay.name + " Num:" + (i - 1); // i-1 as 2 layers beed added. | |
process(lay.pathItems, false); | |
process(lay.compoundPathItems, true); // if any | |
} | |
//clean up | |
NUM_LAY.name = "Numbers"; | |
WORK_LAY.remove(); | |
function process(items, isCompound) { | |
var j = 0, | |
b, xy, p, op; | |
for (; j < items.length; j++) { | |
// process each pathItem | |
op = items[j]; | |
// add stroke | |
if (isCompound) { | |
strokeComPath(op); | |
} else { | |
!op.closed && op.closed = true; | |
op.filled = false; | |
op.stroked = true; | |
}; | |
b = getCenterBounds(op); | |
xy = getMinVisibleSize(b) > 20 ? // two or more visual center exists, as the bounds width is too big | |
[b[0] + 2, b[1] - 2] : // use the top left position with a little adjust | |
[b[0] + (b[2] - b[0]) / 2, b[1] + (b[3] - b[1]) / 2]; | |
add_nums(i - 1, xy); | |
} | |
} | |
function getMinVisibleSize(b){ | |
var s = Math.min(b[2] - b[0], b[1] - b[3]); | |
return Math.abs(s); | |
} | |
function getGeometricCenter(p){ | |
var b = p.geometricBounds; | |
return [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2]; | |
} | |
// returns square of distance between p1 and p2 | |
function getDist2(p1, p2){ | |
return Math.pow(p1[0] + p2[0], 2) + Math.pow(p1[1] + p2[1], 2); | |
} | |
// returns visibleBounds of a path in a compoundPath p | |
// which is closest to center of the original path op | |
function findBestBounds(op, p){ | |
var opc = getGeometricCenter(op); | |
var idx = 0, d; | |
var minD = getDist2(opc, getGeometricCenter(p.pathItems[0])); | |
for(var i = 0, iEnd = p.pathItems.length; i < iEnd; i++){ | |
d = getDist2(opc, getGeometricCenter(p.pathItems[i])); | |
if(d < minD){ | |
minD = d; | |
idx = i; | |
} | |
} | |
return p.pathItems[idx].visibleBounds; | |
} | |
function applyOffset(op, checkBounds){ | |
var p = op.duplicate(WORK_LAY, ElementPlacement.PLACEATBEGINNING); | |
var offset = Math.min(p.width, p.height) / 10 > 1 ? 1 : 0.5, | |
xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>' | |
.replace('#offset', '-' + offset), | |
TIMES = 50; // if shapes are too large, should increase times to 100 or even bigger. | |
if(checkBounds){ | |
// check its size only if it needs, because it's too slow | |
while (TIMES-- && getMinVisibleSize(p.visibleBounds) > 3) p.applyEffect(xmlstring); | |
} else { | |
while (TIMES--) p.applyEffect(xmlstring); | |
} | |
return p; | |
} | |
function getCenterBounds(op) { | |
var originalMinSize = getMinVisibleSize(op.visibleBounds); | |
var p = applyOffset(op, false); | |
if(getMinVisibleSize(p.visibleBounds) > originalMinSize){ | |
// in some cases, path p becomes larger for some unknown reason | |
p.remove(); | |
p = applyOffset(op, true); | |
} | |
var b = p.visibleBounds; | |
if(getMinVisibleSize(b) > 20){ | |
activeDocument.selection = [p]; | |
executeMenuCommand("expandStyle"); | |
p = activeDocument.selection[0]; | |
if(p.typename == "CompoundPathItem"){ | |
b = findBestBounds(op, p); | |
} | |
} | |
p.remove(); | |
return b; | |
} | |
function add_nums(n, xy) { | |
var txt = NUM_LAY.textFrames.add(); | |
txt.contents = n; | |
txt.textRange.justification = Justification.CENTER; | |
txt.textRange.characterAttributes.size = 6; | |
txt.position = [xy[0] - txt.width / 2, xy[1] + txt.height / 2]; | |
} | |
function strokeComPath(compoundPath) { | |
var p = compoundPath.pathItems, | |
l = p.length, | |
i = 0; | |
for (; i < l; i++) { | |
!p[i].closed && p[i].closed = true; | |
p[i].stroked = true; | |
p[i].filled = false; | |
}; | |
} | |
})(); |
I see. I didn't know that topic! Very interesting discussion.
If "more speed" is what they are concerned with, "more simple" way (= your Gist) may be better, even if it (rarely) produces minor errors.
There may be a pure Mathematical solution, but it's too complex for me to implement.
I tried adding some simple modifications to jsclipper, but I couldn't include it in Illustrator script for now.
At least it seems that its manipulation is based on polygons, not bezier curves.
So you must convert curves into polygons before you use its function.
It will take much time.
Got it. Thank you for taking your time and the detailed explanation.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello,
One more question: as this problem comes from a forum question, and some of us wonder there must be a prue Mathematical solution. Do you think that's possible? or maybe you can port some exists library to Illustrator as you have done with Delaunay diagrams?
here are 2 links I have searched:1, 2