@weasel-js/geom 1.4.3 → 1.5.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.
@@ -0,0 +1,70 @@
1
+ /** Three-component vectors and unit quaternions. Immutable tuples throughout:
2
+ * a pose stored in a history snapshot must not be writable through the value
3
+ * handed to a renderer. */
4
+ type Vec3 = readonly [number, number, number];
5
+ /** `[x, y, z, w]`, w last — the layout three.js and glMatrix both use. */
6
+ type Quat = readonly [number, number, number, number];
7
+ declare function add(a: Vec3, b: Vec3): Vec3;
8
+ declare function sub(a: Vec3, b: Vec3): Vec3;
9
+ declare function scale(a: Vec3, k: number): Vec3;
10
+ declare function dot(a: Vec3, b: Vec3): number;
11
+ declare function cross(a: Vec3, b: Vec3): Vec3;
12
+ /** Squared length. Compare distances with this and skip the square root. */
13
+ declare function len2(a: Vec3): number;
14
+ declare function len(a: Vec3): number;
15
+ /** A vector with no length, or no finite one, normalizes to the zero vector
16
+ * rather than to `NaN`. Every other vector keeps its direction, however short. */
17
+ declare function normalize(a: Vec3): Vec3;
18
+ declare function quatIdentity(): Quat;
19
+ declare function quatFromAxisAngle(axis: Vec3, angle: number): Quat;
20
+
21
+ /** 4x4 matrices in GL's column-major order: element (row `r`, column `c`) is
22
+ * `m[c * 4 + r]`, which is the layout `gl.uniformMatrix4fv` reads without a
23
+ * transpose and the one three.js `toArray()` emits. */
24
+
25
+ /** 16 numbers, column-major. */
26
+ type Mat4 = readonly number[];
27
+ declare function identity(): Mat4;
28
+ declare function multiply(a: Mat4, b: Mat4): Mat4;
29
+ /** `[x, y, z, w]` in whatever space `m` maps into — clip space, when `m` is a view-projection. */
30
+ declare function transformPoint4(m: Mat4, p: Vec3): readonly [number, number, number, number];
31
+ /** `transformPoint4` divided through by w, however small. A point on the eye
32
+ * plane (w = 0) comes back non-finite. */
33
+ declare function transformPoint(m: Mat4, p: Vec3): Vec3;
34
+ /** Inverse, or null when the matrix is singular, non-finite, or too
35
+ * ill-conditioned to invert meaningfully at its own scale. */
36
+ declare function invert(m: Mat4): Mat4 | null;
37
+ declare function compose(position: Vec3, rotation: Quat, scaling: Vec3): Mat4;
38
+ declare function perspective(fovY: number, aspect: number, near: number, far: number): Mat4;
39
+ /** A view from `eye` toward `target`. With the eye on its target, or `up`
40
+ * parallel to the view to within rounding, the view has no orientation and
41
+ * the result is singular. */
42
+ declare function lookAt(eye: Vec3, target: Vec3, up: Vec3): Mat4;
43
+
44
+ /** Rays, axis-aligned boxes, and the intersections picking is built from. */
45
+
46
+ interface Ray {
47
+ origin: Vec3;
48
+ direction: Vec3;
49
+ }
50
+ /** An axis-aligned box. `min` is componentwise <= `max`. */
51
+ interface Aabb {
52
+ min: Vec3;
53
+ max: Vec3;
54
+ }
55
+ /** Distance along the ray to the box, or null. A ray starting inside returns 0. */
56
+ declare function intersectRayAabb(ray: Ray, min: Vec3, max: Vec3): number | null;
57
+ /** Plane is `dot(normal, p) === offset`. Null when the ray runs parallel to the
58
+ * plane to within rounding, or points away from it. */
59
+ declare function intersectRayPlane(ray: Ray, normal: Vec3, offset: number): number | null;
60
+ /**
61
+ * The axis-aligned box enclosing `local` after `m`. All eight corners are
62
+ * transformed and re-bounded, so a rotation widens the result rather than
63
+ * rotating it — an AABB cannot represent an oriented box, and pretending
64
+ * otherwise is how a hit test starts missing its own geometry.
65
+ */
66
+ declare function transformAabb(m: Mat4, local: Aabb): Aabb;
67
+ /** The box centred on `center` reaching `radius` along every axis. */
68
+ declare function aabbAround(center: Vec3, radius: number): Aabb;
69
+
70
+ export { type Aabb, type Mat4, type Quat, type Ray, type Vec3, aabbAround, add, compose, cross, dot, identity, intersectRayAabb, intersectRayPlane, invert, len, len2, lookAt, multiply, normalize, perspective, quatFromAxisAngle, quatIdentity, scale, sub, transformAabb, transformPoint, transformPoint4 };
@@ -0,0 +1,258 @@
1
+ import { SINGULAR_RATIO } from '../chunk-NHMWNQTE.js';
2
+
3
+ // src/3d/vec3.ts
4
+ function add(a, b) {
5
+ return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
6
+ }
7
+ function sub(a, b) {
8
+ return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
9
+ }
10
+ function scale(a, k) {
11
+ return [a[0] * k, a[1] * k, a[2] * k];
12
+ }
13
+ function dot(a, b) {
14
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
15
+ }
16
+ function cross(a, b) {
17
+ return [
18
+ a[1] * b[2] - a[2] * b[1],
19
+ a[2] * b[0] - a[0] * b[2],
20
+ a[0] * b[1] - a[1] * b[0]
21
+ ];
22
+ }
23
+ function len2(a) {
24
+ return dot(a, a);
25
+ }
26
+ function len(a) {
27
+ return Math.sqrt(len2(a));
28
+ }
29
+ function normalize(a) {
30
+ const l = len(a);
31
+ return l > 0 && l < Infinity ? scale(a, 1 / l) : [0, 0, 0];
32
+ }
33
+ function quatIdentity() {
34
+ return [0, 0, 0, 1];
35
+ }
36
+ function quatFromAxisAngle(axis, angle) {
37
+ const a = normalize(axis);
38
+ const half = angle / 2;
39
+ const s = Math.sin(half);
40
+ return [a[0] * s, a[1] * s, a[2] * s, Math.cos(half)];
41
+ }
42
+
43
+ // src/3d/mat4.ts
44
+ function identity() {
45
+ return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
46
+ }
47
+ function multiply(a, b) {
48
+ const out = new Array(16);
49
+ for (let c = 0; c < 4; c++) {
50
+ for (let r = 0; r < 4; r++) {
51
+ let sum = 0;
52
+ for (let k = 0; k < 4; k++) sum += a[k * 4 + r] * b[c * 4 + k];
53
+ out[c * 4 + r] = sum;
54
+ }
55
+ }
56
+ return out;
57
+ }
58
+ function transformPoint4(m, p) {
59
+ const [x, y, z] = p;
60
+ return [
61
+ m[0] * x + m[4] * y + m[8] * z + m[12],
62
+ m[1] * x + m[5] * y + m[9] * z + m[13],
63
+ m[2] * x + m[6] * y + m[10] * z + m[14],
64
+ m[3] * x + m[7] * y + m[11] * z + m[15]
65
+ ];
66
+ }
67
+ function transformPoint(m, p) {
68
+ const [x, y, z, w] = transformPoint4(m, p);
69
+ if (w === 1) return [x, y, z];
70
+ return [x / w, y / w, z / w];
71
+ }
72
+ function invert(m) {
73
+ const [
74
+ m00,
75
+ m01,
76
+ m02,
77
+ m03,
78
+ m10,
79
+ m11,
80
+ m12,
81
+ m13,
82
+ m20,
83
+ m21,
84
+ m22,
85
+ m23,
86
+ m30,
87
+ m31,
88
+ m32,
89
+ m33
90
+ ] = m;
91
+ const b00 = m00 * m11 - m01 * m10;
92
+ const b01 = m00 * m12 - m02 * m10;
93
+ const b02 = m00 * m13 - m03 * m10;
94
+ const b03 = m01 * m12 - m02 * m11;
95
+ const b04 = m01 * m13 - m03 * m11;
96
+ const b05 = m02 * m13 - m03 * m12;
97
+ const b06 = m20 * m31 - m21 * m30;
98
+ const b07 = m20 * m32 - m22 * m30;
99
+ const b08 = m20 * m33 - m23 * m30;
100
+ const b09 = m21 * m32 - m22 * m31;
101
+ const b10 = m21 * m33 - m23 * m31;
102
+ const b11 = m22 * m33 - m23 * m32;
103
+ const det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
104
+ const scale2 = Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02 + m03 * m03) * Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12 + m13 * m13) * Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22 + m23 * m23) * Math.sqrt(m30 * m30 + m31 * m31 + m32 * m32 + m33 * m33);
105
+ if (!(Math.abs(det) > SINGULAR_RATIO * scale2)) return null;
106
+ const d = 1 / det;
107
+ return [
108
+ (m11 * b11 - m12 * b10 + m13 * b09) * d,
109
+ (m02 * b10 - m01 * b11 - m03 * b09) * d,
110
+ (m31 * b05 - m32 * b04 + m33 * b03) * d,
111
+ (m22 * b04 - m21 * b05 - m23 * b03) * d,
112
+ (m12 * b08 - m10 * b11 - m13 * b07) * d,
113
+ (m00 * b11 - m02 * b08 + m03 * b07) * d,
114
+ (m32 * b02 - m30 * b05 - m33 * b01) * d,
115
+ (m20 * b05 - m22 * b02 + m23 * b01) * d,
116
+ (m10 * b10 - m11 * b08 + m13 * b06) * d,
117
+ (m01 * b08 - m00 * b10 - m03 * b06) * d,
118
+ (m30 * b04 - m31 * b02 + m33 * b00) * d,
119
+ (m21 * b02 - m20 * b04 - m23 * b00) * d,
120
+ (m11 * b07 - m10 * b09 - m12 * b06) * d,
121
+ (m00 * b09 - m01 * b07 + m02 * b06) * d,
122
+ (m31 * b01 - m30 * b03 - m32 * b00) * d,
123
+ (m20 * b03 - m21 * b01 + m22 * b00) * d
124
+ ];
125
+ }
126
+ function compose(position, rotation, scaling) {
127
+ const [x, y, z, w] = rotation;
128
+ const x2 = x + x;
129
+ const y2 = y + y;
130
+ const z2 = z + z;
131
+ const xx = x * x2;
132
+ const xy = x * y2;
133
+ const xz = x * z2;
134
+ const yy = y * y2;
135
+ const yz = y * z2;
136
+ const zz = z * z2;
137
+ const wx = w * x2;
138
+ const wy = w * y2;
139
+ const wz = w * z2;
140
+ const [sx, sy, sz] = scaling;
141
+ return [
142
+ (1 - (yy + zz)) * sx,
143
+ (xy + wz) * sx,
144
+ (xz - wy) * sx,
145
+ 0,
146
+ (xy - wz) * sy,
147
+ (1 - (xx + zz)) * sy,
148
+ (yz + wx) * sy,
149
+ 0,
150
+ (xz + wy) * sz,
151
+ (yz - wx) * sz,
152
+ (1 - (xx + yy)) * sz,
153
+ 0,
154
+ position[0],
155
+ position[1],
156
+ position[2],
157
+ 1
158
+ ];
159
+ }
160
+ function perspective(fovY, aspect, near, far) {
161
+ const f = 1 / Math.tan(fovY / 2);
162
+ const range = near - far;
163
+ return [
164
+ f / aspect,
165
+ 0,
166
+ 0,
167
+ 0,
168
+ 0,
169
+ f,
170
+ 0,
171
+ 0,
172
+ 0,
173
+ 0,
174
+ (far + near) / range,
175
+ -1,
176
+ 0,
177
+ 0,
178
+ 2 * far * near / range,
179
+ 0
180
+ ];
181
+ }
182
+ function lookAt(eye, target, up) {
183
+ const back = normalize(sub(eye, target));
184
+ const side = cross(up, back);
185
+ const right = len(side) > SINGULAR_RATIO * len(up) ? normalize(side) : [0, 0, 0];
186
+ const trueUp = cross(back, right);
187
+ return [
188
+ right[0],
189
+ trueUp[0],
190
+ back[0],
191
+ 0,
192
+ right[1],
193
+ trueUp[1],
194
+ back[1],
195
+ 0,
196
+ right[2],
197
+ trueUp[2],
198
+ back[2],
199
+ 0,
200
+ -dot(right, eye),
201
+ -dot(trueUp, eye),
202
+ -dot(back, eye),
203
+ 1
204
+ ];
205
+ }
206
+
207
+ // src/3d/ray3.ts
208
+ function intersectRayAabb(ray, min, max) {
209
+ let tMin = Number.NEGATIVE_INFINITY;
210
+ let tMax = Number.POSITIVE_INFINITY;
211
+ for (let axis = 0; axis < 3; axis++) {
212
+ const o = ray.origin[axis];
213
+ const d = ray.direction[axis];
214
+ if (d === 0) {
215
+ if (o < min[axis] || o > max[axis]) return null;
216
+ continue;
217
+ }
218
+ let t1 = (min[axis] - o) / d;
219
+ let t2 = (max[axis] - o) / d;
220
+ if (t1 > t2) [t1, t2] = [t2, t1];
221
+ if (t1 > tMin) tMin = t1;
222
+ if (t2 < tMax) tMax = t2;
223
+ if (tMin > tMax) return null;
224
+ }
225
+ if (tMax < 0) return null;
226
+ return tMin < 0 ? 0 : tMin;
227
+ }
228
+ function intersectRayPlane(ray, normal, offset) {
229
+ const denom = dot(normal, ray.direction);
230
+ if (!(Math.abs(denom) > SINGULAR_RATIO * len(normal) * len(ray.direction))) return null;
231
+ const t = (offset - dot(normal, ray.origin)) / denom;
232
+ return t < 0 ? null : t;
233
+ }
234
+ function transformAabb(m, local) {
235
+ let min = [Infinity, Infinity, Infinity];
236
+ let max = [-Infinity, -Infinity, -Infinity];
237
+ for (let i = 0; i < 8; i++) {
238
+ const corner = [
239
+ i & 1 ? local.max[0] : local.min[0],
240
+ i & 2 ? local.max[1] : local.min[1],
241
+ i & 4 ? local.max[2] : local.min[2]
242
+ ];
243
+ const p = transformPoint(m, corner);
244
+ min = [Math.min(min[0], p[0]), Math.min(min[1], p[1]), Math.min(min[2], p[2])];
245
+ max = [Math.max(max[0], p[0]), Math.max(max[1], p[1]), Math.max(max[2], p[2])];
246
+ }
247
+ return { min, max };
248
+ }
249
+ function aabbAround(center, radius) {
250
+ return {
251
+ min: [center[0] - radius, center[1] - radius, center[2] - radius],
252
+ max: [center[0] + radius, center[1] + radius, center[2] + radius]
253
+ };
254
+ }
255
+
256
+ export { aabbAround, add, compose, cross, dot, identity, intersectRayAabb, intersectRayPlane, invert, len, len2, lookAt, multiply, normalize, perspective, quatFromAxisAngle, quatIdentity, scale, sub, transformAabb, transformPoint, transformPoint4 };
257
+ //# sourceMappingURL=index.js.map
258
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/3d/vec3.ts","../../src/3d/mat4.ts","../../src/3d/ray3.ts"],"names":["scale"],"mappings":"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","file":"index.js","sourcesContent":["/** Three-component vectors and unit quaternions. Immutable tuples throughout:\n * a pose stored in a history snapshot must not be writable through the value\n * handed to a renderer. */\n\nexport type Vec3 = readonly [number, number, number];\n/** `[x, y, z, w]`, w last — the layout three.js and glMatrix both use. */\nexport type Quat = readonly [number, number, number, number];\n\nexport function add(a: Vec3, b: Vec3): Vec3 {\n return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];\n}\n\nexport function sub(a: Vec3, b: Vec3): Vec3 {\n return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];\n}\n\nexport function scale(a: Vec3, k: number): Vec3 {\n return [a[0] * k, a[1] * k, a[2] * k];\n}\n\nexport function dot(a: Vec3, b: Vec3): number {\n return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];\n}\n\nexport function cross(a: Vec3, b: Vec3): Vec3 {\n return [\n a[1] * b[2] - a[2] * b[1],\n a[2] * b[0] - a[0] * b[2],\n a[0] * b[1] - a[1] * b[0],\n ];\n}\n\n/** Squared length. Compare distances with this and skip the square root. */\nexport function len2(a: Vec3): number {\n return dot(a, a);\n}\n\nexport function len(a: Vec3): number {\n return Math.sqrt(len2(a));\n}\n\n/** A vector with no length, or no finite one, normalizes to the zero vector\n * rather than to `NaN`. Every other vector keeps its direction, however short. */\nexport function normalize(a: Vec3): Vec3 {\n const l = len(a);\n return l > 0 && l < Infinity ? scale(a, 1 / l) : [0, 0, 0];\n}\n\nexport function quatIdentity(): Quat {\n return [0, 0, 0, 1];\n}\n\nexport function quatFromAxisAngle(axis: Vec3, angle: number): Quat {\n const a = normalize(axis);\n const half = angle / 2;\n const s = Math.sin(half);\n return [a[0] * s, a[1] * s, a[2] * s, Math.cos(half)];\n}\n","/** 4x4 matrices in GL's column-major order: element (row `r`, column `c`) is\n * `m[c * 4 + r]`, which is the layout `gl.uniformMatrix4fv` reads without a\n * transpose and the one three.js `toArray()` emits. */\n\nimport { SINGULAR_RATIO } from '../scalar';\nimport { cross, dot, len, normalize, sub, type Quat, type Vec3 } from './vec3';\n\n/** 16 numbers, column-major. */\nexport type Mat4 = readonly number[];\n\nexport function identity(): Mat4 {\n return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];\n}\n\nexport function multiply(a: Mat4, b: Mat4): Mat4 {\n const out = new Array<number>(16);\n for (let c = 0; c < 4; c++) {\n for (let r = 0; r < 4; r++) {\n let sum = 0;\n for (let k = 0; k < 4; k++) sum += a[k * 4 + r] * b[c * 4 + k];\n out[c * 4 + r] = sum;\n }\n }\n return out;\n}\n\n/** `[x, y, z, w]` in whatever space `m` maps into — clip space, when `m` is a view-projection. */\nexport function transformPoint4(\n m: Mat4,\n p: Vec3,\n): readonly [number, number, number, number] {\n const [x, y, z] = p;\n return [\n m[0] * x + m[4] * y + m[8] * z + m[12],\n m[1] * x + m[5] * y + m[9] * z + m[13],\n m[2] * x + m[6] * y + m[10] * z + m[14],\n m[3] * x + m[7] * y + m[11] * z + m[15],\n ];\n}\n\n/** `transformPoint4` divided through by w, however small. A point on the eye\n * plane (w = 0) comes back non-finite. */\nexport function transformPoint(m: Mat4, p: Vec3): Vec3 {\n const [x, y, z, w] = transformPoint4(m, p);\n if (w === 1) return [x, y, z];\n return [x / w, y / w, z / w];\n}\n\n/** Inverse, or null when the matrix is singular, non-finite, or too\n * ill-conditioned to invert meaningfully at its own scale. */\nexport function invert(m: Mat4): Mat4 | null {\n const [\n m00, m01, m02, m03,\n m10, m11, m12, m13,\n m20, m21, m22, m23,\n m30, m31, m32, m33,\n ] = m;\n\n const b00 = m00 * m11 - m01 * m10;\n const b01 = m00 * m12 - m02 * m10;\n const b02 = m00 * m13 - m03 * m10;\n const b03 = m01 * m12 - m02 * m11;\n const b04 = m01 * m13 - m03 * m11;\n const b05 = m02 * m13 - m03 * m12;\n const b06 = m20 * m31 - m21 * m30;\n const b07 = m20 * m32 - m22 * m30;\n const b08 = m20 * m33 - m23 * m30;\n const b09 = m21 * m32 - m22 * m31;\n const b10 = m21 * m33 - m23 * m31;\n const b11 = m22 * m33 - m23 * m32;\n\n const det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;\n // Hadamard: |det| never exceeds the product of the column lengths, so the\n // ratio is a volume in [0, 1] that no per-column scale can shrink.\n const scale =\n Math.sqrt(m00 * m00 + m01 * m01 + m02 * m02 + m03 * m03) *\n Math.sqrt(m10 * m10 + m11 * m11 + m12 * m12 + m13 * m13) *\n Math.sqrt(m20 * m20 + m21 * m21 + m22 * m22 + m23 * m23) *\n Math.sqrt(m30 * m30 + m31 * m31 + m32 * m32 + m33 * m33);\n // Negated so a non-finite determinant falls out as singular.\n if (!(Math.abs(det) > SINGULAR_RATIO * scale)) return null;\n const d = 1 / det;\n\n return [\n (m11 * b11 - m12 * b10 + m13 * b09) * d,\n (m02 * b10 - m01 * b11 - m03 * b09) * d,\n (m31 * b05 - m32 * b04 + m33 * b03) * d,\n (m22 * b04 - m21 * b05 - m23 * b03) * d,\n (m12 * b08 - m10 * b11 - m13 * b07) * d,\n (m00 * b11 - m02 * b08 + m03 * b07) * d,\n (m32 * b02 - m30 * b05 - m33 * b01) * d,\n (m20 * b05 - m22 * b02 + m23 * b01) * d,\n (m10 * b10 - m11 * b08 + m13 * b06) * d,\n (m01 * b08 - m00 * b10 - m03 * b06) * d,\n (m30 * b04 - m31 * b02 + m33 * b00) * d,\n (m21 * b02 - m20 * b04 - m23 * b00) * d,\n (m11 * b07 - m10 * b09 - m12 * b06) * d,\n (m00 * b09 - m01 * b07 + m02 * b06) * d,\n (m31 * b01 - m30 * b03 - m32 * b00) * d,\n (m20 * b03 - m21 * b01 + m22 * b00) * d,\n ];\n}\n\nexport function compose(position: Vec3, rotation: Quat, scaling: Vec3): Mat4 {\n const [x, y, z, w] = rotation;\n const x2 = x + x;\n const y2 = y + y;\n const z2 = z + z;\n const xx = x * x2;\n const xy = x * y2;\n const xz = x * z2;\n const yy = y * y2;\n const yz = y * z2;\n const zz = z * z2;\n const wx = w * x2;\n const wy = w * y2;\n const wz = w * z2;\n const [sx, sy, sz] = scaling;\n\n return [\n (1 - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0,\n (xy - wz) * sy, (1 - (xx + zz)) * sy, (yz + wx) * sy, 0,\n (xz + wy) * sz, (yz - wx) * sz, (1 - (xx + yy)) * sz, 0,\n position[0], position[1], position[2], 1,\n ];\n}\n\nexport function perspective(fovY: number, aspect: number, near: number, far: number): Mat4 {\n const f = 1 / Math.tan(fovY / 2);\n const range = near - far;\n return [\n f / aspect, 0, 0, 0,\n 0, f, 0, 0,\n 0, 0, (far + near) / range, -1,\n 0, 0, (2 * far * near) / range, 0,\n ];\n}\n\n/** A view from `eye` toward `target`. With the eye on its target, or `up`\n * parallel to the view to within rounding, the view has no orientation and\n * the result is singular. */\nexport function lookAt(eye: Vec3, target: Vec3, up: Vec3): Mat4 {\n const back = normalize(sub(eye, target));\n const side = cross(up, back);\n // |side| is |up| times the sine of the angle between up and the view.\n const right = len(side) > SINGULAR_RATIO * len(up) ? normalize(side) : ([0, 0, 0] as const);\n const trueUp = cross(back, right);\n return [\n right[0], trueUp[0], back[0], 0,\n right[1], trueUp[1], back[1], 0,\n right[2], trueUp[2], back[2], 0,\n -dot(right, eye), -dot(trueUp, eye), -dot(back, eye), 1,\n ];\n}\n","/** Rays, axis-aligned boxes, and the intersections picking is built from. */\n\nimport { SINGULAR_RATIO } from '../scalar';\nimport { dot, len, type Vec3 } from './vec3';\nimport { transformPoint, type Mat4 } from './mat4';\n\nexport interface Ray {\n origin: Vec3;\n direction: Vec3;\n}\n\n/** An axis-aligned box. `min` is componentwise <= `max`. */\nexport interface Aabb {\n min: Vec3;\n max: Vec3;\n}\n\n/** Distance along the ray to the box, or null. A ray starting inside returns 0. */\nexport function intersectRayAabb(ray: Ray, min: Vec3, max: Vec3): number | null {\n let tMin = Number.NEGATIVE_INFINITY;\n let tMax = Number.POSITIVE_INFINITY;\n\n for (let axis = 0; axis < 3; axis++) {\n const o = ray.origin[axis];\n const d = ray.direction[axis];\n // Any other direction, however short, divides to an honest (possibly infinite) t.\n if (d === 0) {\n if (o < min[axis] || o > max[axis]) return null;\n continue;\n }\n let t1 = (min[axis] - o) / d;\n let t2 = (max[axis] - o) / d;\n if (t1 > t2) [t1, t2] = [t2, t1];\n if (t1 > tMin) tMin = t1;\n if (t2 < tMax) tMax = t2;\n if (tMin > tMax) return null;\n }\n\n if (tMax < 0) return null;\n return tMin < 0 ? 0 : tMin;\n}\n\n/** Plane is `dot(normal, p) === offset`. Null when the ray runs parallel to the\n * plane to within rounding, or points away from it. */\nexport function intersectRayPlane(ray: Ray, normal: Vec3, offset: number): number | null {\n const denom = dot(normal, ray.direction);\n if (!(Math.abs(denom) > SINGULAR_RATIO * len(normal) * len(ray.direction))) return null;\n const t = (offset - dot(normal, ray.origin)) / denom;\n return t < 0 ? null : t;\n}\n\n/**\n * The axis-aligned box enclosing `local` after `m`. All eight corners are\n * transformed and re-bounded, so a rotation widens the result rather than\n * rotating it — an AABB cannot represent an oriented box, and pretending\n * otherwise is how a hit test starts missing its own geometry.\n */\nexport function transformAabb(m: Mat4, local: Aabb): Aabb {\n let min: Vec3 = [Infinity, Infinity, Infinity];\n let max: Vec3 = [-Infinity, -Infinity, -Infinity];\n for (let i = 0; i < 8; i++) {\n const corner: Vec3 = [\n i & 1 ? local.max[0] : local.min[0],\n i & 2 ? local.max[1] : local.min[1],\n i & 4 ? local.max[2] : local.min[2],\n ];\n const p = transformPoint(m, corner);\n min = [Math.min(min[0], p[0]), Math.min(min[1], p[1]), Math.min(min[2], p[2])];\n max = [Math.max(max[0], p[0]), Math.max(max[1], p[1]), Math.max(max[2], p[2])];\n }\n return { min, max };\n}\n\n/** The box centred on `center` reaching `radius` along every axis. */\nexport function aabbAround(center: Vec3, radius: number): Aabb {\n return {\n min: [center[0] - radius, center[1] - radius, center[2] - radius],\n max: [center[0] + radius, center[1] + radius, center[2] + radius],\n };\n}\n"]}
@@ -12,6 +12,18 @@ type GeomPath = {
12
12
  coords: ArrayLike<number>;
13
13
  fillRule?: 'nonzero' | 'evenodd';
14
14
  };
15
+ /** A `[x, y]` 2-tuple. */
16
+ type Pair = [number, number];
17
+ /** Closed ring (first vertex repeated as last). */
18
+ type Ring = Pair[];
19
+ /** Polygon: one outer ring optionally followed by hole rings. */
20
+ type Polygon = Ring[];
21
+ /** MultiPolygon: list of polygons (used for boolean op I/O). */
22
+ type MultiPolygon = Polygon[];
23
+ interface PathToMultiPolygonOptions {
24
+ /** Flattening tolerance for bezier segments. Default: `DEFAULT_FLATTEN_TOLERANCE`. */
25
+ tolerance?: number;
26
+ }
15
27
  /** Polygon result shape emitted by `multiPolygonToPath`. */
16
28
  type GeomPolygonPath = {
17
29
  kind: 'polygon';
@@ -19,6 +31,10 @@ type GeomPolygonPath = {
19
31
  coords: Float32Array;
20
32
  fillRule: 'nonzero';
21
33
  };
34
+ /** Convert a `GeomPath` to a `MultiPolygon` suitable for `polygon-clipping`. */
35
+ declare function pathToMultiPolygon(path: GeomPath, opts?: PathToMultiPolygonOptions): MultiPolygon;
36
+ /** Convert a `MultiPolygon` to a polygon path with `fillRule: 'nonzero'`. */
37
+ declare function multiPolygonToPath(mp: MultiPolygon): GeomPolygonPath;
22
38
 
23
39
  /** Union of N paths. Commutative. Returns an empty path if all inputs are empty. */
24
40
  declare function pathUnion(...paths: GeomPath[]): GeomPolygonPath;
@@ -43,5 +59,14 @@ declare function pathExclude(...paths: GeomPath[]): GeomPolygonPath;
43
59
  * inputs is a misuse — the polygon-clipping kernel dominates anyway.
44
60
  */
45
61
  declare function pathDivide(...paths: GeomPath[]): GeomPolygonPath[];
62
+ /**
63
+ * Clip each non-topmost path to the topmost path (Illustrator "Crop").
64
+ * Returns `N - 1` results, one per source-below-top, in input order.
65
+ * Discards the topmost path itself — it acts purely as the clipping mask.
66
+ *
67
+ * Empty results (a source that lies entirely outside the mask) are
68
+ * filtered. With `<2` inputs the result is empty.
69
+ */
70
+ declare function pathCrop(...paths: GeomPath[]): GeomPolygonPath[];
46
71
 
47
- export { type GeomPath, type GeomPolygonPath, pathDivide, pathExclude, pathIntersect, pathSubtract, pathUnion };
72
+ export { type GeomPath, type GeomPolygonPath, type MultiPolygon, type Pair, type PathToMultiPolygonOptions, type Polygon, type Ring, multiPolygonToPath, pathCrop, pathDivide, pathExclude, pathIntersect, pathSubtract, pathToMultiPolygon, pathUnion };
@@ -1,4 +1,4 @@
1
- import { PATH_M, PATH_L, PATH_Z, PATH_Q, elevateQuadraticToCubic, flattenCubic, PATH_C } from '../chunk-RVQRBX6I.js';
1
+ import { PATH_Z, PATH_Q, elevateQuadraticToCubic, flattenCubic, PATH_C, PATH_L, PATH_M } from '../chunk-DQ6QRAWP.js';
2
2
  import polygonClipping from 'polygon-clipping';
3
3
 
4
4
  // src/booleans/adapter.ts
@@ -83,52 +83,89 @@ function pathToMultiPolygon(path, opts = {}) {
83
83
  }
84
84
  finalizeCurrent();
85
85
  if (rings.length === 0) return [];
86
- return nestRings(rings, path.fillRule ?? "nonzero");
86
+ return groupRings(rings, path.fillRule ?? "nonzero");
87
87
  }
88
- function doubleSignedArea(ring) {
88
+ function ringSignedArea(ring) {
89
89
  let a = 0;
90
90
  for (let i = 0, n = ring.length - 1; i < n; i++) {
91
91
  a += ring[i][0] * ring[i + 1][1] - ring[i + 1][0] * ring[i][1];
92
92
  }
93
- return a;
93
+ return a * 0.5;
94
+ }
95
+ function ringBox(ring) {
96
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
97
+ for (const [x, y] of ring) {
98
+ if (x < minX) minX = x;
99
+ if (x > maxX) maxX = x;
100
+ if (y < minY) minY = y;
101
+ if (y > maxY) maxY = y;
102
+ }
103
+ return [minX, minY, maxX, maxY];
94
104
  }
95
105
  function pointInRing(ring, px, py) {
96
106
  let inside = false;
97
- for (let i = 0, j = ring.length - 2, n = ring.length - 1; i < n; j = i++) {
98
- const [xi, yi] = ring[i];
99
- const [xj, yj] = ring[j];
100
- if (yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi) + xi) {
107
+ for (let i = 0, n = ring.length - 1; i < n; i++) {
108
+ const [ax, ay] = ring[i];
109
+ const [bx, by] = ring[i + 1];
110
+ if (ay > py !== by > py && px < (bx - ax) * (py - ay) / (by - ay) + ax) {
101
111
  inside = !inside;
102
112
  }
103
113
  }
104
114
  return inside;
105
115
  }
106
- function nestRings(rings, fillRule) {
116
+ function ringContains(outer, outerBox, inner, innerBox) {
117
+ if (innerBox[0] < outerBox[0] || innerBox[1] < outerBox[1] || innerBox[2] > outerBox[2] || innerBox[3] > outerBox[3]) return false;
118
+ const n = inner.length - 1;
119
+ let votes = 0;
120
+ for (const k of [0, Math.floor(n / 3), Math.floor(2 * n / 3)]) {
121
+ if (pointInRing(outer, inner[k][0], inner[k][1])) votes++;
122
+ }
123
+ return votes >= 2;
124
+ }
125
+ function groupRings(rings, fillRule) {
107
126
  const n = rings.length;
108
127
  if (n === 1) return [[rings[0]]];
109
- const areas = rings.map(doubleSignedArea);
110
- const probes = rings.map((r) => [(r[0][0] + r[1][0]) / 2, (r[0][1] + r[1][1]) / 2]);
111
- const containers = rings.map(() => []);
128
+ const boxes = rings.map(ringBox);
129
+ const orient = rings.map((r) => ringSignedArea(r) >= 0 ? 1 : -1);
130
+ const parent = new Array(n).fill(-1);
131
+ const children = rings.map(() => []);
112
132
  for (let i = 0; i < n; i++) {
133
+ let best = -1;
134
+ let bestArea = Infinity;
113
135
  for (let j = 0; j < n; j++) {
114
- if (i !== j && pointInRing(rings[j], probes[i][0], probes[i][1])) containers[i].push(j);
136
+ if (i === j) continue;
137
+ if (!ringContains(rings[j], boxes[j], rings[i], boxes[i])) continue;
138
+ const area = (boxes[j][2] - boxes[j][0]) * (boxes[j][3] - boxes[j][1]);
139
+ if (area < bestArea) {
140
+ bestArea = area;
141
+ best = j;
142
+ }
143
+ }
144
+ parent[i] = best;
145
+ }
146
+ for (let i = 0; i < n; i++) if (parent[i] >= 0) children[parent[i]].push(i);
147
+ const filled = new Array(n);
148
+ for (let i = 0; i < n; i++) {
149
+ let depth = 0;
150
+ let winding = 0;
151
+ for (let a = i; a >= 0; a = parent[a]) {
152
+ winding += orient[a];
153
+ if (a !== i) depth++;
115
154
  }
155
+ filled[i] = fillRule === "evenodd" ? depth % 2 === 0 : winding !== 0;
116
156
  }
117
- const filled = rings.map((_, i) => {
118
- if (fillRule === "evenodd") return containers[i].length % 2 === 0;
119
- let winding = Math.sign(areas[i]);
120
- for (const j of containers[i]) winding += Math.sign(areas[j]);
121
- return winding !== 0;
122
- });
123
157
  const out = [];
124
158
  for (let i = 0; i < n; i++) {
125
159
  if (!filled[i]) continue;
126
- const poly = [rings[i]];
127
- for (let k = 0; k < n; k++) {
128
- if (filled[k] || containers[k].length !== containers[i].length + 1) continue;
129
- if (containers[k].includes(i)) poly.push(rings[k]);
160
+ if (parent[i] >= 0 && filled[parent[i]]) continue;
161
+ const polygon = [rings[i]];
162
+ const queue = [...children[i]];
163
+ while (queue.length > 0) {
164
+ const c = queue.pop();
165
+ if (filled[c]) queue.push(...children[c]);
166
+ else polygon.push(rings[c]);
130
167
  }
131
- out.push(poly);
168
+ out.push(polygon);
132
169
  }
133
170
  return out;
134
171
  }
@@ -225,7 +262,18 @@ function popcount(n) {
225
262
  }
226
263
  return c;
227
264
  }
265
+ function pathCrop(...paths) {
266
+ if (paths.length < 2) return [];
267
+ const mps = paths.map((p) => pathToMultiPolygon(p));
268
+ const mask = mps[mps.length - 1];
269
+ const out = [];
270
+ for (let i = 0; i < mps.length - 1; i++) {
271
+ const clipped = polygonClipping.intersection(mps[i], mask);
272
+ if (clipped.length > 0) out.push(multiPolygonToPath(clipped));
273
+ }
274
+ return out;
275
+ }
228
276
 
229
- export { pathDivide, pathExclude, pathIntersect, pathSubtract, pathUnion };
277
+ export { multiPolygonToPath, pathCrop, pathDivide, pathExclude, pathIntersect, pathSubtract, pathToMultiPolygon, pathUnion };
230
278
  //# sourceMappingURL=index.js.map
231
279
  //# sourceMappingURL=index.js.map