svg-path-simplify 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +28 -1
  2. package/dist/svg-path-simplify.esm.js +4040 -0
  3. package/dist/svg-path-simplify.esm.min.js +1 -0
  4. package/dist/svg-path-simplify.js +4065 -0
  5. package/dist/svg-path-simplify.min.js +1 -0
  6. package/dist/svg-path-simplify.node.js +4062 -0
  7. package/dist/svg-path-simplify.node.min.js +1 -0
  8. package/index.html +222 -0
  9. package/package.json +2 -2
  10. package/src/constants.js +4 -0
  11. package/src/index.js +18 -3
  12. package/src/pathData_simplify_cubic.js +324 -0
  13. package/src/pathData_simplify_cubic_arr.js +50 -0
  14. package/src/pathData_simplify_cubic_extrapolate.js +220 -0
  15. package/src/pathSimplify-main.js +294 -0
  16. package/src/svgii/...parse.js +402 -0
  17. package/src/svgii/geometry.js +1096 -0
  18. package/src/svgii/geometry_area.js +265 -0
  19. package/src/svgii/geometry_bbox.js +223 -0
  20. package/src/svgii/pathData_analyze.js +896 -0
  21. package/src/svgii/pathData_convert.js +1180 -0
  22. package/src/svgii/pathData_parse.js +487 -0
  23. package/src/svgii/pathData_remove_collinear.js +85 -0
  24. package/src/svgii/pathData_remove_zerolength.js +28 -0
  25. package/src/svgii/pathData_reorder.js +204 -0
  26. package/src/svgii/pathData_reverse.js +124 -0
  27. package/src/svgii/pathData_scale.js +42 -0
  28. package/src/svgii/pathData_split.js +449 -0
  29. package/src/svgii/pathData_stringify.js +146 -0
  30. package/src/svgii/pathData_toPolygon.js +92 -0
  31. package/src/svgii/pathdata_cleanup.js +363 -0
  32. package/src/svgii/poly_analyze.js +172 -0
  33. package/src/svgii/poly_to_pathdata.js +185 -0
  34. package/src/svgii/rounding.js +154 -0
  35. package/src/svgii/simplify.js +248 -0
  36. package/src/svgii/simplify_bezier.js +470 -0
  37. package/src/svgii/simplify_linetos.js +93 -0
  38. package/src/svgii/simplify_polygon.js +135 -0
  39. package/src/svgii/stringify.js +103 -0
  40. package/src/svgii/svg_cleanup.js +80 -0
  41. package/src/svgii/visualize.js +317 -0
  42. package/LICENSE +0 -21
