pattapatta 0.3.0 → 0.4.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 (44) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/{circle-BDbKfrdR.d.ts → circle-CauDMv8V.d.ts} +1 -1
  3. package/dist/circlePacking/index.d.ts +2 -3
  4. package/dist/construction/index.d.ts +11 -3
  5. package/dist/construction/index.js +429 -2
  6. package/dist/construction/index.js.map +1 -1
  7. package/dist/contour/index.d.ts +3 -4
  8. package/dist/contour/index.js.map +1 -1
  9. package/dist/conversion/index.d.ts +2 -3
  10. package/dist/{group-BNjVVYSQ.d.ts → group-YVmSJuGo.d.ts} +1 -1
  11. package/dist/hatch/index.d.ts +70 -4
  12. package/dist/hatch/index.js +414 -3
  13. package/dist/hatch/index.js.map +1 -1
  14. package/dist/hull/index.d.ts +1 -2
  15. package/dist/index.d.ts +12 -13
  16. package/dist/index.js +1816 -1260
  17. package/dist/index.js.map +1 -1
  18. package/dist/meshing/index.d.ts +3 -4
  19. package/dist/morphology/index.d.ts +2 -3
  20. package/dist/optimisation/index.d.ts +2 -3
  21. package/dist/{path-0RjhYjJs.d.ts → path-Boeshk9L.d.ts} +9 -2
  22. package/dist/pointSet/index.d.ts +15 -2
  23. package/dist/pointSet/index.js +148 -2
  24. package/dist/pointSet/index.js.map +1 -1
  25. package/dist/polygonisation/index.d.ts +1 -2
  26. package/dist/polygonisation/index.js +54 -50
  27. package/dist/polygonisation/index.js.map +1 -1
  28. package/dist/predicates/index.d.ts +2 -3
  29. package/dist/processing/index.d.ts +3 -4
  30. package/dist/{segment-BKuIFMKD.d.ts → segment-CpLILSd7.d.ts} +1 -1
  31. package/dist/segmentSet/index.d.ts +41 -3
  32. package/dist/segmentSet/index.js +261 -1
  33. package/dist/segmentSet/index.js.map +1 -1
  34. package/dist/shapeBoolean/index.d.ts +2 -3
  35. package/dist/svg/index.d.ts +2 -3
  36. package/dist/tiling/index.d.ts +10 -4
  37. package/dist/tiling/index.js +148 -13
  38. package/dist/tiling/index.js.map +1 -1
  39. package/dist/transformation/index.d.ts +1 -2
  40. package/dist/triangulation/index.d.ts +1 -2
  41. package/dist/triangulation/index.js.map +1 -1
  42. package/dist/voronoi/index.d.ts +2 -3
  43. package/package.json +1 -1
  44. package/dist/vec2-CWyXN1Wj.d.ts +0 -10
@@ -1,4 +1,4 @@
1
- import { FillRule, intersectD, isPositiveD, pointInPolygonD, PointInPolygonResult } from 'clipper2-ts';
1
+ import { FillRule, intersectD, isPositiveD, areaD, differenceD, pointInPolygonD, PointInPolygonResult } from 'clipper2-ts';
2
2
 
3
3
  // src/types/vec2.ts
