@weasel-js/geom 1.9.4 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/3d/index.js +1 -1
- package/dist/booleans/index.d.ts +44 -29
- package/dist/booleans/index.js +47 -11
- package/dist/booleans/index.js.map +1 -1
- package/dist/{chunk-N5SYTHMR.js → chunk-755Y4YZS.js} +2 -2
- package/dist/chunk-755Y4YZS.js.map +1 -0
- package/dist/{chunk-NL423YYZ.js → chunk-MDT7F32A.js} +4 -4
- package/dist/{chunk-NL423YYZ.js.map → chunk-MDT7F32A.js.map} +1 -1
- package/dist/{chunk-E4TJRGJD.js → chunk-OXH3NOXC.js} +2 -2
- package/dist/chunk-OXH3NOXC.js.map +1 -0
- package/dist/{chunk-X6GJRIQD.js → chunk-WQMYOCFB.js} +16 -4
- package/dist/chunk-WQMYOCFB.js.map +1 -0
- package/dist/{chunk-HPVINMOM.js → chunk-XS6ERH3X.js} +2 -2
- package/dist/chunk-XS6ERH3X.js.map +1 -0
- package/dist/cubicMath-CFXbq6vp.d.ts +116 -0
- package/dist/curves/index.d.ts +1 -1
- package/dist/curves/index.js +2 -2
- package/dist/index.d.ts +572 -116
- package/dist/index.js +876 -97
- package/dist/index.js.map +1 -1
- package/dist/{path-D0CoudGM.d.ts → path-Bf9KeVxC.d.ts} +10 -11
- package/dist/tessellate/index.d.ts +8 -12
- package/dist/tessellate/index.js +22 -5
- package/dist/tessellate/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-E4TJRGJD.js.map +0 -1
- package/dist/chunk-HPVINMOM.js.map +0 -1
- package/dist/chunk-N5SYTHMR.js.map +0 -1
- package/dist/chunk-X6GJRIQD.js.map +0 -1
- package/dist/cubicMath-CpCvuEl8.d.ts +0 -37
package/dist/3d/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PORT_REACH, portControls, portCurvePoints, cubicAt } from '../chunk-YQADYJJ7.js';
|
|
2
2
|
export { PORT_REACH } from '../chunk-YQADYJJ7.js';
|
|
3
|
-
import { SINGULAR_RATIO } from '../chunk-
|
|
3
|
+
import { SINGULAR_RATIO } from '../chunk-755Y4YZS.js';
|
|
4
4
|
|
|
5
5
|
// src/3d/vec3.ts
|
|
6
6
|
function add(a, b) {
|
package/dist/booleans/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as
|
|
2
|
-
import { P as Point } from '../cubicMath-
|
|
1
|
+
import { P as PolygonPath, a as Path } from '../path-Bf9KeVxC.js';
|
|
2
|
+
import { P as Point } from '../cubicMath-CFXbq6vp.js';
|
|
3
3
|
|
|
4
4
|
/** Union of N paths. Commutative. Returns an empty path if all inputs are empty. */
|
|
5
5
|
declare function pathUnion(...paths: Path[]): PolygonPath;
|
|
@@ -9,30 +9,48 @@ declare function pathIntersect(...paths: Path[]): PolygonPath;
|
|
|
9
9
|
declare function pathSubtract(a: Path, b: Path): PolygonPath;
|
|
10
10
|
/** Symmetric difference (XOR) of N paths. Commutative. */
|
|
11
11
|
declare function pathExclude(...paths: Path[]): PolygonPath;
|
|
12
|
+
/** One path of a result that keeps its pieces apart, and the inputs it came
|
|
13
|
+
* from: their indices in the call, ascending, so the last is the topmost of
|
|
14
|
+
* inputs given back to front. */
|
|
15
|
+
interface BooleanPiece {
|
|
16
|
+
path: PolygonPath;
|
|
17
|
+
sources: number[];
|
|
18
|
+
}
|
|
19
|
+
/** {@link pathDividePieces} as bare paths. */
|
|
20
|
+
declare function pathDivide(...paths: Path[]): PolygonPath[];
|
|
21
|
+
/** {@link pathCropPieces} as bare paths. */
|
|
22
|
+
declare function pathCrop(...paths: Path[]): PolygonPath[];
|
|
12
23
|
/**
|
|
13
24
|
* Fracture N paths along every intersection into the maximal set of
|
|
14
|
-
* non-overlapping regions. Returns one
|
|
25
|
+
* non-overlapping regions. Returns one piece per region, naming every input
|
|
26
|
+
* that covers it. For N=2 these are the three Illustrator "Divide" outputs
|
|
27
|
+
* (A−B, B−A, A∩B).
|
|
15
28
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* and no others. By construction the emitted regions are pairwise disjoint
|
|
19
|
-
* and their union equals `pathUnion(A1..AN)`.
|
|
20
|
-
*
|
|
21
|
-
* For N=2 this collapses to the three Illustrator "Divide" outputs
|
|
22
|
-
* (A−B, B−A, A∩B). For N=3 up to 7 regions are emitted. The 2^N − 1
|
|
23
|
-
* subset count limits this to small N in practice; passing more than ~8
|
|
24
|
-
* inputs is a misuse — the polygon-clipping kernel dominates anyway.
|
|
29
|
+
* One region per non-empty subset of the inputs, so the 2^N − 1 subset count
|
|
30
|
+
* limits this to small N; passing more than ~8 inputs is a misuse.
|
|
25
31
|
*/
|
|
26
|
-
declare function
|
|
32
|
+
declare function pathDividePieces(...paths: Path[]): BooleanPiece[];
|
|
27
33
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* Empty results (a source that lies entirely outside the mask) are
|
|
33
|
-
* filtered. With `<2` inputs the result is empty.
|
|
34
|
+
* Remove from each path what the paths after it cover (Illustrator "Trim"):
|
|
35
|
+
* given back to front, every piece is the part of its input left showing.
|
|
36
|
+
* One piece per input in input order, less the inputs wholly hidden.
|
|
34
37
|
*/
|
|
35
|
-
declare function
|
|
38
|
+
declare function pathTrim(...paths: Path[]): BooleanPiece[];
|
|
39
|
+
/**
|
|
40
|
+
* {@link pathTrim}, then unite the pieces of the inputs `keyOf` gives the same
|
|
41
|
+
* key (Illustrator "Merge", keyed by paint). Keys compare with `===`. A piece
|
|
42
|
+
* names every input left showing in it, and the pieces are ordered by their
|
|
43
|
+
* topmost one. Pieces that share a key and do not touch come back as one path
|
|
44
|
+
* of several contours.
|
|
45
|
+
*/
|
|
46
|
+
declare function pathMerge(paths: readonly Path[], keyOf: (index: number) => unknown): BooleanPiece[];
|
|
47
|
+
/**
|
|
48
|
+
* Clip each non-topmost path to the topmost path (Illustrator "Crop"), which
|
|
49
|
+
* acts purely as the mask and is discarded. Returns up to `N - 1` pieces in
|
|
50
|
+
* input order, each naming the one input it was clipped from; a source
|
|
51
|
+
* entirely outside the mask is dropped.
|
|
52
|
+
*/
|
|
53
|
+
declare function pathCropPieces(...paths: Path[]): BooleanPiece[];
|
|
36
54
|
|
|
37
55
|
/**
|
|
38
56
|
* Union the triangles of an indexed mesh (`vertices` as x, y pairs; `indices`
|
|
@@ -74,16 +92,13 @@ interface SplitBySegmentOptions {
|
|
|
74
92
|
*/
|
|
75
93
|
declare function splitPathBySegment(path: Path, a: Point, b: Point, opts?: SplitBySegmentOptions): Path[] | null;
|
|
76
94
|
/**
|
|
77
|
-
* Split `path` along the open polyline `cut` into closed pieces (Knife).
|
|
78
|
-
* freehand cut is a polyline through its samples.
|
|
95
|
+
* Split `path` along the open polyline `cut` into closed pieces (Knife).
|
|
79
96
|
*
|
|
80
97
|
* Only chords the cut crosses end to end are cut: a stretch of the cut that
|
|
81
98
|
* starts or stops inside the fill cuts nothing, and nothing beyond the cut's
|
|
82
|
-
* ends is touched
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* its quadratic and cubic segments; the new edges follow the cut as straight
|
|
86
|
-
* lines, bends included.
|
|
99
|
+
* ends is touched. Curves are split at the crossing parameters by de Casteljau
|
|
100
|
+
* subdivision, so every piece keeps its quadratic and cubic segments; the new
|
|
101
|
+
* edges follow the cut as straight lines, bends included.
|
|
87
102
|
*
|
|
88
103
|
* A loop the cut draws inside the fill, where it crosses its own track, cuts
|
|
89
104
|
* out the region it encloses: that region is returned as its own piece, with
|
|
@@ -91,7 +106,7 @@ declare function splitPathBySegment(path: Path, a: Point, b: Point, opts?: Split
|
|
|
91
106
|
* running through a loop leaves the loop uncut. A closed cut (its last point
|
|
92
107
|
* equal to its first) is one such loop or, where it crosses the boundary, is
|
|
93
108
|
* cut as the chords it makes. Chords that cross each other are cut one after
|
|
94
|
-
* another
|
|
109
|
+
* another.
|
|
95
110
|
*
|
|
96
111
|
* Each connected piece the cut produces is returned as its own path, holes
|
|
97
112
|
* included. Contours the cut misses entirely are returned together as one
|
|
@@ -122,4 +137,4 @@ declare function splitPathByPolyline(path: Path, cut: readonly Point[], opts?: S
|
|
|
122
137
|
*/
|
|
123
138
|
declare function snipPathByPolyline(path: Path, cut: readonly Point[]): Path[] | null;
|
|
124
139
|
|
|
125
|
-
export { type MultiPolygon, type Pair, type PathToMultiPolygonOptions, type Polygon, type Ring, type SplitBySegmentOptions, multiPolygonToPath, pathCrop, pathDivide, pathExclude, pathIntersect, pathSubtract, pathToMultiPolygon, pathUnion, snipPathByPolyline, splitPathByPolyline, splitPathBySegment, trianglesToPath };
|
|
140
|
+
export { type BooleanPiece, type MultiPolygon, type Pair, type PathToMultiPolygonOptions, type Polygon, type Ring, type SplitBySegmentOptions, multiPolygonToPath, pathCrop, pathCropPieces, pathDivide, pathDividePieces, pathExclude, pathIntersect, pathMerge, pathSubtract, pathToMultiPolygon, pathTrim, pathUnion, snipPathByPolyline, splitPathByPolyline, splitPathBySegment, trianglesToPath };
|
package/dist/booleans/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { elevateQuadraticToCubic, splitQuadraticAt, splitCubicAt } from '../chunk-URQMDR6Q.js';
|
|
2
|
-
import { DEFAULT_FLATTEN_TOLERANCE, flattenCubic, segmentsCross, pointInPolygon } from '../chunk-
|
|
3
|
-
import { EPS } from '../chunk-
|
|
4
|
-
import { PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M } from '../chunk-
|
|
2
|
+
import { DEFAULT_FLATTEN_TOLERANCE, fillsOpenSubpaths, flattenCubic, segmentsCross, pointInPolygon } from '../chunk-WQMYOCFB.js';
|
|
3
|
+
import { EPS } from '../chunk-755Y4YZS.js';
|
|
4
|
+
import { PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M } from '../chunk-OXH3NOXC.js';
|
|
5
5
|
import polygonClipping from 'polygon-clipping';
|
|
6
6
|
|
|
7
7
|
// src/booleans/adapter.ts
|
|
@@ -24,7 +24,9 @@ function pathToMultiPolygon(path, opts = {}) {
|
|
|
24
24
|
let startX = 0, startY = 0;
|
|
25
25
|
let ci = 0;
|
|
26
26
|
const { commands, coords } = path;
|
|
27
|
-
const
|
|
27
|
+
const fillsOpen = fillsOpenSubpaths(path);
|
|
28
|
+
const finalizeCurrent = (closed = fillsOpen) => {
|
|
29
|
+
if (!closed) current = null;
|
|
28
30
|
if (!current || current.length === 0) return;
|
|
29
31
|
const first = current[0];
|
|
30
32
|
const last = current[current.length - 1];
|
|
@@ -82,7 +84,7 @@ function pathToMultiPolygon(path, opts = {}) {
|
|
|
82
84
|
break;
|
|
83
85
|
}
|
|
84
86
|
case PATH_Z: {
|
|
85
|
-
finalizeCurrent();
|
|
87
|
+
finalizeCurrent(true);
|
|
86
88
|
cx = startX;
|
|
87
89
|
cy = startY;
|
|
88
90
|
break;
|
|
@@ -235,9 +237,15 @@ function pathExclude(...paths) {
|
|
|
235
237
|
return multiPolygonToPath(polygonClipping.xor(head, ...rest));
|
|
236
238
|
}
|
|
237
239
|
function pathDivide(...paths) {
|
|
240
|
+
return pathDividePieces(...paths).map((p) => p.path);
|
|
241
|
+
}
|
|
242
|
+
function pathCrop(...paths) {
|
|
243
|
+
return pathCropPieces(...paths).map((p) => p.path);
|
|
244
|
+
}
|
|
245
|
+
function pathDividePieces(...paths) {
|
|
238
246
|
if (paths.length === 0) return [];
|
|
239
247
|
if (paths.length === 1) {
|
|
240
|
-
return [multiPolygonToPath(pathToMultiPolygon(paths[0]))];
|
|
248
|
+
return [{ path: multiPolygonToPath(pathToMultiPolygon(paths[0])), sources: [0] }];
|
|
241
249
|
}
|
|
242
250
|
const mps = paths.map((p) => pathToMultiPolygon(p));
|
|
243
251
|
const n = mps.length;
|
|
@@ -248,7 +256,9 @@ function pathDivide(...paths) {
|
|
|
248
256
|
for (const mask of subsets) {
|
|
249
257
|
const inside = [];
|
|
250
258
|
const outside = [];
|
|
259
|
+
const sources = [];
|
|
251
260
|
for (let i = 0; i < n; i++) {
|
|
261
|
+
if (mask & 1 << i) sources.push(i);
|
|
252
262
|
(mask & 1 << i ? inside : outside).push(mps[i]);
|
|
253
263
|
}
|
|
254
264
|
const [insideHead, ...insideRest] = inside;
|
|
@@ -260,10 +270,35 @@ function pathDivide(...paths) {
|
|
|
260
270
|
region = polygonClipping.difference(region, outsideUnion);
|
|
261
271
|
if (region.length === 0) continue;
|
|
262
272
|
}
|
|
263
|
-
out.push(multiPolygonToPath(region));
|
|
273
|
+
out.push({ path: multiPolygonToPath(region), sources });
|
|
274
|
+
}
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
function pathTrim(...paths) {
|
|
278
|
+
const mps = paths.map((p) => pathToMultiPolygon(p));
|
|
279
|
+
const out = [];
|
|
280
|
+
let cover = null;
|
|
281
|
+
for (let i = mps.length - 1; i >= 0; i--) {
|
|
282
|
+
const shown = cover ? polygonClipping.difference(mps[i], cover) : mps[i];
|
|
283
|
+
if (shown.length > 0) out.unshift({ path: multiPolygonToPath(shown), sources: [i] });
|
|
284
|
+
cover = cover ? polygonClipping.union(cover, mps[i]) : mps[i];
|
|
264
285
|
}
|
|
265
286
|
return out;
|
|
266
287
|
}
|
|
288
|
+
function pathMerge(paths, keyOf) {
|
|
289
|
+
const groups = /* @__PURE__ */ new Map();
|
|
290
|
+
for (const piece of pathTrim(...paths)) {
|
|
291
|
+
const key = keyOf(piece.sources[0]);
|
|
292
|
+
const group = groups.get(key);
|
|
293
|
+
if (group) group.push(piece);
|
|
294
|
+
else groups.set(key, [piece]);
|
|
295
|
+
}
|
|
296
|
+
const top = (p) => p.sources[p.sources.length - 1];
|
|
297
|
+
return [...groups.values()].map((g) => g.length === 1 ? g[0] : {
|
|
298
|
+
path: pathUnion(...g.map((p) => p.path)),
|
|
299
|
+
sources: g.map((p) => p.sources[0])
|
|
300
|
+
}).sort((a, b) => top(a) - top(b));
|
|
301
|
+
}
|
|
267
302
|
function popcount(n) {
|
|
268
303
|
let c = 0;
|
|
269
304
|
while (n) {
|
|
@@ -272,14 +307,14 @@ function popcount(n) {
|
|
|
272
307
|
}
|
|
273
308
|
return c;
|
|
274
309
|
}
|
|
275
|
-
function
|
|
310
|
+
function pathCropPieces(...paths) {
|
|
276
311
|
if (paths.length < 2) return [];
|
|
277
312
|
const mps = paths.map((p) => pathToMultiPolygon(p));
|
|
278
313
|
const mask = mps[mps.length - 1];
|
|
279
314
|
const out = [];
|
|
280
315
|
for (let i = 0; i < mps.length - 1; i++) {
|
|
281
316
|
const clipped = polygonClipping.intersection(mps[i], mask);
|
|
282
|
-
if (clipped.length > 0) out.push(multiPolygonToPath(clipped));
|
|
317
|
+
if (clipped.length > 0) out.push({ path: multiPolygonToPath(clipped), sources: [i] });
|
|
283
318
|
}
|
|
284
319
|
return out;
|
|
285
320
|
}
|
|
@@ -475,7 +510,8 @@ function crossingsOnSegment(boundaries, cut, k, out) {
|
|
|
475
510
|
|
|
476
511
|
// src/booleans/contours.ts
|
|
477
512
|
function parseContours(path) {
|
|
478
|
-
|
|
513
|
+
const fillsOpen = path.kind === "rect" || fillsOpenSubpaths(path);
|
|
514
|
+
return parseSubpaths(path).filter((s) => s.closed || fillsOpen).map((s) => s.segs);
|
|
479
515
|
}
|
|
480
516
|
function parseSubpaths(path, implicitClose = true) {
|
|
481
517
|
if (path.kind === "rect") {
|
|
@@ -958,6 +994,6 @@ function snipStations(sub, cut) {
|
|
|
958
994
|
return groups.filter((g) => g.length % 2 === 1).map((g) => g[0]).filter((st) => sub.closed || !same(st.pt, first) && !same(st.pt, end));
|
|
959
995
|
}
|
|
960
996
|
|
|
961
|
-
export { multiPolygonToPath, pathCrop, pathDivide, pathExclude, pathIntersect, pathSubtract, pathToMultiPolygon, pathUnion, snipPathByPolyline, splitPathByPolyline, splitPathBySegment, trianglesToPath };
|
|
997
|
+
export { multiPolygonToPath, pathCrop, pathCropPieces, pathDivide, pathDividePieces, pathExclude, pathIntersect, pathMerge, pathSubtract, pathToMultiPolygon, pathTrim, pathUnion, snipPathByPolyline, splitPathByPolyline, splitPathBySegment, trianglesToPath };
|
|
962
998
|
//# sourceMappingURL=index.js.map
|
|
963
999
|
//# sourceMappingURL=index.js.map
|