@weasel-js/geom 1.5.1 → 1.6.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.
@@ -1,7 +1,18 @@
1
- /** Three-component vectors and unit quaternions. Immutable tuples throughout:
1
+ export { P as PORT_REACH } from '../portCurve-BBr7eHAL.js';
2
+
3
+ /** Three-component vectors and unit quaternions. `Vec3`'s fields are readonly:
2
4
  * 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
+ * handed to a renderer.
6
+ *
7
+ * Named fields rather than a tuple, matching `Vec2` one tier up, so a
8
+ * consumer writing both dimensions says `p.x` in each. `Quat` stays a tuple —
9
+ * it is not a point, and `[x, y, z, w]` is the layout three.js and glMatrix
10
+ * both use. */
11
+ interface Vec3 {
12
+ readonly x: number;
13
+ readonly y: number;
14
+ readonly z: number;
15
+ }
5
16
  /** `[x, y, z, w]`, w last — the layout three.js and glMatrix both use. */
6
17
  type Quat = readonly [number, number, number, number];
7
18
  declare function add(a: Vec3, b: Vec3): Vec3;
@@ -67,4 +78,18 @@ declare function transformAabb(m: Mat4, local: Aabb): Aabb;
67
78
  /** The box centred on `center` reaching `radius` along every axis. */
68
79
  declare function aabbAround(center: Vec3, radius: number): Aabb;
69
80
 
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 };
81
+ /**
82
+ * The port-curve rule one dimension up, in `Vec3`. The rule itself lives in
83
+ * `../portCurve`, stated once over components — this wrapper is types and
84
+ * nothing else, so 2D and 3D cannot disagree about what the curve is.
85
+ */
86
+
87
+ /** `[c1, c2]` for the cubic from `a` to `b`. A null normal falls back to a lerp
88
+ * along the chord; see `../portCurve` for why the two ends differ. */
89
+ declare function portControls(a: Vec3, b: Vec3, outNormal: Vec3 | null | undefined, inNormal: Vec3 | null | undefined, reach?: number): [Vec3, Vec3];
90
+ /** A port curve sampled into `samples` points, excluding its start. */
91
+ declare function portCurvePoints(a: Vec3, b: Vec3, outNormal: Vec3 | null | undefined, inNormal: Vec3 | null | undefined, samples: number, reach?: number): Vec3[];
92
+ /** A cubic evaluated at `t`. The 2D barrel's `cubicEvalAt`, one dimension up. */
93
+ declare function cubicAt(p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, t: number): Vec3;
94
+
95
+ export { type Aabb, type Mat4, type Quat, type Ray, type Vec3, aabbAround, add, compose, cross, cubicAt, dot, identity, intersectRayAabb, intersectRayPlane, invert, len, len2, lookAt, multiply, normalize, perspective, portControls, portCurvePoints, quatFromAxisAngle, quatIdentity, scale, sub, transformAabb, transformPoint, transformPoint4 };
package/dist/3d/index.js CHANGED
@@ -1,24 +1,25 @@
1
- import { SINGULAR_RATIO } from '../chunk-NHMWNQTE.js';
1
+ import { PORT_REACH, SINGULAR_RATIO, portControls, cubicAt } from '../chunk-3GFNUO4N.js';
2
+ export { PORT_REACH } from '../chunk-3GFNUO4N.js';
2
3
 
3
4
  // src/3d/vec3.ts
4
5
  function add(a, b) {
5
- return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
6
+ return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
6
7
  }
7
8
  function sub(a, b) {
8
- return [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
9
+ return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
9
10
  }
10
11
  function scale(a, k) {
11
- return [a[0] * k, a[1] * k, a[2] * k];
12
+ return { x: a.x * k, y: a.y * k, z: a.z * k };
12
13
  }
13
14
  function dot(a, b) {
14
- return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
15
+ return a.x * b.x + a.y * b.y + a.z * b.z;
15
16
  }
16
17
  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
- ];
18
+ return {
19
+ x: a.y * b.z - a.z * b.y,
20
+ y: a.z * b.x - a.x * b.z,
21
+ z: a.x * b.y - a.y * b.x
22
+ };
22
23
  }
23
24
  function len2(a) {
24
25
  return dot(a, a);
@@ -28,7 +29,10 @@ function len(a) {
28
29
  }
29
30
  function normalize(a) {
30
31
  const l = len(a);
31
- return l > 0 && l < Infinity ? scale(a, 1 / l) : [0, 0, 0];
32
+ return l > 0 && l < Infinity ? scale(a, 1 / l) : { x: 0, y: 0, z: 0 };
33
+ }
34
+ function vec3(x, y, z) {
35
+ return { x, y, z };
32
36
  }
33
37
  function quatIdentity() {
34
38
  return [0, 0, 0, 1];
@@ -37,7 +41,7 @@ function quatFromAxisAngle(axis, angle) {
37
41
  const a = normalize(axis);
38
42
  const half = angle / 2;
39
43
  const s = Math.sin(half);
40
- return [a[0] * s, a[1] * s, a[2] * s, Math.cos(half)];
44
+ return [a.x * s, a.y * s, a.z * s, Math.cos(half)];
41
45
  }
42
46
 
43
47
  // src/3d/mat4.ts
@@ -56,7 +60,7 @@ function multiply(a, b) {
56
60
  return out;
57
61
  }
58
62
  function transformPoint4(m, p) {
59
- const [x, y, z] = p;
63
+ const { x, y, z } = p;
60
64
  return [
61
65
  m[0] * x + m[4] * y + m[8] * z + m[12],
62
66
  m[1] * x + m[5] * y + m[9] * z + m[13],
@@ -66,8 +70,8 @@ function transformPoint4(m, p) {
66
70
  }
67
71
  function transformPoint(m, p) {
68
72
  const [x, y, z, w] = transformPoint4(m, p);
69
- if (w === 1) return [x, y, z];
70
- return [x / w, y / w, z / w];
73
+ if (w === 1) return vec3(x, y, z);
74
+ return vec3(x / w, y / w, z / w);
71
75
  }
72
76
  function invert(m) {
73
77
  const [
@@ -137,7 +141,7 @@ function compose(position, rotation, scaling) {
137
141
  const wx = w * x2;
138
142
  const wy = w * y2;
139
143
  const wz = w * z2;
140
- const [sx, sy, sz] = scaling;
144
+ const { x: sx, y: sy, z: sz } = scaling;
141
145
  return [
142
146
  (1 - (yy + zz)) * sx,
143
147
  (xy + wz) * sx,
@@ -151,9 +155,9 @@ function compose(position, rotation, scaling) {
151
155
  (yz - wx) * sz,
152
156
  (1 - (xx + yy)) * sz,
153
157
  0,
154
- position[0],
155
- position[1],
156
- position[2],
158
+ position.x,
159
+ position.y,
160
+ position.z,
157
161
  1
158
162
  ];
159
163
  }
@@ -182,20 +186,20 @@ function perspective(fovY, aspect, near, far) {
182
186
  function lookAt(eye, target, up) {
183
187
  const back = normalize(sub(eye, target));
184
188
  const side = cross(up, back);
185
- const right = len(side) > SINGULAR_RATIO * len(up) ? normalize(side) : [0, 0, 0];
189
+ const right = len(side) > SINGULAR_RATIO * len(up) ? normalize(side) : vec3(0, 0, 0);
186
190
  const trueUp = cross(back, right);
187
191
  return [
188
- right[0],
189
- trueUp[0],
190
- back[0],
192
+ right.x,
193
+ trueUp.x,
194
+ back.x,
191
195
  0,
192
- right[1],
193
- trueUp[1],
194
- back[1],
196
+ right.y,
197
+ trueUp.y,
198
+ back.y,
195
199
  0,
196
- right[2],
197
- trueUp[2],
198
- back[2],
200
+ right.z,
201
+ trueUp.z,
202
+ back.z,
199
203
  0,
200
204
  -dot(right, eye),
201
205
  -dot(trueUp, eye),
@@ -208,7 +212,7 @@ function lookAt(eye, target, up) {
208
212
  function intersectRayAabb(ray, min, max) {
209
213
  let tMin = Number.NEGATIVE_INFINITY;
210
214
  let tMax = Number.POSITIVE_INFINITY;
211
- for (let axis = 0; axis < 3; axis++) {
215
+ for (const axis of ["x", "y", "z"]) {
212
216
  const o = ray.origin[axis];
213
217
  const d = ray.direction[axis];
214
218
  if (d === 0) {
@@ -232,27 +236,61 @@ function intersectRayPlane(ray, normal, offset) {
232
236
  return t < 0 ? null : t;
233
237
  }
234
238
  function transformAabb(m, local) {
235
- let min = [Infinity, Infinity, Infinity];
236
- let max = [-Infinity, -Infinity, -Infinity];
239
+ let min = { x: Infinity, y: Infinity, z: Infinity };
240
+ let max = { x: -Infinity, y: -Infinity, z: -Infinity };
237
241
  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
- ];
242
+ const corner = {
243
+ x: i & 1 ? local.max.x : local.min.x,
244
+ y: i & 2 ? local.max.y : local.min.y,
245
+ z: i & 4 ? local.max.z : local.min.z
246
+ };
243
247
  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])];
248
+ min = { x: Math.min(min.x, p.x), y: Math.min(min.y, p.y), z: Math.min(min.z, p.z) };
249
+ max = { x: Math.max(max.x, p.x), y: Math.max(max.y, p.y), z: Math.max(max.z, p.z) };
246
250
  }
247
251
  return { min, max };
248
252
  }
249
253
  function aabbAround(center, radius) {
250
254
  return {
251
- min: [center[0] - radius, center[1] - radius, center[2] - radius],
252
- max: [center[0] + radius, center[1] + radius, center[2] + radius]
255
+ min: { x: center.x - radius, y: center.y - radius, z: center.z - radius },
256
+ max: { x: center.x + radius, y: center.y + radius, z: center.z + radius }
253
257
  };
254
258
  }
255
259
 
256
- export { aabbAround, add, compose, cross, dot, identity, intersectRayAabb, intersectRayPlane, invert, len, len2, lookAt, multiply, normalize, perspective, quatFromAxisAngle, quatIdentity, scale, sub, transformAabb, transformPoint, transformPoint4 };
260
+ // src/3d/portCurve3.ts
261
+ var comps = (v) => [v.x, v.y, v.z];
262
+ var compsOrNull = (v) => v == null ? v : comps(v);
263
+ var fromComps = (p) => ({ x: p[0], y: p[1], z: p[2] });
264
+ function portControls2(a, b, outNormal, inNormal, reach = PORT_REACH) {
265
+ const [c1, c2] = portControls(
266
+ comps(a),
267
+ comps(b),
268
+ compsOrNull(outNormal),
269
+ compsOrNull(inNormal),
270
+ reach
271
+ );
272
+ return [fromComps(c1), fromComps(c2)];
273
+ }
274
+ function portCurvePoints(a, b, outNormal, inNormal, samples, reach = PORT_REACH) {
275
+ const [c1, c2] = portControls(
276
+ comps(a),
277
+ comps(b),
278
+ compsOrNull(outNormal),
279
+ compsOrNull(inNormal),
280
+ reach
281
+ );
282
+ const out = [];
283
+ for (let s = 1; s <= samples; s++) {
284
+ const p = cubicAt(comps(a), c1, c2, comps(b), s / samples);
285
+ out.push(fromComps(p));
286
+ }
287
+ return out;
288
+ }
289
+ function cubicAt2(p0, p1, p2, p3, t) {
290
+ const p = cubicAt(comps(p0), comps(p1), comps(p2), comps(p3), t);
291
+ return fromComps(p);
292
+ }
293
+
294
+ export { aabbAround, add, compose, cross, cubicAt2 as cubicAt, dot, identity, intersectRayAabb, intersectRayPlane, invert, len, len2, lookAt, multiply, normalize, perspective, portControls2 as portControls, portCurvePoints, quatFromAxisAngle, quatIdentity, scale, sub, transformAabb, transformPoint, transformPoint4 };
257
295
  //# sourceMappingURL=index.js.map
258
296
  //# sourceMappingURL=index.js.map
@@ -1 +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"]}
1
+ {"version":3,"sources":["../../src/3d/vec3.ts","../../src/3d/mat4.ts","../../src/3d/ray3.ts","../../src/3d/portCurve3.ts"],"names":["scale","portControls","cubicAt"],"mappings":"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","file":"index.js","sourcesContent":["/** Three-component vectors and unit quaternions. `Vec3`'s fields are readonly:\n * a pose stored in a history snapshot must not be writable through the value\n * handed to a renderer.\n *\n * Named fields rather than a tuple, matching `Vec2` one tier up, so a\n * consumer writing both dimensions says `p.x` in each. `Quat` stays a tuple —\n * it is not a point, and `[x, y, z, w]` is the layout three.js and glMatrix\n * both use. */\n\nexport interface Vec3 {\n readonly x: number;\n readonly y: number;\n readonly z: number;\n}\n\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 { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };\n}\n\nexport function sub(a: Vec3, b: Vec3): Vec3 {\n return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };\n}\n\nexport function scale(a: Vec3, k: number): Vec3 {\n return { x: a.x * k, y: a.y * k, z: a.z * k };\n}\n\nexport function dot(a: Vec3, b: Vec3): number {\n return a.x * b.x + a.y * b.y + a.z * b.z;\n}\n\nexport function cross(a: Vec3, b: Vec3): Vec3 {\n return {\n x: a.y * b.z - a.z * b.y,\n y: a.z * b.x - a.x * b.z,\n z: a.x * b.y - a.y * b.x,\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) : { x: 0, y: 0, z: 0 };\n}\n\n/** `Vec3` from loose components — the shape `Mat4`'s row math produces. */\nexport function vec3(x: number, y: number, z: number): Vec3 {\n return { x, y, z };\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.x * s, a.y * s, a.z * 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, vec3, 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 vec3(x, y, z);\n return vec3(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 { x: sx, y: sy, z: 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.x, position.y, position.z, 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) : vec3(0, 0, 0);\n const trueUp = cross(back, right);\n return [\n right.x, trueUp.x, back.x, 0,\n right.y, trueUp.y, back.y, 0,\n right.z, trueUp.z, back.z, 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 (const axis of ['x', 'y', 'z'] as const) {\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 = { x: Infinity, y: Infinity, z: Infinity };\n let max: Vec3 = { x: -Infinity, y: -Infinity, z: -Infinity };\n for (let i = 0; i < 8; i++) {\n const corner: Vec3 = {\n x: i & 1 ? local.max.x : local.min.x,\n y: i & 2 ? local.max.y : local.min.y,\n z: i & 4 ? local.max.z : local.min.z,\n };\n const p = transformPoint(m, corner);\n min = { x: Math.min(min.x, p.x), y: Math.min(min.y, p.y), z: Math.min(min.z, p.z) };\n max = { x: Math.max(max.x, p.x), y: Math.max(max.y, p.y), z: Math.max(max.z, p.z) };\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: { x: center.x - radius, y: center.y - radius, z: center.z - radius },\n max: { x: center.x + radius, y: center.y + radius, z: center.z + radius },\n };\n}\n","/**\n * The port-curve rule one dimension up, in `Vec3`. The rule itself lives in\n * `../portCurve`, stated once over components — this wrapper is types and\n * nothing else, so 2D and 3D cannot disagree about what the curve is.\n */\n\nimport { PORT_REACH, cubicAt as cubicAtN, portControls as portControlsN } from '../portCurve';\nimport type { Vec3 } from './vec3';\n\nexport { PORT_REACH };\n\nconst comps = (v: Vec3): [number, number, number] => [v.x, v.y, v.z];\nconst compsOrNull = (v: Vec3 | null | undefined) => (v == null ? v : comps(v));\nconst fromComps = (p: readonly number[]): Vec3 => ({ x: p[0]!, y: p[1]!, z: p[2]! });\n\n/** `[c1, c2]` for the cubic from `a` to `b`. A null normal falls back to a lerp\n * along the chord; see `../portCurve` for why the two ends differ. */\nexport function portControls(\n a: Vec3,\n b: Vec3,\n outNormal: Vec3 | null | undefined,\n inNormal: Vec3 | null | undefined,\n reach: number = PORT_REACH,\n): [Vec3, Vec3] {\n const [c1, c2] = portControlsN(\n comps(a),\n comps(b),\n compsOrNull(outNormal),\n compsOrNull(inNormal),\n reach,\n );\n return [fromComps(c1), fromComps(c2)];\n}\n\n/** A port curve sampled into `samples` points, excluding its start. */\nexport function portCurvePoints(\n a: Vec3,\n b: Vec3,\n outNormal: Vec3 | null | undefined,\n inNormal: Vec3 | null | undefined,\n samples: number,\n reach: number = PORT_REACH,\n): Vec3[] {\n const [c1, c2] = portControlsN(\n comps(a),\n comps(b),\n compsOrNull(outNormal),\n compsOrNull(inNormal),\n reach,\n );\n const out: Vec3[] = [];\n for (let s = 1; s <= samples; s++) {\n const p = cubicAtN(comps(a), c1, c2, comps(b), s / samples);\n out.push(fromComps(p));\n }\n return out;\n}\n\n/** A cubic evaluated at `t`. The 2D barrel's `cubicEvalAt`, one dimension up. */\nexport function cubicAt(p0: Vec3, p1: Vec3, p2: Vec3, p3: Vec3, t: number): Vec3 {\n const p = cubicAtN(comps(p0), comps(p1), comps(p2), comps(p3), t);\n return fromComps(p);\n}\n"]}
@@ -0,0 +1,61 @@
1
+ // src/scalar.ts
2
+ var EPS = 1e-6;
3
+ var SINGULAR_RATIO = 1e-12;
4
+ function cross(ax, ay, bx, by) {
5
+ return ax * by - ay * bx;
6
+ }
7
+ function dot(ax, ay, bx, by) {
8
+ return ax * bx + ay * by;
9
+ }
10
+ function sub(ax, ay, bx, by) {
11
+ return [ax - bx, ay - by];
12
+ }
13
+ function len2(x, y) {
14
+ return x * x + y * y;
15
+ }
16
+ function sign(n) {
17
+ return n > 0 ? 1 : n < 0 ? -1 : 0;
18
+ }
19
+ function approxEq(a, b, eps = EPS) {
20
+ if (a === b) return true;
21
+ const diff = Math.abs(a - b);
22
+ if (!Number.isFinite(diff)) return false;
23
+ const scale = Math.max(1, Math.abs(a), Math.abs(b));
24
+ return diff <= eps * scale;
25
+ }
26
+
27
+ // src/portCurve.ts
28
+ var PORT_REACH = 0.4;
29
+ function portControls(a, b, outNormal, inNormal, reach = PORT_REACH) {
30
+ let sum = 0;
31
+ for (let i = 0; i < a.length; i++) {
32
+ const d = b[i] - a[i];
33
+ sum += d * d;
34
+ }
35
+ const span = Math.sqrt(sum) * reach;
36
+ const c1 = [];
37
+ const c2 = [];
38
+ for (let i = 0; i < a.length; i++) {
39
+ const ai = a[i];
40
+ const bi = b[i];
41
+ c1.push(outNormal == null ? ai + (bi - ai) * reach : ai + outNormal[i] * span);
42
+ c2.push(inNormal == null ? bi - (bi - ai) * reach : bi + inNormal[i] * span);
43
+ }
44
+ return [c1, c2];
45
+ }
46
+ function cubicAt(p0, p1, p2, p3, t) {
47
+ const u = 1 - t;
48
+ const a = u * u * u;
49
+ const b = 3 * u * u * t;
50
+ const c = 3 * u * t * t;
51
+ const d = t * t * t;
52
+ const out = [];
53
+ for (let i = 0; i < p0.length; i++) {
54
+ out.push(a * p0[i] + b * p1[i] + c * p2[i] + d * p3[i]);
55
+ }
56
+ return out;
57
+ }
58
+
59
+ export { EPS, PORT_REACH, SINGULAR_RATIO, approxEq, cross, cubicAt, dot, len2, portControls, sign, sub };
60
+ //# sourceMappingURL=chunk-3GFNUO4N.js.map
61
+ //# sourceMappingURL=chunk-3GFNUO4N.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/scalar.ts","../src/portCurve.ts"],"names":[],"mappings":"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","file":"chunk-3GFNUO4N.js","sourcesContent":["/**\n * Scalar / 2-vector primitives and the kernel-wide epsilon policy.\n *\n * Points are scalar pairs (px, py); there is no point struct. All math is\n * f64 (JS-native). Epsilons are f32-SCALE and magnitude-relative, because\n * stored coords are quantized to Float32 (~7 significant digits) — see the\n * geometry-kernel spec.\n */\n\n/** Base relative epsilon, sized for Float32 storage (~1 part in 1e-6). */\nexport const EPS = 1e-6;\n\n/** A determinant at or below this fraction of its matrix's own scale counts as\n * singular. Dimensionless, so a uniformly tiny matrix still inverts while a\n * large one whose determinant is only rounding does not. */\nexport const SINGULAR_RATIO = 1e-12;\n\n/** 2D cross (wedge) product of vectors (ax,ay) and (bx,by). */\nexport function cross(ax: number, ay: number, bx: number, by: number): number {\n return ax * by - ay * bx;\n}\n\n/** 2D dot product. */\nexport function dot(ax: number, ay: number, bx: number, by: number): number {\n return ax * bx + ay * by;\n}\n\n/** Component difference (ax-bx, ay-by) as a tuple. Cold-path use only. */\nexport function sub(ax: number, ay: number, bx: number, by: number): [number, number] {\n return [ax - bx, ay - by];\n}\n\n/** Squared length of (x,y). Avoids the sqrt; compare against squared thresholds. */\nexport function len2(x: number, y: number): number {\n return x * x + y * y;\n}\n\n/** Three-valued sign. */\nexport function sign(n: number): -1 | 0 | 1 {\n return n > 0 ? 1 : n < 0 ? -1 : 0;\n}\n\n/**\n * Magnitude-scaled approximate equality. Two values are equal when their\n * absolute difference is within EPS scaled by the larger magnitude. Every\n * comparison of two *computed coordinates* goes through this — never `===`,\n * never an f64-tight literal.\n *\n * The exception is a guard against an exact algebraic value that a formula\n * produces bit-for-bit: a homogeneous `w === 1`, a ray's `d === 0`. Those are\n * testing a branch, not comparing coordinates, and `geom/3d` has two of them\n * (`mat4.ts`, `ray3.ts`). Widening one to `approxEq` would change which branch\n * runs, not how precisely it runs.\n */\nexport function approxEq(a: number, b: number, eps: number = EPS): boolean {\n if (a === b) return true; // also the only way two infinities compare equal\n const diff = Math.abs(a - b);\n // Infinity/Infinity is 1, so an unguarded relative test calls every finite\n // number equal to an infinity.\n if (!Number.isFinite(diff)) return false;\n const scale = Math.max(1, Math.abs(a), Math.abs(b));\n return diff <= eps * scale;\n}\n","/**\n * The cubic control points that make a curve leave a port along its normal and\n * arrive at the next against that port's normal — what makes a routed edge read\n * as plugged into a box rather than aimed at it.\n *\n * The rule is stated once, over loose components, and the 2D barrel and `./3d`\n * each wrap it in their own currency. Every operation here is closed on the\n * plane z = 0, so a planar problem answered through the 3D wrapper returns the\n * same numbers as through the 2D one, not an approximation of them.\n */\n\n/** How far a control point reaches toward the other end, as a fraction of the\n * straight-line distance between the two. */\nexport const PORT_REACH = 0.4;\n\n/**\n * `[c1, c2]` for the cubic from `a` to `b`.\n *\n * A null normal falls back to a plain lerp along the chord, which is what makes\n * an unported waypoint curve smoothly instead of kinking. The two ends are not\n * symmetric: `outNormal` points the way the curve departs, while `inNormal`\n * points out of the receiving port, so `c2` is pushed *along* it to arrive\n * against it.\n */\nexport function portControls(\n a: readonly number[],\n b: readonly number[],\n outNormal: readonly number[] | null | undefined,\n inNormal: readonly number[] | null | undefined,\n reach: number = PORT_REACH,\n): [number[], number[]] {\n let sum = 0;\n for (let i = 0; i < a.length; i++) {\n const d = b[i]! - a[i]!;\n sum += d * d;\n }\n const span = Math.sqrt(sum) * reach;\n\n const c1: number[] = [];\n const c2: number[] = [];\n for (let i = 0; i < a.length; i++) {\n const ai = a[i]!;\n const bi = b[i]!;\n c1.push(outNormal == null ? ai + (bi - ai) * reach : ai + outNormal[i]! * span);\n c2.push(inNormal == null ? bi - (bi - ai) * reach : bi + inNormal[i]! * span);\n }\n return [c1, c2];\n}\n\n/** A cubic evaluated at `t`, component-wise, in whatever dimension it was given. */\nexport function cubicAt(\n p0: readonly number[],\n p1: readonly number[],\n p2: readonly number[],\n p3: readonly number[],\n t: number,\n): number[] {\n const u = 1 - t;\n const a = u * u * u;\n const b = 3 * u * u * t;\n const c = 3 * u * t * t;\n const d = t * t * t;\n const out: number[] = [];\n for (let i = 0; i < p0.length; i++) {\n out.push(a * p0[i]! + b * p1[i]! + c * p2[i]! + d * p3[i]!);\n }\n return out;\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export { P as PORT_REACH } from './portCurve-BBr7eHAL.js';
2
+
1
3
  /**
2
4
  * Scalar / 2-vector primitives and the kernel-wide epsilon policy.
3
5
  *
@@ -20,13 +22,19 @@ declare function len2(x: number, y: number): number;
20
22
  declare function sign(n: number): -1 | 0 | 1;
21
23
  /**
22
24
  * Magnitude-scaled approximate equality. Two values are equal when their
23
- * absolute difference is within EPS scaled by the larger magnitude. This is
24
- * the ONLY equality the kernel uses on computed coordinates — never `===`,
25
+ * absolute difference is within EPS scaled by the larger magnitude. Every
26
+ * comparison of two *computed coordinates* goes through this — never `===`,
25
27
  * never an f64-tight literal.
28
+ *
29
+ * The exception is a guard against an exact algebraic value that a formula
30
+ * produces bit-for-bit: a homogeneous `w === 1`, a ray's `d === 0`. Those are
31
+ * testing a branch, not comparing coordinates, and `geom/3d` has two of them
32
+ * (`mat4.ts`, `ray3.ts`). Widening one to `approxEq` would change which branch
33
+ * runs, not how precisely it runs.
26
34
  */
27
35
  declare function approxEq(a: number, b: number, eps?: number): boolean;
28
36
 
29
- type Mat3 = number[];
37
+ type Mat3 = readonly [number, number, number, number, number, number];
30
38
  /** The transform that leaves a point where it is. */
31
39
  declare function identity(): Mat3;
32
40
  /** A pure translation by `(tx, ty)`. */
@@ -50,7 +58,7 @@ declare function boxToBox(sx: number, sy: number, sw: number, sh: number, dx: nu
50
58
  declare function rotateAboutPoint(cx: number, cy: number, rad: number): Mat3;
51
59
 
52
60
  /** Axis-aligned box as [minX, minY, maxX, maxY]. */
53
- type Box = [number, number, number, number];
61
+ type Box = readonly [number, number, number, number];
54
62
  /** An axis-aligned rectangle in object form. `Box` is the tuple form; this is
55
63
  * the one that survives being read by a human. */
56
64
  interface Rect {
@@ -143,6 +151,22 @@ declare function elevateQuadraticToCubic(q0x: number, q0y: number, cx: number, c
143
151
  /** Tight AABB of a cubic, evaluating only extrema that lie on the curve. */
144
152
  declare function cubicBounds(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): Box;
145
153
 
154
+ /**
155
+ * The port-curve rule in the 2D kernel's currency: loose scalars, the way
156
+ * `cubicEvalAt` and `applyToPoint` take them. The rule itself lives in
157
+ * `./portCurve`, stated once over components, so this and `./3d` cannot drift.
158
+ */
159
+
160
+ /**
161
+ * `[c1, c2]` for the cubic from `(ax, ay)` to `(bx, by)`.
162
+ *
163
+ * A null normal falls back to a lerp along the chord. See `./portCurve` for why
164
+ * the two ends are not symmetric.
165
+ */
166
+ declare function portControls(ax: number, ay: number, bx: number, by: number, outNormal: readonly [number, number] | null | undefined, inNormal: readonly [number, number] | null | undefined, reach?: number): [[number, number], [number, number]];
167
+ /** A port curve sampled into `samples` points, excluding its start. */
168
+ declare function portCurvePoints(ax: number, ay: number, bx: number, by: number, outNormal: readonly [number, number] | null | undefined, inNormal: readonly [number, number] | null | undefined, samples: number, reach?: number): [number, number][];
169
+
146
170
  /**
147
171
  * Bezier flattening — subdivide cubic and quadratic segments into polyline
148
172
  * approximations within a flatness tolerance. Used by hit-testing and
@@ -251,4 +275,4 @@ interface PlacedRect {
251
275
  declare function clampRectWithin(rect: Rect, boundary: Rect, padding?: number): Rect;
252
276
  declare function placeRect(options: PlaceRectOptions): PlacedRect;
253
277
 
254
- export { type Box, DEFAULT_FLATTEN_TOLERANCE, EPS, type Mat3, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, type PathCommandCode, type PathCommandName, type PlaceRectOptions, type PlacedRect, type Placement, type PlacementAlign, type PlacementSide, type Rect, applyToPoint, approxEq, boundsOfCoords, boxContainsPoint, boxToBox, clampRectWithin, cross, cubicBounds, cubicEvalAt, dot, elevateQuadraticToCubic, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, identity, invert, len2, multiply, pathCommandCoordCount, placeRect, pointInPolygon, pointSegmentDist2, rectToContour, rotate, rotateAboutPoint, scale, segmentsCross, sign, sub, transformCoords, translate, unionBox };
278
+ export { type Box, DEFAULT_FLATTEN_TOLERANCE, EPS, type Mat3, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, type PathCommandCode, type PathCommandName, type PlaceRectOptions, type PlacedRect, type Placement, type PlacementAlign, type PlacementSide, type Rect, applyToPoint, approxEq, boundsOfCoords, boxContainsPoint, boxToBox, clampRectWithin, cross, cubicBounds, cubicEvalAt, dot, elevateQuadraticToCubic, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, identity, invert, len2, multiply, pathCommandCoordCount, placeRect, pointInPolygon, pointSegmentDist2, portControls, portCurvePoints, rectToContour, rotate, rotateAboutPoint, scale, segmentsCross, sign, sub, transformCoords, translate, unionBox };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { DEFAULT_FLATTEN_TOLERANCE, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, cubicBounds, cubicEvalAt, elevateQuadraticToCubic, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, forEachSegment, pathCommandCoordCount } from './chunk-DQ6QRAWP.js';
2
- import { SINGULAR_RATIO, sign, len2, dot } from './chunk-NHMWNQTE.js';
3
- export { EPS, approxEq, cross, dot, len2, sign, sub } from './chunk-NHMWNQTE.js';
2
+ import { PORT_REACH, SINGULAR_RATIO, portControls, cubicAt, sign, len2, dot } from './chunk-3GFNUO4N.js';
3
+ export { EPS, PORT_REACH, approxEq, cross, dot, len2, sign, sub } from './chunk-3GFNUO4N.js';
4
4
 
5
5
  // src/mat3.ts
6
6
  function identity() {
@@ -78,6 +78,26 @@ function rectToContour(x, y, w, h) {
78
78
  return Float64Array.of(x, y, x + w, y, x + w, y + h, x, y + h);
79
79
  }
80
80
 
81
+ // src/portCurve2.ts
82
+ function portControls2(ax, ay, bx, by, outNormal, inNormal, reach = PORT_REACH) {
83
+ const [c1, c2] = portControls([ax, ay], [bx, by], outNormal, inNormal, reach);
84
+ return [
85
+ [c1[0], c1[1]],
86
+ [c2[0], c2[1]]
87
+ ];
88
+ }
89
+ function portCurvePoints(ax, ay, bx, by, outNormal, inNormal, samples, reach = PORT_REACH) {
90
+ const a = [ax, ay];
91
+ const b = [bx, by];
92
+ const [c1, c2] = portControls(a, b, outNormal, inNormal, reach);
93
+ const out = [];
94
+ for (let s = 1; s <= samples; s++) {
95
+ const p = cubicAt(a, c1, c2, b, s / samples);
96
+ out.push([p[0], p[1]]);
97
+ }
98
+ return out;
99
+ }
100
+
81
101
  // src/polyline.ts
82
102
  function pointInPolygon(coords, px, py, start = 0, end = coords.length >> 1) {
83
103
  if (end - start < 3) return false;
@@ -184,6 +204,6 @@ function placeRect(options) {
184
204
  return { rect: shiftAcross(rect, boundary, resolved.side, padding), placement: resolved };
185
205
  }
186
206
 
187
- export { applyToPoint, boundsOfCoords, boxContainsPoint, boxToBox, clampRectWithin, identity, invert, multiply, placeRect, pointInPolygon, pointSegmentDist2, rectToContour, rotate, rotateAboutPoint, scale, segmentsCross, transformCoords, translate, unionBox };
207
+ export { applyToPoint, boundsOfCoords, boxContainsPoint, boxToBox, clampRectWithin, identity, invert, multiply, placeRect, pointInPolygon, pointSegmentDist2, portControls2 as portControls, portCurvePoints, rectToContour, rotate, rotateAboutPoint, scale, segmentsCross, transformCoords, translate, unionBox };
188
208
  //# sourceMappingURL=index.js.map
189
209
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mat3.ts","../src/box.ts","../src/polyline.ts","../src/affine.ts","../src/place.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * 2D affine transforms in canvas/DOMMatrix order: [a, b, c, d, e, f].\n * x' = a·x + c·y + e\n * y' = b·x + d·y + f\n * Represented as a 6-element number[] (f64). The affine tier of the kernel.\n *\n * Convention alignment: the renderer already has a `Mat3` in\n * `src/renderer/math/mat3.ts`. That one is a 9-element column-major\n * `Float32Array` (a full 3×3) shaped for `uniformMatrix3fv` — a deliberately\n * different *representation* for the WebGL upload path. Its *logical element\n * order* is identical to ours: `create(a, b, c, d, tx, ty)` maps\n * `x' = a·x + c·y + tx`, `y' = b·x + d·y + ty` (canvas/DOMMatrix a,b,c,d,e,f).\n * We keep the pure 6-tuple f64 form here (the kernel form); the 9-element f32\n * form stays a render-layer concern. No second logical convention is created.\n */\nimport { SINGULAR_RATIO } from './scalar';\n\nexport type Mat3 = number[];\n\n/** The transform that leaves a point where it is. */\nexport function identity(): Mat3 {\n return [1, 0, 0, 1, 0, 0];\n}\n\n/** A pure translation by `(tx, ty)`. */\nexport function translate(tx: number, ty: number): Mat3 {\n return [1, 0, 0, 1, tx, ty];\n}\n\n/** A pure scale about the origin. Scale about another point by composing\n * translate → scale → inverse translate with `multiply`. */\nexport function scale(sx: number, sy: number): Mat3 {\n return [sx, 0, 0, sy, 0, 0];\n}\n\n/** A pure rotation about the origin, in radians, clockwise in canvas\n * coordinates (y down). */\nexport function rotate(rad: number): Mat3 {\n const c = Math.cos(rad);\n const s = Math.sin(rad);\n return [c, s, -s, c, 0, 0];\n}\n\n/** Compose: result applies `n` first, then `m` (m·n). */\nexport function multiply(m: Mat3, n: Mat3): Mat3 {\n return [\n m[0] * n[0] + m[2] * n[1],\n m[1] * n[0] + m[3] * n[1],\n m[0] * n[2] + m[2] * n[3],\n m[1] * n[2] + m[3] * n[3],\n m[0] * n[4] + m[2] * n[5] + m[4],\n m[1] * n[4] + m[3] * n[5] + m[5],\n ];\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: Mat3): Mat3 | null {\n const det = m[0] * m[3] - m[1] * m[2];\n // The determinant is an area, so it is judged against the squared column norms.\n const norm2 = Math.max(m[0] * m[0] + m[1] * m[1], m[2] * m[2] + m[3] * m[3]);\n // Negated so a non-finite determinant falls out as singular.\n if (!(Math.abs(det) > SINGULAR_RATIO * norm2)) return null;\n const id = 1 / det;\n const a = m[3] * id;\n const b = -m[1] * id;\n const c = -m[2] * id;\n const d = m[0] * id;\n return [a, b, c, d, -(m[4] * a + m[5] * c), -(m[4] * b + m[5] * d)];\n}\n\n/** Apply to a point, returning a tuple. Cold-path use; hot loops inline. */\nexport function applyToPoint(m: Mat3, x: number, y: number): [number, number] {\n return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];\n}\n\n/** Affine that maps source box (sx,sy,sw,sh) onto destination box (dx,dy,dw,dh). */\nexport function boxToBox(\n sx: number, sy: number, sw: number, sh: number,\n dx: number, dy: number, dw: number, dh: number,\n): Mat3 {\n const kx = sw === 0 ? 1 : dw / sw;\n const ky = sh === 0 ? 1 : dh / sh;\n // translate(dx,dy) · scale(kx,ky) · translate(-sx,-sy)\n return [kx, 0, 0, ky, dx - sx * kx, dy - sy * ky];\n}\n\n/** Rotation by `rad` about pivot (cx,cy): translate(c)·rotate·translate(-c). */\nexport function rotateAboutPoint(cx: number, cy: number, rad: number): Mat3 {\n return multiply(translate(cx, cy), multiply(rotate(rad), translate(-cx, -cy)));\n}\n","/** Axis-aligned box as [minX, minY, maxX, maxY]. */\nexport type Box = [number, number, number, number];\n\n/** An axis-aligned rectangle in object form. `Box` is the tuple form; this is\n * the one that survives being read by a human. */\nexport interface Rect { x: number; y: number; width: number; height: number }\n\n/** Tight bounds of an interleaved coord stream, or null if empty. */\nexport function boundsOfCoords(coords: ArrayLike<number>): Box | null {\n if (coords.length < 2) return null;\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (let i = 0; i + 1 < coords.length; i += 2) {\n const x = coords[i], y = coords[i + 1];\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n }\n return [minX, minY, maxX, maxY];\n}\n\n/** Smallest box containing both inputs. */\nexport function unionBox(a: Box, b: Box): Box {\n return [\n Math.min(a[0], b[0]),\n Math.min(a[1], b[1]),\n Math.max(a[2], b[2]),\n Math.max(a[3], b[3]),\n ];\n}\n\n/** Inclusive point-in-box test. */\nexport function boxContainsPoint(b: Box, x: number, y: number): boolean {\n return x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3];\n}\n\n/** Interleaved corner ring for a rect at (x,y,w,h), wound clockwise from the\n * origin corner. The closing edge is implicit — the same unclosed shape\n * `pointInPolygon` takes, and what a repeated first vertex would leave as a\n * zero-length segment for anything that strokes it. */\nexport function rectToContour(x: number, y: number, w: number, h: number): Float64Array {\n return Float64Array.of(x, y, x + w, y, x + w, y + h, x, y + h);\n}\n","import { sign, dot, len2 } from './scalar';\n\n/**\n * Even-odd ray-cast point-in-polygon over an interleaved, unclosed contour\n * [x0,y0,x1,y1,…]. The closing edge (last→first) is implicit.\n *\n * `start`/`end` are vertex indices, not float offsets, and bound one contour\n * inside a buffer holding several.\n */\nexport function pointInPolygon(\n coords: ArrayLike<number>,\n px: number,\n py: number,\n start = 0,\n end = coords.length >> 1,\n): boolean {\n if (end - start < 3) return false;\n let inside = false;\n for (let i = start, j = end - 1; i < end; j = i++) {\n const xi = coords[i * 2], yi = coords[i * 2 + 1];\n const xj = coords[j * 2], yj = coords[j * 2 + 1];\n const crosses =\n (yi > py) !== (yj > py) &&\n px < ((xj - xi) * (py - yi)) / (yj - yi) + xi;\n if (crosses) inside = !inside;\n }\n return inside;\n}\n\n/**\n * True if segments (ax,ay)-(bx,by) and (cx,cy)-(dx,dy) intersect at a single\n * point. An endpoint landing on the other segment counts (a T-junction and a\n * shared endpoint both answer true) — hit-testing wants a grazing edge to\n * register. Collinear overlap answers false: there is no single crossing\n * point, so the sign test both segments rely on is zero on all four sides.\n */\nexport function segmentsCross(\n ax: number, ay: number, bx: number, by: number,\n cx: number, cy: number, dx: number, dy: number,\n): boolean {\n const d1 = sign((dx - cx) * (ay - cy) - (dy - cy) * (ax - cx));\n const d2 = sign((dx - cx) * (by - cy) - (dy - cy) * (bx - cx));\n const d3 = sign((bx - ax) * (cy - ay) - (by - ay) * (cx - ax));\n const d4 = sign((bx - ax) * (dy - ay) - (by - ay) * (dx - ax));\n return d1 !== d2 && d3 !== d4;\n}\n\n/** Squared distance from (px,py) to segment (ax,ay)-(bx,by), endpoint-clamped. */\nexport function pointSegmentDist2(\n px: number, py: number, ax: number, ay: number, bx: number, by: number,\n): number {\n const vx = bx - ax, vy = by - ay;\n const wx = px - ax, wy = py - ay;\n const vv = len2(vx, vy);\n let t = vv === 0 ? 0 : dot(wx, wy, vx, vy) / vv;\n t = t < 0 ? 0 : t > 1 ? 1 : t;\n const dx = px - (ax + t * vx), dy = py - (ay + t * vy);\n return len2(dx, dy);\n}\n","import type { Mat3 } from './mat3';\n\n/**\n * Apply an affine to an interleaved coord stream, returning a fresh f64\n * buffer. Command codes are unaffected — for a Bezier the transformed control\n * points define the transformed curve exactly (affine invariance), so callers\n * pass `path.coords` straight through and keep `path.commands` as-is.\n */\nexport function transformCoords(coords: ArrayLike<number>, m: Mat3): Float64Array {\n const out = new Float64Array(coords.length);\n const a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];\n for (let i = 0; i + 1 < coords.length; i += 2) {\n const x = coords[i], y = coords[i + 1];\n out[i] = a * x + c * y + e;\n out[i + 1] = b * x + d * y + f;\n }\n return out;\n}\n","import type { Rect } from './box';\n\n/** Which side of the anchor the overlay sits on. */\nexport type PlacementSide = 'top' | 'bottom' | 'left' | 'right';\n\n/** How the overlay lines up along the side it sits on. */\nexport type PlacementAlign = 'start' | 'center' | 'end';\n\n/** A side paired with an alignment along it. */\nexport interface Placement {\n side: PlacementSide;\n align: PlacementAlign;\n}\n\n/** Inputs to {@link placeRect}. All rects share one coordinate space. */\nexport interface PlaceRectOptions {\n anchor: Rect;\n overlay: { width: number; height: number };\n boundary: Rect;\n placement: Placement;\n /** Gap between anchor and overlay along the side axis. Default 0. */\n offset?: number;\n /** Shift along the alignment axis. Default 0. */\n crossOffset?: number;\n /** Minimum gap kept between the overlay and the boundary. Default 0. */\n padding?: number;\n /** Whether to try the opposite side when the preferred one lacks room. Default true. */\n flip?: boolean;\n}\n\n/** Where the overlay landed, and the placement that produced it. */\nexport interface PlacedRect {\n rect: Rect;\n placement: Placement;\n}\n\nfunction alignAlong(start: number, extent: number, size: number, align: PlacementAlign): number {\n if (align === 'start') return start;\n if (align === 'end') return start + extent - size;\n return start + (extent - size) / 2;\n}\n\nfunction positionOn(\n anchor: Rect,\n overlay: { width: number; height: number },\n placement: Placement,\n offset: number,\n crossOffset: number,\n): Rect {\n const { width, height } = overlay;\n const { side, align } = placement;\n if (side === 'top' || side === 'bottom') {\n const y = side === 'bottom' ? anchor.y + anchor.height + offset : anchor.y - offset - height;\n return { x: alignAlong(anchor.x, anchor.width, width, align) + crossOffset, y, width, height };\n }\n const x = side === 'right' ? anchor.x + anchor.width + offset : anchor.x - offset - width;\n return { x, y: alignAlong(anchor.y, anchor.height, height, align) + crossOffset, width, height };\n}\n\nfunction clampAxis(start: number, size: number, low: number, extent: number, padding: number): number {\n const min = low + padding;\n return Math.max(min, Math.min(start, min + extent - padding * 2 - size));\n}\n\n/**\n * Move `rect` the shortest distance that puts it inside `boundary`, keeping its\n * size. A rect too big to fit pins to the boundary's leading edge.\n */\nexport function clampRectWithin(rect: Rect, boundary: Rect, padding = 0): Rect {\n return {\n ...rect,\n x: clampAxis(rect.x, rect.width, boundary.x, boundary.width, padding),\n y: clampAxis(rect.y, rect.height, boundary.y, boundary.height, padding),\n };\n}\n\n/** Slide along the alignment axis until the overlay is inside. */\nfunction shiftAcross(rect: Rect, boundary: Rect, side: PlacementSide, padding: number): Rect {\n const vertical = side === 'top' || side === 'bottom';\n const size = vertical ? rect.width : rect.height;\n const low = (vertical ? boundary.x : boundary.y) + padding;\n const high = low + (vertical ? boundary.width : boundary.height) - padding * 2 - size;\n const placed = Math.max(low, Math.min(vertical ? rect.x : rect.y, high));\n return vertical ? { ...rect, x: placed } : { ...rect, y: placed };\n}\n\nconst OPPOSITE: Record<PlacementSide, PlacementSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\nfunction fitsAlongSide(rect: Rect, boundary: Rect, side: PlacementSide, padding: number): boolean {\n const vertical = side === 'top' || side === 'bottom';\n const start = vertical ? rect.y : rect.x;\n const end = start + (vertical ? rect.height : rect.width);\n const low = (vertical ? boundary.y : boundary.x) + padding;\n const high = low + (vertical ? boundary.height : boundary.width) - padding * 2;\n return start >= low && end <= high;\n}\n\nexport function placeRect(options: PlaceRectOptions): PlacedRect {\n const { anchor, overlay, boundary, placement, offset = 0, crossOffset = 0 } = options;\n const { padding = 0, flip = true } = options;\n\n let resolved = placement;\n let rect = positionOn(anchor, overlay, resolved, offset, crossOffset);\n\n if (flip && !fitsAlongSide(rect, boundary, resolved.side, padding)) {\n const opposite = { side: OPPOSITE[resolved.side], align: resolved.align };\n const flipped = positionOn(anchor, overlay, opposite, offset, crossOffset);\n if (fitsAlongSide(flipped, boundary, opposite.side, padding)) {\n resolved = opposite;\n rect = flipped;\n }\n }\n\n return { rect: shiftAcross(rect, boundary, resolved.side, padding), placement: resolved };\n}\n"]}
1
+ {"version":3,"sources":["../src/mat3.ts","../src/box.ts","../src/portCurve2.ts","../src/polyline.ts","../src/affine.ts","../src/place.ts"],"names":["portControls"],"mappings":";;;;;AAoBO,SAAS,QAAA,GAAiB;AAC/B,EAAA,OAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AAC1B;AAGO,SAAS,SAAA,CAAU,IAAY,EAAA,EAAkB;AACtD,EAAA,OAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,IAAI,EAAE,CAAA;AAC5B;AAIO,SAAS,KAAA,CAAM,IAAY,EAAA,EAAkB;AAClD,EAAA,OAAO,CAAC,EAAA,EAAI,CAAA,EAAG,CAAA,EAAG,EAAA,EAAI,GAAG,CAAC,CAAA;AAC5B;AAIO,SAAS,OAAO,GAAA,EAAmB;AACxC,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACtB,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AACtB,EAAA,OAAO,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AAC3B;AAGO,SAAS,QAAA,CAAS,GAAS,CAAA,EAAe;AAC/C,EAAA,OAAO;AAAA,IACL,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,IAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAAA,IACxB,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,IAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAAA,IACxB,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,IAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAAA,IACxB,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,IAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAAA,IACxB,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,EAAE,CAAC,CAAA;AAAA,IAC/B,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,EAAE,CAAC;AAAA,GACjC;AACF;AAIO,SAAS,OAAO,CAAA,EAAsB;AAC3C,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAEpC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAC,CAAA;AAE3E,EAAA,IAAI,EAAE,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,cAAA,GAAiB,QAAQ,OAAO,IAAA;AACtD,EAAA,MAAM,KAAK,CAAA,GAAI,GAAA;AACf,EAAA,MAAM,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA;AACjB,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA;AAClB,EAAA,MAAM,CAAA,GAAI,CAAC,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA;AAClB,EAAA,MAAM,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,EAAA;AACjB,EAAA,OAAO,CAAC,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,EAAE,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC,IAAI,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,CAAE,CAAA;AACpE;AAGO,SAAS,YAAA,CAAa,CAAA,EAAS,CAAA,EAAW,CAAA,EAA6B;AAC5E,EAAA,OAAO,CAAC,EAAE,CAAC,CAAA,GAAI,IAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,GAAI,CAAA,CAAE,CAAC,GAAG,CAAA,CAAE,CAAC,IAAI,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA,GAAI,CAAA,CAAE,CAAC,CAAC,CAAA;AAChE;AAGO,SAAS,QAAA,CACd,IAAY,EAAA,EAAY,EAAA,EAAY,IACpC,EAAA,EAAY,EAAA,EAAY,IAAY,EAAA,EAC9B;AACN,EAAA,MAAM,EAAA,GAAK,EAAA,KAAO,CAAA,GAAI,CAAA,GAAI,EAAA,GAAK,EAAA;AAC/B,EAAA,MAAM,EAAA,GAAK,EAAA,KAAO,CAAA,GAAI,CAAA,GAAI,EAAA,GAAK,EAAA;AAE/B,EAAA,OAAO,CAAC,EAAA,EAAI,CAAA,EAAG,CAAA,EAAG,EAAA,EAAI,KAAK,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,GAAK,EAAE,CAAA;AAClD;AAGO,SAAS,gBAAA,CAAiB,EAAA,EAAY,EAAA,EAAY,GAAA,EAAmB;AAC1E,EAAA,OAAO,QAAA,CAAS,SAAA,CAAU,EAAA,EAAI,EAAE,GAAG,QAAA,CAAS,MAAA,CAAO,GAAG,CAAA,EAAG,UAAU,CAAC,EAAA,EAAI,CAAC,EAAE,CAAC,CAAC,CAAA;AAC/E;;;AClFO,SAAS,eAAe,MAAA,EAAuC;AACpE,EAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,OAAO,IAAA;AAC9B,EAAA,IAAI,OAAO,QAAA,EAAU,IAAA,GAAO,QAAA,EAAU,IAAA,GAAO,WAAW,IAAA,GAAO,CAAA,QAAA;AAC/D,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AAC7C,IAAA,MAAM,IAAI,MAAA,CAAO,CAAC,GAAG,CAAA,GAAI,MAAA,CAAO,IAAI,CAAC,CAAA;AACrC,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AACrB,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AACrB,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AACrB,IAAA,IAAI,CAAA,GAAI,MAAM,IAAA,GAAO,CAAA;AAAA,EACvB;AACA,EAAA,OAAO,CAAC,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA;AAChC;AAGO,SAAS,QAAA,CAAS,GAAQ,CAAA,EAAa;AAC5C,EAAA,OAAO;AAAA,IACL,KAAK,GAAA,CAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IACnB,KAAK,GAAA,CAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IACnB,KAAK,GAAA,CAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IACnB,KAAK,GAAA,CAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAC;AAAA,GACrB;AACF;AAGO,SAAS,gBAAA,CAAiB,CAAA,EAAQ,CAAA,EAAW,CAAA,EAAoB;AACtE,EAAA,OAAO,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,IAAK,KAAK,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,IAAK,CAAA,IAAK,EAAE,CAAC,CAAA;AACxD;AAMO,SAAS,aAAA,CAAc,CAAA,EAAW,CAAA,EAAW,CAAA,EAAW,CAAA,EAAyB;AACtF,EAAA,OAAO,YAAA,CAAa,EAAA,CAAG,CAAA,EAAG,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAG,IAAI,CAAC,CAAA;AAC/D;;;AC1BO,SAASA,aAAAA,CACd,IACA,EAAA,EACA,EAAA,EACA,IACA,SAAA,EACA,QAAA,EACA,QAAgB,UAAA,EACsB;AACtC,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,aAAc,CAAC,EAAA,EAAI,EAAE,CAAA,EAAG,CAAC,EAAA,EAAI,EAAE,CAAA,EAAG,SAAA,EAAW,UAAU,KAAK,CAAA;AAC7E,EAAA,OAAO;AAAA,IACL,CAAC,EAAA,CAAG,CAAC,CAAA,EAAI,EAAA,CAAG,CAAC,CAAE,CAAA;AAAA,IACf,CAAC,EAAA,CAAG,CAAC,CAAA,EAAI,EAAA,CAAG,CAAC,CAAE;AAAA,GACjB;AACF;AAGO,SAAS,eAAA,CACd,IACA,EAAA,EACA,EAAA,EACA,IACA,SAAA,EACA,QAAA,EACA,OAAA,EACA,KAAA,GAAgB,UAAA,EACI;AACpB,EAAA,MAAM,CAAA,GAAI,CAAC,EAAA,EAAI,EAAE,CAAA;AACjB,EAAA,MAAM,CAAA,GAAI,CAAC,EAAA,EAAI,EAAE,CAAA;AACjB,EAAA,MAAM,CAAC,IAAI,EAAE,CAAA,GAAI,aAAc,CAAA,EAAG,CAAA,EAAG,SAAA,EAAW,QAAA,EAAU,KAAK,CAAA;AAC/D,EAAA,MAAM,MAA0B,EAAC;AACjC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,IAAK,OAAA,EAAS,CAAA,EAAA,EAAK;AACjC,IAAA,MAAM,IAAI,OAAA,CAAS,CAAA,EAAG,IAAI,EAAA,EAAI,CAAA,EAAG,IAAI,OAAO,CAAA;AAC5C,IAAA,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA,CAAE,CAAC,GAAI,CAAA,CAAE,CAAC,CAAE,CAAC,CAAA;AAAA,EACzB;AACA,EAAA,OAAO,GAAA;AACT;;;AC3CO,SAAS,cAAA,CACd,QACA,EAAA,EACA,EAAA,EACA,QAAQ,CAAA,EACR,GAAA,GAAM,MAAA,CAAO,MAAA,IAAU,CAAA,EACd;AACT,EAAA,IAAI,GAAA,GAAM,KAAA,GAAQ,CAAA,EAAG,OAAO,KAAA;AAC5B,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,KAAA,IAAS,CAAA,GAAI,OAAO,CAAA,GAAI,GAAA,GAAM,GAAG,CAAA,GAAI,GAAA,EAAK,IAAI,CAAA,EAAA,EAAK;AACjD,IAAA,MAAM,EAAA,GAAK,OAAO,CAAA,GAAI,CAAC,GAAG,EAAA,GAAK,MAAA,CAAO,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA;AAC/C,IAAA,MAAM,EAAA,GAAK,OAAO,CAAA,GAAI,CAAC,GAAG,EAAA,GAAK,MAAA,CAAO,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA;AAC/C,IAAA,MAAM,OAAA,GACH,EAAA,GAAK,EAAA,KAAS,EAAA,GAAK,EAAA,IACpB,EAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAA,IAAQ,EAAA,GAAK,EAAA,CAAA,GAAM,EAAA;AAC7C,IAAA,IAAI,OAAA,WAAkB,CAAC,MAAA;AAAA,EACzB;AACA,EAAA,OAAO,MAAA;AACT;AASO,SAAS,aAAA,CACd,IAAY,EAAA,EAAY,EAAA,EAAY,IACpC,EAAA,EAAY,EAAA,EAAY,IAAY,EAAA,EAC3B;AACT,EAAA,MAAM,EAAA,GAAK,MAAM,EAAA,GAAK,EAAA,KAAO,KAAK,EAAA,CAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAG,CAAA;AAC7D,EAAA,MAAM,EAAA,GAAK,MAAM,EAAA,GAAK,EAAA,KAAO,KAAK,EAAA,CAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAG,CAAA;AAC7D,EAAA,MAAM,EAAA,GAAK,MAAM,EAAA,GAAK,EAAA,KAAO,KAAK,EAAA,CAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAG,CAAA;AAC7D,EAAA,MAAM,EAAA,GAAK,MAAM,EAAA,GAAK,EAAA,KAAO,KAAK,EAAA,CAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAG,CAAA;AAC7D,EAAA,OAAO,EAAA,KAAO,MAAM,EAAA,KAAO,EAAA;AAC7B;AAGO,SAAS,kBACd,EAAA,EAAY,EAAA,EAAY,EAAA,EAAY,EAAA,EAAY,IAAY,EAAA,EACpD;AACR,EAAA,MAAM,EAAA,GAAK,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,GAAK,EAAA;AAC9B,EAAA,MAAM,EAAA,GAAK,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAA,GAAK,EAAA;AAC9B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,EAAA,EAAI,EAAE,CAAA;AACtB,EAAA,IAAI,CAAA,GAAI,OAAO,CAAA,GAAI,CAAA,GAAI,IAAI,EAAA,EAAI,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA,GAAI,EAAA;AAC7C,EAAA,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AAC5B,EAAA,MAAM,EAAA,GAAK,MAAM,EAAA,GAAK,CAAA,GAAI,KAAK,EAAA,GAAK,EAAA,IAAM,KAAK,CAAA,GAAI,EAAA,CAAA;AACnD,EAAA,OAAO,IAAA,CAAK,IAAI,EAAE,CAAA;AACpB;;;AClDO,SAAS,eAAA,CAAgB,QAA2B,CAAA,EAAuB;AAChF,EAAA,MAAM,GAAA,GAAM,IAAI,YAAA,CAAa,MAAA,CAAO,MAAM,CAAA;AAC1C,EAAA,MAAM,CAAA,GAAI,EAAE,CAAC,CAAA,EAAG,IAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,CAAC,GAAG,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,GAAI,EAAE,CAAC,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAC/D,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AAC7C,IAAA,MAAM,IAAI,MAAA,CAAO,CAAC,GAAG,CAAA,GAAI,MAAA,CAAO,IAAI,CAAC,CAAA;AACrC,IAAA,GAAA,CAAI,CAAC,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACzB,IAAA,GAAA,CAAI,IAAI,CAAC,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,GAAA;AACT;;;ACmBA,SAAS,UAAA,CAAW,KAAA,EAAe,MAAA,EAAgB,IAAA,EAAc,KAAA,EAA+B;AAC9F,EAAA,IAAI,KAAA,KAAU,SAAS,OAAO,KAAA;AAC9B,EAAA,IAAI,KAAA,KAAU,KAAA,EAAO,OAAO,KAAA,GAAQ,MAAA,GAAS,IAAA;AAC7C,EAAA,OAAO,KAAA,GAAA,CAAS,SAAS,IAAA,IAAQ,CAAA;AACnC;AAEA,SAAS,UAAA,CACP,MAAA,EACA,OAAA,EACA,SAAA,EACA,QACA,WAAA,EACM;AACN,EAAA,MAAM,EAAE,KAAA,EAAO,MAAA,EAAO,GAAI,OAAA;AAC1B,EAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,SAAA;AACxB,EAAA,IAAI,IAAA,KAAS,KAAA,IAAS,IAAA,KAAS,QAAA,EAAU;AACvC,IAAA,MAAM,CAAA,GAAI,IAAA,KAAS,QAAA,GAAW,MAAA,CAAO,CAAA,GAAI,OAAO,MAAA,GAAS,MAAA,GAAS,MAAA,CAAO,CAAA,GAAI,MAAA,GAAS,MAAA;AACtF,IAAA,OAAO,EAAE,CAAA,EAAG,UAAA,CAAW,MAAA,CAAO,CAAA,EAAG,MAAA,CAAO,KAAA,EAAO,KAAA,EAAO,KAAK,CAAA,GAAI,WAAA,EAAa,CAAA,EAAG,OAAO,MAAA,EAAO;AAAA,EAC/F;AACA,EAAA,MAAM,CAAA,GAAI,IAAA,KAAS,OAAA,GAAU,MAAA,CAAO,CAAA,GAAI,OAAO,KAAA,GAAQ,MAAA,GAAS,MAAA,CAAO,CAAA,GAAI,MAAA,GAAS,KAAA;AACpF,EAAA,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,UAAA,CAAW,MAAA,CAAO,CAAA,EAAG,MAAA,CAAO,MAAA,EAAQ,MAAA,EAAQ,KAAK,CAAA,GAAI,WAAA,EAAa,OAAO,MAAA,EAAO;AACjG;AAEA,SAAS,SAAA,CAAU,KAAA,EAAe,IAAA,EAAc,GAAA,EAAa,QAAgB,OAAA,EAAyB;AACpG,EAAA,MAAM,MAAM,GAAA,GAAM,OAAA;AAClB,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,GAAA,GAAM,MAAA,GAAS,OAAA,GAAU,CAAA,GAAI,IAAI,CAAC,CAAA;AACzE;AAMO,SAAS,eAAA,CAAgB,IAAA,EAAY,QAAA,EAAgB,OAAA,GAAU,CAAA,EAAS;AAC7E,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,CAAA,EAAG,SAAA,CAAU,IAAA,CAAK,CAAA,EAAG,IAAA,CAAK,OAAO,QAAA,CAAS,CAAA,EAAG,QAAA,CAAS,KAAA,EAAO,OAAO,CAAA;AAAA,IACpE,CAAA,EAAG,SAAA,CAAU,IAAA,CAAK,CAAA,EAAG,IAAA,CAAK,QAAQ,QAAA,CAAS,CAAA,EAAG,QAAA,CAAS,MAAA,EAAQ,OAAO;AAAA,GACxE;AACF;AAGA,SAAS,WAAA,CAAY,IAAA,EAAY,QAAA,EAAgB,IAAA,EAAqB,OAAA,EAAuB;AAC3F,EAAA,MAAM,QAAA,GAAW,IAAA,KAAS,KAAA,IAAS,IAAA,KAAS,QAAA;AAC5C,EAAA,MAAM,IAAA,GAAO,QAAA,GAAW,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,MAAA;AAC1C,EAAA,MAAM,GAAA,GAAA,CAAO,QAAA,GAAW,QAAA,CAAS,CAAA,GAAI,SAAS,CAAA,IAAK,OAAA;AACnD,EAAA,MAAM,IAAA,GAAO,OAAO,QAAA,GAAW,QAAA,CAAS,QAAQ,QAAA,CAAS,MAAA,CAAA,GAAU,UAAU,CAAA,GAAI,IAAA;AACjF,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,CAAA,EAAG,IAAI,CAAC,CAAA;AACvE,EAAA,OAAO,QAAA,GAAW,EAAE,GAAG,IAAA,EAAM,CAAA,EAAG,MAAA,EAAO,GAAI,EAAE,GAAG,IAAA,EAAM,CAAA,EAAG,MAAA,EAAO;AAClE;AAEA,IAAM,QAAA,GAAiD;AAAA,EACrD,GAAA,EAAK,QAAA;AAAA,EACL,MAAA,EAAQ,KAAA;AAAA,EACR,IAAA,EAAM,OAAA;AAAA,EACN,KAAA,EAAO;AACT,CAAA;AAEA,SAAS,aAAA,CAAc,IAAA,EAAY,QAAA,EAAgB,IAAA,EAAqB,OAAA,EAA0B;AAChG,EAAA,MAAM,QAAA,GAAW,IAAA,KAAS,KAAA,IAAS,IAAA,KAAS,QAAA;AAC5C,EAAA,MAAM,KAAA,GAAQ,QAAA,GAAW,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,CAAA;AACvC,EAAA,MAAM,GAAA,GAAM,KAAA,IAAS,QAAA,GAAW,IAAA,CAAK,SAAS,IAAA,CAAK,KAAA,CAAA;AACnD,EAAA,MAAM,GAAA,GAAA,CAAO,QAAA,GAAW,QAAA,CAAS,CAAA,GAAI,SAAS,CAAA,IAAK,OAAA;AACnD,EAAA,MAAM,OAAO,GAAA,IAAO,QAAA,GAAW,SAAS,MAAA,GAAS,QAAA,CAAS,SAAS,OAAA,GAAU,CAAA;AAC7E,EAAA,OAAO,KAAA,IAAS,OAAO,GAAA,IAAO,IAAA;AAChC;AAEO,SAAS,UAAU,OAAA,EAAuC;AAC/D,EAAA,MAAM,EAAE,QAAQ,OAAA,EAAS,QAAA,EAAU,WAAW,MAAA,GAAS,CAAA,EAAG,WAAA,GAAc,CAAA,EAAE,GAAI,OAAA;AAC9E,EAAA,MAAM,EAAE,OAAA,GAAU,CAAA,EAAG,IAAA,GAAO,MAAK,GAAI,OAAA;AAErC,EAAA,IAAI,QAAA,GAAW,SAAA;AACf,EAAA,IAAI,OAAO,UAAA,CAAW,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,QAAQ,WAAW,CAAA;AAEpE,EAAA,IAAI,IAAA,IAAQ,CAAC,aAAA,CAAc,IAAA,EAAM,UAAU,QAAA,CAAS,IAAA,EAAM,OAAO,CAAA,EAAG;AAClE,IAAA,MAAM,QAAA,GAAW,EAAE,IAAA,EAAM,QAAA,CAAS,SAAS,IAAI,CAAA,EAAG,KAAA,EAAO,QAAA,CAAS,KAAA,EAAM;AACxE,IAAA,MAAM,UAAU,UAAA,CAAW,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU,QAAQ,WAAW,CAAA;AACzE,IAAA,IAAI,cAAc,OAAA,EAAS,QAAA,EAAU,QAAA,CAAS,IAAA,EAAM,OAAO,CAAA,EAAG;AAC5D,MAAA,QAAA,GAAW,QAAA;AACX,MAAA,IAAA,GAAO,OAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,QAAA,EAAU,SAAS,IAAA,EAAM,OAAO,CAAA,EAAG,SAAA,EAAW,QAAA,EAAS;AAC1F","file":"index.js","sourcesContent":["/**\n * 2D affine transforms in canvas/DOMMatrix order: [a, b, c, d, e, f].\n * x' = a·x + c·y + e\n * y' = b·x + d·y + f\n * Represented as a readonly 6-tuple (f64). The affine tier of the kernel.\n *\n * Convention alignment: the renderer already has a `Mat3` in\n * `src/renderer/math/mat3.ts`. That one is a 9-element column-major\n * `Float32Array` (a full 3×3) shaped for `uniformMatrix3fv` — a deliberately\n * different *representation* for the WebGL upload path. Its *logical element\n * order* is identical to ours: `create(a, b, c, d, tx, ty)` maps\n * `x' = a·x + c·y + tx`, `y' = b·x + d·y + ty` (canvas/DOMMatrix a,b,c,d,e,f).\n * We keep the pure 6-tuple f64 form here (the kernel form); the 9-element f32\n * form stays a render-layer concern. No second logical convention is created.\n */\nimport { SINGULAR_RATIO } from './scalar';\n\nexport type Mat3 = readonly [number, number, number, number, number, number];\n\n/** The transform that leaves a point where it is. */\nexport function identity(): Mat3 {\n return [1, 0, 0, 1, 0, 0];\n}\n\n/** A pure translation by `(tx, ty)`. */\nexport function translate(tx: number, ty: number): Mat3 {\n return [1, 0, 0, 1, tx, ty];\n}\n\n/** A pure scale about the origin. Scale about another point by composing\n * translate → scale → inverse translate with `multiply`. */\nexport function scale(sx: number, sy: number): Mat3 {\n return [sx, 0, 0, sy, 0, 0];\n}\n\n/** A pure rotation about the origin, in radians, clockwise in canvas\n * coordinates (y down). */\nexport function rotate(rad: number): Mat3 {\n const c = Math.cos(rad);\n const s = Math.sin(rad);\n return [c, s, -s, c, 0, 0];\n}\n\n/** Compose: result applies `n` first, then `m` (m·n). */\nexport function multiply(m: Mat3, n: Mat3): Mat3 {\n return [\n m[0] * n[0] + m[2] * n[1],\n m[1] * n[0] + m[3] * n[1],\n m[0] * n[2] + m[2] * n[3],\n m[1] * n[2] + m[3] * n[3],\n m[0] * n[4] + m[2] * n[5] + m[4],\n m[1] * n[4] + m[3] * n[5] + m[5],\n ];\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: Mat3): Mat3 | null {\n const det = m[0] * m[3] - m[1] * m[2];\n // The determinant is an area, so it is judged against the squared column norms.\n const norm2 = Math.max(m[0] * m[0] + m[1] * m[1], m[2] * m[2] + m[3] * m[3]);\n // Negated so a non-finite determinant falls out as singular.\n if (!(Math.abs(det) > SINGULAR_RATIO * norm2)) return null;\n const id = 1 / det;\n const a = m[3] * id;\n const b = -m[1] * id;\n const c = -m[2] * id;\n const d = m[0] * id;\n return [a, b, c, d, -(m[4] * a + m[5] * c), -(m[4] * b + m[5] * d)];\n}\n\n/** Apply to a point, returning a tuple. Cold-path use; hot loops inline. */\nexport function applyToPoint(m: Mat3, x: number, y: number): [number, number] {\n return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];\n}\n\n/** Affine that maps source box (sx,sy,sw,sh) onto destination box (dx,dy,dw,dh). */\nexport function boxToBox(\n sx: number, sy: number, sw: number, sh: number,\n dx: number, dy: number, dw: number, dh: number,\n): Mat3 {\n const kx = sw === 0 ? 1 : dw / sw;\n const ky = sh === 0 ? 1 : dh / sh;\n // translate(dx,dy) · scale(kx,ky) · translate(-sx,-sy)\n return [kx, 0, 0, ky, dx - sx * kx, dy - sy * ky];\n}\n\n/** Rotation by `rad` about pivot (cx,cy): translate(c)·rotate·translate(-c). */\nexport function rotateAboutPoint(cx: number, cy: number, rad: number): Mat3 {\n return multiply(translate(cx, cy), multiply(rotate(rad), translate(-cx, -cy)));\n}\n","/** Axis-aligned box as [minX, minY, maxX, maxY]. */\nexport type Box = readonly [number, number, number, number];\n\n/** An axis-aligned rectangle in object form. `Box` is the tuple form; this is\n * the one that survives being read by a human. */\nexport interface Rect { x: number; y: number; width: number; height: number }\n\n/** Tight bounds of an interleaved coord stream, or null if empty. */\nexport function boundsOfCoords(coords: ArrayLike<number>): Box | null {\n if (coords.length < 2) return null;\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (let i = 0; i + 1 < coords.length; i += 2) {\n const x = coords[i], y = coords[i + 1];\n if (x < minX) minX = x;\n if (y < minY) minY = y;\n if (x > maxX) maxX = x;\n if (y > maxY) maxY = y;\n }\n return [minX, minY, maxX, maxY];\n}\n\n/** Smallest box containing both inputs. */\nexport function unionBox(a: Box, b: Box): Box {\n return [\n Math.min(a[0], b[0]),\n Math.min(a[1], b[1]),\n Math.max(a[2], b[2]),\n Math.max(a[3], b[3]),\n ];\n}\n\n/** Inclusive point-in-box test. */\nexport function boxContainsPoint(b: Box, x: number, y: number): boolean {\n return x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3];\n}\n\n/** Interleaved corner ring for a rect at (x,y,w,h), wound clockwise from the\n * origin corner. The closing edge is implicit — the same unclosed shape\n * `pointInPolygon` takes, and what a repeated first vertex would leave as a\n * zero-length segment for anything that strokes it. */\nexport function rectToContour(x: number, y: number, w: number, h: number): Float64Array {\n return Float64Array.of(x, y, x + w, y, x + w, y + h, x, y + h);\n}\n","/**\n * The port-curve rule in the 2D kernel's currency: loose scalars, the way\n * `cubicEvalAt` and `applyToPoint` take them. The rule itself lives in\n * `./portCurve`, stated once over components, so this and `./3d` cannot drift.\n */\n\nimport { PORT_REACH, cubicAt as cubicAtN, portControls as portControlsN } from './portCurve';\n\nexport { PORT_REACH };\n\n/**\n * `[c1, c2]` for the cubic from `(ax, ay)` to `(bx, by)`.\n *\n * A null normal falls back to a lerp along the chord. See `./portCurve` for why\n * the two ends are not symmetric.\n */\nexport function portControls(\n ax: number,\n ay: number,\n bx: number,\n by: number,\n outNormal: readonly [number, number] | null | undefined,\n inNormal: readonly [number, number] | null | undefined,\n reach: number = PORT_REACH,\n): [[number, number], [number, number]] {\n const [c1, c2] = portControlsN([ax, ay], [bx, by], outNormal, inNormal, reach);\n return [\n [c1[0]!, c1[1]!],\n [c2[0]!, c2[1]!],\n ];\n}\n\n/** A port curve sampled into `samples` points, excluding its start. */\nexport function portCurvePoints(\n ax: number,\n ay: number,\n bx: number,\n by: number,\n outNormal: readonly [number, number] | null | undefined,\n inNormal: readonly [number, number] | null | undefined,\n samples: number,\n reach: number = PORT_REACH,\n): [number, number][] {\n const a = [ax, ay];\n const b = [bx, by];\n const [c1, c2] = portControlsN(a, b, outNormal, inNormal, reach);\n const out: [number, number][] = [];\n for (let s = 1; s <= samples; s++) {\n const p = cubicAtN(a, c1, c2, b, s / samples);\n out.push([p[0]!, p[1]!]);\n }\n return out;\n}\n","import { sign, dot, len2 } from './scalar';\n\n/**\n * Even-odd ray-cast point-in-polygon over an interleaved, unclosed contour\n * [x0,y0,x1,y1,…]. The closing edge (last→first) is implicit.\n *\n * `start`/`end` are vertex indices, not float offsets, and bound one contour\n * inside a buffer holding several.\n */\nexport function pointInPolygon(\n coords: ArrayLike<number>,\n px: number,\n py: number,\n start = 0,\n end = coords.length >> 1,\n): boolean {\n if (end - start < 3) return false;\n let inside = false;\n for (let i = start, j = end - 1; i < end; j = i++) {\n const xi = coords[i * 2], yi = coords[i * 2 + 1];\n const xj = coords[j * 2], yj = coords[j * 2 + 1];\n const crosses =\n (yi > py) !== (yj > py) &&\n px < ((xj - xi) * (py - yi)) / (yj - yi) + xi;\n if (crosses) inside = !inside;\n }\n return inside;\n}\n\n/**\n * True if segments (ax,ay)-(bx,by) and (cx,cy)-(dx,dy) intersect at a single\n * point. An endpoint landing on the other segment counts (a T-junction and a\n * shared endpoint both answer true) — hit-testing wants a grazing edge to\n * register. Collinear overlap answers false: there is no single crossing\n * point, so the sign test both segments rely on is zero on all four sides.\n */\nexport function segmentsCross(\n ax: number, ay: number, bx: number, by: number,\n cx: number, cy: number, dx: number, dy: number,\n): boolean {\n const d1 = sign((dx - cx) * (ay - cy) - (dy - cy) * (ax - cx));\n const d2 = sign((dx - cx) * (by - cy) - (dy - cy) * (bx - cx));\n const d3 = sign((bx - ax) * (cy - ay) - (by - ay) * (cx - ax));\n const d4 = sign((bx - ax) * (dy - ay) - (by - ay) * (dx - ax));\n return d1 !== d2 && d3 !== d4;\n}\n\n/** Squared distance from (px,py) to segment (ax,ay)-(bx,by), endpoint-clamped. */\nexport function pointSegmentDist2(\n px: number, py: number, ax: number, ay: number, bx: number, by: number,\n): number {\n const vx = bx - ax, vy = by - ay;\n const wx = px - ax, wy = py - ay;\n const vv = len2(vx, vy);\n let t = vv === 0 ? 0 : dot(wx, wy, vx, vy) / vv;\n t = t < 0 ? 0 : t > 1 ? 1 : t;\n const dx = px - (ax + t * vx), dy = py - (ay + t * vy);\n return len2(dx, dy);\n}\n","import type { Mat3 } from './mat3';\n\n/**\n * Apply an affine to an interleaved coord stream, returning a fresh f64\n * buffer. Command codes are unaffected — for a Bezier the transformed control\n * points define the transformed curve exactly (affine invariance), so callers\n * pass `path.coords` straight through and keep `path.commands` as-is.\n */\nexport function transformCoords(coords: ArrayLike<number>, m: Mat3): Float64Array {\n const out = new Float64Array(coords.length);\n const a = m[0], b = m[1], c = m[2], d = m[3], e = m[4], f = m[5];\n for (let i = 0; i + 1 < coords.length; i += 2) {\n const x = coords[i], y = coords[i + 1];\n out[i] = a * x + c * y + e;\n out[i + 1] = b * x + d * y + f;\n }\n return out;\n}\n","import type { Rect } from './box';\n\n/** Which side of the anchor the overlay sits on. */\nexport type PlacementSide = 'top' | 'bottom' | 'left' | 'right';\n\n/** How the overlay lines up along the side it sits on. */\nexport type PlacementAlign = 'start' | 'center' | 'end';\n\n/** A side paired with an alignment along it. */\nexport interface Placement {\n side: PlacementSide;\n align: PlacementAlign;\n}\n\n/** Inputs to {@link placeRect}. All rects share one coordinate space. */\nexport interface PlaceRectOptions {\n anchor: Rect;\n overlay: { width: number; height: number };\n boundary: Rect;\n placement: Placement;\n /** Gap between anchor and overlay along the side axis. Default 0. */\n offset?: number;\n /** Shift along the alignment axis. Default 0. */\n crossOffset?: number;\n /** Minimum gap kept between the overlay and the boundary. Default 0. */\n padding?: number;\n /** Whether to try the opposite side when the preferred one lacks room. Default true. */\n flip?: boolean;\n}\n\n/** Where the overlay landed, and the placement that produced it. */\nexport interface PlacedRect {\n rect: Rect;\n placement: Placement;\n}\n\nfunction alignAlong(start: number, extent: number, size: number, align: PlacementAlign): number {\n if (align === 'start') return start;\n if (align === 'end') return start + extent - size;\n return start + (extent - size) / 2;\n}\n\nfunction positionOn(\n anchor: Rect,\n overlay: { width: number; height: number },\n placement: Placement,\n offset: number,\n crossOffset: number,\n): Rect {\n const { width, height } = overlay;\n const { side, align } = placement;\n if (side === 'top' || side === 'bottom') {\n const y = side === 'bottom' ? anchor.y + anchor.height + offset : anchor.y - offset - height;\n return { x: alignAlong(anchor.x, anchor.width, width, align) + crossOffset, y, width, height };\n }\n const x = side === 'right' ? anchor.x + anchor.width + offset : anchor.x - offset - width;\n return { x, y: alignAlong(anchor.y, anchor.height, height, align) + crossOffset, width, height };\n}\n\nfunction clampAxis(start: number, size: number, low: number, extent: number, padding: number): number {\n const min = low + padding;\n return Math.max(min, Math.min(start, min + extent - padding * 2 - size));\n}\n\n/**\n * Move `rect` the shortest distance that puts it inside `boundary`, keeping its\n * size. A rect too big to fit pins to the boundary's leading edge.\n */\nexport function clampRectWithin(rect: Rect, boundary: Rect, padding = 0): Rect {\n return {\n ...rect,\n x: clampAxis(rect.x, rect.width, boundary.x, boundary.width, padding),\n y: clampAxis(rect.y, rect.height, boundary.y, boundary.height, padding),\n };\n}\n\n/** Slide along the alignment axis until the overlay is inside. */\nfunction shiftAcross(rect: Rect, boundary: Rect, side: PlacementSide, padding: number): Rect {\n const vertical = side === 'top' || side === 'bottom';\n const size = vertical ? rect.width : rect.height;\n const low = (vertical ? boundary.x : boundary.y) + padding;\n const high = low + (vertical ? boundary.width : boundary.height) - padding * 2 - size;\n const placed = Math.max(low, Math.min(vertical ? rect.x : rect.y, high));\n return vertical ? { ...rect, x: placed } : { ...rect, y: placed };\n}\n\nconst OPPOSITE: Record<PlacementSide, PlacementSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\nfunction fitsAlongSide(rect: Rect, boundary: Rect, side: PlacementSide, padding: number): boolean {\n const vertical = side === 'top' || side === 'bottom';\n const start = vertical ? rect.y : rect.x;\n const end = start + (vertical ? rect.height : rect.width);\n const low = (vertical ? boundary.y : boundary.x) + padding;\n const high = low + (vertical ? boundary.height : boundary.width) - padding * 2;\n return start >= low && end <= high;\n}\n\nexport function placeRect(options: PlaceRectOptions): PlacedRect {\n const { anchor, overlay, boundary, placement, offset = 0, crossOffset = 0 } = options;\n const { padding = 0, flip = true } = options;\n\n let resolved = placement;\n let rect = positionOn(anchor, overlay, resolved, offset, crossOffset);\n\n if (flip && !fitsAlongSide(rect, boundary, resolved.side, padding)) {\n const opposite = { side: OPPOSITE[resolved.side], align: resolved.align };\n const flipped = positionOn(anchor, overlay, opposite, offset, crossOffset);\n if (fitsAlongSide(flipped, boundary, opposite.side, padding)) {\n resolved = opposite;\n rect = flipped;\n }\n }\n\n return { rect: shiftAcross(rect, boundary, resolved.side, padding), placement: resolved };\n}\n"]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The cubic control points that make a curve leave a port along its normal and
3
+ * arrive at the next against that port's normal — what makes a routed edge read
4
+ * as plugged into a box rather than aimed at it.
5
+ *
6
+ * The rule is stated once, over loose components, and the 2D barrel and `./3d`
7
+ * each wrap it in their own currency. Every operation here is closed on the
8
+ * plane z = 0, so a planar problem answered through the 3D wrapper returns the
9
+ * same numbers as through the 2D one, not an approximation of them.
10
+ */
11
+ /** How far a control point reaches toward the other end, as a fraction of the
12
+ * straight-line distance between the two. */
13
+ declare const PORT_REACH = 0.4;
14
+
15
+ export { PORT_REACH as P };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@weasel-js/geom",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Pure geometry kernel for @weasel-js/core: affine, box, curve, polyline in 2D. Dependency-free core; polygon booleans in the ./booleans subpath, vectors, quaternions, 4x4 matrices and ray intersection in ./3d.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,29 +0,0 @@
1
- // src/scalar.ts
2
- var EPS = 1e-6;
3
- var SINGULAR_RATIO = 1e-12;
4
- function cross(ax, ay, bx, by) {
5
- return ax * by - ay * bx;
6
- }
7
- function dot(ax, ay, bx, by) {
8
- return ax * bx + ay * by;
9
- }
10
- function sub(ax, ay, bx, by) {
11
- return [ax - bx, ay - by];
12
- }
13
- function len2(x, y) {
14
- return x * x + y * y;
15
- }
16
- function sign(n) {
17
- return n > 0 ? 1 : n < 0 ? -1 : 0;
18
- }
19
- function approxEq(a, b, eps = EPS) {
20
- if (a === b) return true;
21
- const diff = Math.abs(a - b);
22
- if (!Number.isFinite(diff)) return false;
23
- const scale = Math.max(1, Math.abs(a), Math.abs(b));
24
- return diff <= eps * scale;
25
- }
26
-
27
- export { EPS, SINGULAR_RATIO, approxEq, cross, dot, len2, sign, sub };
28
- //# sourceMappingURL=chunk-NHMWNQTE.js.map
29
- //# sourceMappingURL=chunk-NHMWNQTE.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/scalar.ts"],"names":[],"mappings":";AAUO,IAAM,GAAA,GAAM;AAKZ,IAAM,cAAA,GAAiB;AAGvB,SAAS,KAAA,CAAM,EAAA,EAAY,EAAA,EAAY,EAAA,EAAY,EAAA,EAAoB;AAC5E,EAAA,OAAO,EAAA,GAAK,KAAK,EAAA,GAAK,EAAA;AACxB;AAGO,SAAS,GAAA,CAAI,EAAA,EAAY,EAAA,EAAY,EAAA,EAAY,EAAA,EAAoB;AAC1E,EAAA,OAAO,EAAA,GAAK,KAAK,EAAA,GAAK,EAAA;AACxB;AAGO,SAAS,GAAA,CAAI,EAAA,EAAY,EAAA,EAAY,EAAA,EAAY,EAAA,EAA8B;AACpF,EAAA,OAAO,CAAC,EAAA,GAAK,EAAA,EAAI,EAAA,GAAK,EAAE,CAAA;AAC1B;AAGO,SAAS,IAAA,CAAK,GAAW,CAAA,EAAmB;AACjD,EAAA,OAAO,CAAA,GAAI,IAAI,CAAA,GAAI,CAAA;AACrB;AAGO,SAAS,KAAK,CAAA,EAAuB;AAC1C,EAAA,OAAO,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,IAAI,EAAA,GAAK,CAAA;AAClC;AAQO,SAAS,QAAA,CAAS,CAAA,EAAW,CAAA,EAAW,GAAA,GAAc,GAAA,EAAc;AACzE,EAAA,IAAI,CAAA,KAAM,GAAG,OAAO,IAAA;AACpB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AAG3B,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,IAAI,GAAG,OAAO,KAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAC,CAAC,CAAA;AAClD,EAAA,OAAO,QAAQ,GAAA,GAAM,KAAA;AACvB","file":"chunk-NHMWNQTE.js","sourcesContent":["/**\n * Scalar / 2-vector primitives and the kernel-wide epsilon policy.\n *\n * Points are scalar pairs (px, py); there is no point struct. All math is\n * f64 (JS-native). Epsilons are f32-SCALE and magnitude-relative, because\n * stored coords are quantized to Float32 (~7 significant digits) — see the\n * geometry-kernel spec.\n */\n\n/** Base relative epsilon, sized for Float32 storage (~1 part in 1e-6). */\nexport const EPS = 1e-6;\n\n/** A determinant at or below this fraction of its matrix's own scale counts as\n * singular. Dimensionless, so a uniformly tiny matrix still inverts while a\n * large one whose determinant is only rounding does not. */\nexport const SINGULAR_RATIO = 1e-12;\n\n/** 2D cross (wedge) product of vectors (ax,ay) and (bx,by). */\nexport function cross(ax: number, ay: number, bx: number, by: number): number {\n return ax * by - ay * bx;\n}\n\n/** 2D dot product. */\nexport function dot(ax: number, ay: number, bx: number, by: number): number {\n return ax * bx + ay * by;\n}\n\n/** Component difference (ax-bx, ay-by) as a tuple. Cold-path use only. */\nexport function sub(ax: number, ay: number, bx: number, by: number): [number, number] {\n return [ax - bx, ay - by];\n}\n\n/** Squared length of (x,y). Avoids the sqrt; compare against squared thresholds. */\nexport function len2(x: number, y: number): number {\n return x * x + y * y;\n}\n\n/** Three-valued sign. */\nexport function sign(n: number): -1 | 0 | 1 {\n return n > 0 ? 1 : n < 0 ? -1 : 0;\n}\n\n/**\n * Magnitude-scaled approximate equality. Two values are equal when their\n * absolute difference is within EPS scaled by the larger magnitude. This is\n * the ONLY equality the kernel uses on computed coordinates — never `===`,\n * never an f64-tight literal.\n */\nexport function approxEq(a: number, b: number, eps: number = EPS): boolean {\n if (a === b) return true; // also the only way two infinities compare equal\n const diff = Math.abs(a - b);\n // Infinity/Infinity is 1, so an unguarded relative test calls every finite\n // number equal to an infinity.\n if (!Number.isFinite(diff)) return false;\n const scale = Math.max(1, Math.abs(a), Math.abs(b));\n return diff <= eps * scale;\n}\n"]}