@weasel-js/geom 1.10.0 → 1.11.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.
Files changed (55) hide show
  1. package/README.md +140 -16
  2. package/dist/3d/index.d.ts +29 -2
  3. package/dist/3d/index.js +49 -1
  4. package/dist/3d/index.js.map +1 -1
  5. package/dist/booleans/index.d.ts +34 -10
  6. package/dist/booleans/index.js +344 -352
  7. package/dist/booleans/index.js.map +1 -1
  8. package/dist/{chunk-MDT7F32A.js → chunk-6XSJY3TC.js} +10 -39
  9. package/dist/chunk-6XSJY3TC.js.map +1 -0
  10. package/dist/chunk-7KLJZFBY.js +573 -0
  11. package/dist/chunk-7KLJZFBY.js.map +1 -0
  12. package/dist/chunk-B53BERKG.js +386 -0
  13. package/dist/chunk-B53BERKG.js.map +1 -0
  14. package/dist/chunk-CE7IY7TB.js +104 -0
  15. package/dist/chunk-CE7IY7TB.js.map +1 -0
  16. package/dist/chunk-HGF5OVEN.js +129 -0
  17. package/dist/chunk-HGF5OVEN.js.map +1 -0
  18. package/dist/chunk-J2O2B54M.js +800 -0
  19. package/dist/chunk-J2O2B54M.js.map +1 -0
  20. package/dist/chunk-Q66NA2FU.js +174 -0
  21. package/dist/chunk-Q66NA2FU.js.map +1 -0
  22. package/dist/chunk-SASMXDBE.js +443 -0
  23. package/dist/chunk-SASMXDBE.js.map +1 -0
  24. package/dist/chunk-UI3FUWXM.js +533 -0
  25. package/dist/chunk-UI3FUWXM.js.map +1 -0
  26. package/dist/curvature-PkoLduGc.d.ts +454 -0
  27. package/dist/curves/index.d.ts +14 -5
  28. package/dist/curves/index.js +33 -111
  29. package/dist/curves/index.js.map +1 -1
  30. package/dist/index.d.ts +1697 -205
  31. package/dist/index.js +4729 -1308
  32. package/dist/index.js.map +1 -1
  33. package/dist/nd/index.d.ts +91 -27
  34. package/dist/nd/index.js +282 -0
  35. package/dist/nd/index.js.map +1 -1
  36. package/dist/path-BW8d_2RY.d.ts +157 -0
  37. package/dist/portCurve-C5HDWuuV.d.ts +30 -0
  38. package/dist/tessellate/index.d.ts +18 -4
  39. package/dist/tessellate/index.js +21 -277
  40. package/dist/tessellate/index.js.map +1 -1
  41. package/dist/warp/index.d.ts +252 -0
  42. package/dist/warp/index.js +1316 -0
  43. package/dist/warp/index.js.map +1 -0
  44. package/package.json +5 -1
  45. package/dist/chunk-MDT7F32A.js.map +0 -1
  46. package/dist/chunk-OXH3NOXC.js +0 -62
  47. package/dist/chunk-OXH3NOXC.js.map +0 -1
  48. package/dist/chunk-URQMDR6Q.js +0 -80
  49. package/dist/chunk-URQMDR6Q.js.map +0 -1
  50. package/dist/chunk-WQMYOCFB.js +0 -167
  51. package/dist/chunk-WQMYOCFB.js.map +0 -1
  52. package/dist/chunk-XS6ERH3X.js +0 -34
  53. package/dist/chunk-XS6ERH3X.js.map +0 -1
  54. package/dist/cubicMath-CFXbq6vp.d.ts +0 -116
  55. package/dist/path-Bf9KeVxC.d.ts +0 -44
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tessellate/polyline.ts"],"names":[],"mappings":";;;;AAsCO,SAAS,gBAAA,CAAiB,IAAA,EAAY,IAAA,GAAuB,EAAC,EAAe;AAClF,EAAA,IAAI,KAAK,IAAA,KAAS,MAAA,SAAe,CAAC,WAAA,CAAY,IAAI,CAAC,CAAA;AACnD,EAAA,OAAO,cAAA,CAAe,cAAA,CAAe,IAAI,CAAA,EAAG,IAAI,CAAA;AAClD;AAEA,SAAS,YAAY,CAAA,EAAuB;AAC1C,EAAA,MAAM,EAAE,CAAA,EAAG,CAAA,EAAG,OAAO,CAAA,EAAG,MAAA,EAAQ,GAAE,GAAI,CAAA;AACtC,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,MAAM,IAAA,CAAK,aAAA,CAAc,GAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,IAC5C,MAAA,EAAQ,IAAA;AAAA,IACR,OAAA,EAAS,IAAI,WAAA,CAAY,CAAC,GAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,IACrC,OAAA,EAAS,IAAI,WAAA,CAAY,CAAC,GAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,IACrC,OAAA,EAAS,IAAI,YAAA,CAAa,CAAC,GAAG,CAAA,EAAG,CAAA,EAAG,CAAC,CAAC;AAAA,GACxC;AACF;AAEA,SAAS,cAAA,CAAe,GAAgB,IAAA,EAAkC;AACxE,EAAA,MAAM,SAAA,GAAY,KAAK,gBAAA,IAAoB,yBAAA;AAC3C,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAO,GAAI,CAAA;AAC7B,EAAA,MAAM,MAAkB,EAAC;AAEzB,EAAA,IAAI,aAAA,GAAgB,CAAA;AAGpB,EAAA,IAAI,GAAA,GAAuB,IAAA;AAC3B,EAAA,IAAI,EAAA,GAAsB,IAAA;AAC1B,EAAA,IAAI,EAAA,GAAsB,IAAA;AAC1B,EAAA,IAAI,EAAA,GAAsB,IAAA;AAC1B,EAAA,IAAI,OAAA,GAA2B,IAAA;AAE/B,EAAA,IAAI,UAAA,GAAa,EAAA;AAEjB,EAAA,IAAI,WAAA,GAAc,CAAA;AAElB,EAAA,MAAM,eAAe,MAAgB;AACnC,IAAA,GAAA,GAAM,EAAC;AACP,IAAA,EAAA,GAAK,EAAC;AACN,IAAA,EAAA,GAAK,EAAC;AACN,IAAA,EAAA,GAAK,EAAC;AACN,IAAA,MAAM,IAAA,GAAiB,EAAE,MAAA,EAAQ,GAAA,EAAK,QAAQ,KAAA,EAAM;AACpD,IAAA,GAAA,CAAI,KAAK,IAAI,CAAA;AACb,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAUA,EAAA,MAAM,4BAA4B,MAAY;AAC5C,IAAA,IAAI,CAAC,GAAA,IAAO,CAAC,MAAM,CAAC,EAAA,IAAM,CAAC,EAAA,EAAI;AAC/B,IAAA,MAAM,CAAA,GAAI,IAAI,MAAA,GAAS,CAAA;AACvB,IAAA,IAAI,IAAI,CAAA,EAAG;AACX,IAAA,IAAI,IAAI,CAAC,CAAA,KAAM,GAAA,CAAA,CAAK,CAAA,GAAI,KAAK,CAAC,CAAA,IAAK,GAAA,CAAI,CAAC,MAAM,GAAA,CAAA,CAAK,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,CAAC,CAAA,EAAG;AACpE,IAAA,GAAA,CAAI,MAAA,IAAU,CAAA;AACd,IAAA,EAAA,CAAG,MAAA,IAAU,CAAA;AACb,IAAA,EAAA,CAAG,MAAA,IAAU,CAAA;AACb,IAAA,EAAA,CAAG,MAAA,IAAU,CAAA;AAAA,EACf,CAAA;AAEA,EAAA,MAAM,MAAA,GAAS,CAAC,MAAA,KAA2B;AACzC,IAAA,IAAI,CAAC,GAAA,IAAO,CAAC,MAAM,CAAC,EAAA,IAAM,CAAC,EAAA,EAAI;AAC/B,IAAA,MAAA,CAAO,OAAA,GAAU,IAAI,WAAA,CAAY,EAAE,CAAA;AACnC,IAAA,MAAA,CAAO,OAAA,GAAU,IAAI,WAAA,CAAY,EAAE,CAAA;AACnC,IAAA,MAAA,CAAO,OAAA,GAAU,IAAI,YAAA,CAAa,EAAE,CAAA;AAAA,EACtC,CAAA;AAKA,EAAA,MAAM,gBAAA,GAAmB,CAAC,QAAA,EAAkB,QAAA,EAAoB,OAAe,MAAA,KAAyB;AACtG,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,MAAA,EAAA,CAAI,KAAK,UAAU,CAAA;AACnB,MAAA,EAAA,CAAI,KAAK,MAAM,CAAA;AACf,MAAA,EAAA,CAAI,KAAK,KAAA,GAAQ,CAAA,GAAI,SAAS,CAAC,CAAA,GAAI,QAAQ,CAAC,CAAA;AAAA,IAC9C;AACA,IAAA,MAAM,OAAA,GAAW,QAAA,GAAW,QAAA,CAAS,MAAA,GAAU,CAAA;AAC/C,IAAA,EAAA,CAAI,OAAO,CAAA,GAAI,MAAA;AACf,IAAA,EAAA,CAAI,OAAO,CAAA,GAAI,MAAA;AACf,IAAA,EAAA,CAAI,OAAO,CAAA,GAAI,CAAA;AAAA,EACjB,CAAA;AAEA,EAAA,cAAA,CAAe,QAAA,EAAU,QAAQ,CAAC,GAAA,EAAK,UAAU,KAAA,EAAO,KAAA,EAAO,IAAI,YAAA,KAAiB;AAClF,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,IAAI,OAAA,SAAgB,OAAO,CAAA;AAC3B,MAAA,OAAA,GAAU,YAAA,EAAa;AACvB,MAAA,GAAA,CAAK,IAAA,CAAK,OAAO,KAAK,CAAA;AACtB,MAAA,EAAA,CAAI,KAAK,WAAW,CAAA;AACpB,MAAA,EAAA,CAAI,KAAK,WAAW,CAAA;AACpB,MAAA,EAAA,CAAI,KAAK,CAAC,CAAA;AACV,MAAA,UAAA,GAAa,WAAA;AAAA,IACf;AACA,IAAA,QAAQ,GAAA;AAAK,MACX,KAAK,MAAA;AAAA,MACL,KAAK,MAAA,EAAQ;AACX,QAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,UAAA,IAAI,OAAA,SAAgB,OAAO,CAAA;AAC3B,UAAA,OAAA,GAAU,YAAA,EAAa;AACvB,UAAA,WAAA,GAAc,aAAA;AAAA,QAChB;AACA,QAAA,GAAA,CAAK,KAAK,MAAA,CAAO,QAAQ,GAAG,MAAA,CAAO,QAAA,GAAW,CAAC,CAAC,CAAA;AAChD,QAAA,EAAA,CAAI,KAAK,aAAa,CAAA;AACtB,QAAA,EAAA,CAAI,KAAK,aAAa,CAAA;AACtB,QAAA,EAAA,CAAI,KAAK,CAAC,CAAA;AACV,QAAA,UAAA,GAAa,aAAA;AACb,QAAA,aAAA,EAAA;AACA,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,MAAM,MAAA,GAAS,aAAA;AACf,QAAA,MAAM,QAAA,GAAW,IAAK,MAAA,GAAS,CAAA;AAC/B,QAAA,MAAM,WAAqB,EAAC;AAC5B,QAAA,MAAM,KAAA,GAAQ,0BAAA;AAAA,UACZ,KAAA;AAAA,UAAO,KAAA;AAAA,UACP,OAAO,QAAQ,CAAA;AAAA,UAAG,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UACrC,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UACzC,SAAA;AAAA,UAAW,GAAA;AAAA,UAAM,QAAA;AAAA,UAAU,IAAA,CAAK;AAAA,SAClC;AACA,QAAA,gBAAA,CAAiB,QAAA,EAAU,QAAA,EAAU,KAAA,EAAO,MAAM,CAAA;AAClD,QAAA,UAAA,GAAa,MAAA;AACb,QAAA,aAAA,EAAA;AACA,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,MAAM,MAAA,GAAS,aAAA;AACf,QAAA,MAAM,QAAA,GAAW,IAAK,MAAA,GAAS,CAAA;AAC/B,QAAA,MAAM,WAAqB,EAAC;AAC5B,QAAA,MAAM,KAAA,GAAQ,sBAAA;AAAA,UACZ,KAAA;AAAA,UAAO,KAAA;AAAA,UACP,OAAO,QAAQ,CAAA;AAAA,UAAG,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UACrC,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UACzC,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UAAG,MAAA,CAAO,WAAW,CAAC,CAAA;AAAA,UACzC,SAAA;AAAA,UAAW,GAAA;AAAA,UAAM,QAAA;AAAA,UAAU,IAAA,CAAK;AAAA,SAClC;AACA,QAAA,gBAAA,CAAiB,QAAA,EAAU,QAAA,EAAU,KAAA,EAAO,MAAM,CAAA;AAClD,QAAA,UAAA,GAAa,MAAA;AACb,QAAA,aAAA,EAAA;AACA,QAAA;AAAA,MACF;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,IAAI,OAAA,EAAS;AACX,UAAA,OAAA,CAAQ,MAAA,GAAS,IAAA;AACjB,UAAA,yBAAA,EAA0B;AAAA,QAC5B;AACA,QAAA;AAAA,MACF;AAAA,MACA;AACE,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,uCAAA,EAA0C,GAAG,CAAA,CAAE,CAAA;AAAA;AACnE,EACF,CAAC,CAAA;AAED,EAAA,IAAI,OAAA,SAAgB,OAAO,CAAA;AAC3B,EAAA,OAAO,GAAA;AACT","file":"chunk-6XSJY3TC.js","sourcesContent":["import { forEachSegment, PATH_M, PATH_L, PATH_Z, PATH_C, PATH_Q } from '../commands';\nimport { resolveCorners } from '../paths/corners';\nimport { rectToContour } from '../box';\nimport { DEFAULT_FLATTEN_TOLERANCE, flattenCubicWithArcLen, flattenQuadraticWithArcLen } from '../flatten';\nimport type { Path, PolygonPath, RectPath } from '../path';\n\n/** One contour of a path, flattened to straight segments. */\nexport interface Polyline {\n /** Interleaved x,y vertices (length = 2 × point count). */\n points: number[];\n /** Whether the contour was closed (ends with Z, or is a RectPath). */\n closed: boolean;\n /** For each point, the previous anchor index. Anchor-aligned points set A === B. */\n anchorA?: Uint32Array;\n /** For each point, the next anchor index. */\n anchorB?: Uint32Array;\n /** For each point, the arc-length fraction along (A, B). 0 at anchor A; for anchor-aligned, set to 0. */\n anchorT?: Float32Array;\n /** Per-point stroke width, populated by the tessellator when the Stroke\n * carries `vertexWidths`. Undefined means uniform `Stroke.width`. */\n widths?: Float32Array;\n /** Per-point distance the ribbon's middle sits off the path toward the\n * normal `(−dy, dx)` of the direction of travel: half the right edge's\n * distance less the left's. Set alongside `widths` only when the two sides\n * differ somewhere; undefined means centered. */\n offsets?: Float32Array;\n}\n\n/** Options for `extractPolylines`. */\nexport interface ExtractOptions {\n flattenTolerance?: number;\n /** Most a curve may turn, in radians, between two flattened vertices.\n * Unbounded when unset. */\n maxTurn?: number;\n}\n\n/** Flatten each contour of a path to a straight-segment polyline, carrying the\n * anchor parameterization per point. A rect yields one closed contour. */\nexport function extractPolylines(path: Path, opts: ExtractOptions = {}): Polyline[] {\n if (path.kind === 'rect') return [extractRect(path)];\n return extractPolygon(resolveCorners(path), opts);\n}\n\nfunction extractRect(p: RectPath): Polyline {\n const { x, y, width: w, height: h } = p;\n return {\n points: Array.from(rectToContour(x, y, w, h)),\n closed: true,\n anchorA: new Uint32Array([0, 1, 2, 3]),\n anchorB: new Uint32Array([0, 1, 2, 3]),\n anchorT: new Float32Array([0, 0, 0, 0]),\n };\n}\n\nfunction extractPolygon(p: PolygonPath, opts: ExtractOptions): Polyline[] {\n const tolerance = opts.flattenTolerance ?? DEFAULT_FLATTEN_TOLERANCE;\n const { commands, coords } = p;\n const out: Polyline[] = [];\n // Anchors are numbered globally (across all contours) in command-stream order.\n let anchorCounter = 0;\n\n // Builders for the current polyline.\n let pts: number[] | null = null;\n let aA: number[] | null = null;\n let aB: number[] | null = null;\n let aT: number[] | null = null;\n let current: Polyline | null = null;\n\n let prevAnchor = -1;\n // The anchor a subpath opened by a bare drawing command starts from.\n let startAnchor = 0;\n\n const beginContour = (): Polyline => {\n pts = [];\n aA = [];\n aB = [];\n aT = [];\n const next: Polyline = { points: pts, closed: false };\n out.push(next);\n return next;\n };\n\n /**\n * A closed contour's last point repeating its first leaves a zero-length\n * closing segment, which the stroker discards along with the wrap-around\n * join it should have carried, notching the ribbon at the contour's start.\n * Every font outline serialized by opentype.js is written this way. Exact\n * equality is the right test: the duplicate is a re-emission of the same\n * number, and a near-miss is a genuine (if tiny) segment the author asked for.\n */\n const dropDuplicateClosingPoint = (): void => {\n if (!pts || !aA || !aB || !aT) return;\n const n = pts.length / 2;\n if (n < 2) return;\n if (pts[0] !== pts[(n - 1) * 2] || pts[1] !== pts[(n - 1) * 2 + 1]) return;\n pts.length -= 2;\n aA.length -= 1;\n aB.length -= 1;\n aT.length -= 1;\n };\n\n const commit = (target: Polyline): void => {\n if (!pts || !aA || !aB || !aT) return;\n target.anchorA = new Uint32Array(aA);\n target.anchorB = new Uint32Array(aB);\n target.anchorT = new Float32Array(aT);\n };\n\n // Fill anchorA/B/T for each point a curve just appended: interior points\n // interpolate (prevAnchor → target), and the final point is pinned to the\n // target so the draw-time lerp returns anchor B's color exactly.\n const pushCurveAnchors = (segStart: number, arcAccum: number[], total: number, target: number): void => {\n for (let k = 0; k < arcAccum.length; k++) {\n aA!.push(prevAnchor);\n aB!.push(target);\n aT!.push(total > 0 ? arcAccum[k] / total : 0);\n }\n const lastIdx = (segStart + arcAccum.length) - 1;\n aA![lastIdx] = target;\n aB![lastIdx] = target;\n aT![lastIdx] = 0;\n };\n\n forEachSegment(commands, coords, (cmd, coordIdx, prevX, prevY, _i, opensSubpath) => {\n if (opensSubpath) {\n if (current) commit(current);\n current = beginContour();\n pts!.push(prevX, prevY);\n aA!.push(startAnchor);\n aB!.push(startAnchor);\n aT!.push(0);\n prevAnchor = startAnchor;\n }\n switch (cmd) {\n case PATH_M:\n case PATH_L: {\n if (cmd === PATH_M) {\n if (current) commit(current);\n current = beginContour();\n startAnchor = anchorCounter;\n }\n pts!.push(coords[coordIdx], coords[coordIdx + 1]);\n aA!.push(anchorCounter);\n aB!.push(anchorCounter);\n aT!.push(0);\n prevAnchor = anchorCounter;\n anchorCounter++;\n break;\n }\n case PATH_Q: {\n const target = anchorCounter;\n const segStart = pts!.length / 2;\n const arcAccum: number[] = [];\n const total = flattenQuadraticWithArcLen(\n prevX, prevY,\n coords[coordIdx], coords[coordIdx + 1],\n coords[coordIdx + 2], coords[coordIdx + 3],\n tolerance, pts!, arcAccum, opts.maxTurn,\n );\n pushCurveAnchors(segStart, arcAccum, total, target);\n prevAnchor = target;\n anchorCounter++;\n break;\n }\n case PATH_C: {\n const target = anchorCounter;\n const segStart = pts!.length / 2;\n const arcAccum: number[] = [];\n const total = flattenCubicWithArcLen(\n prevX, prevY,\n coords[coordIdx], coords[coordIdx + 1],\n coords[coordIdx + 2], coords[coordIdx + 3],\n coords[coordIdx + 4], coords[coordIdx + 5],\n tolerance, pts!, arcAccum, opts.maxTurn,\n );\n pushCurveAnchors(segStart, arcAccum, total, target);\n prevAnchor = target;\n anchorCounter++;\n break;\n }\n case PATH_Z: {\n if (current) {\n current.closed = true;\n dropDuplicateClosingPoint();\n }\n break;\n }\n default:\n throw new Error(`extractPolylines: unknown command code ${cmd}`);\n }\n });\n\n if (current) commit(current);\n return out;\n}\n"]}
@@ -0,0 +1,573 @@
1
+ import { nearestOnLine, nearestOnCubic } from './chunk-CE7IY7TB.js';
2
+ import { cornerCuts, decodeContours, fillsOpenSubpaths, resolveCorners, segmentsCross, pointInPolygon } from './chunk-J2O2B54M.js';
3
+ import { EPS } from './chunk-755Y4YZS.js';
4
+ import { withoutCorners, compactCorners, PATH_M, PATH_L, PATH_Q, PATH_C, PATH_Z, forEachSegment, pathCommandCoordCount, PathBuilder, splitQuadraticAt, splitCubicAt } from './chunk-B53BERKG.js';
5
+
6
+ // src/paths/cornerCarry.ts
7
+ var flatCache = /* @__PURE__ */ new WeakMap();
8
+ function flatAnchorIndices(path) {
9
+ const hit = flatCache.get(path);
10
+ if (hit) return hit;
11
+ const { commands, coords } = path;
12
+ const out = [];
13
+ let flat = 0, first = 0, count = 0;
14
+ let sx = 0, sy = 0, ex = 0, ey = 0, curve = false;
15
+ forEachSegment(commands, coords, (cmd, ci) => {
16
+ if (cmd === PATH_Z) {
17
+ if (count > 1 && curve && ex === sx && ey === sy) {
18
+ out[out.length - 1] = first;
19
+ flat--;
20
+ }
21
+ count = 0;
22
+ return;
23
+ }
24
+ const n = pathCommandCoordCount(cmd);
25
+ ex = coords[ci + n - 2];
26
+ ey = coords[ci + n - 1];
27
+ curve = cmd === PATH_C || cmd === PATH_Q;
28
+ if (cmd === PATH_M || count === 0) {
29
+ first = flat;
30
+ sx = ex;
31
+ sy = ey;
32
+ count = 0;
33
+ }
34
+ count++;
35
+ out.push(flat++);
36
+ });
37
+ const result = Int32Array.from(out);
38
+ flatCache.set(path, result);
39
+ return result;
40
+ }
41
+ function carryCorners(from, to, sources) {
42
+ const bare = withoutCorners(to);
43
+ const specs = from.corners;
44
+ if (!specs) return bare;
45
+ const fromFlat = flatAnchorIndices(from);
46
+ const toFlat = flatAnchorIndices(to);
47
+ const placed = /* @__PURE__ */ new Set();
48
+ const next = [];
49
+ for (let k = 0; k < toFlat.length; k++) {
50
+ const s = sources[k];
51
+ if (s === void 0 || s < 0 || s >= fromFlat.length) continue;
52
+ const f = fromFlat[s];
53
+ const spec = specs[f];
54
+ if (!spec || placed.has(f)) continue;
55
+ placed.add(f);
56
+ while (next.length < toFlat[k]) next.push(null);
57
+ next[toFlat[k]] = spec;
58
+ }
59
+ const corners = compactCorners(next);
60
+ return corners ? { ...bare, corners } : bare;
61
+ }
62
+ function anchorRange(start, count) {
63
+ const out = new Int32Array(count);
64
+ for (let i = 0; i < count; i++) out[i] = start + i;
65
+ return out;
66
+ }
67
+
68
+ // src/paths/cornerRestore.ts
69
+ var CORNER_RESTORE_TOLERANCE = 1e-3;
70
+ function cornerTraces(path) {
71
+ if (path.kind !== "polygon") return [];
72
+ return cornerCuts(path).map(({ anchor, spec, start, end, pieces }) => ({ anchor, spec, start, end, pieces }));
73
+ }
74
+ function keepCorners(sources, result, tolerance = CORNER_RESTORE_TOLERANCE) {
75
+ const traces = sources.flatMap(cornerTraces);
76
+ return traces.length === 0 ? result : restoreCorners(result, traces, tolerance);
77
+ }
78
+ var dist = (a, b) => Math.hypot(a.x - b.x, a.y - b.y);
79
+ function onTrace(p, t, tol) {
80
+ let from = t.start;
81
+ for (const piece of t.pieces) {
82
+ const d = piece.kind === "line" ? nearestOnLine(p.x, p.y, from.x, from.y, piece.to.x, piece.to.y).dist : nearestOnCubic(p.x, p.y, from.x, from.y, piece.c1.x, piece.c1.y, piece.c2.x, piece.c2.y, piece.to.x, piece.to.y).dist;
83
+ if (d <= tol) return true;
84
+ from = piece.to;
85
+ }
86
+ return false;
87
+ }
88
+ function blossom(s, u, v, w) {
89
+ const lerp = (a2, b2, t) => ({ x: a2.x + (b2.x - a2.x) * t, y: a2.y + (b2.y - a2.y) * t });
90
+ const a = lerp(s.p0, s.c1, u), b = lerp(s.c1, s.c2, u), c = lerp(s.c2, s.p3, u);
91
+ const d = lerp(a, b, v), e = lerp(b, c, v);
92
+ return lerp(d, e, w);
93
+ }
94
+ function extendTo(s, target, from, tol) {
95
+ const at = (u2) => blossom(s, u2, u2, u2);
96
+ const d1 = (u2) => {
97
+ const a = blossom(s, u2, u2, 0), b = blossom(s, u2, u2, 1);
98
+ return { x: 3 * (b.x - a.x), y: 3 * (b.y - a.y) };
99
+ };
100
+ const speed = Math.hypot(d1(from).x, d1(from).y);
101
+ if (speed === 0) return null;
102
+ let u = from + (from === 1 ? 1 : -1) * dist(at(from), target) / speed;
103
+ for (let i = 0; i < 30; i++) {
104
+ const p = at(u), d = d1(u);
105
+ const dd = d.x * d.x + d.y * d.y;
106
+ if (dd === 0) break;
107
+ u -= ((p.x - target.x) * d.x + (p.y - target.y) * d.y) / dd;
108
+ }
109
+ return dist(at(u), target) <= tol ? u : null;
110
+ }
111
+ function reachSeg(s, start, end, tol) {
112
+ const p0 = start ?? s.p0, p3 = end ?? s.p3;
113
+ if (s.line) return { line: true, p0, c1: p0, c2: p3, p3 };
114
+ const u0 = start ? extendTo(s, start, 0, tol) : 0;
115
+ const u1 = end ? extendTo(s, end, 1, tol) : 1;
116
+ if (u0 === null || u1 === null) return null;
117
+ return { line: false, p0, c1: blossom(s, u0, u0, u1), c2: blossom(s, u0, u1, u1), p3 };
118
+ }
119
+ function endsCut(a, edge, p, t, tol) {
120
+ if (dist(a, p) <= tol) return true;
121
+ return edge.line && onTrace(a, t, tol) && nearestOnLine(p.x, p.y, edge.p0.x, edge.p0.y, edge.p3.x, edge.p3.y).dist <= tol;
122
+ }
123
+ function findRun(c, t, tol) {
124
+ const n = c.anchors.length;
125
+ for (let i = c.closed ? 0 : 1; i < n; i++) {
126
+ for (const [first, last] of [[t.start, t.end], [t.end, t.start]]) {
127
+ if (!endsCut(c.anchors[i], c.segs[(i - 1 + n) % n], first, t, tol)) continue;
128
+ for (let j = i + 1, steps = 1; steps < c.segs.length; j++, steps++) {
129
+ if (!c.closed && j >= n - 1) break;
130
+ const a = c.anchors[j % n];
131
+ const seg = c.segs[(j - 1) % n];
132
+ if (!seg.line && !onTrace(blossom(seg, 0.5, 0.5, 0.5), t, tol)) break;
133
+ if (endsCut(a, c.segs[j % n], last, t, tol)) return { from: i, to: j % n, trace: t };
134
+ if (!onTrace(a, t, tol)) break;
135
+ }
136
+ }
137
+ }
138
+ return null;
139
+ }
140
+ function covered(run, n) {
141
+ const out = [];
142
+ for (let k = run.from; ; k = (k + 1) % n) {
143
+ out.push(k);
144
+ if (k === run.to) return out;
145
+ }
146
+ }
147
+ function foldContour(c, runs, specs, tol) {
148
+ const n = c.anchors.length;
149
+ const runAt = /* @__PURE__ */ new Map();
150
+ const inside = /* @__PURE__ */ new Set();
151
+ for (const run of runs) {
152
+ runAt.set(run.from, run);
153
+ for (const k of covered(run, n)) inside.add(k);
154
+ }
155
+ let begin = 0;
156
+ if (c.closed) {
157
+ const free = c.anchors.findIndex((_a, k) => !inside.has(k));
158
+ begin = free >= 0 ? free : runs[0].from;
159
+ }
160
+ const nodes = [];
161
+ const exits = [];
162
+ for (let step = 0, k = begin; step < n; ) {
163
+ const run = runAt.get(k);
164
+ if (run) {
165
+ nodes.push({ at: run.trace.anchor, spec: run.trace.spec });
166
+ exits.push(run.to);
167
+ const span = covered(run, n).length;
168
+ step += span;
169
+ k = (run.to + 1) % n;
170
+ } else {
171
+ nodes.push({ at: c.anchors[k], spec: specs[k] ?? null });
172
+ exits.push(k);
173
+ step++;
174
+ k = (k + 1) % n;
175
+ }
176
+ }
177
+ const runEnds = new Set(runs.map((r) => r.to));
178
+ const segs = [];
179
+ const count = c.closed ? nodes.length : nodes.length - 1;
180
+ for (let m = 0; m < count; m++) {
181
+ const exit = exits[m];
182
+ const moveStart = runEnds.has(exit) ? nodes[m].at : void 0;
183
+ const moveEnd = runAt.has((exit + 1) % n) ? nodes[(m + 1) % nodes.length].at : void 0;
184
+ const reached = reachSeg(c.segs[exit], moveStart, moveEnd, tol);
185
+ if (!reached) return null;
186
+ segs.push(reached);
187
+ }
188
+ return { nodes, segs, closed: c.closed, folded: [...runs] };
189
+ }
190
+ function write(contours, result) {
191
+ const b = new PathBuilder();
192
+ const specs = [];
193
+ for (const { nodes, segs, closed } of contours) {
194
+ b.moveTo(nodes[0].at.x, nodes[0].at.y);
195
+ specs.push(nodes[0].spec);
196
+ segs.forEach((s, m) => {
197
+ const to = nodes[(m + 1) % nodes.length];
198
+ const closing = closed && m === segs.length - 1;
199
+ if (closing && s.line) return;
200
+ if (s.line) b.lineTo(to.at.x, to.at.y);
201
+ else b.curveTo(s.c1.x, s.c1.y, s.c2.x, s.c2.y, to.at.x, to.at.y);
202
+ specs.push(to.spec);
203
+ });
204
+ if (closed) b.close();
205
+ }
206
+ const { commands, coords } = b.build();
207
+ const built = { ...withoutCorners(result), commands, coords };
208
+ const flat = flatAnchorIndices(built);
209
+ const corners = [];
210
+ specs.forEach((spec, k) => {
211
+ if (!spec) return;
212
+ while (corners.length < flat[k]) corners.push(null);
213
+ corners[flat[k]] = spec;
214
+ });
215
+ const compact = compactCorners(corners);
216
+ return compact ? { ...built, corners: compact } : built;
217
+ }
218
+ function failedTraces(path, tol, folded) {
219
+ const bad = new Set(folded.map((r) => r.trace));
220
+ for (const cut of cornerCuts(path)) {
221
+ for (const t of bad) {
222
+ if (dist(cut.anchor, t.anchor) > tol) continue;
223
+ const same = dist(cut.start, t.start) <= tol && dist(cut.end, t.end) <= tol || dist(cut.start, t.end) <= tol && dist(cut.end, t.start) <= tol;
224
+ if (same) bad.delete(t);
225
+ }
226
+ }
227
+ return bad;
228
+ }
229
+ function restoreCorners(result, traces, tolerance = CORNER_RESTORE_TOLERANCE) {
230
+ const contours = decodeContours(result);
231
+ if (!contours || traces.length === 0) return result;
232
+ const rejected = /* @__PURE__ */ new Set();
233
+ for (let attempt = 0; attempt <= traces.length; attempt++) {
234
+ const rebuilt = [];
235
+ for (const c of contours) {
236
+ const runs = [];
237
+ const used = /* @__PURE__ */ new Set();
238
+ for (const t of traces) {
239
+ if (rejected.has(t)) continue;
240
+ const run = findRun(c, t, tolerance);
241
+ if (!run) continue;
242
+ const span = covered(run, c.anchors.length);
243
+ if (span.some((k) => used.has(k))) continue;
244
+ span.forEach((k) => used.add(k));
245
+ runs.push(run);
246
+ }
247
+ const specs = c.anchors.map((_a, k) => result.corners?.[c.first + k] ?? null);
248
+ const folded2 = runs.length > 0 ? foldContour(c, runs, specs, tolerance) : null;
249
+ if (runs.length > 0 && !folded2) {
250
+ runs.forEach((r) => rejected.add(r.trace));
251
+ rebuilt.length = 0;
252
+ break;
253
+ }
254
+ rebuilt.push(folded2 ?? { nodes: c.anchors.map((at, k) => ({ at, spec: specs[k] })), segs: c.segs, closed: c.closed, folded: [] });
255
+ }
256
+ if (rebuilt.length !== contours.length) continue;
257
+ const folded = rebuilt.flatMap((r) => r.folded);
258
+ if (folded.length === 0) return result;
259
+ const out = write(rebuilt, result);
260
+ const bad = failedTraces(out, tolerance, folded);
261
+ if (bad.size === 0) return out;
262
+ bad.forEach((t) => rejected.add(t));
263
+ }
264
+ return result;
265
+ }
266
+
267
+ // src/booleans/contourSegments.ts
268
+ function evalSeg(s, t) {
269
+ const u = 1 - t;
270
+ if (s.length === 2) return { x: u * s[0].x + t * s[1].x, y: u * s[0].y + t * s[1].y };
271
+ if (s.length === 3) {
272
+ const a2 = u * u, b2 = 2 * u * t, c2 = t * t;
273
+ return { x: a2 * s[0].x + b2 * s[1].x + c2 * s[2].x, y: a2 * s[0].y + b2 * s[1].y + c2 * s[2].y };
274
+ }
275
+ const a = u * u * u, b = 3 * u * u * t, c = 3 * u * t * t, d = t * t * t;
276
+ return {
277
+ x: a * s[0].x + b * s[1].x + c * s[2].x + d * s[3].x,
278
+ y: a * s[0].y + b * s[1].y + c * s[2].y + d * s[3].y
279
+ };
280
+ }
281
+ function derivSeg(s, t) {
282
+ const n = s.length - 1;
283
+ const d = [];
284
+ for (let i = 0; i < n; i++) d.push({ x: n * (s[i + 1].x - s[i].x), y: n * (s[i + 1].y - s[i].y) });
285
+ return d.length === 1 ? d[0] : evalSeg(d, t);
286
+ }
287
+ function splitSeg(s, t) {
288
+ const pts = (c) => {
289
+ const out = [];
290
+ for (let i = 0; i < c.length; i += 2) out.push({ x: c[i], y: c[i + 1] });
291
+ return out;
292
+ };
293
+ if (s.length === 2) {
294
+ const m = evalSeg(s, t);
295
+ return [[s[0], m], [m, s[1]]];
296
+ }
297
+ if (s.length === 3) {
298
+ const [l2, r2] = splitQuadraticAt(s[0].x, s[0].y, s[1].x, s[1].y, s[2].x, s[2].y, t);
299
+ return [pts(l2), pts(r2)];
300
+ }
301
+ const [l, r] = splitCubicAt(s[0].x, s[0].y, s[1].x, s[1].y, s[2].x, s[2].y, s[3].x, s[3].y, t);
302
+ return [pts(l), pts(r)];
303
+ }
304
+ function subSeg(s, t0, t1, p0, p1) {
305
+ if (t1 - t0 <= 0) return null;
306
+ let out = s;
307
+ if (t0 > 0) out = splitSeg(out, t0)[1];
308
+ const u = (t1 - t0) / (1 - t0);
309
+ if (u < 1) out = splitSeg(out, u)[0];
310
+ out = out.slice();
311
+ out[0] = p0;
312
+ out[out.length - 1] = p1;
313
+ return out;
314
+ }
315
+ var reverseContour = (c) => c.map((s) => s.slice().reverse()).reverse();
316
+ function sampleContour(c) {
317
+ const out = [];
318
+ for (const s of c) {
319
+ const n = s.length === 2 ? 1 : 16;
320
+ for (let i = 0; i < n; i++) {
321
+ const p = evalSeg(s, i / n);
322
+ out.push(p.x, p.y);
323
+ }
324
+ }
325
+ return out;
326
+ }
327
+ function signedArea(c) {
328
+ const pts = sampleContour(c);
329
+ let a = 0;
330
+ for (let i = 0; i < pts.length; i += 2) {
331
+ const j = (i + 2) % pts.length;
332
+ a += pts[i] * pts[j + 1] - pts[j] * pts[i + 1];
333
+ }
334
+ return a / 2;
335
+ }
336
+ function sideCoeffs(s, o, d) {
337
+ return s.map((p) => d.x * (p.y - o.y) - d.y * (p.x - o.x));
338
+ }
339
+ function bernstein(f, t) {
340
+ const u = 1 - t;
341
+ if (f.length === 2) return u * f[0] + t * f[1];
342
+ if (f.length === 3) return u * u * f[0] + 2 * u * t * f[1] + t * t * f[2];
343
+ return u * u * u * f[0] + 3 * u * u * t * f[1] + 3 * u * t * t * f[2] + t * t * t * f[3];
344
+ }
345
+ function signChanges(f, zeroIsPositive) {
346
+ const sgn = (v) => v > 0 ? 1 : v < 0 ? -1 : zeroIsPositive ? 1 : 0;
347
+ const cuts = [0, ...criticalPoints(f), 1];
348
+ const out = [];
349
+ for (let i = 0; i + 1 < cuts.length; i++) {
350
+ let lo = cuts[i], hi = cuts[i + 1];
351
+ const slo = sgn(bernstein(f, lo)), shi = sgn(bernstein(f, hi));
352
+ if (slo === 0 && i > 0) {
353
+ const before = sgn(bernstein(f, lo - 1e-7)), after = sgn(bernstein(f, lo + 1e-7));
354
+ if (before * after < 0) out.push({ t: lo, before, after });
355
+ }
356
+ if (slo * shi >= 0) continue;
357
+ for (let it = 0; it < 64; it++) {
358
+ const mid = (lo + hi) / 2;
359
+ if (sgn(bernstein(f, mid)) === slo) lo = mid;
360
+ else hi = mid;
361
+ }
362
+ out.push({ t: (lo + hi) / 2, before: slo, after: shi });
363
+ }
364
+ return out;
365
+ }
366
+ function criticalPoints(f) {
367
+ if (f.length < 3) return [];
368
+ const n = f.length - 1;
369
+ const d = f.slice(1).map((v, i) => n * (v - f[i]));
370
+ let A = 0, B, C;
371
+ if (d.length === 2) {
372
+ B = d[1] - d[0];
373
+ C = d[0];
374
+ } else {
375
+ A = d[0] - 2 * d[1] + d[2];
376
+ B = 2 * (d[1] - d[0]);
377
+ C = d[0];
378
+ }
379
+ const out = [];
380
+ const scale = Math.max(Math.abs(A), Math.abs(B), Math.abs(C)) || 1;
381
+ if (Math.abs(A) / scale < 1e-12) {
382
+ if (Math.abs(B) / scale > 1e-12) out.push(-C / B);
383
+ } else {
384
+ const disc = B * B - 4 * A * C;
385
+ if (disc >= 0) {
386
+ const q = -0.5 * (B + Math.sign(B || 1) * Math.sqrt(disc));
387
+ out.push(q / A);
388
+ if (q !== 0) out.push(C / q);
389
+ }
390
+ }
391
+ return out.filter((t) => t > 0 && t < 1).sort((x, y) => x - y);
392
+ }
393
+ function endSide(f, fromStart) {
394
+ const n = f.length;
395
+ for (let i = 1; i < n; i++) {
396
+ const v = fromStart ? f[i] : f[n - 1 - i];
397
+ if (v !== 0) return Math.sign(v);
398
+ }
399
+ return 0;
400
+ }
401
+
402
+ // src/booleans/contours.ts
403
+ function parseContours(path) {
404
+ const fillsOpen = path.kind === "rect" || fillsOpenSubpaths(path);
405
+ return parseSubpaths(path).filter((s) => s.closed || fillsOpen).map((s) => s.segs);
406
+ }
407
+ function parseSubpaths(given, implicitClose = true) {
408
+ const path = resolveCorners(given);
409
+ if (path.kind === "rect") {
410
+ const { x, y, width: w, height: h } = path;
411
+ const p = [{ x, y }, { x: x + w, y }, { x: x + w, y: y + h }, { x, y: y + h }];
412
+ return [{ segs: p.map((q, i) => [q, p[(i + 1) % 4]]), closed: true }];
413
+ }
414
+ const out = [];
415
+ let cur = [];
416
+ let start = { x: 0, y: 0 };
417
+ let pen = start;
418
+ const finish = (closed) => {
419
+ if (cur.length > 0 && (closed || implicitClose) && (pen.x !== start.x || pen.y !== start.y)) {
420
+ cur.push([pen, start]);
421
+ }
422
+ if (cur.length > 0) out.push({ segs: cur, closed });
423
+ cur = [];
424
+ pen = start;
425
+ };
426
+ const c = path.coords;
427
+ let k = 0;
428
+ for (const cmd of path.commands) {
429
+ if (cmd === PATH_M) {
430
+ finish(false);
431
+ start = pen = { x: c[k], y: c[k + 1] };
432
+ k += 2;
433
+ } else if (cmd === PATH_L) {
434
+ const e = { x: c[k], y: c[k + 1] };
435
+ if (e.x !== pen.x || e.y !== pen.y) cur.push([pen, e]);
436
+ pen = e;
437
+ k += 2;
438
+ } else if (cmd === PATH_Q) {
439
+ const e = { x: c[k + 2], y: c[k + 3] };
440
+ cur.push([pen, { x: c[k], y: c[k + 1] }, e]);
441
+ pen = e;
442
+ k += 4;
443
+ } else if (cmd === PATH_C) {
444
+ const e = { x: c[k + 4], y: c[k + 5] };
445
+ cur.push([pen, { x: c[k], y: c[k + 1] }, { x: c[k + 2], y: c[k + 3] }, e]);
446
+ pen = e;
447
+ k += 6;
448
+ } else if (cmd === PATH_Z) {
449
+ finish(true);
450
+ }
451
+ }
452
+ finish(false);
453
+ return out;
454
+ }
455
+ function contoursIntersect(contours, tol) {
456
+ const edges = [];
457
+ contours.forEach((contour, ci) => {
458
+ const pts = [];
459
+ for (const s of contour) {
460
+ let n = 1;
461
+ if (s.length > 2) {
462
+ let len = 0;
463
+ for (let i = 0; i + 1 < s.length; i++) len += Math.hypot(s[i + 1].x - s[i].x, s[i + 1].y - s[i].y);
464
+ n = Math.min(64, Math.max(2, Math.ceil(Math.sqrt(len / Math.max(tol, 1e-3)))));
465
+ }
466
+ for (let i = 0; i < n; i++) pts.push(evalSeg(s, i / n));
467
+ }
468
+ for (let i = 0; i < pts.length; i++) {
469
+ const p = pts[i], q = pts[(i + 1) % pts.length];
470
+ edges.push({ x0: p.x, y0: p.y, x1: q.x, y1: q.y, c: ci, i, n: pts.length });
471
+ }
472
+ });
473
+ for (let i = 0; i < edges.length; i++) {
474
+ const e = edges[i];
475
+ for (let j = i + 1; j < edges.length; j++) {
476
+ const f = edges[j];
477
+ if (e.c === f.c && (j - i === 1 || i === 0 && f.i === f.n - 1)) continue;
478
+ if (Math.max(e.x0, e.x1) < Math.min(f.x0, f.x1) || Math.max(f.x0, f.x1) < Math.min(e.x0, e.x1)) continue;
479
+ if (Math.max(e.y0, e.y1) < Math.min(f.y0, f.y1) || Math.max(f.y0, f.y1) < Math.min(e.y0, e.y1)) continue;
480
+ if (segmentsCross(e.x0, e.y0, e.x1, e.y1, f.x0, f.y0, f.x1, f.y1)) return true;
481
+ }
482
+ }
483
+ return false;
484
+ }
485
+ function windingAt(q, contours) {
486
+ const dir = { x: 1, y: 0 };
487
+ let w = 0;
488
+ for (const contour of contours) {
489
+ for (const s of contour) {
490
+ for (const c of signChanges(sideCoeffs(s, q, dir), true)) {
491
+ if (evalSeg(s, c.t).x > q.x) w += c.after > 0 ? 1 : -1;
492
+ }
493
+ }
494
+ }
495
+ return w;
496
+ }
497
+ function extentOf(contours) {
498
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
499
+ for (const c of contours) for (const s of c) for (const p of s) {
500
+ minX = Math.min(minX, p.x);
501
+ maxX = Math.max(maxX, p.x);
502
+ minY = Math.min(minY, p.y);
503
+ maxY = Math.max(maxY, p.y);
504
+ }
505
+ return Math.hypot(maxX - minX, maxY - minY);
506
+ }
507
+ function negligibleArea(contours) {
508
+ const extent = extentOf(contours);
509
+ return extent * extent * EPS * EPS;
510
+ }
511
+ function orientBoundaries(contours, fillRule) {
512
+ const filled = (q) => {
513
+ const w = windingAt(q, contours);
514
+ return fillRule === "evenodd" ? (w & 1) !== 0 : w !== 0;
515
+ };
516
+ const eps = Math.max(extentOf(contours) * 1e-6, 1e-9);
517
+ const out = [];
518
+ for (const contour of contours) {
519
+ let probe = contour[0];
520
+ let best = -1;
521
+ for (const s of contour) {
522
+ const len = Math.hypot(s[s.length - 1].x - s[0].x, s[s.length - 1].y - s[0].y);
523
+ if (len > best) {
524
+ best = len;
525
+ probe = s;
526
+ }
527
+ }
528
+ const p = evalSeg(probe, 0.5);
529
+ let tan = derivSeg(probe, 0.5);
530
+ const tl = Math.hypot(tan.x, tan.y);
531
+ if (tl === 0) continue;
532
+ tan = { x: tan.x / tl, y: tan.y / tl };
533
+ const left = filled({ x: p.x - tan.y * eps, y: p.y + tan.x * eps });
534
+ const right = filled({ x: p.x + tan.y * eps, y: p.y - tan.x * eps });
535
+ if (left && !right) out.push(contour);
536
+ else if (right && !left) out.push(reverseContour(contour));
537
+ }
538
+ return out;
539
+ }
540
+
541
+ // src/booleans/cutRegions.ts
542
+ function assembleRegions(outers, holes) {
543
+ const regions = outers.map((o) => ({ loops: [o], ring: sampleContour(o), area: signedArea(o) }));
544
+ for (const h of holes) {
545
+ const hp = evalSeg(h[0], 0.5);
546
+ let best = null;
547
+ for (const r of regions) {
548
+ if (pointInPolygon(r.ring, hp.x, hp.y) && (!best || r.area < best.area)) best = r;
549
+ }
550
+ best?.loops.push(h);
551
+ }
552
+ return regions.map((r) => r.loops);
553
+ }
554
+ var regionArea = (r) => r.reduce((s, c) => s + signedArea(c), 0);
555
+ var toPath = (loops, fillRule) => writePath(loops.map((segs) => ({ segs, closed: true })), fillRule);
556
+ function writePath(subpaths, fillRule) {
557
+ const cmds = [];
558
+ const xs = [];
559
+ for (const { segs, closed } of subpaths) {
560
+ cmds.push(PATH_M);
561
+ xs.push(segs[0][0].x, segs[0][0].y);
562
+ for (const s of segs) {
563
+ cmds.push(s.length === 2 ? PATH_L : s.length === 3 ? PATH_Q : PATH_C);
564
+ for (let i = 1; i < s.length; i++) xs.push(s[i].x, s[i].y);
565
+ }
566
+ if (closed) cmds.push(PATH_Z);
567
+ }
568
+ return { kind: "polygon", commands: new Uint8Array(cmds), coords: new Float32Array(xs), fillRule };
569
+ }
570
+
571
+ export { CORNER_RESTORE_TOLERANCE, anchorRange, assembleRegions, carryCorners, contoursIntersect, cornerTraces, derivSeg, endSide, evalSeg, extentOf, keepCorners, negligibleArea, orientBoundaries, parseContours, parseSubpaths, regionArea, restoreCorners, reverseContour, sampleContour, sideCoeffs, signChanges, signedArea, subSeg, toPath, windingAt, writePath };
572
+ //# sourceMappingURL=chunk-7KLJZFBY.js.map
573
+ //# sourceMappingURL=chunk-7KLJZFBY.js.map