modern-path2d 1.5.1 → 1.5.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/dist/index.mjs CHANGED
@@ -296,980 +296,833 @@ class BoundingBox {
296
296
  }
297
297
  }
298
298
 
299
- function svgAngle(ux, uy, vx, vy) {
300
- const dot = ux * vx + uy * vy;
301
- const len = Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy);
302
- let ang = Math.acos(Math.max(-1, Math.min(1, dot / len)));
303
- if (ux * vy - uy * vx < 0)
304
- ang = -ang;
305
- return ang;
299
+ function catmullRom(t, p0, p1, p2, p3) {
300
+ const v0 = (p2 - p0) * 0.5;
301
+ const v1 = (p3 - p1) * 0.5;
302
+ const t2 = t * t;
303
+ const t3 = t * t2;
304
+ return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
306
305
  }
307
- function parseArcCommand(path, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, start, end) {
308
- if (rx === 0 || ry === 0) {
309
- path.lineTo(end.x, end.y);
310
- return;
306
+
307
+ const PI = Math.PI;
308
+ const PI_2 = PI * 2;
309
+ function toKebabCase(str) {
310
+ return str.replace(/[^a-z0-9]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
311
+ }
312
+ function getIntersectionPoint(p1, p2, q1, q2) {
313
+ const r = p2.clone().sub(p1);
314
+ const s = q2.clone().sub(q1);
315
+ const q1p1 = q1.clone().sub(p1);
316
+ const crossRS = r.cross(s);
317
+ if (crossRS === 0) {
318
+ return new Vector2(
319
+ (p1.x + q1.x) / 2,
320
+ (p1.y + q1.y) / 2
321
+ );
311
322
  }
312
- xAxisRotation = xAxisRotation * Math.PI / 180;
313
- rx = Math.abs(rx);
314
- ry = Math.abs(ry);
315
- const dx2 = (start.x - end.x) / 2;
316
- const dy2 = (start.y - end.y) / 2;
317
- const x1p = Math.cos(xAxisRotation) * dx2 + Math.sin(xAxisRotation) * dy2;
318
- const y1p = -Math.sin(xAxisRotation) * dx2 + Math.cos(xAxisRotation) * dy2;
319
- let rxs = rx * rx;
320
- let rys = ry * ry;
321
- const x1ps = x1p * x1p;
322
- const y1ps = y1p * y1p;
323
- const cr = x1ps / rxs + y1ps / rys;
324
- if (cr > 1) {
325
- const s = Math.sqrt(cr);
326
- rx = s * rx;
327
- ry = s * ry;
328
- rxs = rx * rx;
329
- rys = ry * ry;
323
+ const t = q1p1.cross(s) / crossRS;
324
+ if (Math.abs(t) > 1) {
325
+ return new Vector2(
326
+ (p1.x + q1.x) / 2,
327
+ (p1.y + q1.y) / 2
328
+ );
330
329
  }
331
- const dq = rxs * y1ps + rys * x1ps;
332
- const pq = (rxs * rys - dq) / dq;
333
- let q = Math.sqrt(Math.max(0, pq));
334
- if (largeArcFlag === sweepFlag)
335
- q = -q;
336
- const cxp = q * rx * y1p / ry;
337
- const cyp = -q * ry * x1p / rx;
338
- const cx = Math.cos(xAxisRotation) * cxp - Math.sin(xAxisRotation) * cyp + (start.x + end.x) / 2;
339
- const cy = Math.sin(xAxisRotation) * cxp + Math.cos(xAxisRotation) * cyp + (start.y + end.y) / 2;
340
- const theta = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
341
- const delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry) % (Math.PI * 2);
342
- path.ellipse(cx, cy, rx, ry, xAxisRotation, theta, theta + delta, sweepFlag === 0);
330
+ return new Vector2(
331
+ p1.x + t * r.x,
332
+ p1.y + t * r.y
333
+ );
343
334
  }
344
335
 
345
- const RE$3 = {
346
- WHITESPACE: /[ \t\r\n]/,
347
- DIGIT: /\d/,
348
- SIGN: /[-+]/,
349
- POINT: /\./,
350
- COMMA: /,/,
351
- EXP: /e/i,
352
- FLAGS: /[01]/
353
- };
354
- function parsePathDataArgs(input, flags, stride = 0) {
355
- const SEP = 0;
356
- const INT = 1;
357
- const FLOAT = 2;
358
- const EXP = 3;
359
- let state = SEP;
360
- let seenComma = true;
361
- let number = "";
362
- let exponent = "";
363
- const result = [];
364
- function throwSyntaxError(current2, i, partial) {
365
- const error = new SyntaxError(`Unexpected character "${current2}" at index ${i}.`);
366
- error.partial = partial;
367
- throw error;
368
- }
369
- function newNumber() {
370
- if (number !== "") {
371
- if (exponent === "")
372
- result.push(Number(number));
373
- else result.push(Number(number) * 10 ** Number(exponent));
336
+ const FUNCTIONS_RE = /([\w-]+)\((.+?)\)/g;
337
+ const ARGS_RE = /[^,]+/g;
338
+ const ARG_RE = /([-e.\d]+)(.*)/;
339
+ function parseCssFunctions(propertyValue, context = {}) {
340
+ const functions = [];
341
+ let match;
342
+ while ((match = FUNCTIONS_RE.exec(propertyValue)) !== null) {
343
+ const [, name, value] = match;
344
+ if (name) {
345
+ functions.push({
346
+ name,
347
+ args: parseCssArgs(name, value, context)
348
+ });
374
349
  }
375
- number = "";
376
- exponent = "";
377
350
  }
378
- let current;
379
- const length = input.length;
380
- for (let i = 0; i < length; i++) {
381
- current = input[i];
382
- if (Array.isArray(flags) && flags.includes(result.length % stride) && RE$3.FLAGS.test(current)) {
383
- state = INT;
384
- number = current;
385
- newNumber();
386
- continue;
387
- }
388
- if (state === SEP) {
389
- if (RE$3.WHITESPACE.test(current)) {
390
- continue;
391
- }
392
- if (RE$3.DIGIT.test(current) || RE$3.SIGN.test(current)) {
393
- state = INT;
394
- number = current;
395
- continue;
396
- }
397
- if (RE$3.POINT.test(current)) {
398
- state = FLOAT;
399
- number = current;
400
- continue;
401
- }
402
- if (RE$3.COMMA.test(current)) {
403
- if (seenComma) {
404
- throwSyntaxError(current, i, result);
405
- }
406
- seenComma = true;
407
- }
408
- }
409
- if (state === INT) {
410
- if (RE$3.DIGIT.test(current)) {
411
- number += current;
412
- continue;
413
- }
414
- if (RE$3.POINT.test(current)) {
415
- number += current;
416
- state = FLOAT;
417
- continue;
418
- }
419
- if (RE$3.EXP.test(current)) {
420
- state = EXP;
421
- continue;
422
- }
423
- if (RE$3.SIGN.test(current) && number.length === 1 && RE$3.SIGN.test(number[0])) {
424
- throwSyntaxError(current, i, result);
425
- }
426
- }
427
- if (state === FLOAT) {
428
- if (RE$3.DIGIT.test(current)) {
429
- number += current;
430
- continue;
431
- }
432
- if (RE$3.EXP.test(current)) {
433
- state = EXP;
434
- continue;
435
- }
436
- if (RE$3.POINT.test(current) && number[number.length - 1] === ".") {
437
- throwSyntaxError(current, i, result);
438
- }
439
- }
440
- if (state === EXP) {
441
- if (RE$3.DIGIT.test(current)) {
442
- exponent += current;
443
- continue;
444
- }
445
- if (RE$3.SIGN.test(current)) {
446
- if (exponent === "") {
447
- exponent += current;
448
- continue;
449
- }
450
- if (exponent.length === 1 && RE$3.SIGN.test(exponent)) {
451
- throwSyntaxError(current, i, result);
452
- }
351
+ return functions;
352
+ }
353
+ function parseCssArgs(name, value, context = {}) {
354
+ const values = [];
355
+ let match;
356
+ let i = 0;
357
+ while ((match = ARGS_RE.exec(value)) !== null) {
358
+ values.push(
359
+ parseCssArg(name, match[0], {
360
+ ...context,
361
+ index: i++
362
+ })
363
+ );
364
+ }
365
+ return values;
366
+ }
367
+ function parseCssArg(name, value, context = {}) {
368
+ const { width = 1, height = 1, index = 0 } = context;
369
+ const matched = value.match(ARG_RE);
370
+ const result = {
371
+ unit: matched?.[2] ?? null,
372
+ value,
373
+ intValue: Number(matched?.[1]),
374
+ normalizedIntValue: 0,
375
+ normalizedDefaultIntValue: 0
376
+ };
377
+ switch (name) {
378
+ case "scale":
379
+ case "scaleX":
380
+ case "scaleY":
381
+ case "scale3d":
382
+ result.normalizedDefaultIntValue = 1;
383
+ break;
384
+ }
385
+ switch (result.unit) {
386
+ case "%":
387
+ result.normalizedIntValue = result.intValue / 100;
388
+ break;
389
+ case "rad":
390
+ result.normalizedIntValue = result.intValue / PI_2;
391
+ break;
392
+ case "deg":
393
+ result.normalizedIntValue = result.intValue / 360;
394
+ break;
395
+ case "px":
396
+ switch (index) {
397
+ case 0:
398
+ result.normalizedIntValue = result.intValue / width;
399
+ break;
400
+ case 1:
401
+ result.normalizedIntValue = result.intValue / height;
402
+ break;
453
403
  }
454
- }
455
- if (RE$3.WHITESPACE.test(current)) {
456
- newNumber();
457
- state = SEP;
458
- seenComma = false;
459
- } else if (RE$3.COMMA.test(current)) {
460
- newNumber();
461
- state = SEP;
462
- seenComma = true;
463
- } else if (RE$3.SIGN.test(current)) {
464
- newNumber();
465
- state = INT;
466
- number = current;
467
- } else if (RE$3.POINT.test(current)) {
468
- newNumber();
469
- state = FLOAT;
470
- number = current;
471
- } else {
472
- throwSyntaxError(current, i, result);
473
- }
404
+ break;
405
+ case "turn":
406
+ case "em":
407
+ // div fontSize
408
+ case "rem":
409
+ // div fontSize
410
+ default:
411
+ result.normalizedIntValue = result.intValue;
412
+ break;
474
413
  }
475
- newNumber();
476
414
  return result;
477
415
  }
478
416
 
479
- function getReflection(a, b) {
480
- return a - (b - a);
417
+ function cubicBezierP0(t, p) {
418
+ const k = 1 - t;
419
+ return k * k * k * p;
481
420
  }
482
- function svgPathCommandsAddToPath2D(commands, path) {
483
- const current = new Vector2();
484
- const control = new Vector2();
485
- for (let i = 0, l = commands.length; i < l; i++) {
486
- const cmd = commands[i];
487
- if (cmd.type === "m" || cmd.type === "M") {
488
- if (cmd.type === "m") {
489
- current.add(cmd);
490
- } else {
491
- current.copyFrom(cmd);
492
- }
493
- path.moveTo(current.x, current.y);
494
- control.copyFrom(current);
495
- } else if (cmd.type === "h" || cmd.type === "H") {
496
- if (cmd.type === "h") {
497
- current.x += cmd.x;
498
- } else {
499
- current.x = cmd.x;
500
- }
501
- path.lineTo(current.x, current.y);
502
- control.copyFrom(current);
503
- } else if (cmd.type === "v" || cmd.type === "V") {
504
- if (cmd.type === "v") {
505
- current.y += cmd.y;
506
- } else {
507
- current.y = cmd.y;
508
- }
509
- path.lineTo(current.x, current.y);
510
- control.copyFrom(current);
511
- } else if (cmd.type === "l" || cmd.type === "L") {
512
- if (cmd.type === "l") {
513
- current.add(cmd);
514
- } else {
515
- current.copyFrom(cmd);
516
- }
517
- path.lineTo(current.x, current.y);
518
- control.copyFrom(current);
519
- } else if (cmd.type === "c" || cmd.type === "C") {
520
- if (cmd.type === "c") {
521
- path.bezierCurveTo(
522
- current.x + cmd.x1,
523
- current.y + cmd.y1,
524
- current.x + cmd.x2,
525
- current.y + cmd.y2,
526
- current.x + cmd.x,
527
- current.y + cmd.y
528
- );
529
- control.x = current.x + cmd.x2;
530
- control.y = current.y + cmd.y2;
531
- current.add(cmd);
532
- } else {
533
- path.bezierCurveTo(
534
- cmd.x1,
535
- cmd.y1,
536
- cmd.x2,
537
- cmd.y2,
538
- cmd.x,
539
- cmd.y
540
- );
541
- control.x = cmd.x2;
542
- control.y = cmd.y2;
543
- current.copyFrom(cmd);
544
- }
545
- } else if (cmd.type === "s" || cmd.type === "S") {
546
- if (cmd.type === "s") {
547
- path.bezierCurveTo(
548
- getReflection(current.x, control.x),
549
- getReflection(current.y, control.y),
550
- current.x + cmd.x2,
551
- current.y + cmd.y2,
552
- current.x + cmd.x,
553
- current.y + cmd.y
554
- );
555
- control.x = current.x + cmd.x2;
556
- control.y = current.y + cmd.y2;
557
- current.add(cmd);
558
- } else {
559
- path.bezierCurveTo(
560
- getReflection(current.x, control.x),
561
- getReflection(current.y, control.y),
562
- cmd.x2,
563
- cmd.y2,
564
- cmd.x,
565
- cmd.y
566
- );
567
- control.x = cmd.x2;
568
- control.y = cmd.y2;
569
- current.copyFrom(cmd);
570
- }
571
- } else if (cmd.type === "q" || cmd.type === "Q") {
572
- if (cmd.type === "q") {
573
- path.quadraticCurveTo(
574
- current.x + cmd.x1,
575
- current.y + cmd.y1,
576
- current.x + cmd.x,
577
- current.y + cmd.y
578
- );
579
- control.x = current.x + cmd.x1;
580
- control.y = current.y + cmd.y1;
581
- current.add(cmd);
582
- } else {
583
- path.quadraticCurveTo(
584
- cmd.x1,
585
- cmd.y1,
586
- cmd.x,
587
- cmd.y
588
- );
589
- control.x = cmd.x1;
590
- control.y = cmd.y1;
591
- current.copyFrom(cmd);
592
- }
593
- } else if (cmd.type === "t" || cmd.type === "T") {
594
- const rx = getReflection(current.x, control.x);
595
- const ry = getReflection(current.y, control.y);
596
- control.x = rx;
597
- control.y = ry;
598
- if (cmd.type === "t") {
599
- path.quadraticCurveTo(
600
- rx,
601
- ry,
602
- current.x + cmd.x,
603
- current.y + cmd.y
604
- );
605
- current.add(cmd);
606
- } else {
607
- path.quadraticCurveTo(
608
- rx,
609
- ry,
610
- cmd.x,
611
- cmd.y
612
- );
613
- current.copyFrom(cmd);
421
+ function cubicBezierP1(t, p) {
422
+ const k = 1 - t;
423
+ return 3 * k * k * t * p;
424
+ }
425
+ function cubicBezierP2(t, p) {
426
+ return 3 * (1 - t) * t * t * p;
427
+ }
428
+ function cubicBezierP3(t, p) {
429
+ return t * t * t * p;
430
+ }
431
+ function cubicBezier(t, p0, p1, p2, p3) {
432
+ return cubicBezierP0(t, p0) + cubicBezierP1(t, p1) + cubicBezierP2(t, p2) + cubicBezierP3(t, p3);
433
+ }
434
+
435
+ function fillTriangulate(pointArray, options = {}) {
436
+ let {
437
+ vertices = [],
438
+ indices = [],
439
+ holes = [],
440
+ verticesStride = 2,
441
+ verticesOffset = vertices.length / verticesStride,
442
+ indicesOffset = indices.length
443
+ } = options;
444
+ const triangles = earcut(pointArray, holes, 2);
445
+ if (triangles.length) {
446
+ for (let i = 0; i < triangles.length; i += 3) {
447
+ indices[indicesOffset++] = triangles[i] + verticesOffset;
448
+ indices[indicesOffset++] = triangles[i + 1] + verticesOffset;
449
+ indices[indicesOffset++] = triangles[i + 2] + verticesOffset;
450
+ }
451
+ let index = verticesOffset * verticesStride;
452
+ for (let i = 0; i < pointArray.length; i += 2) {
453
+ vertices[index] = pointArray[i];
454
+ vertices[index + 1] = pointArray[i + 1];
455
+ index += verticesStride;
456
+ }
457
+ }
458
+ return {
459
+ vertices,
460
+ indices
461
+ };
462
+ }
463
+
464
+ const RECURSION_LIMIT$1 = 8;
465
+ const FLT_EPSILON$1 = 11920929e-14;
466
+ const PATH_DISTANCE_EPSILON$1 = 1;
467
+ function getAdaptiveCubicBezierCurvePoints(sX, sY, x1, y1, x2, y2, x, y, smoothness = 0.5, points = []) {
468
+ const scale = 1;
469
+ const smoothing = Math.min(
470
+ 0.99,
471
+ // a value of 1.0 actually inverts smoothing, so we cap it at 0.99
472
+ Math.max(0, smoothness)
473
+ );
474
+ let distanceTolerance = (PATH_DISTANCE_EPSILON$1 - smoothing) / scale;
475
+ distanceTolerance *= distanceTolerance;
476
+ recursive$1(sX, sY, x1, y1, x2, y2, x, y, points, distanceTolerance, 0);
477
+ points.push(x, y);
478
+ return points;
479
+ }
480
+ function recursive$1(x1, y1, x2, y2, x3, y3, x4, y4, points, distanceTolerance, level) {
481
+ if (level > RECURSION_LIMIT$1)
482
+ return;
483
+ const x12 = (x1 + x2) / 2;
484
+ const y12 = (y1 + y2) / 2;
485
+ const x23 = (x2 + x3) / 2;
486
+ const y23 = (y2 + y3) / 2;
487
+ const x34 = (x3 + x4) / 2;
488
+ const y34 = (y3 + y4) / 2;
489
+ const x123 = (x12 + x23) / 2;
490
+ const y123 = (y12 + y23) / 2;
491
+ const x234 = (x23 + x34) / 2;
492
+ const y234 = (y23 + y34) / 2;
493
+ const x1234 = (x123 + x234) / 2;
494
+ const y1234 = (y123 + y234) / 2;
495
+ if (level > 0) {
496
+ let dx = x4 - x1;
497
+ let dy = y4 - y1;
498
+ const d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx);
499
+ const d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx);
500
+ if (d2 > FLT_EPSILON$1 && d3 > FLT_EPSILON$1) {
501
+ if ((d2 + d3) * (d2 + d3) <= distanceTolerance * (dx * dx + dy * dy)) {
502
+ {
503
+ points.push(x1234, y1234);
504
+ return;
505
+ }
614
506
  }
615
- } else if (cmd.type === "a" || cmd.type === "A") {
616
- const start = current.clone();
617
- if (cmd.type === "a") {
618
- if (cmd.x === 0 && cmd.y === 0)
619
- continue;
620
- current.add(cmd);
621
- } else {
622
- if (current.equals(cmd))
623
- continue;
624
- current.copyFrom(cmd);
507
+ } else if (d2 > FLT_EPSILON$1) {
508
+ if (d2 * d2 <= distanceTolerance * (dx * dx + dy * dy)) {
509
+ {
510
+ points.push(x1234, y1234);
511
+ return;
512
+ }
625
513
  }
626
- control.copyFrom(current);
627
- parseArcCommand(
628
- path,
629
- cmd.rx,
630
- cmd.ry,
631
- cmd.angle,
632
- cmd.largeArcFlag,
633
- cmd.sweepFlag,
634
- start,
635
- current
636
- );
637
- } else if (cmd.type === "z" || cmd.type === "Z") {
638
- if (path.startPoint) {
639
- current.copyFrom(path.startPoint);
514
+ } else if (d3 > FLT_EPSILON$1) {
515
+ if (d3 * d3 <= distanceTolerance * (dx * dx + dy * dy)) {
516
+ {
517
+ points.push(x1234, y1234);
518
+ return;
519
+ }
640
520
  }
641
- path.closePath();
642
521
  } else {
643
- console.warn("Unsupported commands", cmd);
522
+ dx = x1234 - (x1 + x4) / 2;
523
+ dy = y1234 - (y1 + y4) / 2;
524
+ if (dx * dx + dy * dy <= distanceTolerance) {
525
+ points.push(x1234, y1234);
526
+ return;
527
+ }
644
528
  }
645
529
  }
530
+ recursive$1(x1, y1, x12, y12, x123, y123, x1234, y1234, points, distanceTolerance, level + 1);
531
+ recursive$1(x1234, y1234, x234, y234, x34, y34, x4, y4, points, distanceTolerance, level + 1);
646
532
  }
647
533
 
648
- function svgPathCommandsToData(commands) {
649
- let first;
650
- let prev;
651
- const data = [];
652
- for (let i = 0, len = commands.length; i < len; i++) {
653
- const cmd = commands[i];
654
- switch (cmd.type) {
655
- case "m":
656
- case "M":
657
- if (cmd.x.toFixed(4) === prev?.x.toFixed(4) && cmd.y.toFixed(4) === prev?.y.toFixed(4)) {
658
- continue;
659
- }
660
- data.push(`${cmd.type} ${cmd.x} ${cmd.y}`);
661
- prev = { x: cmd.x, y: cmd.y };
662
- first = { x: cmd.x, y: cmd.y };
663
- break;
664
- case "h":
665
- case "H":
666
- data.push(`${cmd.type} ${cmd.x}`);
667
- prev = { x: cmd.x, y: prev?.y ?? 0 };
668
- break;
669
- case "v":
670
- case "V":
671
- data.push(`${cmd.type} ${cmd.y}`);
672
- prev = { x: prev?.x ?? 0, y: cmd.y };
673
- break;
674
- case "l":
675
- case "L":
676
- data.push(`${cmd.type} ${cmd.x} ${cmd.y}`);
677
- prev = { x: cmd.x, y: cmd.y };
678
- break;
679
- case "c":
680
- case "C":
681
- data.push(`${cmd.type} ${cmd.x1} ${cmd.y1} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`);
682
- prev = { x: cmd.x, y: cmd.y };
683
- break;
684
- case "s":
685
- case "S":
686
- data.push(`${cmd.type} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`);
687
- prev = { x: cmd.x, y: cmd.y };
688
- break;
689
- case "q":
690
- case "Q":
691
- data.push(`${cmd.type} ${cmd.x1} ${cmd.y1} ${cmd.x} ${cmd.y}`);
692
- prev = { x: cmd.x, y: cmd.y };
693
- break;
694
- case "t":
695
- case "T":
696
- data.push(`${cmd.type} ${cmd.x} ${cmd.y}`);
697
- prev = { x: cmd.x, y: cmd.y };
698
- break;
699
- case "a":
700
- case "A":
701
- data.push(`${cmd.type} ${cmd.rx} ${cmd.ry} ${cmd.angle} ${cmd.largeArcFlag} ${cmd.sweepFlag} ${cmd.x} ${cmd.y}`);
702
- prev = { x: cmd.x, y: cmd.y };
703
- break;
704
- case "z":
705
- case "Z":
706
- data.push(cmd.type);
707
- if (first) {
708
- prev = { x: first.x, y: first.y };
709
- }
710
- break;
534
+ const RECURSION_LIMIT = 8;
535
+ const FLT_EPSILON = 11920929e-14;
536
+ const PATH_DISTANCE_EPSILON = 1;
537
+ function getAdaptiveQuadraticBezierCurvePoints(sX, sY, x1, y1, x, y, smoothness = 0.5, points = []) {
538
+ const scale = 1;
539
+ const smoothing = Math.min(
540
+ 0.99,
541
+ // a value of 1.0 actually inverts smoothing, so we cap it at 0.99
542
+ Math.max(0, smoothness)
543
+ );
544
+ let distanceTolerance = (PATH_DISTANCE_EPSILON - smoothing) / scale;
545
+ distanceTolerance *= distanceTolerance;
546
+ recursive(points, sX, sY, x1, y1, x, y, distanceTolerance, 0);
547
+ points.push(x, y);
548
+ return points;
549
+ }
550
+ function recursive(points, x1, y1, x2, y2, x3, y3, distanceTolerance, level) {
551
+ if (level > RECURSION_LIMIT)
552
+ return;
553
+ const x12 = (x1 + x2) / 2;
554
+ const y12 = (y1 + y2) / 2;
555
+ const x23 = (x2 + x3) / 2;
556
+ const y23 = (y2 + y3) / 2;
557
+ const x123 = (x12 + x23) / 2;
558
+ const y123 = (y12 + y23) / 2;
559
+ let dx = x3 - x1;
560
+ let dy = y3 - y1;
561
+ const d = Math.abs((x2 - x3) * dy - (y2 - y3) * dx);
562
+ if (d > FLT_EPSILON) {
563
+ if (d * d <= distanceTolerance * (dx * dx + dy * dy)) {
564
+ {
565
+ points.push(x123, y123);
566
+ return;
567
+ }
568
+ }
569
+ } else {
570
+ dx = x123 - (x1 + x3) / 2;
571
+ dy = y123 - (y1 + y3) / 2;
572
+ if (dx * dx + dy * dy <= distanceTolerance) {
573
+ points.push(x123, y123);
574
+ return;
711
575
  }
712
576
  }
713
- return data.join(" ");
577
+ recursive(points, x1, y1, x12, y12, x123, y123, distanceTolerance, level + 1);
578
+ recursive(points, x123, y123, x23, y23, x3, y3, distanceTolerance, level + 1);
714
579
  }
715
580
 
716
- const RE$2 = /[a-df-z][^a-df-z]*/gi;
717
- function svgPathDataToCommands(data) {
718
- const commands = [];
719
- const matched = data.match(RE$2);
720
- if (!matched) {
721
- return commands;
722
- }
723
- for (let i = 0, len = matched.length; i < len; i++) {
724
- const command = matched[i];
725
- const type = command.charAt(0);
726
- const data2 = command.slice(1).trim();
727
- let args;
728
- switch (type) {
729
- case "m":
730
- case "M":
731
- args = parsePathDataArgs(data2);
732
- for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
733
- if (i2 === 0) {
734
- commands.push({ type, x: args[i2], y: args[i2 + 1] });
735
- } else {
736
- commands.push({ type: type === "m" ? "l" : "L", x: args[i2], y: args[i2 + 1] });
737
- }
738
- }
739
- break;
740
- case "h":
741
- case "H":
742
- args = parsePathDataArgs(data2);
743
- for (let i2 = 0, len2 = args.length; i2 < len2; i2++) {
744
- commands.push({ type, x: args[i2] });
745
- }
746
- break;
747
- case "v":
748
- case "V":
749
- args = parsePathDataArgs(data2);
750
- for (let i2 = 0, len2 = args.length; i2 < len2; i2++) {
751
- commands.push({ type, y: args[i2] });
752
- }
753
- break;
754
- case "l":
755
- case "L":
756
- args = parsePathDataArgs(data2);
757
- for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
758
- commands.push({ type, x: args[i2], y: args[i2 + 1] });
759
- }
760
- break;
761
- case "c":
762
- case "C":
763
- args = parsePathDataArgs(data2);
764
- for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 6) {
765
- commands.push({
766
- type,
767
- x1: args[i2],
768
- y1: args[i2 + 1],
769
- x2: args[i2 + 2],
770
- y2: args[i2 + 3],
771
- x: args[i2 + 4],
772
- y: args[i2 + 5]
773
- });
774
- }
775
- break;
776
- case "s":
777
- case "S":
778
- args = parsePathDataArgs(data2);
779
- for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 4) {
780
- commands.push({
781
- type,
782
- x2: args[i2],
783
- y2: args[i2 + 1],
784
- x: args[i2 + 2],
785
- y: args[i2 + 3]
786
- });
787
- }
788
- break;
789
- case "q":
790
- case "Q":
791
- args = parsePathDataArgs(data2);
792
- for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 4) {
793
- commands.push({
794
- type,
795
- x1: args[i2],
796
- y1: args[i2 + 1],
797
- x: args[i2 + 2],
798
- y: args[i2 + 3]
799
- });
800
- }
801
- break;
802
- case "t":
803
- case "T":
804
- args = parsePathDataArgs(data2);
805
- for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
806
- commands.push({
807
- type,
808
- x: args[i2],
809
- y: args[i2 + 1]
810
- });
811
- }
812
- break;
813
- case "a":
814
- case "A":
815
- args = parsePathDataArgs(data2, [3, 4], 7);
816
- for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 7) {
817
- commands.push({
818
- type,
819
- rx: args[i2],
820
- ry: args[i2 + 1],
821
- angle: args[i2 + 2],
822
- largeArcFlag: args[i2 + 3],
823
- sweepFlag: args[i2 + 4],
824
- x: args[i2 + 5],
825
- y: args[i2 + 6]
826
- });
827
- }
828
- break;
829
- case "z":
830
- case "Z":
831
- commands.push({
832
- type
833
- });
834
- break;
835
- default:
836
- console.warn(command);
837
- }
581
+ function getDirectedArea(vertices) {
582
+ let area = 0;
583
+ const n = vertices.length;
584
+ for (let i = 0; i < n; i += 2) {
585
+ const x0 = vertices[i];
586
+ const y0 = vertices[i + 1];
587
+ const x1 = vertices[(i + 2) % (n - 1)];
588
+ const y1 = vertices[(i + 3) % n];
589
+ area += x0 * y1 - x1 * y0;
838
590
  }
839
- return commands;
591
+ return area / 2;
840
592
  }
841
593
 
842
- const dataUri = "data:image/svg+xml;";
843
- const base64DataUri = `${dataUri}base64,`;
844
- const utf8DataUri = `${dataUri}charset=utf8,`;
845
- function svgToDom(svg) {
846
- if (typeof svg === "string") {
847
- let xml;
848
- if (svg.startsWith(base64DataUri)) {
849
- svg = svg.substring(base64DataUri.length, svg.length);
850
- xml = atob(svg);
851
- } else if (svg.startsWith(utf8DataUri)) {
852
- svg = svg.substring(utf8DataUri.length, svg.length);
853
- xml = decodeURIComponent(svg);
594
+ function cross(ax, ay, bx, by, cx, cy) {
595
+ return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
596
+ }
597
+ function windingNumber(px, py, polygon) {
598
+ const polygonLen = polygon.length;
599
+ let wn = 0;
600
+ for (let i = 0, j = polygonLen - 2; i < polygonLen; j = i, i += 2) {
601
+ const xi = polygon[i];
602
+ const yi = polygon[i + 1];
603
+ const xj = polygon[j];
604
+ const yj = polygon[j + 1];
605
+ if (yi <= py) {
606
+ if (yj > py && cross(xj, yj, xi, yi, px, py) > 0)
607
+ wn++;
854
608
  } else {
855
- xml = svg;
856
- }
857
- const doc = new DOMParser().parseFromString(xml, "text/xml");
858
- const error = doc.querySelector("parsererror");
859
- if (error) {
860
- throw new Error(`${error.textContent ?? "parser error"}
861
- ${xml}`);
609
+ if (yj <= py && cross(xj, yj, xi, yi, px, py) < 0)
610
+ wn--;
862
611
  }
863
- return doc.documentElement;
864
- } else {
865
- return svg;
866
612
  }
613
+ return wn;
867
614
  }
868
-
869
- const defaultUnit = "px";
870
- const defaultDPI = 90;
871
- const units = ["mm", "cm", "in", "pt", "pc", "px"];
872
- const unitConversion = {
873
- mm: {
874
- mm: 1,
875
- cm: 0.1,
876
- in: 1 / 25.4,
877
- pt: 72 / 25.4,
878
- pc: 6 / 25.4,
879
- px: -1
880
- },
881
- cm: {
882
- mm: 10,
883
- cm: 1,
884
- in: 1 / 2.54,
885
- pt: 72 / 2.54,
886
- pc: 6 / 2.54,
887
- px: -1
888
- },
889
- in: {
890
- mm: 25.4,
891
- cm: 2.54,
892
- in: 1,
893
- pt: 72,
894
- pc: 6,
895
- px: -1
896
- },
897
- pt: {
898
- mm: 25.4 / 72,
899
- cm: 2.54 / 72,
900
- in: 1 / 72,
901
- pt: 1,
902
- pc: 6 / 72,
903
- px: -1
904
- },
905
- pc: {
906
- mm: 25.4 / 6,
907
- cm: 2.54 / 6,
908
- in: 1 / 6,
909
- pt: 72 / 6,
910
- pc: 1,
911
- px: -1
912
- },
913
- px: {
914
- px: 1
915
- }
916
- };
917
- function parseFloatWithUnits(string) {
918
- let theUnit = "px";
919
- if (typeof string === "string") {
920
- for (let i = 0, n = units.length; i < n; i++) {
921
- const u = units[i];
922
- if (string.endsWith(u)) {
923
- theUnit = u;
924
- string = string.substring(0, string.length - u.length);
925
- break;
615
+ function distance(p1, p2) {
616
+ const dx = p2[0] - p1[0];
617
+ const dy = p2[1] - p1[1];
618
+ return Math.sqrt(dx * dx + dy * dy);
619
+ }
620
+ function nonzeroFillRule(paths) {
621
+ const results = paths.map((_, i) => ({ index: i }));
622
+ const testPointsGroups = paths.map((path) => {
623
+ const len = path.length;
624
+ if (!len) {
625
+ return [];
626
+ }
627
+ let xMinYAuto = [Number.MAX_SAFE_INTEGER, 0];
628
+ let xAutoYMin = [0, Number.MAX_SAFE_INTEGER];
629
+ let xMaxYAuto = [Number.MIN_SAFE_INTEGER, 0];
630
+ let xAutoYMax = [0, Number.MIN_SAFE_INTEGER];
631
+ for (let i = 0; i < len; i += 2) {
632
+ const x = path[i];
633
+ const y = path[i + 1];
634
+ if (xMinYAuto[0] > x) {
635
+ xMinYAuto = [x, y];
636
+ }
637
+ if (xAutoYMin[1] > y) {
638
+ xAutoYMin = [x, y];
639
+ }
640
+ if (xMaxYAuto[0] < x) {
641
+ xMaxYAuto = [x, y];
642
+ }
643
+ if (xAutoYMax[1] < y) {
644
+ xAutoYMax = [x, y];
926
645
  }
927
646
  }
928
- }
929
- let scale;
930
- {
931
- scale = unitConversion[theUnit][defaultUnit];
932
- if (scale < 0) {
933
- scale = unitConversion[theUnit].in * defaultDPI;
647
+ const mid = [
648
+ (xMinYAuto[0] + xMaxYAuto[0]) / 2,
649
+ (xAutoYMin[1] + xAutoYMax[1]) / 2
650
+ ];
651
+ let xMidYMinDx;
652
+ let xMidYMaxDx;
653
+ let xMidYMin;
654
+ let xMidYMax;
655
+ let xMinYMidDy;
656
+ let xMaxYMidDy;
657
+ let xMinYMid;
658
+ let xMaxYMid;
659
+ for (let i = 0; i < len; i += 2) {
660
+ const x = path[i];
661
+ const y = path[i + 1];
662
+ const _dx = Math.abs(x - mid[0]);
663
+ const _dy = Math.abs(y - mid[1]);
664
+ if (y < mid[1] && (!xMidYMinDx || _dx < xMidYMinDx)) {
665
+ xMidYMinDx = _dx;
666
+ xMidYMin = [x, y];
667
+ }
668
+ if (y > mid[1] && (!xMidYMaxDx || _dx < xMidYMaxDx)) {
669
+ xMidYMaxDx = _dx;
670
+ xMidYMax = [x, y];
671
+ }
672
+ if (x < mid[0] && (!xMinYMidDy || _dy < xMinYMidDy)) {
673
+ xMinYMidDy = _dy;
674
+ xMinYMid = [x, y];
675
+ }
676
+ if (x > mid[0] && (!xMaxYMidDy || _dy < xMaxYMidDy)) {
677
+ xMaxYMidDy = _dy;
678
+ xMaxYMid = [x, y];
679
+ }
934
680
  }
935
- }
936
- return scale * Number.parseFloat(string);
937
- }
938
-
939
- function getNodeTransform(node, currentTransform, transformStack) {
940
- if (!(node.hasAttribute("transform") || node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y")))) {
941
- return null;
942
- }
943
- const transform = parseNodeTransform(node);
944
- if (transformStack.length > 0) {
945
- transform.prepend(transformStack[transformStack.length - 1]);
946
- }
947
- currentTransform.copyFrom(transform);
948
- transformStack.push(transform);
949
- return transform;
950
- }
951
- function parseNodeTransform(node) {
952
- const transform = new Transform2D();
953
- if (node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y"))) {
954
- transform.translate(
955
- parseFloatWithUnits(node.getAttribute("x")),
956
- parseFloatWithUnits(node.getAttribute("y"))
957
- );
958
- }
959
- if (node.hasAttribute("transform")) {
960
- transform.appendCssTransform(node.getAttribute("transform"));
961
- }
962
- return transform;
963
- }
964
-
965
- function parseCircleNode(node) {
966
- return new Path2D().arc(
967
- parseFloatWithUnits(node.getAttribute("cx") || 0),
968
- parseFloatWithUnits(node.getAttribute("cy") || 0),
969
- parseFloatWithUnits(node.getAttribute("r") || 0),
970
- 0,
971
- Math.PI * 2
972
- );
973
- }
974
-
975
- function parseCSSStylesheet(node, stylesheets) {
976
- if (!node.sheet || !node.sheet.cssRules || !node.sheet.cssRules.length)
977
- return;
978
- for (let i = 0; i < node.sheet.cssRules.length; i++) {
979
- const stylesheet = node.sheet.cssRules[i];
980
- if (stylesheet.type !== 1)
981
- continue;
982
- const selectorList = stylesheet.selectorText.split(/,/g).filter(Boolean).map((i2) => i2.trim());
983
- const definitions = {};
984
- for (let len = stylesheet.style.length, i2 = 0; i2 < len; i2++) {
985
- const name = stylesheet.style.item(i2);
986
- definitions[name] = stylesheet.style.getPropertyValue(name);
681
+ return [
682
+ xMinYAuto,
683
+ xAutoYMin,
684
+ xMaxYAuto,
685
+ xAutoYMax,
686
+ xMidYMin,
687
+ xMidYMax,
688
+ xMinYMid,
689
+ xMaxYMid
690
+ ].filter(Boolean);
691
+ });
692
+ for (let i = 0, len = paths.length; i < len; i++) {
693
+ const _results = [];
694
+ const testPoints = testPointsGroups[i];
695
+ for (let j = 0; j < len; j++) {
696
+ if (i === j)
697
+ continue;
698
+ const wnMap = {};
699
+ const wnList = [];
700
+ for (let p = 0, pLen = testPoints.length; p < pLen; p++) {
701
+ const [x, y] = testPoints[p];
702
+ const winding = windingNumber(x, y, paths[j]);
703
+ wnMap[winding] = (wnMap[winding] ?? 0) + 1;
704
+ wnList.push(winding);
705
+ }
706
+ if (wnList.filter((v) => v !== 0).length > wnList.filter((v) => v === 0).length) {
707
+ _results.push({
708
+ index: i,
709
+ parentIndex: j,
710
+ winding: Number(
711
+ Array.from(Object.entries(wnMap)).sort((a, b) => b[1] - a[1])?.[0]?.[0] ?? 0
712
+ ),
713
+ dist: distance(testPointsGroups[i][0], testPointsGroups[j][0])
714
+ });
715
+ }
987
716
  }
988
- for (let j = 0; j < selectorList.length; j++) {
989
- stylesheets[selectorList[j]] = Object.assign(
990
- stylesheets[selectorList[j]] || {},
991
- { ...definitions }
992
- );
717
+ if (_results.reduce((total, item) => total + item.winding, 0) !== 0) {
718
+ _results.sort((a, b) => a.dist - b.dist);
719
+ results[i] = _results[0];
993
720
  }
994
721
  }
722
+ return results;
995
723
  }
996
724
 
997
- function parseEllipseNode(node) {
998
- return new Path2D().ellipse(
999
- parseFloatWithUnits(node.getAttribute("cx") || 0),
1000
- parseFloatWithUnits(node.getAttribute("cy") || 0),
1001
- parseFloatWithUnits(node.getAttribute("rx") || 0),
1002
- parseFloatWithUnits(node.getAttribute("ry") || 0),
1003
- 0,
1004
- 0,
1005
- Math.PI * 2
1006
- );
725
+ function quadraticBezierP0(t, p) {
726
+ const k = 1 - t;
727
+ return k * k * p;
1007
728
  }
1008
-
1009
- function parseLineNode(node) {
1010
- return new Path2D().moveTo(
1011
- parseFloatWithUnits(node.getAttribute("x1") || 0),
1012
- parseFloatWithUnits(node.getAttribute("y1") || 0)
1013
- ).lineTo(
1014
- parseFloatWithUnits(node.getAttribute("x2") || 0),
1015
- parseFloatWithUnits(node.getAttribute("y2") || 0)
1016
- );
729
+ function quadraticBezierP1(t, p) {
730
+ return 2 * (1 - t) * t * p;
1017
731
  }
1018
-
1019
- function parsePathNode(node) {
1020
- const path = new Path2D();
1021
- const d = node.getAttribute("d");
1022
- if (!d || d === "none")
1023
- return null;
1024
- path.addData(d);
1025
- return path;
732
+ function quadraticBezierP2(t, p) {
733
+ return t * t * p;
734
+ }
735
+ function quadraticBezier(t, p0, p1, p2) {
736
+ return quadraticBezierP0(t, p0) + quadraticBezierP1(t, p1) + quadraticBezierP2(t, p2);
1026
737
  }
1027
738
 
1028
- const RE$1 = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
1029
- function parsePolygonNode(node) {
1030
- const path = new Path2D();
1031
- let index = 0;
1032
- node.getAttribute("points")?.replace(RE$1, (match, a, b) => {
1033
- const x = parseFloatWithUnits(a);
1034
- const y = parseFloatWithUnits(b);
1035
- if (index === 0) {
1036
- path.moveTo(x, y);
1037
- } else {
1038
- path.lineTo(x, y);
1039
- }
1040
- index++;
1041
- return match;
1042
- });
1043
- path.currentCurve.autoClose = true;
1044
- return path;
1045
- }
1046
-
1047
- const RE = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
1048
- function parsePolylineNode(node) {
1049
- const path = new Path2D();
1050
- let index = 0;
1051
- node.getAttribute("points")?.replace(RE, (match, a, b) => {
1052
- const x = parseFloatWithUnits(a);
1053
- const y = parseFloatWithUnits(b);
1054
- if (index === 0) {
1055
- path.moveTo(x, y);
1056
- } else {
1057
- path.lineTo(x, y);
1058
- }
1059
- index++;
1060
- return match;
1061
- });
1062
- path.currentCurve.autoClose = false;
1063
- return path;
1064
- }
1065
-
1066
- function parseRectNode(node) {
1067
- const x = parseFloatWithUnits(node.getAttribute("x") || 0);
1068
- const y = parseFloatWithUnits(node.getAttribute("y") || 0);
1069
- const rx = parseFloatWithUnits(node.getAttribute("rx") || node.getAttribute("ry") || 0);
1070
- const ry = parseFloatWithUnits(node.getAttribute("ry") || node.getAttribute("rx") || 0);
1071
- const w = parseFloatWithUnits(node.getAttribute("width"));
1072
- const h = parseFloatWithUnits(node.getAttribute("height"));
1073
- const bci = 1 - 0.551915024494;
1074
- const path = new Path2D();
1075
- path.moveTo(x + rx, y);
1076
- path.lineTo(x + w - rx, y);
1077
- if (rx !== 0 || ry !== 0) {
1078
- path.bezierCurveTo(
1079
- x + w - rx * bci,
1080
- y,
1081
- x + w,
1082
- y + ry * bci,
1083
- x + w,
1084
- y + ry
1085
- );
1086
- }
1087
- path.lineTo(x + w, y + h - ry);
1088
- if (rx !== 0 || ry !== 0) {
1089
- path.bezierCurveTo(
1090
- x + w,
1091
- y + h - ry * bci,
1092
- x + w - rx * bci,
1093
- y + h,
1094
- x + w - rx,
1095
- y + h
1096
- );
1097
- }
1098
- path.lineTo(x + rx, y + h);
1099
- if (rx !== 0 || ry !== 0) {
1100
- path.bezierCurveTo(
1101
- x + rx * bci,
1102
- y + h,
1103
- x,
1104
- y + h - ry * bci,
1105
- x,
1106
- y + h - ry
1107
- );
739
+ const closePointEps = 1e-4;
740
+ const curveEps = 1e-4;
741
+ function strokeTriangulate(points, options = {}) {
742
+ const {
743
+ vertices = [],
744
+ indices = [],
745
+ lineStyle = {
746
+ alignment: 0.5,
747
+ cap: "butt",
748
+ join: "miter",
749
+ width: 1,
750
+ miterLimit: 10
751
+ },
752
+ flipAlignment = false,
753
+ closed = true
754
+ } = options;
755
+ const eps = closePointEps;
756
+ if (points.length === 0) {
757
+ return { vertices, indices };
1108
758
  }
1109
- path.lineTo(x, y + ry);
1110
- if (rx !== 0 || ry !== 0) {
1111
- path.bezierCurveTo(x, y + ry * bci, x + rx * bci, y, x + rx, y);
759
+ const style = lineStyle;
760
+ let alignment = style.alignment;
761
+ if (lineStyle.alignment !== 0.5) {
762
+ let orientation = getOrientationOfPoints(points);
763
+ if (flipAlignment)
764
+ orientation *= -1;
765
+ alignment = (alignment - 0.5) * orientation + 0.5;
1112
766
  }
1113
- return path;
1114
- }
1115
-
1116
- function parseStyle(node, style, stylesheets) {
1117
- style = Object.assign({}, style);
1118
- let stylesheetStyles = {};
1119
- if (node.hasAttribute("class")) {
1120
- const classSelectors = node.getAttribute("class").split(/\s/).filter(Boolean).map((i) => i.trim());
1121
- for (let i = 0; i < classSelectors.length; i++) {
1122
- stylesheetStyles = Object.assign(stylesheetStyles, stylesheets[`.${classSelectors[i]}`]);
767
+ const firstPoint = { x: points[0], y: points[1] };
768
+ const lastPoint = { x: points[points.length - 2], y: points[points.length - 1] };
769
+ const closedShape = closed;
770
+ const closedPath = Math.abs(firstPoint.x - lastPoint.x) < eps && Math.abs(firstPoint.y - lastPoint.y) < eps;
771
+ if (closedShape) {
772
+ points = points.slice();
773
+ if (closedPath) {
774
+ points.pop();
775
+ points.pop();
776
+ lastPoint.x = points[points.length - 2];
777
+ lastPoint.y = points[points.length - 1];
1123
778
  }
779
+ const midPointX = (firstPoint.x + lastPoint.x) * 0.5;
780
+ const midPointY = (lastPoint.y + firstPoint.y) * 0.5;
781
+ points.unshift(midPointX, midPointY);
782
+ points.push(midPointX, midPointY);
1124
783
  }
1125
- if (node.hasAttribute("id")) {
1126
- stylesheetStyles = Object.assign(stylesheetStyles, stylesheets[`#${node.getAttribute("id")}`]);
1127
- }
1128
- for (let len = node.style.length, i = 0; i < len; i++) {
1129
- const name = node.style.item(i);
1130
- const value = node.style.getPropertyValue(name);
1131
- style[name] = value;
1132
- stylesheetStyles[name] = value;
1133
- }
1134
- function addStyle(svgName, jsName, adjustFunction = copy) {
1135
- if (node.hasAttribute(svgName))
1136
- style[jsName] = adjustFunction(node.getAttribute(svgName));
1137
- if (stylesheetStyles[svgName])
1138
- style[jsName] = adjustFunction(stylesheetStyles[svgName]);
1139
- }
1140
- function copy(v) {
1141
- if (v.startsWith("url"))
1142
- console.warn("url access in attributes is not implemented.");
1143
- return v;
1144
- }
1145
- function clamp(v) {
1146
- return Math.max(0, Math.min(1, parseFloatWithUnits(v)));
1147
- }
1148
- function positive(v) {
1149
- return Math.max(0, parseFloatWithUnits(v));
1150
- }
1151
- function array(v) {
1152
- return v.split(" ").filter((v2) => v2 !== "").map((v2) => parseFloatWithUnits(v2));
784
+ const verts = vertices;
785
+ const length = points.length / 2;
786
+ let indexCount = points.length;
787
+ const indexStart = verts.length / 2;
788
+ const width = style.width / 2;
789
+ const widthSquared = width * width;
790
+ const miterLimitSquared = style.miterLimit * style.miterLimit;
791
+ let x0 = points[0];
792
+ let y0 = points[1];
793
+ let x1 = points[2];
794
+ let y1 = points[3];
795
+ let x2 = 0;
796
+ let y2 = 0;
797
+ let perpX = -(y0 - y1);
798
+ let perpY = x0 - x1;
799
+ let perp1x = 0;
800
+ let perp1y = 0;
801
+ let dist = Math.sqrt(perpX * perpX + perpY * perpY);
802
+ perpX /= dist;
803
+ perpY /= dist;
804
+ perpX *= width;
805
+ perpY *= width;
806
+ const ratio = alignment;
807
+ const innerWeight = (1 - ratio) * 2;
808
+ const outerWeight = ratio * 2;
809
+ if (!closedShape) {
810
+ if (style.cap === "round") {
811
+ indexCount += round(
812
+ x0 - perpX * (innerWeight - outerWeight) * 0.5,
813
+ y0 - perpY * (innerWeight - outerWeight) * 0.5,
814
+ x0 - perpX * innerWeight,
815
+ y0 - perpY * innerWeight,
816
+ x0 + perpX * outerWeight,
817
+ y0 + perpY * outerWeight,
818
+ verts,
819
+ true
820
+ ) + 2;
821
+ } else if (style.cap === "square") {
822
+ indexCount += square(x0, y0, perpX, perpY, innerWeight, outerWeight, true, verts);
823
+ }
1153
824
  }
1154
- addStyle("fill", "fill");
1155
- addStyle("fill-opacity", "fillOpacity", clamp);
1156
- addStyle("fill-rule", "fillRule");
1157
- addStyle("opacity", "opacity", clamp);
1158
- addStyle("stroke", "stroke");
1159
- addStyle("stroke-opacity", "strokeOpacity", clamp);
1160
- addStyle("stroke-width", "strokeWidth", positive);
1161
- addStyle("stroke-linecap", "strokeLinecap");
1162
- addStyle("stroke-linejoin", "strokeLinejoin");
1163
- addStyle("stroke-miterlimit", "strokeMiterlimit", positive);
1164
- addStyle("stroke-dasharray", "strokeDasharray", array);
1165
- addStyle("stroke-dashoffset", "strokeDashoffset", parseFloatWithUnits);
1166
- addStyle("visibility", "visibility");
1167
- return style;
1168
- }
1169
-
1170
- function parseNode(node, style, paths = [], stylesheets = {}) {
1171
- if (node.nodeType !== 1)
1172
- return paths;
1173
- let isDefsNode = false;
1174
- let path = null;
1175
- let _style = { ...style };
1176
- switch (node.nodeName) {
1177
- case "svg":
1178
- _style = parseStyle(node, _style, stylesheets);
1179
- break;
1180
- case "style":
1181
- parseCSSStylesheet(node, stylesheets);
1182
- break;
1183
- case "g":
1184
- _style = parseStyle(node, _style, stylesheets);
1185
- break;
1186
- case "path":
1187
- _style = parseStyle(node, _style, stylesheets);
1188
- if (node.hasAttribute("d"))
1189
- path = parsePathNode(node);
1190
- break;
1191
- case "rect":
1192
- _style = parseStyle(node, _style, stylesheets);
1193
- path = parseRectNode(node);
1194
- break;
1195
- case "polygon":
1196
- _style = parseStyle(node, _style, stylesheets);
1197
- path = parsePolygonNode(node);
1198
- break;
1199
- case "polyline":
1200
- _style = parseStyle(node, _style, stylesheets);
1201
- path = parsePolylineNode(node);
1202
- break;
1203
- case "circle":
1204
- _style = parseStyle(node, _style, stylesheets);
1205
- path = parseCircleNode(node);
1206
- break;
1207
- case "ellipse":
1208
- _style = parseStyle(node, _style, stylesheets);
1209
- path = parseEllipseNode(node);
1210
- break;
1211
- case "line":
1212
- _style = parseStyle(node, _style, stylesheets);
1213
- path = parseLineNode(node);
1214
- break;
1215
- case "defs":
1216
- isDefsNode = true;
1217
- break;
1218
- case "use": {
1219
- _style = parseStyle(node, _style, stylesheets);
1220
- const href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href") || node.getAttribute("href") || "";
1221
- const usedNodeId = href.substring(1);
1222
- const usedNode = node.viewportElement?.getElementById(usedNodeId);
1223
- if (usedNode) {
1224
- parseNode(usedNode, _style, paths, stylesheets);
825
+ verts.push(
826
+ x0 - perpX * innerWeight,
827
+ y0 - perpY * innerWeight
828
+ );
829
+ verts.push(
830
+ x0 + perpX * outerWeight,
831
+ y0 + perpY * outerWeight
832
+ );
833
+ for (let i = 1; i < length - 1; ++i) {
834
+ x0 = points[(i - 1) * 2];
835
+ y0 = points[(i - 1) * 2 + 1];
836
+ x1 = points[i * 2];
837
+ y1 = points[i * 2 + 1];
838
+ x2 = points[(i + 1) * 2];
839
+ y2 = points[(i + 1) * 2 + 1];
840
+ perpX = -(y0 - y1);
841
+ perpY = x0 - x1;
842
+ dist = Math.sqrt(perpX * perpX + perpY * perpY);
843
+ perpX /= dist;
844
+ perpY /= dist;
845
+ perpX *= width;
846
+ perpY *= width;
847
+ perp1x = -(y1 - y2);
848
+ perp1y = x1 - x2;
849
+ dist = Math.sqrt(perp1x * perp1x + perp1y * perp1y);
850
+ perp1x /= dist;
851
+ perp1y /= dist;
852
+ perp1x *= width;
853
+ perp1y *= width;
854
+ const dx0 = x1 - x0;
855
+ const dy0 = y0 - y1;
856
+ const dx1 = x1 - x2;
857
+ const dy1 = y2 - y1;
858
+ const dot = dx0 * dx1 + dy0 * dy1;
859
+ const cross = dy0 * dx1 - dy1 * dx0;
860
+ const clockwise = cross < 0;
861
+ if (Math.abs(cross) < 1e-3 * Math.abs(dot)) {
862
+ verts.push(
863
+ x1 - perpX * innerWeight,
864
+ y1 - perpY * innerWeight
865
+ );
866
+ verts.push(
867
+ x1 + perpX * outerWeight,
868
+ y1 + perpY * outerWeight
869
+ );
870
+ if (dot >= 0) {
871
+ if (style.join === "round") {
872
+ indexCount += round(
873
+ x1,
874
+ y1,
875
+ x1 - perpX * innerWeight,
876
+ y1 - perpY * innerWeight,
877
+ x1 - perp1x * innerWeight,
878
+ y1 - perp1y * innerWeight,
879
+ verts,
880
+ false
881
+ ) + 4;
882
+ } else {
883
+ indexCount += 2;
884
+ }
885
+ verts.push(
886
+ x1 - perp1x * outerWeight,
887
+ y1 - perp1y * outerWeight
888
+ );
889
+ verts.push(
890
+ x1 + perp1x * innerWeight,
891
+ y1 + perp1y * innerWeight
892
+ );
893
+ }
894
+ continue;
895
+ }
896
+ const c1 = (-perpX + x0) * (-perpY + y1) - (-perpX + x1) * (-perpY + y0);
897
+ const c2 = (-perp1x + x2) * (-perp1y + y1) - (-perp1x + x1) * (-perp1y + y2);
898
+ const px = (dx0 * c2 - dx1 * c1) / cross;
899
+ const py = (dy1 * c1 - dy0 * c2) / cross;
900
+ const pDist = (px - x1) * (px - x1) + (py - y1) * (py - y1);
901
+ const imx = x1 + (px - x1) * innerWeight;
902
+ const imy = y1 + (py - y1) * innerWeight;
903
+ const omx = x1 - (px - x1) * outerWeight;
904
+ const omy = y1 - (py - y1) * outerWeight;
905
+ const smallerInsideSegmentSq = Math.min(dx0 * dx0 + dy0 * dy0, dx1 * dx1 + dy1 * dy1);
906
+ const insideWeight = clockwise ? innerWeight : outerWeight;
907
+ const smallerInsideDiagonalSq = smallerInsideSegmentSq + insideWeight * insideWeight * widthSquared;
908
+ const insideMiterOk = pDist <= smallerInsideDiagonalSq;
909
+ if (insideMiterOk) {
910
+ if (style.join === "bevel" || pDist / widthSquared > miterLimitSquared) {
911
+ if (clockwise) {
912
+ verts.push(imx, imy);
913
+ verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
914
+ verts.push(imx, imy);
915
+ verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
916
+ } else {
917
+ verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
918
+ verts.push(omx, omy);
919
+ verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
920
+ verts.push(omx, omy);
921
+ }
922
+ indexCount += 2;
923
+ } else if (style.join === "round") {
924
+ if (clockwise) {
925
+ verts.push(imx, imy);
926
+ verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
927
+ indexCount += round(
928
+ x1,
929
+ y1,
930
+ x1 + perpX * outerWeight,
931
+ y1 + perpY * outerWeight,
932
+ x1 + perp1x * outerWeight,
933
+ y1 + perp1y * outerWeight,
934
+ verts,
935
+ true
936
+ ) + 4;
937
+ verts.push(imx, imy);
938
+ verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
939
+ } else {
940
+ verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
941
+ verts.push(omx, omy);
942
+ indexCount += round(
943
+ x1,
944
+ y1,
945
+ x1 - perpX * innerWeight,
946
+ y1 - perpY * innerWeight,
947
+ x1 - perp1x * innerWeight,
948
+ y1 - perp1y * innerWeight,
949
+ verts,
950
+ false
951
+ ) + 4;
952
+ verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
953
+ verts.push(omx, omy);
954
+ }
1225
955
  } else {
1226
- console.warn(`'use node' references non-existent node id: ${usedNodeId}`);
956
+ verts.push(imx, imy);
957
+ verts.push(omx, omy);
1227
958
  }
1228
- break;
959
+ } else {
960
+ verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
961
+ verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
962
+ if (style.join === "round") {
963
+ if (clockwise) {
964
+ indexCount += round(
965
+ x1,
966
+ y1,
967
+ x1 + perpX * outerWeight,
968
+ y1 + perpY * outerWeight,
969
+ x1 + perp1x * outerWeight,
970
+ y1 + perp1y * outerWeight,
971
+ verts,
972
+ true
973
+ ) + 2;
974
+ } else {
975
+ indexCount += round(
976
+ x1,
977
+ y1,
978
+ x1 - perpX * innerWeight,
979
+ y1 - perpY * innerWeight,
980
+ x1 - perp1x * innerWeight,
981
+ y1 - perp1y * innerWeight,
982
+ verts,
983
+ false
984
+ ) + 2;
985
+ }
986
+ } else if (style.join === "miter" && pDist / widthSquared <= miterLimitSquared) {
987
+ if (clockwise) {
988
+ verts.push(omx, omy);
989
+ verts.push(omx, omy);
990
+ } else {
991
+ verts.push(imx, imy);
992
+ verts.push(imx, imy);
993
+ }
994
+ indexCount += 2;
995
+ }
996
+ verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
997
+ verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
998
+ indexCount += 2;
1229
999
  }
1230
- default:
1231
- console.warn(node);
1232
- break;
1233
- }
1234
- if (_style.display === "none") {
1235
- return paths;
1236
1000
  }
1237
- const currentTransform = new Transform2D();
1238
- const transformStack = [];
1239
- const transform = getNodeTransform(node, currentTransform, transformStack);
1240
- if (path) {
1241
- path.applyTransform(currentTransform);
1242
- paths.push(path);
1243
- path.style = { ..._style };
1001
+ x0 = points[(length - 2) * 2];
1002
+ y0 = points[(length - 2) * 2 + 1];
1003
+ x1 = points[(length - 1) * 2];
1004
+ y1 = points[(length - 1) * 2 + 1];
1005
+ perpX = -(y0 - y1);
1006
+ perpY = x0 - x1;
1007
+ dist = Math.sqrt(perpX * perpX + perpY * perpY);
1008
+ perpX /= dist;
1009
+ perpY /= dist;
1010
+ perpX *= width;
1011
+ perpY *= width;
1012
+ verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
1013
+ verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
1014
+ if (!closedShape) {
1015
+ if (style.cap === "round") {
1016
+ indexCount += round(
1017
+ x1 - perpX * (innerWeight - outerWeight) * 0.5,
1018
+ y1 - perpY * (innerWeight - outerWeight) * 0.5,
1019
+ x1 - perpX * innerWeight,
1020
+ y1 - perpY * innerWeight,
1021
+ x1 + perpX * outerWeight,
1022
+ y1 + perpY * outerWeight,
1023
+ verts,
1024
+ false
1025
+ ) + 2;
1026
+ } else if (style.cap === "square") {
1027
+ indexCount += square(x1, y1, perpX, perpY, innerWeight, outerWeight, false, verts);
1028
+ }
1244
1029
  }
1245
- const childNodes = node.childNodes;
1246
- for (let i = 0, len = childNodes.length; i < len; i++) {
1247
- const node2 = childNodes[i];
1248
- if (isDefsNode && node2.nodeName !== "style" && node2.nodeName !== "defs")
1030
+ const eps2 = curveEps * curveEps;
1031
+ for (let i = indexStart; i < indexCount + indexStart - 2; ++i) {
1032
+ x0 = verts[i * 2];
1033
+ y0 = verts[i * 2 + 1];
1034
+ x1 = verts[(i + 1) * 2];
1035
+ y1 = verts[(i + 1) * 2 + 1];
1036
+ x2 = verts[(i + 2) * 2];
1037
+ y2 = verts[(i + 2) * 2 + 1];
1038
+ if (Math.abs(x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)) < eps2) {
1249
1039
  continue;
1250
- parseNode(node2, _style, paths, stylesheets);
1251
- }
1252
- if (transform) {
1253
- transformStack.pop();
1254
- if (transformStack.length > 0) {
1255
- currentTransform.copyFrom(transformStack[transformStack.length - 1]);
1256
- } else {
1257
- currentTransform.identity();
1258
1040
  }
1041
+ indices.push(i, i + 1, i + 2);
1259
1042
  }
1260
- return paths;
1261
- }
1262
-
1263
- function svgToPath2DSet(svg) {
1264
- const dom = svgToDom(svg);
1265
- return new Path2DSet(
1266
- parseNode(dom, {}),
1267
- dom.getAttribute("viewBox")?.trim().split(" ").map((v) => Number(v))
1268
- );
1043
+ return {
1044
+ vertices,
1045
+ indices
1046
+ };
1047
+ }
1048
+ function getOrientationOfPoints(points) {
1049
+ const m = points.length;
1050
+ if (m < 6) {
1051
+ return 1;
1052
+ }
1053
+ let area = 0;
1054
+ for (let i = 0, x1 = points[m - 2], y1 = points[m - 1]; i < m; i += 2) {
1055
+ const x2 = points[i];
1056
+ const y2 = points[i + 1];
1057
+ area += (x2 - x1) * (y2 + y1);
1058
+ x1 = x2;
1059
+ y1 = y2;
1060
+ }
1061
+ if (area < 0) {
1062
+ return -1;
1063
+ }
1064
+ return 1;
1065
+ }
1066
+ function square(x, y, nx, ny, innerWeight, outerWeight, clockwise, verts) {
1067
+ const ix = x - nx * innerWeight;
1068
+ const iy = y - ny * innerWeight;
1069
+ const ox = x + nx * outerWeight;
1070
+ const oy = y + ny * outerWeight;
1071
+ let exx;
1072
+ let eyy;
1073
+ if (clockwise) {
1074
+ exx = ny;
1075
+ eyy = -nx;
1076
+ } else {
1077
+ exx = -ny;
1078
+ eyy = nx;
1079
+ }
1080
+ const eix = ix + exx;
1081
+ const eiy = iy + eyy;
1082
+ const eox = ox + exx;
1083
+ const eoy = oy + eyy;
1084
+ verts.push(eix, eiy);
1085
+ verts.push(eox, eoy);
1086
+ return 2;
1087
+ }
1088
+ function round(cx, cy, sx, sy, ex, ey, verts, clockwise) {
1089
+ const cx2p0x = sx - cx;
1090
+ const cy2p0y = sy - cy;
1091
+ let angle0 = Math.atan2(cx2p0x, cy2p0y);
1092
+ let angle1 = Math.atan2(ex - cx, ey - cy);
1093
+ if (clockwise && angle0 < angle1) {
1094
+ angle0 += Math.PI * 2;
1095
+ } else if (!clockwise && angle0 > angle1) {
1096
+ angle1 += Math.PI * 2;
1097
+ }
1098
+ let startAngle = angle0;
1099
+ const angleDiff = angle1 - angle0;
1100
+ const absAngleDiff = Math.abs(angleDiff);
1101
+ const radius = Math.sqrt(cx2p0x * cx2p0x + cy2p0y * cy2p0y);
1102
+ const segCount = (15 * absAngleDiff * Math.sqrt(radius) / Math.PI >> 0) + 1;
1103
+ const angleInc = angleDiff / segCount;
1104
+ startAngle += angleInc;
1105
+ if (clockwise) {
1106
+ verts.push(cx, cy);
1107
+ verts.push(sx, sy);
1108
+ for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
1109
+ verts.push(cx, cy);
1110
+ verts.push(cx + Math.sin(angle) * radius, cy + Math.cos(angle) * radius);
1111
+ }
1112
+ verts.push(cx, cy);
1113
+ verts.push(ex, ey);
1114
+ } else {
1115
+ verts.push(sx, sy);
1116
+ verts.push(cx, cy);
1117
+ for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
1118
+ verts.push(cx + Math.sin(angle) * radius, cy + Math.cos(angle) * radius);
1119
+ verts.push(cx, cy);
1120
+ }
1121
+ verts.push(ex, ey);
1122
+ verts.push(cx, cy);
1123
+ }
1124
+ return segCount * 2;
1269
1125
  }
1270
-
1271
- const PI = Math.PI;
1272
- const PI_2 = PI * 2;
1273
1126
 
1274
1127
  class Transform2D {
1275
1128
  constructor(a = 1, b = 0, c = 0, d = 1, tx = 0, ty = 0) {
@@ -1552,115 +1405,78 @@ class Transform2D {
1552
1405
  equals(t2d) {
1553
1406
  return t2d.a === this.a && t2d.b === this.b && t2d.c === this.c && t2d.d === this.d && t2d.tx === this.tx && t2d.ty === this.ty;
1554
1407
  }
1555
- appendCssTransform(cssTransform) {
1556
- const transformsTexts = cssTransform.split(")");
1557
- const transform = new Transform2D();
1558
- for (let tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex--) {
1559
- const transformText = transformsTexts[tIndex].trim();
1560
- if (transformText === "")
1561
- continue;
1562
- const openParPos = transformText.indexOf("(");
1563
- const closeParPos = transformText.length;
1564
- if (openParPos > 0 && openParPos < closeParPos) {
1565
- const transformType = transformText.slice(0, openParPos);
1566
- const array = parsePathDataArgs(transformText.slice(openParPos + 1));
1567
- transform.identity();
1568
- switch (transformType) {
1569
- case "translateX":
1570
- transform.translateX(array[0]);
1571
- break;
1572
- case "translateY":
1573
- transform.translateY(array[0]);
1574
- break;
1575
- case "translateZ":
1576
- transform.translateZ(array[0]);
1577
- break;
1578
- case "translate":
1579
- transform.translate(
1580
- array[0],
1581
- array[1] ?? array[0]
1582
- );
1583
- break;
1584
- case "translate3d":
1585
- transform.translate3d(
1586
- array[0],
1587
- array[1] ?? array[0],
1588
- array[2] ?? array[1] ?? array[0]
1589
- );
1590
- break;
1591
- case "scaleX":
1592
- transform.scaleX(array[0]);
1593
- break;
1594
- case "scaleY":
1595
- transform.scaleY(array[0]);
1596
- break;
1597
- case "scale":
1598
- transform.scale(
1599
- array[0],
1600
- array[1] ?? array[0]
1601
- );
1602
- break;
1603
- case "scale3d":
1604
- transform.scale3d(
1605
- array[0],
1606
- array[1] ?? array[0],
1607
- array[2] ?? array[1] ?? array[0]
1608
- );
1609
- break;
1610
- case "rotate": {
1611
- const rad = array[0] * Math.PI / 180;
1612
- if (array.length >= 3) {
1613
- const cx = array[1];
1614
- const cy = array[2];
1615
- transform.translate(-cx, -cy).rotate(rad).translate(cx, cy);
1616
- } else {
1617
- transform.rotate(rad);
1618
- }
1619
- break;
1620
- }
1621
- case "rotateX":
1622
- transform.rotateX(array[0] * Math.PI / 180);
1623
- break;
1624
- case "rotateY":
1625
- transform.rotateY(array[0] * Math.PI / 180);
1626
- break;
1627
- case "rotateZ":
1628
- transform.rotateZ(array[0] * Math.PI / 180);
1629
- break;
1630
- case "rotate3d":
1631
- transform.rotate3d(
1632
- array[0] * Math.PI / 180,
1633
- (array[1] ?? array[0]) * Math.PI / 180,
1634
- (array[2] ?? array[1] ?? array[0]) * Math.PI / 180,
1635
- (array[3] ?? array[2] ?? array[1] ?? array[0]) * Math.PI / 180
1636
- );
1637
- break;
1638
- case "skewX":
1639
- transform.set(1, 0, Math.tan(array[0] * Math.PI / 180), 1, 0, 0);
1640
- break;
1641
- case "skewY":
1642
- transform.set(1, Math.tan(array[0] * Math.PI / 180), 0, 1, 0, 0);
1643
- break;
1644
- case "skew": {
1645
- const ax = array[0];
1646
- const ay = array[1] ?? 0;
1647
- transform.set(1, Math.tan(ay * Math.PI / 180), Math.tan(ax * Math.PI / 180), 1, 0, 0);
1648
- break;
1649
- }
1650
- case "matrix":
1651
- transform.set(
1652
- array[0],
1653
- array[1],
1654
- array[2],
1655
- array[3],
1656
- array[4],
1657
- array[5]
1658
- );
1659
- break;
1660
- }
1408
+ appendCssTransform(cssTransform, ctx = {}) {
1409
+ const { width = 1, height = 1 } = ctx;
1410
+ const output = new Transform2D();
1411
+ parseCssFunctions(cssTransform, { width, height }).reverse().forEach(({ name, args }) => {
1412
+ const values = args.map((arg) => arg.normalizedIntValue);
1413
+ switch (name) {
1414
+ case "translate":
1415
+ output.translate(values[0] * width, (values[1] ?? values[0]) * height);
1416
+ break;
1417
+ case "translateX":
1418
+ output.translateX(values[0] * width);
1419
+ break;
1420
+ case "translateY":
1421
+ output.translateY(values[0] * height);
1422
+ break;
1423
+ case "translateZ":
1424
+ output.translateZ(values[0]);
1425
+ break;
1426
+ case "translate3d":
1427
+ output.translate3d(
1428
+ values[0] * width,
1429
+ (values[1] ?? values[0]) * height,
1430
+ values[2] ?? values[1] ?? values[0]
1431
+ );
1432
+ break;
1433
+ case "scale":
1434
+ output.scale(values[0], values[1] ?? values[0]);
1435
+ break;
1436
+ case "scaleX":
1437
+ output.scaleX(values[0]);
1438
+ break;
1439
+ case "scaleY":
1440
+ output.scaleY(values[0]);
1441
+ break;
1442
+ case "scale3d":
1443
+ output.scale3d(values[0], values[1] ?? values[0], values[2] ?? values[1] ?? values[0]);
1444
+ break;
1445
+ case "rotate":
1446
+ output.rotate(values[0] * PI_2);
1447
+ break;
1448
+ case "rotateX":
1449
+ output.rotateX(values[0] * PI_2);
1450
+ break;
1451
+ case "rotateY":
1452
+ output.rotateY(values[0] * PI_2);
1453
+ break;
1454
+ case "rotateZ":
1455
+ output.rotateZ(values[0] * PI_2);
1456
+ break;
1457
+ case "rotate3d":
1458
+ output.rotate3d(
1459
+ values[0] * PI_2,
1460
+ (values[1] ?? values[0]) * PI_2,
1461
+ (values[2] ?? values[1] ?? values[0]) * PI_2,
1462
+ (values[3] ?? values[2] ?? values[1] ?? values[0]) * PI_2
1463
+ );
1464
+ break;
1465
+ case "skew":
1466
+ output.skew(values[0], values[0] ?? values[1]);
1467
+ break;
1468
+ case "skewX":
1469
+ output.skewX(values[0]);
1470
+ break;
1471
+ case "skewY":
1472
+ output.skewY(values[0]);
1473
+ break;
1474
+ case "matrix":
1475
+ output.set(values[0], values[1], values[2], values[3], values[4], values[5]);
1476
+ break;
1661
1477
  }
1662
- this.prepend(transform);
1663
- }
1478
+ });
1479
+ this.prepend(output);
1664
1480
  return this;
1665
1481
  }
1666
1482
  clone() {
@@ -1702,749 +1518,976 @@ class Transform2D {
1702
1518
  }
1703
1519
  }
1704
1520
 
1705
- function catmullRom(t, p0, p1, p2, p3) {
1706
- const v0 = (p2 - p0) * 0.5;
1707
- const v1 = (p3 - p1) * 0.5;
1708
- const t2 = t * t;
1709
- const t3 = t * t2;
1710
- return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (-3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1;
1711
- }
1712
-
1713
- function cubicBezierP0(t, p) {
1714
- const k = 1 - t;
1715
- return k * k * k * p;
1716
- }
1717
- function cubicBezierP1(t, p) {
1718
- const k = 1 - t;
1719
- return 3 * k * k * t * p;
1720
- }
1721
- function cubicBezierP2(t, p) {
1722
- return 3 * (1 - t) * t * t * p;
1723
- }
1724
- function cubicBezierP3(t, p) {
1725
- return t * t * t * p;
1521
+ function svgAngle(ux, uy, vx, vy) {
1522
+ const dot = ux * vx + uy * vy;
1523
+ const len = Math.sqrt(ux * ux + uy * uy) * Math.sqrt(vx * vx + vy * vy);
1524
+ let ang = Math.acos(Math.max(-1, Math.min(1, dot / len)));
1525
+ if (ux * vy - uy * vx < 0)
1526
+ ang = -ang;
1527
+ return ang;
1726
1528
  }
1727
- function cubicBezier(t, p0, p1, p2, p3) {
1728
- return cubicBezierP0(t, p0) + cubicBezierP1(t, p1) + cubicBezierP2(t, p2) + cubicBezierP3(t, p3);
1529
+ function parseArcCommand(path, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, start, end) {
1530
+ if (rx === 0 || ry === 0) {
1531
+ path.lineTo(end.x, end.y);
1532
+ return;
1533
+ }
1534
+ xAxisRotation = xAxisRotation * Math.PI / 180;
1535
+ rx = Math.abs(rx);
1536
+ ry = Math.abs(ry);
1537
+ const dx2 = (start.x - end.x) / 2;
1538
+ const dy2 = (start.y - end.y) / 2;
1539
+ const x1p = Math.cos(xAxisRotation) * dx2 + Math.sin(xAxisRotation) * dy2;
1540
+ const y1p = -Math.sin(xAxisRotation) * dx2 + Math.cos(xAxisRotation) * dy2;
1541
+ let rxs = rx * rx;
1542
+ let rys = ry * ry;
1543
+ const x1ps = x1p * x1p;
1544
+ const y1ps = y1p * y1p;
1545
+ const cr = x1ps / rxs + y1ps / rys;
1546
+ if (cr > 1) {
1547
+ const s = Math.sqrt(cr);
1548
+ rx = s * rx;
1549
+ ry = s * ry;
1550
+ rxs = rx * rx;
1551
+ rys = ry * ry;
1552
+ }
1553
+ const dq = rxs * y1ps + rys * x1ps;
1554
+ const pq = (rxs * rys - dq) / dq;
1555
+ let q = Math.sqrt(Math.max(0, pq));
1556
+ if (largeArcFlag === sweepFlag)
1557
+ q = -q;
1558
+ const cxp = q * rx * y1p / ry;
1559
+ const cyp = -q * ry * x1p / rx;
1560
+ const cx = Math.cos(xAxisRotation) * cxp - Math.sin(xAxisRotation) * cyp + (start.x + end.x) / 2;
1561
+ const cy = Math.sin(xAxisRotation) * cxp + Math.cos(xAxisRotation) * cyp + (start.y + end.y) / 2;
1562
+ const theta = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);
1563
+ const delta = svgAngle((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry) % (Math.PI * 2);
1564
+ path.ellipse(cx, cy, rx, ry, xAxisRotation, theta, theta + delta, sweepFlag === 0);
1729
1565
  }
1730
1566
 
1731
- function fillTriangulate(pointArray, options = {}) {
1732
- let {
1733
- vertices = [],
1734
- indices = [],
1735
- holes = [],
1736
- verticesStride = 2,
1737
- verticesOffset = vertices.length / verticesStride,
1738
- indicesOffset = indices.length
1739
- } = options;
1740
- const triangles = earcut(pointArray, holes, 2);
1741
- if (triangles.length) {
1742
- for (let i = 0; i < triangles.length; i += 3) {
1743
- indices[indicesOffset++] = triangles[i] + verticesOffset;
1744
- indices[indicesOffset++] = triangles[i + 1] + verticesOffset;
1745
- indices[indicesOffset++] = triangles[i + 2] + verticesOffset;
1746
- }
1747
- let index = verticesOffset * verticesStride;
1748
- for (let i = 0; i < pointArray.length; i += 2) {
1749
- vertices[index] = pointArray[i];
1750
- vertices[index + 1] = pointArray[i + 1];
1751
- index += verticesStride;
1567
+ const RE$3 = {
1568
+ WHITESPACE: /[ \t\r\n]/,
1569
+ DIGIT: /\d/,
1570
+ SIGN: /[-+]/,
1571
+ POINT: /\./,
1572
+ COMMA: /,/,
1573
+ EXP: /e/i,
1574
+ FLAGS: /[01]/
1575
+ };
1576
+ function parsePathDataArgs(input, flags, stride = 0) {
1577
+ const SEP = 0;
1578
+ const INT = 1;
1579
+ const FLOAT = 2;
1580
+ const EXP = 3;
1581
+ let state = SEP;
1582
+ let seenComma = true;
1583
+ let number = "";
1584
+ let exponent = "";
1585
+ const result = [];
1586
+ function throwSyntaxError(current2, i, partial) {
1587
+ const error = new SyntaxError(`Unexpected character "${current2}" at index ${i}.`);
1588
+ error.partial = partial;
1589
+ throw error;
1590
+ }
1591
+ function newNumber() {
1592
+ if (number !== "") {
1593
+ if (exponent === "")
1594
+ result.push(Number(number));
1595
+ else result.push(Number(number) * 10 ** Number(exponent));
1752
1596
  }
1597
+ number = "";
1598
+ exponent = "";
1753
1599
  }
1754
- return {
1755
- vertices,
1756
- indices
1757
- };
1758
- }
1759
-
1760
- const RECURSION_LIMIT$1 = 8;
1761
- const FLT_EPSILON$1 = 11920929e-14;
1762
- const PATH_DISTANCE_EPSILON$1 = 1;
1763
- function getAdaptiveCubicBezierCurvePoints(sX, sY, x1, y1, x2, y2, x, y, smoothness = 0.5, points = []) {
1764
- const scale = 1;
1765
- const smoothing = Math.min(
1766
- 0.99,
1767
- // a value of 1.0 actually inverts smoothing, so we cap it at 0.99
1768
- Math.max(0, smoothness)
1769
- );
1770
- let distanceTolerance = (PATH_DISTANCE_EPSILON$1 - smoothing) / scale;
1771
- distanceTolerance *= distanceTolerance;
1772
- recursive$1(sX, sY, x1, y1, x2, y2, x, y, points, distanceTolerance, 0);
1773
- points.push(x, y);
1774
- return points;
1775
- }
1776
- function recursive$1(x1, y1, x2, y2, x3, y3, x4, y4, points, distanceTolerance, level) {
1777
- if (level > RECURSION_LIMIT$1)
1778
- return;
1779
- const x12 = (x1 + x2) / 2;
1780
- const y12 = (y1 + y2) / 2;
1781
- const x23 = (x2 + x3) / 2;
1782
- const y23 = (y2 + y3) / 2;
1783
- const x34 = (x3 + x4) / 2;
1784
- const y34 = (y3 + y4) / 2;
1785
- const x123 = (x12 + x23) / 2;
1786
- const y123 = (y12 + y23) / 2;
1787
- const x234 = (x23 + x34) / 2;
1788
- const y234 = (y23 + y34) / 2;
1789
- const x1234 = (x123 + x234) / 2;
1790
- const y1234 = (y123 + y234) / 2;
1791
- if (level > 0) {
1792
- let dx = x4 - x1;
1793
- let dy = y4 - y1;
1794
- const d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx);
1795
- const d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx);
1796
- if (d2 > FLT_EPSILON$1 && d3 > FLT_EPSILON$1) {
1797
- if ((d2 + d3) * (d2 + d3) <= distanceTolerance * (dx * dx + dy * dy)) {
1798
- {
1799
- points.push(x1234, y1234);
1800
- return;
1801
- }
1600
+ let current;
1601
+ const length = input.length;
1602
+ for (let i = 0; i < length; i++) {
1603
+ current = input[i];
1604
+ if (Array.isArray(flags) && flags.includes(result.length % stride) && RE$3.FLAGS.test(current)) {
1605
+ state = INT;
1606
+ number = current;
1607
+ newNumber();
1608
+ continue;
1609
+ }
1610
+ if (state === SEP) {
1611
+ if (RE$3.WHITESPACE.test(current)) {
1612
+ continue;
1802
1613
  }
1803
- } else if (d2 > FLT_EPSILON$1) {
1804
- if (d2 * d2 <= distanceTolerance * (dx * dx + dy * dy)) {
1805
- {
1806
- points.push(x1234, y1234);
1807
- return;
1808
- }
1614
+ if (RE$3.DIGIT.test(current) || RE$3.SIGN.test(current)) {
1615
+ state = INT;
1616
+ number = current;
1617
+ continue;
1809
1618
  }
1810
- } else if (d3 > FLT_EPSILON$1) {
1811
- if (d3 * d3 <= distanceTolerance * (dx * dx + dy * dy)) {
1812
- {
1813
- points.push(x1234, y1234);
1814
- return;
1619
+ if (RE$3.POINT.test(current)) {
1620
+ state = FLOAT;
1621
+ number = current;
1622
+ continue;
1623
+ }
1624
+ if (RE$3.COMMA.test(current)) {
1625
+ if (seenComma) {
1626
+ throwSyntaxError(current, i, result);
1815
1627
  }
1628
+ seenComma = true;
1816
1629
  }
1817
- } else {
1818
- dx = x1234 - (x1 + x4) / 2;
1819
- dy = y1234 - (y1 + y4) / 2;
1820
- if (dx * dx + dy * dy <= distanceTolerance) {
1821
- points.push(x1234, y1234);
1822
- return;
1630
+ }
1631
+ if (state === INT) {
1632
+ if (RE$3.DIGIT.test(current)) {
1633
+ number += current;
1634
+ continue;
1635
+ }
1636
+ if (RE$3.POINT.test(current)) {
1637
+ number += current;
1638
+ state = FLOAT;
1639
+ continue;
1640
+ }
1641
+ if (RE$3.EXP.test(current)) {
1642
+ state = EXP;
1643
+ continue;
1644
+ }
1645
+ if (RE$3.SIGN.test(current) && number.length === 1 && RE$3.SIGN.test(number[0])) {
1646
+ throwSyntaxError(current, i, result);
1823
1647
  }
1824
1648
  }
1825
- }
1826
- recursive$1(x1, y1, x12, y12, x123, y123, x1234, y1234, points, distanceTolerance, level + 1);
1827
- recursive$1(x1234, y1234, x234, y234, x34, y34, x4, y4, points, distanceTolerance, level + 1);
1828
- }
1829
-
1830
- const RECURSION_LIMIT = 8;
1831
- const FLT_EPSILON = 11920929e-14;
1832
- const PATH_DISTANCE_EPSILON = 1;
1833
- function getAdaptiveQuadraticBezierCurvePoints(sX, sY, x1, y1, x, y, smoothness = 0.5, points = []) {
1834
- const scale = 1;
1835
- const smoothing = Math.min(
1836
- 0.99,
1837
- // a value of 1.0 actually inverts smoothing, so we cap it at 0.99
1838
- Math.max(0, smoothness)
1839
- );
1840
- let distanceTolerance = (PATH_DISTANCE_EPSILON - smoothing) / scale;
1841
- distanceTolerance *= distanceTolerance;
1842
- recursive(points, sX, sY, x1, y1, x, y, distanceTolerance, 0);
1843
- points.push(x, y);
1844
- return points;
1845
- }
1846
- function recursive(points, x1, y1, x2, y2, x3, y3, distanceTolerance, level) {
1847
- if (level > RECURSION_LIMIT)
1848
- return;
1849
- const x12 = (x1 + x2) / 2;
1850
- const y12 = (y1 + y2) / 2;
1851
- const x23 = (x2 + x3) / 2;
1852
- const y23 = (y2 + y3) / 2;
1853
- const x123 = (x12 + x23) / 2;
1854
- const y123 = (y12 + y23) / 2;
1855
- let dx = x3 - x1;
1856
- let dy = y3 - y1;
1857
- const d = Math.abs((x2 - x3) * dy - (y2 - y3) * dx);
1858
- if (d > FLT_EPSILON) {
1859
- if (d * d <= distanceTolerance * (dx * dx + dy * dy)) {
1860
- {
1861
- points.push(x123, y123);
1862
- return;
1649
+ if (state === FLOAT) {
1650
+ if (RE$3.DIGIT.test(current)) {
1651
+ number += current;
1652
+ continue;
1653
+ }
1654
+ if (RE$3.EXP.test(current)) {
1655
+ state = EXP;
1656
+ continue;
1657
+ }
1658
+ if (RE$3.POINT.test(current) && number[number.length - 1] === ".") {
1659
+ throwSyntaxError(current, i, result);
1863
1660
  }
1864
1661
  }
1865
- } else {
1866
- dx = x123 - (x1 + x3) / 2;
1867
- dy = y123 - (y1 + y3) / 2;
1868
- if (dx * dx + dy * dy <= distanceTolerance) {
1869
- points.push(x123, y123);
1870
- return;
1662
+ if (state === EXP) {
1663
+ if (RE$3.DIGIT.test(current)) {
1664
+ exponent += current;
1665
+ continue;
1666
+ }
1667
+ if (RE$3.SIGN.test(current)) {
1668
+ if (exponent === "") {
1669
+ exponent += current;
1670
+ continue;
1671
+ }
1672
+ if (exponent.length === 1 && RE$3.SIGN.test(exponent)) {
1673
+ throwSyntaxError(current, i, result);
1674
+ }
1675
+ }
1871
1676
  }
1872
- }
1873
- recursive(points, x1, y1, x12, y12, x123, y123, distanceTolerance, level + 1);
1874
- recursive(points, x123, y123, x23, y23, x3, y3, distanceTolerance, level + 1);
1875
- }
1876
-
1877
- function getDirectedArea(vertices) {
1878
- let area = 0;
1879
- const n = vertices.length;
1880
- for (let i = 0; i < n; i += 2) {
1881
- const x0 = vertices[i];
1882
- const y0 = vertices[i + 1];
1883
- const x1 = vertices[(i + 2) % (n - 1)];
1884
- const y1 = vertices[(i + 3) % n];
1885
- area += x0 * y1 - x1 * y0;
1886
- }
1887
- return area / 2;
1888
- }
1889
-
1890
- function toKebabCase(str) {
1891
- return str.replace(/[^a-z0-9]/gi, "-").replace(/\B([A-Z])/g, "-$1").toLowerCase();
1892
- }
1893
- function getIntersectionPoint(p1, p2, q1, q2) {
1894
- const r = p2.clone().sub(p1);
1895
- const s = q2.clone().sub(q1);
1896
- const q1p1 = q1.clone().sub(p1);
1897
- const crossRS = r.cross(s);
1898
- if (crossRS === 0) {
1899
- return new Vector2(
1900
- (p1.x + q1.x) / 2,
1901
- (p1.y + q1.y) / 2
1902
- );
1903
- }
1904
- const t = q1p1.cross(s) / crossRS;
1905
- if (Math.abs(t) > 1) {
1906
- return new Vector2(
1907
- (p1.x + q1.x) / 2,
1908
- (p1.y + q1.y) / 2
1909
- );
1910
- }
1911
- return new Vector2(
1912
- p1.x + t * r.x,
1913
- p1.y + t * r.y
1914
- );
1915
- }
1916
-
1917
- function cross(ax, ay, bx, by, cx, cy) {
1918
- return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
1919
- }
1920
- function windingNumber(px, py, polygon) {
1921
- const polygonLen = polygon.length;
1922
- let wn = 0;
1923
- for (let i = 0, j = polygonLen - 2; i < polygonLen; j = i, i += 2) {
1924
- const xi = polygon[i];
1925
- const yi = polygon[i + 1];
1926
- const xj = polygon[j];
1927
- const yj = polygon[j + 1];
1928
- if (yi <= py) {
1929
- if (yj > py && cross(xj, yj, xi, yi, px, py) > 0)
1930
- wn++;
1677
+ if (RE$3.WHITESPACE.test(current)) {
1678
+ newNumber();
1679
+ state = SEP;
1680
+ seenComma = false;
1681
+ } else if (RE$3.COMMA.test(current)) {
1682
+ newNumber();
1683
+ state = SEP;
1684
+ seenComma = true;
1685
+ } else if (RE$3.SIGN.test(current)) {
1686
+ newNumber();
1687
+ state = INT;
1688
+ number = current;
1689
+ } else if (RE$3.POINT.test(current)) {
1690
+ newNumber();
1691
+ state = FLOAT;
1692
+ number = current;
1931
1693
  } else {
1932
- if (yj <= py && cross(xj, yj, xi, yi, px, py) < 0)
1933
- wn--;
1694
+ throwSyntaxError(current, i, result);
1934
1695
  }
1935
1696
  }
1936
- return wn;
1697
+ newNumber();
1698
+ return result;
1937
1699
  }
1938
- function distance(p1, p2) {
1939
- const dx = p2[0] - p1[0];
1940
- const dy = p2[1] - p1[1];
1941
- return Math.sqrt(dx * dx + dy * dy);
1700
+
1701
+ function getReflection(a, b) {
1702
+ return a - (b - a);
1942
1703
  }
1943
- function nonzeroFillRule(paths) {
1944
- const results = paths.map((_, i) => ({ index: i }));
1945
- const testPointsGroups = paths.map((path) => {
1946
- const len = path.length;
1947
- if (!len) {
1948
- return [];
1949
- }
1950
- let xMinYAuto = [Number.MAX_SAFE_INTEGER, 0];
1951
- let xAutoYMin = [0, Number.MAX_SAFE_INTEGER];
1952
- let xMaxYAuto = [Number.MIN_SAFE_INTEGER, 0];
1953
- let xAutoYMax = [0, Number.MIN_SAFE_INTEGER];
1954
- for (let i = 0; i < len; i += 2) {
1955
- const x = path[i];
1956
- const y = path[i + 1];
1957
- if (xMinYAuto[0] > x) {
1958
- xMinYAuto = [x, y];
1704
+ function svgPathCommandsAddToPath2D(commands, path) {
1705
+ const current = new Vector2();
1706
+ const control = new Vector2();
1707
+ for (let i = 0, l = commands.length; i < l; i++) {
1708
+ const cmd = commands[i];
1709
+ if (cmd.type === "m" || cmd.type === "M") {
1710
+ if (cmd.type === "m") {
1711
+ current.add(cmd);
1712
+ } else {
1713
+ current.copyFrom(cmd);
1959
1714
  }
1960
- if (xAutoYMin[1] > y) {
1961
- xAutoYMin = [x, y];
1715
+ path.moveTo(current.x, current.y);
1716
+ control.copyFrom(current);
1717
+ } else if (cmd.type === "h" || cmd.type === "H") {
1718
+ if (cmd.type === "h") {
1719
+ current.x += cmd.x;
1720
+ } else {
1721
+ current.x = cmd.x;
1962
1722
  }
1963
- if (xMaxYAuto[0] < x) {
1964
- xMaxYAuto = [x, y];
1723
+ path.lineTo(current.x, current.y);
1724
+ control.copyFrom(current);
1725
+ } else if (cmd.type === "v" || cmd.type === "V") {
1726
+ if (cmd.type === "v") {
1727
+ current.y += cmd.y;
1728
+ } else {
1729
+ current.y = cmd.y;
1965
1730
  }
1966
- if (xAutoYMax[1] < y) {
1967
- xAutoYMax = [x, y];
1731
+ path.lineTo(current.x, current.y);
1732
+ control.copyFrom(current);
1733
+ } else if (cmd.type === "l" || cmd.type === "L") {
1734
+ if (cmd.type === "l") {
1735
+ current.add(cmd);
1736
+ } else {
1737
+ current.copyFrom(cmd);
1968
1738
  }
1969
- }
1970
- const mid = [
1971
- (xMinYAuto[0] + xMaxYAuto[0]) / 2,
1972
- (xAutoYMin[1] + xAutoYMax[1]) / 2
1973
- ];
1974
- let xMidYMinDx;
1975
- let xMidYMaxDx;
1976
- let xMidYMin;
1977
- let xMidYMax;
1978
- let xMinYMidDy;
1979
- let xMaxYMidDy;
1980
- let xMinYMid;
1981
- let xMaxYMid;
1982
- for (let i = 0; i < len; i += 2) {
1983
- const x = path[i];
1984
- const y = path[i + 1];
1985
- const _dx = Math.abs(x - mid[0]);
1986
- const _dy = Math.abs(y - mid[1]);
1987
- if (y < mid[1] && (!xMidYMinDx || _dx < xMidYMinDx)) {
1988
- xMidYMinDx = _dx;
1989
- xMidYMin = [x, y];
1739
+ path.lineTo(current.x, current.y);
1740
+ control.copyFrom(current);
1741
+ } else if (cmd.type === "c" || cmd.type === "C") {
1742
+ if (cmd.type === "c") {
1743
+ path.bezierCurveTo(
1744
+ current.x + cmd.x1,
1745
+ current.y + cmd.y1,
1746
+ current.x + cmd.x2,
1747
+ current.y + cmd.y2,
1748
+ current.x + cmd.x,
1749
+ current.y + cmd.y
1750
+ );
1751
+ control.x = current.x + cmd.x2;
1752
+ control.y = current.y + cmd.y2;
1753
+ current.add(cmd);
1754
+ } else {
1755
+ path.bezierCurveTo(
1756
+ cmd.x1,
1757
+ cmd.y1,
1758
+ cmd.x2,
1759
+ cmd.y2,
1760
+ cmd.x,
1761
+ cmd.y
1762
+ );
1763
+ control.x = cmd.x2;
1764
+ control.y = cmd.y2;
1765
+ current.copyFrom(cmd);
1990
1766
  }
1991
- if (y > mid[1] && (!xMidYMaxDx || _dx < xMidYMaxDx)) {
1992
- xMidYMaxDx = _dx;
1993
- xMidYMax = [x, y];
1767
+ } else if (cmd.type === "s" || cmd.type === "S") {
1768
+ if (cmd.type === "s") {
1769
+ path.bezierCurveTo(
1770
+ getReflection(current.x, control.x),
1771
+ getReflection(current.y, control.y),
1772
+ current.x + cmd.x2,
1773
+ current.y + cmd.y2,
1774
+ current.x + cmd.x,
1775
+ current.y + cmd.y
1776
+ );
1777
+ control.x = current.x + cmd.x2;
1778
+ control.y = current.y + cmd.y2;
1779
+ current.add(cmd);
1780
+ } else {
1781
+ path.bezierCurveTo(
1782
+ getReflection(current.x, control.x),
1783
+ getReflection(current.y, control.y),
1784
+ cmd.x2,
1785
+ cmd.y2,
1786
+ cmd.x,
1787
+ cmd.y
1788
+ );
1789
+ control.x = cmd.x2;
1790
+ control.y = cmd.y2;
1791
+ current.copyFrom(cmd);
1994
1792
  }
1995
- if (x < mid[0] && (!xMinYMidDy || _dy < xMinYMidDy)) {
1996
- xMinYMidDy = _dy;
1997
- xMinYMid = [x, y];
1793
+ } else if (cmd.type === "q" || cmd.type === "Q") {
1794
+ if (cmd.type === "q") {
1795
+ path.quadraticCurveTo(
1796
+ current.x + cmd.x1,
1797
+ current.y + cmd.y1,
1798
+ current.x + cmd.x,
1799
+ current.y + cmd.y
1800
+ );
1801
+ control.x = current.x + cmd.x1;
1802
+ control.y = current.y + cmd.y1;
1803
+ current.add(cmd);
1804
+ } else {
1805
+ path.quadraticCurveTo(
1806
+ cmd.x1,
1807
+ cmd.y1,
1808
+ cmd.x,
1809
+ cmd.y
1810
+ );
1811
+ control.x = cmd.x1;
1812
+ control.y = cmd.y1;
1813
+ current.copyFrom(cmd);
1998
1814
  }
1999
- if (x > mid[0] && (!xMaxYMidDy || _dy < xMaxYMidDy)) {
2000
- xMaxYMidDy = _dy;
2001
- xMaxYMid = [x, y];
1815
+ } else if (cmd.type === "t" || cmd.type === "T") {
1816
+ const rx = getReflection(current.x, control.x);
1817
+ const ry = getReflection(current.y, control.y);
1818
+ control.x = rx;
1819
+ control.y = ry;
1820
+ if (cmd.type === "t") {
1821
+ path.quadraticCurveTo(
1822
+ rx,
1823
+ ry,
1824
+ current.x + cmd.x,
1825
+ current.y + cmd.y
1826
+ );
1827
+ current.add(cmd);
1828
+ } else {
1829
+ path.quadraticCurveTo(
1830
+ rx,
1831
+ ry,
1832
+ cmd.x,
1833
+ cmd.y
1834
+ );
1835
+ current.copyFrom(cmd);
2002
1836
  }
2003
- }
2004
- return [
2005
- xMinYAuto,
2006
- xAutoYMin,
2007
- xMaxYAuto,
2008
- xAutoYMax,
2009
- xMidYMin,
2010
- xMidYMax,
2011
- xMinYMid,
2012
- xMaxYMid
2013
- ].filter(Boolean);
2014
- });
2015
- for (let i = 0, len = paths.length; i < len; i++) {
2016
- const _results = [];
2017
- const testPoints = testPointsGroups[i];
2018
- for (let j = 0; j < len; j++) {
2019
- if (i === j)
2020
- continue;
2021
- const wnMap = {};
2022
- const wnList = [];
2023
- for (let p = 0, pLen = testPoints.length; p < pLen; p++) {
2024
- const [x, y] = testPoints[p];
2025
- const winding = windingNumber(x, y, paths[j]);
2026
- wnMap[winding] = (wnMap[winding] ?? 0) + 1;
2027
- wnList.push(winding);
1837
+ } else if (cmd.type === "a" || cmd.type === "A") {
1838
+ const start = current.clone();
1839
+ if (cmd.type === "a") {
1840
+ if (cmd.x === 0 && cmd.y === 0)
1841
+ continue;
1842
+ current.add(cmd);
1843
+ } else {
1844
+ if (current.equals(cmd))
1845
+ continue;
1846
+ current.copyFrom(cmd);
2028
1847
  }
2029
- if (wnList.filter((v) => v !== 0).length > wnList.filter((v) => v === 0).length) {
2030
- _results.push({
2031
- index: i,
2032
- parentIndex: j,
2033
- winding: Number(
2034
- Array.from(Object.entries(wnMap)).sort((a, b) => b[1] - a[1])?.[0]?.[0] ?? 0
2035
- ),
2036
- dist: distance(testPointsGroups[i][0], testPointsGroups[j][0])
2037
- });
1848
+ control.copyFrom(current);
1849
+ parseArcCommand(
1850
+ path,
1851
+ cmd.rx,
1852
+ cmd.ry,
1853
+ cmd.angle,
1854
+ cmd.largeArcFlag,
1855
+ cmd.sweepFlag,
1856
+ start,
1857
+ current
1858
+ );
1859
+ } else if (cmd.type === "z" || cmd.type === "Z") {
1860
+ if (path.startPoint) {
1861
+ current.copyFrom(path.startPoint);
2038
1862
  }
2039
- }
2040
- if (_results.reduce((total, item) => total + item.winding, 0) !== 0) {
2041
- _results.sort((a, b) => a.dist - b.dist);
2042
- results[i] = _results[0];
1863
+ path.closePath();
1864
+ } else {
1865
+ console.warn("Unsupported commands", cmd);
2043
1866
  }
2044
1867
  }
2045
- return results;
2046
- }
2047
-
2048
- function quadraticBezierP0(t, p) {
2049
- const k = 1 - t;
2050
- return k * k * p;
2051
- }
2052
- function quadraticBezierP1(t, p) {
2053
- return 2 * (1 - t) * t * p;
2054
- }
2055
- function quadraticBezierP2(t, p) {
2056
- return t * t * p;
2057
- }
2058
- function quadraticBezier(t, p0, p1, p2) {
2059
- return quadraticBezierP0(t, p0) + quadraticBezierP1(t, p1) + quadraticBezierP2(t, p2);
2060
1868
  }
2061
1869
 
2062
- const closePointEps = 1e-4;
2063
- const curveEps = 1e-4;
2064
- function strokeTriangulate(points, options = {}) {
2065
- const {
2066
- vertices = [],
2067
- indices = [],
2068
- lineStyle = {
2069
- alignment: 0.5,
2070
- cap: "butt",
2071
- join: "miter",
2072
- width: 1,
2073
- miterLimit: 10
2074
- },
2075
- flipAlignment = false,
2076
- closed = true
2077
- } = options;
2078
- const eps = closePointEps;
2079
- if (points.length === 0) {
2080
- return { vertices, indices };
2081
- }
2082
- const style = lineStyle;
2083
- let alignment = style.alignment;
2084
- if (lineStyle.alignment !== 0.5) {
2085
- let orientation = getOrientationOfPoints(points);
2086
- if (flipAlignment)
2087
- orientation *= -1;
2088
- alignment = (alignment - 0.5) * orientation + 0.5;
2089
- }
2090
- const firstPoint = { x: points[0], y: points[1] };
2091
- const lastPoint = { x: points[points.length - 2], y: points[points.length - 1] };
2092
- const closedShape = closed;
2093
- const closedPath = Math.abs(firstPoint.x - lastPoint.x) < eps && Math.abs(firstPoint.y - lastPoint.y) < eps;
2094
- if (closedShape) {
2095
- points = points.slice();
2096
- if (closedPath) {
2097
- points.pop();
2098
- points.pop();
2099
- lastPoint.x = points[points.length - 2];
2100
- lastPoint.y = points[points.length - 1];
1870
+ function svgPathCommandsToData(commands) {
1871
+ let first;
1872
+ let prev;
1873
+ const data = [];
1874
+ for (let i = 0, len = commands.length; i < len; i++) {
1875
+ const cmd = commands[i];
1876
+ switch (cmd.type) {
1877
+ case "m":
1878
+ case "M":
1879
+ if (cmd.x.toFixed(4) === prev?.x.toFixed(4) && cmd.y.toFixed(4) === prev?.y.toFixed(4)) {
1880
+ continue;
1881
+ }
1882
+ data.push(`${cmd.type} ${cmd.x} ${cmd.y}`);
1883
+ prev = { x: cmd.x, y: cmd.y };
1884
+ first = { x: cmd.x, y: cmd.y };
1885
+ break;
1886
+ case "h":
1887
+ case "H":
1888
+ data.push(`${cmd.type} ${cmd.x}`);
1889
+ prev = { x: cmd.x, y: prev?.y ?? 0 };
1890
+ break;
1891
+ case "v":
1892
+ case "V":
1893
+ data.push(`${cmd.type} ${cmd.y}`);
1894
+ prev = { x: prev?.x ?? 0, y: cmd.y };
1895
+ break;
1896
+ case "l":
1897
+ case "L":
1898
+ data.push(`${cmd.type} ${cmd.x} ${cmd.y}`);
1899
+ prev = { x: cmd.x, y: cmd.y };
1900
+ break;
1901
+ case "c":
1902
+ case "C":
1903
+ data.push(`${cmd.type} ${cmd.x1} ${cmd.y1} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`);
1904
+ prev = { x: cmd.x, y: cmd.y };
1905
+ break;
1906
+ case "s":
1907
+ case "S":
1908
+ data.push(`${cmd.type} ${cmd.x2} ${cmd.y2} ${cmd.x} ${cmd.y}`);
1909
+ prev = { x: cmd.x, y: cmd.y };
1910
+ break;
1911
+ case "q":
1912
+ case "Q":
1913
+ data.push(`${cmd.type} ${cmd.x1} ${cmd.y1} ${cmd.x} ${cmd.y}`);
1914
+ prev = { x: cmd.x, y: cmd.y };
1915
+ break;
1916
+ case "t":
1917
+ case "T":
1918
+ data.push(`${cmd.type} ${cmd.x} ${cmd.y}`);
1919
+ prev = { x: cmd.x, y: cmd.y };
1920
+ break;
1921
+ case "a":
1922
+ case "A":
1923
+ data.push(`${cmd.type} ${cmd.rx} ${cmd.ry} ${cmd.angle} ${cmd.largeArcFlag} ${cmd.sweepFlag} ${cmd.x} ${cmd.y}`);
1924
+ prev = { x: cmd.x, y: cmd.y };
1925
+ break;
1926
+ case "z":
1927
+ case "Z":
1928
+ data.push(cmd.type);
1929
+ if (first) {
1930
+ prev = { x: first.x, y: first.y };
1931
+ }
1932
+ break;
2101
1933
  }
2102
- const midPointX = (firstPoint.x + lastPoint.x) * 0.5;
2103
- const midPointY = (lastPoint.y + firstPoint.y) * 0.5;
2104
- points.unshift(midPointX, midPointY);
2105
- points.push(midPointX, midPointY);
2106
1934
  }
2107
- const verts = vertices;
2108
- const length = points.length / 2;
2109
- let indexCount = points.length;
2110
- const indexStart = verts.length / 2;
2111
- const width = style.width / 2;
2112
- const widthSquared = width * width;
2113
- const miterLimitSquared = style.miterLimit * style.miterLimit;
2114
- let x0 = points[0];
2115
- let y0 = points[1];
2116
- let x1 = points[2];
2117
- let y1 = points[3];
2118
- let x2 = 0;
2119
- let y2 = 0;
2120
- let perpX = -(y0 - y1);
2121
- let perpY = x0 - x1;
2122
- let perp1x = 0;
2123
- let perp1y = 0;
2124
- let dist = Math.sqrt(perpX * perpX + perpY * perpY);
2125
- perpX /= dist;
2126
- perpY /= dist;
2127
- perpX *= width;
2128
- perpY *= width;
2129
- const ratio = alignment;
2130
- const innerWeight = (1 - ratio) * 2;
2131
- const outerWeight = ratio * 2;
2132
- if (!closedShape) {
2133
- if (style.cap === "round") {
2134
- indexCount += round(
2135
- x0 - perpX * (innerWeight - outerWeight) * 0.5,
2136
- y0 - perpY * (innerWeight - outerWeight) * 0.5,
2137
- x0 - perpX * innerWeight,
2138
- y0 - perpY * innerWeight,
2139
- x0 + perpX * outerWeight,
2140
- y0 + perpY * outerWeight,
2141
- verts,
2142
- true
2143
- ) + 2;
2144
- } else if (style.cap === "square") {
2145
- indexCount += square(x0, y0, perpX, perpY, innerWeight, outerWeight, true, verts);
2146
- }
1935
+ return data.join(" ");
1936
+ }
1937
+
1938
+ const RE$2 = /[a-df-z][^a-df-z]*/gi;
1939
+ function svgPathDataToCommands(data) {
1940
+ const commands = [];
1941
+ const matched = data.match(RE$2);
1942
+ if (!matched) {
1943
+ return commands;
2147
1944
  }
2148
- verts.push(
2149
- x0 - perpX * innerWeight,
2150
- y0 - perpY * innerWeight
2151
- );
2152
- verts.push(
2153
- x0 + perpX * outerWeight,
2154
- y0 + perpY * outerWeight
2155
- );
2156
- for (let i = 1; i < length - 1; ++i) {
2157
- x0 = points[(i - 1) * 2];
2158
- y0 = points[(i - 1) * 2 + 1];
2159
- x1 = points[i * 2];
2160
- y1 = points[i * 2 + 1];
2161
- x2 = points[(i + 1) * 2];
2162
- y2 = points[(i + 1) * 2 + 1];
2163
- perpX = -(y0 - y1);
2164
- perpY = x0 - x1;
2165
- dist = Math.sqrt(perpX * perpX + perpY * perpY);
2166
- perpX /= dist;
2167
- perpY /= dist;
2168
- perpX *= width;
2169
- perpY *= width;
2170
- perp1x = -(y1 - y2);
2171
- perp1y = x1 - x2;
2172
- dist = Math.sqrt(perp1x * perp1x + perp1y * perp1y);
2173
- perp1x /= dist;
2174
- perp1y /= dist;
2175
- perp1x *= width;
2176
- perp1y *= width;
2177
- const dx0 = x1 - x0;
2178
- const dy0 = y0 - y1;
2179
- const dx1 = x1 - x2;
2180
- const dy1 = y2 - y1;
2181
- const dot = dx0 * dx1 + dy0 * dy1;
2182
- const cross = dy0 * dx1 - dy1 * dx0;
2183
- const clockwise = cross < 0;
2184
- if (Math.abs(cross) < 1e-3 * Math.abs(dot)) {
2185
- verts.push(
2186
- x1 - perpX * innerWeight,
2187
- y1 - perpY * innerWeight
2188
- );
2189
- verts.push(
2190
- x1 + perpX * outerWeight,
2191
- y1 + perpY * outerWeight
2192
- );
2193
- if (dot >= 0) {
2194
- if (style.join === "round") {
2195
- indexCount += round(
2196
- x1,
2197
- y1,
2198
- x1 - perpX * innerWeight,
2199
- y1 - perpY * innerWeight,
2200
- x1 - perp1x * innerWeight,
2201
- y1 - perp1y * innerWeight,
2202
- verts,
2203
- false
2204
- ) + 4;
2205
- } else {
2206
- indexCount += 2;
1945
+ for (let i = 0, len = matched.length; i < len; i++) {
1946
+ const command = matched[i];
1947
+ const type = command.charAt(0);
1948
+ const data2 = command.slice(1).trim();
1949
+ let args;
1950
+ switch (type) {
1951
+ case "m":
1952
+ case "M":
1953
+ args = parsePathDataArgs(data2);
1954
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
1955
+ if (i2 === 0) {
1956
+ commands.push({ type, x: args[i2], y: args[i2 + 1] });
1957
+ } else {
1958
+ commands.push({ type: type === "m" ? "l" : "L", x: args[i2], y: args[i2 + 1] });
1959
+ }
2207
1960
  }
2208
- verts.push(
2209
- x1 - perp1x * outerWeight,
2210
- y1 - perp1y * outerWeight
2211
- );
2212
- verts.push(
2213
- x1 + perp1x * innerWeight,
2214
- y1 + perp1y * innerWeight
2215
- );
2216
- }
2217
- continue;
2218
- }
2219
- const c1 = (-perpX + x0) * (-perpY + y1) - (-perpX + x1) * (-perpY + y0);
2220
- const c2 = (-perp1x + x2) * (-perp1y + y1) - (-perp1x + x1) * (-perp1y + y2);
2221
- const px = (dx0 * c2 - dx1 * c1) / cross;
2222
- const py = (dy1 * c1 - dy0 * c2) / cross;
2223
- const pDist = (px - x1) * (px - x1) + (py - y1) * (py - y1);
2224
- const imx = x1 + (px - x1) * innerWeight;
2225
- const imy = y1 + (py - y1) * innerWeight;
2226
- const omx = x1 - (px - x1) * outerWeight;
2227
- const omy = y1 - (py - y1) * outerWeight;
2228
- const smallerInsideSegmentSq = Math.min(dx0 * dx0 + dy0 * dy0, dx1 * dx1 + dy1 * dy1);
2229
- const insideWeight = clockwise ? innerWeight : outerWeight;
2230
- const smallerInsideDiagonalSq = smallerInsideSegmentSq + insideWeight * insideWeight * widthSquared;
2231
- const insideMiterOk = pDist <= smallerInsideDiagonalSq;
2232
- if (insideMiterOk) {
2233
- if (style.join === "bevel" || pDist / widthSquared > miterLimitSquared) {
2234
- if (clockwise) {
2235
- verts.push(imx, imy);
2236
- verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
2237
- verts.push(imx, imy);
2238
- verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
2239
- } else {
2240
- verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
2241
- verts.push(omx, omy);
2242
- verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
2243
- verts.push(omx, omy);
1961
+ break;
1962
+ case "h":
1963
+ case "H":
1964
+ args = parsePathDataArgs(data2);
1965
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2++) {
1966
+ commands.push({ type, x: args[i2] });
2244
1967
  }
2245
- indexCount += 2;
2246
- } else if (style.join === "round") {
2247
- if (clockwise) {
2248
- verts.push(imx, imy);
2249
- verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
2250
- indexCount += round(
2251
- x1,
2252
- y1,
2253
- x1 + perpX * outerWeight,
2254
- y1 + perpY * outerWeight,
2255
- x1 + perp1x * outerWeight,
2256
- y1 + perp1y * outerWeight,
2257
- verts,
2258
- true
2259
- ) + 4;
2260
- verts.push(imx, imy);
2261
- verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
2262
- } else {
2263
- verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
2264
- verts.push(omx, omy);
2265
- indexCount += round(
2266
- x1,
2267
- y1,
2268
- x1 - perpX * innerWeight,
2269
- y1 - perpY * innerWeight,
2270
- x1 - perp1x * innerWeight,
2271
- y1 - perp1y * innerWeight,
2272
- verts,
2273
- false
2274
- ) + 4;
2275
- verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
2276
- verts.push(omx, omy);
1968
+ break;
1969
+ case "v":
1970
+ case "V":
1971
+ args = parsePathDataArgs(data2);
1972
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2++) {
1973
+ commands.push({ type, y: args[i2] });
2277
1974
  }
2278
- } else {
2279
- verts.push(imx, imy);
2280
- verts.push(omx, omy);
2281
- }
2282
- } else {
2283
- verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
2284
- verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
2285
- if (style.join === "round") {
2286
- if (clockwise) {
2287
- indexCount += round(
2288
- x1,
2289
- y1,
2290
- x1 + perpX * outerWeight,
2291
- y1 + perpY * outerWeight,
2292
- x1 + perp1x * outerWeight,
2293
- y1 + perp1y * outerWeight,
2294
- verts,
2295
- true
2296
- ) + 2;
2297
- } else {
2298
- indexCount += round(
2299
- x1,
2300
- y1,
2301
- x1 - perpX * innerWeight,
2302
- y1 - perpY * innerWeight,
2303
- x1 - perp1x * innerWeight,
2304
- y1 - perp1y * innerWeight,
2305
- verts,
2306
- false
2307
- ) + 2;
1975
+ break;
1976
+ case "l":
1977
+ case "L":
1978
+ args = parsePathDataArgs(data2);
1979
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
1980
+ commands.push({ type, x: args[i2], y: args[i2 + 1] });
2308
1981
  }
2309
- } else if (style.join === "miter" && pDist / widthSquared <= miterLimitSquared) {
2310
- if (clockwise) {
2311
- verts.push(omx, omy);
2312
- verts.push(omx, omy);
2313
- } else {
2314
- verts.push(imx, imy);
2315
- verts.push(imx, imy);
1982
+ break;
1983
+ case "c":
1984
+ case "C":
1985
+ args = parsePathDataArgs(data2);
1986
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 6) {
1987
+ commands.push({
1988
+ type,
1989
+ x1: args[i2],
1990
+ y1: args[i2 + 1],
1991
+ x2: args[i2 + 2],
1992
+ y2: args[i2 + 3],
1993
+ x: args[i2 + 4],
1994
+ y: args[i2 + 5]
1995
+ });
2316
1996
  }
2317
- indexCount += 2;
1997
+ break;
1998
+ case "s":
1999
+ case "S":
2000
+ args = parsePathDataArgs(data2);
2001
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 4) {
2002
+ commands.push({
2003
+ type,
2004
+ x2: args[i2],
2005
+ y2: args[i2 + 1],
2006
+ x: args[i2 + 2],
2007
+ y: args[i2 + 3]
2008
+ });
2009
+ }
2010
+ break;
2011
+ case "q":
2012
+ case "Q":
2013
+ args = parsePathDataArgs(data2);
2014
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 4) {
2015
+ commands.push({
2016
+ type,
2017
+ x1: args[i2],
2018
+ y1: args[i2 + 1],
2019
+ x: args[i2 + 2],
2020
+ y: args[i2 + 3]
2021
+ });
2022
+ }
2023
+ break;
2024
+ case "t":
2025
+ case "T":
2026
+ args = parsePathDataArgs(data2);
2027
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 2) {
2028
+ commands.push({
2029
+ type,
2030
+ x: args[i2],
2031
+ y: args[i2 + 1]
2032
+ });
2033
+ }
2034
+ break;
2035
+ case "a":
2036
+ case "A":
2037
+ args = parsePathDataArgs(data2, [3, 4], 7);
2038
+ for (let i2 = 0, len2 = args.length; i2 < len2; i2 += 7) {
2039
+ commands.push({
2040
+ type,
2041
+ rx: args[i2],
2042
+ ry: args[i2 + 1],
2043
+ angle: args[i2 + 2],
2044
+ largeArcFlag: args[i2 + 3],
2045
+ sweepFlag: args[i2 + 4],
2046
+ x: args[i2 + 5],
2047
+ y: args[i2 + 6]
2048
+ });
2049
+ }
2050
+ break;
2051
+ case "z":
2052
+ case "Z":
2053
+ commands.push({
2054
+ type
2055
+ });
2056
+ break;
2057
+ default:
2058
+ console.warn(command);
2059
+ }
2060
+ }
2061
+ return commands;
2062
+ }
2063
+
2064
+ const dataUri = "data:image/svg+xml;";
2065
+ const base64DataUri = `${dataUri}base64,`;
2066
+ const utf8DataUri = `${dataUri}charset=utf8,`;
2067
+ function svgToDom(svg) {
2068
+ if (typeof svg === "string") {
2069
+ let xml;
2070
+ if (svg.startsWith(base64DataUri)) {
2071
+ svg = svg.substring(base64DataUri.length, svg.length);
2072
+ xml = atob(svg);
2073
+ } else if (svg.startsWith(utf8DataUri)) {
2074
+ svg = svg.substring(utf8DataUri.length, svg.length);
2075
+ xml = decodeURIComponent(svg);
2076
+ } else {
2077
+ xml = svg;
2078
+ }
2079
+ const doc = new DOMParser().parseFromString(xml, "text/xml");
2080
+ const error = doc.querySelector("parsererror");
2081
+ if (error) {
2082
+ throw new Error(`${error.textContent ?? "parser error"}
2083
+ ${xml}`);
2084
+ }
2085
+ return doc.documentElement;
2086
+ } else {
2087
+ return svg;
2088
+ }
2089
+ }
2090
+
2091
+ const defaultUnit = "px";
2092
+ const defaultDPI = 90;
2093
+ const units = ["mm", "cm", "in", "pt", "pc", "px"];
2094
+ const unitConversion = {
2095
+ mm: {
2096
+ mm: 1,
2097
+ cm: 0.1,
2098
+ in: 1 / 25.4,
2099
+ pt: 72 / 25.4,
2100
+ pc: 6 / 25.4,
2101
+ px: -1
2102
+ },
2103
+ cm: {
2104
+ mm: 10,
2105
+ cm: 1,
2106
+ in: 1 / 2.54,
2107
+ pt: 72 / 2.54,
2108
+ pc: 6 / 2.54,
2109
+ px: -1
2110
+ },
2111
+ in: {
2112
+ mm: 25.4,
2113
+ cm: 2.54,
2114
+ in: 1,
2115
+ pt: 72,
2116
+ pc: 6,
2117
+ px: -1
2118
+ },
2119
+ pt: {
2120
+ mm: 25.4 / 72,
2121
+ cm: 2.54 / 72,
2122
+ in: 1 / 72,
2123
+ pt: 1,
2124
+ pc: 6 / 72,
2125
+ px: -1
2126
+ },
2127
+ pc: {
2128
+ mm: 25.4 / 6,
2129
+ cm: 2.54 / 6,
2130
+ in: 1 / 6,
2131
+ pt: 72 / 6,
2132
+ pc: 1,
2133
+ px: -1
2134
+ },
2135
+ px: {
2136
+ px: 1
2137
+ }
2138
+ };
2139
+ function parseFloatWithUnits(string) {
2140
+ let theUnit = "px";
2141
+ if (typeof string === "string") {
2142
+ for (let i = 0, n = units.length; i < n; i++) {
2143
+ const u = units[i];
2144
+ if (string.endsWith(u)) {
2145
+ theUnit = u;
2146
+ string = string.substring(0, string.length - u.length);
2147
+ break;
2318
2148
  }
2319
- verts.push(x1 - perp1x * innerWeight, y1 - perp1y * innerWeight);
2320
- verts.push(x1 + perp1x * outerWeight, y1 + perp1y * outerWeight);
2321
- indexCount += 2;
2322
2149
  }
2323
2150
  }
2324
- x0 = points[(length - 2) * 2];
2325
- y0 = points[(length - 2) * 2 + 1];
2326
- x1 = points[(length - 1) * 2];
2327
- y1 = points[(length - 1) * 2 + 1];
2328
- perpX = -(y0 - y1);
2329
- perpY = x0 - x1;
2330
- dist = Math.sqrt(perpX * perpX + perpY * perpY);
2331
- perpX /= dist;
2332
- perpY /= dist;
2333
- perpX *= width;
2334
- perpY *= width;
2335
- verts.push(x1 - perpX * innerWeight, y1 - perpY * innerWeight);
2336
- verts.push(x1 + perpX * outerWeight, y1 + perpY * outerWeight);
2337
- if (!closedShape) {
2338
- if (style.cap === "round") {
2339
- indexCount += round(
2340
- x1 - perpX * (innerWeight - outerWeight) * 0.5,
2341
- y1 - perpY * (innerWeight - outerWeight) * 0.5,
2342
- x1 - perpX * innerWeight,
2343
- y1 - perpY * innerWeight,
2344
- x1 + perpX * outerWeight,
2345
- y1 + perpY * outerWeight,
2346
- verts,
2347
- false
2348
- ) + 2;
2349
- } else if (style.cap === "square") {
2350
- indexCount += square(x1, y1, perpX, perpY, innerWeight, outerWeight, false, verts);
2351
- }
2151
+ let scale;
2152
+ {
2153
+ scale = unitConversion[theUnit][defaultUnit];
2154
+ if (scale < 0) {
2155
+ scale = unitConversion[theUnit].in * defaultDPI;
2156
+ }
2157
+ }
2158
+ return scale * Number.parseFloat(string);
2159
+ }
2160
+
2161
+ function getNodeTransform(node, currentTransform, transformStack) {
2162
+ if (!(node.hasAttribute("transform") || node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y")))) {
2163
+ return null;
2164
+ }
2165
+ const transform = parseNodeTransform(node);
2166
+ if (transformStack.length > 0) {
2167
+ transform.prepend(transformStack[transformStack.length - 1]);
2168
+ }
2169
+ currentTransform.copyFrom(transform);
2170
+ transformStack.push(transform);
2171
+ return transform;
2172
+ }
2173
+ function parseNodeTransform(node) {
2174
+ const transform = new Transform2D();
2175
+ if (node.nodeName === "use" && (node.hasAttribute("x") || node.hasAttribute("y"))) {
2176
+ transform.translate(
2177
+ parseFloatWithUnits(node.getAttribute("x")),
2178
+ parseFloatWithUnits(node.getAttribute("y"))
2179
+ );
2180
+ }
2181
+ if (node.hasAttribute("transform")) {
2182
+ transform.appendCssTransform(node.getAttribute("transform"));
2183
+ }
2184
+ return transform;
2185
+ }
2186
+
2187
+ function parseCircleNode(node) {
2188
+ return new Path2D().arc(
2189
+ parseFloatWithUnits(node.getAttribute("cx") || 0),
2190
+ parseFloatWithUnits(node.getAttribute("cy") || 0),
2191
+ parseFloatWithUnits(node.getAttribute("r") || 0),
2192
+ 0,
2193
+ Math.PI * 2
2194
+ );
2195
+ }
2196
+
2197
+ function parseCSSStylesheet(node, stylesheets) {
2198
+ if (!node.sheet || !node.sheet.cssRules || !node.sheet.cssRules.length)
2199
+ return;
2200
+ for (let i = 0; i < node.sheet.cssRules.length; i++) {
2201
+ const stylesheet = node.sheet.cssRules[i];
2202
+ if (stylesheet.type !== 1)
2203
+ continue;
2204
+ const selectorList = stylesheet.selectorText.split(/,/g).filter(Boolean).map((i2) => i2.trim());
2205
+ const definitions = {};
2206
+ for (let len = stylesheet.style.length, i2 = 0; i2 < len; i2++) {
2207
+ const name = stylesheet.style.item(i2);
2208
+ definitions[name] = stylesheet.style.getPropertyValue(name);
2209
+ }
2210
+ for (let j = 0; j < selectorList.length; j++) {
2211
+ stylesheets[selectorList[j]] = Object.assign(
2212
+ stylesheets[selectorList[j]] || {},
2213
+ { ...definitions }
2214
+ );
2215
+ }
2216
+ }
2217
+ }
2218
+
2219
+ function parseEllipseNode(node) {
2220
+ return new Path2D().ellipse(
2221
+ parseFloatWithUnits(node.getAttribute("cx") || 0),
2222
+ parseFloatWithUnits(node.getAttribute("cy") || 0),
2223
+ parseFloatWithUnits(node.getAttribute("rx") || 0),
2224
+ parseFloatWithUnits(node.getAttribute("ry") || 0),
2225
+ 0,
2226
+ 0,
2227
+ Math.PI * 2
2228
+ );
2229
+ }
2230
+
2231
+ function parseLineNode(node) {
2232
+ return new Path2D().moveTo(
2233
+ parseFloatWithUnits(node.getAttribute("x1") || 0),
2234
+ parseFloatWithUnits(node.getAttribute("y1") || 0)
2235
+ ).lineTo(
2236
+ parseFloatWithUnits(node.getAttribute("x2") || 0),
2237
+ parseFloatWithUnits(node.getAttribute("y2") || 0)
2238
+ );
2239
+ }
2240
+
2241
+ function parsePathNode(node) {
2242
+ const path = new Path2D();
2243
+ const d = node.getAttribute("d");
2244
+ if (!d || d === "none")
2245
+ return null;
2246
+ path.addData(d);
2247
+ return path;
2248
+ }
2249
+
2250
+ const RE$1 = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
2251
+ function parsePolygonNode(node) {
2252
+ const path = new Path2D();
2253
+ let index = 0;
2254
+ node.getAttribute("points")?.replace(RE$1, (match, a, b) => {
2255
+ const x = parseFloatWithUnits(a);
2256
+ const y = parseFloatWithUnits(b);
2257
+ if (index === 0) {
2258
+ path.moveTo(x, y);
2259
+ } else {
2260
+ path.lineTo(x, y);
2261
+ }
2262
+ index++;
2263
+ return match;
2264
+ });
2265
+ path.currentCurve.autoClose = true;
2266
+ return path;
2267
+ }
2268
+
2269
+ const RE = /([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
2270
+ function parsePolylineNode(node) {
2271
+ const path = new Path2D();
2272
+ let index = 0;
2273
+ node.getAttribute("points")?.replace(RE, (match, a, b) => {
2274
+ const x = parseFloatWithUnits(a);
2275
+ const y = parseFloatWithUnits(b);
2276
+ if (index === 0) {
2277
+ path.moveTo(x, y);
2278
+ } else {
2279
+ path.lineTo(x, y);
2280
+ }
2281
+ index++;
2282
+ return match;
2283
+ });
2284
+ path.currentCurve.autoClose = false;
2285
+ return path;
2286
+ }
2287
+
2288
+ function parseRectNode(node) {
2289
+ const x = parseFloatWithUnits(node.getAttribute("x") || 0);
2290
+ const y = parseFloatWithUnits(node.getAttribute("y") || 0);
2291
+ const rx = parseFloatWithUnits(node.getAttribute("rx") || node.getAttribute("ry") || 0);
2292
+ const ry = parseFloatWithUnits(node.getAttribute("ry") || node.getAttribute("rx") || 0);
2293
+ const w = parseFloatWithUnits(node.getAttribute("width"));
2294
+ const h = parseFloatWithUnits(node.getAttribute("height"));
2295
+ const bci = 1 - 0.551915024494;
2296
+ const path = new Path2D();
2297
+ path.moveTo(x + rx, y);
2298
+ path.lineTo(x + w - rx, y);
2299
+ if (rx !== 0 || ry !== 0) {
2300
+ path.bezierCurveTo(
2301
+ x + w - rx * bci,
2302
+ y,
2303
+ x + w,
2304
+ y + ry * bci,
2305
+ x + w,
2306
+ y + ry
2307
+ );
2308
+ }
2309
+ path.lineTo(x + w, y + h - ry);
2310
+ if (rx !== 0 || ry !== 0) {
2311
+ path.bezierCurveTo(
2312
+ x + w,
2313
+ y + h - ry * bci,
2314
+ x + w - rx * bci,
2315
+ y + h,
2316
+ x + w - rx,
2317
+ y + h
2318
+ );
2319
+ }
2320
+ path.lineTo(x + rx, y + h);
2321
+ if (rx !== 0 || ry !== 0) {
2322
+ path.bezierCurveTo(
2323
+ x + rx * bci,
2324
+ y + h,
2325
+ x,
2326
+ y + h - ry * bci,
2327
+ x,
2328
+ y + h - ry
2329
+ );
2330
+ }
2331
+ path.lineTo(x, y + ry);
2332
+ if (rx !== 0 || ry !== 0) {
2333
+ path.bezierCurveTo(x, y + ry * bci, x + rx * bci, y, x + rx, y);
2334
+ }
2335
+ return path;
2336
+ }
2337
+
2338
+ function parseStyle(node, style, stylesheets) {
2339
+ style = Object.assign({}, style);
2340
+ let stylesheetStyles = {};
2341
+ if (node.hasAttribute("class")) {
2342
+ const classSelectors = node.getAttribute("class").split(/\s/).filter(Boolean).map((i) => i.trim());
2343
+ for (let i = 0; i < classSelectors.length; i++) {
2344
+ stylesheetStyles = Object.assign(stylesheetStyles, stylesheets[`.${classSelectors[i]}`]);
2345
+ }
2346
+ }
2347
+ if (node.hasAttribute("id")) {
2348
+ stylesheetStyles = Object.assign(stylesheetStyles, stylesheets[`#${node.getAttribute("id")}`]);
2352
2349
  }
2353
- const eps2 = curveEps * curveEps;
2354
- for (let i = indexStart; i < indexCount + indexStart - 2; ++i) {
2355
- x0 = verts[i * 2];
2356
- y0 = verts[i * 2 + 1];
2357
- x1 = verts[(i + 1) * 2];
2358
- y1 = verts[(i + 1) * 2 + 1];
2359
- x2 = verts[(i + 2) * 2];
2360
- y2 = verts[(i + 2) * 2 + 1];
2361
- if (Math.abs(x0 * (y1 - y2) + x1 * (y2 - y0) + x2 * (y0 - y1)) < eps2) {
2362
- continue;
2363
- }
2364
- indices.push(i, i + 1, i + 2);
2350
+ for (let len = node.style.length, i = 0; i < len; i++) {
2351
+ const name = node.style.item(i);
2352
+ const value = node.style.getPropertyValue(name);
2353
+ style[name] = value;
2354
+ stylesheetStyles[name] = value;
2365
2355
  }
2366
- return {
2367
- vertices,
2368
- indices
2369
- };
2370
- }
2371
- function getOrientationOfPoints(points) {
2372
- const m = points.length;
2373
- if (m < 6) {
2374
- return 1;
2356
+ function addStyle(svgName, jsName, adjustFunction = copy) {
2357
+ if (node.hasAttribute(svgName))
2358
+ style[jsName] = adjustFunction(node.getAttribute(svgName));
2359
+ if (stylesheetStyles[svgName])
2360
+ style[jsName] = adjustFunction(stylesheetStyles[svgName]);
2375
2361
  }
2376
- let area = 0;
2377
- for (let i = 0, x1 = points[m - 2], y1 = points[m - 1]; i < m; i += 2) {
2378
- const x2 = points[i];
2379
- const y2 = points[i + 1];
2380
- area += (x2 - x1) * (y2 + y1);
2381
- x1 = x2;
2382
- y1 = y2;
2362
+ function copy(v) {
2363
+ if (v.startsWith("url"))
2364
+ console.warn("url access in attributes is not implemented.");
2365
+ return v;
2383
2366
  }
2384
- if (area < 0) {
2385
- return -1;
2367
+ function clamp(v) {
2368
+ return Math.max(0, Math.min(1, parseFloatWithUnits(v)));
2386
2369
  }
2387
- return 1;
2388
- }
2389
- function square(x, y, nx, ny, innerWeight, outerWeight, clockwise, verts) {
2390
- const ix = x - nx * innerWeight;
2391
- const iy = y - ny * innerWeight;
2392
- const ox = x + nx * outerWeight;
2393
- const oy = y + ny * outerWeight;
2394
- let exx;
2395
- let eyy;
2396
- if (clockwise) {
2397
- exx = ny;
2398
- eyy = -nx;
2399
- } else {
2400
- exx = -ny;
2401
- eyy = nx;
2370
+ function positive(v) {
2371
+ return Math.max(0, parseFloatWithUnits(v));
2402
2372
  }
2403
- const eix = ix + exx;
2404
- const eiy = iy + eyy;
2405
- const eox = ox + exx;
2406
- const eoy = oy + eyy;
2407
- verts.push(eix, eiy);
2408
- verts.push(eox, eoy);
2409
- return 2;
2410
- }
2411
- function round(cx, cy, sx, sy, ex, ey, verts, clockwise) {
2412
- const cx2p0x = sx - cx;
2413
- const cy2p0y = sy - cy;
2414
- let angle0 = Math.atan2(cx2p0x, cy2p0y);
2415
- let angle1 = Math.atan2(ex - cx, ey - cy);
2416
- if (clockwise && angle0 < angle1) {
2417
- angle0 += Math.PI * 2;
2418
- } else if (!clockwise && angle0 > angle1) {
2419
- angle1 += Math.PI * 2;
2373
+ function array(v) {
2374
+ return v.split(" ").filter((v2) => v2 !== "").map((v2) => parseFloatWithUnits(v2));
2420
2375
  }
2421
- let startAngle = angle0;
2422
- const angleDiff = angle1 - angle0;
2423
- const absAngleDiff = Math.abs(angleDiff);
2424
- const radius = Math.sqrt(cx2p0x * cx2p0x + cy2p0y * cy2p0y);
2425
- const segCount = (15 * absAngleDiff * Math.sqrt(radius) / Math.PI >> 0) + 1;
2426
- const angleInc = angleDiff / segCount;
2427
- startAngle += angleInc;
2428
- if (clockwise) {
2429
- verts.push(cx, cy);
2430
- verts.push(sx, sy);
2431
- for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
2432
- verts.push(cx, cy);
2433
- verts.push(cx + Math.sin(angle) * radius, cy + Math.cos(angle) * radius);
2376
+ addStyle("fill", "fill");
2377
+ addStyle("fill-opacity", "fillOpacity", clamp);
2378
+ addStyle("fill-rule", "fillRule");
2379
+ addStyle("opacity", "opacity", clamp);
2380
+ addStyle("stroke", "stroke");
2381
+ addStyle("stroke-opacity", "strokeOpacity", clamp);
2382
+ addStyle("stroke-width", "strokeWidth", positive);
2383
+ addStyle("stroke-linecap", "strokeLinecap");
2384
+ addStyle("stroke-linejoin", "strokeLinejoin");
2385
+ addStyle("stroke-miterlimit", "strokeMiterlimit", positive);
2386
+ addStyle("stroke-dasharray", "strokeDasharray", array);
2387
+ addStyle("stroke-dashoffset", "strokeDashoffset", parseFloatWithUnits);
2388
+ addStyle("visibility", "visibility");
2389
+ return style;
2390
+ }
2391
+
2392
+ function parseNode(node, style, paths = [], stylesheets = {}) {
2393
+ if (node.nodeType !== 1)
2394
+ return paths;
2395
+ let isDefsNode = false;
2396
+ let path = null;
2397
+ let _style = { ...style };
2398
+ switch (node.nodeName) {
2399
+ case "svg":
2400
+ _style = parseStyle(node, _style, stylesheets);
2401
+ break;
2402
+ case "style":
2403
+ parseCSSStylesheet(node, stylesheets);
2404
+ break;
2405
+ case "g":
2406
+ _style = parseStyle(node, _style, stylesheets);
2407
+ break;
2408
+ case "path":
2409
+ _style = parseStyle(node, _style, stylesheets);
2410
+ if (node.hasAttribute("d"))
2411
+ path = parsePathNode(node);
2412
+ break;
2413
+ case "rect":
2414
+ _style = parseStyle(node, _style, stylesheets);
2415
+ path = parseRectNode(node);
2416
+ break;
2417
+ case "polygon":
2418
+ _style = parseStyle(node, _style, stylesheets);
2419
+ path = parsePolygonNode(node);
2420
+ break;
2421
+ case "polyline":
2422
+ _style = parseStyle(node, _style, stylesheets);
2423
+ path = parsePolylineNode(node);
2424
+ break;
2425
+ case "circle":
2426
+ _style = parseStyle(node, _style, stylesheets);
2427
+ path = parseCircleNode(node);
2428
+ break;
2429
+ case "ellipse":
2430
+ _style = parseStyle(node, _style, stylesheets);
2431
+ path = parseEllipseNode(node);
2432
+ break;
2433
+ case "line":
2434
+ _style = parseStyle(node, _style, stylesheets);
2435
+ path = parseLineNode(node);
2436
+ break;
2437
+ case "defs":
2438
+ isDefsNode = true;
2439
+ break;
2440
+ case "use": {
2441
+ _style = parseStyle(node, _style, stylesheets);
2442
+ const href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href") || node.getAttribute("href") || "";
2443
+ const usedNodeId = href.substring(1);
2444
+ const usedNode = node.viewportElement?.getElementById(usedNodeId);
2445
+ if (usedNode) {
2446
+ parseNode(usedNode, _style, paths, stylesheets);
2447
+ } else {
2448
+ console.warn(`'use node' references non-existent node id: ${usedNodeId}`);
2449
+ }
2450
+ break;
2434
2451
  }
2435
- verts.push(cx, cy);
2436
- verts.push(ex, ey);
2437
- } else {
2438
- verts.push(sx, sy);
2439
- verts.push(cx, cy);
2440
- for (let i = 1, angle = startAngle; i < segCount; i++, angle += angleInc) {
2441
- verts.push(cx + Math.sin(angle) * radius, cy + Math.cos(angle) * radius);
2442
- verts.push(cx, cy);
2452
+ default:
2453
+ console.warn(node);
2454
+ break;
2455
+ }
2456
+ if (_style.display === "none") {
2457
+ return paths;
2458
+ }
2459
+ const currentTransform = new Transform2D();
2460
+ const transformStack = [];
2461
+ const transform = getNodeTransform(node, currentTransform, transformStack);
2462
+ if (path) {
2463
+ path.applyTransform(currentTransform);
2464
+ paths.push(path);
2465
+ path.style = { ..._style };
2466
+ }
2467
+ const childNodes = node.childNodes;
2468
+ for (let i = 0, len = childNodes.length; i < len; i++) {
2469
+ const node2 = childNodes[i];
2470
+ if (isDefsNode && node2.nodeName !== "style" && node2.nodeName !== "defs")
2471
+ continue;
2472
+ parseNode(node2, _style, paths, stylesheets);
2473
+ }
2474
+ if (transform) {
2475
+ transformStack.pop();
2476
+ if (transformStack.length > 0) {
2477
+ currentTransform.copyFrom(transformStack[transformStack.length - 1]);
2478
+ } else {
2479
+ currentTransform.identity();
2443
2480
  }
2444
- verts.push(ex, ey);
2445
- verts.push(cx, cy);
2446
2481
  }
2447
- return segCount * 2;
2482
+ return paths;
2483
+ }
2484
+
2485
+ function svgToPath2DSet(svg) {
2486
+ const dom = svgToDom(svg);
2487
+ return new Path2DSet(
2488
+ parseNode(dom, {}),
2489
+ dom.getAttribute("viewBox")?.trim().split(" ").map((v) => Number(v))
2490
+ );
2448
2491
  }
2449
2492
 
2450
2493
  class Curve {
@@ -4442,4 +4485,4 @@ function applyFFD(point, grid, width = grid.width, height = grid.height) {
4442
4485
  point.set(x, y);
4443
4486
  }
4444
4487
 
4445
- export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };
4488
+ export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, PI, PI_2, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Transform2D, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, getIntersectionPoint, nonzeroFillRule, parseArcCommand, parseCssArg, parseCssArgs, parseCssFunctions, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDom, svgToPath2DSet, toKebabCase };