svg-path-simplify 0.0.8 → 0.0.9

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 (34) hide show
  1. package/README.md +25 -5
  2. package/dist/svg-path-simplify.esm.js +576 -494
  3. package/dist/svg-path-simplify.esm.min.js +1 -1
  4. package/dist/svg-path-simplify.js +576 -494
  5. package/dist/svg-path-simplify.min.js +1 -1
  6. package/dist/svg-path-simplify.node.js +576 -494
  7. package/dist/svg-path-simplify.node.min.js +1 -1
  8. package/index.html +86 -29
  9. package/package.json +1 -1
  10. package/src/detect_input.js +17 -10
  11. package/src/index.js +3 -0
  12. package/src/pathData_simplify_cubic.js +113 -106
  13. package/src/pathData_simplify_cubic_extrapolate.js +25 -11
  14. package/src/pathSimplify-main.js +89 -182
  15. package/src/svgii/geometry_flatness.js +29 -36
  16. package/src/svgii/pathData_analyze.js +4 -0
  17. package/src/svgii/pathData_convert.js +26 -17
  18. package/src/svgii/pathData_interpolate.js +65 -0
  19. package/src/svgii/pathData_parse.js +25 -9
  20. package/src/svgii/pathData_parse_els.js +18 -12
  21. package/src/svgii/pathData_remove_collinear.js +31 -28
  22. package/src/svgii/pathData_remove_orphaned.js +5 -4
  23. package/src/svgii/pathData_remove_zerolength.js +8 -4
  24. package/src/svgii/pathData_reorder.js +6 -2
  25. package/src/svgii/pathData_simplify_refineCorners.js +160 -0
  26. package/src/svgii/{simplify_refineExtremes.js → pathData_simplify_refineExtremes.js} +78 -43
  27. package/src/svgii/pathData_split.js +42 -15
  28. package/src/svgii/pathData_stringify.js +3 -12
  29. package/src/svgii/rounding.js +16 -14
  30. package/src/svgii/svg_cleanup.js +1 -1
  31. package/src/pathData_simplify_cubic_arr.js +0 -50
  32. package/src/svgii/simplify.js +0 -248
  33. package/src/svgii/simplify_bezier.js +0 -470
  34. package/src/svgii/simplify_linetos.js +0 -93