4
4
  function vec2(x, y) {
@@ -98,8 +98,41 @@ function pointInRing(point, ring) {
98
98
  function clipIntersect(a, b) {
99
99
  return intersectD(a, b, DEFAULT_FILL_RULE);
100
100
  }
101
+ function clipDifference(a, b) {
102
+ return differenceD(a, b, DEFAULT_FILL_RULE);
103
+ }
104
+ function pathsArea(paths) {
105
+ let sum = 0;
106
+ for (const p of paths) {
107
+ sum += Math.abs(areaD(p));
108
+ }
109
+ return sum;
110
+ }
101
111
 
102
112
  // src/predicates/index.ts
113
+ function ringArea(ring) {
114
+ if (ring.length < 3) return 0;
115
+ let sum = 0;
116
+ for (let i = 0; i < ring.length; i++) {
117
+ const a = ring[i];
118
+ const b = ring[(i + 1) % ring.length];
119
+ sum += a.x * b.y - b.x * a.y;
120
+ }
121
+ return sum / 2;
122
+ }
123
+ function area(p) {
124
+ if (!p.closed || p.rings.length === 0) return 0;
125
+ try {
126
+ return pathsArea(pathToPathsD(p));
127
+ } catch {
128
+ let total = 0;
129
+ for (let i = 0; i < p.rings.length; i++) {
130
+ const a = Math.abs(ringArea(p.rings[i]));
131
+ total += i === 0 ? a : -a;
132
+ }
133
+ return Math.max(0, total);
134
+ }
135
+ }
103
136
  function bounds(p) {
104
137
  let minX = Infinity;
105
138
  let minY = Infinity;
@@ -119,16 +152,6 @@ function bounds(p) {
119
152
  return { minX, minY, maxX, maxY };
120
153
  }
121
154
 
122
- // src/construction/index.ts
123
- function createRect(x, y, width, height) {
124
- return polygon([
125
- { x, y },
126
- { x: x + width, y },
127
- { x: x + width, y: y + height },
128
- { x, y: y + height }
129
- ]);
130
- }
131
-
132
155
  // src/shapeBoolean/index.ts
133
156
  function ensureClosed(p) {
134
157
  if (!p.closed) {
@@ -143,6 +166,35 @@ function intersect(a, b) {
143
166
  );
144
167
  return pathsDToGroup(result);
145
168
  }
169
+ function subtract(a, b) {
170
+ const result = clipDifference(
171
+ pathToPathsD(ensureClosed(a)),
172
+ pathToPathsD(ensureClosed(b))
173
+ );
174
+ return pathsDToGroup(result);
175
+ }
176
+
177
+ // src/construction/index.ts
178
+ function createCircle(cx, cy, radius, segments = 64) {
179
+ return createRegularPolygon(cx, cy, radius, Math.max(3, Math.floor(segments)));
180
+ }
181
+ function createRect(x, y, width, height) {
182
+ return polygon([
183
+ { x, y },
184
+ { x: x + width, y },
185
+ { x: x + width, y: y + height },
186
+ { x, y: y + height }
187
+ ]);
188
+ }
189
+ function createRegularPolygon(cx, cy, radius, sides, rotation = -Math.PI / 2) {
190
+ const n = Math.max(3, Math.floor(sides));
191
+ const ring = [];
192
+ for (let i = 0; i < n; i++) {
193
+ const t = rotation + i / n * Math.PI * 2;
194
+ ring.push({ x: cx + Math.cos(t) * radius, y: cy + Math.sin(t) * radius });
195
+ }
196
+ return polygon(ring);
197
+ }
146
198
 
147
199
  // src/processing/index.ts
148
200
  function slice(p, a, b) {
@@ -326,6 +378,88 @@ function sliceDivision(p, spacing, angle = 0) {
326
378
  function hatchSubdivision(p, spacing, angle = 0) {
327
379
  return sliceDivision(p, spacing, angle);
328
380
  }
381
+ function arcDivision(width, height, arcs, seed = 1, circlePoints = 64) {
382
+ const w = Math.max(width, 1e-9);
383
+ const h = Math.max(height, 1e-9);
384
+ const n = Math.max(0, Math.floor(arcs));
385
+ const segs = Math.max(8, Math.floor(circlePoints));
386
+ const rect = createRect(0, 0, w, h);
387
+ if (n === 0) return group([rect]);
388
+ const rng = mulberry32(seed >>> 0);
389
+ let faces = [rect];
390
+ const minArea = w * h * 1e-8;
391
+ for (let i = 0; i < n; i++) {
392
+ const { cx, cy, r } = sampleBoundaryCircle(w, h, rng);
393
+ const disk = createCircle(cx, cy, r, segs);
394
+ const next = [];
395
+ for (const face of faces) {
396
+ for (const piece of intersect(face, disk).paths) {
397
+ if (area(piece) > minArea) next.push(piece);
398
+ }
399
+ for (const piece of subtract(face, disk).paths) {
400
+ if (area(piece) > minArea) next.push(piece);
401
+ }
402
+ }
403
+ if (next.length > 0) faces = next;
404
+ }
405
+ return group(faces);
406
+ }
407
+ function sampleBoundaryCircle(w, h, rng) {
408
+ const peri = 2 * (w + h);
409
+ let t = rng() * peri;
410
+ let cx;
411
+ let cy;
412
+ let side;
413
+ if (t < w) {
414
+ side = 0;
415
+ cx = t;
416
+ cy = 0;
417
+ } else {
418
+ t -= w;
419
+ if (t < h) {
420
+ side = 1;
421
+ cx = w;
422
+ cy = t;
423
+ } else {
424
+ t -= h;
425
+ if (t < w) {
426
+ side = 2;
427
+ cx = w - t;
428
+ cy = h;
429
+ } else {
430
+ side = 3;
431
+ cx = 0;
432
+ cy = h - (t - w);
433
+ }
434
+ }
435
+ }
436
+ const distOther = [
437
+ cy,
438
+ // to top
439
+ w - cx,
440
+ // to right
441
+ h - cy,
442
+ // to bottom
443
+ cx
444
+ // to left
445
+ ];
446
+ let minSecond = Infinity;
447
+ for (let s = 0; s < 4; s++) {
448
+ if (s === side) continue;
449
+ minSecond = Math.min(minSecond, distOther[s]);
450
+ }
451
+ const maxR = Math.hypot(w, h);
452
+ const r = minSecond + rng() * Math.max(0, maxR - minSecond);
453
+ return { cx, cy, r: Math.max(r, minSecond + 1e-6) };
454
+ }
455
+ function mulberry32(a) {
456
+ return function() {
457
+ let t = a += 1831565813;
458
+ t = Math.imul(t ^ t >>> 15, t | 1);
459
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
460
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
461
+ };
462
+ }
329
463
  function mid(a, b) {
330
464
  return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
331
465
  }
@@ -336,9 +470,10 @@ var tiling = {
336
470
  quadSubdivision,
337
471
  triangleSubdivision,
338
472
  sliceDivision,
339
- hatchSubdivision
473
+ hatchSubdivision,
474
+ arcDivision
340
475
  };
341
476
 
342
- export { hatchSubdivision, hexTiling, quadSubdivision, rectSubdivision, sliceDivision, squareGrid, tiling, triangleSubdivision };
477
+ export { arcDivision, hatchSubdivision, hexTiling, quadSubdivision, rectSubdivision, sliceDivision, squareGrid, tiling, triangleSubdivision };
343
478
  //# sourceMappingURL=index.js.map
344
479
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/vec2.ts","../../src/types/path.ts","../../src/types/group.ts","../../src/clipper/convert.ts","../../src/predicates/index.ts","../../src/construction/index.ts","../../src/shapeBoolean/index.ts","../../src/processing/index.ts","../../src/tiling/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** 2D point / vector. */\nexport type Vec2 = {\n x: number\n y: number\n}\n\nexport function vec2(x: number, y: number): Vec2 {\n return { x, y }\n}\n\nexport function cloneVec2(v: Vec2): Vec2 {\n return { x: v.x, y: v.y }\n}\n\nexport function equalsVec2(a: Vec2, b: Vec2, eps = 1e-9): boolean {\n return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps\n}\n","import type { Vec2 } from './vec2.js'\nimport { cloneVec2, equalsVec2 } from './vec2.js'\n\n/** Ordered ring of vertices (typically without repeating the closing vertex). */\nexport type Ring = Vec2[]\n\n/**\n * A path: one exterior ring plus optional holes, or an open polyline.\n * `rings[0]` is the exterior (or the open polyline when `closed` is false).\n * Additional rings are holes (only meaningful when `closed` is true).\n */\nexport type Path = {\n rings: Ring[]\n closed: boolean\n}\n\nexport function path(rings: Ring[], closed = true): Path {\n return {\n rings: rings.map((ring) => ring.map(cloneVec2)),\n closed,\n }\n}\n\nexport function polyline(points: Ring): Path {\n return path([points], false)\n}\n\nexport function polygon(exterior: Ring, holes: Ring[] = []): Path {\n return path([exterior, ...holes], true)\n}\n\n/** Drop a trailing vertex that duplicates the first (SVG often closes this way). */\nexport function normalizeRing(ring: Ring, eps = 1e-9): Ring {\n if (ring.length < 2) return ring.map(cloneVec2)\n const first = ring[0]\n const last = ring[ring.length - 1]\n if (first && last && equalsVec2(first, last, eps)) {\n return ring.slice(0, -1).map(cloneVec2)\n }\n return ring.map(cloneVec2)\n}\n\nexport function clonePath(p: Path): Path {\n return {\n closed: p.closed,\n rings: p.rings.map((ring) => ring.map(cloneVec2)),\n }\n}\n","import type { Path } from './path.js'\nimport { clonePath } from './path.js'\n\n/**\n * Ordered collection of paths. Later entries are “on top” for occlusion-style ops.\n */\nexport type Group = {\n paths: Path[]\n}\n\nexport function group(paths: Path[] = []): Group {\n return { paths: paths.map(clonePath) }\n}\n\nexport function groupFromPaths(...paths: Path[]): Group {\n return group(paths)\n}\n\nexport function cloneGroup(g: Group): Group {\n return group(g.paths)\n}\n","import {\n FillRule,\n areaD,\n differenceD,\n intersectD,\n isPositiveD,\n pointInPolygonD,\n PointInPolygonResult,\n unionD,\n xorD,\n type PathD,\n type PathsD,\n type PointD,\n} from 'clipper2-ts'\nimport type { Group, Path, Ring, Vec2 } from '../types/index.js'\nimport { group, normalizeRing, path, vec2 } from '../types/index.js'\n\nexport const DEFAULT_FILL_RULE = FillRule.NonZero\n\nexport function ringToPathD(ring: Ring): PathD {\n const pts: PointD[] = []\n for (const v of normalizeRing(ring)) {\n pts.push({ x: v.x, y: v.y, z: 0 })\n }\n return pts\n}\n\n/** Closed path → Clipper subject/clip paths (exterior + holes). */\nexport function pathToPathsD(p: Path): PathsD {\n if (!p.closed || p.rings.length === 0) {\n throw new Error('Boolean ops require a closed path with at least one ring')\n }\n return p.rings.map((ring) => ringToPathD(ring))\n}\n\nexport function pathsDToGroup(paths: PathsD): Group {\n if (paths.length === 0) return group([])\n\n const outers: { ring: Ring; holes: Ring[] }[] = []\n const holes: Ring[] = []\n\n for (const pd of paths) {\n const ring = pathDToRing(pd)\n if (ring.length < 3) continue\n if (isPositiveD(pd)) {\n outers.push({ ring, holes: [] })\n } else {\n holes.push(ring)\n }\n }\n\n for (const hole of holes) {\n const sample = hole[0]\n if (!sample) continue\n let assigned = false\n for (const outer of outers) {\n if (pointInRing(sample, outer.ring)) {\n outer.holes.push(hole)\n assigned = true\n break\n }\n }\n if (!assigned) {\n // Treat unmatched negative rings as their own outers (orientation flip).\n outers.push({ ring: [...hole].reverse(), holes: [] })\n }\n }\n\n return group(outers.map((o) => path([o.ring, ...o.holes], true)))\n}\n\nexport function pathDToRing(pd: PathD): Ring {\n return normalizeRing(pd.map((p) => vec2(p.x, p.y)))\n}\n\nexport function pointInRing(point: Vec2, ring: Ring): boolean {\n const result = pointInPolygonD(\n { x: point.x, y: point.y, z: 0 },\n ringToPathD(ring),\n )\n return (\n result === PointInPolygonResult.IsInside ||\n result === PointInPolygonResult.IsOn\n )\n}\n\nexport function clipUnion(a: PathsD, b: PathsD): PathsD {\n return unionD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipIntersect(a: PathsD, b: PathsD): PathsD {\n return intersectD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipDifference(a: PathsD, b: PathsD): PathsD {\n return differenceD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipXor(a: PathsD, b: PathsD): PathsD {\n return xorD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function pathsArea(paths: PathsD): number {\n let sum = 0\n for (const p of paths) {\n sum += Math.abs(areaD(p))\n }\n return sum\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { vec2 } from '../types/index.js'\nimport {\n pathToPathsD,\n pathsArea,\n pointInRing,\n} from '../clipper/convert.js'\n\n/** Signed area of a closed ring (shoelace). */\nexport function ringArea(ring: Vec2[]): number {\n if (ring.length < 3) return 0\n let sum = 0\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n sum += a.x * b.y - b.x * a.y\n }\n return sum / 2\n}\n\n/** Absolute area of a closed path (exterior minus holes). */\nexport function area(p: Path): number {\n if (!p.closed || p.rings.length === 0) return 0\n try {\n return pathsArea(pathToPathsD(p))\n } catch {\n let total = 0\n for (let i = 0; i < p.rings.length; i++) {\n const a = Math.abs(ringArea(p.rings[i]!))\n total += i === 0 ? a : -a\n }\n return Math.max(0, total)\n }\n}\n\nexport function areaGroup(g: Group): number {\n return g.paths.reduce((sum, p) => sum + area(p), 0)\n}\n\n/** Centroid of a closed exterior ring (ignores holes for Phase 2). */\nexport function centroid(p: Path): Vec2 {\n const ring = p.rings[0]\n if (!ring || ring.length === 0) return vec2(0, 0)\n const a = ringArea(ring)\n if (Math.abs(a) < 1e-12) {\n let sx = 0\n let sy = 0\n for (const v of ring) {\n sx += v.x\n sy += v.y\n }\n return vec2(sx / ring.length, sy / ring.length)\n }\n let cx = 0\n let cy = 0\n for (let i = 0; i < ring.length; i++) {\n const p0 = ring[i]!\n const p1 = ring[(i + 1) % ring.length]!\n const cross = p0.x * p1.y - p1.x * p0.y\n cx += (p0.x + p1.x) * cross\n cy += (p0.y + p1.y) * cross\n }\n return vec2(cx / (6 * a), cy / (6 * a))\n}\n\nexport function containsPoint(p: Path, point: Vec2): boolean {\n if (!p.closed || !p.rings[0]) return false\n if (!pointInRing(point, p.rings[0])) return false\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && pointInRing(point, hole)) return false\n }\n return true\n}\n\nexport function bounds(p: Path): {\n minX: number\n minY: number\n maxX: number\n maxY: number\n} {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const ring of p.rings) {\n for (const v of ring) {\n minX = Math.min(minX, v.x)\n minY = Math.min(minY, v.y)\n maxX = Math.max(maxX, v.x)\n maxY = Math.max(maxY, v.y)\n }\n }\n if (!Number.isFinite(minX)) {\n return { minX: 0, minY: 0, maxX: 0, maxY: 0 }\n }\n return { minX, minY, maxX, maxY }\n}\n\nexport function width(p: Path): number {\n const b = bounds(p)\n return b.maxX - b.minX\n}\n\nexport function height(p: Path): number {\n const b = bounds(p)\n return b.maxY - b.minY\n}\n\n/** Rough polygon similarity via absolute area difference relative to max area. */\nexport function areaSimilarity(a: Path, b: Path): number {\n const aa = area(a)\n const bb = area(b)\n const denom = Math.max(aa, bb, 1e-12)\n return 1 - Math.abs(aa - bb) / denom\n}\n\nexport const predicates = {\n area,\n areaGroup,\n ringArea,\n centroid,\n containsPoint,\n bounds,\n width,\n height,\n areaSimilarity,\n}\n","import type { Path, Vec2 } from '../types/index.js'\nimport { path, polygon, polyline } from '../types/index.js'\n\n/** Regular n-gon approximating a circle. */\nexport function createCircle(\n cx: number,\n cy: number,\n radius: number,\n segments = 64,\n): Path {\n return createRegularPolygon(cx, cy, radius, Math.max(3, Math.floor(segments)))\n}\n\nexport function createRect(\n x: number,\n y: number,\n width: number,\n height: number,\n): Path {\n return polygon([\n { x, y },\n { x: x + width, y },\n { x: x + width, y: y + height },\n { x, y: y + height },\n ])\n}\n\nexport function createRegularPolygon(\n cx: number,\n cy: number,\n radius: number,\n sides: number,\n rotation = -Math.PI / 2,\n): Path {\n const n = Math.max(3, Math.floor(sides))\n const ring: Vec2[] = []\n for (let i = 0; i < n; i++) {\n const t = rotation + (i / n) * Math.PI * 2\n ring.push({ x: cx + Math.cos(t) * radius, y: cy + Math.sin(t) * radius })\n }\n return polygon(ring)\n}\n\n/** Annulus as exterior + hole. */\nexport function createRing(\n cx: number,\n cy: number,\n outerRadius: number,\n innerRadius: number,\n segments = 64,\n): Path {\n const outer = createCircle(cx, cy, outerRadius, segments).rings[0]!\n const inner = createCircle(cx, cy, Math.min(innerRadius, outerRadius), segments)\n .rings[0]!\n // hole winding opposite for Clipper\n return path([outer, [...inner].reverse()], true)\n}\n\n/** Open circular arc polyline from `startAngle` to `endAngle` (radians). */\nexport function createArc(\n cx: number,\n cy: number,\n radius: number,\n startAngle: number,\n endAngle: number,\n segments = 32,\n): Path {\n const n = Math.max(2, Math.floor(segments))\n const pts: Vec2[] = []\n for (let i = 0; i <= n; i++) {\n const t = startAngle + ((endAngle - startAngle) * i) / n\n pts.push({ x: cx + Math.cos(t) * radius, y: cy + Math.sin(t) * radius })\n }\n return polyline(pts)\n}\n\n/** Star polygon (outer/inner radius alternating). */\nexport function createStar(\n cx: number,\n cy: number,\n outerRadius: number,\n innerRadius: number,\n points = 5,\n rotation = -Math.PI / 2,\n): Path {\n const n = Math.max(3, Math.floor(points))\n const ring: Vec2[] = []\n for (let i = 0; i < n * 2; i++) {\n const r = i % 2 === 0 ? outerRadius : innerRadius\n const t = rotation + (i / (n * 2)) * Math.PI * 2\n ring.push({ x: cx + Math.cos(t) * r, y: cy + Math.sin(t) * r })\n }\n return polygon(ring)\n}\n\n/** Koch snowflake after `iterations` refinement (0 = equilateral triangle). */\nexport function createKochSnowflake(\n cx: number,\n cy: number,\n radius: number,\n iterations = 3,\n): Path {\n const tri = createRegularPolygon(cx, cy, radius, 3)\n let ring = tri.rings[0]!\n const iters = Math.max(0, Math.min(6, Math.floor(iterations)))\n for (let i = 0; i < iters; i++) {\n ring = kochRefine(ring)\n }\n return polygon(ring)\n}\n\nfunction kochRefine(ring: Vec2[]): Vec2[] {\n const out: Vec2[] = []\n const n = ring.length\n for (let i = 0; i < n; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n const dx = b.x - a.x\n const dy = b.y - a.y\n const p1 = { x: a.x + dx / 3, y: a.y + dy / 3 }\n const p2 = { x: a.x + (2 * dx) / 3, y: a.y + (2 * dy) / 3 }\n // outward peak (left of directed edge in Y-down SVG coords = rotate +90 for CCW tri)\n const px = a.x + dx / 2 - dy * (Math.sqrt(3) / 6)\n const py = a.y + dy / 2 + dx * (Math.sqrt(3) / 6)\n out.push(a, p1, { x: px, y: py }, p2)\n }\n return out\n}\n\nexport const construction = {\n createCircle,\n createRect,\n createRegularPolygon,\n createRing,\n createArc,\n createStar,\n createKochSnowflake,\n}\n","import type { Group, Path } from '../types/index.js'\nimport { group, groupFromPaths, path, polygon, vec2 } from '../types/index.js'\nimport {\n clipDifference,\n clipIntersect,\n clipUnion,\n clipXor,\n pathToPathsD,\n pathsDToGroup,\n} from '../clipper/convert.js'\n\nfunction ensureClosed(p: Path): Path {\n if (!p.closed) {\n throw new Error('shapeBoolean requires closed paths')\n }\n return p\n}\n\n/** Union of two closed paths. */\nexport function union(a: Path, b: Path): Group {\n const result = clipUnion(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Union of many closed paths (folded left-to-right). */\nexport function unionAll(paths: Path[]): Group {\n if (paths.length === 0) return group([])\n let acc = pathToPathsD(ensureClosed(paths[0]!))\n for (let i = 1; i < paths.length; i++) {\n acc = clipUnion(acc, pathToPathsD(ensureClosed(paths[i]!)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Intersection of two closed paths. */\nexport function intersect(a: Path, b: Path): Group {\n const result = clipIntersect(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract b from a (a \\ b). */\nexport function subtract(a: Path, b: Path): Group {\n const result = clipDifference(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract many shapes from a base. */\nexport function subtractAll(base: Path, shapes: Path[]): Group {\n let acc = pathToPathsD(ensureClosed(base))\n for (const s of shapes) {\n acc = clipDifference(acc, pathToPathsD(ensureClosed(s)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Symmetric difference. */\nexport function symDifference(a: Path, b: Path): Group {\n const result = clipXor(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Complement of shape within axis-aligned rectangle [0,width] x [0,height]. */\nexport function complement(shape: Path, width: number, height: number): Group {\n const frame = polygon([\n vec2(0, 0),\n vec2(width, 0),\n vec2(width, height),\n vec2(0, height),\n ])\n return subtract(frame, shape)\n}\n\n/**\n * Painter-style occlusion: later paths in the group are on top.\n * Each path has higher paths subtracted from it; returns visible remainders.\n */\nexport function occlusionSubtract(g: Group): Group {\n const paths = g.paths\n const visible: Path[] = []\n for (let i = 0; i < paths.length; i++) {\n const subject = paths[i]\n if (!subject) continue\n const occluders = paths.slice(i + 1)\n const piece =\n occluders.length === 0\n ? groupFromPaths(ensureClosed(subject))\n : subtractAll(subject, occluders)\n for (const p of piece.paths) {\n visible.push(p)\n }\n }\n return group(visible)\n}\n\n/**\n * Regions covered by at least two input shapes.\n * If `merged`, collapse multi-overlaps into disjoint patches via union of pairwise intersects.\n */\nexport function overlapRegions(shapes: Path[], merged: boolean): Group {\n if (shapes.length < 2) return group([])\n const pairs: Path[] = []\n for (let i = 0; i < shapes.length; i++) {\n for (let j = i + 1; j < shapes.length; j++) {\n const a = shapes[i]\n const b = shapes[j]\n if (!a || !b) continue\n for (const p of intersect(a, b).paths) {\n pairs.push(p)\n }\n }\n }\n if (!merged) return group(pairs)\n return unionAll(pairs)\n}\n\nexport const shapeBoolean = {\n union,\n unionAll,\n intersect,\n subtract,\n subtractAll,\n symDifference,\n complement,\n occlusionSubtract,\n overlapRegions,\n}\n","import type { Group, Path, Segment, Vec2 } from '../types/index.js'\nimport { path, normalizeRing, polygon, segment, group } from '../types/index.js'\nimport { bounds, containsPoint, centroid } from '../predicates/index.js'\nimport { intersect, unionAll } from '../shapeBoolean/index.js'\n\n/** Exterior ring as its own closed path (holes dropped). */\nexport function extractPerimeter(p: Path): Path {\n const exterior = p.rings[0]\n if (!exterior) return path([], true)\n return polygon(exterior)\n}\n\n/** Alias for extractPerimeter. */\nexport function extractBoundary(p: Path): Path {\n return extractPerimeter(p)\n}\n\n/** Each hole as a separate closed path. */\nexport function extractHoles(p: Path): Path[] {\n const holes: Path[] = []\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && hole.length >= 3) holes.push(polygon(hole))\n }\n return holes\n}\n\n/**\n * Insert vertices so no edge exceeds `maxSegLen`.\n * Closed rings treat the wrap-around edge.\n */\nexport function densify(p: Path, maxSegLen: number): Path {\n if (maxSegLen <= 0) return p\n return path(\n p.rings.map((ring) => densifyRing(ring, maxSegLen, p.closed)),\n p.closed,\n )\n}\n\nfunction densifyRing(\n ring: Vec2[],\n maxSegLen: number,\n closed: boolean,\n): Vec2[] {\n if (ring.length < 2) return [...ring]\n const out: Vec2[] = []\n const n = ring.length\n const edges = closed ? n : n - 1\n for (let i = 0; i < edges; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n out.push(a)\n const dist = Math.hypot(b.x - a.x, b.y - a.y)\n const steps = Math.floor(dist / maxSegLen)\n for (let s = 1; s < steps; s++) {\n const t = s / steps\n out.push({\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n })\n }\n }\n if (!closed) out.push(ring[n - 1]!)\n return closed ? normalizeRing(out) : out\n}\n\n/** Drop holes whose absolute area is below `minArea`. */\nexport function removeSmallHoles(p: Path, minArea: number): Path {\n if (p.rings.length <= 1) return p\n const exterior = p.rings[0]!\n const kept = p.rings.slice(1).filter((hole) => {\n const a = Math.abs(shoelace(hole))\n return a >= minArea\n })\n return path([exterior, ...kept], p.closed)\n}\n\n/** Seeded uniform random points inside a closed path. */\nexport function generateRandomPoints(\n p: Path,\n count: number,\n seed = 1,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const b = bounds(p)\n const out: Vec2[] = []\n let attempts = 0\n const maxAttempts = Math.max(count * 50, 100)\n while (out.length < count && attempts < maxAttempts) {\n attempts++\n const pt = {\n x: b.minX + rng() * (b.maxX - b.minX),\n y: b.minY + rng() * (b.maxY - b.minY),\n }\n if (containsPoint(p, pt)) out.push(pt)\n }\n return out\n}\n\n/** Axis-aligned grid samples that fall inside the path. */\nexport function generateRandomGridPoints(\n p: Path,\n spacing: number,\n): Vec2[] {\n const step = Math.max(spacing, 1e-9)\n const b = bounds(p)\n const out: Vec2[] = []\n for (let x = b.minX; x <= b.maxX + 1e-12; x += step) {\n for (let y = b.minY; y <= b.maxY + 1e-12; y += step) {\n const pt = { x, y }\n if (containsPoint(p, pt)) out.push(pt)\n }\n }\n return out\n}\n\n/** Evenly spaced samples along the exterior perimeter. */\nexport function pointsOnExterior(p: Path, count: number): Vec2[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 2 || count <= 0) return []\n const lengths = edgeLengths(ring, true)\n const total = lengths.reduce((s, L) => s + L, 0)\n if (total < 1e-12) return []\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n const target = (i / count) * total\n out.push(pointAtArcLength(ring, lengths, target))\n }\n return out\n}\n\n/** Exterior edges as segments. */\nexport function segmentsOnExterior(p: Path): Segment[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 2) return []\n const n = ring.length\n const closed = p.closed\n const edges = closed ? n : n - 1\n const out: Segment[] = []\n for (let i = 0; i < edges; i++) {\n out.push(segment(ring[i]!, ring[(i + 1) % n]!))\n }\n return out\n}\n\n/**\n * Cut `p` with the infinite line through `a`→`b`.\n * Returns pieces on both sides (typically 0–2 paths).\n */\nexport function slice(p: Path, a: Vec2, b: Vec2): Group {\n const dx = b.x - a.x\n const dy = b.y - a.y\n const len = Math.hypot(dx, dy)\n if (len < 1e-12) return group([p])\n const nx = -dy / len\n const ny = dx / len\n const bb = bounds(p)\n const span =\n Math.hypot(bb.maxX - bb.minX, bb.maxY - bb.minY) * 4 + 10\n const left = halfPlanePoly(a, nx, ny, span)\n const right = halfPlanePoly(a, -nx, -ny, span)\n const parts: Path[] = []\n for (const half of [left, right]) {\n parts.push(...intersect(p, half).paths)\n }\n return group(parts)\n}\n\n/** Split through the centroid with a vertical cut (left/right). */\nexport function centroidSplit(p: Path): Group {\n const c = centroid(p)\n const bb = bounds(p)\n const pad = Math.max(bb.maxY - bb.minY, 1) + 1\n return slice(p, { x: c.x, y: c.y - pad }, { x: c.x, y: c.y + pad })\n}\n\n/** Union all closed paths in a group (dissolve overlapping contours). */\nexport function dissolve(paths: Path[]): Group {\n return unionAll(paths)\n}\n\n/** Vertex–edge intersection points between two path boundaries. */\nexport function intersectionPoints(a: Path, b: Path): Vec2[] {\n const segsA = allSegments(a)\n const segsB = allSegments(b)\n const out: Vec2[] = []\n const seen = new Set<string>()\n for (const sa of segsA) {\n for (const sb of segsB) {\n const hit = segmentIntersection(sa.a, sa.b, sb.a, sb.b)\n if (!hit) continue\n const key = `${hit.x.toFixed(9)},${hit.y.toFixed(9)}`\n if (seen.has(key)) continue\n seen.add(key)\n out.push(hit)\n }\n }\n return out\n}\n\nfunction halfPlanePoly(\n origin: Vec2,\n nx: number,\n ny: number,\n span: number,\n): Path {\n // Orthonormal tangent\n const tx = -ny\n const ty = nx\n const o = origin\n return polygon([\n {\n x: o.x - tx * span + nx * 1e-9,\n y: o.y - ty * span + ny * 1e-9,\n },\n {\n x: o.x + tx * span + nx * 1e-9,\n y: o.y + ty * span + ny * 1e-9,\n },\n {\n x: o.x + tx * span + nx * span,\n y: o.y + ty * span + ny * span,\n },\n {\n x: o.x - tx * span + nx * span,\n y: o.y - ty * span + ny * span,\n },\n ])\n}\n\nfunction allSegments(p: Path): Segment[] {\n const out: Segment[] = []\n for (const ring of p.rings) {\n const n = ring.length\n const edges = p.closed ? n : Math.max(0, n - 1)\n for (let i = 0; i < edges; i++) {\n out.push(segment(ring[i]!, ring[(i + 1) % n]!))\n }\n }\n return out\n}\n\nfunction segmentIntersection(\n a: Vec2,\n b: Vec2,\n c: Vec2,\n d: Vec2,\n): Vec2 | null {\n const rX = b.x - a.x\n const rY = b.y - a.y\n const sX = d.x - c.x\n const sY = d.y - c.y\n const den = rX * sY - rY * sX\n if (Math.abs(den) < 1e-14) return null\n const t = ((c.x - a.x) * sY - (c.y - a.y) * sX) / den\n const u = ((c.x - a.x) * rY - (c.y - a.y) * rX) / den\n if (t < -1e-9 || t > 1 + 1e-9 || u < -1e-9 || u > 1 + 1e-9) return null\n return { x: a.x + t * rX, y: a.y + t * rY }\n}\n\nfunction edgeLengths(ring: Vec2[], closed: boolean): number[] {\n const n = ring.length\n const edges = closed ? n : n - 1\n const lengths: number[] = []\n for (let i = 0; i < edges; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n lengths.push(Math.hypot(b.x - a.x, b.y - a.y))\n }\n return lengths\n}\n\nfunction pointAtArcLength(\n ring: Vec2[],\n lengths: number[],\n target: number,\n): Vec2 {\n let remain = target\n const n = ring.length\n for (let i = 0; i < lengths.length; i++) {\n const L = lengths[i]!\n if (remain <= L || i === lengths.length - 1) {\n const t = L < 1e-12 ? 0 : remain / L\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n return {\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n }\n }\n remain -= L\n }\n return { ...ring[0]! }\n}\n\nfunction shoelace(ring: Vec2[]): number {\n let sum = 0\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n sum += a.x * b.y - b.x * a.y\n }\n return sum / 2\n}\n\nfunction mulberry32(a: number): () => number {\n return function () {\n let t = (a += 0x6d2b79f5)\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nexport const processing = {\n extractPerimeter,\n extractBoundary,\n extractHoles,\n densify,\n removeSmallHoles,\n generateRandomPoints,\n generateRandomGridPoints,\n pointsOnExterior,\n segmentsOnExterior,\n slice,\n centroidSplit,\n dissolve,\n intersectionPoints,\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { group, polygon } from '../types/index.js'\nimport { bounds } from '../predicates/index.js'\nimport { createRect } from '../construction/index.js'\nimport { intersect } from '../shapeBoolean/index.js'\nimport { slice } from '../processing/index.js'\n\n/** Axis-aligned square cells covering a box. */\nexport function squareGrid(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Group {\n const s = Math.max(spacing, 1e-9)\n const paths: Path[] = []\n for (let x = minX; x < maxX - 1e-12; x += s) {\n for (let y = minY; y < maxY - 1e-12; y += s) {\n const w = Math.min(s, maxX - x)\n const h = Math.min(s, maxY - y)\n if (w > 1e-12 && h > 1e-12) paths.push(createRect(x, y, w, h))\n }\n }\n return group(paths)\n}\n\n/** Pointy-top hex cells covering a box (flat radii ≈ spacing/2). */\nexport function hexTiling(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Group {\n const s = Math.max(spacing, 1e-9)\n const r = s / 2\n const dx = s * 0.75\n const dy = s * Math.sqrt(3) * 0.5\n const paths: Path[] = []\n let row = 0\n for (let y = minY + r; y <= maxY + r; y += dy, row++) {\n const x0 = minX + r + (row % 2 === 0 ? 0 : dx * 0.5)\n for (let x = x0; x <= maxX + r; x += dx) {\n paths.push(hexagon(x, y, r))\n }\n }\n return group(paths)\n}\n\nfunction hexagon(cx: number, cy: number, r: number): Path {\n const ring: Vec2[] = []\n for (let i = 0; i < 6; i++) {\n const t = (Math.PI / 180) * (60 * i - 30)\n ring.push({ x: cx + Math.cos(t) * r, y: cy + Math.sin(t) * r })\n }\n return polygon(ring)\n}\n\n/** Split a rectangle into an `nx` × `ny` grid of cells. */\nexport function rectSubdivision(p: Path, nx: number, ny: number): Group {\n const b = bounds(p)\n const cols = Math.max(1, Math.floor(nx))\n const rows = Math.max(1, Math.floor(ny))\n const dw = (b.maxX - b.minX) / cols\n const dh = (b.maxY - b.minY) / rows\n const paths: Path[] = []\n for (let i = 0; i < cols; i++) {\n for (let j = 0; j < rows; j++) {\n const cell = createRect(\n b.minX + i * dw,\n b.minY + j * dh,\n dw,\n dh,\n )\n paths.push(...intersect(p, cell).paths)\n }\n }\n return group(paths)\n}\n\n/** Recursively split each quad face into 4 by edge midpoints (`depth` times). */\nexport function quadSubdivision(faces: Path[], depth = 1): Group {\n let cur = faces\n const d = Math.max(0, Math.floor(depth))\n for (let i = 0; i < d; i++) {\n const next: Path[] = []\n for (const f of cur) {\n next.push(...subdivideQuad(f))\n }\n cur = next\n }\n return group(cur)\n}\n\nfunction subdivideQuad(p: Path): Path[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 4) return [p]\n const [a, b, c, d] = ring\n if (!a || !b || !c || !d) return [p]\n const mab = mid(a, b)\n const mbc = mid(b, c)\n const mcd = mid(c, d)\n const mda = mid(d, a)\n const cen = mid(mid(a, c), mid(b, d))\n return [\n polygon([a, mab, cen, mda]),\n polygon([mab, b, mbc, cen]),\n polygon([cen, mbc, c, mcd]),\n polygon([mda, cen, mcd, d]),\n ]\n}\n\n/** Split each triangle into 4 by edge midpoints. */\nexport function triangleSubdivision(faces: Path[], depth = 1): Group {\n let cur = faces\n const d = Math.max(0, Math.floor(depth))\n for (let i = 0; i < d; i++) {\n const next: Path[] = []\n for (const f of cur) {\n next.push(...subdivideTriangle(f))\n }\n cur = next\n }\n return group(cur)\n}\n\nfunction subdivideTriangle(p: Path): Path[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 3) return [p]\n const a = ring[0]!\n const b = ring[1]!\n const c = ring[2]!\n const mab = mid(a, b)\n const mbc = mid(b, c)\n const mca = mid(c, a)\n return [\n polygon([a, mab, mca]),\n polygon([mab, b, mbc]),\n polygon([mca, mbc, c]),\n polygon([mab, mbc, mca]),\n ]\n}\n\n/**\n * Slice a path into strips with parallel cuts spaced by `spacing`.\n * Angle in radians (0 = vertical cuts).\n */\nexport function sliceDivision(\n p: Path,\n spacing: number,\n angle = 0,\n): Group {\n const s = Math.max(spacing, 1e-9)\n const b = bounds(p)\n const cx = (b.minX + b.maxX) / 2\n const cy = (b.minY + b.maxY) / 2\n const diag = Math.hypot(b.maxX - b.minX, b.maxY - b.minY) + s\n const ux = Math.cos(angle)\n const uy = Math.sin(angle)\n // normal for cut lines\n const nx = -uy\n const ny = ux\n const parts: Path[] = [p]\n for (let t = -diag; t <= diag; t += s) {\n const a = { x: cx + nx * t - ux * diag, y: cy + ny * t - uy * diag }\n const bb = { x: cx + nx * t + ux * diag, y: cy + ny * t + uy * diag }\n const next: Path[] = []\n for (const piece of parts) {\n const g = slice(piece, a, bb)\n next.push(...(g.paths.length ? g.paths : [piece]))\n }\n parts.length = 0\n parts.push(...next)\n }\n return group(parts)\n}\n\n/** Parallel hatch-like strip division (alias of sliceDivision). */\nexport function hatchSubdivision(\n p: Path,\n spacing: number,\n angle = 0,\n): Group {\n return sliceDivision(p, spacing, angle)\n}\n\nfunction mid(a: Vec2, b: Vec2): Vec2 {\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 }\n}\n\nexport const tiling = {\n squareGrid,\n hexTiling,\n rectSubdivision,\n quadSubdivision,\n triangleSubdivision,\n sliceDivision,\n hatchSubdivision,\n}\n"]}
1
+ {"version":3,"sources":["../../src/types/vec2.ts","../../src/types/path.ts","../../src/types/group.ts","../../src/clipper/convert.ts","../../src/predicates/index.ts","../../src/shapeBoolean/index.ts","../../src/construction/index.ts","../../src/processing/index.ts","../../src/tiling/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** 2D point / vector. */\nexport type Vec2 = {\n x: number\n y: number\n}\n\nexport function vec2(x: number, y: number): Vec2 {\n return { x, y }\n}\n\nexport function cloneVec2(v: Vec2): Vec2 {\n return { x: v.x, y: v.y }\n}\n\nexport function equalsVec2(a: Vec2, b: Vec2, eps = 1e-9): boolean {\n return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps\n}\n","import type { Vec2 } from './vec2.js'\nimport { cloneVec2, equalsVec2 } from './vec2.js'\n\n/** Ordered ring of vertices (typically without repeating the closing vertex). */\nexport type Ring = Vec2[]\n\n/**\n * A path: one exterior ring plus optional holes, or an open polyline.\n * `rings[0]` is the exterior (or the open polyline when `closed` is false).\n * Additional rings are holes (only meaningful when `closed` is true).\n */\nexport type Path = {\n rings: Ring[]\n closed: boolean\n}\n\nexport function path(rings: Ring[], closed = true): Path {\n return {\n rings: rings.map((ring) => ring.map(cloneVec2)),\n closed,\n }\n}\n\nexport function polyline(points: Ring): Path {\n return path([points], false)\n}\n\nexport function polygon(exterior: Ring, holes: Ring[] = []): Path {\n return path([exterior, ...holes], true)\n}\n\n/** Drop a trailing vertex that duplicates the first (SVG often closes this way). */\nexport function normalizeRing(ring: Ring, eps = 1e-9): Ring {\n if (ring.length < 2) return ring.map(cloneVec2)\n const first = ring[0]\n const last = ring[ring.length - 1]\n if (first && last && equalsVec2(first, last, eps)) {\n return ring.slice(0, -1).map(cloneVec2)\n }\n return ring.map(cloneVec2)\n}\n\nexport function clonePath(p: Path): Path {\n return {\n closed: p.closed,\n rings: p.rings.map((ring) => ring.map(cloneVec2)),\n }\n}\n","import type { Path } from './path.js'\nimport { clonePath } from './path.js'\n\n/**\n * Ordered collection of paths. Later entries are “on top” for occlusion-style ops.\n */\nexport type Group = {\n paths: Path[]\n}\n\nexport function group(paths: Path[] = []): Group {\n return { paths: paths.map(clonePath) }\n}\n\nexport function groupFromPaths(...paths: Path[]): Group {\n return group(paths)\n}\n\nexport function cloneGroup(g: Group): Group {\n return group(g.paths)\n}\n","import {\n FillRule,\n areaD,\n differenceD,\n intersectD,\n isPositiveD,\n pointInPolygonD,\n PointInPolygonResult,\n unionD,\n xorD,\n type PathD,\n type PathsD,\n type PointD,\n} from 'clipper2-ts'\nimport type { Group, Path, Ring, Vec2 } from '../types/index.js'\nimport { group, normalizeRing, path, vec2 } from '../types/index.js'\n\nexport const DEFAULT_FILL_RULE = FillRule.NonZero\n\nexport function ringToPathD(ring: Ring): PathD {\n const pts: PointD[] = []\n for (const v of normalizeRing(ring)) {\n pts.push({ x: v.x, y: v.y, z: 0 })\n }\n return pts\n}\n\n/** Closed path → Clipper subject/clip paths (exterior + holes). */\nexport function pathToPathsD(p: Path): PathsD {\n if (!p.closed || p.rings.length === 0) {\n throw new Error('Boolean ops require a closed path with at least one ring')\n }\n return p.rings.map((ring) => ringToPathD(ring))\n}\n\nexport function pathsDToGroup(paths: PathsD): Group {\n if (paths.length === 0) return group([])\n\n const outers: { ring: Ring; holes: Ring[] }[] = []\n const holes: Ring[] = []\n\n for (const pd of paths) {\n const ring = pathDToRing(pd)\n if (ring.length < 3) continue\n if (isPositiveD(pd)) {\n outers.push({ ring, holes: [] })\n } else {\n holes.push(ring)\n }\n }\n\n for (const hole of holes) {\n const sample = hole[0]\n if (!sample) continue\n let assigned = false\n for (const outer of outers) {\n if (pointInRing(sample, outer.ring)) {\n outer.holes.push(hole)\n assigned = true\n break\n }\n }\n if (!assigned) {\n // Treat unmatched negative rings as their own outers (orientation flip).\n outers.push({ ring: [...hole].reverse(), holes: [] })\n }\n }\n\n return group(outers.map((o) => path([o.ring, ...o.holes], true)))\n}\n\nexport function pathDToRing(pd: PathD): Ring {\n return normalizeRing(pd.map((p) => vec2(p.x, p.y)))\n}\n\nexport function pointInRing(point: Vec2, ring: Ring): boolean {\n const result = pointInPolygonD(\n { x: point.x, y: point.y, z: 0 },\n ringToPathD(ring),\n )\n return (\n result === PointInPolygonResult.IsInside ||\n result === PointInPolygonResult.IsOn\n )\n}\n\nexport function clipUnion(a: PathsD, b: PathsD): PathsD {\n return unionD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipIntersect(a: PathsD, b: PathsD): PathsD {\n return intersectD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipDifference(a: PathsD, b: PathsD): PathsD {\n return differenceD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipXor(a: PathsD, b: PathsD): PathsD {\n return xorD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function pathsArea(paths: PathsD): number {\n let sum = 0\n for (const p of paths) {\n sum += Math.abs(areaD(p))\n }\n return sum\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { vec2 } from '../types/index.js'\nimport {\n pathToPathsD,\n pathsArea,\n pointInRing,\n} from '../clipper/convert.js'\n\n/** Signed area of a closed ring (shoelace). */\nexport function ringArea(ring: Vec2[]): number {\n if (ring.length < 3) return 0\n let sum = 0\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n sum += a.x * b.y - b.x * a.y\n }\n return sum / 2\n}\n\n/** Absolute area of a closed path (exterior minus holes). */\nexport function area(p: Path): number {\n if (!p.closed || p.rings.length === 0) return 0\n try {\n return pathsArea(pathToPathsD(p))\n } catch {\n let total = 0\n for (let i = 0; i < p.rings.length; i++) {\n const a = Math.abs(ringArea(p.rings[i]!))\n total += i === 0 ? a : -a\n }\n return Math.max(0, total)\n }\n}\n\nexport function areaGroup(g: Group): number {\n return g.paths.reduce((sum, p) => sum + area(p), 0)\n}\n\n/** Centroid of a closed exterior ring (ignores holes for Phase 2). */\nexport function centroid(p: Path): Vec2 {\n const ring = p.rings[0]\n if (!ring || ring.length === 0) return vec2(0, 0)\n const a = ringArea(ring)\n if (Math.abs(a) < 1e-12) {\n let sx = 0\n let sy = 0\n for (const v of ring) {\n sx += v.x\n sy += v.y\n }\n return vec2(sx / ring.length, sy / ring.length)\n }\n let cx = 0\n let cy = 0\n for (let i = 0; i < ring.length; i++) {\n const p0 = ring[i]!\n const p1 = ring[(i + 1) % ring.length]!\n const cross = p0.x * p1.y - p1.x * p0.y\n cx += (p0.x + p1.x) * cross\n cy += (p0.y + p1.y) * cross\n }\n return vec2(cx / (6 * a), cy / (6 * a))\n}\n\nexport function containsPoint(p: Path, point: Vec2): boolean {\n if (!p.closed || !p.rings[0]) return false\n if (!pointInRing(point, p.rings[0])) return false\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && pointInRing(point, hole)) return false\n }\n return true\n}\n\nexport function bounds(p: Path): {\n minX: number\n minY: number\n maxX: number\n maxY: number\n} {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const ring of p.rings) {\n for (const v of ring) {\n minX = Math.min(minX, v.x)\n minY = Math.min(minY, v.y)\n maxX = Math.max(maxX, v.x)\n maxY = Math.max(maxY, v.y)\n }\n }\n if (!Number.isFinite(minX)) {\n return { minX: 0, minY: 0, maxX: 0, maxY: 0 }\n }\n return { minX, minY, maxX, maxY }\n}\n\nexport function width(p: Path): number {\n const b = bounds(p)\n return b.maxX - b.minX\n}\n\nexport function height(p: Path): number {\n const b = bounds(p)\n return b.maxY - b.minY\n}\n\n/** Rough polygon similarity via absolute area difference relative to max area. */\nexport function areaSimilarity(a: Path, b: Path): number {\n const aa = area(a)\n const bb = area(b)\n const denom = Math.max(aa, bb, 1e-12)\n return 1 - Math.abs(aa - bb) / denom\n}\n\nexport const predicates = {\n area,\n areaGroup,\n ringArea,\n centroid,\n containsPoint,\n bounds,\n width,\n height,\n areaSimilarity,\n}\n","import type { Group, Path } from '../types/index.js'\nimport { group, groupFromPaths, path, polygon, vec2 } from '../types/index.js'\nimport {\n clipDifference,\n clipIntersect,\n clipUnion,\n clipXor,\n pathToPathsD,\n pathsDToGroup,\n} from '../clipper/convert.js'\n\nfunction ensureClosed(p: Path): Path {\n if (!p.closed) {\n throw new Error('shapeBoolean requires closed paths')\n }\n return p\n}\n\n/** Union of two closed paths. */\nexport function union(a: Path, b: Path): Group {\n const result = clipUnion(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Union of many closed paths (folded left-to-right). */\nexport function unionAll(paths: Path[]): Group {\n if (paths.length === 0) return group([])\n let acc = pathToPathsD(ensureClosed(paths[0]!))\n for (let i = 1; i < paths.length; i++) {\n acc = clipUnion(acc, pathToPathsD(ensureClosed(paths[i]!)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Intersection of two closed paths. */\nexport function intersect(a: Path, b: Path): Group {\n const result = clipIntersect(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract b from a (a \\ b). */\nexport function subtract(a: Path, b: Path): Group {\n const result = clipDifference(\n pathToPathsD(ensureClosed(a)),\n pathToPathsD(ensureClosed(b)),\n )\n return pathsDToGroup(result)\n}\n\n/** Subtract many shapes from a base. */\nexport function subtractAll(base: Path, shapes: Path[]): Group {\n let acc = pathToPathsD(ensureClosed(base))\n for (const s of shapes) {\n acc = clipDifference(acc, pathToPathsD(ensureClosed(s)))\n }\n return pathsDToGroup(acc)\n}\n\n/** Symmetric difference. */\nexport function symDifference(a: Path, b: Path): Group {\n const result = clipXor(pathToPathsD(ensureClosed(a)), pathToPathsD(ensureClosed(b)))\n return pathsDToGroup(result)\n}\n\n/** Complement of shape within axis-aligned rectangle [0,width] x [0,height]. */\nexport function complement(shape: Path, width: number, height: number): Group {\n const frame = polygon([\n vec2(0, 0),\n vec2(width, 0),\n vec2(width, height),\n vec2(0, height),\n ])\n return subtract(frame, shape)\n}\n\n/**\n * Painter-style occlusion: later paths in the group are on top.\n * Each path has higher paths subtracted from it; returns visible remainders.\n */\nexport function occlusionSubtract(g: Group): Group {\n const paths = g.paths\n const visible: Path[] = []\n for (let i = 0; i < paths.length; i++) {\n const subject = paths[i]\n if (!subject) continue\n const occluders = paths.slice(i + 1)\n const piece =\n occluders.length === 0\n ? groupFromPaths(ensureClosed(subject))\n : subtractAll(subject, occluders)\n for (const p of piece.paths) {\n visible.push(p)\n }\n }\n return group(visible)\n}\n\n/**\n * Regions covered by at least two input shapes.\n * If `merged`, collapse multi-overlaps into disjoint patches via union of pairwise intersects.\n */\nexport function overlapRegions(shapes: Path[], merged: boolean): Group {\n if (shapes.length < 2) return group([])\n const pairs: Path[] = []\n for (let i = 0; i < shapes.length; i++) {\n for (let j = i + 1; j < shapes.length; j++) {\n const a = shapes[i]\n const b = shapes[j]\n if (!a || !b) continue\n for (const p of intersect(a, b).paths) {\n pairs.push(p)\n }\n }\n }\n if (!merged) return group(pairs)\n return unionAll(pairs)\n}\n\nexport const shapeBoolean = {\n union,\n unionAll,\n intersect,\n subtract,\n subtractAll,\n symDifference,\n complement,\n occlusionSubtract,\n overlapRegions,\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { group, path, polygon, polyline } from '../types/index.js'\nimport { compoundVoronoi } from '../voronoi/index.js'\nimport { stochasticMerge } from '../meshing/index.js'\nimport { buffer, smooth } from '../morphology/index.js'\nimport { subtractAll } from '../shapeBoolean/index.js'\n\n/** Regular n-gon approximating a circle. */\nexport function createCircle(\n cx: number,\n cy: number,\n radius: number,\n segments = 64,\n): Path {\n return createRegularPolygon(cx, cy, radius, Math.max(3, Math.floor(segments)))\n}\n\nexport function createRect(\n x: number,\n y: number,\n width: number,\n height: number,\n): Path {\n return polygon([\n { x, y },\n { x: x + width, y },\n { x: x + width, y: y + height },\n { x, y: y + height },\n ])\n}\n\nexport function createRegularPolygon(\n cx: number,\n cy: number,\n radius: number,\n sides: number,\n rotation = -Math.PI / 2,\n): Path {\n const n = Math.max(3, Math.floor(sides))\n const ring: Vec2[] = []\n for (let i = 0; i < n; i++) {\n const t = rotation + (i / n) * Math.PI * 2\n ring.push({ x: cx + Math.cos(t) * radius, y: cy + Math.sin(t) * radius })\n }\n return polygon(ring)\n}\n\n/** Annulus as exterior + hole. */\nexport function createRing(\n cx: number,\n cy: number,\n outerRadius: number,\n innerRadius: number,\n segments = 64,\n): Path {\n const outer = createCircle(cx, cy, outerRadius, segments).rings[0]!\n const inner = createCircle(cx, cy, Math.min(innerRadius, outerRadius), segments)\n .rings[0]!\n // hole winding opposite for Clipper\n return path([outer, [...inner].reverse()], true)\n}\n\n/** Open circular arc polyline from `startAngle` to `endAngle` (radians). */\nexport function createArc(\n cx: number,\n cy: number,\n radius: number,\n startAngle: number,\n endAngle: number,\n segments = 32,\n): Path {\n const n = Math.max(2, Math.floor(segments))\n const pts: Vec2[] = []\n for (let i = 0; i <= n; i++) {\n const t = startAngle + ((endAngle - startAngle) * i) / n\n pts.push({ x: cx + Math.cos(t) * radius, y: cy + Math.sin(t) * radius })\n }\n return polyline(pts)\n}\n\n/** Star polygon (outer/inner radius alternating). */\nexport function createStar(\n cx: number,\n cy: number,\n outerRadius: number,\n innerRadius: number,\n points = 5,\n rotation = -Math.PI / 2,\n): Path {\n const n = Math.max(3, Math.floor(points))\n const ring: Vec2[] = []\n for (let i = 0; i < n * 2; i++) {\n const r = i % 2 === 0 ? outerRadius : innerRadius\n const t = rotation + (i / (n * 2)) * Math.PI * 2\n ring.push({ x: cx + Math.cos(t) * r, y: cy + Math.sin(t) * r })\n }\n return polygon(ring)\n}\n\n/** Koch snowflake after `iterations` refinement (0 = equilateral triangle). */\nexport function createKochSnowflake(\n cx: number,\n cy: number,\n radius: number,\n iterations = 3,\n): Path {\n const tri = createRegularPolygon(cx, cy, radius, 3)\n let ring = tri.rings[0]!\n const iters = Math.max(0, Math.min(6, Math.floor(iterations)))\n for (let i = 0; i < iters; i++) {\n ring = kochRefine(ring)\n }\n return polygon(ring)\n}\n\n/**\n * Sponge-like porous structure (PGS `createSponge`).\n * Voronoi cells are randomly class-merged, smoothed (Chaikin), optionally\n * eroded for wall thickness, then subtracted from the bounding rectangle.\n * Returns a group (may be multi-component).\n */\nexport function createSponge(\n width: number,\n height: number,\n generators: number,\n thickness: number,\n smoothing: number,\n classes: number,\n seed = 1,\n): Group {\n const w = Math.max(width, 1e-9)\n const h = Math.max(height, 1e-9)\n const nGen = Math.max(6, Math.floor(generators))\n const nClasses = Math.max(1, Math.floor(classes))\n const smoothIters = Math.max(0, Math.floor(smoothing))\n const wall = Math.max(0, thickness)\n\n const sites = randomInBox(nGen, 0, 0, w, h, seed)\n const cells = compoundVoronoi(sites, {\n bounds: { minX: 0, minY: 0, maxX: w, maxY: h },\n })\n const merged = stochasticMerge(cells.paths, nClasses, seed + 1)\n\n const pores: Path[] = []\n for (let p of merged.paths) {\n if (smoothIters > 0) p = smooth(p, smoothIters)\n if (wall > 1e-12) {\n // Erode pore blobs so remaining walls are thicker\n pores.push(...buffer(p, -wall * 0.5).paths)\n } else {\n pores.push(p)\n }\n }\n\n const frame = createRect(0, 0, w, h)\n if (pores.length === 0) return group([frame])\n return subtractAll(frame, pores)\n}\n\nfunction randomInBox(\n count: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n seed: number,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n out.push({\n x: minX + rng() * (maxX - minX),\n y: minY + rng() * (maxY - minY),\n })\n }\n return out\n}\n\nfunction mulberry32(a: number): () => number {\n return function () {\n let t = (a += 0x6d2b79f5)\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nfunction kochRefine(ring: Vec2[]): Vec2[] {\n const out: Vec2[] = []\n const n = ring.length\n for (let i = 0; i < n; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n const dx = b.x - a.x\n const dy = b.y - a.y\n const p1 = { x: a.x + dx / 3, y: a.y + dy / 3 }\n const p2 = { x: a.x + (2 * dx) / 3, y: a.y + (2 * dy) / 3 }\n // outward peak (left of directed edge in Y-down SVG coords = rotate +90 for CCW tri)\n const px = a.x + dx / 2 - dy * (Math.sqrt(3) / 6)\n const py = a.y + dy / 2 + dx * (Math.sqrt(3) / 6)\n out.push(a, p1, { x: px, y: py }, p2)\n }\n return out\n}\n\nexport const construction = {\n createCircle,\n createRect,\n createRegularPolygon,\n createRing,\n createArc,\n createStar,\n createKochSnowflake,\n createSponge,\n}\n","import type { Group, Path, Segment, Vec2 } from '../types/index.js'\nimport { path, normalizeRing, polygon, segment, group } from '../types/index.js'\nimport { bounds, containsPoint, centroid } from '../predicates/index.js'\nimport { intersect, unionAll } from '../shapeBoolean/index.js'\n\n/** Exterior ring as its own closed path (holes dropped). */\nexport function extractPerimeter(p: Path): Path {\n const exterior = p.rings[0]\n if (!exterior) return path([], true)\n return polygon(exterior)\n}\n\n/** Alias for extractPerimeter. */\nexport function extractBoundary(p: Path): Path {\n return extractPerimeter(p)\n}\n\n/** Each hole as a separate closed path. */\nexport function extractHoles(p: Path): Path[] {\n const holes: Path[] = []\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && hole.length >= 3) holes.push(polygon(hole))\n }\n return holes\n}\n\n/**\n * Insert vertices so no edge exceeds `maxSegLen`.\n * Closed rings treat the wrap-around edge.\n */\nexport function densify(p: Path, maxSegLen: number): Path {\n if (maxSegLen <= 0) return p\n return path(\n p.rings.map((ring) => densifyRing(ring, maxSegLen, p.closed)),\n p.closed,\n )\n}\n\nfunction densifyRing(\n ring: Vec2[],\n maxSegLen: number,\n closed: boolean,\n): Vec2[] {\n if (ring.length < 2) return [...ring]\n const out: Vec2[] = []\n const n = ring.length\n const edges = closed ? n : n - 1\n for (let i = 0; i < edges; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n out.push(a)\n const dist = Math.hypot(b.x - a.x, b.y - a.y)\n const steps = Math.floor(dist / maxSegLen)\n for (let s = 1; s < steps; s++) {\n const t = s / steps\n out.push({\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n })\n }\n }\n if (!closed) out.push(ring[n - 1]!)\n return closed ? normalizeRing(out) : out\n}\n\n/** Drop holes whose absolute area is below `minArea`. */\nexport function removeSmallHoles(p: Path, minArea: number): Path {\n if (p.rings.length <= 1) return p\n const exterior = p.rings[0]!\n const kept = p.rings.slice(1).filter((hole) => {\n const a = Math.abs(shoelace(hole))\n return a >= minArea\n })\n return path([exterior, ...kept], p.closed)\n}\n\n/** Seeded uniform random points inside a closed path. */\nexport function generateRandomPoints(\n p: Path,\n count: number,\n seed = 1,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const b = bounds(p)\n const out: Vec2[] = []\n let attempts = 0\n const maxAttempts = Math.max(count * 50, 100)\n while (out.length < count && attempts < maxAttempts) {\n attempts++\n const pt = {\n x: b.minX + rng() * (b.maxX - b.minX),\n y: b.minY + rng() * (b.maxY - b.minY),\n }\n if (containsPoint(p, pt)) out.push(pt)\n }\n return out\n}\n\n/** Axis-aligned grid samples that fall inside the path. */\nexport function generateRandomGridPoints(\n p: Path,\n spacing: number,\n): Vec2[] {\n const step = Math.max(spacing, 1e-9)\n const b = bounds(p)\n const out: Vec2[] = []\n for (let x = b.minX; x <= b.maxX + 1e-12; x += step) {\n for (let y = b.minY; y <= b.maxY + 1e-12; y += step) {\n const pt = { x, y }\n if (containsPoint(p, pt)) out.push(pt)\n }\n }\n return out\n}\n\n/** Evenly spaced samples along the exterior perimeter. */\nexport function pointsOnExterior(p: Path, count: number): Vec2[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 2 || count <= 0) return []\n const lengths = edgeLengths(ring, true)\n const total = lengths.reduce((s, L) => s + L, 0)\n if (total < 1e-12) return []\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n const target = (i / count) * total\n out.push(pointAtArcLength(ring, lengths, target))\n }\n return out\n}\n\n/** Exterior edges as segments. */\nexport function segmentsOnExterior(p: Path): Segment[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 2) return []\n const n = ring.length\n const closed = p.closed\n const edges = closed ? n : n - 1\n const out: Segment[] = []\n for (let i = 0; i < edges; i++) {\n out.push(segment(ring[i]!, ring[(i + 1) % n]!))\n }\n return out\n}\n\n/**\n * Cut `p` with the infinite line through `a`→`b`.\n * Returns pieces on both sides (typically 0–2 paths).\n */\nexport function slice(p: Path, a: Vec2, b: Vec2): Group {\n const dx = b.x - a.x\n const dy = b.y - a.y\n const len = Math.hypot(dx, dy)\n if (len < 1e-12) return group([p])\n const nx = -dy / len\n const ny = dx / len\n const bb = bounds(p)\n const span =\n Math.hypot(bb.maxX - bb.minX, bb.maxY - bb.minY) * 4 + 10\n const left = halfPlanePoly(a, nx, ny, span)\n const right = halfPlanePoly(a, -nx, -ny, span)\n const parts: Path[] = []\n for (const half of [left, right]) {\n parts.push(...intersect(p, half).paths)\n }\n return group(parts)\n}\n\n/** Split through the centroid with a vertical cut (left/right). */\nexport function centroidSplit(p: Path): Group {\n const c = centroid(p)\n const bb = bounds(p)\n const pad = Math.max(bb.maxY - bb.minY, 1) + 1\n return slice(p, { x: c.x, y: c.y - pad }, { x: c.x, y: c.y + pad })\n}\n\n/** Union all closed paths in a group (dissolve overlapping contours). */\nexport function dissolve(paths: Path[]): Group {\n return unionAll(paths)\n}\n\n/** Vertex–edge intersection points between two path boundaries. */\nexport function intersectionPoints(a: Path, b: Path): Vec2[] {\n const segsA = allSegments(a)\n const segsB = allSegments(b)\n const out: Vec2[] = []\n const seen = new Set<string>()\n for (const sa of segsA) {\n for (const sb of segsB) {\n const hit = segmentIntersection(sa.a, sa.b, sb.a, sb.b)\n if (!hit) continue\n const key = `${hit.x.toFixed(9)},${hit.y.toFixed(9)}`\n if (seen.has(key)) continue\n seen.add(key)\n out.push(hit)\n }\n }\n return out\n}\n\nfunction halfPlanePoly(\n origin: Vec2,\n nx: number,\n ny: number,\n span: number,\n): Path {\n // Orthonormal tangent\n const tx = -ny\n const ty = nx\n const o = origin\n return polygon([\n {\n x: o.x - tx * span + nx * 1e-9,\n y: o.y - ty * span + ny * 1e-9,\n },\n {\n x: o.x + tx * span + nx * 1e-9,\n y: o.y + ty * span + ny * 1e-9,\n },\n {\n x: o.x + tx * span + nx * span,\n y: o.y + ty * span + ny * span,\n },\n {\n x: o.x - tx * span + nx * span,\n y: o.y - ty * span + ny * span,\n },\n ])\n}\n\nfunction allSegments(p: Path): Segment[] {\n const out: Segment[] = []\n for (const ring of p.rings) {\n const n = ring.length\n const edges = p.closed ? n : Math.max(0, n - 1)\n for (let i = 0; i < edges; i++) {\n out.push(segment(ring[i]!, ring[(i + 1) % n]!))\n }\n }\n return out\n}\n\nfunction segmentIntersection(\n a: Vec2,\n b: Vec2,\n c: Vec2,\n d: Vec2,\n): Vec2 | null {\n const rX = b.x - a.x\n const rY = b.y - a.y\n const sX = d.x - c.x\n const sY = d.y - c.y\n const den = rX * sY - rY * sX\n if (Math.abs(den) < 1e-14) return null\n const t = ((c.x - a.x) * sY - (c.y - a.y) * sX) / den\n const u = ((c.x - a.x) * rY - (c.y - a.y) * rX) / den\n if (t < -1e-9 || t > 1 + 1e-9 || u < -1e-9 || u > 1 + 1e-9) return null\n return { x: a.x + t * rX, y: a.y + t * rY }\n}\n\nfunction edgeLengths(ring: Vec2[], closed: boolean): number[] {\n const n = ring.length\n const edges = closed ? n : n - 1\n const lengths: number[] = []\n for (let i = 0; i < edges; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n lengths.push(Math.hypot(b.x - a.x, b.y - a.y))\n }\n return lengths\n}\n\nfunction pointAtArcLength(\n ring: Vec2[],\n lengths: number[],\n target: number,\n): Vec2 {\n let remain = target\n const n = ring.length\n for (let i = 0; i < lengths.length; i++) {\n const L = lengths[i]!\n if (remain <= L || i === lengths.length - 1) {\n const t = L < 1e-12 ? 0 : remain / L\n const a = ring[i]!\n const b = ring[(i + 1) % n]!\n return {\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n }\n }\n remain -= L\n }\n return { ...ring[0]! }\n}\n\nfunction shoelace(ring: Vec2[]): number {\n let sum = 0\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n sum += a.x * b.y - b.x * a.y\n }\n return sum / 2\n}\n\nfunction mulberry32(a: number): () => number {\n return function () {\n let t = (a += 0x6d2b79f5)\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nexport const processing = {\n extractPerimeter,\n extractBoundary,\n extractHoles,\n densify,\n removeSmallHoles,\n generateRandomPoints,\n generateRandomGridPoints,\n pointsOnExterior,\n segmentsOnExterior,\n slice,\n centroidSplit,\n dissolve,\n intersectionPoints,\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { group, polygon } from '../types/index.js'\nimport { area, bounds } from '../predicates/index.js'\nimport { createCircle, createRect } from '../construction/index.js'\nimport { intersect, subtract } from '../shapeBoolean/index.js'\nimport { slice } from '../processing/index.js'\n\n/** Axis-aligned square cells covering a box. */\nexport function squareGrid(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Group {\n const s = Math.max(spacing, 1e-9)\n const paths: Path[] = []\n for (let x = minX; x < maxX - 1e-12; x += s) {\n for (let y = minY; y < maxY - 1e-12; y += s) {\n const w = Math.min(s, maxX - x)\n const h = Math.min(s, maxY - y)\n if (w > 1e-12 && h > 1e-12) paths.push(createRect(x, y, w, h))\n }\n }\n return group(paths)\n}\n\n/** Pointy-top hex cells covering a box (flat radii ≈ spacing/2). */\nexport function hexTiling(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Group {\n const s = Math.max(spacing, 1e-9)\n const r = s / 2\n const dx = s * 0.75\n const dy = s * Math.sqrt(3) * 0.5\n const paths: Path[] = []\n let row = 0\n for (let y = minY + r; y <= maxY + r; y += dy, row++) {\n const x0 = minX + r + (row % 2 === 0 ? 0 : dx * 0.5)\n for (let x = x0; x <= maxX + r; x += dx) {\n paths.push(hexagon(x, y, r))\n }\n }\n return group(paths)\n}\n\nfunction hexagon(cx: number, cy: number, r: number): Path {\n const ring: Vec2[] = []\n for (let i = 0; i < 6; i++) {\n const t = (Math.PI / 180) * (60 * i - 30)\n ring.push({ x: cx + Math.cos(t) * r, y: cy + Math.sin(t) * r })\n }\n return polygon(ring)\n}\n\n/** Split a rectangle into an `nx` × `ny` grid of cells. */\nexport function rectSubdivision(p: Path, nx: number, ny: number): Group {\n const b = bounds(p)\n const cols = Math.max(1, Math.floor(nx))\n const rows = Math.max(1, Math.floor(ny))\n const dw = (b.maxX - b.minX) / cols\n const dh = (b.maxY - b.minY) / rows\n const paths: Path[] = []\n for (let i = 0; i < cols; i++) {\n for (let j = 0; j < rows; j++) {\n const cell = createRect(\n b.minX + i * dw,\n b.minY + j * dh,\n dw,\n dh,\n )\n paths.push(...intersect(p, cell).paths)\n }\n }\n return group(paths)\n}\n\n/** Recursively split each quad face into 4 by edge midpoints (`depth` times). */\nexport function quadSubdivision(faces: Path[], depth = 1): Group {\n let cur = faces\n const d = Math.max(0, Math.floor(depth))\n for (let i = 0; i < d; i++) {\n const next: Path[] = []\n for (const f of cur) {\n next.push(...subdivideQuad(f))\n }\n cur = next\n }\n return group(cur)\n}\n\nfunction subdivideQuad(p: Path): Path[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 4) return [p]\n const [a, b, c, d] = ring\n if (!a || !b || !c || !d) return [p]\n const mab = mid(a, b)\n const mbc = mid(b, c)\n const mcd = mid(c, d)\n const mda = mid(d, a)\n const cen = mid(mid(a, c), mid(b, d))\n return [\n polygon([a, mab, cen, mda]),\n polygon([mab, b, mbc, cen]),\n polygon([cen, mbc, c, mcd]),\n polygon([mda, cen, mcd, d]),\n ]\n}\n\n/** Split each triangle into 4 by edge midpoints. */\nexport function triangleSubdivision(faces: Path[], depth = 1): Group {\n let cur = faces\n const d = Math.max(0, Math.floor(depth))\n for (let i = 0; i < d; i++) {\n const next: Path[] = []\n for (const f of cur) {\n next.push(...subdivideTriangle(f))\n }\n cur = next\n }\n return group(cur)\n}\n\nfunction subdivideTriangle(p: Path): Path[] {\n const ring = p.rings[0]\n if (!ring || ring.length < 3) return [p]\n const a = ring[0]!\n const b = ring[1]!\n const c = ring[2]!\n const mab = mid(a, b)\n const mbc = mid(b, c)\n const mca = mid(c, a)\n return [\n polygon([a, mab, mca]),\n polygon([mab, b, mbc]),\n polygon([mca, mbc, c]),\n polygon([mab, mbc, mca]),\n ]\n}\n\n/**\n * Slice a path into strips with parallel cuts spaced by `spacing`.\n * Angle in radians (0 = vertical cuts).\n */\nexport function sliceDivision(\n p: Path,\n spacing: number,\n angle = 0,\n): Group {\n const s = Math.max(spacing, 1e-9)\n const b = bounds(p)\n const cx = (b.minX + b.maxX) / 2\n const cy = (b.minY + b.maxY) / 2\n const diag = Math.hypot(b.maxX - b.minX, b.maxY - b.minY) + s\n const ux = Math.cos(angle)\n const uy = Math.sin(angle)\n // normal for cut lines\n const nx = -uy\n const ny = ux\n const parts: Path[] = [p]\n for (let t = -diag; t <= diag; t += s) {\n const a = { x: cx + nx * t - ux * diag, y: cy + ny * t - uy * diag }\n const bb = { x: cx + nx * t + ux * diag, y: cy + ny * t + uy * diag }\n const next: Path[] = []\n for (const piece of parts) {\n const g = slice(piece, a, bb)\n next.push(...(g.paths.length ? g.paths : [piece]))\n }\n parts.length = 0\n parts.push(...next)\n }\n return group(parts)\n}\n\n/** Parallel hatch-like strip division (alias of sliceDivision). */\nexport function hatchSubdivision(\n p: Path,\n spacing: number,\n angle = 0,\n): Group {\n return sliceDivision(p, spacing, angle)\n}\n\n/**\n * Cellular partition of a rectangle using arcs from circles seeded on the\n * boundary (PGS `arcDivision`). Each circle radius is large enough to hit at\n * least two distinct sides.\n */\nexport function arcDivision(\n width: number,\n height: number,\n arcs: number,\n seed = 1,\n circlePoints = 64,\n): Group {\n const w = Math.max(width, 1e-9)\n const h = Math.max(height, 1e-9)\n const n = Math.max(0, Math.floor(arcs))\n const segs = Math.max(8, Math.floor(circlePoints))\n const rect = createRect(0, 0, w, h)\n if (n === 0) return group([rect])\n\n const rng = mulberry32(seed >>> 0)\n let faces: Path[] = [rect]\n const minArea = w * h * 1e-8\n\n for (let i = 0; i < n; i++) {\n const { cx, cy, r } = sampleBoundaryCircle(w, h, rng)\n const disk = createCircle(cx, cy, r, segs)\n const next: Path[] = []\n for (const face of faces) {\n for (const piece of intersect(face, disk).paths) {\n if (area(piece) > minArea) next.push(piece)\n }\n for (const piece of subtract(face, disk).paths) {\n if (area(piece) > minArea) next.push(piece)\n }\n }\n if (next.length > 0) faces = next\n }\n return group(faces)\n}\n\n/** Place a circle center on the AABB perimeter with radius ≥ dist to a second side. */\nfunction sampleBoundaryCircle(\n w: number,\n h: number,\n rng: () => number,\n): { cx: number; cy: number; r: number } {\n const peri = 2 * (w + h)\n let t = rng() * peri\n let cx: number\n let cy: number\n let side: 0 | 1 | 2 | 3\n if (t < w) {\n side = 0 // top y=0\n cx = t\n cy = 0\n } else {\n t -= w\n if (t < h) {\n side = 1 // right x=w\n cx = w\n cy = t\n } else {\n t -= h\n if (t < w) {\n side = 2 // bottom y=h\n cx = w - t\n cy = h\n } else {\n side = 3 // left x=0\n cx = 0\n cy = h - (t - w)\n }\n }\n }\n\n const distOther = [\n cy, // to top\n w - cx, // to right\n h - cy, // to bottom\n cx, // to left\n ]\n // Min distance to a side other than the one we sit on\n let minSecond = Infinity\n for (let s = 0; s < 4; s++) {\n if (s === side) continue\n minSecond = Math.min(minSecond, distOther[s]!)\n }\n const maxR = Math.hypot(w, h)\n const r = minSecond + rng() * Math.max(0, maxR - minSecond)\n return { cx, cy, r: Math.max(r, minSecond + 1e-6) }\n}\n\nfunction mulberry32(a: number): () => number {\n return function () {\n let t = (a += 0x6d2b79f5)\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nfunction mid(a: Vec2, b: Vec2): Vec2 {\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 }\n}\n\nexport const tiling = {\n squareGrid,\n hexTiling,\n rectSubdivision,\n quadSubdivision,\n triangleSubdivision,\n sliceDivision,\n hatchSubdivision,\n arcDivision,\n}\n"]}
@@ -1,5 +1,4 @@
1
- import { V as Vec2 } from '../vec2-CWyXN1Wj.js';
2
- import { P as Path } from '../path-0RjhYjJs.js';
1
+ import { P as Path, V as Vec2 } from '../path-Boeshk9L.js';
3
2
 
4
3
  declare function translate(p: Path, dx: number, dy: number): Path;
5
4
  declare function translateToOrigin(p: Path): Path;
@@ -1,5 +1,4 @@
1
- import { V as Vec2 } from '../vec2-CWyXN1Wj.js';
2
- import { P as Path } from '../path-0RjhYjJs.js';
1
+ import { P as Path, V as Vec2 } from '../path-Boeshk9L.js';
3
2
 
4
3
  /**
5
4
  * Triangulate a closed path into triangle polygons (Clipper2).
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/types/vec2.ts","../../src/types/path.ts","../../src/clipper/convert.ts","../../src/predicates/index.ts","../../src/pointSet/index.ts","../../src/triangulation/index.ts"],"names":["path"],"mappings":"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","file":"index.js","sourcesContent":["/** 2D point / vector. */\nexport type Vec2 = {\n x: number\n y: number\n}\n\nexport function vec2(x: number, y: number): Vec2 {\n return { x, y }\n}\n\nexport function cloneVec2(v: Vec2): Vec2 {\n return { x: v.x, y: v.y }\n}\n\nexport function equalsVec2(a: Vec2, b: Vec2, eps = 1e-9): boolean {\n return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps\n}\n","import type { Vec2 } from './vec2.js'\nimport { cloneVec2, equalsVec2 } from './vec2.js'\n\n/** Ordered ring of vertices (typically without repeating the closing vertex). */\nexport type Ring = Vec2[]\n\n/**\n * A path: one exterior ring plus optional holes, or an open polyline.\n * `rings[0]` is the exterior (or the open polyline when `closed` is false).\n * Additional rings are holes (only meaningful when `closed` is true).\n */\nexport type Path = {\n rings: Ring[]\n closed: boolean\n}\n\nexport function path(rings: Ring[], closed = true): Path {\n return {\n rings: rings.map((ring) => ring.map(cloneVec2)),\n closed,\n }\n}\n\nexport function polyline(points: Ring): Path {\n return path([points], false)\n}\n\nexport function polygon(exterior: Ring, holes: Ring[] = []): Path {\n return path([exterior, ...holes], true)\n}\n\n/** Drop a trailing vertex that duplicates the first (SVG often closes this way). */\nexport function normalizeRing(ring: Ring, eps = 1e-9): Ring {\n if (ring.length < 2) return ring.map(cloneVec2)\n const first = ring[0]\n const last = ring[ring.length - 1]\n if (first && last && equalsVec2(first, last, eps)) {\n return ring.slice(0, -1).map(cloneVec2)\n }\n return ring.map(cloneVec2)\n}\n\nexport function clonePath(p: Path): Path {\n return {\n closed: p.closed,\n rings: p.rings.map((ring) => ring.map(cloneVec2)),\n }\n}\n","import {\n FillRule,\n areaD,\n differenceD,\n intersectD,\n isPositiveD,\n pointInPolygonD,\n PointInPolygonResult,\n unionD,\n xorD,\n type PathD,\n type PathsD,\n type PointD,\n} from 'clipper2-ts'\nimport type { Group, Path, Ring, Vec2 } from '../types/index.js'\nimport { group, normalizeRing, path, vec2 } from '../types/index.js'\n\nexport const DEFAULT_FILL_RULE = FillRule.NonZero\n\nexport function ringToPathD(ring: Ring): PathD {\n const pts: PointD[] = []\n for (const v of normalizeRing(ring)) {\n pts.push({ x: v.x, y: v.y, z: 0 })\n }\n return pts\n}\n\n/** Closed path → Clipper subject/clip paths (exterior + holes). */\nexport function pathToPathsD(p: Path): PathsD {\n if (!p.closed || p.rings.length === 0) {\n throw new Error('Boolean ops require a closed path with at least one ring')\n }\n return p.rings.map((ring) => ringToPathD(ring))\n}\n\nexport function pathsDToGroup(paths: PathsD): Group {\n if (paths.length === 0) return group([])\n\n const outers: { ring: Ring; holes: Ring[] }[] = []\n const holes: Ring[] = []\n\n for (const pd of paths) {\n const ring = pathDToRing(pd)\n if (ring.length < 3) continue\n if (isPositiveD(pd)) {\n outers.push({ ring, holes: [] })\n } else {\n holes.push(ring)\n }\n }\n\n for (const hole of holes) {\n const sample = hole[0]\n if (!sample) continue\n let assigned = false\n for (const outer of outers) {\n if (pointInRing(sample, outer.ring)) {\n outer.holes.push(hole)\n assigned = true\n break\n }\n }\n if (!assigned) {\n // Treat unmatched negative rings as their own outers (orientation flip).\n outers.push({ ring: [...hole].reverse(), holes: [] })\n }\n }\n\n return group(outers.map((o) => path([o.ring, ...o.holes], true)))\n}\n\nexport function pathDToRing(pd: PathD): Ring {\n return normalizeRing(pd.map((p) => vec2(p.x, p.y)))\n}\n\nexport function pointInRing(point: Vec2, ring: Ring): boolean {\n const result = pointInPolygonD(\n { x: point.x, y: point.y, z: 0 },\n ringToPathD(ring),\n )\n return (\n result === PointInPolygonResult.IsInside ||\n result === PointInPolygonResult.IsOn\n )\n}\n\nexport function clipUnion(a: PathsD, b: PathsD): PathsD {\n return unionD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipIntersect(a: PathsD, b: PathsD): PathsD {\n return intersectD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipDifference(a: PathsD, b: PathsD): PathsD {\n return differenceD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipXor(a: PathsD, b: PathsD): PathsD {\n return xorD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function pathsArea(paths: PathsD): number {\n let sum = 0\n for (const p of paths) {\n sum += Math.abs(areaD(p))\n }\n return sum\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { vec2 } from '../types/index.js'\nimport {\n pathToPathsD,\n pathsArea,\n pointInRing,\n} from '../clipper/convert.js'\n\n/** Signed area of a closed ring (shoelace). */\nexport function ringArea(ring: Vec2[]): number {\n if (ring.length < 3) return 0\n let sum = 0\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n sum += a.x * b.y - b.x * a.y\n }\n return sum / 2\n}\n\n/** Absolute area of a closed path (exterior minus holes). */\nexport function area(p: Path): number {\n if (!p.closed || p.rings.length === 0) return 0\n try {\n return pathsArea(pathToPathsD(p))\n } catch {\n let total = 0\n for (let i = 0; i < p.rings.length; i++) {\n const a = Math.abs(ringArea(p.rings[i]!))\n total += i === 0 ? a : -a\n }\n return Math.max(0, total)\n }\n}\n\nexport function areaGroup(g: Group): number {\n return g.paths.reduce((sum, p) => sum + area(p), 0)\n}\n\n/** Centroid of a closed exterior ring (ignores holes for Phase 2). */\nexport function centroid(p: Path): Vec2 {\n const ring = p.rings[0]\n if (!ring || ring.length === 0) return vec2(0, 0)\n const a = ringArea(ring)\n if (Math.abs(a) < 1e-12) {\n let sx = 0\n let sy = 0\n for (const v of ring) {\n sx += v.x\n sy += v.y\n }\n return vec2(sx / ring.length, sy / ring.length)\n }\n let cx = 0\n let cy = 0\n for (let i = 0; i < ring.length; i++) {\n const p0 = ring[i]!\n const p1 = ring[(i + 1) % ring.length]!\n const cross = p0.x * p1.y - p1.x * p0.y\n cx += (p0.x + p1.x) * cross\n cy += (p0.y + p1.y) * cross\n }\n return vec2(cx / (6 * a), cy / (6 * a))\n}\n\nexport function containsPoint(p: Path, point: Vec2): boolean {\n if (!p.closed || !p.rings[0]) return false\n if (!pointInRing(point, p.rings[0])) return false\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && pointInRing(point, hole)) return false\n }\n return true\n}\n\nexport function bounds(p: Path): {\n minX: number\n minY: number\n maxX: number\n maxY: number\n} {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const ring of p.rings) {\n for (const v of ring) {\n minX = Math.min(minX, v.x)\n minY = Math.min(minY, v.y)\n maxX = Math.max(maxX, v.x)\n maxY = Math.max(maxY, v.y)\n }\n }\n if (!Number.isFinite(minX)) {\n return { minX: 0, minY: 0, maxX: 0, maxY: 0 }\n }\n return { minX, minY, maxX, maxY }\n}\n\nexport function width(p: Path): number {\n const b = bounds(p)\n return b.maxX - b.minX\n}\n\nexport function height(p: Path): number {\n const b = bounds(p)\n return b.maxY - b.minY\n}\n\n/** Rough polygon similarity via absolute area difference relative to max area. */\nexport function areaSimilarity(a: Path, b: Path): number {\n const aa = area(a)\n const bb = area(b)\n const denom = Math.max(aa, bb, 1e-12)\n return 1 - Math.abs(aa - bb) / denom\n}\n\nexport const predicates = {\n area,\n areaGroup,\n ringArea,\n centroid,\n containsPoint,\n bounds,\n width,\n height,\n areaSimilarity,\n}\n","import type { Vec2 } from '../types/index.js'\n\n/** Seeded uniform random points in an axis-aligned box. */\nexport function random(\n count: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n seed = 1,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n out.push({\n x: minX + rng() * (maxX - minX),\n y: minY + rng() * (maxY - minY),\n })\n }\n return out\n}\n\n/** Square lattice points covering [minX,maxX] × [minY,maxY]. */\nexport function squareGrid(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Vec2[] {\n const s = Math.max(spacing, 1e-9)\n const out: Vec2[] = []\n for (let x = minX; x <= maxX + 1e-12; x += s) {\n for (let y = minY; y <= maxY + 1e-12; y += s) {\n out.push({ x, y })\n }\n }\n return out\n}\n\n/** Hexagonal lattice points covering the box. */\nexport function hexGrid(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Vec2[] {\n const s = Math.max(spacing, 1e-9)\n const dx = s\n const dy = s * Math.sqrt(3) * 0.5\n const out: Vec2[] = []\n let row = 0\n for (let y = minY; y <= maxY + 1e-12; y += dy, row++) {\n const x0 = minX + (row % 2 === 0 ? 0 : s * 0.5)\n for (let x = x0; x <= maxX + 1e-12; x += dx) {\n out.push({ x, y })\n }\n }\n return out\n}\n\n/** Ring of `count` points around `center` with `radius`. */\nexport function ring(\n count: number,\n center: Vec2,\n radius: number,\n): Vec2[] {\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n const t = (i / count) * Math.PI * 2\n out.push({\n x: center.x + Math.cos(t) * radius,\n y: center.y + Math.sin(t) * radius,\n })\n }\n return out\n}\n\nfunction mulberry32(a: number): () => number {\n return function () {\n let t = (a += 0x6d2b79f5)\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** Bridson-ish Poisson disk sample in a box (seeded). */\nexport function poisson(\n minDistance: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n seed = 1,\n maxAttempts = 30,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const r = Math.max(minDistance, 1e-9)\n const cell = r / Math.SQRT2\n const w = maxX - minX\n const h = maxY - minY\n const gw = Math.max(1, Math.ceil(w / cell))\n const gh = Math.max(1, Math.ceil(h / cell))\n const grid: (number | null)[] = Array(gw * gh).fill(null)\n const points: Vec2[] = []\n const active: number[] = []\n\n const gx = (p: Vec2) => Math.min(gw - 1, Math.floor((p.x - minX) / cell))\n const gy = (p: Vec2) => Math.min(gh - 1, Math.floor((p.y - minY) / cell))\n\n const emit = (p: Vec2) => {\n const i = points.length\n points.push(p)\n active.push(i)\n grid[gy(p) * gw + gx(p)] = i\n }\n\n emit({\n x: minX + rng() * w,\n y: minY + rng() * h,\n })\n\n while (active.length > 0) {\n const ai = Math.floor(rng() * active.length)\n const i = active[ai]!\n const src = points[i]!\n let found = false\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const ang = rng() * Math.PI * 2\n const rad = r * (1 + rng())\n const cand = {\n x: src.x + Math.cos(ang) * rad,\n y: src.y + Math.sin(ang) * rad,\n }\n if (\n cand.x < minX ||\n cand.x > maxX ||\n cand.y < minY ||\n cand.y > maxY\n ) {\n continue\n }\n const cx = gx(cand)\n const cy = gy(cand)\n let ok = true\n for (let yy = Math.max(0, cy - 2); yy <= Math.min(gh - 1, cy + 2) && ok; yy++) {\n for (let xx = Math.max(0, cx - 2); xx <= Math.min(gw - 1, cx + 2); xx++) {\n const j = grid[yy * gw + xx]\n if (j == null) continue\n const q = points[j]!\n if (Math.hypot(cand.x - q.x, cand.y - q.y) < r) {\n ok = false\n break\n }\n }\n }\n if (ok) {\n emit(cand)\n found = true\n break\n }\n }\n if (!found) active.splice(ai, 1)\n }\n return points\n}\n\n/** Drop points closer than `minDistance` (greedy keep-first). */\nexport function prunePointsWithinDistance(\n points: Vec2[],\n minDistance: number,\n): Vec2[] {\n const r = Math.max(minDistance, 0)\n const out: Vec2[] = []\n for (const p of points) {\n if (out.every((q) => Math.hypot(p.x - q.x, p.y - q.y) >= r)) {\n out.push(p)\n }\n }\n return out\n}\n\nexport const pointSet = {\n random,\n squareGrid,\n hexGrid,\n ring,\n poisson,\n prunePointsWithinDistance,\n}\n","import { triangulateD } from 'clipper2-ts'\nimport { Delaunay } from 'd3-delaunay'\nimport type { Path, Vec2 } from '../types/index.js'\nimport { polygon } from '../types/index.js'\nimport { pathToPathsD, pathDToRing } from '../clipper/convert.js'\nimport { bounds, containsPoint } from '../predicates/index.js'\nimport { poisson } from '../pointSet/index.js'\n\n/**\n * Triangulate a closed path into triangle polygons (Clipper2).\n * Holes are supported when present on the path. `useDelaunay` prefers\n * better-shaped triangles when Clipper can apply it.\n */\nexport function earCutTriangulation(\n p: Path,\n options: { useDelaunay?: boolean; precision?: number } = {},\n): Path[] {\n if (!p.closed || p.rings.length === 0) return []\n const { solution } = triangulateD(\n pathToPathsD(p),\n options.precision ?? 8,\n options.useDelaunay ?? false,\n )\n const tris: Path[] = []\n for (const pd of solution) {\n const ring = pathDToRing(pd)\n if (ring.length >= 3) tris.push(polygon(ring.slice(0, 3)))\n }\n return tris\n}\n\n/** Alias matching PGS naming for Clipper/Delaunay triangulation of a polygon. */\nexport function delaunayTriangulation(p: Path): Path[] {\n return earCutTriangulation(p, { useDelaunay: true })\n}\n\n/** Delaunay triangulation of a point set (d3-delaunay). */\nexport function delaunayTriangulationPoints(points: Vec2[]): Path[] {\n if (points.length < 3) return []\n const delaunay = Delaunay.from(\n points,\n (d) => d.x,\n (d) => d.y,\n )\n const tris: Path[] = []\n const { triangles } = delaunay\n for (let i = 0; i < triangles.length; i += 3) {\n const a = points[triangles[i]!]!\n const b = points[triangles[i + 1]!]!\n const c = points[triangles[i + 2]!]!\n tris.push(polygon([a, b, c]))\n }\n return tris\n}\n\n/**\n * Boundary vertices plus Poisson-disk Steiner points inside `path`.\n */\nexport function poissonTriangulationPoints(\n path: Path,\n minDistance: number,\n seed = 1,\n): Vec2[] {\n if (!path.closed || path.rings.length === 0) return []\n const b = bounds(path)\n const samples = poisson(\n minDistance,\n b.minX,\n b.minY,\n b.maxX,\n b.maxY,\n seed,\n ).filter((pt) => containsPoint(path, pt))\n return dedupePoints([...pathVertices(path), ...samples])\n}\n\n/**\n * Delaunay triangulation of a path with Poisson Steiner points inserted.\n * Triangles whose centroid falls outside the path (or in a hole) are dropped.\n */\nexport function poissonTriangulation(\n path: Path,\n minDistance: number,\n seed = 1,\n): Path[] {\n const pts = poissonTriangulationPoints(path, minDistance, seed)\n return trianglesInsidePath(delaunayTriangulationPoints(pts), path)\n}\n\nexport type RefineOptions = {\n /** Minimum allowed interior angle (radians). Default ≈ 20°. */\n minAngle?: number\n /** Safety cap on Steiner insertions. Default `200`. */\n maxIterations?: number\n}\n\n/**\n * Ruppert-inspired angle refinement for plotter meshes.\n * Clean-room approximation (not a full constrained CDT): insert circumcenters\n * of skinny triangles when they lie inside the path; otherwise split the\n * longest edge of that triangle (simple encroachment stand-in).\n */\nexport function refine(path: Path, options: RefineOptions = {}): Path[] {\n if (!path.closed || path.rings.length === 0) return []\n const minAngle = options.minAngle ?? (20 * Math.PI) / 180\n const maxIterations = Math.max(1, options.maxIterations ?? 200)\n const points = dedupePoints(pathVertices(path))\n if (points.length < 3) return []\n\n for (let iter = 0; iter < maxIterations; iter++) {\n const tris = trianglesInsidePath(\n delaunayTriangulationPoints(points),\n path,\n )\n if (tris.length === 0) break\n\n let skinny: Path | null = null\n let worst = minAngle\n for (const t of tris) {\n const a = minTriangleAngle(t)\n if (a < worst) {\n worst = a\n skinny = t\n }\n }\n if (!skinny) break\n\n const ring = skinny.rings[0]!\n const cc = circumcenter(ring[0]!, ring[1]!, ring[2]!)\n if (!cc) break\n\n const insert = containsPoint(path, cc)\n ? cc\n : longestEdgeMidpoint(ring[0]!, ring[1]!, ring[2]!)\n if (\n points.some((p) => Math.hypot(p.x - insert.x, p.y - insert.y) < 1e-9)\n ) {\n break\n }\n points.push(insert)\n }\n\n return trianglesInsidePath(delaunayTriangulationPoints(points), path)\n}\n\nfunction pathVertices(path: Path): Vec2[] {\n const out: Vec2[] = []\n for (const ring of path.rings) {\n for (const v of ring) out.push({ x: v.x, y: v.y })\n }\n return out\n}\n\nfunction dedupePoints(points: Vec2[], eps = 1e-9): Vec2[] {\n const out: Vec2[] = []\n for (const p of points) {\n if (out.some((q) => Math.hypot(q.x - p.x, q.y - p.y) < eps)) continue\n out.push(p)\n }\n return out\n}\n\nfunction triangleCentroid(t: Path): Vec2 | null {\n const r = t.rings[0]\n if (!r || r.length < 3) return null\n return {\n x: (r[0]!.x + r[1]!.x + r[2]!.x) / 3,\n y: (r[0]!.y + r[1]!.y + r[2]!.y) / 3,\n }\n}\n\nfunction trianglesInsidePath(tris: Path[], path: Path): Path[] {\n return tris.filter((t) => {\n const c = triangleCentroid(t)\n return c != null && containsPoint(path, c)\n })\n}\n\nfunction minTriangleAngle(t: Path): number {\n const r = t.rings[0]\n if (!r || r.length < 3) return 0\n const a = r[0]!\n const b = r[1]!\n const c = r[2]!\n return Math.min(angleAt(a, b, c), angleAt(b, c, a), angleAt(c, a, b))\n}\n\nfunction angleAt(vertex: Vec2, p: Vec2, q: Vec2): number {\n const ux = p.x - vertex.x\n const uy = p.y - vertex.y\n const vx = q.x - vertex.x\n const vy = q.y - vertex.y\n const lu = Math.hypot(ux, uy)\n const lv = Math.hypot(vx, vy)\n if (lu < 1e-18 || lv < 1e-18) return 0\n const cos = Math.max(-1, Math.min(1, (ux * vx + uy * vy) / (lu * lv)))\n return Math.acos(cos)\n}\n\nfunction circumcenter(a: Vec2, b: Vec2, c: Vec2): Vec2 | null {\n const d =\n 2 * (a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y))\n if (Math.abs(d) < 1e-18) return null\n const a2 = a.x * a.x + a.y * a.y\n const b2 = b.x * b.x + b.y * b.y\n const c2 = c.x * c.x + c.y * c.y\n return {\n x: (a2 * (b.y - c.y) + b2 * (c.y - a.y) + c2 * (a.y - b.y)) / d,\n y: (a2 * (c.x - b.x) + b2 * (a.x - c.x) + c2 * (b.x - a.x)) / d,\n }\n}\n\nfunction longestEdgeMidpoint(a: Vec2, b: Vec2, c: Vec2): Vec2 {\n const edges: [Vec2, Vec2][] = [\n [a, b],\n [b, c],\n [c, a],\n ]\n let best = edges[0]!\n let bestLen = -1\n for (const e of edges) {\n const len = Math.hypot(e[0].x - e[1].x, e[0].y - e[1].y)\n if (len > bestLen) {\n bestLen = len\n best = e\n }\n }\n return { x: (best[0].x + best[1].x) / 2, y: (best[0].y + best[1].y) / 2 }\n}\n\nexport const triangulation = {\n earCutTriangulation,\n delaunayTriangulation,\n delaunayTriangulationPoints,\n poissonTriangulation,\n poissonTriangulationPoints,\n refine,\n}\n"]}
1
+ {"version":3,"sources":["../../src/types/vec2.ts","../../src/types/path.ts","../../src/clipper/convert.ts","../../src/predicates/index.ts","../../src/pointSet/index.ts","../../src/triangulation/index.ts"],"names":["path"],"mappings":"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","file":"index.js","sourcesContent":["/** 2D point / vector. */\nexport type Vec2 = {\n x: number\n y: number\n}\n\nexport function vec2(x: number, y: number): Vec2 {\n return { x, y }\n}\n\nexport function cloneVec2(v: Vec2): Vec2 {\n return { x: v.x, y: v.y }\n}\n\nexport function equalsVec2(a: Vec2, b: Vec2, eps = 1e-9): boolean {\n return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps\n}\n","import type { Vec2 } from './vec2.js'\nimport { cloneVec2, equalsVec2 } from './vec2.js'\n\n/** Ordered ring of vertices (typically without repeating the closing vertex). */\nexport type Ring = Vec2[]\n\n/**\n * A path: one exterior ring plus optional holes, or an open polyline.\n * `rings[0]` is the exterior (or the open polyline when `closed` is false).\n * Additional rings are holes (only meaningful when `closed` is true).\n */\nexport type Path = {\n rings: Ring[]\n closed: boolean\n}\n\nexport function path(rings: Ring[], closed = true): Path {\n return {\n rings: rings.map((ring) => ring.map(cloneVec2)),\n closed,\n }\n}\n\nexport function polyline(points: Ring): Path {\n return path([points], false)\n}\n\nexport function polygon(exterior: Ring, holes: Ring[] = []): Path {\n return path([exterior, ...holes], true)\n}\n\n/** Drop a trailing vertex that duplicates the first (SVG often closes this way). */\nexport function normalizeRing(ring: Ring, eps = 1e-9): Ring {\n if (ring.length < 2) return ring.map(cloneVec2)\n const first = ring[0]\n const last = ring[ring.length - 1]\n if (first && last && equalsVec2(first, last, eps)) {\n return ring.slice(0, -1).map(cloneVec2)\n }\n return ring.map(cloneVec2)\n}\n\nexport function clonePath(p: Path): Path {\n return {\n closed: p.closed,\n rings: p.rings.map((ring) => ring.map(cloneVec2)),\n }\n}\n","import {\n FillRule,\n areaD,\n differenceD,\n intersectD,\n isPositiveD,\n pointInPolygonD,\n PointInPolygonResult,\n unionD,\n xorD,\n type PathD,\n type PathsD,\n type PointD,\n} from 'clipper2-ts'\nimport type { Group, Path, Ring, Vec2 } from '../types/index.js'\nimport { group, normalizeRing, path, vec2 } from '../types/index.js'\n\nexport const DEFAULT_FILL_RULE = FillRule.NonZero\n\nexport function ringToPathD(ring: Ring): PathD {\n const pts: PointD[] = []\n for (const v of normalizeRing(ring)) {\n pts.push({ x: v.x, y: v.y, z: 0 })\n }\n return pts\n}\n\n/** Closed path → Clipper subject/clip paths (exterior + holes). */\nexport function pathToPathsD(p: Path): PathsD {\n if (!p.closed || p.rings.length === 0) {\n throw new Error('Boolean ops require a closed path with at least one ring')\n }\n return p.rings.map((ring) => ringToPathD(ring))\n}\n\nexport function pathsDToGroup(paths: PathsD): Group {\n if (paths.length === 0) return group([])\n\n const outers: { ring: Ring; holes: Ring[] }[] = []\n const holes: Ring[] = []\n\n for (const pd of paths) {\n const ring = pathDToRing(pd)\n if (ring.length < 3) continue\n if (isPositiveD(pd)) {\n outers.push({ ring, holes: [] })\n } else {\n holes.push(ring)\n }\n }\n\n for (const hole of holes) {\n const sample = hole[0]\n if (!sample) continue\n let assigned = false\n for (const outer of outers) {\n if (pointInRing(sample, outer.ring)) {\n outer.holes.push(hole)\n assigned = true\n break\n }\n }\n if (!assigned) {\n // Treat unmatched negative rings as their own outers (orientation flip).\n outers.push({ ring: [...hole].reverse(), holes: [] })\n }\n }\n\n return group(outers.map((o) => path([o.ring, ...o.holes], true)))\n}\n\nexport function pathDToRing(pd: PathD): Ring {\n return normalizeRing(pd.map((p) => vec2(p.x, p.y)))\n}\n\nexport function pointInRing(point: Vec2, ring: Ring): boolean {\n const result = pointInPolygonD(\n { x: point.x, y: point.y, z: 0 },\n ringToPathD(ring),\n )\n return (\n result === PointInPolygonResult.IsInside ||\n result === PointInPolygonResult.IsOn\n )\n}\n\nexport function clipUnion(a: PathsD, b: PathsD): PathsD {\n return unionD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipIntersect(a: PathsD, b: PathsD): PathsD {\n return intersectD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipDifference(a: PathsD, b: PathsD): PathsD {\n return differenceD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function clipXor(a: PathsD, b: PathsD): PathsD {\n return xorD(a, b, DEFAULT_FILL_RULE)\n}\n\nexport function pathsArea(paths: PathsD): number {\n let sum = 0\n for (const p of paths) {\n sum += Math.abs(areaD(p))\n }\n return sum\n}\n","import type { Group, Path, Vec2 } from '../types/index.js'\nimport { vec2 } from '../types/index.js'\nimport {\n pathToPathsD,\n pathsArea,\n pointInRing,\n} from '../clipper/convert.js'\n\n/** Signed area of a closed ring (shoelace). */\nexport function ringArea(ring: Vec2[]): number {\n if (ring.length < 3) return 0\n let sum = 0\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i]!\n const b = ring[(i + 1) % ring.length]!\n sum += a.x * b.y - b.x * a.y\n }\n return sum / 2\n}\n\n/** Absolute area of a closed path (exterior minus holes). */\nexport function area(p: Path): number {\n if (!p.closed || p.rings.length === 0) return 0\n try {\n return pathsArea(pathToPathsD(p))\n } catch {\n let total = 0\n for (let i = 0; i < p.rings.length; i++) {\n const a = Math.abs(ringArea(p.rings[i]!))\n total += i === 0 ? a : -a\n }\n return Math.max(0, total)\n }\n}\n\nexport function areaGroup(g: Group): number {\n return g.paths.reduce((sum, p) => sum + area(p), 0)\n}\n\n/** Centroid of a closed exterior ring (ignores holes for Phase 2). */\nexport function centroid(p: Path): Vec2 {\n const ring = p.rings[0]\n if (!ring || ring.length === 0) return vec2(0, 0)\n const a = ringArea(ring)\n if (Math.abs(a) < 1e-12) {\n let sx = 0\n let sy = 0\n for (const v of ring) {\n sx += v.x\n sy += v.y\n }\n return vec2(sx / ring.length, sy / ring.length)\n }\n let cx = 0\n let cy = 0\n for (let i = 0; i < ring.length; i++) {\n const p0 = ring[i]!\n const p1 = ring[(i + 1) % ring.length]!\n const cross = p0.x * p1.y - p1.x * p0.y\n cx += (p0.x + p1.x) * cross\n cy += (p0.y + p1.y) * cross\n }\n return vec2(cx / (6 * a), cy / (6 * a))\n}\n\nexport function containsPoint(p: Path, point: Vec2): boolean {\n if (!p.closed || !p.rings[0]) return false\n if (!pointInRing(point, p.rings[0])) return false\n for (let i = 1; i < p.rings.length; i++) {\n const hole = p.rings[i]\n if (hole && pointInRing(point, hole)) return false\n }\n return true\n}\n\nexport function bounds(p: Path): {\n minX: number\n minY: number\n maxX: number\n maxY: number\n} {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const ring of p.rings) {\n for (const v of ring) {\n minX = Math.min(minX, v.x)\n minY = Math.min(minY, v.y)\n maxX = Math.max(maxX, v.x)\n maxY = Math.max(maxY, v.y)\n }\n }\n if (!Number.isFinite(minX)) {\n return { minX: 0, minY: 0, maxX: 0, maxY: 0 }\n }\n return { minX, minY, maxX, maxY }\n}\n\nexport function width(p: Path): number {\n const b = bounds(p)\n return b.maxX - b.minX\n}\n\nexport function height(p: Path): number {\n const b = bounds(p)\n return b.maxY - b.minY\n}\n\n/** Rough polygon similarity via absolute area difference relative to max area. */\nexport function areaSimilarity(a: Path, b: Path): number {\n const aa = area(a)\n const bb = area(b)\n const denom = Math.max(aa, bb, 1e-12)\n return 1 - Math.abs(aa - bb) / denom\n}\n\nexport const predicates = {\n area,\n areaGroup,\n ringArea,\n centroid,\n containsPoint,\n bounds,\n width,\n height,\n areaSimilarity,\n}\n","import type { Path, Vec2 } from '../types/index.js'\nimport { polygon, polyline } from '../types/index.js'\nimport { hilbertSort } from './hilbert.js'\n\nexport { hilbertSort } from './hilbert.js'\n\n/** Seeded uniform random points in an axis-aligned box. */\nexport function random(\n count: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n seed = 1,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n out.push({\n x: minX + rng() * (maxX - minX),\n y: minY + rng() * (maxY - minY),\n })\n }\n return out\n}\n\n/** Square lattice points covering [minX,maxX] × [minY,maxY]. */\nexport function squareGrid(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Vec2[] {\n const s = Math.max(spacing, 1e-9)\n const out: Vec2[] = []\n for (let x = minX; x <= maxX + 1e-12; x += s) {\n for (let y = minY; y <= maxY + 1e-12; y += s) {\n out.push({ x, y })\n }\n }\n return out\n}\n\n/** Hexagonal lattice points covering the box. */\nexport function hexGrid(\n spacing: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n): Vec2[] {\n const s = Math.max(spacing, 1e-9)\n const dx = s\n const dy = s * Math.sqrt(3) * 0.5\n const out: Vec2[] = []\n let row = 0\n for (let y = minY; y <= maxY + 1e-12; y += dy, row++) {\n const x0 = minX + (row % 2 === 0 ? 0 : s * 0.5)\n for (let x = x0; x <= maxX + 1e-12; x += dx) {\n out.push({ x, y })\n }\n }\n return out\n}\n\n/** Ring of `count` points around `center` with `radius`. */\nexport function ring(\n count: number,\n center: Vec2,\n radius: number,\n): Vec2[] {\n const out: Vec2[] = []\n for (let i = 0; i < count; i++) {\n const t = (i / count) * Math.PI * 2\n out.push({\n x: center.x + Math.cos(t) * radius,\n y: center.y + Math.sin(t) * radius,\n })\n }\n return out\n}\n\nfunction mulberry32(a: number): () => number {\n return function () {\n let t = (a += 0x6d2b79f5)\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** Bridson-ish Poisson disk sample in a box (seeded). */\nexport function poisson(\n minDistance: number,\n minX: number,\n minY: number,\n maxX: number,\n maxY: number,\n seed = 1,\n maxAttempts = 30,\n): Vec2[] {\n const rng = mulberry32(seed >>> 0)\n const r = Math.max(minDistance, 1e-9)\n const cell = r / Math.SQRT2\n const w = maxX - minX\n const h = maxY - minY\n const gw = Math.max(1, Math.ceil(w / cell))\n const gh = Math.max(1, Math.ceil(h / cell))\n const grid: (number | null)[] = Array(gw * gh).fill(null)\n const points: Vec2[] = []\n const active: number[] = []\n\n const gx = (p: Vec2) => Math.min(gw - 1, Math.floor((p.x - minX) / cell))\n const gy = (p: Vec2) => Math.min(gh - 1, Math.floor((p.y - minY) / cell))\n\n const emit = (p: Vec2) => {\n const i = points.length\n points.push(p)\n active.push(i)\n grid[gy(p) * gw + gx(p)] = i\n }\n\n emit({\n x: minX + rng() * w,\n y: minY + rng() * h,\n })\n\n while (active.length > 0) {\n const ai = Math.floor(rng() * active.length)\n const i = active[ai]!\n const src = points[i]!\n let found = false\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const ang = rng() * Math.PI * 2\n const rad = r * (1 + rng())\n const cand = {\n x: src.x + Math.cos(ang) * rad,\n y: src.y + Math.sin(ang) * rad,\n }\n if (\n cand.x < minX ||\n cand.x > maxX ||\n cand.y < minY ||\n cand.y > maxY\n ) {\n continue\n }\n const cx = gx(cand)\n const cy = gy(cand)\n let ok = true\n for (let yy = Math.max(0, cy - 2); yy <= Math.min(gh - 1, cy + 2) && ok; yy++) {\n for (let xx = Math.max(0, cx - 2); xx <= Math.min(gw - 1, cx + 2); xx++) {\n const j = grid[yy * gw + xx]\n if (j == null) continue\n const q = points[j]!\n if (Math.hypot(cand.x - q.x, cand.y - q.y) < r) {\n ok = false\n break\n }\n }\n }\n if (ok) {\n emit(cand)\n found = true\n break\n }\n }\n if (!found) active.splice(ai, 1)\n }\n return points\n}\n\n/** Drop points closer than `minDistance` (greedy keep-first). */\nexport function prunePointsWithinDistance(\n points: Vec2[],\n minDistance: number,\n): Vec2[] {\n const r = Math.max(minDistance, 0)\n const out: Vec2[] = []\n for (const p of points) {\n if (out.every((q) => Math.hypot(p.x - q.x, p.y - q.y) >= r)) {\n out.push(p)\n }\n }\n return out\n}\n\n/**\n * Approximate shortest tour (TSP): nearest-neighbor constructive heuristic\n * followed by 2-opt improvement. Returns a closed path visiting each point once.\n */\nexport function findShortestTour(points: Vec2[]): Path {\n if (points.length === 0) return polygon([])\n if (points.length === 1) return polygon([{ ...points[0]! }])\n if (points.length === 2) {\n return polyline([\n { ...points[0]! },\n { ...points[1]! },\n { ...points[0]! },\n ])\n }\n\n const tour = nearestNeighborTour(points)\n twoOpt(tour)\n return polygon(tour)\n}\n\nfunction nearestNeighborTour(points: Vec2[]): Vec2[] {\n const remaining = points.map((p) => ({ ...p }))\n // Start at lexicographically smallest point for determinism\n let startI = 0\n for (let i = 1; i < remaining.length; i++) {\n const a = remaining[i]!\n const b = remaining[startI]!\n if (a.x < b.x || (a.x === b.x && a.y < b.y)) startI = i\n }\n const ordered: Vec2[] = [remaining.splice(startI, 1)[0]!]\n while (remaining.length) {\n const last = ordered[ordered.length - 1]!\n let bestI = 0\n let bestD = Infinity\n for (let i = 0; i < remaining.length; i++) {\n const d = Math.hypot(\n remaining[i]!.x - last.x,\n remaining[i]!.y - last.y,\n )\n if (d < bestD) {\n bestD = d\n bestI = i\n }\n }\n ordered.push(remaining.splice(bestI, 1)[0]!)\n }\n return ordered\n}\n\n/** In-place 2-opt until no improving swap remains. */\nfunction twoOpt(tour: Vec2[]): void {\n const n = tour.length\n if (n < 4) return\n let improved = true\n while (improved) {\n improved = false\n for (let i = 0; i < n - 1; i++) {\n for (let j = i + 2; j < n; j++) {\n if (i === 0 && j === n - 1) continue\n const a = tour[i]!\n const b = tour[(i + 1) % n]!\n const c = tour[j]!\n const d = tour[(j + 1) % n]!\n const before =\n Math.hypot(a.x - b.x, a.y - b.y) + Math.hypot(c.x - d.x, c.y - d.y)\n const after =\n Math.hypot(a.x - c.x, a.y - c.y) + Math.hypot(b.x - d.x, b.y - d.y)\n if (after + 1e-12 < before) {\n // Reverse segment (i+1 .. j)\n let lo = i + 1\n let hi = j\n while (lo < hi) {\n const tmp = tour[lo]!\n tour[lo] = tour[hi]!\n tour[hi] = tmp\n lo++\n hi--\n }\n improved = true\n }\n }\n }\n }\n}\n\nexport const pointSet = {\n random,\n squareGrid,\n hexGrid,\n ring,\n poisson,\n prunePointsWithinDistance,\n hilbertSort,\n findShortestTour,\n}\n","import { triangulateD } from 'clipper2-ts'\nimport { Delaunay } from 'd3-delaunay'\nimport type { Path, Vec2 } from '../types/index.js'\nimport { polygon } from '../types/index.js'\nimport { pathToPathsD, pathDToRing } from '../clipper/convert.js'\nimport { bounds, containsPoint } from '../predicates/index.js'\nimport { poisson } from '../pointSet/index.js'\n\n/**\n * Triangulate a closed path into triangle polygons (Clipper2).\n * Holes are supported when present on the path. `useDelaunay` prefers\n * better-shaped triangles when Clipper can apply it.\n */\nexport function earCutTriangulation(\n p: Path,\n options: { useDelaunay?: boolean; precision?: number } = {},\n): Path[] {\n if (!p.closed || p.rings.length === 0) return []\n const { solution } = triangulateD(\n pathToPathsD(p),\n options.precision ?? 8,\n options.useDelaunay ?? false,\n )\n const tris: Path[] = []\n for (const pd of solution) {\n const ring = pathDToRing(pd)\n if (ring.length >= 3) tris.push(polygon(ring.slice(0, 3)))\n }\n return tris\n}\n\n/** Alias matching PGS naming for Clipper/Delaunay triangulation of a polygon. */\nexport function delaunayTriangulation(p: Path): Path[] {\n return earCutTriangulation(p, { useDelaunay: true })\n}\n\n/** Delaunay triangulation of a point set (d3-delaunay). */\nexport function delaunayTriangulationPoints(points: Vec2[]): Path[] {\n if (points.length < 3) return []\n const delaunay = Delaunay.from(\n points,\n (d) => d.x,\n (d) => d.y,\n )\n const tris: Path[] = []\n const { triangles } = delaunay\n for (let i = 0; i < triangles.length; i += 3) {\n const a = points[triangles[i]!]!\n const b = points[triangles[i + 1]!]!\n const c = points[triangles[i + 2]!]!\n tris.push(polygon([a, b, c]))\n }\n return tris\n}\n\n/**\n * Boundary vertices plus Poisson-disk Steiner points inside `path`.\n */\nexport function poissonTriangulationPoints(\n path: Path,\n minDistance: number,\n seed = 1,\n): Vec2[] {\n if (!path.closed || path.rings.length === 0) return []\n const b = bounds(path)\n const samples = poisson(\n minDistance,\n b.minX,\n b.minY,\n b.maxX,\n b.maxY,\n seed,\n ).filter((pt) => containsPoint(path, pt))\n return dedupePoints([...pathVertices(path), ...samples])\n}\n\n/**\n * Delaunay triangulation of a path with Poisson Steiner points inserted.\n * Triangles whose centroid falls outside the path (or in a hole) are dropped.\n */\nexport function poissonTriangulation(\n path: Path,\n minDistance: number,\n seed = 1,\n): Path[] {\n const pts = poissonTriangulationPoints(path, minDistance, seed)\n return trianglesInsidePath(delaunayTriangulationPoints(pts), path)\n}\n\nexport type RefineOptions = {\n /** Minimum allowed interior angle (radians). Default ≈ 20°. */\n minAngle?: number\n /** Safety cap on Steiner insertions. Default `200`. */\n maxIterations?: number\n}\n\n/**\n * Ruppert-inspired angle refinement for plotter meshes.\n * Clean-room approximation (not a full constrained CDT): insert circumcenters\n * of skinny triangles when they lie inside the path; otherwise split the\n * longest edge of that triangle (simple encroachment stand-in).\n */\nexport function refine(path: Path, options: RefineOptions = {}): Path[] {\n if (!path.closed || path.rings.length === 0) return []\n const minAngle = options.minAngle ?? (20 * Math.PI) / 180\n const maxIterations = Math.max(1, options.maxIterations ?? 200)\n const points = dedupePoints(pathVertices(path))\n if (points.length < 3) return []\n\n for (let iter = 0; iter < maxIterations; iter++) {\n const tris = trianglesInsidePath(\n delaunayTriangulationPoints(points),\n path,\n )\n if (tris.length === 0) break\n\n let skinny: Path | null = null\n let worst = minAngle\n for (const t of tris) {\n const a = minTriangleAngle(t)\n if (a < worst) {\n worst = a\n skinny = t\n }\n }\n if (!skinny) break\n\n const ring = skinny.rings[0]!\n const cc = circumcenter(ring[0]!, ring[1]!, ring[2]!)\n if (!cc) break\n\n const insert = containsPoint(path, cc)\n ? cc\n : longestEdgeMidpoint(ring[0]!, ring[1]!, ring[2]!)\n if (\n points.some((p) => Math.hypot(p.x - insert.x, p.y - insert.y) < 1e-9)\n ) {\n break\n }\n points.push(insert)\n }\n\n return trianglesInsidePath(delaunayTriangulationPoints(points), path)\n}\n\nfunction pathVertices(path: Path): Vec2[] {\n const out: Vec2[] = []\n for (const ring of path.rings) {\n for (const v of ring) out.push({ x: v.x, y: v.y })\n }\n return out\n}\n\nfunction dedupePoints(points: Vec2[], eps = 1e-9): Vec2[] {\n const out: Vec2[] = []\n for (const p of points) {\n if (out.some((q) => Math.hypot(q.x - p.x, q.y - p.y) < eps)) continue\n out.push(p)\n }\n return out\n}\n\nfunction triangleCentroid(t: Path): Vec2 | null {\n const r = t.rings[0]\n if (!r || r.length < 3) return null\n return {\n x: (r[0]!.x + r[1]!.x + r[2]!.x) / 3,\n y: (r[0]!.y + r[1]!.y + r[2]!.y) / 3,\n }\n}\n\nfunction trianglesInsidePath(tris: Path[], path: Path): Path[] {\n return tris.filter((t) => {\n const c = triangleCentroid(t)\n return c != null && containsPoint(path, c)\n })\n}\n\nfunction minTriangleAngle(t: Path): number {\n const r = t.rings[0]\n if (!r || r.length < 3) return 0\n const a = r[0]!\n const b = r[1]!\n const c = r[2]!\n return Math.min(angleAt(a, b, c), angleAt(b, c, a), angleAt(c, a, b))\n}\n\nfunction angleAt(vertex: Vec2, p: Vec2, q: Vec2): number {\n const ux = p.x - vertex.x\n const uy = p.y - vertex.y\n const vx = q.x - vertex.x\n const vy = q.y - vertex.y\n const lu = Math.hypot(ux, uy)\n const lv = Math.hypot(vx, vy)\n if (lu < 1e-18 || lv < 1e-18) return 0\n const cos = Math.max(-1, Math.min(1, (ux * vx + uy * vy) / (lu * lv)))\n return Math.acos(cos)\n}\n\nfunction circumcenter(a: Vec2, b: Vec2, c: Vec2): Vec2 | null {\n const d =\n 2 * (a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y))\n if (Math.abs(d) < 1e-18) return null\n const a2 = a.x * a.x + a.y * a.y\n const b2 = b.x * b.x + b.y * b.y\n const c2 = c.x * c.x + c.y * c.y\n return {\n x: (a2 * (b.y - c.y) + b2 * (c.y - a.y) + c2 * (a.y - b.y)) / d,\n y: (a2 * (c.x - b.x) + b2 * (a.x - c.x) + c2 * (b.x - a.x)) / d,\n }\n}\n\nfunction longestEdgeMidpoint(a: Vec2, b: Vec2, c: Vec2): Vec2 {\n const edges: [Vec2, Vec2][] = [\n [a, b],\n [b, c],\n [c, a],\n ]\n let best = edges[0]!\n let bestLen = -1\n for (const e of edges) {\n const len = Math.hypot(e[0].x - e[1].x, e[0].y - e[1].y)\n if (len > bestLen) {\n bestLen = len\n best = e\n }\n }\n return { x: (best[0].x + best[1].x) / 2, y: (best[0].y + best[1].y) / 2 }\n}\n\nexport const triangulation = {\n earCutTriangulation,\n delaunayTriangulation,\n delaunayTriangulationPoints,\n poissonTriangulation,\n poissonTriangulationPoints,\n refine,\n}\n"]}