@weasel-js/geom 1.9.4 → 1.10.0

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.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { PORT_REACH, portControls, portCurvePoints } from './chunk-YQADYJJ7.js';
2
2
  export { PORT_REACH } from './chunk-YQADYJJ7.js';
3
- import { cubicPointAt } from './chunk-HPVINMOM.js';
4
- export { cubicPointAt, fitCubicThroughDeletion, splitCubicAtT } from './chunk-HPVINMOM.js';
3
+ import { cubicPointAt, splitCubicAtT, fitCubicThroughDeletion } from './chunk-XS6ERH3X.js';
4
+ export { cubicPointAt, fitCubicThroughDeletion, splitCubicAtT } from './chunk-XS6ERH3X.js';
5
5
  import { cubicEvalAt, elevateQuadraticToCubic, cubicBounds } from './chunk-URQMDR6Q.js';
6
6
  export { cubicBounds, cubicEvalAt, elevateQuadraticToCubic, quadraticEvalAt, splitCubicAt, splitLineAt, splitQuadraticAt } from './chunk-URQMDR6Q.js';
7
- import { extractPolylines } from './chunk-NL423YYZ.js';
8
- export { boundsOfCoords, boxContainsBox, boxContainsPoint, rectToContour, unionBox } from './chunk-NL423YYZ.js';
9
- import { DEFAULT_FLATTEN_TOLERANCE, pointInPolygon, pointSegmentDist2, flattenQuadratic, flattenCubic, segmentsCross } from './chunk-X6GJRIQD.js';
10
- export { DEFAULT_FLATTEN_TOLERANCE, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, pointInPolygon, pointSegmentDist2, segmentsCross } from './chunk-X6GJRIQD.js';
11
- import { SINGULAR_RATIO } from './chunk-N5SYTHMR.js';
12
- export { EPS, approxEq, clamp, cross, dot, len2, sign, sub } from './chunk-N5SYTHMR.js';
13
- import { forEachSegment, PATH_M, PATH_L, PATH_Q, PATH_C, PATH_Z, pathCommandCoordCount } from './chunk-E4TJRGJD.js';
14
- export { PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, forEachSegment, pathCommandCoordCount } from './chunk-E4TJRGJD.js';
7
+ import { extractPolylines, rectToContour } from './chunk-MDT7F32A.js';
8
+ export { boundsOfCoords, boxContainsBox, boxContainsPoint, rectToContour, unionBox } from './chunk-MDT7F32A.js';
9
+ import { fillsOpenSubpaths, pointInPolygon, pointSegmentDist2, flattenQuadratic, flattenCubic, DEFAULT_FLATTEN_TOLERANCE, segmentsCross } from './chunk-WQMYOCFB.js';
10
+ export { DEFAULT_FLATTEN_TOLERANCE, defaultOpenFill, fillsOpenSubpaths, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, pointInPolygon, pointSegmentDist2, segmentsCross, setDefaultOpenFill } from './chunk-WQMYOCFB.js';
11
+ import { SINGULAR_RATIO } from './chunk-755Y4YZS.js';
12
+ export { EPS, approxEq, clamp, cross, dot, len2, sign, sub } from './chunk-755Y4YZS.js';
13
+ import { forEachSegment, PATH_M, PATH_L, PATH_Q, PATH_C, PATH_Z, pathCommandCoordCount } from './chunk-OXH3NOXC.js';
14
+ export { PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, forEachSegment, pathCommandCoordCount } from './chunk-OXH3NOXC.js';
15
15
 
16
16
  // src/view.ts
17
17
  var ZOOM_FLOOR = 1e-9;
@@ -453,7 +453,7 @@ function translatePolygonCopy(path, dx, dy) {
453
453
  next[ci + k + 1] = coords[ci + k + 1] + dy;
454
454
  }
455
455
  });
456
- return { kind: "polygon", commands: path.commands, coords: next, fillRule: path.fillRule };
456
+ return { ...path, coords: next };
457
457
  }
