-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPath Length.jsx
337 lines (303 loc) · 10.3 KB
/
Path Length.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// Path Length
// finds out length of the each selected path
// and total length of the selected paths
// then write out them on the artboard as text object
// This script uses JavaScript's "length" property of PathItem.
// if it is available (= CS3 or later).
// You can force calculate the length by "use_native_property"
// setting set to false. ( see below )
// NOTE 1:
// The return values of "PathItem.length" property and the function in this script
// are slightly different especially in complex paths.
// It seems that the difference is 0.05 mm at most.
// NOTE 2:
// You can modify the font name by editing the script.
// The name must be the postscript-name of the font.
// You can get it by using the helper function getFontName().
//
// 1. Please modify line 60 as follows. Then save.
// before:main();
// after :getFontName(); //main();
//
// 2. Please select a point text object. Then run the script.
// You'll see the postscript name of the font of the selected text in the
// message dialog.
//
// 3. Please modify line 70 of the script as follows.
// before: var font_name = "MyriadPro-Regular";
// after : var font_name = "<font name you got>";
//
// 4. Please restore line 60 of the script as follows. Then save.
// before:getFontName(); //main();
// after :main();
//
// 5. Please Select some paths and run the script. ...Hope it works!
// test env: Adobe Illustrator CS3, CS6 (Windows)
// Copyright(c) 2009-2013 Hiroyuki Sato
// https://github.com/shspage
// This script is distributed under the MIT License.
// See the LICENSE file for details.
// Wed, 30 Jan 2013 07:08:22 +0900
// 2011-01-18: changed the default font_name (TimesNewRomanPSMT -> MyriadPro-Regular)
// modified writeResultAsText() so that the each text be placed above of the related path
// 2011-01-19: added an option put_text_on_the_first_layer (line 74)
// modified writeResultAsText() so that the each text be placed according to this new option.
// placed texts are selected finally.
var ver10 = (version.indexOf('10') == 0);
var verCS1 = (version.indexOf('11') == 0);
var verCS2 = (version.indexOf('12') == 0);
//var tim = new Date();
main();
//alert(new Date() - tim);
function main(){
// Settings =================================
// use "PathItem.length" property if CS3 or later
var use_native_property = true;
var font_size = 12;
var font_name = "MyriadPro-Regular";
var digit = 2; // number of digits after decimal point (round off last digit)
var use_mm_4_unit = true; // use millimeter as unit: true/false(use point)
var put_text_on_the_first_layer = false;
// true: put the texts on the first layer of the document. unlock and show it if it is locked or hidden.
// false: put the texts on the active layer. if it is locked or hidden, put the text on the topmost
// layer of the selection.
var div_num = 1024;
// ==========================================
if(ver10 || verCS1 || verCS2){
use_native_property = false;
}
if (documents.length<1){
return;
}
var sel = activeDocument.selection;
if (!(sel instanceof Array) || sel.length<1){
return;
}
var selected_paths = [];
extractpaths(sel, 1, selected_paths);
if(selected_paths.length<1){
return;
}
// prepares the layer
var lay;
if(put_text_on_the_first_layer){
lay = activeDocument.layers[0];
if(lay.locked) lay.locked = false;
if(!lay.visible) lay.visible = true;
} else {
lay = activeDocument.activeLayer;
if(lay.locked || !lay.visible){
lay = selected_paths[0].layer
}
}
var path_length = 0;
var all_paths_length = 0;
var unit = use_mm_4_unit ? "mm" : "";
var position_to_write_result;
var i, j, k;
var path_points, segment_length;
var results = [];
for(i = 0; i < selected_paths.length; i++){
if(use_native_property){
path_length = selected_paths[i].length;
} else {
path_points = selected_paths[i].pathPoints;
for(j = 0; j < path_points.length; j++){
if(j == path_points.length - 1){
if(selected_paths[i].closed){
k = 0;
} else {
break;
}
} else {
k = j + 1;
}
segment_length = getLength([path_points[j].anchor, path_points[j].rightDirection,
path_points[k].leftDirection, path_points[k].anchor],
div_num);
path_length += segment_length;
}
}
all_paths_length += path_length;
// write out the result
if(use_mm_4_unit){
path_length = pt2mm(path_length); // convert to millimeter
}
position_to_write_result = findCenter( selected_paths[i] );
writeResultAsText(lay,
fixedTo(path_length, digit) + unit,
font_name,
font_size,
position_to_write_result,
results);
path_length = 0;
}
// write out the total length
if(selected_paths.length > 1){
if( use_mm_4_unit ){
all_paths_length = pt2mm( all_paths_length ); // convert to millimeter
}
position_to_write_result[1] -= font_size;
writeResultAsText(lay,
"all: " + fixedTo(all_paths_length, digit) + unit,
font_name,
font_size,
position_to_write_result,
results);
}
activeDocument.selection = results.concat(selected_paths);
}
// ------------------------------------------------
// return the segment length
// segment = part of a path between 2 anchors
// q = [Q0[x,y],Q1,Q2,Q3], div_num = division number
// Simpson's method : with simplified coefficients to speed-up
function getLength(q, div_num){
var div_unit = 1 / div_num;
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 fc = function(t, k){
return Math.sqrt(t * ( t * ( t * ( t * k[0] + k[1]) + k[2]) + k[3]) + k[4]) || 0;
};
var total = 0;
var i;
for(i = 1; i < div_num; i += 2){
total += fc(i * div_unit, k);
}
total *= 2;
for(i = 2; i < div_num; i += 2){
total += fc(i * div_unit, k);
}
return (fc(0, k) + fc(1, k) + total * 2) * div_unit;
}
// ------------------------------------------------
// less simplified Simpson's method (for verify)
function getLength2(q, div_num){
var div_unit = 1 / div_num;
var m = [q[3][0] - q[0][0] + 3 * (q[1][0] - q[2][0]),
3 * (q[0][0] - 2 * q[1][0] + q[2][0]),
3 * (q[1][0] - q[0][0])];
var n = [q[3][1] - q[0][1] + 3 * (q[1][1] - q[2][1]),
3 * (q[0][1] - 2 * q[1][1] + q[2][1]),
3 * (q[1][1] - q[0][1])];
var fc = function(t, m, n){
return Math.sqrt(Math.pow(3*t*t*m[0] + 2*t*m[1] + m[2], 2)
+ Math.pow(3*t*t*n[0] + 2*t*n[1] + n[2], 2)) || 0;
};
var total = 0;
var i;
for(i = 1; i < div_num; i += 2){
total += 4.0 * fc(i * div_unit, m, n);
}
for(i = 2; i< div_num; i+= 2){
total += 2.0 * fc(i * div_unit, m, n);
}
return (fc(0, m, n) + fc(1, m, n) + total) * div_unit / 3;
}
// ------------------------------------------------
// convert PostScript point to millimeter
function pt2mm(n){
return n * 0.35277778;
}
// ------------------------------------------------
// writes out "str" as a Text object.
// AI10 compatibility is experimental
function writeResultAsText(lay, str, nam, siz, posi, results){
if(ver10){
var tx = lay.textArtItems.add();
with(tx){
contents = str;
with(textRange()){
font = nam;
size = siz;
}
position = [posi[0]-width/2, posi[1]+height/2];
}
results.push(tx);
} else {
var tx = lay.textFrames.add();
with(tx){
contents = str;
with(textRange){
with(characterAttributes){
size = siz;
textFont = textFonts.getByName(nam);
}
with(paragraphAttributes){
justification = Justification.LEFT;
autoLeadingAmount = 120;
}
}
position = [posi[0]-width/2, posi[1]+height/2];
}
results.push(tx);
}
}
// ------------------------------------------------
// find out the center[x, y] of the PageItem
function findCenter(pi){
var gb = pi.geometricBounds; // left, top, right, bottom
return [(gb[0] + gb[2]) / 2, (gb[1] + gb[3]) / 2];
}
// --------------------------------------
function extractpaths(s, pp_length_limit, paths){
for(var i = 0; i < s.length; i++){
if(s[i].typename == "PathItem"
&& !s[i].guides && !s[i].clipping){
if(pp_length_limit
&& s[i].pathPoints.length <= pp_length_limit){
continue;
}
paths.push(s[i]);
} else if(s[i].typename == "GroupItem"){
extractpaths(s[i].pageItems, pp_length_limit, paths);
} else if(s[i].typename == "CompoundPathItem"){
extractpaths(s[i].pathItems, pp_length_limit , paths);
}
}
}
// ------------------------------------------------
// notify 1st character's font name in the selected text object
function getFontName(){
if (documents.length<1){
return;
}
var s = activeDocument.selection;
var text_object = ver10 ? "TextArtItem" : "TextFrame";
if (!(s instanceof Array)
|| s.length<1
|| s[0].typename != text_object
|| s[0].contents.length<1){
alert("Usage: Select a text object, then run this script");
} else if(ver10){
alert(activeDocument.selection[0].textRange(0,0).font);
} else {
alert(activeDocument.selection[0].textRange.characters[0].textFont.name);
}
}
// ------------------------------------------------
// It seems that "toFixed" is not available in AI10
function fixedTo(n, k){
var m = Math.pow(10 ,k);
var s = (Math.round(n * m)) + "";
if(k <= 0){
return s;
}
while(s.length < k + 1){
s = "0" + s;
}
var len = s.length - k;
s = s.substr(0, len) + "." + s.substr(len, k);
s = s.replace(/0+$/, "");
s = s.replace(/\.$/, "");
return s;
}