Skip to content

Instantly share code, notes, and snippets.

@shspage
Created August 2, 2018 13:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shspage/646954cbd4af0f3ac9e9fe1d3607b90b to your computer and use it in GitHub Desktop.
Save shspage/646954cbd4af0f3ac9e9fe1d3607b90b to your computer and use it in GitHub Desktop.
Illustrator script : Round Any Corner (for Open Path)

最新のイラレはコーナーウィジェットという便利な機能がありますが、色々な事情でまだ古いバージョンを使っている方には、まだ拙作の角を丸めるスクリプト(角を丸くするplus, Round Any Corner)を使って頂いているらしいのです。

先日頂いたメールで、その方はカッティングマシーン用のデータをイラレで作っていて、その用途のために意図的に図形の角の部分でパスを切っているとのこと。そうするとその「角」はスクリプトが丸める処理対象にならず、丸まらないので困っているとか。なので、そういう「角」も丸めるためのバージョンを作りました。

方法としては、処理するパスをいったんクローズパスに変えて、丸めたあとでオープンパスに戻すということをしています。

  • スクリプトの最初の FORCE_TREAT_AS_CLOSED_PATHfalse にすると従来の挙動になります。
  • FORCE_TREAT_AS_CLOSED_PATH_ONLY_IF_START_AND_END_POINT_CLOSE_ENOUGHtrue にすると、パスの始点と終点の距離が MIN_DIST 以内の場合のみ、始点と終点を繋いだ角も丸めます。デフォルトは false にしてあるので、始点と終点が離れたオープンパスを処理するとおかしなことになります。

通常版と説明はここにあります。http://shspage.com/aijs/#maruplus

