pattapatta 0.2.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 (74) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +98 -0
  4. package/dist/circle-BDbKfrdR.d.ts +12 -0
  5. package/dist/circlePacking/index.d.ts +78 -0
  6. package/dist/circlePacking/index.js +381 -0
  7. package/dist/circlePacking/index.js.map +1 -0
  8. package/dist/cli.js +365 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/construction/index.d.ts +26 -0
  11. package/dist/construction/index.js +102 -0
  12. package/dist/construction/index.js.map +1 -0
  13. package/dist/contour/index.d.ts +20 -0
  14. package/dist/contour/index.js +118 -0
  15. package/dist/contour/index.js.map +1 -0
  16. package/dist/conversion/index.d.ts +31 -0
  17. package/dist/conversion/index.js +99 -0
  18. package/dist/conversion/index.js.map +1 -0
  19. package/dist/group-BNjVVYSQ.d.ts +13 -0
  20. package/dist/hatch/index.d.ts +41 -0
  21. package/dist/hatch/index.js +253 -0
  22. package/dist/hatch/index.js.map +1 -0
  23. package/dist/hull/index.d.ts +16 -0
  24. package/dist/hull/index.js +97 -0
  25. package/dist/hull/index.js.map +1 -0
  26. package/dist/index.d.ts +67 -0
  27. package/dist/index.js +3933 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/meshing/index.d.ts +125 -0
  30. package/dist/meshing/index.js +1333 -0
  31. package/dist/meshing/index.js.map +1 -0
  32. package/dist/morphology/index.d.ts +58 -0
  33. package/dist/morphology/index.js +268 -0
  34. package/dist/morphology/index.js.map +1 -0
  35. package/dist/optimisation/index.d.ts +43 -0
  36. package/dist/optimisation/index.js +400 -0
  37. package/dist/optimisation/index.js.map +1 -0
  38. package/dist/path-0RjhYjJs.d.ts +21 -0
  39. package/dist/pointSet/index.d.ts +24 -0
  40. package/dist/pointSet/index.js +139 -0
  41. package/dist/pointSet/index.js.map +1 -0
  42. package/dist/polygonisation/index.d.ts +44 -0
  43. package/dist/polygonisation/index.js +310 -0
  44. package/dist/polygonisation/index.js.map +1 -0
  45. package/dist/predicates/index.d.ts +35 -0
  46. package/dist/predicates/index.js +159 -0
  47. package/dist/predicates/index.js.map +1 -0
  48. package/dist/processing/index.d.ts +54 -0
  49. package/dist/processing/index.js +457 -0
  50. package/dist/processing/index.js.map +1 -0
  51. package/dist/segment-BKuIFMKD.d.ts +10 -0
  52. package/dist/segmentSet/index.d.ts +25 -0
  53. package/dist/segmentSet/index.js +109 -0
  54. package/dist/segmentSet/index.js.map +1 -0
  55. package/dist/shapeBoolean/index.d.ts +41 -0
  56. package/dist/shapeBoolean/index.js +211 -0
  57. package/dist/shapeBoolean/index.js.map +1 -0
  58. package/dist/svg/index.d.ts +38 -0
  59. package/dist/svg/index.js +317 -0
  60. package/dist/svg/index.js.map +1 -0
  61. package/dist/tiling/index.d.ts +32 -0
  62. package/dist/tiling/index.js +344 -0
  63. package/dist/tiling/index.js.map +1 -0
  64. package/dist/transformation/index.d.ts +37 -0
  65. package/dist/transformation/index.js +184 -0
  66. package/dist/transformation/index.js.map +1 -0
  67. package/dist/triangulation/index.d.ts +48 -0
  68. package/dist/triangulation/index.js +334 -0
  69. package/dist/triangulation/index.js.map +1 -0
  70. package/dist/vec2-CWyXN1Wj.d.ts +10 -0
  71. package/dist/voronoi/index.d.ts +31 -0
  72. package/dist/voronoi/index.js +211 -0
  73. package/dist/voronoi/index.js.map +1 -0
  74. package/package.json +165 -0