@@ -1,470 +0,0 @@
1
- import { pathDataArcsToCubics, pathDataQuadraticToCubic, quadratic2Cubic, pathDataToRelative, pathDataToAbsolute, pathDataToLonghands, pathDataToShorthands, pathDataToQuadratic, cubicToQuad, arcToBezier, pathDataToVerbose, convertArrayPathData, revertPathDataToArray, cubicToArc } from './pathData_convert.js';
2
-
3
-
4
- import { getAngle, bezierhasExtreme, getDistance, getSquareDistance, pointAtT, checkLineIntersection, interpolate, getPointOnEllipse, commandIsFlat, getPathDataVertices } from "./geometry";
5
-
6
- import { getPathArea, getPolygonArea, getRelativeAreaDiff, getBezierAreaAccuracy } from "./geometry_area.js";
7
-
8
- import { renderPoint } from './visualize.js';
9
-
10
-
11
-
12
- /**
13
- * Function to simplify cubic Bézier sequences
14
- * thresh defines a threshold based on the
15
- * segment size
16
- * tolerance describes a percentage based deviation
17
- * comparing unoptimized against combined segment areas
18
- */
19
- export function simplifyBezierSequence(chunk, tolerance = 7.5, keepDetails = true, forceCubic = false) {
20
-
21
-
22
- //console.log('forceCubic simplifyBezierSequence', forceCubic);
23
- //tolerance = 20
24
-
25
- // t value for control point extrapolation
26
- const t = 1.333;
27
-
28
- // collect simplified path data commands
29
- let simplified = [];
30
- let Clen = chunk.length;
31
- let { type, p0, cp1, cp2 = null, p, values } = chunk[0];
32
-
33
- // get original chunk area for error detection
34
- let pathDataChunk = [{ type: 'M', values: [p0.x, p0.y] }, ...chunk];
35
-
36
- // unoptimized area
37
- let area0 = getPathArea(pathDataChunk);
38
-
39
- let p0_1, cp1_1, cp2_1, p_1;
40
- let cp1_2, cp2_2, p_2;
41
- let areaDiff, cp1_cubic, cp2_cubic;
42
-
43
- let indexEnd = chunk.length - 1;
44
- let indexMid = chunk.length > 2 ? Math.ceil(chunk.length / 2) - 1 : 1
45
-
46
- // compare accuracy
47
- let accurate = false;
48
- let areaDiff1 = 10000
49
- let areaDiff2 = 10000
50
- let areaDiff3 = 10000
51
- let comAreaDiff1, comAreaDiff2, comAreaDiff3;
52
- let ptMid, cp1_cubic_1, cp2_cubic_1, cp1_cubic_2, cp2_cubic_2, cp1_cubic_3, cp2_cubic_3;
53
- let areaCptPoly
54
-
55
- let log = []
56
- let c_3_1 = 0, c_3_2 = 0, c_2_1 = 0, c_2_2 = 0;
57
-
58
-
59
- /**
60
- * try to replace single cubics
61
- * with quadratic commands
62
- */
63
-
64
- //forceCubic = true;
65
- //if (area0 < 0.01) forceCubic = true;
66
-
67
- if (!forceCubic && Clen === 1 && type === 'C') {
68
-
69
- let thresh = area0 * 4;
70
- //check flatness
71
- let flatness = commandIsFlat([p0, cp1, cp2, p])
72
- areaCptPoly = flatness.area
73
-
74
-
75
- if (flatness.flat) {
76
- console.log('is flat cubic!');
77
- console.log(flatness, 'thresh');
78
-
79
- simplified = [{ type: 'L', values: [p.x, p.y] }];
80
- log.push('cubic to quadratic')
81
- return simplified
82
- }
83
-
84
-
85
- // quadratic controlpoint
86
- let cpQ = checkLineIntersection(p0, cp1, p, cp2, false);
87
- simplified = [chunk[0]];
88
-
89
- if (cpQ) {
90
- comAreaDiff1 = getBezierAreaAccuracy([p0, cpQ, p], area0, areaCptPoly, tolerance).areaDiff
91
-
92
- // can be converted to quadratic
93
- if (comAreaDiff1 < tolerance) {
94
- simplified = [{ type: 'Q', values: [cpQ.x, cpQ.y, p.x, p.y] }];
95
- log.push('cubic to quadratic')
96
- }
97
- }
98
- return simplified
99
- }
100
-
101
-
102
- if (Clen > 1) {
103
-
104
-
105
- //console.log(Clen, area0);
106
-
107
- /**
108
- * normalize quadratic
109
- * to cubics
110
- */
111
-
112
- // convert quadratic to cubic
113
-
114
- if (type === 'Q') {
115
- chunk.forEach((com, i) => {
116
- let c1 = quadratic2Cubic(com.p0, com.values);
117
-
118
- //console.log('com Q', com, c1);
119
- //let dQ = `M ${com.p0.x} ${com.p0.y} Q ${com.values.join(' ')}`
120
-
121
- let cp1 = { x: c1.values[0], y: c1.values[1] };
122
- let cp2 = { x: c1.values[2], y: c1.values[3] };
123
-
124
- //chunk[i] = {type:'C', values:[cp1_1.x, cp1_1.y, cp2_1.x, cp2_1.y, com.values[2], com.values[3]]};
125
- chunk[i].type = 'C'
126
- chunk[i].cp1 = cp1;
127
- chunk[i].cp2 = cp2;
128
- chunk[i].values = [cp1.x, cp1.y, cp2.x, cp2.y, com.p.x, com.p.y];
129
-
130
- //let d = `M ${com.p0.x} ${com.p0.y} C ${[cp1.x, cp1.y, cp2.x, cp2.y, com.p.x, com.p.y].join(' ')}`
131
- //renderPoint(svg1, p, 'orange')
132
- //console.log('dQ', dQ+d);
133
- })
134
-
135
- type = 'C';
136
- //console.log('chunk Q', chunk);
137
- }
138
-
139
-
140
- p0_1 = chunk[1].p0;
141
- cp1_1 = chunk[1].cp1;
142
- cp2_1 = type === 'C' ? chunk[1].cp2 : null;
143
- p_1 = chunk[1].p;
144
-
145
- //get end points
146
- p_2 = chunk[indexEnd].p;
147
- cp1_2 = chunk[indexEnd].cp1;
148
- cp2_2 = type === 'C' ? chunk[indexEnd].cp2 : chunk[indexEnd].cp1;
149
-
150
- areaCptPoly = getPolygonArea([p0, cp1, cp2_1, p_2])
151
- //console.log('cp2_2',p0_1, p_1, cp2_2, cp1_2, p_2, areaCptPoly);
152
-
153
-
154
- /**
155
- * check flatness of chunk
156
- * beziers might be linots
157
- */
158
-
159
-
160
- //console.log('forceCubic', forceCubic);
161
-
162
- //forceCubic= true
163
- if (!forceCubic) {
164
-
165
- //renderPoint(svg1, p, 'cyan' )
166
-
167
- let chunkPoints = chunk.map(com => { return [com.p0, com.cp1, com.cp2, com.p] }).flat()
168
- let { flat, ratio } = commandIsFlat(chunkPoints)
169
- //console.log('chunkPoints', chunkPoints, flat);
170
-
171
- /*
172
- if (flat) {
173
- let last = chunkPoints.slice(-1)[0]
174
- simplified.push({ type: 'L', values: [last.x, last.y] });
175
- //console.log('chunk flat', simplified, last);
176
- log.push('all commands are flat')
177
- return simplified
178
- }else{
179
- }
180
- */
181
- }
182
-
183
-
184
- }
185
-
186
-
187
- // 3 or more subsequent bezier segments
188
- if (Clen > 2) {
189
-
190
- /**
191
- * Cubics to Arcs:
192
- * educated guess -
193
- * check if control points build a right angle
194
- */
195
- let { com, isArc, area } = cubicToArc(p0, cp1, cp2_2, p_2);
196
- areaDiff = getRelativeAreaDiff(area0, area)
197
- //console.log('flat', chunkPoints, flatness);
198
- //renderPoint(svg1, p, 'cyan')
199
-
200
- // arc approximations should be more precise - otherwise we prefer cubics
201
- if (isArc && areaDiff < tolerance * 0.75) {
202
- simplified = [com];
203
- //renderPoint(svg1, p, 'orange')
204
- log.push('cubic to arc')
205
- return simplified
206
- }
207
-
208
-
209
- /**
210
- * more than 2 segments
211
- * try to interpolate tangents from
212
- * mid control point tangents
213
- */
214
-
215
- // get mid segment and get tangent intersection
216
- let p_m = chunk[indexMid].p;
217
- //console.log('indexMid', indexMid, chunk.length);
218
-
219
-
220
- // get mit segments cps
221
- let cpMid_1 = type === 'C' ? chunk[indexMid].cp2 : chunk[indexMid].cp1;
222
- let cp1_Int = checkLineIntersection(p_m, cpMid_1, p0, cp1, false);
223
-
224
-
225
- if (cp1_Int) {
226
- let cp2_Int = checkLineIntersection(p_m, cpMid_1, p_2, cp2_2, false);
227
- cp1_cubic = cp1_Int;
228
- cp2_cubic = cp2_Int;
229
-
230
- //renderPoint(svg1, cpMid_1, 'orange')
231
- //renderPoint(svg1, cp1_cubic, 'magenta')
232
- //renderPoint(svg1, cp2_cubic, 'cyan')
233
-
234
- // extrapolate control points
235
- cp1_cubic_1 = pointAtT([p0, cp1_cubic], t);
236
- cp2_cubic_1 = pointAtT([p_2, cp2_cubic], t);
237
-
238
- // test accuracy
239
- comAreaDiff1 = getBezierAreaAccuracy([p0, cp1_cubic_1, cp2_cubic_1, p_2], area0, areaCptPoly, tolerance);
240
- accurate = comAreaDiff1.accurate;
241
- areaDiff1 = comAreaDiff1.areaDiff
242
- areaDiff = areaDiff1;
243
-
244
- //console.log('3.1: ', areaDiff1);
245
-
246
- }
247
-
248
-
249
- /**
250
- * 2nd try
251
- * odd - calculate interpolated mid tangents
252
- */
253
- if (!accurate) {
254
- let controlPoints = type === 'C' ? [p0_1, cp1_1, cp2_1, p_1] : [p0_1, cp1_1, p_1];
255
-
256
- // interpolate mid point in mid segment and get cpts
257
- ptMid = pointAtT(controlPoints, 0.5, true, true);
258
-
259
- let cp1_mid = type === 'C' ? ptMid.cpts[2] : ptMid.cpts[0];
260
- cp1_cubic_2 = checkLineIntersection(ptMid, cp1_mid, cp1, p0, false);
261
- cp2_cubic_2 = checkLineIntersection(ptMid, cp1_mid, cp2_2, p_2, false);
262
-
263
-
264
- // extrapolate control points
265
- cp1_cubic_2 = pointAtT([p0, cp1_cubic_2], t);
266
- cp2_cubic_2 = pointAtT([p_2, cp2_cubic_2], t);
267
-
268
- // test accuracy
269
- comAreaDiff2 = getBezierAreaAccuracy([p0, cp1_cubic_2, cp2_cubic_2, p_2], area0, areaCptPoly, tolerance);
270
- accurate = comAreaDiff2.accurate;
271
- areaDiff2 = comAreaDiff2.areaDiff
272
- //console.log('3.2: ', areaDiff2);
273
-
274
- }
275
-
276
- // final
277
- cp1_cubic = areaDiff1 < areaDiff2 ? cp1_cubic_1 : cp1_cubic_2
278
- cp2_cubic = areaDiff1 < areaDiff2 ? cp2_cubic_1 : cp2_cubic_2
279
- areaDiff = areaDiff1 < areaDiff2 ? areaDiff1 : areaDiff2
280
- log.push(areaDiff1 < areaDiff2 ? '3.1 is better' : '3.2 is better')
281
-
282
-
283
- if (areaDiff < tolerance) {
284
- //renderPoint(svg1, p, 'magenta')
285
- }
286
-
287
-
288
- }
289
-
290
- // combine 2 cubic segments
291
- else if (Clen === 2) {
292
-
293
-
294
- cp2_1 = chunk[0].cp2;
295
- cp2_2 = chunk[1].cp2;
296
-
297
- /**
298
- * Approach 1:
299
- * get combined control points
300
- * by extrapolating mid tangent intersection
301
- */
302
-
303
- // Get cp intersection point
304
- let cpI, cp1_cubicInter, cp2_cubicInter;
305
-
306
- cpI = checkLineIntersection(p0, cp1, cp2_2, p_2, false);
307
- if (cpI) {
308
- //console.log('2 cubics:', p, cp2_1, p0, cpI);
309
- cp1_cubicInter = checkLineIntersection(p, cp2_1, p0, cpI, false);
310
- cp2_cubicInter = checkLineIntersection(p, cp1_2, p_2, cpI, false);
311
-
312
- // extrapolate control points
313
- cp1_cubic_1 = pointAtT([p0, cp1_cubicInter], t);
314
- cp2_cubic_1 = pointAtT([p_2, cp2_cubicInter], t);
315
-
316
- // get area to detect sign changes
317
- comAreaDiff1 = getBezierAreaAccuracy([p0, cp1_cubic_1, cp2_cubic_1, p_2], area0, areaCptPoly, tolerance);
318
-
319
- accurate = comAreaDiff1.accurate;
320
- areaDiff1 = comAreaDiff1.areaDiff
321
- }
322
-
323
- //console.log('2.1: ', areaDiff1, cp1_cubic_1, cp2_cubic_1);
324
- //renderPoint(svg1, cp1_cubic_1, 'cyan')
325
- //renderPoint(svg1, cp2_cubic_1, 'orange')
326
- //renderPoint(svg1, p, 'magenta')
327
-
328
- if (comAreaDiff1 < tolerance) {
329
- //renderPoint(svg1, p, 'blue')
330
- }
331
-
332
-
333
- /**
334
- * If Approach 1 is too imprecise:
335
- * Approach 2:
336
- * add segments' cp tangents lengths for
337
- * combined control points
338
- */
339
-
340
- if (!accurate) {
341
-
342
- // 1 distances between "tangent handles"
343
- let t0Length = getDistance(p0, cp1_1);
344
- let t1Length = getDistance(p_1, cp2_2);
345
-
346
- // new average tangent length
347
- let t2Length = t0Length + t1Length;
348
- let tRat0 = t2Length / t0Length;
349
- let tRat1 = t2Length / t1Length;
350
-
351
- // extrapolate cp tangents
352
- cp1_cubic_2 = pointAtT([p0, cp1_1], tRat0);
353
- cp2_cubic_2 = pointAtT([p_1, cp2_2], tRat1);
354
-
355
- // accuracy
356
- comAreaDiff2 = getBezierAreaAccuracy([p0, cp1_cubic_2, cp2_cubic_2, p_2], area0, areaCptPoly, tolerance);
357
- accurate = comAreaDiff2.accurate;
358
- areaDiff2 = comAreaDiff2.areaDiff
359
-
360
- // renderPoint(svg1, cp1_cubic_2, 'cyan')
361
- // renderPoint(svg1, cp2_cubic_2, 'orange')
362
-
363
- }
364
-
365
- /**
366
- * 3rd try
367
- * take larger segment as reference
368
- */
369
-
370
- if (!accurate) {
371
-
372
- //[p0, cp1, cp2, p] = chunk[0];
373
- //console.log('chunk[0]', chunk[0]);
374
-
375
- cp1 = chunk[0].cp1
376
- cp2 = chunk[0].cp2
377
- p = chunk[0].p
378
-
379
- let controlPoints = [p0, cp1, cp2, p]
380
-
381
- // interpolate mid point in mid segment and get cpts
382
- ptMid = pointAtT(controlPoints, 0.5, true, true);
383
-
384
- let cp1_mid = type === 'C' ? ptMid.cpts[2] : ptMid.cpts[0];
385
- cp1_cubic_3 = checkLineIntersection(ptMid, cp1_mid, cp1, p0, false);
386
- cp2_cubic_3 = checkLineIntersection(ptMid, cp1_mid, cp2_2, p_2, false);
387
-
388
-
389
- // extrapolate control points
390
- cp1_cubic_3 = pointAtT([p0, cp1_cubic_3], t);
391
- cp2_cubic_3 = pointAtT([p_2, cp2_cubic_3], t);
392
-
393
-
394
- // test accuracy
395
- comAreaDiff2 = getBezierAreaAccuracy([p0, cp1_cubic_3, cp2_cubic_3, p_2], area0, areaCptPoly, tolerance);
396
- accurate = comAreaDiff2.accurate;
397
- areaDiff3 = comAreaDiff2.areaDiff
398
-
399
- if (areaDiff3 < tolerance && areaDiff3 < areaDiff2) {
400
- cp1_cubic_2 = cp1_cubic_3
401
- cp2_cubic_2 = cp2_cubic_3
402
- areaDiff2 = areaDiff3
403
- //console.log('2.3');
404
- log.push(areaDiff3 < areaDiff2 ? '2.3 is better' : '2.2 is better', areaDiff3, areaDiff2)
405
- }
406
-
407
- }
408
-
409
- // final
410
- cp1_cubic = areaDiff1 < areaDiff2 ? cp1_cubic_1 : cp1_cubic_2
411
- cp2_cubic = areaDiff1 < areaDiff2 ? cp2_cubic_1 : cp2_cubic_2
412
- areaDiff = areaDiff1 < areaDiff2 ? areaDiff1 : areaDiff2
413
-
414
- //cp1_cubic = cp1_cubic_1
415
- //cp2_cubic = cp2_cubic_1
416
-
417
-
418
- if (areaDiff < tolerance) {
419
- /*
420
- let polyArea = getPolygonArea([p0,cp1_cubic, cp2_cubic, p_2 ])
421
-
422
- //console.log('area0', area0, areaDiff, comAreaDiff2, comAreaDiff3, comAreaDiff1);
423
- console.log('area0', area0, 'areaDiff', areaDiff, 'tolerance', tolerance, comAreaDiff1, comAreaDiff2, comAreaDiff3, 'polyArea', polyArea);
424
- renderPoint(svg1, p, 'blue')
425
- renderPoint(svg1, cp1_cubic, 'magenta')
426
- renderPoint(svg1, cp2_cubic, 'orange')
427
- */
428
- }
429
-
430
- log.push(areaDiff1 < areaDiff2 ? '2.1 is better' : '2.2 is better', areaDiff1, areaDiff2)
431
-
432
-
433
- }
434
-
435
-
436
- // no cpts - return original
437
- if (!cp1_cubic || !cp2_cubic) {
438
- //console.log('no cpts', [...chunk]);
439
- return [...chunk];
440
- //return [...chunk];
441
- }
442
-
443
-
444
- // !!! CAN be simplified
445
- if (areaDiff < tolerance) {
446
- //console.log('!!! IS simplified!!!', area0, areaDiff, tolerance);
447
- simplified.push({ type: 'C', values: [cp1_cubic.x, cp1_cubic.y, cp2_cubic.x, cp2_cubic.y, p_2.x, p_2.y] });
448
- }
449
-
450
- // !!! no way to simplify
451
- else {
452
- //simplified = [...chunk];
453
- simplified = chunk;
454
- //console.log('not simplified!!!', areaDiff, 'area0:', area0, 'areaSimple', areaSimple, tolerance);
455
- /*
456
- let d = comSimple.map(com => { return `${com.type} ${com.values.join(' ')}` }).join(' ')
457
- let d0 = pathDataChunk.map(com => { return `${com.type} ${com.values.join(' ')}` }).join(' ')
458
- */
459
-
460
- }
461
-
462
- let diffCom = pathDataChunk.length - simplified.length
463
- log.push('saved:' + diffCom, 'results:' + [c_3_1, c_3_2, c_2_1, c_2_2].join(', '))
464
-
465
- //console.log(log);
466
-
467
- return simplified;
468
- }
469
-
470
-
@@ -1,93 +0,0 @@
1
- import { getAngle, bezierhasExtreme, getPathDataVertices, svgArcToCenterParam, getSquareDistance, commandIsFlat } from "./geometry";
2
- import { renderPoint } from "./visualize";
3
- //import { renderPoint, renderPath } from "./visualize";
4
-
5
-
6
-
7
-
8
- export function simplifyLinetoSequence(chunk, thresh = 0.1) {
9
-
10
-
11
- let valuesL = chunk[0].values.slice(-2).map(val => +val.toFixed(8))
12
- let p0 = chunk[0].p0
13
- //let p0 = { x: valuesL[0], y: valuesL[1] }
14
- let p = p0;
15
- let simplified = [];
16
-
17
- //console.log('chunk lineto', chunk);
18
- //renderPoint(svg1, p0, 'orange')
19
-
20
-
21
- for (let i = 1, len = chunk.length; i < len; i++) {
22
- let com = chunk[i - 1];
23
- valuesL = com.values.slice(-2).map(val => +val.toFixed(8))
24
- p = { x: valuesL[0], y: valuesL[1] }
25
-
26
-
27
- // zero length
28
- if ((p.x === p0.x && p.y === p0.y)) {
29
- console.log('zero length', com);
30
- p0 = p
31
- continue
32
- }
33
-
34
- // check flatness
35
- let comN = chunk[i];
36
- let valuesNL = comN.values.slice(-2)
37
- let pN = { x: valuesNL[0], y: valuesNL[1] }
38
-
39
-
40
-
41
- // check if adjacent linetos are flat
42
- let flatness = commandIsFlat([p0, p, pN])
43
- let isFlatN = flatness.flat;
44
-
45
- //renderPoint(svg1, pN, 'blue', '0.5%')
46
-
47
- /*
48
- if (!isFlatN) {
49
- renderPoint(svg1, p, 'orange', '0.75%')
50
- console.log( flatness, thresh);
51
- renderPoint(svg1, p0, 'cyan', '1%', '0.5')
52
- renderPoint(svg1, pN, 'magenta', '0.5%')
53
- }
54
- */
55
-
56
- // next lineto is flat – don't add command
57
- if (isFlatN) {
58
-
59
- // check angles
60
- let ang1 = getAngle(p0, p, true)
61
- let ang2 = getAngle(p, pN, true)
62
- let angDiff = Math.abs(ang1 - ang2)
63
- //*180/Math.PI
64
- //console.log(angDiff, flatness, thresh);
65
-
66
- if (angDiff < Math.PI / 4) {
67
- //renderPoint(svg1, p0, 'cyan', '1%', '0.5')
68
- //renderPoint(svg1, p, 'magenta', '0.5%')
69
- //p0 = p
70
- continue
71
-
72
- }
73
-
74
-
75
- //console.log('flat', flatness, 'thresh', thresh, dist, p0, p);
76
- // update p0
77
- }
78
-
79
-
80
- p0 = p
81
-
82
- simplified.push(com)
83
- }
84
-
85
-
86
- // always add last command in chunk
87
- simplified.push(chunk[chunk.length - 1])
88
-
89
- //simplified.push(...chunk)
90
-
91
- return simplified;
92
-
93
- }