// Round Any Corner (for Open Path)
// rounds selected corners of PathItems.
// Especially for the corners at the intersection point of curves,
// this script may work better than "Round Corners" filter (but slower).
// ## How To Use
// 1. Select the anchor(s) or whole path(s) to round.
// 2. Run this script. Adjust the values in the dialog.
// Then click OK.
// ## Rounding Method
// Basically, the rounding method is compatible with the "Round Corners" filter.
// It is to add two anchors instead of the original anchor, at the points of
// specified line length from each selected corner. So if there're too many
// anchors on original path, this script can not round nicely.
// ## Radius
// Actually, the specified "radius" is not for a radius of arcs which drawn.
// It is for the line length from each selected corner and is for the base
// to compute the length of handles. The reason calling it "radius" is
// for compatibility with the "Round Corners" filter.
// ## Max TextBox
// You can change the max value of the slider by the the "max" textbox.
// Input the value and click "apply".
// Inputed number of digits after decimal point is reflected to the slider value.
// If the max value is "10.00", you can set the value like 8.23 with the slider.
// If it is "10", you can set the value as integer.
// This script does not round the corners which already rounded.
// (for example, select a circle and run this script does nothing)
// ### notice
// In the rounding process, the script merges anchors which nearly
// overlapped (when the distance between anchors is less than 0.05 points).
// This script does not work for some part of compound paths.
// When this occurs, please select part of the compound path or release the compound path and
// select them, then run script again.
// I still have not figured out how to get properties from grouped paths inside a compound path.
// If you prefer the slider interface of the previous version,
// uncomment the lines which marked as "uncomment to use slider-version".
// test env: Adobe Illustrator CC (Win)
// Copyright(c) 2005 Hiroyuki Sato
// https://github.com/shspage
// This script is distributed under the MIT License.
// See the LICENSE file for details.
// 2018.07.20, modified to ignore locked/hidden objects in a selected group
// 2018.08.01, modified to round open paths
var FORCE_TREAT_AS_CLOSED_PATH = true;
// ...CLOSE_ENOUGH means "distance <= MIN_DIST"
var FORCE_TREAT_AS_CLOSED_PATH_ONLY_IF_START_AND_END_POINT_CLOSE_ENOUGH = false;
var MIN_DIST = 1.0; // point
main();
function main(){
// setting ----------------------------------------------
// -- rr : rounding radius ( unit : point )
// ------------------------------------------------------
var conf = {
rr : 5,
maxSliderValue : "100",
unit : "pt",
errmsg : ""
}
var paths = [];
getPathItemsInSelection(1, paths); // extract pathItems which pathpoints length is greater than 1
if(paths.length < 1) return;
var selectedSpec = getSelectedSpec(paths);
var previewed = false;
var clearPreview = function(){
if(previewed){
undo();
redraw();
previewed = false;
applySelectedSpec( paths, selectedSpec );
}
}
var drawPreview = function(){
if( conf.rr > 0){
roundAnyCorner( paths, conf );
previewed = true;
}
}
var getRoundDigit = function( s ){
var n = 0;
if(s.indexOf(".") >= 0){
n = s.replace(/^[^\.]+\./, "").length;
}
return n;
}
if( conf.rr > conf.maxSliderValue ) conf.rr = conf.maxSliderValue;
var round_digit = getRoundDigit( conf.maxSliderValue );
// show a dialog
var win = new Window("dialog", "Round Any Corner" );
win.alignChildren = "fill";
win.sliderPanel = win.add("panel", undefined, "radius");
win.sliderPanel.orientation = "column";
win.sliderPanel.alignChildren = "fill";
win.sliderPanel.gp1 = win.sliderPanel.add("group");
/* // uncomment to use slider-version
win.sliderPanel.gp1.radiusSlider = win.sliderPanel.gp1.add("slider", undefined, conf.rr, 0, conf.maxSliderValue);
win.sliderPanel.gp1.radiusSlider.size = [180, 20];
*/
win.sliderPanel.gp1.txtBox = win.sliderPanel.gp1.add("edittext", undefined, conf.rr);
win.sliderPanel.gp1.txtBox.justify = "right";
win.sliderPanel.gp1.txtBox.characters = 8;
/* // uncomment to use slider-version
win.sliderPanel.gp1.txtBox.characters = 5;
*/
win.sliderPanel.gp1.txtBox.helpTip = "hit TAB to set the input value temporarily";
/* // uncomment to use slider-version
win.sliderPanel.gp2 = win.sliderPanel.add("group");
win.sliderPanel.gp2.alignment = "right";
win.sliderPanel.gp2.maxValueCaptionText = win.sliderPanel.gp2.add("statictext", undefined, "max");
win.sliderPanel.gp2.maxValueTextBox = win.sliderPanel.gp2.add("edittext", undefined, conf.maxSliderValue);
win.sliderPanel.gp2.maxValueTextBox.characters = 6;
win.sliderPanel.gp2.maxValueTextBox.justify = "right";
win.sliderPanel.gp2.applyMaxValueButton = win.sliderPanel.gp2.add("button", undefined, "apply");
win.sliderPanel.gp2.applyMaxValueButton.size = [60, 24];
*/
win.unitRadioPanel = win.add("panel", undefined, "unit" );
win.unitRadioPanel.orientation = "row";
win.sliderPanel.alignChildren = "fill";
win.unitRadioPanel.ptRb = win.unitRadioPanel.add("radiobutton", undefined, "pt/px");
win.unitRadioPanel.mmRb = win.unitRadioPanel.add("radiobutton", undefined, "mm");
win.unitRadioPanel.inchRb = win.unitRadioPanel.add("radiobutton", undefined, "inch");
win.chkGroup = win.add("group");
win.chkGroup.alignment = "center";
win.chkGroup.previewChk = win.chkGroup.add("checkbox", undefined, "preview");
win.btnGroup = win.add("group", undefined );
win.btnGroup.alignment = "center";
win.btnGroup.okBtn = win.btnGroup.add("button", undefined, "OK");
win.btnGroup.cancelBtn = win.btnGroup.add("button", undefined, "Cancel");
if( conf.unit == "mm" ){
win.unitRadioPanel.mmRb.value = true;
} else if( conf.unit == "inch"){
win.unitRadioPanel.inchRb.value = true;
} else {
win.unitRadioPanel.ptRb.value = true;
conf.unit = "pt";
}
var getValues = function(){
conf.rr = win.sliderPanel.gp1.txtBox.text;
if(win.unitRadioPanel.mmRb.value){
conf.rr = convertUnit(win.sliderPanel.gp1.txtBox.text, "mm", "pt");
} else if(win.unitRadioPanel.inchRb.value){
conf.rr = convertUnit(win.sliderPanel.gp1.txtBox.text, "inch", "pt");
}
}
var processPreview = function( is_preview ){
if( ! is_preview || win.chkGroup.previewChk.value){
try{
win.enabled = false;
getValues();
clearPreview();
drawPreview();
if( is_preview ) redraw();
} catch(e){
alert(e);
} finally{
win.enabled = true;
}
}
}
/* // uncomment to use slider-version
win.sliderPanel.gp2.applyMaxValueButton.onClick = function(){
try{
win.enabled = false;
var mv = win.sliderPanel.gp2.maxValueTextBox.text.replace(/[^0-9\.]/g ,"");
with(win.sliderPanel.gp1.radiusSlider){
if( mv == "" || isNaN(mv) ){
alert("please input a number for the max value");
mv = maxvalue;
} else {
round_digit = getRoundDigit( mv );
}
if(value > mv) value = mv;
var v = value;
maxvalue = mv;
value = v;
}
with(win.sliderPanel.gp1){
txtBox.text = radiusSlider.value.toFixed( round_digit );
}
processPreview( true );
} catch(e){
alert(e);
} finally{
win.enabled = true;
}
}
*/
win.unitRadioPanel.ptRb.onClick = function(){
processPreview( true );
}
win.unitRadioPanel.mmRb.onClick = function(){
processPreview( true );
}
win.unitRadioPanel.inchRb.onClick = function(){
processPreview( true );
}
win.chkGroup.previewChk.onClick = function(){
if( win.chkGroup.previewChk.value ){
processPreview( true );
} else {
if(previewed){
clearPreview();
redraw();
}
}
}
win.sliderPanel.gp1.txtBox.onChange = function(){
var v = parseFloat(this.text);
if(isNaN(v)){
v = conf.rr;
} else if(v < 0){
v = 0;
/* // uncomment to use slider-version
} else if(v > win.sliderPanel.gp1.radiusSlider.maxvalue){
v = win.sliderPanel.gp1.radiusSlider.maxvalue;
*/
}
this.text = v;
/* // uncomment to use slider-version
win.sliderPanel.gp1.radiusSlider.value = v;
*/
processPreview( true );
}
/* // uncomment to use slider-version
win.sliderPanel.gp1.radiusSlider.onChanging = function(){
win.sliderPanel.gp1.txtBox.text = this.value.toFixed( round_digit );
}
win.sliderPanel.gp1.radiusSlider.onChange = function(){
win.sliderPanel.gp1.txtBox.text = this.value.toFixed( round_digit );
processPreview( true );
}
*/
win.btnGroup.okBtn.onClick = function(){
processPreview( false );
win.close();
}
win.btnGroup.cancelBtn.onClick = function(){
try{
win.enabled = false;
clearPreview();
} catch(e){
alert(e);
} finally{
win.enabled = true;
}
win.close();
}
win.show();
// error messasges aren't implemented for now
if( conf.errmsg != "") alert( conf.errmsg );
}
function convertUnit(n, fromUnit, toUnit){
if( fromUnit == "pt" ){
if( toUnit == "mm"){
n *= 0.352777778;
} else if( toUnit == "inch"){
n /= 72;
}
} else if( fromUnit == "mm"){
if( toUnit == "pt"){
n *= 2.83464567;
} else if( toUnit == "inch"){
n /= 25.4;
}
} else if( unit == "inch"){
if( toUnit == "pt"){
n *= 72;
} else if( toUnit == "mm"){
n *= 25.4;
}
}
return n;
}
function roundAnyCorner( s, conf ){
var rr = conf.rr;
// var tim = new Date();
var p, op, pnts;
var op_tmp;
var skipList, adjRdirAtEnd, redrawFlg;
var i, nxi, pvi, q, d,ds, r, g, t, qb;
var anc1, ldir1, rdir1, anc2, ldir2, rdir2;
var hanLen = 4 * (Math.sqrt(2) - 1) / 3;
var ptyp = PointType.SMOOTH;
for(var j = 0; j < s.length; j++){
p = s[j].pathPoints;
op_tmp = closeThePathIfItNeeds(s[j]);
if(readjustAnchors(p) < 2) continue; // reduce anchors
op = !s[j].closed;
pnts = op ? [getDat(p[0])] : [];
redrawFlg = false;
adjRdirAtEnd = 0;
skipList = [(op || !isSelected(p[0]) || ! isCorner(p, 0))];
for(i = 1; i < p.length; i++){
skipList.push((! isSelected(p[i])
|| ! isCorner(p,i)
|| (op && i == p.length - 1)));
}
for(i = 0; i < p.length; i++){
nxi = parseIdx(p, i + 1);
if(nxi < 0) break;
pvi = parseIdx(p, i - 1);
q = [p[i].anchor, p[i].rightDirection,
p[nxi].leftDirection, p[nxi].anchor];
ds = dist(q[0], q[3]) / 2;
if(arrEq(q[0], q[1]) && arrEq(q[2], q[3])){ // straight side
r = Math.min(ds, rr);
g = getRad(q[0], q[3]);
anc1 = getPnt(q[0], g, r);
ldir1 = getPnt(anc1, g + Math.PI, r * hanLen);
if(skipList[nxi]){
if(!skipList[i]){
pnts.push([anc1, anc1, ldir1, ptyp]);
redrawFlg = true;
}
pnts.push(getDat(p[nxi]));
} else {
if(r<rr){ // when the length of the side is less than rr * 2
pnts.push([anc1,
getPnt(anc1, getRad(ldir1, anc1), r * hanLen),
ldir1,
ptyp]);
} else {
if(!skipList[i]) pnts.push([anc1, anc1, ldir1, ptyp]);
anc2 = getPnt(q[3], g+Math.PI, r);
pnts.push([anc2,
getPnt(anc2, g, r * hanLen),
anc2,
ptyp]);
}
redrawFlg = true;
}
} else { // not straight side
d = getT4Len(q, 0) / 2;
r = Math.min(d,rr);
t = getT4Len(q, r);
anc1 = bezier(q, t);
rdir1 = defHan(t, q, 1);
ldir1 = getPnt(anc1, getRad(rdir1, anc1), r * hanLen);
if(skipList[nxi]){
if(skipList[i]){
pnts.push(getDat(p[nxi]));
} else {
pnts.push([anc1, rdir1, ldir1, ptyp]);
with(p[nxi]) pnts.push([anchor,
rightDirection,
adjHan(anchor, leftDirection, 1 - t),
ptyp]);
redrawFlg = true;
}
} else { // skipList[nxi] = false
if(r < rr){ // the length of the side is less than rr * 2
if(skipList[i]){
if(!op && i == 0){
adjRdirAtEnd = t;
} else {
pnts[pnts.length-1][1] = adjHan(q[0], q[1], t);
}
pnts.push([anc1,
getPnt(anc1, getRad(ldir1, anc1), r * hanLen),
defHan(t, q, 0),
ptyp]);
} else {
pnts.push([anc1,
getPnt(anc1, getRad(ldir1, anc1), r * hanLen),
ldir1,
ptyp]);
}
} else { // round the corner with the radius rr
if(skipList[i]){
t = getT4Len(q, -r);
anc2 = bezier(q, t);
if(!op && i==0) {
adjRdirAtEnd = t;
} else {
pnts[pnts.length - 1][1] = adjHan(q[0], q[1], t);
}
ldir2 = defHan(t, q, 0);
rdir2 = getPnt(anc2, getRad(ldir2, anc2), r * hanLen);
pnts.push([anc2, rdir2, ldir2 , ptyp]);
} else {
qb = [anc1, rdir1, adjHan(q[3], q[2], 1 - t), q[3]];
t = getT4Len(qb, -r);
anc2 = bezier(qb, t);
ldir2 = defHan(t,qb,0);
rdir2 = getPnt(anc2, getRad(ldir2, anc2), r*hanLen);
rdir1 = adjHan(anc1, rdir1, t);
pnts.push([anc1, rdir1, ldir1, ptyp],
[anc2, rdir2, ldir2, ptyp]);
}
}
redrawFlg = true;
}
}
}
if(adjRdirAtEnd > 0){
pnts[pnts.length - 1][1] = adjHan(p[0].anchor, p[0].rightDirection, adjRdirAtEnd);
}
if(redrawFlg){
// redraw
for(i = p.length-1; i > 0; i--) p[i].remove();
for(i = 0; i < pnts.length; i++){
pt = i > 0 ? p.add() : p[0];
with(pt){
anchor = pnts[i][0];
rightDirection = pnts[i][1];
leftDirection = pnts[i][2];
pointType = pnts[i][3];
}
}
}
restoreOpenPath(s[j], op_tmp);
}
activeDocument.selection = s;
// alert(new Date() - tim);
}
// ------------------------------------------------
function closeThePathIfItNeeds(p){
var op_tmp = !(p.closed);
if(FORCE_TREAT_AS_CLOSED_PATH && op_tmp){
var pp = p.pathPoints;
if(FORCE_TREAT_AS_CLOSED_PATH_ONLY_IF_START_AND_END_POINT_CLOSE_ENOUGH
&& dist(pp[0].anchor, pp[pp.length -1].anchor) > MIN_DIST){
// does nothing
} else {
p.closed = true;
}
}
return op_tmp;
}
// ------------------------------------------------
function restoreOpenPath(p, op_tmp){
if(FORCE_TREAT_AS_CLOSED_PATH && op_tmp && p.closed){
p.closed = false;
var pp = p.pathPoints;
var ppa = pp.add();
ppa.anchor = pp[0].anchor;
ppa.rightDirection = pp[0].rightDirection;
ppa.leftDirection = pp[0].leftDirection;
}
}
// ------------------------------------------------
// return [x,y] of the distance "len" and the angle "rad"(in radian)
// from "pt"=[x,y]
function getPnt(pt, rad, len){
return [pt[0] + Math.cos(rad) * len,
pt[1] + Math.sin(rad) * len];
}
// ------------------------------------------------
// return the [x, y] coordinate of the handle of the point on the bezier curve
// that corresponds to the parameter "t"
// n=0:leftDir, n=1:rightDir
function defHan(t, q, n){
return [t * (t * (q[n][0] - 2 * q[n+1][0] + q[n+2][0]) + 2 * (q[n+1][0] - q[n][0])) + q[n][0],
t * (t * (q[n][1] - 2 * q[n+1][1] + q[n+2][1]) + 2 * (q[n+1][1] - q[n][1])) + q[n][1]];
}
// -----------------------------------------------
// return the [x, y] coordinate on the bezier curve
// that corresponds to the paramter "t"
function bezier(q, t) {
var u = 1 - t;
return [u*u*u * q[0][0] + 3*u*t*(u* q[1][0] + t* q[2][0]) + t*t*t * q[3][0],
u*u*u * q[0][1] + 3*u*t*(u* q[1][1] + t* q[2][1]) + t*t*t * q[3][1]];
}
// ------------------------------------------------
// adjust the length of the handle "dir"
// by the magnification ratio "m",
// returns the modified [x, y] coordinate of the handle
// "anc" is the anchor [x, y]
function adjHan(anc, dir, m){
return [anc[0] + (dir[0] - anc[0]) * m,
anc[1] + (dir[1] - anc[1]) * m];
}
// ------------------------------------------------
// return true if the pathPoints "p[idx]" is a corner
function isCorner(p, idx){
var pnt0 = getAnglePnt(p, idx, -1);
var pnt1 = getAnglePnt(p, idx, 1);
if(! pnt0 || ! pnt1) return false; // at the end of a open-path
if(pnt0.length < 1 || pnt1.length<1) return false; // anchor is overlapping, so cannot determine the angle
var rad = getRad2(pnt0, p[idx].anchor, pnt1, true);
if(rad > Math.PI - 0.1) return false; // set the angle tolerance here
return true;
}
// ------------------------------------------------
// "p"=pathPoints, "idx1"=index of pathpoint
// "dir" = -1, returns previous point [x,y] to get the angle of tangent at pathpoints[idx1]
// "dir" = 1, returns next ...
function getAnglePnt(p, idx1, dir){
if(!dir) dir = -1;
var idx2 = parseIdx(p, idx1 + dir);
if(idx2 < 0) return null; // at the end of a open-path
var p2 = p[idx2];
with(p[idx1]){
if(dir<0){
if(arrEq(leftDirection, anchor)){
if(arrEq(p2.anchor, anchor)) return [];
if(arrEq(p2.anchor, p2.rightDirection)
|| arrEq(p2.rightDirection, anchor)) return p2.anchor;
else return p2.rightDirection;
} else {
return leftDirection;
}
} else {
if(arrEq(anchor, rightDirection)){
if(arrEq(anchor, p2.anchor)) return [];
if(arrEq(p2.anchor, p2.leftDirection)
|| arrEq(anchor, p2.leftDirection)) return p2.anchor;
else return p2.leftDirection;
} else {
return rightDirection;
}
}
}
}
// --------------------------------------
// if the contents of both arrays are equal, return true (lengthes must be same)
function arrEq(arr1, arr2) {
for(var i = 0; i < arr1.length; i++){
if (arr1[i] != arr2[i]) return false;
}
return true;
}
// ------------------------------------------------
// return the distance between p1=[x,y] and p2=[x,y]
function dist(p1, p2) {
return Math.sqrt(Math.pow(p1[0] - p2[0], 2)
+ Math.pow(p1[1] - p2[1], 2));
}
// ------------------------------------------------
// return the squared distance between p1=[x,y] and p2=[x,y]
function dist2(p1, p2) {
return Math.pow(p1[0] - p2[0],2)
+ Math.pow(p1[1] - p2[1],2);
}
// --------------------------------------
// return the angle in radian
// of the line drawn from p1=[x,y] from p2
function getRad(p1,p2) {
return Math.atan2(p2[1] - p1[1],
p2[0] - p1[0]);
}
// --------------------------------------
// return the angle between two line segments
// o-p1 and o-p2 ( 0 - Math.PI)
function getRad2(p1, o, p2){
var v1 = normalize(p1, o);
var v2 = normalize(p2, o);
return Math.acos(v1[0] * v2[0] + v1[1] * v2[1]);
}
// ------------------------------------------------
function normalize(p, o){
var d = dist(p, o);
return d == 0 ? [0, 0] : [(p[0] - o[0]) / d,
(p[1] - o[1]) / d];
}
// ------------------------------------------------
// return the bezier curve parameter "t"
// at the point which the length of the bezier curve segment
// (from the point start drawing) is "len"
// when "len" is 0, return the length of whole this segment.
function getT4Len(q, len){
var m = [ q[3][0] - q[0][0] + 3 * (q[1][0] - q[2][0]),
q[0][0] - 2 * q[1][0] + q[2][0],
q[1][0] - q[0][0] ];
var n = [ q[3][1] - q[0][1] + 3 * (q[1][1] - q[2][1]),
q[0][1] - 2 * q[1][1] + q[2][1],
q[1][1] - q[0][1] ];
var k = [ m[0] * m[0] + n[0] * n[0],
4 * (m[0] * m[1] + n[0] * n[1]),
2 * ((m[0] * m[2] + n[0] * n[2]) + 2 * (m[1] * m[1] + n[1] * n[1])),
4 * (m[1] * m[2] + n[1] * n[2]),
m[2] * m[2] + n[2] * n[2] ];
var fullLen = getLength(k, 1);
if(len == 0){
return fullLen;
} else if(len < 0){
len += fullLen;
if(len < 0) return 0;
} else if(len > fullLen){
return 1;
}
var t, d;
var t0 = 0;
var t1 = 1;
var torelance = 0.001;
for(var h = 1; h < 30; h++){
t = t0 + (t1 - t0) / 2;
d = len - getLength(k, t);
if(Math.abs(d) < torelance) break;
else if(d < 0) t1 = t;
else t0 = t;
}
return t;
}
// ------------------------------------------------
// return the length of bezier curve segment
// in range of parameter from 0 to "t"
function getLength(k, t){
var h = t / 128;
var hh = h * 2;
var fc = function(t, k){
return Math.sqrt(t * (t * (t * (t * k[0] + k[1]) + k[2]) + k[3]) + k[4]) || 0 };
var total = (fc(0, k) - fc(t, k)) / 2;
for(var i = h; i < t; i += hh) total += 2 * fc(i, k) + fc(i + h, k);
return total * hh;
}
// ------------------------------------------------
// extract PathItems from the selection which length of PathPoints
// is greater than "n"
function getPathItemsInSelection(n, paths){
if(documents.length < 1) return;
var s = activeDocument.selection;
if (!(s instanceof Array) || s.length < 1) return;
extractPaths(s, n, paths);
}
// --------------------------------------
// extract PathItems from "s" (Array of PageItems -- ex. selection),
// and put them into an Array "paths". If "pp_length_limit" is specified,
// this function extracts PathItems which PathPoints length is greater
// than this number.
function extractPaths(s, pp_length_limit, paths){
for(var i = 0; i < s.length; i++){
if(s[i].locked || s[i].hidden){
continue;
} else if(s[i].typename == "PathItem"){
if(pp_length_limit
&& s[i].pathPoints.length <= pp_length_limit){
continue;
}
paths.push(s[i]);
} else if(s[i].typename == "GroupItem"){
// search for PathItems in GroupItem, recursively
extractPaths(s[i].pageItems, pp_length_limit, paths);
} else if(s[i].typename == "CompoundPathItem"){
// searches for pathitems in CompoundPathItem, recursively
// ( ### Grouped PathItems in CompoundPathItem are ignored ### )
extractPaths(s[i].pathItems, pp_length_limit , paths);
}
}
}
// --------------------------------------
// merge nearly overlapped anchor points
// return the length of pathpoints after merging
function readjustAnchors(p){
// Settings ==========================
// merge the anchor points when the distance between
// 2 points is within ### square root ### of this value (in point)
var minDist = 0.0025;
// ===================================
if(p.length < 2) return 1;
var i;
if(p.parent.closed){
for(i = p.length - 1; i >= 1; i--){
if(dist2(p[0].anchor, p[i].anchor) < minDist){
p[0].leftDirection = p[i].leftDirection;
p[i].remove();
} else {
break;
}
}
}
for(i = p.length - 1; i >= 1; i--){
if(dist2(p[i].anchor, p[i - 1].anchor) < minDist){
p[i - 1].rightDirection = p[i].rightDirection;
p[i].remove();
}
}
return p.length;
}
// -----------------------------------------------
// return pathpoint's index. when the argument is out of bounds,
// fixes it if the path is closed (ex. next of last index is 0),
// or return -1 if the path is not closed.
function parseIdx(p, n){ // PathPoints, number for index
var len = p.length;
if(p.parent.closed){
return n >= 0 ? n % len : len - Math.abs(n % len);
} else {
return (n < 0 || n > len - 1) ? -1 : n;
}
}
// -----------------------------------------------
function getDat(p){ // pathPoint
with(p) return [anchor, rightDirection, leftDirection, pointType];
}
// -----------------------------------------------
function isSelected(p){ // PathPoint
return p.selected == PathPointSelection.ANCHORPOINT;
}
// -----------------------------------------------
function getSelectedSpec( paths ){
var specs = [];
var j, pp, spec;
for( var i = 0; i < paths.length; i++ ){
pp = paths[i].pathPoints;
spec = [];
for( j = 0; j < pp.length; j++ ){
spec.push( pp[j].selected );
}
specs.push( spec );
}
return specs;
}
// -----------------------------------------------
function applySelectedSpec( paths, specs ){
var j, pp;
for( var i = 0; i < paths.length; i++ ){
pp = paths[i].pathPoints;
for( j = 0; j < pp.length; j++ ){
pp[j].selected = specs[i][j];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment