Last active
September 17, 2023 06:16
-
-
Save moluapple/94aaf66070f618641a8a4d34bfb8d4bf 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, s, 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 = [b[0] + (b[2] - b[0]) / 2, b[1] + (b[3] - b[1]) / 2]; | |
s = ( | |
Math.min(op.height, op.width) < 20 || | |
(op.area && Math.abs(op.area) < 150) | |
) ? 4 : 6; // adjust font size for small area paths. | |
add_nums(i - 1, xy, s); | |
} | |
} | |
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), | |
// offset value the small the better, but meantime more slow. | |
offset = function() { | |
var minsize = Math.min(p.width, p.height); | |
if (minsize >= 50) { | |
return '-1' | |
} else if (20 < minsize && minsize < 50) { | |
return '-0.5' | |
} else { | |
return '-0.2' // 0.2 * 2 (both side ) * 50 (Times) = 20 | |
} | |
}, | |
xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>' | |
.replace('#offset', offset()), | |
TIMES = 100; // if shapes are too large, should increase the value. | |
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) > 10) { | |
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, s) { | |
var txt = NUM_LAY.textFrames.add(); | |
txt.contents = n; | |
txt.textRange.justification = Justification.CENTER; | |
txt.textRange.characterAttributes.size = s; | |
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; | |
}; | |
} | |
})(); |
Many thanks to you, Hiroyuki Sato. I've integrate your code, and adjust some setting values to get better result.
Thank you for taking your time to integrate!
@shspage hello, I tried it but lay.pathItems.length is always 0, why?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello,
Very interesting and useful! I was impressed with the way to use LiveEffect in a script. It's so smart.
But I found 2 issues.
Though these may not be problems in your usage, I tried fixing this. I'll be happy if you integrate it.