@@ -0,0 +1,211 @@
1
+ import { Delaunay } from 'd3-delaunay';
2
+ import { FillRule, intersectD, isPositiveD, pointInPolygonD, PointInPolygonResult } from 'clipper2-ts';
3
+
4
+ // src/voronoi/index.ts
5
+
6
+ // src/types/vec2.ts
7
+ function vec2(x, y) {
8
+ return { x, y };
9
+ }
10
+ function cloneVec2(v) {
11
+ return { x: v.x, y: v.y };
12
+ }
13
+ function equalsVec2(a, b, eps = 1e-9) {
14
+ return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps;
15
+ }
16
+
17
+ // src/types/path.ts
18
+ function path(rings, closed = true) {
19
+ return {
20
+ rings: rings.map((ring) => ring.map(cloneVec2)),
21
+ closed
22
+ };
23
+ }
24
+ function polygon(exterior, holes = []) {
25
+ return path([exterior, ...holes], true);
26
+ }
27
+ function normalizeRing(ring, eps = 1e-9) {
28
+ if (ring.length < 2) return ring.map(cloneVec2);
29
+ const first = ring[0];
30
+ const last = ring[ring.length - 1];
31
+ if (first && last && equalsVec2(first, last, eps)) {
32
+ return ring.slice(0, -1).map(cloneVec2);
33
+ }
34
+ return ring.map(cloneVec2);
35
+ }
36
+ function clonePath(p) {
37
+ return {
38
+ closed: p.closed,
39
+ rings: p.rings.map((ring) => ring.map(cloneVec2))
40
+ };
41
+ }
42
+
43
+ // src/types/group.ts
44
+ function group(paths = []) {
45
+ return { paths: paths.map(clonePath) };
46
+ }
47
+ var DEFAULT_FILL_RULE = FillRule.NonZero;
48
+ function ringToPathD(ring) {
49
+ const pts = [];
50
+ for (const v of normalizeRing(ring)) {
51
+ pts.push({ x: v.x, y: v.y, z: 0 });
52
+ }
53
+ return pts;
54
+ }
55
+ function pathToPathsD(p) {
56
+ if (!p.closed || p.rings.length === 0) {
57
+ throw new Error("Boolean ops require a closed path with at least one ring");
58
+ }
59
+ return p.rings.map((ring) => ringToPathD(ring));
60
+ }
61
+ function pathsDToGroup(paths) {
62
+ if (paths.length === 0) return group([]);
63
+ const outers = [];
64
+ const holes = [];
65
+ for (const pd of paths) {
66
+ const ring = pathDToRing(pd);
67
+ if (ring.length < 3) continue;
68
+ if (isPositiveD(pd)) {
69
+ outers.push({ ring, holes: [] });
70
+ } else {
71
+ holes.push(ring);
72
+ }
73
+ }
74
+ for (const hole of holes) {
75
+ const sample = hole[0];
76
+ if (!sample) continue;
77
+ let assigned = false;
78
+ for (const outer of outers) {
79
+ if (pointInRing(sample, outer.ring)) {
80
+ outer.holes.push(hole);
81
+ assigned = true;
82
+ break;
83
+ }
84
+ }
85
+ if (!assigned) {
86
+ outers.push({ ring: [...hole].reverse(), holes: [] });
87
+ }
88
+ }
89
+ return group(outers.map((o) => path([o.ring, ...o.holes], true)));
90
+ }
91
+ function pathDToRing(pd) {
92
+ return normalizeRing(pd.map((p) => vec2(p.x, p.y)));
93
+ }
94
+ function pointInRing(point, ring) {
95
+ const result = pointInPolygonD(
96
+ { x: point.x, y: point.y, z: 0 },
97
+ ringToPathD(ring)
98
+ );
99
+ return result === PointInPolygonResult.IsInside || result === PointInPolygonResult.IsOn;
100
+ }
101
+ function clipIntersect(a, b) {
102
+ return intersectD(a, b, DEFAULT_FILL_RULE);
103
+ }
104
+
105
+ // src/predicates/index.ts
106
+ function bounds(p) {
107
+ let minX = Infinity;
108
+ let minY = Infinity;
109
+ let maxX = -Infinity;
110
+ let maxY = -Infinity;
111
+ for (const ring of p.rings) {
112
+ for (const v of ring) {
113
+ minX = Math.min(minX, v.x);
114
+ minY = Math.min(minY, v.y);
115
+ maxX = Math.max(maxX, v.x);
116
+ maxY = Math.max(maxY, v.y);
117
+ }
118
+ }
119
+ if (!Number.isFinite(minX)) {
120
+ return { minX: 0, minY: 0, maxX: 0, maxY: 0 };
121
+ }
122
+ return { minX, minY, maxX, maxY };
123
+ }
124
+
125
+ // src/shapeBoolean/index.ts
126
+ function ensureClosed(p) {
127
+ if (!p.closed) {
128
+ throw new Error("shapeBoolean requires closed paths");
129
+ }
130
+ return p;
131
+ }
132
+ function intersect(a, b) {
133
+ const result = clipIntersect(
134
+ pathToPathsD(ensureClosed(a)),
135
+ pathToPathsD(ensureClosed(b))
136
+ );
137
+ return pathsDToGroup(result);
138
+ }
139
+
140
+ // src/voronoi/index.ts
141
+ function compoundVoronoi(sites, options = {}) {
142
+ if (sites.length === 0) return group([]);
143
+ if (sites.length === 1) {
144
+ const b2 = options.bounds ?? padBounds(sites, 1);
145
+ return group([
146
+ polygon([
147
+ { x: b2.minX, y: b2.minY },
148
+ { x: b2.maxX, y: b2.minY },
149
+ { x: b2.maxX, y: b2.maxY },
150
+ { x: b2.minX, y: b2.maxY }
151
+ ])
152
+ ]);
153
+ }
154
+ const b = options.bounds ?? padBounds(sites, 0.1);
155
+ const delaunay = Delaunay.from(
156
+ sites,
157
+ (d) => d.x,
158
+ (d) => d.y
159
+ );
160
+ const voronoi2 = delaunay.voronoi([b.minX, b.minY, b.maxX, b.maxY]);
161
+ const paths = [];
162
+ for (let i = 0; i < sites.length; i++) {
163
+ const poly = voronoi2.cellPolygon(i);
164
+ if (!poly || poly.length < 3) continue;
165
+ const ring = poly.slice(0, -1).map(([x, y]) => ({ x, y }));
166
+ if (ring.length >= 3) paths.push(polygon(ring));
167
+ }
168
+ return group(paths);
169
+ }
170
+ function innerVoronoi(sites, container, options = {}) {
171
+ const b = options.bounds ?? {
172
+ ...bounds(container)
173
+ };
174
+ const cells = compoundVoronoi(sites, { bounds: b });
175
+ const clipped = [];
176
+ for (const cell of cells.paths) {
177
+ clipped.push(...intersect(cell, container).paths);
178
+ }
179
+ return group(clipped);
180
+ }
181
+ function innerVoronoiRaw(sites, options = {}) {
182
+ return compoundVoronoi(sites, options);
183
+ }
184
+ function padBounds(sites, padRatio) {
185
+ let minX = Infinity;
186
+ let minY = Infinity;
187
+ let maxX = -Infinity;
188
+ let maxY = -Infinity;
189
+ for (const s of sites) {
190
+ minX = Math.min(minX, s.x);
191
+ minY = Math.min(minY, s.y);
192
+ maxX = Math.max(maxX, s.x);
193
+ maxY = Math.max(maxY, s.y);
194
+ }
195
+ const pad = Math.max(maxX - minX, maxY - minY, 1) * padRatio + 1e-6;
196
+ return {
197
+ minX: minX - pad,
198
+ minY: minY - pad,
199
+ maxX: maxX + pad,
200
+ maxY: maxY + pad
201
+ };
202
+ }
203
+ var voronoi = {
204
+ compoundVoronoi,
205
+ innerVoronoi,
206
+ innerVoronoiRaw
207
+ };
208
+
209
+ export { compoundVoronoi, innerVoronoi, innerVoronoiRaw, voronoi };
210
+ //# sourceMappingURL=index.js.map
211
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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/shapeBoolean/index.ts","../../src/voronoi/index.ts"],"names":["b","voronoi"],"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 { Delaunay } from 'd3-delaunay'\nimport type { Group, Path, Vec2 } from '../types/index.js'\nimport { group, polygon } from '../types/index.js'\nimport { bounds } from '../predicates/index.js'\nimport { intersect } from '../shapeBoolean/index.js'\n\nexport type VoronoiOptions = {\n /** Clip cells to this bbox; default padded bounds of the sites. */\n bounds?: { minX: number; minY: number; maxX: number; maxY: number }\n}\n\n/**\n * Voronoi cells for a point set as closed polygons (clipped to a bbox).\n * PGS `compoundVoronoi` analogue — one path per site.\n */\nexport function compoundVoronoi(\n sites: Vec2[],\n options: VoronoiOptions = {},\n): Group {\n if (sites.length === 0) return group([])\n if (sites.length === 1) {\n const b = options.bounds ?? padBounds(sites, 1)\n return group([\n polygon([\n { x: b.minX, y: b.minY },\n { x: b.maxX, y: b.minY },\n { x: b.maxX, y: b.maxY },\n { x: b.minX, y: b.maxY },\n ]),\n ])\n }\n\n const b = options.bounds ?? padBounds(sites, 0.1)\n const delaunay = Delaunay.from(\n sites,\n (d) => d.x,\n (d) => d.y,\n )\n const voronoi = delaunay.voronoi([b.minX, b.minY, b.maxX, b.maxY])\n const paths: Path[] = []\n for (let i = 0; i < sites.length; i++) {\n const poly = voronoi.cellPolygon(i)\n if (!poly || poly.length < 3) continue\n // d3 closes the ring by repeating the first point\n const ring = poly.slice(0, -1).map(([x, y]) => ({ x, y }))\n if (ring.length >= 3) paths.push(polygon(ring))\n }\n return group(paths)\n}\n\n/**\n * Voronoi clipped to the interior of `container` (intersect each cell).\n */\nexport function innerVoronoi(\n sites: Vec2[],\n container: Path,\n options: VoronoiOptions = {},\n): Group {\n const b = options.bounds ?? {\n ...bounds(container),\n }\n const cells = compoundVoronoi(sites, { bounds: b })\n const clipped: Path[] = []\n for (const cell of cells.paths) {\n clipped.push(...intersect(cell, container).paths)\n }\n return group(clipped)\n}\n\n/** Raw cell polygons without container clip (same as compoundVoronoi). */\nexport function innerVoronoiRaw(\n sites: Vec2[],\n options: VoronoiOptions = {},\n): Group {\n return compoundVoronoi(sites, options)\n}\n\nfunction padBounds(\n sites: Vec2[],\n padRatio: number,\n): { minX: number; minY: number; maxX: number; maxY: number } {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const s of sites) {\n minX = Math.min(minX, s.x)\n minY = Math.min(minY, s.y)\n maxX = Math.max(maxX, s.x)\n maxY = Math.max(maxY, s.y)\n }\n const pad =\n Math.max(maxX - minX, maxY - minY, 1) * padRatio + 1e-6\n return {\n minX: minX - pad,\n minY: minY - pad,\n maxX: maxX + pad,\n maxY: maxY + pad,\n }\n}\n\nexport const voronoi = {\n compoundVoronoi,\n innerVoronoi,\n innerVoronoiRaw,\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,165 @@
1
+ {
2
+ "name": "pattapatta",
3
+ "version": "0.2.0",
4
+ "description": "Pen-plotter geometry library (PGS-inspired): hatching, packing, boolean paths for SVG",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "license": "MIT",
8
+ "author": "MadOrkestra",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/MadOrkestra/pattapatta.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/MadOrkestra/pattapatta/issues"
15
+ },
16
+ "homepage": "https://github.com/MadOrkestra/pattapatta#readme",
17
+ "keywords": [
18
+ "pen-plotter",
19
+ "svg",
20
+ "geometry",
21
+ "hatching",
22
+ "circle-packing",
23
+ "boolean",
24
+ "clipper",
25
+ "voronoi",
26
+ "pgs"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "main": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/index.d.ts",
36
+ "import": "./dist/index.js"
37
+ },
38
+ "./svg": {
39
+ "types": "./dist/svg/index.d.ts",
40
+ "import": "./dist/svg/index.js"
41
+ },
42
+ "./shapeBoolean": {
43
+ "types": "./dist/shapeBoolean/index.d.ts",
44
+ "import": "./dist/shapeBoolean/index.js"
45
+ },
46
+ "./predicates": {
47
+ "types": "./dist/predicates/index.d.ts",
48
+ "import": "./dist/predicates/index.js"
49
+ },
50
+ "./segmentSet": {
51
+ "types": "./dist/segmentSet/index.d.ts",
52
+ "import": "./dist/segmentSet/index.js"
53
+ },
54
+ "./hatch": {
55
+ "types": "./dist/hatch/index.d.ts",
56
+ "import": "./dist/hatch/index.js"
57
+ },
58
+ "./circlePacking": {
59
+ "types": "./dist/circlePacking/index.d.ts",
60
+ "import": "./dist/circlePacking/index.js"
61
+ },
62
+ "./morphology": {
63
+ "types": "./dist/morphology/index.d.ts",
64
+ "import": "./dist/morphology/index.js"
65
+ },
66
+ "./transformation": {
67
+ "types": "./dist/transformation/index.d.ts",
68
+ "import": "./dist/transformation/index.js"
69
+ },
70
+ "./processing": {
71
+ "types": "./dist/processing/index.d.ts",
72
+ "import": "./dist/processing/index.js"
73
+ },
74
+ "./conversion": {
75
+ "types": "./dist/conversion/index.d.ts",
76
+ "import": "./dist/conversion/index.js"
77
+ },
78
+ "./contour": {
79
+ "types": "./dist/contour/index.d.ts",
80
+ "import": "./dist/contour/index.js"
81
+ },
82
+ "./hull": {
83
+ "types": "./dist/hull/index.d.ts",
84
+ "import": "./dist/hull/index.js"
85
+ },
86
+ "./triangulation": {
87
+ "types": "./dist/triangulation/index.d.ts",
88
+ "import": "./dist/triangulation/index.js"
89
+ },
90
+ "./pointSet": {
91
+ "types": "./dist/pointSet/index.d.ts",
92
+ "import": "./dist/pointSet/index.js"
93
+ },
94
+ "./optimisation": {
95
+ "types": "./dist/optimisation/index.d.ts",
96
+ "import": "./dist/optimisation/index.js"
97
+ },
98
+ "./voronoi": {
99
+ "types": "./dist/voronoi/index.d.ts",
100
+ "import": "./dist/voronoi/index.js"
101
+ },
102
+ "./construction": {
103
+ "types": "./dist/construction/index.d.ts",
104
+ "import": "./dist/construction/index.js"
105
+ },
106
+ "./tiling": {
107
+ "types": "./dist/tiling/index.d.ts",
108
+ "import": "./dist/tiling/index.js"
109
+ },
110
+ "./polygonisation": {
111
+ "types": "./dist/polygonisation/index.d.ts",
112
+ "import": "./dist/polygonisation/index.js"
113
+ },
114
+ "./meshing": {
115
+ "types": "./dist/meshing/index.d.ts",
116
+ "import": "./dist/meshing/index.js"
117
+ },
118
+ "./package.json": "./package.json"
119
+ },
120
+ "bin": {
121
+ "pattapatta": "./dist/cli.js"
122
+ },
123
+ "files": [
124
+ "dist",
125
+ "README.md",
126
+ "CHANGELOG.md",
127
+ "LICENSE"
128
+ ],
129
+ "packageManager": "pnpm@10.22.0",
130
+ "scripts": {
131
+ "build": "tsup",
132
+ "test": "vitest run",
133
+ "test:watch": "vitest",
134
+ "typecheck": "tsc --noEmit",
135
+ "docs:examples": "pnpm run build && node scripts/generate-docs-examples.mjs",
136
+ "docs:dev": "pnpm --filter website dev",
137
+ "docs:build": "pnpm --filter website build",
138
+ "changeset": "changeset",
139
+ "version-packages": "changeset version",
140
+ "release": "pnpm build && changeset publish",
141
+ "prepack": "pnpm run build",
142
+ "prepublishOnly": "pnpm test && pnpm run build"
143
+ },
144
+ "engines": {
145
+ "node": ">=18",
146
+ "pnpm": ">=10"
147
+ },
148
+ "pnpm": {
149
+ "onlyBuiltDependencies": [
150
+ "esbuild"
151
+ ]
152
+ },
153
+ "devDependencies": {
154
+ "@changesets/cli": "^3.0.3",
155
+ "@types/d3-delaunay": "^6.0.4",
156
+ "@types/node": "^22.13.10",
157
+ "tsup": "^8.4.0",
158
+ "typescript": "^5.8.2",
159
+ "vitest": "^3.0.9"
160
+ },
161
+ "dependencies": {
162
+ "clipper2-ts": "^2.0.1-18",
163
+ "d3-delaunay": "^6.0.4"
164
+ }
165
+ }