@@ -0,0 +1,449 @@
1
+ import { pointAtT, svgArcToCenterParam, getBezierExtremeT } from "./geometry";
2
+ import { renderPoint, renderPath } from "./visualize";
3
+
4
+
5
+ /**
6
+ * split segments into chunks to
7
+ * prevent simplification across
8
+ * extremes, corners or direction changes
9
+ */
10
+
11
+ export function getPathDataPlusChunks(pathDataPlus = [], debug = false) {
12
+
13
+ // loop sub paths
14
+ for (let s = 0, l = pathDataPlus.length; s < l; s++) {
15
+ let sub = pathDataPlus[s];
16
+ let pathDataSub = sub.pathData;
17
+ pathDataPlus[s].chunks = [[pathDataSub[0]], []];
18
+
19
+ let pathDataChunks = [[pathDataSub[0]], []];
20
+ let ind = 1
21
+
22
+ let wasExtreme = false
23
+ let wasCorner = false
24
+ let wasClosePath = false;
25
+ let prevType = 'M';
26
+ let typeChange = false;
27
+
28
+
29
+ for (let i = 1, len = pathDataSub.length; i < len; i++) {
30
+ let com = pathDataSub[i]
31
+
32
+ let { extreme, corner, directionChange } = com;
33
+ typeChange = prevType !== com.type;
34
+ let split = directionChange || wasExtreme || wasCorner || wasClosePath || typeChange;
35
+ //let split = wasExtreme
36
+
37
+
38
+ // new chunk
39
+ if (split) {
40
+ /*
41
+ if(directionChange){
42
+ renderPoint(svg1, com.p0 , 'red')
43
+ }
44
+ if(wasExtreme){
45
+ renderPoint(svg1, com.p0 , 'blue')
46
+ }
47
+
48
+ if(wasCorner){
49
+ renderPoint(svg1, com.p0 , 'magenta')
50
+ }
51
+
52
+ if(wasClosePath){
53
+ renderPoint(svg1, com.p0 , 'red')
54
+ }
55
+
56
+ if(typeChange && com.type==='Q' && prevType==='M'){
57
+ console.log('typechange', pathDataSub[i], pathDataSub[i-1]);
58
+ renderPoint(svg1, com.p0 , 'purple')
59
+ }
60
+ */
61
+
62
+ //let orphanedC = pathDataChunks[ind].length===1 && i<len-1 && wasExtreme
63
+ //orphanedC=false
64
+ //console.log('orphanedC', i, len, orphanedC, pathDataChunks[ind].length);
65
+
66
+ if (pathDataChunks[ind].length) {
67
+ pathDataChunks.push([]);
68
+ ind++
69
+ }
70
+ }
71
+
72
+ wasExtreme = extreme
73
+ wasCorner = corner;
74
+ wasClosePath = com.type.toLowerCase() === 'z'
75
+ prevType = com.type
76
+ //pathDataPlus[s].chunks[ind].push(com);
77
+ pathDataChunks[ind].push(com)
78
+
79
+ }
80
+
81
+
82
+ // debug rendering
83
+ if (debug) {
84
+
85
+ //console.log('show chunks', pathDataChunks);
86
+ pathDataChunks.forEach((ch, i) => {
87
+ let stroke = i % 2 === 0 ? 'green' : 'orange';
88
+ if(i===pathDataChunks.length-2){
89
+ stroke = 'magenta'
90
+ }
91
+
92
+ let M = ch[0].p0;
93
+ if (M) {
94
+ //renderPoint(svg1, M, 'green', '1%')
95
+ let d = `M ${M.x} ${M.y}`
96
+
97
+ ch.forEach(com => {
98
+ //console.log(com);
99
+ d += `${com.type} ${com.values.join(' ')}`
100
+ //let pt = com.p;
101
+ //renderPoint(svg1, pt, 'cyan')
102
+ })
103
+ //console.log(d);
104
+ renderPath(svg1, d, stroke, '0.5%', '0.5')
105
+ }
106
+
107
+ })
108
+ }
109
+
110
+ // add to pathdataPlus object
111
+ pathDataPlus[s].chunks = pathDataChunks
112
+
113
+ }
114
+
115
+ //console.log(pathDataPlus);
116
+ return pathDataPlus
117
+
118
+ }
119
+
120
+
121
+
122
+
123
+ /**
124
+ * split compound paths into
125
+ * sub path data array
126
+ */
127
+ export function splitSubpaths(pathData) {
128
+
129
+ let subPathArr = [];
130
+
131
+ //split segments after M command
132
+
133
+ try{
134
+ let subPathIndices = pathData.map((com, i) => (com.type.toLowerCase() === 'm' ? i : -1)).filter(i => i !== -1);
135
+
136
+ }catch{
137
+ console.log('catch', pathData);
138
+ }
139
+
140
+
141
+ let subPathIndices = pathData.map((com, i) => (com.type.toLowerCase() === 'm' ? i : -1)).filter(i => i !== -1);
142
+ //let subPathIndices = pathData.map((com, i) => (com.type === 'M' ? i : -1)).filter(i => i !== -1);
143
+
144
+ // no compound path
145
+ if (subPathIndices.length === 1) {
146
+ return [pathData]
147
+ }
148
+ subPathIndices.forEach((index, i) => {
149
+ subPathArr.push(pathData.slice(index, subPathIndices[i + 1]));
150
+ });
151
+
152
+ return subPathArr;
153
+ }
154
+
155
+
156
+
157
+ /**
158
+ * calculate split command points
159
+ * for single t value
160
+ */
161
+ export function splitCommand(points, t) {
162
+
163
+ let seg1 = [];
164
+ let seg2 = [];
165
+
166
+ let p0 = points[0];
167
+ let cp1 = points[1];
168
+ let cp2 = points[points.length - 2];
169
+ let p = points[points.length - 1];
170
+ let m0,m1,m2,m3,m4, p2
171
+
172
+
173
+ // cubic
174
+ if (points.length === 4) {
175
+ m0 = pointAtT([p0, cp1], t);
176
+ m1 = pointAtT([cp1, cp2], t);
177
+ m2 = pointAtT([cp2, p], t);
178
+ m3 = pointAtT([m0, m1], t);
179
+ m4 = pointAtT([m1, m2], t);
180
+
181
+ // split end point
182
+ p2 = pointAtT([m3, m4], t);
183
+
184
+ // 1. segment
185
+ seg1.push(
186
+ { x: p0.x, y: p0.y },
187
+ { x: m0.x, y: m0.y },
188
+ { x: m3.x, y: m3.y },
189
+ { x: p2.x, y: p2.y },
190
+ )
191
+ // 2. segment
192
+ seg2.push(
193
+ { x: p2.x, y: p2.y },
194
+ { x: m4.x, y: m4.y },
195
+ { x: m2.x, y: m2.y },
196
+ { x: p.x, y: p.y },
197
+ )
198
+ }
199
+
200
+ // quadratic
201
+ else if (points.length === 3) {
202
+ m1 = pointAtT([p0, cp1], t);
203
+ m2 = pointAtT([cp1, p], t);
204
+ p2 = pointAtT([m1, m2], t);
205
+
206
+ // 1. segment
207
+ seg1.push(
208
+ { x: p0.x, y: p0.y },
209
+ { x: m1.x, y: m1.y },
210
+ { x: p2.x, y: p2.y },
211
+ )
212
+
213
+ // 1. segment
214
+ seg2.push(
215
+ { x: p2.x, y: p2.y },
216
+ { x: m2.x, y: m2.y },
217
+ { x: p.x, y: p.y },
218
+ )
219
+ }
220
+
221
+ // lineto
222
+ else if (points.length === 2) {
223
+ m1 = pointAtT([p0, p], t);
224
+
225
+ // 1. segment
226
+ seg1.push(
227
+ { x: p0.x, y: p0.y },
228
+ { x: m1.x, y: m1.y },
229
+ )
230
+
231
+ // 1. segment
232
+ seg2.push(
233
+ { x: m1.x, y: m1.y },
234
+ { x: p.x, y: p.y },
235
+ )
236
+ }
237
+ return [seg1, seg2];
238
+ }
239
+
240
+
241
+ /**
242
+ * calculate command extremes
243
+ */
244
+
245
+ export function addExtemesToCommand(p0, values, tMin=0, tMax=1) {
246
+
247
+ let pathDataNew = [];
248
+
249
+ let type = values.length === 6 ? 'C' : 'Q'
250
+ let cp1 = { x: values[0], y: values[1] }
251
+ let cp2 = type === 'C' ? { x: values[2], y: values[3] } : cp1
252
+ let p = { x: values[4], y: values[5] }
253
+
254
+
255
+ // get inner bbox
256
+ let xMax = Math.max(p.x, p0.x)
257
+ let xMin = Math.min(p.x, p0.x)
258
+ let yMax = Math.max(p.y, p0.y)
259
+ let yMin = Math.min(p.y, p0.y)
260
+
261
+ let extremeCount = 0;
262
+
263
+ //has extreme - split
264
+ if (
265
+ cp1.x < xMin ||
266
+ cp1.x > xMax ||
267
+ cp1.y < yMin ||
268
+ cp1.y > yMax ||
269
+ cp2.x < xMin ||
270
+ cp2.x > xMax ||
271
+ cp2.y < yMin ||
272
+ cp2.y > yMax
273
+
274
+ ) {
275
+ let pts = type === 'C' ? [p0, cp1, cp2, p] : [p0, cp1, p];
276
+ let tArr = getBezierExtremeT(pts).sort();
277
+
278
+ // avoid t split too close to start or end
279
+ tArr = tArr.filter(t=>t>tMin && t<tMax)
280
+
281
+ if(tArr.length){
282
+ let commandsSplit = splitCommandAtTValues(p0, values, tArr)
283
+ pathDataNew.push(...commandsSplit)
284
+ extremeCount += commandsSplit.length;
285
+ }else{
286
+ //console.log('no extreme: ', tArr);
287
+ pathDataNew.push({ type: type, values: values })
288
+ }
289
+
290
+ }
291
+ // no extremes
292
+ else {
293
+ pathDataNew.push({ type: type, values: values })
294
+ }
295
+
296
+ return { pathData: pathDataNew, count: extremeCount };
297
+
298
+ }
299
+
300
+
301
+
302
+ export function addExtremePoints(pathData, tMin=0, tMax=1) {
303
+ let pathDataNew = [pathData[0]];
304
+ // previous on path point
305
+ let p0 = { x: pathData[0].values[0], y: pathData[0].values[1] };
306
+ let M = { x: pathData[0].values[0], y: pathData[0].values[1] };
307
+ let len = pathData.length;
308
+
309
+ for (let c = 1; len && c < len; c++) {
310
+ let com = pathData[c];
311
+ //let comPrev = pathData[c - 1];
312
+ //let comN = pathData[c + 1] ? pathData[c + 1] : '';
313
+ let { type, values } = com;
314
+ let valsL = values.slice(-2);
315
+ let p = { x: valsL[0], y: valsL[1] };
316
+
317
+ if (type !== 'C' && type !== 'Q') {
318
+ pathDataNew.push(com)
319
+ }
320
+
321
+ else {
322
+ // add extremes
323
+ if (type === 'C' || type === 'Q') {
324
+ let comExt = addExtemesToCommand(p0, values, tMin, tMax).pathData;
325
+ //console.log('comExt', comExt);
326
+ pathDataNew.push(...comExt )
327
+ }
328
+ }
329
+
330
+ p0 = { x: valsL[0], y: valsL[1] };
331
+
332
+ if (type.toLowerCase() === "z") {
333
+ p0 = M;
334
+ } else if (type === "M") {
335
+ M = { x: valsL[0], y: valsL[1] };
336
+ }
337
+ }
338
+
339
+ //console.log(pathData.length, pathDataNew.length)
340
+ return pathDataNew;
341
+ }
342
+
343
+
344
+
345
+ /**
346
+ * split commands multiple times
347
+ * based on command points
348
+ * and t array
349
+ */
350
+ export function splitCommandAtTValues(p0, values, tArr, returnCommand = true) {
351
+ let segmentPoints = [];
352
+
353
+ if (!tArr.length) {
354
+ return false
355
+ }
356
+
357
+ let valuesL = values.length;
358
+ let p = { x: values[valuesL - 2], y: values[valuesL - 1] };
359
+ let type, cp1, cp2, points;
360
+
361
+
362
+ if (values.length === 2) {
363
+ type = 'L'
364
+ points = [p0, p]
365
+ }
366
+ else if (values.length === 4) {
367
+ type = 'Q'
368
+ cp1 = { x: values[0], y: values[1] };
369
+ points = [p0, cp1, p]
370
+ }
371
+ else if (values.length === 6) {
372
+ type = 'C'
373
+ cp1 = { x: values[0], y: values[1] };
374
+ cp2 = { x: values[2], y: values[3] };
375
+ points = [p0, cp1, cp2, p]
376
+ }
377
+
378
+
379
+
380
+ if (tArr.length) {
381
+ // single t
382
+ if (tArr.length === 1) {
383
+ let segs = splitCommand(points, tArr[0]);
384
+ let points1 = segs[0]
385
+ let points2 = segs[1]
386
+ segmentPoints.push(points1, points2)
387
+ //return segmentPoints;
388
+ } else {
389
+
390
+ // 1st segment
391
+ let t1 = tArr[0];
392
+ let seg0 = splitCommand(points, t1);
393
+ let points0 = seg0[0];
394
+ segmentPoints.push(points0)
395
+ points = seg0[1];
396
+
397
+ //console.log('tarr', tArr);
398
+
399
+ for (let i = 1; i < tArr.length; i++) {
400
+ t1 = tArr[i - 1]
401
+ let t2 = tArr[i]
402
+
403
+ // new t value for 2nd segment
404
+ let t2_1 = (t2 - t1) / (1 - t1)
405
+ let segs2 = splitCommand(points, t2_1);
406
+ segmentPoints.push(segs2[0])
407
+
408
+ if (i === tArr.length - 1) {
409
+ segmentPoints.push(segs2[segs2.length - 1])
410
+ }
411
+ // take 2nd segment for next splitting
412
+ points = segs2[1];
413
+ }
414
+ }
415
+ }
416
+
417
+ if (returnCommand) {
418
+
419
+ let pathData = [];
420
+ let com, values;
421
+
422
+ segmentPoints.forEach(seg => {
423
+ com = { type: '', values: [] };
424
+ seg.shift();
425
+ values = seg.map(val => { return Object.values(val) }).flat()
426
+ com.values = values;
427
+
428
+ // cubic
429
+ if (seg.length === 3) {
430
+ com.type = 'C';
431
+ }
432
+
433
+ // quadratic
434
+ else if (seg.length === 2) {
435
+ com.type = 'Q';
436
+ }
437
+
438
+ // lineto
439
+ else if (seg.length === 1) {
440
+ com.type = 'L';
441
+ }
442
+ pathData.push(com)
443
+ })
444
+ return pathData;
445
+ }
446
+
447
+ return segmentPoints;
448
+ }
449
+
@@ -0,0 +1,146 @@
1
+
2
+ /**
3
+ * serialize pathData array to
4
+ * d attribute string
5
+ */
6
+
7
+ export function pathDataToD(pathData, optimize = 0) {
8
+
9
+ optimize = parseFloat(optimize)
10
+
11
+ let beautify = optimize > 1;
12
+ let minify = beautify || optimize ? false : true;
13
+
14
+ // Convert first "M" to "m" if followed by "l" (when minified)
15
+ if (pathData[1].type === "l" && minify) {
16
+ pathData[0].type = "m";
17
+ }
18
+
19
+ let d = '';
20
+ let suff = beautify ? `\n` : ' ';
21
+
22
+
23
+ if (minify) {
24
+ d = `${pathData[0].type} ${pathData[0].values.join(" ")}`;
25
+ } else {
26
+ d = `${pathData[0].type} ${pathData[0].values.join(" ")}${suff}`;
27
+ }
28
+
29
+ for (let i = 1, len = pathData.length; i < len; i++) {
30
+ let com0 = pathData[i - 1];
31
+ let com = pathData[i];
32
+ let { type, values } = com;
33
+
34
+ // Minify Arc commands (A/a) – actually sucks!
35
+ if (minify && (type === 'A' || type === 'a')) {
36
+ values = [
37
+ values[0], values[1], values[2],
38
+ `${values[3]}${values[4]}${values[5]}`,
39
+ values[6]
40
+ ];
41
+ }
42
+
43
+ // Omit type for repeated commands
44
+ type = (com0.type === com.type && com.type.toLowerCase() !== 'm' && minify)
45
+ ? " "
46
+ : (
47
+ (com0.type === "m" && com.type === "l") ||
48
+ (com0.type === "M" && com.type === "l") ||
49
+ (com0.type === "M" && com.type === "L")
50
+ ) && minify
51
+ ? " "
52
+ : com.type;
53
+
54
+
55
+ // concatenate subsequent floating point values
56
+ if (minify) {
57
+
58
+ //console.log(optimize, beautify, minify);
59
+
60
+ let valsString = '';
61
+ let prevWasFloat = false;
62
+
63
+ for (let v = 0, l = values.length; v < l; v++) {
64
+ let val = values[v];
65
+ let valStr = val.toString();
66
+ let isFloat = valStr.includes('.');
67
+ let isSmallFloat = isFloat && Math.abs(val) < 1;
68
+
69
+
70
+ // Remove leading zero from small floats *only* if the previous was also a float
71
+ if (isSmallFloat && prevWasFloat) {
72
+ valStr = valStr.replace(/^0\./, '.');
73
+ }
74
+
75
+ // Add space unless this is the first value OR previous was a small float
76
+ if (v > 0 && !(prevWasFloat && isSmallFloat)) {
77
+ valsString += ' ';
78
+ }
79
+ //console.log(isSmallFloat, prevWasFloat, valStr);
80
+
81
+ valsString += valStr
82
+ //.replace(/-0./g, '-.').replace(/ -./g, '-.')
83
+ prevWasFloat = isSmallFloat;
84
+ }
85
+
86
+ //console.log('minify', valsString);
87
+ d += `${type}${valsString}`;
88
+
89
+ }
90
+ // regular non-minified output
91
+ else {
92
+ d += `${type} ${values.join(' ')}${suff}`;
93
+ }
94
+ }
95
+
96
+ if (minify) {
97
+ d = d
98
+ .replace(/ 0\./g, " .") // Space before small decimals
99
+ .replace(/ -/g, "-") // Remove space before negatives
100
+ .replace(/-0\./g, "-.") // Remove leading zero from negative decimals
101
+ .replace(/Z/g, "z"); // Convert uppercase 'Z' to lowercase
102
+ }
103
+
104
+ return d;
105
+ }
106
+
107
+
108
+ export function pathDataToD_0(pathData, decimals = -1, minify = false) {
109
+ // implicit l command
110
+ if (pathData[1].type === "l" && minify) {
111
+ pathData[0].type = "m";
112
+ }
113
+ let d = `${pathData[0].type}${pathData[0].values.join(" ")}`;
114
+
115
+ for (let i = 1; i < pathData.length; i++) {
116
+ let com0 = pathData[i - 1];
117
+ let com = pathData[i];
118
+
119
+ let type = (com0.type === com.type && minify) ?
120
+ " " : (
121
+ (com0.type === "m" && com.type === "l") ||
122
+ (com0.type === "M" && com.type === "l") ||
123
+ (com0.type === "M" && com.type === "L")
124
+ ) && minify ?
125
+ " " : com.type;
126
+
127
+ // round
128
+ if (com.values.length && decimals > -1) {
129
+ com.values = com.values.map(val => { return +val.toFixed(decimals) })
130
+ }
131
+ d += `${type}${com.values.join(" ")}`;
132
+ }
133
+
134
+
135
+ if (minify) {
136
+ d = d
137
+ .replaceAll(" 0.", " .")
138
+ .replaceAll(" -", "-")
139
+ .replaceAll("-0.", "-.")
140
+ .replace(/\s+([mlcsqtahvz])/gi, "$1")
141
+ .replaceAll("Z", "z");
142
+ }
143
+
144
+ return d;
145
+ }
146
+
@@ -0,0 +1,92 @@
1
+ import { pointAtT } from "./geometry";
2
+ import { getPolyBBox } from "./geometry_bbox";
3
+ import { addDimensionData, analyzePathData } from "./pathData_analyze";
4
+ import { addExtremePoints } from "./pathData_split";
5
+
6
+ export function pathDataToPolyPlus(pathDataArr = [], addExtremes=true) {
7
+
8
+ // check if splitting sub paths is required
9
+ pathDataArr = Object.hasOwnProperty(pathDataArr[0].type) ? splitSubpaths(pathDataArr) : pathDataArr;
10
+
11
+ let dimMin = Infinity;
12
+ let dimMax = 0;
13
+
14
+
15
+ /**
16
+ * add extremes to beziers
17
+ * to reproduce the shape better
18
+ */
19
+ if(addExtremes){
20
+ pathDataArr.forEach((pathData, i) => {
21
+
22
+ //pathDataArr[i] = addExtremePoints(pathData)
23
+ let pathDataE = addExtremePoints(pathData)
24
+
25
+ //pathDataArr[i] = analyzePathData(pathDataE).pathData
26
+ pathDataArr[i] = addDimensionData(pathDataE)
27
+
28
+ })
29
+ }
30
+
31
+
32
+ /**
33
+ * approximate min and max segment sizes
34
+ * for segment splitting
35
+ */
36
+ pathDataArr.forEach(pathData => {
37
+
38
+ let dimArr = pathData.filter(com => com.dimA).sort((a, b) => a.dimA - b.DimA)
39
+ let dimMinL = dimArr[0].dimA
40
+ let dimMaxL = dimArr[dimArr.length - 1].dimA
41
+ //console.log('dimArr', dimArr, dimMaxL);
42
+ if (dimMinL && dimMinL < dimMin) dimMin = dimMinL;
43
+ if (dimMaxL && dimMaxL > dimMax) dimMax = dimMaxL;
44
+
45
+ })
46
+
47
+ //console.log(dimMin, dimMax);
48
+
49
+ // find split point based on smallest point distance
50
+ dimMin = (dimMin * 2 + dimMax) / 2 * 0.5
51
+
52
+ // collect vertices
53
+ let polyArr = [];
54
+
55
+
56
+ pathDataArr.forEach(pathData => {
57
+
58
+ let poly = [pathData[0].p0];
59
+
60
+ pathData.forEach(com => {
61
+
62
+ let { type, values, dimA = null, p0, p, cp1 = null, cp2 = null } = com;
63
+ let split = type === 'C' && dimA ? Math.ceil(dimA / dimMin) : 0;
64
+
65
+ if (type === 'C' && split) {
66
+
67
+ let splitT = 1 / split;
68
+
69
+ for (let i = 1; i < split; i++) {
70
+
71
+ let t = splitT * i;
72
+ let ptI = pointAtT([p0, cp1, cp2, p], t)
73
+ poly.push(ptI)
74
+ }
75
+
76
+ }
77
+ poly.push(p)
78
+ })
79
+
80
+ polyArr.push(poly)
81
+
82
+ /*
83
+ let bb = getPolyBBox(poly);
84
+ let dimAv = (bb.width+bb.height)/2
85
+ console.log('dimAv', dimAv);
86
+ */
87
+
88
+ })
89
+
90
+ return polyArr
91
+
92
+ }