458
458
  function scalePathToBounds(path, target) {
459
459
  if (path.kind === "rect") {
@@ -483,54 +483,74 @@ function pathOrigin(path) {
483
483
 
484
484
  // src/paths/splitSubpaths.ts
485
485
  function splitSubpaths(path) {
486
- const { commands, coords, fillRule } = path;
486
+ const { commands, coords } = path;
487
487
  const out = [];
488
488
  let cmdStart = 0;
489
489
  let coordStart = 0;
490
490
  forEachSegment(commands, coords, (cmd, ci, _px, _py, i) => {
491
491
  if (cmd !== PATH_M || i <= cmdStart) return;
492
- out.push({
493
- kind: "polygon",
494
- commands: commands.slice(cmdStart, i),
495
- coords: coords.slice(coordStart, ci),
496
- fillRule
497
- });
492
+ out.push({ ...path, commands: commands.slice(cmdStart, i), coords: coords.slice(coordStart, ci) });
498
493
  cmdStart = i;
499
494
  coordStart = ci;
500
495
  });
501
- out.push({
502
- kind: "polygon",
503
- commands: commands.slice(cmdStart),
504
- coords: coords.slice(coordStart),
505
- fillRule
506
- });
496
+ out.push({ ...path, commands: commands.slice(cmdStart), coords: coords.slice(coordStart) });
507
497
  return out;
508
498
  }
509
499
 
500
+ // src/paths/splitByClosure.ts
501
+ var endsInZ = (sub3) => sub3.commands[sub3.commands.length - 1] === PATH_Z;
502
+ function hasOpenSubpath(path) {
503
+ return path.kind === "polygon" && path.commands.length > 0 && splitSubpaths(path).some((sub3) => !endsInZ(sub3));
504
+ }
505
+ function splitByClosure(path) {
506
+ const closed = [];
507
+ const open = [];
508
+ if (path.commands.length > 0) {
509
+ for (const sub3 of splitSubpaths(path)) (endsInZ(sub3) ? closed : open).push(sub3);
510
+ }
511
+ const join = (subs) => {
512
+ if (subs.length === 0) return null;
513
+ const commands = new Uint8Array(subs.reduce((n, s) => n + s.commands.length, 0));
514
+ const coords = new Float32Array(subs.reduce((n, s) => n + s.coords.length, 0));
515
+ let ci = 0, xi = 0;
516
+ for (const s of subs) {
517
+ commands.set(s.commands, ci);
518
+ coords.set(s.coords, xi);
519
+ ci += s.commands.length;
520
+ xi += s.coords.length;
521
+ }
522
+ return { ...path, commands, coords };
523
+ };
524
+ return { closed: join(closed), open: join(open) };
525
+ }
526
+
510
527
  // src/paths/winding.ts
511
528
  var GL_T = [0.5 - Math.sqrt(15) / 10, 0.5, 0.5 + Math.sqrt(15) / 10];
512
529
  var GL_W = [5 / 18, 8 / 18, 5 / 18];
513
530
  function pathSignedArea(path) {
514
531
  if (path.kind === "rect") return path.width * path.height;
515
532
  const { commands, coords } = path;
533
+ const fillsOpen = fillsOpenSubpaths(path);
534
+ let total = 0;
516
535
  let twice = 0;
517
536
  let startX = 0, startY = 0;
518
537
  let open = false;
519
538
  let endX = 0, endY = 0;
520
- const close = () => {
521
- if (open) twice += endX * startY - startX * endY;
539
+ const close = (drawn) => {
540
+ if (open && (drawn || fillsOpen)) total += twice + endX * startY - startX * endY;
541
+ twice = 0;
522
542
  open = false;
523
543
  };
524
544
  forEachSegment(commands, coords, (cmd, ci, px, py) => {
525
545
  if (cmd === PATH_M) {
526
- close();
546
+ close(false);
527
547
  startX = endX = coords[ci];
528
548
  startY = endY = coords[ci + 1];
529
549
  open = true;
530
550
  return;
531
551
  }
532
552
  if (cmd === PATH_Z) {
533
- close();
553
+ close(true);
534
554
  endX = startX;
535
555
  endY = startY;
536
556
  return;
@@ -569,8 +589,8 @@ function pathSignedArea(path) {
569
589
  endX = x3;
570
590
  endY = y3;
571
591
  });
572
- close();
573
- return twice / 2;
592
+ close(false);
593
+ return total / 2;
574
594
  }
575
595
  function reversePath(path) {
576
596
  const cmds = [];
@@ -627,12 +647,7 @@ function reversePath(path) {
627
647
  segs.push({ cmd, args: Array.from(coords.subarray(ci, ci + n)), fromX: px, fromY: py });
628
648
  });
629
649
  flush(false);
630
- return {
631
- kind: "polygon",
632
- commands: new Uint8Array(cmds),
633
- coords: new Float32Array(out),
634
- fillRule: path.fillRule
635
- };
650
+ return { ...path, commands: new Uint8Array(cmds), coords: new Float32Array(out) };
636
651
  }
637
652
 
638
653
  // src/paths/pathFromD.ts
@@ -1174,6 +1189,72 @@ function emitStraightCubic(b, a, c) {
1174
1189
  b.curveTo(cp1x, cp1y, cp2x, cp2y, c.x, c.y);
1175
1190
  }
1176
1191
 
1192
+ // src/pathSubpaths.ts
1193
+ function flatSubpaths(path, tolerance) {
1194
+ const { commands, coords } = path;
1195
+ const closed = [];
1196
+ const open = [];
1197
+ let sub3 = [];
1198
+ forEachSegment(commands, coords, (cmd, ci, curX, curY, _i, opensSubpath) => {
1199
+ if (opensSubpath) sub3 = [curX, curY];
1200
+ switch (cmd) {
1201
+ case PATH_M:
1202
+ if (sub3.length >= 2) open.push(sub3);
1203
+ sub3 = [coords[ci], coords[ci + 1]];
1204
+ break;
1205
+ case PATH_L:
1206
+ sub3.push(coords[ci], coords[ci + 1]);
1207
+ break;
1208
+ case PATH_C:
1209
+ flattenCubic(
1210
+ curX,
1211
+ curY,
1212
+ coords[ci],
1213
+ coords[ci + 1],
1214
+ coords[ci + 2],
1215
+ coords[ci + 3],
1216
+ coords[ci + 4],
1217
+ coords[ci + 5],
1218
+ tolerance,
1219
+ sub3
1220
+ );
1221
+ break;
1222
+ case PATH_Q:
1223
+ flattenQuadratic(
1224
+ curX,
1225
+ curY,
1226
+ coords[ci],
1227
+ coords[ci + 1],
1228
+ coords[ci + 2],
1229
+ coords[ci + 3],
1230
+ tolerance,
1231
+ sub3
1232
+ );
1233
+ break;
1234
+ case PATH_Z:
1235
+ if (sub3.length >= 6) closed.push(sub3);
1236
+ else if (sub3.length >= 2) open.push(sub3);
1237
+ sub3 = [];
1238
+ break;
1239
+ default:
1240
+ throw new Error(`pathHitTest: unknown command ${cmd}`);
1241
+ }
1242
+ });
1243
+ if (sub3.length >= 2) open.push(sub3);
1244
+ return { closed, open };
1245
+ }
1246
+ function regionSubpaths(path, opts) {
1247
+ const flat = flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
1248
+ if (!fillsOpenSubpaths(path)) return flat;
1249
+ return {
1250
+ closed: [...flat.closed, ...flat.open.filter((sub3) => sub3.length >= 6)],
1251
+ open: flat.open.filter((sub3) => sub3.length < 6)
1252
+ };
1253
+ }
1254
+ function closedSubpaths(path, opts) {
1255
+ return regionSubpaths(path, opts).closed;
1256
+ }
1257
+
1177
1258
  // src/screenBand.ts
1178
1259
  function stretchOf(m) {
1179
1260
  const e = (m.a + m.d) / 2;
@@ -1277,62 +1358,6 @@ function distToEllipse(e0, e1, y0, y1) {
1277
1358
  }
1278
1359
 
1279
1360
  // src/pathHitTest.ts
1280
- function flatSubpaths(path, tolerance) {
1281
- const { commands, coords } = path;
1282
- const closed = [];
1283
- const open = [];
1284
- let sub3 = [];
1285
- forEachSegment(commands, coords, (cmd, ci, curX, curY, _i, opensSubpath) => {
1286
- if (opensSubpath) sub3 = [curX, curY];
1287
- switch (cmd) {
1288
- case PATH_M:
1289
- if (sub3.length >= 2) open.push(sub3);
1290
- sub3 = [coords[ci], coords[ci + 1]];
1291
- break;
1292
- case PATH_L:
1293
- sub3.push(coords[ci], coords[ci + 1]);
1294
- break;
1295
- case PATH_C:
1296
- flattenCubic(
1297
- curX,
1298
- curY,
1299
- coords[ci],
1300
- coords[ci + 1],
1301
- coords[ci + 2],
1302
- coords[ci + 3],
1303
- coords[ci + 4],
1304
- coords[ci + 5],
1305
- tolerance,
1306
- sub3
1307
- );
1308
- break;
1309
- case PATH_Q:
1310
- flattenQuadratic(
1311
- curX,
1312
- curY,
1313
- coords[ci],
1314
- coords[ci + 1],
1315
- coords[ci + 2],
1316
- coords[ci + 3],
1317
- tolerance,
1318
- sub3
1319
- );
1320
- break;
1321
- case PATH_Z:
1322
- if (sub3.length >= 6) closed.push(sub3);
1323
- else if (sub3.length >= 2) open.push(sub3);
1324
- sub3 = [];
1325
- break;
1326
- default:
1327
- throw new Error(`pathHitTest: unknown command ${cmd}`);
1328
- }
1329
- });
1330
- if (sub3.length >= 2) open.push(sub3);
1331
- return { closed, open };
1332
- }
1333
- function closedSubpaths(path, opts) {
1334
- return flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE).closed;
1335
- }
1336
1361
  function pointInPath(path, x, y, opts = {}) {
1337
1362
  if (path.kind === "rect") {
1338
1363
  return x >= path.x && x <= path.x + path.width && y >= path.y && y <= path.y + path.height;
@@ -1530,7 +1555,7 @@ function polygonContainsPath(polygon, path, opts = {}) {
1530
1555
  if (path.kind === "rect") {
1531
1556
  subpaths = [flattenVerts(rectToVerts(path))];
1532
1557
  } else {
1533
- const { closed, open } = flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
1558
+ const { closed, open } = regionSubpaths(path, opts);
1534
1559
  subpaths = [...closed, ...open];
1535
1560
  }
1536
1561
  if (subpaths.length === 0) return false;
@@ -1544,14 +1569,349 @@ function polygonContainsPath(polygon, path, opts = {}) {
1544
1569
  }
1545
1570
  function polygonIntersectsPath(polygon, path, opts = {}) {
1546
1571
  if (polygon.length < 3) return false;
1547
- if (path.kind === "rect") return polygonsIntersect(rectToVerts(path), polygon);
1548
- const { closed, open } = flatSubpaths(path, opts.tolerance ?? DEFAULT_FLATTEN_TOLERANCE);
1572
+ const filled = opts.filled !== false;
1573
+ if (path.kind === "rect" && filled) return polygonsIntersect(rectToVerts(path), polygon);
1574
+ const { closed, open } = path.kind === "rect" ? { closed: [flattenVerts(rectToVerts(path))], open: [] } : regionSubpaths(path, opts);
1549
1575
  const flatPoly = flattenVerts(polygon);
1550
1576
  if (anyVertexInPolygon(closed, flatPoly) || anyVertexInPolygon(open, flatPoly)) return true;
1551
1577
  if (anyEdgeCrossesPolygon(closed, polygon) || anyOpenEdgeCrossesPolygon(open, polygon)) {
1552
1578
  return true;
1553
1579
  }
1554
- return closed.length > 0 && pointInPath(path, polygon[0].x, polygon[0].y, opts);
1580
+ return filled && closed.length > 0 && pointInPath(path, polygon[0].x, polygon[0].y, opts);
1581
+ }
1582
+
1583
+ // src/paths/markers.ts
1584
+ function circlePath(cx, cy, r, segments = 32) {
1585
+ const cmds = new Uint8Array(segments + 1);
1586
+ const coords = new Float32Array(segments * 2);
1587
+ cmds[0] = PATH_M;
1588
+ coords[0] = cx + r;
1589
+ coords[1] = cy;
1590
+ for (let i = 1; i < segments; i++) {
1591
+ cmds[i] = PATH_L;
1592
+ const theta = i / segments * Math.PI * 2;
1593
+ coords[i * 2] = cx + r * Math.cos(theta);
1594
+ coords[i * 2 + 1] = cy + r * Math.sin(theta);
1595
+ }
1596
+ cmds[segments] = PATH_Z;
1597
+ return { kind: "polygon", commands: cmds, coords, fillRule: "nonzero" };
1598
+ }
1599
+ function squarePath(cx, cy, size) {
1600
+ const half = size / 2;
1601
+ const x0 = cx - half, y0 = cy - half;
1602
+ const x1 = cx + half, y1 = cy + half;
1603
+ return {
1604
+ kind: "polygon",
1605
+ commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),
1606
+ coords: new Float32Array([x0, y0, x1, y0, x1, y1, x0, y1]),
1607
+ fillRule: "nonzero"
1608
+ };
1609
+ }
1610
+ function rectMarkerPath(x, y, width, height) {
1611
+ return {
1612
+ kind: "polygon",
1613
+ commands: new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]),
1614
+ coords: Float32Array.from(rectToContour(x, y, width, height)),
1615
+ fillRule: "nonzero"
1616
+ };
1617
+ }
1618
+ function roundRectPath(x, y, width, height, r, cornerSamples = 8) {
1619
+ const radius = Math.max(0, Math.min(r, Math.min(width, height) / 2));
1620
+ if (radius === 0) return rectMarkerPath(x, y, width, height);
1621
+ const HALF_PI = Math.PI / 2;
1622
+ const corners = [
1623
+ [x + radius, y + radius, Math.PI],
1624
+ [x + width - radius, y + radius, -HALF_PI],
1625
+ [x + width - radius, y + height - radius, 0],
1626
+ [x + radius, y + height - radius, HALF_PI]
1627
+ ];
1628
+ const perCorner = cornerSamples + 1;
1629
+ const count = corners.length * perCorner;
1630
+ const cmds = new Uint8Array(count + 1);
1631
+ const coords = new Float32Array(count * 2);
1632
+ let i = 0;
1633
+ for (const [cx, cy, start] of corners) {
1634
+ for (let s = 0; s <= cornerSamples; s++) {
1635
+ const theta = start + s / cornerSamples * HALF_PI;
1636
+ cmds[i] = i === 0 ? PATH_M : PATH_L;
1637
+ coords[i * 2] = cx + radius * Math.cos(theta);
1638
+ coords[i * 2 + 1] = cy + radius * Math.sin(theta);
1639
+ i++;
1640
+ }
1641
+ }
1642
+ cmds[count] = PATH_Z;
1643
+ return { kind: "polygon", commands: cmds, coords, fillRule: "nonzero" };
1644
+ }
1645
+
1646
+ // src/paths/anchors.ts
1647
+ function pathToAnchors(path) {
1648
+ const { commands, coords } = path;
1649
+ const anchors = [];
1650
+ const closed = [];
1651
+ let current = null;
1652
+ forEachSegment(commands, coords, (cmd, ci) => {
1653
+ switch (cmd) {
1654
+ case PATH_M: {
1655
+ if (current) {
1656
+ anchors.push(current);
1657
+ closed.push(false);
1658
+ }
1659
+ current = [{ x: coords[ci], y: coords[ci + 1] }];
1660
+ break;
1661
+ }
1662
+ case PATH_L: {
1663
+ if (!current) throw new Error("pathToAnchors: L without prior M");
1664
+ current.push({ x: coords[ci], y: coords[ci + 1] });
1665
+ break;
1666
+ }
1667
+ case PATH_C: {
1668
+ if (!current) throw new Error("pathToAnchors: C without prior M");
1669
+ const prev = current[current.length - 1];
1670
+ prev.outHandle = { x: coords[ci], y: coords[ci + 1] };
1671
+ current.push({
1672
+ x: coords[ci + 4],
1673
+ y: coords[ci + 5],
1674
+ inHandle: { x: coords[ci + 2], y: coords[ci + 3] }
1675
+ });
1676
+ break;
1677
+ }
1678
+ case PATH_Q: {
1679
+ if (!current) throw new Error("pathToAnchors: Q without prior M");
1680
+ const handle = { x: coords[ci], y: coords[ci + 1] };
1681
+ const prev = current[current.length - 1];
1682
+ prev.outHandle = handle;
1683
+ current.push({ x: coords[ci + 2], y: coords[ci + 3], inHandle: { ...handle } });
1684
+ break;
1685
+ }
1686
+ case PATH_Z: {
1687
+ if (current) {
1688
+ foldClosingCurve(current);
1689
+ anchors.push(current);
1690
+ closed.push(true);
1691
+ current = null;
1692
+ }
1693
+ break;
1694
+ }
1695
+ default:
1696
+ throw new Error(`pathToAnchors: unknown command ${cmd}`);
1697
+ }
1698
+ });
1699
+ if (current) {
1700
+ anchors.push(current);
1701
+ closed.push(false);
1702
+ }
1703
+ return { anchors, closed };
1704
+ }
1705
+ function foldClosingCurve(sub3) {
1706
+ if (sub3.length < 2) return;
1707
+ const first = sub3[0];
1708
+ const last = sub3[sub3.length - 1];
1709
+ if (!last.inHandle || last.x !== first.x || last.y !== first.y) return;
1710
+ sub3.pop();
1711
+ first.inHandle = last.inHandle;
1712
+ }
1713
+ function anchorsToPath(anchors, closed, like) {
1714
+ const b = new PathBuilder();
1715
+ for (let s = 0; s < anchors.length; s++) {
1716
+ const sub3 = anchors[s];
1717
+ if (sub3.length === 0) continue;
1718
+ b.moveTo(sub3[0].x, sub3[0].y);
1719
+ for (let i = 1; i < sub3.length; i++) {
1720
+ const prev = sub3[i - 1];
1721
+ const cur = sub3[i];
1722
+ const hasHandle = prev.outHandle != null || cur.inHandle != null;
1723
+ if (!hasHandle) {
1724
+ b.lineTo(cur.x, cur.y);
1725
+ } else {
1726
+ const c1 = prev.outHandle ?? { x: prev.x, y: prev.y };
1727
+ const c2 = cur.inHandle ?? { x: cur.x, y: cur.y };
1728
+ b.curveTo(c1.x, c1.y, c2.x, c2.y, cur.x, cur.y);
1729
+ }
1730
+ }
1731
+ if (closed[s]) {
1732
+ const last = sub3[sub3.length - 1];
1733
+ const first = sub3[0];
1734
+ const hasHandle = last.outHandle != null || first.inHandle != null;
1735
+ if (hasHandle) {
1736
+ const c1 = last.outHandle ?? { x: last.x, y: last.y };
1737
+ const c2 = first.inHandle ?? { x: first.x, y: first.y };
1738
+ b.curveTo(c1.x, c1.y, c2.x, c2.y, first.x, first.y);
1739
+ }
1740
+ b.close();
1741
+ }
1742
+ }
1743
+ const built = b.build();
1744
+ return like ? { ...like, commands: built.commands, coords: built.coords } : built;
1745
+ }
1746
+ var SMOOTH_THRESHOLD = 1e-3;
1747
+ function isAnchorSmooth(a) {
1748
+ if (!a.inHandle || !a.outHandle) return false;
1749
+ const inDX = a.inHandle.x - a.x;
1750
+ const inDY = a.inHandle.y - a.y;
1751
+ const outDX = a.outHandle.x - a.x;
1752
+ const outDY = a.outHandle.y - a.y;
1753
+ const inLen = Math.hypot(inDX, inDY);
1754
+ const outLen = Math.hypot(outDX, outDY);
1755
+ if (inLen === 0 || outLen === 0) return false;
1756
+ const cross2 = (inDX * outDY - inDY * outDX) / (inLen * outLen);
1757
+ return Math.abs(cross2) < SMOOTH_THRESHOLD;
1758
+ }
1759
+ function countPathAnchors(path) {
1760
+ if (path.kind === "rect") return 4;
1761
+ const cmds = path.commands;
1762
+ let n = 0;
1763
+ for (let i = 0; i < cmds.length; i++) {
1764
+ const c = cmds[i];
1765
+ if (c === PATH_M || c === PATH_L || c === PATH_C || c === PATH_Q) n++;
1766
+ }
1767
+ return n;
1768
+ }
1769
+ function segmentEnds(anchors, closed, sub3, segIdx) {
1770
+ const s = anchors[sub3];
1771
+ if (!s || segIdx < 0) return null;
1772
+ if (segIdx + 1 < s.length) return { a: s[segIdx], b: s[segIdx + 1] };
1773
+ if (closed?.[sub3] && s.length > 1 && segIdx === s.length - 1) return { a: s[segIdx], b: s[0] };
1774
+ return null;
1775
+ }
1776
+ function isStraightSegment(a, b) {
1777
+ return a.outHandle == null && b.inHandle == null;
1778
+ }
1779
+ function nearestOnSegment(a, b, x, y) {
1780
+ const p1 = a.outHandle ?? a;
1781
+ const p2 = b.inHandle ?? b;
1782
+ const hit = isStraightSegment(a, b) ? nearestOnLine(x, y, a.x, a.y, b.x, b.y) : nearestOnCubic(x, y, a.x, a.y, p1.x, p1.y, p2.x, p2.y, b.x, b.y);
1783
+ return { t: hit.t, d2: hit.dist * hit.dist };
1784
+ }
1785
+ function nearestSegmentT(anchors, wx, wy, closed) {
1786
+ let bestD2 = Infinity;
1787
+ let best = null;
1788
+ for (let s = 0; s < anchors.length; s++) {
1789
+ const segCount = anchors[s].length - (closed?.[s] ? 0 : 1);
1790
+ for (let i = 0; i < segCount; i++) {
1791
+ const ends = segmentEnds(anchors, closed, s, i);
1792
+ if (!ends) continue;
1793
+ const hit = nearestOnSegment(ends.a, ends.b, wx, wy);
1794
+ if (hit.d2 < bestD2) {
1795
+ bestD2 = hit.d2;
1796
+ best = { sub: s, segIdx: i, t: hit.t };
1797
+ }
1798
+ }
1799
+ }
1800
+ return best;
1801
+ }
1802
+
1803
+ // src/glMat3.ts
1804
+ function create(a, b, c, d, tx, ty) {
1805
+ return new Float64Array([a, b, 0, c, d, 0, tx, ty, 1]);
1806
+ }
1807
+ function identity2() {
1808
+ return create(1, 0, 0, 1, 0, 0);
1809
+ }
1810
+ function multiply2(out, m) {
1811
+ const a = out[0], b = out[1];
1812
+ const c = out[3], d = out[4];
1813
+ const tx = out[6], ty = out[7];
1814
+ const ma = m[0], mb = m[1];
1815
+ const mc = m[3], md = m[4];
1816
+ const mtx = m[6], mty = m[7];
1817
+ return create(
1818
+ a * ma + c * mb,
1819
+ // new a
1820
+ b * ma + d * mb,
1821
+ // new b
1822
+ a * mc + c * md,
1823
+ // new c
1824
+ b * mc + d * md,
1825
+ // new d
1826
+ a * mtx + c * mty + tx,
1827
+ // new tx
1828
+ b * mtx + d * mty + ty
1829
+ // new ty
1830
+ );
1831
+ }
1832
+ function translated(m, tx, ty) {
1833
+ const t = create(1, 0, 0, 1, tx, ty);
1834
+ return multiply2(m, t);
1835
+ }
1836
+ function scaled(m, sx, sy) {
1837
+ const s = create(sx, 0, 0, sy, 0, 0);
1838
+ return multiply2(m, s);
1839
+ }
1840
+ function toAffine(m) {
1841
+ return [m[0], m[1], m[3], m[4], m[6], m[7]];
1842
+ }
1843
+ function fromAffine(a) {
1844
+ return create(a[0], a[1], a[2], a[3], a[4], a[5]);
1845
+ }
1846
+ function invert2(m) {
1847
+ const inv = invert(toAffine(m));
1848
+ return inv && fromAffine(inv);
1849
+ }
1850
+ function toUniform(m) {
1851
+ return Float32Array.from(m);
1852
+ }
1853
+ function apply(m, x, y) {
1854
+ const a = m[0], b = m[1];
1855
+ const c = m[3], d = m[4];
1856
+ const tx = m[6], ty = m[7];
1857
+ return [a * x + c * y + tx, b * x + d * y + ty];
1858
+ }
1859
+ function screenToClip(width, height) {
1860
+ return create(
1861
+ 2 / width,
1862
+ // a
1863
+ 0,
1864
+ // b
1865
+ 0,
1866
+ // c
1867
+ -2 / height,
1868
+ // d
1869
+ -1,
1870
+ // tx
1871
+ 1
1872
+ // ty
1873
+ );
1874
+ }
1875
+ function meanScaleOf(m) {
1876
+ return Math.sqrt(Math.abs(m[0] * m[4] - m[1] * m[3]));
1877
+ }
1878
+ function minScaleOf(m) {
1879
+ const sum = m[0] * m[0] + m[1] * m[1] + m[3] * m[3] + m[4] * m[4];
1880
+ const det = m[0] * m[4] - m[1] * m[3];
1881
+ return Math.sqrt(Math.max(0, (sum - Math.sqrt(Math.max(0, sum * sum - 4 * det * det))) / 2));
1882
+ }
1883
+ var mat3 = {
1884
+ identity: identity2,
1885
+ toAffine,
1886
+ fromAffine,
1887
+ multiply: multiply2,
1888
+ translated,
1889
+ scaled,
1890
+ invert: invert2,
1891
+ toUniform,
1892
+ apply,
1893
+ screenToClip,
1894
+ meanScaleOf,
1895
+ minScaleOf
1896
+ };
1897
+
1898
+ // src/viewToMat3.ts
1899
+ function viewToMat3(view) {
1900
+ const sx = view.scale.x;
1901
+ const sy = view.scale.y;
1902
+ const tx = -view.x * sx + 0;
1903
+ const ty = -view.y * sy + 0;
1904
+ return new Float64Array([
1905
+ sx,
1906
+ 0,
1907
+ 0,
1908
+ 0,
1909
+ sy,
1910
+ 0,
1911
+ tx,
1912
+ ty,
1913
+ 1
1914
+ ]);
1555
1915
  }
1556
1916
 
1557
1917
  // src/place.ts
@@ -1801,6 +2161,425 @@ function resolveEasing(spec) {
1801
2161
  throw new Error("resolveEasing: unrecognized easing spec");
1802
2162
  }
1803
2163
 
1804
- export { EASINGS, PathBuilder, SPRING_PRESETS, ZOOM_FLOOR, applyToPoint, boundsOfPath, boxToBox, clampRectWithin, composePath, cubicBezierEasing, decomposePath, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, ellipsePath, identity, invert, linePath, linear, multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, normalizeZoom, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathFromD, pathIntersectsPolygon, pathIntersectsRect, pathSignedArea, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls2 as portControls, portCurvePoints2 as portCurvePoints, rectPath, regularPolygonPath, resolveEasing, reversePath, rotate, rotateAboutPoint, scale, scalePathToBounds, schneiderFit, splitSubpaths, starPath, strokeHitTest, transformCoords, transformPath, translate, translatePath, unionBoundsPath };
2164
+ // src/meanScale.ts
2165
+ function meanScale(s) {
2166
+ return Math.sqrt(Math.abs(s.x * s.y));
2167
+ }
2168
+
2169
+ // src/pxExtent.ts
2170
+ function pxExtent(px, scale2, rotation = 0) {
2171
+ if (!rotation) {
2172
+ return {
2173
+ x: px / Math.abs(scale2.x),
2174
+ y: px / Math.abs(scale2.y)
2175
+ };
2176
+ }
2177
+ const c = Math.cos(rotation), s = Math.sin(rotation);
2178
+ return {
2179
+ x: px * Math.hypot(c / scale2.x, s / scale2.y),
2180
+ y: px * Math.hypot(s / scale2.x, c / scale2.y)
2181
+ };
2182
+ }
2183
+ function scaleDelta(dx, dy, scale2) {
2184
+ return { x: dx * scale2.x, y: dy * scale2.y };
2185
+ }
2186
+ function withinPxBox(dx, dy, px, scale2) {
2187
+ const s = scaleDelta(dx, dy, scale2);
2188
+ return Math.abs(s.x) <= px && Math.abs(s.y) <= px;
2189
+ }
2190
+ function withinPxRadius(dx, dy, px, scale2) {
2191
+ const s = scaleDelta(dx, dy, scale2);
2192
+ return s.x * s.x + s.y * s.y <= px * px;
2193
+ }
2194
+ function standoff(anchor, normal, px, scale2) {
2195
+ const k = Math.sign(scale2.x * scale2.y) || 1;
2196
+ let nx = normal.x * scale2.y * k;
2197
+ let ny = normal.y * scale2.x * k;
2198
+ const l = Math.hypot(nx, ny) || 1;
2199
+ nx /= l;
2200
+ ny /= l;
2201
+ return { x: anchor.x + nx * px / scale2.x, y: anchor.y + ny * px / scale2.y, nx, ny };
2202
+ }
2203
+ function screenAngleOf(rotation, scale2) {
2204
+ return Math.atan2(Math.sin(rotation) * scale2.y, Math.cos(rotation) * scale2.x);
2205
+ }
2206
+
2207
+ // src/poseRotation.ts
2208
+ function poseRotationOf(pose) {
2209
+ const p = pose;
2210
+ if (p.rotation && p.x != null && p.y != null && p.width != null && p.height != null) {
2211
+ return { cx: p.x + p.width / 2, cy: p.y + p.height / 2, rotation: p.rotation };
2212
+ }
2213
+ return null;
2214
+ }
2215
+ function rotatePathAround(path, cx, cy, rotation) {
2216
+ if (path.kind === "rect") {
2217
+ return rotateRectCorners(path.x, path.y, path.width, path.height, cx, cy, rotation);
2218
+ }
2219
+ return rotatePolygon(path, cx, cy, rotation);
2220
+ }
2221
+ function rotatePolygon(path, cx, cy, rotation) {
2222
+ const cos = Math.cos(rotation);
2223
+ const sin = Math.sin(rotation);
2224
+ const { commands, coords } = path;
2225
+ const next = new Float32Array(coords.length);
2226
+ forEachSegment(commands, coords, (cmd, ci) => {
2227
+ for (let k = 0, len = pathCommandCoordCount(cmd); k < len; k += 2) {
2228
+ const dx = coords[ci + k] - cx;
2229
+ const dy = coords[ci + k + 1] - cy;
2230
+ next[ci + k] = cx + dx * cos - dy * sin;
2231
+ next[ci + k + 1] = cy + dx * sin + dy * cos;
2232
+ }
2233
+ });
2234
+ return { ...path, coords: next };
2235
+ }
2236
+ function rotateRectCorners(x, y, w, h, cx, cy, rotation) {
2237
+ const cos = Math.cos(rotation);
2238
+ const sin = Math.sin(rotation);
2239
+ const rotate2 = (px, py) => {
2240
+ const dx = px - cx;
2241
+ const dy = py - cy;
2242
+ return [cx + dx * cos - dy * sin, cy + dx * sin + dy * cos];
2243
+ };
2244
+ const [x0, y0] = rotate2(x, y);
2245
+ const [x1, y1] = rotate2(x + w, y);
2246
+ const [x2, y2] = rotate2(x + w, y + h);
2247
+ const [x3, y3] = rotate2(x, y + h);
2248
+ const commands = new Uint8Array([PATH_M, PATH_L, PATH_L, PATH_L, PATH_Z]);
2249
+ const coords = new Float32Array([x0, y0, x1, y1, x2, y2, x3, y3]);
2250
+ return { kind: "polygon", commands, coords, fillRule: "nonzero" };
2251
+ }
2252
+
2253
+ // src/poseFrame.ts
2254
+ function poseLinearOf(pose) {
2255
+ const t = pose?.transform;
2256
+ if (!Array.isArray(t) || t.length !== 4) return null;
2257
+ if (t[0] === 1 && t[1] === 0 && t[2] === 0 && t[3] === 1) return null;
2258
+ return t;
2259
+ }
2260
+ function poseFrameOf(pose) {
2261
+ const p = pose;
2262
+ if (!p || p.x == null || p.y == null || p.width == null || p.height == null) return null;
2263
+ const linear2 = poseLinearOf(p);
2264
+ if (!p.rotation && !linear2) return null;
2265
+ const cx = p.x + p.width / 2;
2266
+ const cy = p.y + p.height / 2;
2267
+ if (!linear2) return rotateAboutPoint(cx, cy, p.rotation);
2268
+ const [a, b, c, d] = linear2;
2269
+ const about = [a, b, c, d, cx - (a * cx + c * cy), cy - (b * cx + d * cy)];
2270
+ return p.rotation ? multiply(rotateAboutPoint(cx, cy, p.rotation), about) : about;
2271
+ }
2272
+ function poseFrameInverseOf(pose) {
2273
+ if (!poseLinearOf(pose)) {
2274
+ const r = poseRotationOf(pose);
2275
+ return r && rotateAboutPoint(r.cx, r.cy, -r.rotation);
2276
+ }
2277
+ const frame = poseFrameOf(pose);
2278
+ return frame && invert(frame);
2279
+ }
2280
+ function pathThroughPoseFrame(path, pose) {
2281
+ if (poseLinearOf(pose)) {
2282
+ const frame = poseFrameOf(pose);
2283
+ return frame ? transformPath(path, frame) : path;
2284
+ }
2285
+ const r = poseRotationOf(pose);
2286
+ return r ? rotatePathAround(path, r.cx, r.cy, r.rotation) : path;
2287
+ }
2288
+
2289
+ // src/paths/anchorEdits.ts
2290
+ function anchorCount(set) {
2291
+ let n = 0;
2292
+ for (const sub3 of set.anchors) n += sub3.length;
2293
+ return n;
2294
+ }
2295
+ function locateAnchor(set, flatIndex) {
2296
+ if (flatIndex < 0) return null;
2297
+ let remaining = flatIndex;
2298
+ for (let sub3 = 0; sub3 < set.anchors.length; sub3++) {
2299
+ const len = set.anchors[sub3].length;
2300
+ if (remaining < len) return { sub: sub3, idx: remaining };
2301
+ remaining -= len;
2302
+ }
2303
+ return null;
2304
+ }
2305
+ function flatAnchorIndex(set, sub3, idx) {
2306
+ if (sub3 < 0 || sub3 >= set.anchors.length) return -1;
2307
+ if (idx < 0 || idx >= set.anchors[sub3].length) return -1;
2308
+ let base = 0;
2309
+ for (let s = 0; s < sub3; s++) base += set.anchors[s].length;
2310
+ return base + idx;
2311
+ }
2312
+ function anchorAt(set, flatIndex) {
2313
+ const loc = locateAnchor(set, flatIndex);
2314
+ if (!loc) return null;
2315
+ return set.anchors[loc.sub][loc.idx] ?? null;
2316
+ }
2317
+ function editAnchorSet(path, edit) {
2318
+ const set = pathToAnchors(path);
2319
+ const changed = edit(set);
2320
+ if (changed === false) return null;
2321
+ return anchorsToPath(set.anchors, set.closed, path);
2322
+ }
2323
+ function translateAnchorBy(set, flatIndex, dx, dy) {
2324
+ const a = anchorAt(set, flatIndex);
2325
+ if (!a) return false;
2326
+ a.x += dx;
2327
+ a.y += dy;
2328
+ if (a.inHandle) {
2329
+ a.inHandle.x += dx;
2330
+ a.inHandle.y += dy;
2331
+ }
2332
+ if (a.outHandle) {
2333
+ a.outHandle.x += dx;
2334
+ a.outHandle.y += dy;
2335
+ }
2336
+ return true;
2337
+ }
2338
+ function moveHandleTo(set, flatIndex, side, toX, toY, breakSmoothness) {
2339
+ const a = anchorAt(set, flatIndex);
2340
+ if (!a) return false;
2341
+ const wasSmooth = isAnchorSmooth(a);
2342
+ const target = { x: toX, y: toY };
2343
+ if (side === "out") a.outHandle = target;
2344
+ else a.inHandle = target;
2345
+ const oppositeSide = side === "out" ? "in" : "out";
2346
+ const opposite = oppositeSide === "in" ? a.inHandle : a.outHandle;
2347
+ if (!breakSmoothness && wasSmooth && opposite) {
2348
+ const mirrored = { x: 2 * a.x - target.x, y: 2 * a.y - target.y };
2349
+ if (oppositeSide === "in") a.inHandle = mirrored;
2350
+ else a.outHandle = mirrored;
2351
+ }
2352
+ return true;
2353
+ }
2354
+ function insertAnchorOnSegment(set, args) {
2355
+ const ends = segmentEnds(set.anchors, set.closed, args.sub, args.segIdx);
2356
+ if (!ends) return -1;
2357
+ const { a, b } = ends;
2358
+ const at = args.segIdx + 1;
2359
+ if (isStraightSegment(a, b)) {
2360
+ set.anchors[args.sub].splice(at, 0, {
2361
+ x: a.x + (b.x - a.x) * args.t,
2362
+ y: a.y + (b.y - a.y) * args.t
2363
+ });
2364
+ return flatAnchorIndex(set, args.sub, at);
2365
+ }
2366
+ const p0 = a, p1 = a.outHandle ?? a, p2 = b.inHandle ?? b, p3 = b;
2367
+ const { left, right } = splitCubicAtT(p0, p1, p2, p3, args.t);
2368
+ a.outHandle = { x: left[1].x, y: left[1].y };
2369
+ b.inHandle = { x: right[2].x, y: right[2].y };
2370
+ set.anchors[args.sub].splice(at, 0, {
2371
+ x: left[3].x,
2372
+ y: left[3].y,
2373
+ inHandle: { x: left[2].x, y: left[2].y },
2374
+ outHandle: { x: right[1].x, y: right[1].y }
2375
+ });
2376
+ return flatAnchorIndex(set, args.sub, at);
2377
+ }
2378
+ function segmentAt(set, x, y, opts) {
2379
+ const scale2 = opts.scale ?? { x: 1, y: 1 };
2380
+ const onScreen = (p) => ({ x: p.x * scale2.x, y: p.y * scale2.y });
2381
+ const screenAnchors = set.anchors.map((sub3) => sub3.map((a) => ({
2382
+ ...onScreen(a),
2383
+ ...a.inHandle ? { inHandle: onScreen(a.inHandle) } : {},
2384
+ ...a.outHandle ? { outHandle: onScreen(a.outHandle) } : {}
2385
+ })));
2386
+ const hit = nearestSegmentT(screenAnchors, x * scale2.x, y * scale2.y, set.closed);
2387
+ if (!hit) return null;
2388
+ const ends = segmentEnds(set.anchors, set.closed, hit.sub, hit.segIdx);
2389
+ const point = pointOnSegment(ends.a, ends.b, hit.t);
2390
+ const tol = opts.tolerancePx;
2391
+ if (!withinPxRadius(point.x - x, point.y - y, tol, scale2)) return null;
2392
+ if (withinPxRadius(point.x - ends.a.x, point.y - ends.a.y, tol, scale2)) return null;
2393
+ if (withinPxRadius(point.x - ends.b.x, point.y - ends.b.y, tol, scale2)) return null;
2394
+ return { sub: hit.sub, segIdx: hit.segIdx, t: hit.t, x: point.x, y: point.y };
2395
+ }
2396
+ function pointOnSegment(a, b, t) {
2397
+ if (isStraightSegment(a, b)) return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
2398
+ return cubicPointAt(a, a.outHandle ?? a, b.inHandle ?? b, b, t);
2399
+ }
2400
+ function deleteAnchorsAt(set, flatIndexes) {
2401
+ const bySub = /* @__PURE__ */ new Map();
2402
+ for (const flat of new Set(flatIndexes)) {
2403
+ const loc = locateAnchor(set, flat);
2404
+ if (!loc) continue;
2405
+ const list = bySub.get(loc.sub);
2406
+ if (list) list.push(loc.idx);
2407
+ else bySub.set(loc.sub, [loc.idx]);
2408
+ }
2409
+ if (bySub.size === 0) return false;
2410
+ let survivors = 0;
2411
+ for (let s = 0; s < set.anchors.length; s++) {
2412
+ const doomed = bySub.get(s)?.length ?? 0;
2413
+ if (set.anchors[s].length - doomed >= 2) survivors++;
2414
+ }
2415
+ if (survivors === 0) return false;
2416
+ for (const [s, indices] of bySub) {
2417
+ const sub3 = set.anchors[s];
2418
+ if (!sub3) continue;
2419
+ indices.sort((a, b) => b - a);
2420
+ for (const i of indices) {
2421
+ const wraps = set.closed[s] && sub3.length > 2;
2422
+ const prev = wraps ? sub3[(i - 1 + sub3.length) % sub3.length] : sub3[i - 1];
2423
+ const next = wraps ? sub3[(i + 1) % sub3.length] : sub3[i + 1];
2424
+ if (prev && next) {
2425
+ const { c1, c2 } = fitCubicThroughDeletion(prev, next);
2426
+ prev.outHandle = c1;
2427
+ next.inHandle = c2;
2428
+ }
2429
+ sub3.splice(i, 1);
2430
+ }
2431
+ }
2432
+ for (let s = set.anchors.length - 1; s >= 0; s--) {
2433
+ if (set.anchors[s].length < 2) {
2434
+ set.anchors.splice(s, 1);
2435
+ set.closed.splice(s, 1);
2436
+ }
2437
+ }
2438
+ return true;
2439
+ }
2440
+ function openSubpathAt(set, flatIndex) {
2441
+ const loc = locateAnchor(set, flatIndex);
2442
+ if (!loc) return false;
2443
+ if (!set.closed[loc.sub]) return false;
2444
+ const sub3 = set.anchors[loc.sub];
2445
+ if (!sub3) return false;
2446
+ const { inHandle, ...start } = sub3[loc.idx];
2447
+ const end = { x: start.x, y: start.y, ...inHandle ? { inHandle } : {} };
2448
+ set.anchors[loc.sub] = [start, ...sub3.slice(loc.idx + 1), ...sub3.slice(0, loc.idx), end];
2449
+ set.closed[loc.sub] = false;
2450
+ return true;
2451
+ }
2452
+ function anchorsInRect(set, rect) {
2453
+ const x2 = rect.x + rect.width;
2454
+ const y2 = rect.y + rect.height;
2455
+ const hits = [];
2456
+ let flat = 0;
2457
+ for (const sub3 of set.anchors) {
2458
+ for (const a of sub3) {
2459
+ if (a.x >= rect.x && a.x <= x2 && a.y >= rect.y && a.y <= y2) hits.push(flat);
2460
+ flat++;
2461
+ }
2462
+ }
2463
+ return hits;
2464
+ }
2465
+
2466
+ // src/paths/nearestAnchor.ts
2467
+ function nearestPathAnchor(paths, point, px, scale2, accept) {
2468
+ let best = null;
2469
+ let bestD2 = px * px;
2470
+ for (const { id, path } of paths) {
2471
+ const { anchors, closed } = pathToAnchors(path);
2472
+ for (let sub3 = 0; sub3 < anchors.length; sub3++) {
2473
+ const list = anchors[sub3];
2474
+ for (let idx = 0; idx < list.length; idx++) {
2475
+ const a = list[idx];
2476
+ const s = scaleDelta(a.x - point.x, a.y - point.y, scale2);
2477
+ const d2 = s.x * s.x + s.y * s.y;
2478
+ if (d2 > bestD2 || best !== null && d2 === bestD2) continue;
2479
+ const end = closed[sub3] ? null : idx === list.length - 1 ? "last" : idx === 0 ? "first" : null;
2480
+ const hit = { id, sub: sub3, idx, x: a.x, y: a.y, end };
2481
+ if (accept && !accept(hit)) continue;
2482
+ best = hit;
2483
+ bestD2 = d2;
2484
+ }
2485
+ }
2486
+ }
2487
+ return best;
2488
+ }
2489
+ function reverseAnchors(anchors) {
2490
+ return anchors.map((a) => {
2491
+ const { inHandle, outHandle, ...rest } = a;
2492
+ const r = { ...rest };
2493
+ if (outHandle) r.inHandle = { ...outHandle };
2494
+ if (inHandle) r.outHandle = { ...inHandle };
2495
+ return r;
2496
+ }).reverse();
2497
+ }
2498
+
2499
+ // src/paths/pathInWorld.ts
2500
+ function pathInPoseFrame(path, pose) {
2501
+ if (path.kind === "rect") {
2502
+ if (path.x === pose.x && path.y === pose.y && path.width === pose.width && path.height === pose.height) return path;
2503
+ return { kind: "rect", x: pose.x, y: pose.y, width: pose.width, height: pose.height };
2504
+ }
2505
+ const b = boundsOfPath(path);
2506
+ if (b.x === pose.x && b.y === pose.y && b.width === pose.width && b.height === pose.height) {
2507
+ return path;
2508
+ }
2509
+ const m = boxToBox(b.x, b.y, b.width, b.height, pose.x, pose.y, pose.width, pose.height);
2510
+ return transformPath(path, m);
2511
+ }
2512
+ function pathInWorld(path, pose) {
2513
+ const local = pathInPoseFrame(path, pose);
2514
+ const frame = poseFrameOf(pose);
2515
+ if (!frame) return local;
2516
+ return transformPath(local, frame);
2517
+ }
2518
+ function worldEditToStorage(pose, worldPath) {
2519
+ const back = poseFrameInverseOf(pose);
2520
+ const frame = back && poseFrameOf(pose);
2521
+ const unrotated = back ? transformPath(worldPath, back) : worldPath;
2522
+ const b = boundsOfPath(unrotated);
2523
+ const aligned = translatePath(unrotated, -b.x, -b.y);
2524
+ let x = b.x, y = b.y;
2525
+ if (frame) {
2526
+ const [cx, cy] = applyToPoint(frame, b.x + b.width / 2, b.y + b.height / 2);
2527
+ x = cx - b.width / 2;
2528
+ y = cy - b.height / 2;
2529
+ }
2530
+ return {
2531
+ pose: { ...pose, x, y, width: b.width, height: b.height },
2532
+ path: aligned
2533
+ };
2534
+ }
2535
+
2536
+ // src/typedArrayJson.ts
2537
+ var TYPED_ARRAY_CONSTRUCTORS = {
2538
+ i8: Int8Array,
2539
+ u8: Uint8Array,
2540
+ u8c: Uint8ClampedArray,
2541
+ i16: Int16Array,
2542
+ u16: Uint16Array,
2543
+ i32: Int32Array,
2544
+ u32: Uint32Array,
2545
+ f32: Float32Array,
2546
+ f64: Float64Array
2547
+ };
2548
+ var TAGS = new Map(
2549
+ Object.keys(TYPED_ARRAY_CONSTRUCTORS).map((tag) => [TYPED_ARRAY_CONSTRUCTORS[tag].name, tag])
2550
+ );
2551
+ var classOf = (value) => Object.prototype.toString.call(value).slice(8, -1);
2552
+ function tagTypedArray(value) {
2553
+ if (!ArrayBuffer.isView(value)) return void 0;
2554
+ const tag = TAGS.get(classOf(value));
2555
+ return tag && { __ta: tag, data: Array.from(value) };
2556
+ }
2557
+ function untagTypedArray(value) {
2558
+ if (value === null || typeof value !== "object") return void 0;
2559
+ const { __ta: tag, data } = value;
2560
+ if (typeof tag !== "string" || !Object.hasOwn(TYPED_ARRAY_CONSTRUCTORS, tag) || !Array.isArray(data)) return void 0;
2561
+ return TYPED_ARRAY_CONSTRUCTORS[tag].from(data);
2562
+ }
2563
+ var isPlain = (value) => classOf(value) === "Object";
2564
+ function mapDeep(value, leaf) {
2565
+ const swapped = leaf(value);
2566
+ if (swapped !== void 0) return swapped;
2567
+ if (Array.isArray(value)) return value.map((v) => mapDeep(v, leaf));
2568
+ if (!isPlain(value)) return value;
2569
+ const out = {};
2570
+ for (const key of Object.keys(value)) out[key] = mapDeep(value[key], leaf);
2571
+ return out;
2572
+ }
2573
+ function tagTypedArrays(value) {
2574
+ return mapDeep(value, tagTypedArray);
2575
+ }
2576
+ function reviveTypedArrays(value) {
2577
+ return mapDeep(value, untagTypedArray);
2578
+ }
2579
+ function typedArrayReplacer(_key, value) {
2580
+ return tagTypedArray(value) ?? value;
2581
+ }
2582
+
2583
+ export { EASINGS, PathBuilder, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, anchorAt, anchorCount, anchorsInRect, anchorsToPath, applyToPoint, boundsOfPath, boxToBox, circlePath, clampRectWithin, composePath, countPathAnchors, cubicBezierEasing, decomposePath, deleteAnchorsAt, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorSet, ellipsePath, flatAnchorIndex, hasOpenSubpath, identity, insertAnchorOnSegment, invert, isAnchorSmooth, isStraightSegment, linePath, linear, locateAnchor, mat3, meanScale, moveHandleTo, multiply, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, nearestPathAnchor, nearestSegmentT, normalizeZoom, openSubpathAt, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSignedArea, pathThroughPoseFrame, pathToAnchors, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonFromPoints, polygonIntersectsPath, polylineFromPoints, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, pxExtent, rectMarkerPath, rectPath, regularPolygonPath, resolveEasing, reverseAnchors, reversePath, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roundRectPath, scale, scaleDelta, scalePathToBounds, schneiderFit, screenAngleOf, segmentAt, segmentEnds, splitByClosure, splitSubpaths, squarePath, standoff, starPath, strokeHitTest, tagTypedArray, tagTypedArrays, transformCoords, transformPath, translate, translateAnchorBy, translatePath, typedArrayReplacer, unionBoundsPath, untagTypedArray, viewToMat3, withinPxBox, withinPxRadius, worldEditToStorage };
1805
2584
  //# sourceMappingURL=index.js.map
1806
2585
  //# sourceMappingURL=index.js.map