Skip to content

Instantly share code, notes, and snippets.

@shspage
Forked from moluapple/find visual center.jsx
Last active May 18, 2016 13:50
Show Gist options
  • Save shspage/daf5b265a01b97171aa3f8f83c2c2ada to your computer and use it in GitHub Desktop.
Save shspage/daf5b265a01b97171aa3f8f83c2c2ada to your computer and use it in GitHub Desktop.
[Illustrator] 寻找不规则形状中心点(find visual center of an irregularly shaped polygon with Illustrator)
(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;
};
}
})();
@moluapple
Copy link

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