@woosh/meep-engine 2.147.0 → 2.148.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.d.ts +4 -4
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.js +48 -52
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.d.ts +23 -21
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.js +41 -406
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts +5 -4
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +400 -395
- package/src/engine/physics/body/SolverBodyState.d.ts +142 -0
- package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -0
- package/src/engine/physics/body/SolverBodyState.js +251 -0
- package/src/engine/physics/broadphase/generate_pairs.d.ts +2 -1
- package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
- package/src/engine/physics/broadphase/generate_pairs.js +5 -3
- package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
- package/src/engine/physics/constraint/solve_constraints.js +691 -673
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +21 -18
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +223 -91
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts +23 -0
- package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
- package/src/engine/physics/inertia/world_inverse_inertia.js +116 -77
- package/src/engine/physics/integration/integrate_position.d.ts +11 -1
- package/src/engine/physics/integration/integrate_position.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_position.js +97 -79
- package/src/engine/physics/integration/integrate_velocity.d.ts +12 -3
- package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_velocity.js +201 -160
- package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_box_manifold.js +750 -665
- package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/box_triangle_contact.js +4 -34
- package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts +16 -0
- package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +1 -0
- package/src/engine/physics/narrowphase/clip_against_axis_uv.js +49 -0
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +24 -3
- package/src/engine/physics/queries/raycast.d.ts.map +1 -1
- package/src/engine/physics/queries/raycast.js +7 -4
- package/src/engine/physics/solver/solve_contacts.d.ts +2 -2
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
- package/src/engine/physics/solver/solve_contacts.js +1341 -1173
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"description": "Pure JavaScript game engine. Fully featured and production ready.",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"author": "Alexander Goldring",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.148.0",
|
|
10
10
|
"main": "build/meep.module.js",
|
|
11
11
|
"module": "build/meep.module.js",
|
|
12
12
|
"exports": {
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
* of candidate critical points (see the variant docs for what each reports
|
|
14
14
|
* and how many entries the result buffer needs):
|
|
15
15
|
* - 1D: range overlap or extrema-based closest pair → 1 pair.
|
|
16
|
-
* -
|
|
17
|
-
* to
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* - ND (≥ 2): grid-Newton interior critical points + boundary minima → up
|
|
17
|
+
* to 89 pairs (~178 floats). dim === 2 uses this path too; the former
|
|
18
|
+
* bespoke 2D Bezout specialization was removed because it missed interior
|
|
19
|
+
* non-intersection closest approaches.
|
|
20
20
|
*
|
|
21
21
|
* Required buffer size: caller must reserve enough space for the worst
|
|
22
22
|
* case of the dim it intends to call with. Reserving ≥ 178 floats past
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_hermite_intersection_spline3_hermite.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_intersection_spline3_hermite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spline3_hermite_intersection_spline3_hermite.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_intersection_spline3_hermite.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,gEAPW,YAAY,GAAC,MAAM,EAAE,KACrB,YAAY,GAAC,MAAM,EAAE,OACrB,MAAM,UACN,YAAY,GAAC,MAAM,EAAE,iBACrB,MAAM,GACJ,MAAM,CAclB"}
|
|
@@ -1,52 +1,48 @@
|
|
|
1
|
-
import { assert } from "../../assert.js";
|
|
2
|
-
import { spline3_hermite_intersection_spline3_hermite_1d } from "./spline3_hermite_intersection_spline3_hermite_1d.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* -
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* @param {Float64Array|number[]}
|
|
31
|
-
* @param {
|
|
32
|
-
* @param {number}
|
|
33
|
-
* @param {
|
|
34
|
-
* @
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return spline3_hermite_intersection_spline3_hermite_nd(a, b, dim, result, result_offset);
|
|
52
|
-
}
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
import { spline3_hermite_intersection_spline3_hermite_1d } from "./spline3_hermite_intersection_spline3_hermite_1d.js";
|
|
3
|
+
import { spline3_hermite_intersection_spline3_hermite_nd } from "./spline3_hermite_intersection_spline3_hermite_nd.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Critical points of squared distance between two cubic Hermite curves over
|
|
7
|
+
* the [0,1]² parameter square. Writes (s, t) pairs sequentially into
|
|
8
|
+
* `result` starting at `result_offset` and returns the count of pairs
|
|
9
|
+
* written. Caller is responsible for evaluating both curves at each pair
|
|
10
|
+
* and computing distance (e.g. to pick the nearest root).
|
|
11
|
+
*
|
|
12
|
+
* Coefficient layout for `a` and `b`: per-dimension grouped quads,
|
|
13
|
+
* `[p0_0, p1_0, m0_0, m1_0, p0_1, p1_1, m0_1, m1_1, ..., m1_{dim-1}]`,
|
|
14
|
+
* length `4 * dim`. dim ≥ 1.
|
|
15
|
+
*
|
|
16
|
+
* Internally dispatched by dimension; each path enumerates different sets
|
|
17
|
+
* of candidate critical points (see the variant docs for what each reports
|
|
18
|
+
* and how many entries the result buffer needs):
|
|
19
|
+
* - 1D: range overlap or extrema-based closest pair → 1 pair.
|
|
20
|
+
* - ND (≥ 2): grid-Newton interior critical points + boundary minima → up
|
|
21
|
+
* to 89 pairs (~178 floats). dim === 2 uses this path too; the former
|
|
22
|
+
* bespoke 2D Bezout specialization was removed because it missed interior
|
|
23
|
+
* non-intersection closest approaches.
|
|
24
|
+
*
|
|
25
|
+
* Required buffer size: caller must reserve enough space for the worst
|
|
26
|
+
* case of the dim it intends to call with. Reserving ≥ 178 floats past
|
|
27
|
+
* `result_offset` covers all dims.
|
|
28
|
+
*
|
|
29
|
+
* @param {Float64Array|number[]} a length 4*dim
|
|
30
|
+
* @param {Float64Array|number[]} b length 4*dim
|
|
31
|
+
* @param {number} dim
|
|
32
|
+
* @param {Float64Array|number[]} result
|
|
33
|
+
* @param {number} result_offset
|
|
34
|
+
* @returns {number} number of (s, t) pairs written
|
|
35
|
+
*/
|
|
36
|
+
export function spline3_hermite_intersection_spline3_hermite(
|
|
37
|
+
a, b, dim,
|
|
38
|
+
result, result_offset
|
|
39
|
+
) {
|
|
40
|
+
assert.greaterThanOrEqual(dim, 1, 'dim');
|
|
41
|
+
|
|
42
|
+
if (dim === 1) {
|
|
43
|
+
return spline3_hermite_intersection_spline3_hermite_1d(a, b, result, result_offset);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// dim >= 2 (including 2D) goes through the dimension-agnostic ND path.
|
|
47
|
+
return spline3_hermite_intersection_spline3_hermite_nd(a, b, dim, result, result_offset);
|
|
48
|
+
}
|
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* @deprecated The dedicated 2D Bezout specialization has been removed. It
|
|
3
|
+
* enumerated interior *intersections* (via the (3,3)/(3,3) Bezout resultant)
|
|
4
|
+
* plus the four boundary-edge minima only — it never enumerated interior
|
|
5
|
+
* *non-intersection* critical points, so it silently missed the closest
|
|
6
|
+
* approach of two non-intersecting cubic arcs whenever that approach is
|
|
7
|
+
* interior-to-interior (wrong on ~27% of random curve pairs, by as much as
|
|
8
|
+
* several units of squared distance). Its premise — "no interior intersection
|
|
9
|
+
* ⇒ the global minimum lies on the boundary" — is false for cubic arcs.
|
|
5
10
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* (s*, 0) with s* minimising ‖A(s) − B(0)‖²
|
|
12
|
-
* (s*, 1) with s* minimising ‖A(s) − B(1)‖²
|
|
13
|
-
* Each `nearest_t_on_curve` call internally tests endpoints, so corners
|
|
14
|
-
* are folded into these as appropriate.
|
|
11
|
+
* This symbol is retained only so existing callers keep working; it now
|
|
12
|
+
* forwards to the dimension-agnostic
|
|
13
|
+
* {@link spline3_hermite_intersection_spline3_hermite_nd} path, which
|
|
14
|
+
* enumerates interior critical points (grid-seeded 2D Newton) in addition to
|
|
15
|
+
* the boundary minima and is correct for the full closest-approach problem.
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* Prefer the dimension dispatcher
|
|
18
|
+
* {@link spline3_hermite_intersection_spline3_hermite} or
|
|
19
|
+
* `spline3_hermite_intersection_spline3_hermite_nd` directly. Note the buffer
|
|
20
|
+
* requirement is now the ND worst case: `result.length >= result_offset +
|
|
21
|
+
* 2 * ND_MAX_ROOTS` floats (currently 178), not the old 2D bound.
|
|
18
22
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* input curves is constant on an axis, etc.), the routine forwards to the
|
|
24
|
-
* dimension-agnostic ND path.
|
|
23
|
+
* Critical-point enumerator for the 2D Hermite curve-pair problem. Writes
|
|
24
|
+
* (s, t) pairs sequentially into `result` starting at `result_offset` and
|
|
25
|
+
* returns the count of pairs written. The caller evaluates both curves at each
|
|
26
|
+
* pair and picks the one(s) it cares about (closest, within threshold, etc.).
|
|
25
27
|
*
|
|
26
28
|
* @param {Float64Array|number[]} a length 8: [a_p0_x, a_p1_x, a_m0_x, a_m1_x, a_p0_y, a_p1_y, a_m0_y, a_m1_y]
|
|
27
29
|
* @param {Float64Array|number[]} b length 8 (same layout)
|
|
28
|
-
* @param {Float64Array|number[]} result length >= result_offset +
|
|
30
|
+
* @param {Float64Array|number[]} result length >= result_offset + 2 * ND_MAX_ROOTS
|
|
29
31
|
* @param {number} result_offset
|
|
30
32
|
* @returns {number} number of (s, t) pairs written
|
|
31
33
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_hermite_intersection_spline3_hermite_2d.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spline3_hermite_intersection_spline3_hermite_2d.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,mEANW,YAAY,GAAC,MAAM,EAAE,KACrB,YAAY,GAAC,MAAM,EAAE,UACrB,YAAY,GAAC,MAAM,EAAE,iBACrB,MAAM,GACJ,MAAM,CAOlB"}
|
|
@@ -1,406 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Bezout entries. The four polynomial-valued ones are degree ≤ 3 in s; the two
|
|
43
|
-
// scalar-valued ones are stored as plain numbers in `_bz_const`.
|
|
44
|
-
// _bz_poly[0] = B[0,0] (degree 3 in s)
|
|
45
|
-
// _bz_poly[1] = B[0,1]
|
|
46
|
-
// _bz_poly[2] = B[0,2]
|
|
47
|
-
// _bz_poly[3] = B[1,1]
|
|
48
|
-
const _bz_poly = [
|
|
49
|
-
new Float64Array(4),
|
|
50
|
-
new Float64Array(4),
|
|
51
|
-
new Float64Array(4),
|
|
52
|
-
new Float64Array(4),
|
|
53
|
-
];
|
|
54
|
-
// _bz_const[0] = B[1,2], _bz_const[1] = B[2,2]
|
|
55
|
-
const _bz_const = new Float64Array(2);
|
|
56
|
-
|
|
57
|
-
// Resultant coefficients (degree ≤ 9 → 10 slots).
|
|
58
|
-
const _resultant = new Float64Array(10);
|
|
59
|
-
|
|
60
|
-
// Scratch polynomials used while computing det(Bezout).
|
|
61
|
-
const _tmp_poly_a = new Float64Array(10);
|
|
62
|
-
const _tmp_poly_b = new Float64Array(10);
|
|
63
|
-
const _tmp_poly_c = new Float64Array(10);
|
|
64
|
-
const _tmp_poly_d = new Float64Array(10);
|
|
65
|
-
|
|
66
|
-
const _root_buffer_s = new Float64Array(9);
|
|
67
|
-
const _root_buffer_t = new Float64Array(3);
|
|
68
|
-
|
|
69
|
-
const Y_MATCH_TOLERANCE = 1e-7;
|
|
70
|
-
|
|
71
|
-
// ── core algorithm helpers ────────────────────────────────────────────────
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Build the 6 Bezout entries (4 polynomial, 2 constant) from the monomial
|
|
75
|
-
* coefficients of A and B. See module preamble for the algebraic derivation.
|
|
76
|
-
*
|
|
77
|
-
* Layout:
|
|
78
|
-
* a-side polys are A_*(s) in monomial basis (cubic in s). Their coefficient
|
|
79
|
-
* arrays here are length 4 (constant ... s³).
|
|
80
|
-
* b-side polys are B_*(t) — we only need the *coefficients* (constants
|
|
81
|
-
* wrt s) in the bivariate form P(s,t) = A_x(s) − B_x(t). So β_kx = the k-th
|
|
82
|
-
* monomial coefficient of B_x.
|
|
83
|
-
*/
|
|
84
|
-
function build_bezout_entries(a_x, a_y, b_x, b_y) {
|
|
85
|
-
// Coefficients of P(s, t) viewed as polynomial in t with s-poly coeffs:
|
|
86
|
-
// p_0(s) = A_x(s) − β0_x (cubic in s)
|
|
87
|
-
// p_1 = -β1_x (constant)
|
|
88
|
-
// p_2 = -β2_x
|
|
89
|
-
// p_3 = -β3_x
|
|
90
|
-
// and similarly q_k for Q.
|
|
91
|
-
|
|
92
|
-
const beta_1x = -b_x[1];
|
|
93
|
-
const beta_2x = -b_x[2];
|
|
94
|
-
const beta_3x = -b_x[3];
|
|
95
|
-
|
|
96
|
-
const beta_1y = -b_y[1];
|
|
97
|
-
const beta_2y = -b_y[2];
|
|
98
|
-
const beta_3y = -b_y[3];
|
|
99
|
-
|
|
100
|
-
// p_0(s) = A_x(s) - β0_x
|
|
101
|
-
const p0 = _tmp_poly_a;
|
|
102
|
-
p0[0] = a_x[0] - b_x[0];
|
|
103
|
-
p0[1] = a_x[1];
|
|
104
|
-
p0[2] = a_x[2];
|
|
105
|
-
p0[3] = a_x[3];
|
|
106
|
-
|
|
107
|
-
// q_0(s) = A_y(s) - β0_y
|
|
108
|
-
const q0 = _tmp_poly_b;
|
|
109
|
-
q0[0] = a_y[0] - b_y[0];
|
|
110
|
-
q0[1] = a_y[1];
|
|
111
|
-
q0[2] = a_y[2];
|
|
112
|
-
q0[3] = a_y[3];
|
|
113
|
-
|
|
114
|
-
// B[0,0] = a_1 b_0 - a_0 b_1 = beta_1x * q_0(s) - p_0(s) * beta_1y
|
|
115
|
-
const b00 = _bz_poly[0];
|
|
116
|
-
for (let i = 0; i < 4; i++){
|
|
117
|
-
b00[i] = beta_1x * q0[i] - p0[i] * beta_1y;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// B[0,1] = a_2 b_0 - a_0 b_2 = beta_2x * q_0(s) - p_0(s) * beta_2y
|
|
121
|
-
const b01 = _bz_poly[1];
|
|
122
|
-
for (let i = 0; i < 4; i++){
|
|
123
|
-
b01[i] = beta_2x * q0[i] - p0[i] * beta_2y;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// B[0,2] = a_3 b_0 - a_0 b_3 = beta_3x * q_0(s) - p_0(s) * beta_3y
|
|
127
|
-
const b02 = _bz_poly[2];
|
|
128
|
-
for (let i = 0; i < 4; i++){
|
|
129
|
-
b02[i] = beta_3x * q0[i] - p0[i] * beta_3y;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// B[1,1] = (a_3 b_0 - a_0 b_3) + (a_2 b_1 - a_1 b_2)
|
|
133
|
-
// = B[0,2] + (beta_2x * beta_1y - beta_1x * beta_2y)
|
|
134
|
-
const b11 = _bz_poly[3];
|
|
135
|
-
const inner = beta_2x * beta_1y - beta_1x * beta_2y;
|
|
136
|
-
for (let i = 0; i < 4; i++){
|
|
137
|
-
b11[i] = b02[i];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
b11[0] += inner;
|
|
141
|
-
|
|
142
|
-
// B[1,2] = a_3 b_1 - a_1 b_3 = beta_3x * beta_1y - beta_1x * beta_3y (constant)
|
|
143
|
-
_bz_const[0] = beta_3x * beta_1y - beta_1x * beta_3y;
|
|
144
|
-
|
|
145
|
-
// B[2,2] = a_3 b_2 - a_2 b_3 = beta_3x * beta_2y - beta_2x * beta_3y (constant)
|
|
146
|
-
_bz_const[1] = beta_3x * beta_2y - beta_2x * beta_3y;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Compute det(Bezout) as a polynomial in s and write its coefficients into
|
|
151
|
-
* `_resultant`. Returns the (effective) degree + 1 — i.e. the number of
|
|
152
|
-
* coefficients that are meaningful.
|
|
153
|
-
*
|
|
154
|
-
* Closed form: det(B) = B[0,2]·(B[0,1]·B[1,2] − B[0,2]·B[1,1])
|
|
155
|
-
* − B[1,2]·(B[0,0]·B[1,2] − B[0,2]·B[0,1])
|
|
156
|
-
* + B[2,2]·(B[0,0]·B[1,1] − B[0,1]²)
|
|
157
|
-
*
|
|
158
|
-
* B[0,0], B[0,1], B[0,2], B[1,1] are cubic polynomials in s (length 4).
|
|
159
|
-
* B[1,2], B[2,2] are constants (length 1).
|
|
160
|
-
*/
|
|
161
|
-
function compute_resultant() {
|
|
162
|
-
const b00 = _bz_poly[0]; // length 4
|
|
163
|
-
const b01 = _bz_poly[1]; // length 4
|
|
164
|
-
const b02 = _bz_poly[2]; // length 4
|
|
165
|
-
const b11 = _bz_poly[3]; // length 4
|
|
166
|
-
const b12 = _bz_const[0];
|
|
167
|
-
const b22 = _bz_const[1];
|
|
168
|
-
|
|
169
|
-
_resultant.fill(0);
|
|
170
|
-
|
|
171
|
-
// ── Term A: B[0,2] · (B[0,1] · B[1,2] − B[0,2] · B[1,1]) ──
|
|
172
|
-
// tmp_c = B[0,1] · B[1,2] (cubic × constant → cubic, length 4)
|
|
173
|
-
const tmp_c = _tmp_poly_c;
|
|
174
|
-
let tmp_c_len = 4;
|
|
175
|
-
|
|
176
|
-
for (let i = 0; i < 4; i++){
|
|
177
|
-
tmp_c[i] = b01[i] * b12;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// tmp_d = B[0,2] · B[1,1] (cubic × cubic → degree 6, length 7)
|
|
181
|
-
const tmp_d = _tmp_poly_d;
|
|
182
|
-
const tmp_d_len = polynomial_multiply(tmp_d, b02, 4, b11, 4);
|
|
183
|
-
|
|
184
|
-
// tmp_c -= tmp_d (length 7)
|
|
185
|
-
tmp_c_len = polynomial_sub_into(tmp_c, tmp_c_len, tmp_d, tmp_d_len);
|
|
186
|
-
|
|
187
|
-
// term_a = B[0,2] · tmp_c (length 4 + 7 − 1 = 10)
|
|
188
|
-
const tmp_a = _tmp_poly_a;
|
|
189
|
-
const tmp_a_len = polynomial_multiply(tmp_a, b02, 4, tmp_c, tmp_c_len);
|
|
190
|
-
|
|
191
|
-
// resultant += term_a
|
|
192
|
-
polynomial_add_into(_resultant, 0, tmp_a, tmp_a_len);
|
|
193
|
-
|
|
194
|
-
// ── Term B: −B[1,2] · (B[0,0] · B[1,2] − B[0,2] · B[0,1]) ──
|
|
195
|
-
// tmp_c = B[0,0] · B[1,2] (cubic × constant)
|
|
196
|
-
tmp_c_len = 4;
|
|
197
|
-
for (let i = 0; i < 4; i++) tmp_c[i] = b00[i] * b12;
|
|
198
|
-
|
|
199
|
-
// tmp_d = B[0,2] · B[0,1] (cubic × cubic → length 7)
|
|
200
|
-
const tmp_d_len_2 = polynomial_multiply(tmp_d, b02, 4, b01, 4);
|
|
201
|
-
|
|
202
|
-
tmp_c_len = polynomial_sub_into(tmp_c, tmp_c_len, tmp_d, tmp_d_len_2);
|
|
203
|
-
|
|
204
|
-
polynomial_scale_into(tmp_c, tmp_c_len, -b12);
|
|
205
|
-
polynomial_add_into(_resultant, _resultant.length, tmp_c, tmp_c_len);
|
|
206
|
-
|
|
207
|
-
// ── Term C: B[2,2] · (B[0,0] · B[1,1] − B[0,1]²) ──
|
|
208
|
-
const tmp_d_len_3 = polynomial_multiply(tmp_d, b00, 4, b11, 4); // length 7
|
|
209
|
-
tmp_c_len = polynomial_multiply(tmp_c, b01, 4, b01, 4); // length 7
|
|
210
|
-
|
|
211
|
-
polynomial_sub_into(tmp_d, tmp_d_len_3, tmp_c, tmp_c_len);
|
|
212
|
-
|
|
213
|
-
polynomial_scale_into(tmp_d, tmp_d_len_3, b22);
|
|
214
|
-
polynomial_add_into(_resultant, _resultant.length, tmp_d, tmp_d_len_3);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* For a given s, find a t in [0,1] such that A_x(s) − B_x(t) = 0 AND
|
|
219
|
-
* A_y(s) ≈ B_y(t) (the latter within Y_MATCH_TOLERANCE). Returns the matched
|
|
220
|
-
* t, or -1 if none.
|
|
221
|
-
*/
|
|
222
|
-
function recover_t(a, b, s) {
|
|
223
|
-
// A_x(s) value:
|
|
224
|
-
const a_x_at_s = spline3_hermite(s, a[0], a[1], a[2], a[3]);
|
|
225
|
-
const a_y_at_s = spline3_hermite(s, a[4], a[5], a[6], a[7]);
|
|
226
|
-
|
|
227
|
-
// Solve B_x(t) = a_x_at_s for t:
|
|
228
|
-
// B_x in monomial: β0_x + β1_x t + β2_x t² + β3_x t³ - a_x_at_s = 0
|
|
229
|
-
const t_count = solveCubic(
|
|
230
|
-
_root_buffer_t, 0,
|
|
231
|
-
_B_x_mono[3], _B_x_mono[2], _B_x_mono[1], _B_x_mono[0] - a_x_at_s
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
let best_t = -1;
|
|
235
|
-
let best_dy = Number.POSITIVE_INFINITY;
|
|
236
|
-
|
|
237
|
-
for (let i = 0; i < t_count; i++) {
|
|
238
|
-
const t = _root_buffer_t[i];
|
|
239
|
-
|
|
240
|
-
if (t < 0 || t > 1) continue;
|
|
241
|
-
|
|
242
|
-
const b_y_at_t = spline3_hermite(t, b[4], b[5], b[6], b[7]);
|
|
243
|
-
const dy = Math.abs(a_y_at_s - b_y_at_t);
|
|
244
|
-
|
|
245
|
-
if (dy < best_dy) {
|
|
246
|
-
best_dy = dy;
|
|
247
|
-
best_t = t;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
if (best_dy > Y_MATCH_TOLERANCE) return -1;
|
|
253
|
-
return best_t;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Find the minimum of ||point − B(t)||² over t in [0,1], where `point` is a 2D
|
|
258
|
-
* point (px, py). Solves the quintic ∂/∂t = 0 by feeding it to
|
|
259
|
-
* polynomial_real_roots_in_interval and tests each root + the two endpoints.
|
|
260
|
-
*
|
|
261
|
-
* Writes `[t, dist²]` into the returned 2-element module scratch.
|
|
262
|
-
*/
|
|
263
|
-
const _edge_tmp_quintic = new Float64Array(6);
|
|
264
|
-
const _edge_tmp_roots = new Float64Array(5);
|
|
265
|
-
const _edge_result = new Float64Array(2);
|
|
266
|
-
|
|
267
|
-
function nearest_t_on_curve(b_mono_x, b_mono_y, point_x, point_y) {
|
|
268
|
-
// ‖B(t) − point‖² is degree 6 in t. Its derivative is degree 5 — the
|
|
269
|
-
// shared accumulator builds it per axis, dropping the constant factor of
|
|
270
|
-
// 2 since it doesn't affect root locations.
|
|
271
|
-
|
|
272
|
-
const quintic = _edge_tmp_quintic;
|
|
273
|
-
for (let i = 0; i < 6; i++) {
|
|
274
|
-
quintic[i] = 0;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
cubic_residual_times_derivative_accumulate(quintic, b_mono_x, 0, point_x);
|
|
278
|
-
cubic_residual_times_derivative_accumulate(quintic, b_mono_y, 0, point_y);
|
|
279
|
-
|
|
280
|
-
const root_count = polynomial_real_roots_in_interval(
|
|
281
|
-
quintic, 5, 0, 1, _edge_tmp_roots, 0
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
let best_t = 0;
|
|
285
|
-
let best_d2 = Number.POSITIVE_INFINITY;
|
|
286
|
-
|
|
287
|
-
for (let i = -2; i < root_count; i++) {
|
|
288
|
-
// i = -2 → t = 0; i = -1 → t = 1; otherwise interior roots
|
|
289
|
-
const t = i === -2 ? 0 : (i === -1 ? 1 : _edge_tmp_roots[i]);
|
|
290
|
-
const ex = polynomial_cubic_horner_eval(b_mono_x, 0, t) - point_x;
|
|
291
|
-
const ey = polynomial_cubic_horner_eval(b_mono_y, 0, t) - point_y;
|
|
292
|
-
const d2 = ex * ex + ey * ey;
|
|
293
|
-
if (d2 < best_d2) {
|
|
294
|
-
best_d2 = d2;
|
|
295
|
-
best_t = t;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
_edge_result[0] = best_t;
|
|
300
|
-
_edge_result[1] = best_d2;
|
|
301
|
-
return _edge_result;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Critical-point enumerator for the 2D Hermite curve-pair intersection
|
|
306
|
-
* problem. Writes (s, t) pairs sequentially into `result` starting at
|
|
307
|
-
* `result_offset` and returns the count.
|
|
308
|
-
*
|
|
309
|
-
* What is reported:
|
|
310
|
-
* - All interior true intersections found by the Bezout resultant (up to 9).
|
|
311
|
-
* - Four boundary closest-approach pairs, one per edge of [0,1]²:
|
|
312
|
-
* (0, t*) with t* minimising ‖A(0) − B(t)‖²
|
|
313
|
-
* (1, t*) with t* minimising ‖A(1) − B(t)‖²
|
|
314
|
-
* (s*, 0) with s* minimising ‖A(s) − B(0)‖²
|
|
315
|
-
* (s*, 1) with s* minimising ‖A(s) − B(1)‖²
|
|
316
|
-
* Each `nearest_t_on_curve` call internally tests endpoints, so corners
|
|
317
|
-
* are folded into these as appropriate.
|
|
318
|
-
*
|
|
319
|
-
* Caller is responsible for evaluating both curves at each (s, t) and picking
|
|
320
|
-
* whichever pair(s) they care about (closest, within threshold, etc.).
|
|
321
|
-
*
|
|
322
|
-
* Typical buffer size: at most 9 interior + 4 boundary = 13 pairs →
|
|
323
|
-
* `result.length >= result_offset + 26`. in degenerate cases up to 89 pairs.
|
|
324
|
-
*
|
|
325
|
-
* Edge case: if the Bezout resultant is numerically degenerate (one of the
|
|
326
|
-
* input curves is constant on an axis, etc.), the routine forwards to the
|
|
327
|
-
* dimension-agnostic ND path.
|
|
328
|
-
*
|
|
329
|
-
* @param {Float64Array|number[]} a length 8: [a_p0_x, a_p1_x, a_m0_x, a_m1_x, a_p0_y, a_p1_y, a_m0_y, a_m1_y]
|
|
330
|
-
* @param {Float64Array|number[]} b length 8 (same layout)
|
|
331
|
-
* @param {Float64Array|number[]} result length >= result_offset + 198
|
|
332
|
-
* @param {number} result_offset
|
|
333
|
-
* @returns {number} number of (s, t) pairs written
|
|
334
|
-
*/
|
|
335
|
-
export function spline3_hermite_intersection_spline3_hermite_2d(
|
|
336
|
-
a, b,
|
|
337
|
-
result, result_offset
|
|
338
|
-
) {
|
|
339
|
-
spline3_hermite_to_monomial(_A_x_mono, 0, 1, a[0], a[1], a[2], a[3]);
|
|
340
|
-
spline3_hermite_to_monomial(_A_y_mono, 0, 1, a[4], a[5], a[6], a[7]);
|
|
341
|
-
spline3_hermite_to_monomial(_B_x_mono, 0, 1, b[0], b[1], b[2], b[3]);
|
|
342
|
-
spline3_hermite_to_monomial(_B_y_mono, 0, 1, b[4], b[5], b[6], b[7]);
|
|
343
|
-
|
|
344
|
-
build_bezout_entries(_A_x_mono, _A_y_mono, _B_x_mono, _B_y_mono);
|
|
345
|
-
compute_resultant();
|
|
346
|
-
|
|
347
|
-
// Detect a degenerate resultant. This happens when one (or both) input
|
|
348
|
-
// curves is degree < 3 in its parameter — straight axis-aligned lines are
|
|
349
|
-
// the canonical example. The (3,3)/(3,3) Bezout construction collapses
|
|
350
|
-
// because the relevant leading coefficients are zero. In that case, fall
|
|
351
|
-
// back to the dimension-agnostic Newton-from-grid path.
|
|
352
|
-
let max_resultant_mag = 0;
|
|
353
|
-
for (let i = 0; i < _resultant.length; i++) {
|
|
354
|
-
const v = Math.abs(_resultant[i]);
|
|
355
|
-
if (v > max_resultant_mag) max_resultant_mag = v;
|
|
356
|
-
}
|
|
357
|
-
if (max_resultant_mag < 1e-12) {
|
|
358
|
-
return spline3_hermite_intersection_spline3_hermite_nd(a, b, 2, result, result_offset);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
const s_root_count = polynomial_real_roots_in_interval(
|
|
362
|
-
_resultant, 9, 0, 1, _root_buffer_s, 0
|
|
363
|
-
);
|
|
364
|
-
|
|
365
|
-
let write = result_offset;
|
|
366
|
-
|
|
367
|
-
// Interior intersections (true: distance² = 0).
|
|
368
|
-
for (let i = 0; i < s_root_count; i++) {
|
|
369
|
-
const s = _root_buffer_s[i];
|
|
370
|
-
const t = recover_t(a, b, s);
|
|
371
|
-
if (t >= 0) {
|
|
372
|
-
result[write++] = s;
|
|
373
|
-
result[write++] = t;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
// Boundary closest-approach pairs — one per edge of [0,1]². Each call
|
|
378
|
-
// internally tests the edge endpoints (corners) and reports the minimum.
|
|
379
|
-
|
|
380
|
-
// Edge s = 0: minimise ‖A(0) − B(t)‖² over t.
|
|
381
|
-
{
|
|
382
|
-
const r = nearest_t_on_curve(_B_x_mono, _B_y_mono, a[0], a[4]);
|
|
383
|
-
result[write++] = 0;
|
|
384
|
-
result[write++] = r[0];
|
|
385
|
-
}
|
|
386
|
-
// Edge s = 1.
|
|
387
|
-
{
|
|
388
|
-
const r = nearest_t_on_curve(_B_x_mono, _B_y_mono, a[1], a[5]);
|
|
389
|
-
result[write++] = 1;
|
|
390
|
-
result[write++] = r[0];
|
|
391
|
-
}
|
|
392
|
-
// Edge t = 0: minimise ‖A(s) − B(0)‖² over s.
|
|
393
|
-
{
|
|
394
|
-
const r = nearest_t_on_curve(_A_x_mono, _A_y_mono, b[0], b[4]);
|
|
395
|
-
result[write++] = r[0];
|
|
396
|
-
result[write++] = 0;
|
|
397
|
-
}
|
|
398
|
-
// Edge t = 1.
|
|
399
|
-
{
|
|
400
|
-
const r = nearest_t_on_curve(_A_x_mono, _A_y_mono, b[1], b[5]);
|
|
401
|
-
result[write++] = r[0];
|
|
402
|
-
result[write++] = 1;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
return (write - result_offset) >> 1;
|
|
406
|
-
}
|
|
1
|
+
import { spline3_hermite_intersection_spline3_hermite_nd } from "./spline3_hermite_intersection_spline3_hermite_nd.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated The dedicated 2D Bezout specialization has been removed. It
|
|
5
|
+
* enumerated interior *intersections* (via the (3,3)/(3,3) Bezout resultant)
|
|
6
|
+
* plus the four boundary-edge minima only — it never enumerated interior
|
|
7
|
+
* *non-intersection* critical points, so it silently missed the closest
|
|
8
|
+
* approach of two non-intersecting cubic arcs whenever that approach is
|
|
9
|
+
* interior-to-interior (wrong on ~27% of random curve pairs, by as much as
|
|
10
|
+
* several units of squared distance). Its premise — "no interior intersection
|
|
11
|
+
* ⇒ the global minimum lies on the boundary" — is false for cubic arcs.
|
|
12
|
+
*
|
|
13
|
+
* This symbol is retained only so existing callers keep working; it now
|
|
14
|
+
* forwards to the dimension-agnostic
|
|
15
|
+
* {@link spline3_hermite_intersection_spline3_hermite_nd} path, which
|
|
16
|
+
* enumerates interior critical points (grid-seeded 2D Newton) in addition to
|
|
17
|
+
* the boundary minima and is correct for the full closest-approach problem.
|
|
18
|
+
*
|
|
19
|
+
* Prefer the dimension dispatcher
|
|
20
|
+
* {@link spline3_hermite_intersection_spline3_hermite} or
|
|
21
|
+
* `spline3_hermite_intersection_spline3_hermite_nd` directly. Note the buffer
|
|
22
|
+
* requirement is now the ND worst case: `result.length >= result_offset +
|
|
23
|
+
* 2 * ND_MAX_ROOTS` floats (currently 178), not the old 2D bound.
|
|
24
|
+
*
|
|
25
|
+
* Critical-point enumerator for the 2D Hermite curve-pair problem. Writes
|
|
26
|
+
* (s, t) pairs sequentially into `result` starting at `result_offset` and
|
|
27
|
+
* returns the count of pairs written. The caller evaluates both curves at each
|
|
28
|
+
* pair and picks the one(s) it cares about (closest, within threshold, etc.).
|
|
29
|
+
*
|
|
30
|
+
* @param {Float64Array|number[]} a length 8: [a_p0_x, a_p1_x, a_m0_x, a_m1_x, a_p0_y, a_p1_y, a_m0_y, a_m1_y]
|
|
31
|
+
* @param {Float64Array|number[]} b length 8 (same layout)
|
|
32
|
+
* @param {Float64Array|number[]} result length >= result_offset + 2 * ND_MAX_ROOTS
|
|
33
|
+
* @param {number} result_offset
|
|
34
|
+
* @returns {number} number of (s, t) pairs written
|
|
35
|
+
*/
|
|
36
|
+
export function spline3_hermite_intersection_spline3_hermite_2d(
|
|
37
|
+
a, b,
|
|
38
|
+
result, result_offset
|
|
39
|
+
) {
|
|
40
|
+
return spline3_hermite_intersection_spline3_hermite_nd(a, b, 2, result, result_offset);
|
|
41
|
+
}
|