@flighthq/path-boolean 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/booleanPaths.d.ts +7 -0
- package/dist/booleanPaths.d.ts.map +1 -0
- package/dist/booleanPaths.js +47 -0
- package/dist/booleanPaths.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/martinezKernel.d.ts +3 -0
- package/dist/martinezKernel.d.ts.map +1 -0
- package/dist/martinezKernel.js +625 -0
- package/dist/martinezKernel.js.map +1 -0
- package/dist/offsetPath.d.ts +3 -0
- package/dist/offsetPath.d.ts.map +1 -0
- package/dist/offsetPath.js +318 -0
- package/dist/offsetPath.js.map +1 -0
- package/dist/pathBooleanBackend.d.ts +5 -0
- package/dist/pathBooleanBackend.d.ts.map +1 -0
- package/dist/pathBooleanBackend.js +24 -0
- package/dist/pathBooleanBackend.js.map +1 -0
- package/dist/resolvePathRegions.d.ts +3 -0
- package/dist/resolvePathRegions.d.ts.map +1 -0
- package/dist/resolvePathRegions.js +28 -0
- package/dist/resolvePathRegions.js.map +1 -0
- package/dist/simplifyPath.d.ts +3 -0
- package/dist/simplifyPath.d.ts.map +1 -0
- package/dist/simplifyPath.js +16 -0
- package/dist/simplifyPath.js.map +1 -0
- package/dist/unionAllPaths.d.ts +3 -0
- package/dist/unionAllPaths.d.ts.map +1 -0
- package/dist/unionAllPaths.js +35 -0
- package/dist/unionAllPaths.js.map +1 -0
- package/package.json +38 -0
- package/src/booleanPaths.test.ts +163 -0
- package/src/fuzzInvariants.test.ts +203 -0
- package/src/martinezKernel.test.ts +376 -0
- package/src/offsetPath.test.ts +223 -0
- package/src/pathBooleanBackend.test.ts +50 -0
- package/src/resolvePathRegions.test.ts +48 -0
- package/src/simplifyPath.test.ts +146 -0
- package/src/unionAllPaths.test.ts +92 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offsetPath.d.ts","sourceRoot":"","sources":["../src/offsetPath.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAiC,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAc9F,wBAAgB,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,IAAI,CAgD3G"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { flattenPath } from '@flighthq/path';
|
|
2
|
+
import { resolvePathRegions } from './resolvePathRegions';
|
|
3
|
+
// Offsets a path outward (positive `delta`, inflate) or inward (negative `delta`, deflate) by a signed
|
|
4
|
+
// distance, returning a fresh polygon-outline `Path`. The input is flattened to polygon contours at the
|
|
5
|
+
// option tolerance; each closed contour is offset into a grown/shrunk ring and each open contour is
|
|
6
|
+
// offset into a closed slab outline capped at both terminals. Corner style on the convex side of a
|
|
7
|
+
// vertex is chosen by `options.join` (miter/bevel/round/square); open-path terminals by `options.end`
|
|
8
|
+
// (butt/round/square). The raw offset rings are then self-unioned by the active boolean kernel under
|
|
9
|
+
// non-zero fill to resolve the self-overlap concave corners produce, merge touching rings, and emit a
|
|
10
|
+
// clean, hole-correct outline. `delta` is signed against a canonical orientation, so positive always
|
|
11
|
+
// grows regardless of input winding. Over-deflating a region past self-collapse drops it, so the result
|
|
12
|
+
// can be an empty path (no commands).
|
|
13
|
+
export function offsetPath(path, delta, options) {
|
|
14
|
+
const join = options?.join ?? 'miter';
|
|
15
|
+
const end = options?.end ?? 'butt';
|
|
16
|
+
const miterLimit = options?.miterLimit ?? DEFAULT_MITER_LIMIT;
|
|
17
|
+
const arcTolerance = options?.arcTolerance ?? DEFAULT_ARC_TOLERANCE;
|
|
18
|
+
const contours = flattenPath(path, options?.tolerance);
|
|
19
|
+
// Coincident-point tolerance, made relative to the input's coordinate extent so the same corners
|
|
20
|
+
// collapse whether the contour is in pixels or micrometres; falls back to a fixed absolute when the
|
|
21
|
+
// extent is degenerate. Squared to match the squared-distance comparisons it feeds.
|
|
22
|
+
const pointEpsSq = getContourPointEps(contours) ** 2;
|
|
23
|
+
const rawRings = [];
|
|
24
|
+
for (const contour of contours) {
|
|
25
|
+
const closed = isClosedContour(contour, pointEpsSq);
|
|
26
|
+
const vertices = getCleanContourVertices(contour, closed, pointEpsSq);
|
|
27
|
+
if (closed) {
|
|
28
|
+
// Fewer than three distinct vertices enclose no area to offset.
|
|
29
|
+
if (vertices.length < 6)
|
|
30
|
+
continue;
|
|
31
|
+
const orientation = getRingOrientationSign(vertices);
|
|
32
|
+
const ring = buildOffsetRing(vertices, delta * orientation, NO_CAPS, join, end, miterLimit, arcTolerance);
|
|
33
|
+
if (ring.length < 6)
|
|
34
|
+
continue;
|
|
35
|
+
// Drop a ring deflated past self-collapse. Such a ring either fully inverts (its winding flips) or
|
|
36
|
+
// folds back so an inward offset fails to reduce the enclosed area — the global signature of a full
|
|
37
|
+
// collapse. (Partial self-overlap that stays same-signed is left for the positive-fill union below.)
|
|
38
|
+
const offsetArea = getRingSignedArea(ring);
|
|
39
|
+
const inverted = Math.sign(offsetArea) !== orientation;
|
|
40
|
+
const notReduced = delta < 0 && Math.abs(offsetArea) >= Math.abs(getRingSignedArea(vertices));
|
|
41
|
+
if (inverted || notReduced)
|
|
42
|
+
continue;
|
|
43
|
+
// Orient the surviving ring counter-clockwise (positive area) so the positive-fill self-union keeps
|
|
44
|
+
// it whatever the source winding was.
|
|
45
|
+
rawRings.push(offsetArea < 0 ? reverseVertexLoop(ring) : ring);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Fewer than two distinct vertices form no segment to stroke.
|
|
49
|
+
if (vertices.length < 4)
|
|
50
|
+
continue;
|
|
51
|
+
const caps = new Set([0, vertices.length / 2 - 1]);
|
|
52
|
+
const loop = getOpenContourLoop(vertices);
|
|
53
|
+
const ring = buildOffsetRing(loop, Math.abs(delta), caps, join, end, miterLimit, arcTolerance);
|
|
54
|
+
// A stroked slab always bounds a positive-area band; orient it counter-clockwise so positive-fill
|
|
55
|
+
// union keeps it regardless of which way the doubled loop happened to wind.
|
|
56
|
+
if (ring.length >= 6)
|
|
57
|
+
rawRings.push(getRingSignedArea(ring) < 0 ? reverseVertexLoop(ring) : ring);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Self-union the raw rings under positive fill (Clipper's InflatePaths cleanup fill): where a concave
|
|
61
|
+
// corner's inner-miter emission overshoots on a feature narrower than 2·|delta|, it dissolves the
|
|
62
|
+
// negatively-wound self-overlap that non-zero fill would have kept; it also merges touching rings and
|
|
63
|
+
// emits a clean, hole-correct outline (empty ring set → empty path).
|
|
64
|
+
return resolvePathRegions(rawRings, 'positive');
|
|
65
|
+
}
|
|
66
|
+
// Assembles one offset ring for a closed vertex loop by walking its vertices and emitting, at each, the
|
|
67
|
+
// join (or end cap, for the flagged terminal indices of an open-path loop) that bridges the offset end
|
|
68
|
+
// of the previous edge to the offset start of the next. `signedDelta` is the outward offset distance;
|
|
69
|
+
// the outward direction is the per-edge right normal, so a positively-oriented loop grows on positive
|
|
70
|
+
// `signedDelta`. `capIndices` is empty for a genuine closed contour and holds the two terminal indices
|
|
71
|
+
// for an open contour's doubled loop.
|
|
72
|
+
function buildOffsetRing(vertices, signedDelta, capIndices, join, end, miterLimit, arcTolerance) {
|
|
73
|
+
const count = vertices.length / 2;
|
|
74
|
+
// Per-edge unit direction and right normal; edge k runs from vertex k to vertex (k + 1) mod count.
|
|
75
|
+
const dirX = new Array(count);
|
|
76
|
+
const dirY = new Array(count);
|
|
77
|
+
const normalX = new Array(count);
|
|
78
|
+
const normalY = new Array(count);
|
|
79
|
+
for (let k = 0; k < count; k++) {
|
|
80
|
+
const kn = (k + 1) % count;
|
|
81
|
+
const dx = vertices[2 * kn] - vertices[2 * k];
|
|
82
|
+
const dy = vertices[2 * kn + 1] - vertices[2 * k + 1];
|
|
83
|
+
const length = Math.hypot(dx, dy);
|
|
84
|
+
const inverse = length > 0 ? 1 / length : 0;
|
|
85
|
+
dirX[k] = dx * inverse;
|
|
86
|
+
dirY[k] = dy * inverse;
|
|
87
|
+
normalX[k] = dirY[k];
|
|
88
|
+
normalY[k] = -dirX[k];
|
|
89
|
+
}
|
|
90
|
+
const ring = [];
|
|
91
|
+
for (let k = 0; k < count; k++) {
|
|
92
|
+
const previous = (k - 1 + count) % count;
|
|
93
|
+
const vx = vertices[2 * k];
|
|
94
|
+
const vy = vertices[2 * k + 1];
|
|
95
|
+
const previousEndX = vx + signedDelta * normalX[previous];
|
|
96
|
+
const previousEndY = vy + signedDelta * normalY[previous];
|
|
97
|
+
const thisStartX = vx + signedDelta * normalX[k];
|
|
98
|
+
const thisStartY = vy + signedDelta * normalY[k];
|
|
99
|
+
if (capIndices.has(k)) {
|
|
100
|
+
emitOffsetEndCap(ring, vx, vy, previousEndX, previousEndY, thisStartX, thisStartY, dirX[previous], dirY[previous], dirX[k], dirY[k], Math.abs(signedDelta), end, arcTolerance);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
emitOffsetJoin(ring, vx, vy, previousEndX, previousEndY, thisStartX, thisStartY, dirX[previous], dirY[previous], dirX[k], dirY[k], signedDelta, join, miterLimit, arcTolerance);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return ring;
|
|
107
|
+
}
|
|
108
|
+
// Emits the terminal cap of an open path at vertex (vx, vy), bridging the offset end of the incoming
|
|
109
|
+
// side (previousEnd) to the offset start of the outgoing side (thisStart), which sit on opposite sides
|
|
110
|
+
// of the terminal. `butt` connects them flat, `square` extends both out past the terminal by `radius`,
|
|
111
|
+
// and `round` sweeps a half-circle of that radius around the terminal. `previousEnd` is emitted first;
|
|
112
|
+
// `thisStart` is always emitted last.
|
|
113
|
+
function emitOffsetEndCap(ring, vx, vy, previousEndX, previousEndY, thisStartX, thisStartY, previousDirX, previousDirY, thisDirX, thisDirY, radius, end, arcTolerance) {
|
|
114
|
+
ring.push(previousEndX, previousEndY);
|
|
115
|
+
if (end === 'square') {
|
|
116
|
+
ring.push(previousEndX + radius * previousDirX, previousEndY + radius * previousDirY);
|
|
117
|
+
ring.push(thisStartX - radius * thisDirX, thisStartY - radius * thisDirY);
|
|
118
|
+
}
|
|
119
|
+
else if (end === 'round') {
|
|
120
|
+
const startAngle = Math.atan2(previousEndY - vy, previousEndX - vx);
|
|
121
|
+
// Sweep the half-circle that bulges past the terminal — the side the incoming direction points.
|
|
122
|
+
const midX = Math.cos(startAngle + HALF_PI);
|
|
123
|
+
const midY = Math.sin(startAngle + HALF_PI);
|
|
124
|
+
const sweep = (midX * previousDirX + midY * previousDirY >= 0 ? 1 : -1) * Math.PI;
|
|
125
|
+
pushOffsetArc(ring, vx, vy, radius, startAngle, sweep, arcTolerance);
|
|
126
|
+
}
|
|
127
|
+
ring.push(thisStartX, thisStartY);
|
|
128
|
+
}
|
|
129
|
+
// Emits the join at vertex (vx, vy) on the convex (gap) side, bridging the offset end of the previous
|
|
130
|
+
// edge (previousEnd) to the offset start of the next edge (thisStart). On the concave side the two
|
|
131
|
+
// offset edges overlap; the outline routes back through the original vertex (previousEnd → vertex →
|
|
132
|
+
// thisStart), leaving a self-crossing spur with consistent winding for the kernel's self-union to
|
|
133
|
+
// resolve. `miter` extends the two offset edges to their apex, falling back to a bevel
|
|
134
|
+
// when that apex is farther than `miterLimit * |signedDelta|`; `bevel` chamfers straight across;
|
|
135
|
+
// `round` sweeps an arc of radius `|signedDelta|`; `square` extends both edges by `|signedDelta|`.
|
|
136
|
+
// `previousEnd` is emitted first; `thisStart` is always emitted last.
|
|
137
|
+
function emitOffsetJoin(ring, vx, vy, previousEndX, previousEndY, thisStartX, thisStartY, previousDirX, previousDirY, thisDirX, thisDirY, signedDelta, join, miterLimit, arcTolerance) {
|
|
138
|
+
ring.push(previousEndX, previousEndY);
|
|
139
|
+
const turn = previousDirX * thisDirY - previousDirY * thisDirX;
|
|
140
|
+
const convex = turn * signedDelta > 0;
|
|
141
|
+
if (!convex) {
|
|
142
|
+
// Inner (overlap) corner: emit where the two offset edge lines cross — the inner miter point. For a
|
|
143
|
+
// mild corner this is the correct clean vertex; for a feature narrower than 2·|delta| it overshoots
|
|
144
|
+
// past the offset edges, and the resulting self-crossing spur is dissolved by the positive-fill
|
|
145
|
+
// self-union, which drops the negatively-wound overshoot region. Positive fill is what makes this
|
|
146
|
+
// robust where non-zero fill (which keeps the overshoot) could not.
|
|
147
|
+
if (Math.abs(turn) > PARALLEL_EPS) {
|
|
148
|
+
const advance = ((thisStartX - previousEndX) * thisDirY - (thisStartY - previousEndY) * thisDirX) / turn;
|
|
149
|
+
ring.push(previousEndX + advance * previousDirX, previousEndY + advance * previousDirY);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
if (join === 'miter') {
|
|
154
|
+
// Intersect the two offset edge lines; the apex is where the extended normals meet.
|
|
155
|
+
if (Math.abs(turn) > PARALLEL_EPS) {
|
|
156
|
+
const advance = ((thisStartX - previousEndX) * thisDirY - (thisStartY - previousEndY) * thisDirX) / turn;
|
|
157
|
+
const apexX = previousEndX + advance * previousDirX;
|
|
158
|
+
const apexY = previousEndY + advance * previousDirY;
|
|
159
|
+
const miterLength = Math.hypot(apexX - vx, apexY - vy);
|
|
160
|
+
if (miterLength <= miterLimit * Math.abs(signedDelta))
|
|
161
|
+
ring.push(apexX, apexY);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else if (join === 'square') {
|
|
165
|
+
const radius = Math.abs(signedDelta);
|
|
166
|
+
ring.push(previousEndX + radius * previousDirX, previousEndY + radius * previousDirY);
|
|
167
|
+
ring.push(thisStartX - radius * thisDirX, thisStartY - radius * thisDirY);
|
|
168
|
+
}
|
|
169
|
+
else if (join === 'round') {
|
|
170
|
+
const radius = Math.abs(signedDelta);
|
|
171
|
+
const startAngle = Math.atan2(previousEndY - vy, previousEndX - vx);
|
|
172
|
+
const endAngle = Math.atan2(thisStartY - vy, thisStartX - vx);
|
|
173
|
+
pushOffsetArc(ring, vx, vy, radius, startAngle, getShortSweep(startAngle, endAngle), arcTolerance);
|
|
174
|
+
}
|
|
175
|
+
// A bevel adds nothing between previousEnd and thisStart — the straight edge is the chamfer.
|
|
176
|
+
}
|
|
177
|
+
ring.push(thisStartX, thisStartY);
|
|
178
|
+
}
|
|
179
|
+
// Removes consecutive coincident points from a flattened contour and, for a closed contour, the closing
|
|
180
|
+
// vertex that repeats the first, yielding a clean `[x0, y0, ...]` vertex loop with no zero-length edges.
|
|
181
|
+
// `pointEpsSq` is the squared coincidence tolerance (magnitude-relative, computed by the caller).
|
|
182
|
+
function getCleanContourVertices(contour, closed, pointEpsSq) {
|
|
183
|
+
const out = [];
|
|
184
|
+
for (let i = 0; i < contour.length; i += 2) {
|
|
185
|
+
const x = contour[i];
|
|
186
|
+
const y = contour[i + 1];
|
|
187
|
+
if (out.length >= 2) {
|
|
188
|
+
const dx = x - out[out.length - 2];
|
|
189
|
+
const dy = y - out[out.length - 1];
|
|
190
|
+
if (dx * dx + dy * dy <= pointEpsSq)
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
out.push(x, y);
|
|
194
|
+
}
|
|
195
|
+
if (closed && out.length >= 4) {
|
|
196
|
+
const dx = out[0] - out[out.length - 2];
|
|
197
|
+
const dy = out[1] - out[out.length - 1];
|
|
198
|
+
if (dx * dx + dy * dy <= pointEpsSq)
|
|
199
|
+
out.length -= 2;
|
|
200
|
+
}
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
// The coincident-point tolerance for a contour set, scaled to the largest coordinate span across all
|
|
204
|
+
// contours so it tracks the input magnitude; falls back to a fixed absolute for degenerate extent.
|
|
205
|
+
function getContourPointEps(contours) {
|
|
206
|
+
let minX = Infinity;
|
|
207
|
+
let minY = Infinity;
|
|
208
|
+
let maxX = -Infinity;
|
|
209
|
+
let maxY = -Infinity;
|
|
210
|
+
for (const contour of contours) {
|
|
211
|
+
for (let i = 0; i < contour.length; i += 2) {
|
|
212
|
+
const x = contour[i];
|
|
213
|
+
const y = contour[i + 1];
|
|
214
|
+
if (x < minX)
|
|
215
|
+
minX = x;
|
|
216
|
+
if (x > maxX)
|
|
217
|
+
maxX = x;
|
|
218
|
+
if (y < minY)
|
|
219
|
+
minY = y;
|
|
220
|
+
if (y > maxY)
|
|
221
|
+
maxY = y;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const extent = Math.max(maxX - minX, maxY - minY);
|
|
225
|
+
return extent > 0 ? extent * POINT_EPS_RELATIVE : POINT_EPS;
|
|
226
|
+
}
|
|
227
|
+
// Builds the doubled vertex loop for an open contour: the forward vertices followed by the interior
|
|
228
|
+
// vertices in reverse. Offsetting this as a closed loop strokes both sides of the polyline, with the
|
|
229
|
+
// two terminal vertices (indices 0 and count - 1) reversing 180° so they take an end cap, not a join.
|
|
230
|
+
function getOpenContourLoop(vertices) {
|
|
231
|
+
const count = vertices.length / 2;
|
|
232
|
+
const loop = vertices.slice();
|
|
233
|
+
for (let k = count - 2; k >= 1; k--)
|
|
234
|
+
loop.push(vertices[2 * k], vertices[2 * k + 1]);
|
|
235
|
+
return loop;
|
|
236
|
+
}
|
|
237
|
+
// Signed orientation of a vertex loop under the standard shoelace convention: +1 counter-clockwise,
|
|
238
|
+
// -1 clockwise, +1 for a degenerate zero-area loop.
|
|
239
|
+
function getRingOrientationSign(vertices) {
|
|
240
|
+
const sign = Math.sign(getRingSignedArea(vertices));
|
|
241
|
+
return sign === 0 ? 1 : sign;
|
|
242
|
+
}
|
|
243
|
+
// Twice-halved shoelace signed area of an implicitly-closed vertex loop.
|
|
244
|
+
function getRingSignedArea(vertices) {
|
|
245
|
+
let area = 0;
|
|
246
|
+
const count = vertices.length / 2;
|
|
247
|
+
for (let k = 0; k < count; k++) {
|
|
248
|
+
const kn = (k + 1) % count;
|
|
249
|
+
area += vertices[2 * k] * vertices[2 * kn + 1] - vertices[2 * kn] * vertices[2 * k + 1];
|
|
250
|
+
}
|
|
251
|
+
return area * 0.5;
|
|
252
|
+
}
|
|
253
|
+
// The signed angular sweep from `startAngle` to `endAngle` taking the short way around, in (-PI, PI].
|
|
254
|
+
// Convex offset corners subtend the exterior turn angle, which is always the short arc.
|
|
255
|
+
function getShortSweep(startAngle, endAngle) {
|
|
256
|
+
let sweep = endAngle - startAngle;
|
|
257
|
+
while (sweep <= -Math.PI)
|
|
258
|
+
sweep += TWO_PI;
|
|
259
|
+
while (sweep > Math.PI)
|
|
260
|
+
sweep -= TWO_PI;
|
|
261
|
+
return sweep;
|
|
262
|
+
}
|
|
263
|
+
// Whether a flattened contour is closed: it has at least three points and its last point coincides with
|
|
264
|
+
// its first (the explicit closing vertex `flattenPath` appends on a CLOSE). An open polyline whose ends
|
|
265
|
+
// happen to coincide is treated as closed — an acceptable inference at pixel scale. `pointEpsSq` is the
|
|
266
|
+
// squared coincidence tolerance (magnitude-relative, computed by the caller).
|
|
267
|
+
function isClosedContour(contour, pointEpsSq) {
|
|
268
|
+
const n = contour.length;
|
|
269
|
+
if (n < 6)
|
|
270
|
+
return false;
|
|
271
|
+
const dx = contour[0] - contour[n - 2];
|
|
272
|
+
const dy = contour[1] - contour[n - 1];
|
|
273
|
+
return dx * dx + dy * dy <= pointEpsSq;
|
|
274
|
+
}
|
|
275
|
+
// Tessellates a circular arc about (cx, cy) of the given radius from `startAngle` sweeping by the signed
|
|
276
|
+
// `sweep`, pushing only the interior points (the caller emits the arc endpoints). Segment count is set
|
|
277
|
+
// so no chord deviates from the true circle by more than `arcTolerance`.
|
|
278
|
+
function pushOffsetArc(ring, cx, cy, radius, startAngle, sweep, arcTolerance) {
|
|
279
|
+
const maxAngle = arcTolerance > 0 && arcTolerance < radius ? 2 * Math.acos(1 - arcTolerance / radius) : Math.PI;
|
|
280
|
+
const steps = Math.max(1, Math.ceil(Math.abs(sweep) / maxAngle));
|
|
281
|
+
for (let i = 1; i < steps; i++) {
|
|
282
|
+
const angle = startAngle + sweep * (i / steps);
|
|
283
|
+
ring.push(cx + radius * Math.cos(angle), cy + radius * Math.sin(angle));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// Reverses a flat `[x0, y0, ...]` vertex loop in place-free fashion, flipping its winding while keeping
|
|
287
|
+
// vertex 0 first, so a clockwise loop becomes counter-clockwise and vice versa.
|
|
288
|
+
function reverseVertexLoop(vertices) {
|
|
289
|
+
const count = vertices.length / 2;
|
|
290
|
+
const out = new Array(vertices.length);
|
|
291
|
+
out[0] = vertices[0];
|
|
292
|
+
out[1] = vertices[1];
|
|
293
|
+
for (let k = 1; k < count; k++) {
|
|
294
|
+
const source = count - k;
|
|
295
|
+
out[2 * k] = vertices[2 * source];
|
|
296
|
+
out[2 * k + 1] = vertices[2 * source + 1];
|
|
297
|
+
}
|
|
298
|
+
return out;
|
|
299
|
+
}
|
|
300
|
+
// Default maximum deviation between a round join/end arc and its true circle, in path units — a quarter
|
|
301
|
+
// pixel, matching the flattener's default and sane for pixel-scale output.
|
|
302
|
+
const DEFAULT_ARC_TOLERANCE = 0.25;
|
|
303
|
+
// Default miter length ceiling as a multiple of |delta|, the Clipper2 default: corners sharper than
|
|
304
|
+
// ~60° fall back to a bevel.
|
|
305
|
+
const DEFAULT_MITER_LIMIT = 2;
|
|
306
|
+
const HALF_PI = Math.PI / 2;
|
|
307
|
+
const NO_CAPS = new Set();
|
|
308
|
+
// Fallback absolute coincidence epsilon for degenerate zero-extent input, where the relative form has
|
|
309
|
+
// nothing to scale against. Well below any realistic flatten tolerance.
|
|
310
|
+
const POINT_EPS = 1e-9;
|
|
311
|
+
// Relative coincidence factor: the point-merge tolerance is this fraction of the input's coordinate
|
|
312
|
+
// extent, so corners collapse consistently whether the contour is in pixels or micrometres.
|
|
313
|
+
const POINT_EPS_RELATIVE = 1e-9;
|
|
314
|
+
// Below this cross-product magnitude the two offset edges are effectively parallel and a miter apex is
|
|
315
|
+
// unstable, so the join degrades to a bevel.
|
|
316
|
+
const PARALLEL_EPS = 1e-12;
|
|
317
|
+
const TWO_PI = Math.PI * 2;
|
|
318
|
+
//# sourceMappingURL=offsetPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offsetPath.js","sourceRoot":"","sources":["../src/offsetPath.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PathBooleanBackend } from '@flighthq/types';
|
|
2
|
+
export declare function createDefaultPathBooleanBackend(): PathBooleanBackend;
|
|
3
|
+
export declare function getPathBooleanBackend(): PathBooleanBackend;
|
|
4
|
+
export declare function setPathBooleanBackend(backend: PathBooleanBackend | null): void;
|
|
5
|
+
//# sourceMappingURL=pathBooleanBackend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathBooleanBackend.d.ts","sourceRoot":"","sources":["../src/pathBooleanBackend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAO1D,wBAAgB,+BAA+B,IAAI,kBAAkB,CAEpE;AAID,wBAAgB,qBAAqB,IAAI,kBAAkB,CAG1D;AAKD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAE9E"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createMartinezPathBooleanBackend } from './martinezKernel';
|
|
2
|
+
// Builds a fresh instance of the default boolean kernel — the from-scratch Martinez–Rueda–Feito
|
|
3
|
+
// sweep-line. Callers that want the built-in behavior without touching the shared module-level backend
|
|
4
|
+
// (for example to run it alongside a swapped-in native kernel) construct one here.
|
|
5
|
+
export function createDefaultPathBooleanBackend() {
|
|
6
|
+
return createMartinezPathBooleanBackend();
|
|
7
|
+
}
|
|
8
|
+
// Returns the active boolean kernel, lazily installing the default Martinez kernel on first use. There
|
|
9
|
+
// is always a backend; the operation functions dispatch through this.
|
|
10
|
+
export function getPathBooleanBackend() {
|
|
11
|
+
if (_backend === null)
|
|
12
|
+
_backend = createDefaultPathBooleanBackend();
|
|
13
|
+
return _backend;
|
|
14
|
+
}
|
|
15
|
+
// Installs a boolean kernel for all subsequent operations, or clears back to the lazy default when
|
|
16
|
+
// passed null. A heavier or faster kernel (a faithful Clipper port, a wasm drop-in) swaps in here
|
|
17
|
+
// without changing the operation API.
|
|
18
|
+
export function setPathBooleanBackend(backend) {
|
|
19
|
+
_backend = backend;
|
|
20
|
+
}
|
|
21
|
+
// The active kernel, or null until the first getPathBooleanBackend call installs the default. Held at
|
|
22
|
+
// module scope but never populated at import time, so importing this package has no side effects.
|
|
23
|
+
let _backend = null;
|
|
24
|
+
//# sourceMappingURL=pathBooleanBackend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pathBooleanBackend.js","sourceRoot":"","sources":["../src/pathBooleanBackend.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gCAAgC,EAAE,MAAM,kBAAkB,CAAC;AAEpE,gGAAgG;AAChG,uGAAuG;AACvG,mFAAmF;AACnF,MAAM,UAAU,+BAA+B;IAC7C,OAAO,gCAAgC,EAAE,CAAC;AAC5C,CAAC;AAED,uGAAuG;AACvG,sEAAsE;AACtE,MAAM,UAAU,qBAAqB;IACnC,IAAI,QAAQ,KAAK,IAAI;QAAE,QAAQ,GAAG,+BAA+B,EAAE,CAAC;IACpE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,mGAAmG;AACnG,kGAAkG;AAClG,sCAAsC;AACtC,MAAM,UAAU,qBAAqB,CAAC,OAAkC;IACtE,QAAQ,GAAG,OAAO,CAAC;AACrB,CAAC;AAED,sGAAsG;AACtG,kGAAkG;AAClG,IAAI,QAAQ,GAA8B,IAAI,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePathRegions.d.ts","sourceRoot":"","sources":["../src/resolvePathRegions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAarF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAW5G"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { appendPathClose, appendPathLineTo, appendPathMoveTo, createPath } from '@flighthq/path';
|
|
2
|
+
import { getPathBooleanBackend } from './pathBooleanBackend';
|
|
3
|
+
// Resolves a set of raw polygon rings into a single clean, valid filled-region `Path` by self-unioning
|
|
4
|
+
// them through the active boolean kernel under `fillRule`, then rebuilding the resolved contours with the
|
|
5
|
+
// path builders. This is the shared "raw rings → clean outline" primitive that both `offsetPath` (feeding
|
|
6
|
+
// the rings it strokes around each contour, always `nonZero`) and `simplifyPath` (feeding a path's own
|
|
7
|
+
// flattened contours under the caller's fill rule) compose over. The kernel dissolves self-overlap, merges
|
|
8
|
+
// touching rings, and traces holes counter-wound to their outer ring, so the rebuilt path is always
|
|
9
|
+
// `nonZero` regardless of the input fill rule. `fillRule` is the kernel-level `PathBooleanFillRule`
|
|
10
|
+
// superset: `simplifyPath` passes the caller's `evenOdd`/`nonZero`, while `offsetPath` passes `positive`
|
|
11
|
+
// for its offset-cleanup fill. An empty ring set yields an empty path (no commands).
|
|
12
|
+
export function resolvePathRegions(rings, fillRule) {
|
|
13
|
+
const path = createPath('nonZero');
|
|
14
|
+
if (rings.length === 0)
|
|
15
|
+
return path;
|
|
16
|
+
const resolved = getPathBooleanBackend().computePathBoolean(rings, EMPTY_CONTOURS, 'union', fillRule);
|
|
17
|
+
for (const ring of resolved) {
|
|
18
|
+
if (ring.length < 6)
|
|
19
|
+
continue;
|
|
20
|
+
appendPathMoveTo(path, ring[0], ring[1]);
|
|
21
|
+
for (let i = 2; i < ring.length; i += 2)
|
|
22
|
+
appendPathLineTo(path, ring[i], ring[i + 1]);
|
|
23
|
+
appendPathClose(path);
|
|
24
|
+
}
|
|
25
|
+
return path;
|
|
26
|
+
}
|
|
27
|
+
const EMPTY_CONTOURS = [];
|
|
28
|
+
//# sourceMappingURL=resolvePathRegions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePathRegions.js","sourceRoot":"","sources":["../src/resolvePathRegions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjG,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,uGAAuG;AACvG,0GAA0G;AAC1G,0GAA0G;AAC1G,uGAAuG;AACvG,2GAA2G;AAC3G,oGAAoG;AACpG,oGAAoG;AACpG,yGAAyG;AACzG,qFAAqF;AACrF,MAAM,UAAU,kBAAkB,CAAC,KAAoC,EAAE,QAA6B;IACpG,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtG,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC9B,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;YAAE,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACtF,eAAe,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,cAAc,GAAkC,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simplifyPath.d.ts","sourceRoot":"","sources":["../src/simplifyPath.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAYhE,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,IAAI,CAI/F"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { flattenPath } from '@flighthq/path';
|
|
2
|
+
import { resolvePathRegions } from './resolvePathRegions';
|
|
3
|
+
// Resolves a single path — possibly self-intersecting, self-overlapping, or holding several contours —
|
|
4
|
+
// into a clean, valid filled-region outline under its fill rule. This is the Clipper `SimplifyPaths` /
|
|
5
|
+
// Skia `Simplify` operation: the path is flattened to polygon contours at `options.tolerance`, then
|
|
6
|
+
// self-unioned through the active boolean kernel under `options.fillRule` (default `nonZero`). The two
|
|
7
|
+
// fill rules diverge on self-overlapping input — a region covered twice with the same winding fills solid
|
|
8
|
+
// under `nonZero` but punches an even-odd hole — which is why the fill rule travels with the operation.
|
|
9
|
+
// Returns a fresh polygon-outline `Path` (holes traced counter-wound to their outer ring); empty or fully
|
|
10
|
+
// degenerate input yields an empty path with no commands.
|
|
11
|
+
export function simplifyPath(path, options) {
|
|
12
|
+
const fillRule = options?.fillRule ?? 'nonZero';
|
|
13
|
+
const contours = flattenPath(path, options?.tolerance);
|
|
14
|
+
return resolvePathRegions(contours, fillRule);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=simplifyPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simplifyPath.js","sourceRoot":"","sources":["../src/simplifyPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,uGAAuG;AACvG,uGAAuG;AACvG,oGAAoG;AACpG,uGAAuG;AACvG,0GAA0G;AAC1G,wGAAwG;AACxG,0GAA0G;AAC1G,0DAA0D;AAC1D,MAAM,UAAU,YAAY,CAAC,IAAoB,EAAE,OAAsC;IACvF,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,SAAS,CAAC;IAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACvD,OAAO,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unionAllPaths.d.ts","sourceRoot":"","sources":["../src/unionAllPaths.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAsB,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAWpF,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,QAAQ,CAAC,IAAI,CAAC,EAAE,EAChC,GAAG,CAAC,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GACrC,IAAI,CAsBN"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { appendPathClose, appendPathLineTo, appendPathMoveTo, createPath, flattenPath } from '@flighthq/path';
|
|
2
|
+
import { getPathBooleanBackend } from './pathBooleanBackend';
|
|
3
|
+
// N-way union of a list of paths into one clean filled-region outline. Every path is flattened to polygon
|
|
4
|
+
// contours at the option tolerance and the whole set is folded together in a single union pass through the
|
|
5
|
+
// active kernel under the fill rule (default `nonZero`), so overlaps merge and holes are preserved exactly
|
|
6
|
+
// as a repeated binary `unionPaths` fold would produce, without the intermediate allocations. The result
|
|
7
|
+
// contours are written into `out` (a fresh `nonZero` path when omitted). An empty list yields an empty
|
|
8
|
+
// path; a single path yields its own self-overlap-resolved region, matching `simplifyPath`. Every input is
|
|
9
|
+
// fully read before `out` is written, so `out` may safely alias any path in the list.
|
|
10
|
+
export function unionAllPaths(paths, out, options) {
|
|
11
|
+
const fillRule = options?.fillRule ?? 'nonZero';
|
|
12
|
+
const contours = [];
|
|
13
|
+
for (const path of paths) {
|
|
14
|
+
for (const contour of flattenPath(path, options?.tolerance))
|
|
15
|
+
contours.push(contour);
|
|
16
|
+
}
|
|
17
|
+
const result = contours.length === 0
|
|
18
|
+
? EMPTY_CONTOURS
|
|
19
|
+
: getPathBooleanBackend().computePathBoolean(contours, EMPTY_CONTOURS, 'union', fillRule);
|
|
20
|
+
const path = out ?? createPath('nonZero');
|
|
21
|
+
path.commands.length = 0;
|
|
22
|
+
path.data.length = 0;
|
|
23
|
+
path.winding = 'nonZero';
|
|
24
|
+
for (const ring of result) {
|
|
25
|
+
if (ring.length < 6)
|
|
26
|
+
continue;
|
|
27
|
+
appendPathMoveTo(path, ring[0], ring[1]);
|
|
28
|
+
for (let i = 2; i < ring.length; i += 2)
|
|
29
|
+
appendPathLineTo(path, ring[i], ring[i + 1]);
|
|
30
|
+
appendPathClose(path);
|
|
31
|
+
}
|
|
32
|
+
return path;
|
|
33
|
+
}
|
|
34
|
+
const EMPTY_CONTOURS = [];
|
|
35
|
+
//# sourceMappingURL=unionAllPaths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unionAllPaths.js","sourceRoot":"","sources":["../src/unionAllPaths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG9G,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,0GAA0G;AAC1G,2GAA2G;AAC3G,2GAA2G;AAC3G,yGAAyG;AACzG,uGAAuG;AACvG,2GAA2G;AAC3G,sFAAsF;AACtF,MAAM,UAAU,aAAa,CAC3B,KAAgC,EAChC,GAAU,EACV,OAAsC;IAEtC,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,SAAS,CAAC;IAChD,MAAM,QAAQ,GAAyB,EAAE,CAAC;IAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,MAAM,GACV,QAAQ,CAAC,MAAM,KAAK,CAAC;QACnB,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,qBAAqB,EAAE,CAAC,kBAAkB,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAE9F,MAAM,IAAI,GAAG,GAAG,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACrB,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;IACzB,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS;QAC9B,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;YAAE,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACtF,eAAe,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,cAAc,GAAkC,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flighthq/path-boolean",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"src/**/*.test.ts",
|
|
16
|
+
"!dist/**/*.test.js",
|
|
17
|
+
"!dist/**/*.test.d.ts",
|
|
18
|
+
"!dist/**/*.test.js.map",
|
|
19
|
+
"!dist/**/*.test.d.ts.map"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc -b",
|
|
23
|
+
"clean": "tsc -b --clean",
|
|
24
|
+
"test": "vitest run --config vitest.config.ts",
|
|
25
|
+
"test:watch": "vitest --watch --config vitest.config.ts",
|
|
26
|
+
"prepack": "npm run clean && npm run clean:dist && npm run build",
|
|
27
|
+
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@flighthq/path": "0.1.0",
|
|
31
|
+
"@flighthq/types": "0.1.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"typescript": "^5.3.0"
|
|
35
|
+
},
|
|
36
|
+
"description": "2D constructive solid geometry boolean operations (union/intersection/difference/xor) for @flighthq/path",
|
|
37
|
+
"sideEffects": false
|
|
38
|
+
}
|