svg-path-simplify 0.1.3 → 0.2.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.
- package/README.md +10 -0
- package/dist/svg-path-simplify.esm.js +3905 -1533
- package/dist/svg-path-simplify.esm.min.js +13 -1
- package/dist/svg-path-simplify.js +3923 -1551
- package/dist/svg-path-simplify.min.js +13 -1
- package/dist/svg-path-simplify.min.js.gz +0 -0
- package/index.html +61 -31
- package/package.json +3 -5
- package/src/constants.js +3 -0
- package/src/index-node.js +0 -1
- package/src/index.js +26 -0
- package/src/pathData_simplify_cubic.js +74 -31
- package/src/pathData_simplify_cubicsToArcs.js +566 -0
- package/src/pathData_simplify_harmonize_cpts.js +170 -0
- package/src/pathData_simplify_revertToquadratics.js +21 -0
- package/src/pathSimplify-main.js +253 -86
- package/src/poly-fit-curve-schneider.js +570 -0
- package/src/simplify_poly_RDP.js +146 -0
- package/src/simplify_poly_radial_distance.js +100 -0
- package/src/svg_getViewbox.js +1 -1
- package/src/svgii/geometry.js +389 -63
- package/src/svgii/geometry_area.js +2 -1
- package/src/svgii/pathData_analyze.js +259 -212
- package/src/svgii/pathData_convert.js +91 -663
- package/src/svgii/pathData_fromPoly.js +12 -0
- package/src/svgii/pathData_parse.js +90 -89
- package/src/svgii/pathData_parse_els.js +3 -0
- package/src/svgii/pathData_parse_fontello.js +449 -0
- package/src/svgii/pathData_remove_collinear.js +44 -37
- package/src/svgii/pathData_reorder.js +2 -1
- package/src/svgii/pathData_simplify_redraw.js +343 -0
- package/src/svgii/pathData_simplify_refineCorners.js +18 -9
- package/src/svgii/pathData_simplify_refineExtremes.js +19 -78
- package/src/svgii/pathData_split.js +42 -45
- package/src/svgii/pathData_toPolygon.js +130 -4
- package/src/svgii/poly_analyze.js +470 -14
- package/src/svgii/poly_to_pathdata.js +224 -19
- package/src/svgii/rounding.js +55 -112
- package/src/svgii/svg_cleanup.js +13 -1
- package/src/svgii/visualize.js +8 -3
- package/{debug.cjs → tests/debug.cjs} +3 -0
- /package/{test.js → tests/test.js} +0 -0
- /package/{testSVG.js → tests/testSVG.js} +0 -0
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import { getPathDataVertices, getPointOnEllipse, pointAtT, checkLineIntersection, getDistance, interpolate, getAngle } from './geometry.js';
|
|
4
4
|
|
|
5
5
|
import { splitSubpaths } from "./convert_segments";
|
|
6
|
-
|
|
7
|
-
|
|
8
6
|
import { getPolygonArea, getPathArea, getRelativeAreaDiff } from './geometry_area.js';
|
|
9
7
|
import { splitSubpaths } from './pathData_split.js';
|
|
10
8
|
import { getPolyBBox} from './geometry_bbox.js';
|
|
@@ -12,7 +10,7 @@ import { renderPoint, renderPath } from "./visualize";
|
|
|
12
10
|
*/
|
|
13
11
|
|
|
14
12
|
|
|
15
|
-
import { checkLineIntersection, getAngle, getDeltaAngle, getDistance, getDistAv, getSquareDistance, interpolate, pointAtT, rotatePoint, toParametricAngle } from './geometry';
|
|
13
|
+
import { checkLineIntersection, getAngle, getDeltaAngle, getDistance, getDistAv, getDistManhattan, getSquareDistance, interpolate, pointAtT, rotatePoint, toParametricAngle } from './geometry';
|
|
16
14
|
import { getPathArea, getPolygonArea, getRelativeAreaDiff } from './geometry_area';
|
|
17
15
|
import { pathDataToD } from './pathData_stringify';
|
|
18
16
|
import { roundPathData } from './rounding';
|
|
@@ -53,15 +51,49 @@ export function revertCubicQuadratic(p0 = {}, cp1 = {}, cp2 = {}, p = {}) {
|
|
|
53
51
|
|
|
54
52
|
export function convertPathData(pathData, {
|
|
55
53
|
toShorthands = true,
|
|
54
|
+
toLonghands = false,
|
|
56
55
|
toRelative = true,
|
|
57
|
-
|
|
56
|
+
toAbsolute = false,
|
|
57
|
+
decimals = 3,
|
|
58
|
+
arcToCubic = false,
|
|
59
|
+
quadraticToCubic = false,
|
|
60
|
+
|
|
61
|
+
// assume we need full normalization
|
|
62
|
+
hasRelatives = true,
|
|
63
|
+
hasShorthands = true,
|
|
64
|
+
hasQuadratics = true,
|
|
65
|
+
hasArcs = true,
|
|
66
|
+
testTypes = false
|
|
67
|
+
|
|
68
|
+
|
|
58
69
|
} = {}) {
|
|
59
70
|
|
|
71
|
+
// pathdata properties - test= true adds a manual test
|
|
72
|
+
if (testTypes) {
|
|
73
|
+
//console.log('test for conversions');
|
|
74
|
+
let commands = Array.from(new Set(pathData.map(com => com.type))).join('');
|
|
75
|
+
hasRelatives = /[lcqamts]/gi.test(commands);
|
|
76
|
+
hasQuadratics = /[qt]/gi.test(commands);
|
|
77
|
+
hasArcs = /[a]/gi.test(commands);
|
|
78
|
+
hasShorthands = /[vhst]/gi.test(commands);
|
|
79
|
+
isPoly = /[mlz]/gi.test(commands);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
// some params exclude each other
|
|
84
|
+
toRelative = toAbsolute ? false : toRelative;
|
|
85
|
+
toShorthands = toLonghands ? false : toShorthands
|
|
86
|
+
|
|
60
87
|
|
|
61
88
|
//console.log(toShorthands, toRelative, decimals);
|
|
89
|
+
if (hasQuadratics && quadraticToCubic) pathData = pathDataQuadraticToCubic(pathData);
|
|
90
|
+
if (hasArcs && arcToCubic) pathData = pathDataArcsToCubics(pathData);
|
|
62
91
|
|
|
63
92
|
//if(decimals>-1 && decimals<2) pathData = roundPathData(pathData, decimals);
|
|
64
93
|
if (toShorthands) pathData = pathDataToShorthands(pathData);
|
|
94
|
+
if (hasShorthands && toLonghands) pathData = pathDataToLonghands(pathData);
|
|
95
|
+
|
|
96
|
+
if (toAbsolute) pathData = pathDataToAbsolute(pathData);
|
|
65
97
|
|
|
66
98
|
// pre round - before relative conversion to minimize distortions
|
|
67
99
|
if (decimals > -1 && toRelative) pathData = roundPathData(pathData, decimals);
|
|
@@ -174,37 +206,36 @@ export function pathDataToAbsoluteOrRelative(pathData, toRelative = false, decim
|
|
|
174
206
|
pathData[0].values = pathData[0].values.map(val => +val.toFixed(decimals));
|
|
175
207
|
}
|
|
176
208
|
|
|
209
|
+
let len = pathData.length;
|
|
177
210
|
let M = pathData[0].values;
|
|
178
211
|
let x = M[0],
|
|
179
212
|
y = M[1],
|
|
180
213
|
mx = x,
|
|
181
214
|
my = y;
|
|
182
215
|
|
|
183
|
-
for (let i = 1
|
|
216
|
+
for (let i = 1; i < len; i++) {
|
|
184
217
|
let com = pathData[i];
|
|
185
218
|
let { type, values } = com;
|
|
186
|
-
let
|
|
219
|
+
let vLen = values.length;
|
|
220
|
+
let typeRel = type.toLowerCase();
|
|
221
|
+
let typeAbs =type.toUpperCase();
|
|
222
|
+
let typeNew = toRelative ? typeRel : typeAbs;
|
|
187
223
|
|
|
188
|
-
if (type !==
|
|
189
|
-
type =
|
|
190
|
-
com.type = type;
|
|
224
|
+
if (type !== typeNew) {
|
|
225
|
+
com.type = typeNew;
|
|
191
226
|
|
|
192
|
-
switch (
|
|
227
|
+
switch (typeRel) {
|
|
193
228
|
case "a":
|
|
194
|
-
case "A":
|
|
195
229
|
values[5] = toRelative ? values[5] - x : values[5] + x;
|
|
196
230
|
values[6] = toRelative ? values[6] - y : values[6] + y;
|
|
197
231
|
break;
|
|
198
232
|
case "v":
|
|
199
|
-
case "V":
|
|
200
233
|
values[0] = toRelative ? values[0] - y : values[0] + y;
|
|
201
234
|
break;
|
|
202
235
|
case "h":
|
|
203
|
-
case "H":
|
|
204
236
|
values[0] = toRelative ? values[0] - x : values[0] + x;
|
|
205
237
|
break;
|
|
206
238
|
case "m":
|
|
207
|
-
case "M":
|
|
208
239
|
if (toRelative) {
|
|
209
240
|
values[0] -= x;
|
|
210
241
|
values[1] -= y;
|
|
@@ -226,23 +257,18 @@ export function pathDataToAbsoluteOrRelative(pathData, toRelative = false, decim
|
|
|
226
257
|
}
|
|
227
258
|
}
|
|
228
259
|
|
|
229
|
-
|
|
230
|
-
switch (type) {
|
|
260
|
+
switch (typeRel) {
|
|
231
261
|
case "z":
|
|
232
|
-
case "Z":
|
|
233
262
|
x = mx;
|
|
234
263
|
y = my;
|
|
235
264
|
break;
|
|
236
265
|
case "h":
|
|
237
|
-
case "H":
|
|
238
266
|
x = toRelative ? x + values[0] : values[0];
|
|
239
267
|
break;
|
|
240
268
|
case "v":
|
|
241
|
-
case "V":
|
|
242
269
|
y = toRelative ? y + values[0] : values[0];
|
|
243
270
|
break;
|
|
244
271
|
case "m":
|
|
245
|
-
case "M":
|
|
246
272
|
mx = values[vLen - 2] + (toRelative ? x : 0);
|
|
247
273
|
my = values[vLen - 1] + (toRelative ? y : 0);
|
|
248
274
|
default:
|
|
@@ -386,7 +412,6 @@ export function pathDataToShorthands(pathData, decimals = -1, test = false) {
|
|
|
386
412
|
|
|
387
413
|
//pathData = JSON.parse(JSON.stringify(pathData))
|
|
388
414
|
//console.log('has dec', pathData);
|
|
389
|
-
|
|
390
415
|
/**
|
|
391
416
|
* analyze pathdata – if you're sure your data is already absolute skip it via test=false
|
|
392
417
|
*/
|
|
@@ -401,47 +426,67 @@ export function pathDataToShorthands(pathData, decimals = -1, test = false) {
|
|
|
401
426
|
let len = pathData.length
|
|
402
427
|
let pathDataShorts = new Array(len);
|
|
403
428
|
|
|
404
|
-
let comShort =
|
|
405
|
-
type: "M",
|
|
406
|
-
values: pathData[0].values
|
|
407
|
-
};
|
|
408
|
-
|
|
429
|
+
let comShort = pathData[0]
|
|
409
430
|
pathDataShorts[0] = comShort;
|
|
410
431
|
|
|
411
432
|
let p0 = { x: pathData[0].values[0], y: pathData[0].values[1] };
|
|
412
|
-
let p;
|
|
413
|
-
let tolerance = 0.01
|
|
433
|
+
let p = p0;
|
|
414
434
|
|
|
415
435
|
for (let i = 1; i < len; i++) {
|
|
416
436
|
|
|
417
437
|
let com = pathData[i];
|
|
438
|
+
comShort = com;
|
|
418
439
|
let { type, values } = com;
|
|
419
440
|
let valuesLen = values.length;
|
|
420
441
|
let valuesLast = [values[valuesLen - 2], values[valuesLen - 1]];
|
|
421
442
|
|
|
422
|
-
//
|
|
443
|
+
// previous command
|
|
423
444
|
let comPrev = pathData[i - 1];
|
|
424
|
-
let typePrev = comPrev.type
|
|
425
445
|
|
|
426
446
|
//last on-path point
|
|
427
447
|
p = { x: valuesLast[0], y: valuesLast[1] };
|
|
428
448
|
|
|
449
|
+
// deltas for h or v
|
|
450
|
+
let dx = Math.abs(p.x - p0.x)
|
|
451
|
+
let dy = Math.abs(p.y - p0.y)
|
|
452
|
+
let maxDist = getDistManhattan(p0, p) * 0.01
|
|
453
|
+
|
|
454
|
+
|
|
429
455
|
// first bezier control point for S/T shorthand tests
|
|
430
|
-
let
|
|
456
|
+
let isShort = false, isHorizontal = false, isVertical = false;
|
|
431
457
|
|
|
458
|
+
if ((type === 'C' && comPrev.type === 'C') || (type === 'Q' && comPrev.type === 'Q')) {
|
|
459
|
+
let cpPrev = comPrev.type === 'C' ? { x: comPrev.values[2], y: comPrev.values[3] } : { x: comPrev.values[0], y: comPrev.values[1] };
|
|
460
|
+
let cpFirst = { x: values[0], y: values[1] };
|
|
432
461
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
let h = Math.abs(p.y - p0.y)
|
|
436
|
-
let thresh = (w + h) / 2 * tolerance
|
|
462
|
+
let dx1 = (p0.x - cpPrev.x)
|
|
463
|
+
let dy1 = (p0.y - cpPrev.y)
|
|
437
464
|
|
|
438
|
-
|
|
465
|
+
//adjust maxDist
|
|
466
|
+
maxDist = getDistManhattan(cpPrev, cpFirst) * 0.05
|
|
467
|
+
|
|
468
|
+
// reflected cp
|
|
469
|
+
let cpR = { x: cpPrev.x + dx1 * 2, y: cpPrev.y + dy1 * 2 }
|
|
470
|
+
let distCp = getDistManhattan(cpR, cpFirst)
|
|
471
|
+
|
|
472
|
+
isShort = distCp < maxDist;
|
|
473
|
+
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
else if (type === 'L') {
|
|
477
|
+
isHorizontal = dy === 0 || dy < maxDist;
|
|
478
|
+
isVertical = dx === 0 || dx < maxDist;
|
|
479
|
+
isShort = isVertical || isHorizontal;
|
|
480
|
+
|
|
481
|
+
if (isShort) {
|
|
482
|
+
//renderPoint(markers, p, 'magenta')
|
|
483
|
+
}
|
|
484
|
+
}
|
|
439
485
|
|
|
440
486
|
|
|
441
487
|
switch (type) {
|
|
442
488
|
case "L":
|
|
443
|
-
|
|
444
|
-
if (h === 0 || (h < thresh && w > thresh)) {
|
|
489
|
+
if (isHorizontal) {
|
|
445
490
|
//console.log('is H');
|
|
446
491
|
comShort = {
|
|
447
492
|
type: "H",
|
|
@@ -450,83 +495,34 @@ export function pathDataToShorthands(pathData, decimals = -1, test = false) {
|
|
|
450
495
|
}
|
|
451
496
|
|
|
452
497
|
// V
|
|
453
|
-
|
|
498
|
+
if (isVertical) {
|
|
454
499
|
//console.log('is V', w, h);
|
|
455
500
|
comShort = {
|
|
456
501
|
type: "V",
|
|
457
502
|
values: [values[1]]
|
|
458
503
|
};
|
|
459
|
-
}
|
|
460
|
-
//console.log('not', type, h, w, thresh, com);
|
|
461
|
-
comShort = com;
|
|
462
|
-
}
|
|
463
|
-
|
|
504
|
+
}
|
|
464
505
|
break;
|
|
465
506
|
|
|
466
507
|
case "Q":
|
|
467
508
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
//console.log('skip T:', type, typePrev);
|
|
471
|
-
p0 = { x: valuesLast[0], y: valuesLast[1] };
|
|
472
|
-
//pathDataShorts.push(com);
|
|
473
|
-
pathDataShorts[i] = com;
|
|
474
|
-
continue;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
let cp1_prev = { x: comPrev.values[0], y: comPrev.values[1] };
|
|
478
|
-
// reflected Q control points
|
|
479
|
-
cp1_reflected = { x: (2 * p0.x - cp1_prev.x), y: (2 * p0.y - cp1_prev.y) };
|
|
480
|
-
|
|
481
|
-
//let thresh = (diffX+diffY)/2
|
|
482
|
-
diffX = Math.abs(cp1.x - cp1_reflected.x)
|
|
483
|
-
diffY = Math.abs(cp1.y - cp1_reflected.y)
|
|
484
|
-
diff = (diffX + diffY) / 2
|
|
485
|
-
|
|
486
|
-
if (diff < thresh) {
|
|
487
|
-
//console.log('is T', diff, thresh);
|
|
509
|
+
if (isShort) {
|
|
510
|
+
//comShort = com;
|
|
488
511
|
comShort = {
|
|
489
512
|
type: "T",
|
|
490
513
|
values: [p.x, p.y]
|
|
491
514
|
};
|
|
492
|
-
} else {
|
|
493
|
-
comShort = com;
|
|
494
515
|
}
|
|
495
516
|
|
|
496
517
|
break;
|
|
497
518
|
case "C":
|
|
498
|
-
|
|
499
|
-
let cp2 = { x: values[2], y: values[3] };
|
|
500
|
-
|
|
501
|
-
if (typePrev !== 'C') {
|
|
502
|
-
//console.log('skip S', typePrev);
|
|
503
|
-
//pathDataShorts.push(com);
|
|
504
|
-
pathDataShorts[i] = com;
|
|
505
|
-
|
|
506
|
-
p0 = { x: valuesLast[0], y: valuesLast[1] };
|
|
507
|
-
continue;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
let cp2_prev = { x: comPrev.values[2], y: comPrev.values[3] };
|
|
511
|
-
|
|
512
|
-
// reflected C control points
|
|
513
|
-
cp1_reflected = { x: (2 * p0.x - cp2_prev.x), y: (2 * p0.y - cp2_prev.y) };
|
|
514
|
-
|
|
515
|
-
//let thresh = (diffX+diffY)/2
|
|
516
|
-
diffX = Math.abs(cp1.x - cp1_reflected.x)
|
|
517
|
-
diffY = Math.abs(cp1.y - cp1_reflected.y)
|
|
518
|
-
diff = (diffX + diffY) / 2
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (diff < thresh) {
|
|
519
|
+
if (isShort) {
|
|
522
520
|
//console.log('is S');
|
|
523
521
|
comShort = {
|
|
524
522
|
type: "S",
|
|
525
|
-
values: [
|
|
523
|
+
values: [values[2], values[3], p.x, p.y]
|
|
526
524
|
};
|
|
527
|
-
}
|
|
528
|
-
comShort = com;
|
|
529
|
-
}
|
|
525
|
+
}
|
|
530
526
|
break;
|
|
531
527
|
default:
|
|
532
528
|
comShort = {
|
|
@@ -535,19 +531,8 @@ export function pathDataToShorthands(pathData, decimals = -1, test = false) {
|
|
|
535
531
|
};
|
|
536
532
|
}
|
|
537
533
|
|
|
538
|
-
|
|
539
|
-
if (com.decimals || com.decimals === 0) {
|
|
540
|
-
comShort.decimals = com.decimals
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// round final values
|
|
544
|
-
if (decimals > -1) {
|
|
545
|
-
comShort.values = comShort.values.map(val => { return +val.toFixed(decimals) })
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
p0 = { x: valuesLast[0], y: valuesLast[1] };
|
|
534
|
+
p0 = p;
|
|
549
535
|
pathDataShorts[i] = comShort;
|
|
550
|
-
//pathDataShorts.push(comShort);
|
|
551
536
|
}
|
|
552
537
|
|
|
553
538
|
//console.log('pathDataShorts', pathDataShorts);
|
|
@@ -968,560 +953,3 @@ export function convertArrayPathData(pathDataArray) {
|
|
|
968
953
|
return pathData;
|
|
969
954
|
}
|
|
970
955
|
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
/**
|
|
977
|
-
* cubics to arcs
|
|
978
|
-
*/
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
export function combineCubicsToArcs(pathData = [], {
|
|
982
|
-
threshold = 0,
|
|
983
|
-
} = {}) {
|
|
984
|
-
|
|
985
|
-
let l = pathData.length;
|
|
986
|
-
let pathDataN = [pathData[0]];
|
|
987
|
-
|
|
988
|
-
for (let i = 1; i < l; i++) {
|
|
989
|
-
let com = pathData[i];
|
|
990
|
-
let { type, cp1 = null, cp2 = null, p0, p } = com;
|
|
991
|
-
let comP = pathData[i - 1];
|
|
992
|
-
let comN = pathData[i + 1] ? pathData[i + 1] : null;
|
|
993
|
-
let comN2 = pathData[i + 2] ? pathData[i + 2] : null;
|
|
994
|
-
|
|
995
|
-
if (type === 'C' && comN && comN.type === 'C') {
|
|
996
|
-
|
|
997
|
-
let thresh = getDistAv(p0, p) * 0.02;
|
|
998
|
-
//thresh = getDistAv(p0, p) * 10000;
|
|
999
|
-
|
|
1000
|
-
let dx1 = Math.abs(p0.x - cp1.x)
|
|
1001
|
-
let dy1 = Math.abs(p0.y - cp1.y)
|
|
1002
|
-
|
|
1003
|
-
let isHorizontal1 = dy1 < thresh;
|
|
1004
|
-
let isVertical1 = dx1 < thresh;
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
let dx2 = Math.abs(comN.p0.x - comN.cp1.x)
|
|
1008
|
-
let dy2 = Math.abs(comN.p0.y - comN.cp1.y)
|
|
1009
|
-
|
|
1010
|
-
let isHorizontal2 = dy2 < thresh;
|
|
1011
|
-
let isVertical2 = dx2 < thresh;
|
|
1012
|
-
|
|
1013
|
-
//console.log(isHorizontal1, isVertical1);
|
|
1014
|
-
|
|
1015
|
-
// check angles
|
|
1016
|
-
let angleDiff1 = (isHorizontal1 || isVertical1) ? 0 : Infinity;
|
|
1017
|
-
let angleDiff2 = (isHorizontal2 || isVertical2) ? 0 : Infinity;
|
|
1018
|
-
|
|
1019
|
-
if (!isHorizontal1 && !isVertical1) {
|
|
1020
|
-
//console.log('get angles', isHorizontal1, isVertical1);
|
|
1021
|
-
let angle1 = getAngle(p0, cp1, true);
|
|
1022
|
-
let angle2 = getAngle(p, cp2, true);
|
|
1023
|
-
let deltaAngle = Math.abs(angle1 - angle2) * 180 / Math.PI;
|
|
1024
|
-
angleDiff1 = Math.abs((deltaAngle % 180) - 90);
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
if (!isHorizontal2 && !isVertical2) {
|
|
1028
|
-
//console.log('get angles', isHorizontal1, isVertical1);
|
|
1029
|
-
let angle1 = getAngle(p0, cp1, true);
|
|
1030
|
-
let angle2 = getAngle(p, cp2, true);
|
|
1031
|
-
let deltaAngle = Math.abs(angle1 - angle2) * 180 / Math.PI;
|
|
1032
|
-
angleDiff2 = Math.abs((deltaAngle % 180) - 90);
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
let isRightAngle1 = angleDiff1 < 3;
|
|
1037
|
-
let isRightAngle2 = angleDiff2 < 3;
|
|
1038
|
-
|
|
1039
|
-
let centroids = [];
|
|
1040
|
-
let poly = [];
|
|
1041
|
-
let rArr = []
|
|
1042
|
-
let largeArc = 0;
|
|
1043
|
-
|
|
1044
|
-
// final on path point
|
|
1045
|
-
let p_a = p
|
|
1046
|
-
|
|
1047
|
-
// 2 possible candidates - test radius
|
|
1048
|
-
if (isRightAngle1 && isRightAngle2) {
|
|
1049
|
-
//renderPoint(markers, com.p)
|
|
1050
|
-
|
|
1051
|
-
let pI = checkLineIntersection(p0, cp1, p, cp2, false);
|
|
1052
|
-
let r1 = getDistance(p0, pI);
|
|
1053
|
-
let r2 = getDistance(p, pI);
|
|
1054
|
-
let rDiff1 = Math.abs(r1 - r2)
|
|
1055
|
-
//let r = r1
|
|
1056
|
-
|
|
1057
|
-
rArr.push(r1, r2)
|
|
1058
|
-
|
|
1059
|
-
poly.push(p0, p)
|
|
1060
|
-
p_a = p
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
// 2 commands can be combined – similar radii
|
|
1064
|
-
if (rDiff1 < thresh) {
|
|
1065
|
-
|
|
1066
|
-
//renderPoint(markers, com.p)
|
|
1067
|
-
|
|
1068
|
-
// add to polygon for sweep
|
|
1069
|
-
poly.push(comN.p)
|
|
1070
|
-
|
|
1071
|
-
// update final point
|
|
1072
|
-
p_a = comN.p
|
|
1073
|
-
|
|
1074
|
-
// approximate/average final center point for final radius
|
|
1075
|
-
let cp1_r = rotatePoint(cp1, p0.x, p0.y, (Math.PI * -0.5))
|
|
1076
|
-
let cp2_r = rotatePoint(cp2, p.x, p.y, (Math.PI * 0.5))
|
|
1077
|
-
|
|
1078
|
-
let cp1_r2 = rotatePoint(comN.cp1, comN.p0.x, comN.p0.y, (Math.PI * -0.5))
|
|
1079
|
-
let cp2_r2 = rotatePoint(comN.cp2, comN.p.x, comN.p.y, (Math.PI * 0.5))
|
|
1080
|
-
|
|
1081
|
-
// assumed centroid
|
|
1082
|
-
let ptC = checkLineIntersection(p0, cp1_r, p, cp2_r, false)
|
|
1083
|
-
let ptC2 = checkLineIntersection(comN.p0, cp1_r2, comN.p, cp2_r2, false)
|
|
1084
|
-
let distC = ptC && ptC2 ? getDistAv(ptC, ptC2) : Infinity
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
// 2 commands can definitely be combined
|
|
1088
|
-
if (distC < thresh) {
|
|
1089
|
-
//renderPoint(markers, ptC, 'cyan', '1.2%', '0.5')
|
|
1090
|
-
//renderPoint(markers, ptC2, 'magenta', '0.5%', '0.5')
|
|
1091
|
-
|
|
1092
|
-
// add to centroid array
|
|
1093
|
-
centroids.push(ptC, ptC2)
|
|
1094
|
-
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
if (comN2 && comN2.type === 'C') {
|
|
1099
|
-
|
|
1100
|
-
let cp1_r3 = rotatePoint(comN2.cp1, comN2.p0.x, comN2.p0.y, (Math.PI * -0.5))
|
|
1101
|
-
let cp2_r3 = rotatePoint(comN2.cp2, comN2.p.x, comN2.p.y, (Math.PI * 0.5))
|
|
1102
|
-
let ptC3 = checkLineIntersection(comN2.p0, cp1_r3, comN2.p, cp2_r3, false)
|
|
1103
|
-
|
|
1104
|
-
let distC2 = ptC && ptC3 ? getDistAv(ptC, ptC3) : Infinity
|
|
1105
|
-
|
|
1106
|
-
// can be combined with 3rd command
|
|
1107
|
-
if (distC2 < thresh) {
|
|
1108
|
-
//renderPoint(markers, ptC3, 'green', '2%', '0.3')
|
|
1109
|
-
|
|
1110
|
-
let r3 = getDistance(ptC3, comN2.p)
|
|
1111
|
-
rArr.push(r3)
|
|
1112
|
-
|
|
1113
|
-
// update final point
|
|
1114
|
-
p_a = comN2.p
|
|
1115
|
-
poly.push(p, comN2.p)
|
|
1116
|
-
|
|
1117
|
-
largeArc = 1;
|
|
1118
|
-
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
//console.log(rDiff1, r, r1, r2);
|
|
1122
|
-
|
|
1123
|
-
} else {
|
|
1124
|
-
pathDataN.push(com)
|
|
1125
|
-
continue
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
// create new arc command
|
|
1132
|
-
if (poly.length > 1) {
|
|
1133
|
-
|
|
1134
|
-
// get average radius
|
|
1135
|
-
//rArr = rArr.sort()
|
|
1136
|
-
let rA = Math.max(...rArr)
|
|
1137
|
-
rA = rArr[0]
|
|
1138
|
-
|
|
1139
|
-
let centroidA;
|
|
1140
|
-
let xArr = centroids.map(pt => pt.x)
|
|
1141
|
-
let yArr = centroids.map(pt => pt.y)
|
|
1142
|
-
|
|
1143
|
-
centroidA = {
|
|
1144
|
-
x: (xArr.reduce((a, b) => a + b, 0)) / centroids.length,
|
|
1145
|
-
y: (yArr.reduce((a, b) => a + b, 0)) / centroids.length
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
//console.log(xArr, centroidA);
|
|
1149
|
-
|
|
1150
|
-
//rA = getDistance(p0, centroids[0])
|
|
1151
|
-
|
|
1152
|
-
rA = getDistance(p0, centroidA)
|
|
1153
|
-
let rA2 = getDistance(p, centroidA)
|
|
1154
|
-
//rA = (rA+rA2) /2
|
|
1155
|
-
//rA = Math.min(rA,rA2)
|
|
1156
|
-
|
|
1157
|
-
// rA = ((Math.min(...rArr) * 2 + Math.max(...rArr)) ) / 3
|
|
1158
|
-
//console.log(rArr, rA);
|
|
1159
|
-
|
|
1160
|
-
let area = getPolygonArea(poly, false)
|
|
1161
|
-
let sweep = area < 0 ? 0 : 1;
|
|
1162
|
-
|
|
1163
|
-
let comA = { type: 'A', values: [rA, rA, 0, largeArc, sweep, p_a.x, p_a.y], p0, p: p_a }
|
|
1164
|
-
|
|
1165
|
-
console.log('comA', comA);
|
|
1166
|
-
|
|
1167
|
-
pathDataN.push(comA)
|
|
1168
|
-
|
|
1169
|
-
i += rArr.length - 1;
|
|
1170
|
-
//i++
|
|
1171
|
-
continue
|
|
1172
|
-
/*
|
|
1173
|
-
*/
|
|
1174
|
-
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
// test angles
|
|
1181
|
-
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
pathDataN.push(com)
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
let d = pathDataToD(pathDataN)
|
|
1188
|
-
console.log(d);
|
|
1189
|
-
|
|
1190
|
-
console.log('pathDataN', pathDataN);
|
|
1191
|
-
return pathDataN
|
|
1192
|
-
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
export function cubicCommandToArc(p0, cp1, cp2, p, tolerance = 7.5) {
|
|
1196
|
-
|
|
1197
|
-
//console.log(p0, cp1, cp2, p, segArea );
|
|
1198
|
-
let com = { type: 'C', values: [cp1.x, cp1.y, cp2.x, cp2.y, p.x, p.y] };
|
|
1199
|
-
//let pathDataChunk = [{ type: 'M', values: [p0.x, p0.y] }, com];
|
|
1200
|
-
|
|
1201
|
-
let arcSegArea = 0, isArc = false
|
|
1202
|
-
|
|
1203
|
-
// check angles
|
|
1204
|
-
let angle1 = getAngle(p0, cp1, true);
|
|
1205
|
-
let angle2 = getAngle(p, cp2, true);
|
|
1206
|
-
let deltaAngle = Math.abs(angle1 - angle2) * 180 / Math.PI;
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
let angleDiff = Math.abs((deltaAngle % 180) - 90);
|
|
1210
|
-
let isRightAngle = angleDiff < 3;
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
/*
|
|
1214
|
-
let cp1_r = rotatePoint(cp1, p0.x, p0.y, (Math.PI * -0.5))
|
|
1215
|
-
let cp2_r = rotatePoint(cp2, p.x, p.y, (Math.PI * 0.5))
|
|
1216
|
-
//renderPoint(markers, cp1_r )
|
|
1217
|
-
|
|
1218
|
-
// assumed centroid
|
|
1219
|
-
let ptC = checkLineIntersection(p0, cp1_r, p, cp2_r, false)
|
|
1220
|
-
|
|
1221
|
-
let dist0 = getSquareDistance(p0, p)
|
|
1222
|
-
let dist1 = getSquareDistance(p0, ptC)
|
|
1223
|
-
let dist2 = getSquareDistance(p, ptC)
|
|
1224
|
-
|
|
1225
|
-
// let mid point
|
|
1226
|
-
let ptM = pointAtT([p0, cp1, cp2, p], 0.5)
|
|
1227
|
-
//let dist3 = getSquareDistance(ptM, ptC)
|
|
1228
|
-
let diff1 = Math.abs(dist1 - dist2)
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
if (diff1 <= dist0 * 0.01) {
|
|
1232
|
-
|
|
1233
|
-
let r = Math.sqrt((dist1 + dist2) / 2)
|
|
1234
|
-
//r = Math.sqrt((dist1 + dist2 + dist3) / 3)
|
|
1235
|
-
//r = Math.sqrt( Math.min(dist1, dist2) )
|
|
1236
|
-
//r=0.25
|
|
1237
|
-
//console.log('diff1', diff1, r);
|
|
1238
|
-
|
|
1239
|
-
let arcArea = getPolygonArea([p0, cp1, cp2, p])
|
|
1240
|
-
let sweep = arcArea < 0 ? 0 : 1;
|
|
1241
|
-
|
|
1242
|
-
// new arc command
|
|
1243
|
-
let comArc = { type: 'A', values: [r, r, 0, 0, sweep, p.x, p.y] };
|
|
1244
|
-
//renderPoint(markers, ptC)
|
|
1245
|
-
//renderPoint(markers, ptM)
|
|
1246
|
-
isArc = true;
|
|
1247
|
-
|
|
1248
|
-
return { com: comArc, isArc, area: arcSegArea }
|
|
1249
|
-
|
|
1250
|
-
}
|
|
1251
|
-
*/
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
if (isRightAngle) {
|
|
1255
|
-
// point between cps
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
let pI = checkLineIntersection(p0, cp1, p, cp2, false);
|
|
1259
|
-
|
|
1260
|
-
if (pI) {
|
|
1261
|
-
|
|
1262
|
-
let r1 = getDistance(p0, pI);
|
|
1263
|
-
let r2 = getDistance(p, pI);
|
|
1264
|
-
|
|
1265
|
-
let rMax = +Math.max(r1, r2).toFixed(8);
|
|
1266
|
-
let rMin = +Math.min(r1, r2).toFixed(8);
|
|
1267
|
-
|
|
1268
|
-
let rx = rMin
|
|
1269
|
-
let ry = rMax
|
|
1270
|
-
|
|
1271
|
-
let arcArea = getPolygonArea([p0, cp1, cp2, p])
|
|
1272
|
-
let sweep = arcArea < 0 ? 0 : 1;
|
|
1273
|
-
|
|
1274
|
-
let w = Math.abs(p.x - p0.x);
|
|
1275
|
-
let h = Math.abs(p.y - p0.y);
|
|
1276
|
-
let landscape = w > h;
|
|
1277
|
-
|
|
1278
|
-
let circular = (100 / rx * Math.abs(rx - ry)) < 5;
|
|
1279
|
-
|
|
1280
|
-
if (circular) {
|
|
1281
|
-
//rx = (rx+ry)/2
|
|
1282
|
-
rx = rMax
|
|
1283
|
-
ry = rx;
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
if (landscape) {
|
|
1287
|
-
//console.log('landscape', w, h);
|
|
1288
|
-
rx = rMax
|
|
1289
|
-
ry = rMin
|
|
1290
|
-
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
// get original cubic area
|
|
1294
|
-
let comO = [
|
|
1295
|
-
{ type: 'M', values: [p0.x, p0.y] },
|
|
1296
|
-
{ type: 'C', values: [cp1.x, cp1.y, cp2.x, cp2.y, p.x, p.y] }
|
|
1297
|
-
];
|
|
1298
|
-
|
|
1299
|
-
let comArea = getPathArea(comO);
|
|
1300
|
-
|
|
1301
|
-
// new arc command
|
|
1302
|
-
let comArc = { type: 'A', values: [rx, ry, 0, 0, sweep, p.x, p.y] };
|
|
1303
|
-
|
|
1304
|
-
// calculate arc seg area
|
|
1305
|
-
arcSegArea = (Math.PI * (rx * ry)) / 4
|
|
1306
|
-
|
|
1307
|
-
// subtract polygon between start, end and center point
|
|
1308
|
-
arcSegArea -= Math.abs(getPolygonArea([p0, p, pI]))
|
|
1309
|
-
|
|
1310
|
-
let areaDiff = getRelativeAreaDiff(comArea, arcSegArea);
|
|
1311
|
-
|
|
1312
|
-
if (areaDiff < tolerance) {
|
|
1313
|
-
isArc = true;
|
|
1314
|
-
com = comArc;
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
return { com: com, isArc, area: arcSegArea }
|
|
1321
|
-
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
/**
|
|
1325
|
-
* combine adjacent arcs
|
|
1326
|
-
*/
|
|
1327
|
-
|
|
1328
|
-
export function combineArcs(pathData) {
|
|
1329
|
-
|
|
1330
|
-
let arcSeq = [[]]
|
|
1331
|
-
let ind = 0
|
|
1332
|
-
let arcIndices = [[]];
|
|
1333
|
-
let p0 = { x: pathData[0].values[0], y: pathData[0].values[1] }, p;
|
|
1334
|
-
|
|
1335
|
-
for (let i = 0, len = pathData.length; i < len; i++) {
|
|
1336
|
-
let com = pathData[i];
|
|
1337
|
-
let { type, values } = com;
|
|
1338
|
-
|
|
1339
|
-
if (type === 'A') {
|
|
1340
|
-
|
|
1341
|
-
let comPrev = pathData[i - 1];
|
|
1342
|
-
|
|
1343
|
-
/**
|
|
1344
|
-
* previous p0 values might not be correct
|
|
1345
|
-
* anymore due to cubic simplification
|
|
1346
|
-
*/
|
|
1347
|
-
let valsL = comPrev.values.slice(-2);
|
|
1348
|
-
p0 = { x: valsL[0], y: valsL[1] };
|
|
1349
|
-
|
|
1350
|
-
let [rx, ry, xAxisRotation, largeArc, sweep, x, y] = values;
|
|
1351
|
-
|
|
1352
|
-
// check if arc is circular
|
|
1353
|
-
let circular = (100 / rx * Math.abs(rx - ry)) < 5;
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
//add p0
|
|
1357
|
-
p = { x: values[5], y: values[6] }
|
|
1358
|
-
com.p0 = p0;
|
|
1359
|
-
com.p = p;
|
|
1360
|
-
com.circular = circular;
|
|
1361
|
-
|
|
1362
|
-
let comNext = pathData[i + 1];
|
|
1363
|
-
|
|
1364
|
-
//add first
|
|
1365
|
-
if (!arcSeq[ind].length && comNext && comNext.type === 'A') {
|
|
1366
|
-
arcSeq[ind].push(com)
|
|
1367
|
-
arcIndices[ind].push(i)
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
if (comNext && comNext.type === 'A') {
|
|
1371
|
-
let [rx1, ry1, xAxisRotation0, largeArc, sweep, x, y] = comNext.values;
|
|
1372
|
-
let diffRx = rx != rx1 ? 100 / rx * Math.abs(rx - rx1) : 0
|
|
1373
|
-
let diffRy = ry != ry1 ? 100 / ry * Math.abs(ry - ry1) : 0
|
|
1374
|
-
//let diff = (diffRx + diffRy) / 2
|
|
1375
|
-
//let circular2 = (100 / rx1 * Math.abs(rx1 - ry1)) < 5;
|
|
1376
|
-
|
|
1377
|
-
p = { x: comNext.values[5], y: comNext.values[6] }
|
|
1378
|
-
comNext.p0 = p0;
|
|
1379
|
-
comNext.p = p;
|
|
1380
|
-
|
|
1381
|
-
// add if radii are almost same
|
|
1382
|
-
if (diffRx < 5 && diffRy < 5) {
|
|
1383
|
-
//console.log(rx, rx1, ry, ry1, 'diff:',diff, 'circular', circular, circular2);
|
|
1384
|
-
arcSeq[ind].push(comNext)
|
|
1385
|
-
arcIndices[ind].push(i + 1)
|
|
1386
|
-
} else {
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
// start new segment
|
|
1390
|
-
arcSeq.push([])
|
|
1391
|
-
arcIndices.push([])
|
|
1392
|
-
ind++
|
|
1393
|
-
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
else {
|
|
1398
|
-
//arcSeq[ind].push(com)
|
|
1399
|
-
//arcIndices[ind].push(i - 1)
|
|
1400
|
-
arcSeq.push([])
|
|
1401
|
-
arcIndices.push([])
|
|
1402
|
-
ind++
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
|
|
1407
|
-
if (!arcIndices.length) return pathData;
|
|
1408
|
-
|
|
1409
|
-
arcSeq = arcSeq.filter(item => item.length)
|
|
1410
|
-
arcIndices = arcIndices.filter(item => item.length)
|
|
1411
|
-
//console.log('combine arcs:', arcSeq, arcIndices);
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
// Process in reverse to avoid index shifting
|
|
1415
|
-
for (let i = arcSeq.length - 1; i >= 0; i--) {
|
|
1416
|
-
const seq = arcSeq[i];
|
|
1417
|
-
const start = arcIndices[i][0];
|
|
1418
|
-
const len = seq.length;
|
|
1419
|
-
|
|
1420
|
-
// Average radii to prevent distortions
|
|
1421
|
-
let rxA = 0, ryA = 0;
|
|
1422
|
-
seq.forEach(({ values }) => {
|
|
1423
|
-
const [rx, ry] = values;
|
|
1424
|
-
rxA += rx;
|
|
1425
|
-
ryA += ry;
|
|
1426
|
-
});
|
|
1427
|
-
rxA /= len;
|
|
1428
|
-
ryA /= len;
|
|
1429
|
-
|
|
1430
|
-
// Correct near-circular arcs
|
|
1431
|
-
//console.log('seq', seq);
|
|
1432
|
-
|
|
1433
|
-
//let rDiff = 100 / rxA * Math.abs(rxA - ryA);
|
|
1434
|
-
//let circular = rDiff < 5;
|
|
1435
|
-
|
|
1436
|
-
// check if arc is circular
|
|
1437
|
-
let circular = (100 / rxA * Math.abs(rxA - ryA)) < 5;
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
if (circular) {
|
|
1441
|
-
// average radii
|
|
1442
|
-
rxA = (rxA + ryA) / 2;
|
|
1443
|
-
ryA = rxA;
|
|
1444
|
-
}
|
|
1445
|
-
|
|
1446
|
-
let comPrev = pathData[start - 1]
|
|
1447
|
-
let comPrevVals = comPrev.values.slice(-2)
|
|
1448
|
-
let M = { type: 'M', values: [comPrevVals[0], comPrevVals[1]] }
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
if (len === 4) {
|
|
1452
|
-
//console.log('4 arcs');
|
|
1453
|
-
|
|
1454
|
-
let [rx, ry, xAxisRotation, largeArc, sweep, x1, y1] = seq[1].values;
|
|
1455
|
-
let [, , , , , x2, y2] = seq[3].values;
|
|
1456
|
-
|
|
1457
|
-
let xDiff = Math.abs(x2 - x1);
|
|
1458
|
-
let yDiff = Math.abs(y2 - y1);
|
|
1459
|
-
let horizontal = xDiff > yDiff;
|
|
1460
|
-
|
|
1461
|
-
if (circular) {
|
|
1462
|
-
let adjustY = !horizontal ? rxA * 2 : 0;
|
|
1463
|
-
//x1 = M.values[0];
|
|
1464
|
-
//y1 = M.values[1] + adjustY;
|
|
1465
|
-
//x2 = M.values[0];
|
|
1466
|
-
//y2 = M.values[1];
|
|
1467
|
-
|
|
1468
|
-
// simplify radii
|
|
1469
|
-
rxA = 1;
|
|
1470
|
-
ryA = 1;
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
let com1 = { type: 'A', values: [rxA, ryA, xAxisRotation, largeArc, sweep, x1, y1] };
|
|
1474
|
-
let com2 = { type: 'A', values: [rxA, ryA, xAxisRotation, largeArc, sweep, x2, y2] };
|
|
1475
|
-
|
|
1476
|
-
// This now correctly replaces the original 4 arc commands with 2
|
|
1477
|
-
pathData.splice(start, len, com1, com2);
|
|
1478
|
-
//console.log(com1, com2);
|
|
1479
|
-
}
|
|
1480
|
-
|
|
1481
|
-
else if (len === 3) {
|
|
1482
|
-
//console.log('3 arcs');
|
|
1483
|
-
let [rx, ry, xAxisRotation, largeArc, sweep, x1, y1] = seq[0].values;
|
|
1484
|
-
let [rx2, ry2, , , , x2, y2] = seq[2].values;
|
|
1485
|
-
|
|
1486
|
-
// must be large arc
|
|
1487
|
-
largeArc = 1;
|
|
1488
|
-
let com1 = { type: 'A', values: [rxA, ryA, xAxisRotation, largeArc, sweep, x2, y2] };
|
|
1489
|
-
|
|
1490
|
-
// replace
|
|
1491
|
-
pathData.splice(start, len, com1);
|
|
1492
|
-
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
else if (len === 2) {
|
|
1497
|
-
//console.log('2 arcs');
|
|
1498
|
-
let [rx, ry, xAxisRotation, largeArc, sweep, x1, y1] = seq[0].values;
|
|
1499
|
-
let [rx2, ry2, , , , x2, y2] = seq[1].values;
|
|
1500
|
-
|
|
1501
|
-
// if circular or non-elliptic xAxisRotation has no effect
|
|
1502
|
-
if (circular) {
|
|
1503
|
-
rxA = 1;
|
|
1504
|
-
ryA = 1;
|
|
1505
|
-
xAxisRotation = 0;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
// check if arc is already ideal
|
|
1509
|
-
let { p0, p } = seq[0];
|
|
1510
|
-
let [p0_1, p_1] = [seq[1].p0, seq[1].p];
|
|
1511
|
-
|
|
1512
|
-
if (p0.x !== p_1.x || p0.y !== p_1.y) {
|
|
1513
|
-
|
|
1514
|
-
let com1 = { type: 'A', values: [rxA, ryA, xAxisRotation, largeArc, sweep, x2, y2] };
|
|
1515
|
-
|
|
1516
|
-
// replace
|
|
1517
|
-
pathData.splice(start, len, com1);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
else {
|
|
1522
|
-
//console.log('single arc');
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
return pathData
|
|
1527
|
-
}
|