@woosh/meep-engine 2.135.1 → 2.138.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/geom/2d/aabb/aabb2_intersects_ray.d.ts.map +1 -1
- package/src/core/geom/2d/aabb/aabb2_intersects_ray.js +5 -7
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
- package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +2 -3
- package/src/core/geom/3d/aabb/aabb3_intersects_line_segment.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_intersects_line_segment.js +9 -11
- package/src/core/geom/3d/tetrahedra/tetrahedron_compute_circumsphere.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedron_compute_circumsphere.js +6 -4
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.d.ts.map +1 -1
- package/src/core/geom/3d/topology/simplify/quadratic/Quadric3.js +1 -2
- package/src/core/geom/packing/miniball/Miniball.d.ts.map +1 -1
- package/src/core/geom/packing/miniball/Miniball.js +4 -11
- package/src/core/geom/packing/miniball/Subspan.d.ts +14 -39
- package/src/core/geom/packing/miniball/Subspan.d.ts.map +1 -1
- package/src/core/geom/packing/miniball/Subspan.js +105 -158
- package/src/core/geom/packing/miniball/miniball_compute_quality.d.ts.map +1 -1
- package/src/core/geom/packing/miniball/miniball_compute_quality.js +2 -6
- package/src/core/geom/vec/vector_axpy.d.ts +12 -0
- package/src/core/geom/vec/vector_axpy.d.ts.map +1 -0
- package/src/core/geom/vec/vector_axpy.js +15 -0
- package/src/core/geom/vec/vector_axpy_offset.d.ts +17 -0
- package/src/core/geom/vec/vector_axpy_offset.d.ts.map +1 -0
- package/src/core/geom/vec/vector_axpy_offset.js +20 -0
- package/src/core/geom/vec/vector_dot_offset.d.ts +18 -0
- package/src/core/geom/vec/vector_dot_offset.d.ts.map +1 -0
- package/src/core/geom/vec/vector_dot_offset.js +25 -0
- package/src/core/math/complex/complex_horner_eval.d.ts +2 -2
- package/src/core/math/complex/complex_horner_eval.d.ts.map +1 -1
- package/src/core/math/complex/complex_horner_eval.js +4 -1
- package/src/core/math/fabsf.d.ts +2 -3
- package/src/core/math/fabsf.d.ts.map +1 -1
- package/src/core/math/fabsf.js +3 -5
- package/src/core/math/linalg/cubic_residual_times_derivative_accumulate.d.ts +26 -0
- package/src/core/math/linalg/cubic_residual_times_derivative_accumulate.d.ts.map +1 -0
- package/src/core/math/linalg/cubic_residual_times_derivative_accumulate.js +43 -0
- package/src/core/math/linalg/eigen/matrix_eigenvalues_in_place.d.ts +2 -1
- package/src/core/math/linalg/eigen/matrix_eigenvalues_in_place.d.ts.map +1 -1
- package/src/core/math/linalg/eigen/matrix_eigenvalues_in_place.js +2 -1
- package/src/core/math/linalg/eigen/matrix_householder_in_place.d.ts +10 -4
- package/src/core/math/linalg/eigen/matrix_householder_in_place.d.ts.map +1 -1
- package/src/core/math/linalg/eigen/matrix_householder_in_place.js +122 -98
- package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts +2 -2
- package/src/core/math/linalg/eigen/matrix_qr_in_place.d.ts.map +1 -1
- package/src/core/math/linalg/eigen/matrix_qr_in_place.js +144 -124
- package/src/core/math/linalg/givens/givens_apply_rows.d.ts +22 -0
- package/src/core/math/linalg/givens/givens_apply_rows.d.ts.map +1 -0
- package/src/core/math/linalg/givens/givens_apply_rows.js +28 -0
- package/src/core/math/linalg/givens/givens_apply_rows_offset.d.ts +24 -0
- package/src/core/math/linalg/givens/givens_apply_rows_offset.d.ts.map +1 -0
- package/src/core/math/linalg/givens/givens_apply_rows_offset.js +30 -0
- package/src/core/math/linalg/givens/givens_rotation_coefficients.d.ts +25 -0
- package/src/core/math/linalg/givens/givens_rotation_coefficients.d.ts.map +1 -0
- package/src/core/math/linalg/givens/givens_rotation_coefficients.js +39 -0
- package/src/core/math/linalg/lu_factor_linear_system.d.ts +1 -1
- package/src/core/math/linalg/lu_factor_linear_system.d.ts.map +1 -1
- package/src/core/math/linalg/lu_factor_linear_system.js +108 -117
- package/src/core/math/linalg/lu_solve_linear_system.d.ts +1 -1
- package/src/core/math/linalg/lu_solve_linear_system.js +53 -53
- package/src/core/math/linalg/polynomial_add_into.d.ts +18 -0
- package/src/core/math/linalg/polynomial_add_into.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_add_into.js +29 -0
- package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.d.ts +6 -1
- package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.d.ts.map +1 -1
- package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.js +19 -12
- package/src/core/math/linalg/polynomial_cubic_derivative_eval.d.ts +15 -0
- package/src/core/math/linalg/polynomial_cubic_derivative_eval.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_cubic_derivative_eval.js +16 -0
- package/src/core/math/linalg/polynomial_cubic_horner_eval.d.ts +18 -0
- package/src/core/math/linalg/polynomial_cubic_horner_eval.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_cubic_horner_eval.js +19 -0
- package/src/core/math/linalg/polynomial_cubic_second_derivative_eval.d.ts +13 -0
- package/src/core/math/linalg/polynomial_cubic_second_derivative_eval.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_cubic_second_derivative_eval.js +14 -0
- package/src/core/math/linalg/polynomial_multiply.d.ts +21 -0
- package/src/core/math/linalg/polynomial_multiply.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_multiply.js +41 -0
- package/src/core/math/linalg/polynomial_real_roots_in_interval.d.ts +6 -1
- package/src/core/math/linalg/polynomial_real_roots_in_interval.d.ts.map +1 -1
- package/src/core/math/linalg/polynomial_real_roots_in_interval.js +9 -2
- package/src/core/math/linalg/polynomial_scale_into.d.ts +14 -0
- package/src/core/math/linalg/polynomial_scale_into.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_scale_into.js +17 -0
- package/src/core/math/linalg/polynomial_sub_into.d.ts +18 -0
- package/src/core/math/linalg/polynomial_sub_into.d.ts.map +1 -0
- package/src/core/math/linalg/polynomial_sub_into.js +29 -0
- package/src/core/math/linalg/solve_linear_system.d.ts +1 -1
- package/src/core/math/linalg/solve_linear_system.js +1 -1
- package/src/core/math/linalg/solve_linear_system_GEPP_2x2.d.ts +4 -4
- package/src/core/math/linalg/solve_linear_system_GEPP_2x2.d.ts.map +1 -1
- package/src/core/math/linalg/solve_linear_system_GEPP_2x2.js +96 -91
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite.d.ts +18 -10
- 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 +18 -10
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.d.ts +13 -6
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.js +16 -11
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_2d.d.ts +25 -3
- 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 +78 -135
- package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts +30 -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 +188 -132
- package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.d.ts +7 -3
- package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.d.ts.map +1 -1
- package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.js +35 -6
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/CalcTexArea.js +1 -2
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.d.ts.map +1 -1
- package/src/engine/graphics/geometry/MikkT/InitTriInfo.js +6 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { cubic_residual_times_derivative_accumulate } from "../linalg/cubic_residual_times_derivative_accumulate.js";
|
|
2
|
+
import { polynomial_cubic_horner_eval } from "../linalg/polynomial_cubic_horner_eval.js";
|
|
1
3
|
import { polynomial_real_roots_in_interval } from "../linalg/polynomial_real_roots_in_interval.js";
|
|
2
|
-
import { solve_linear_system_GEPP_2x2 } from "../linalg/solve_linear_system_GEPP_2x2.js";
|
|
3
4
|
import { spline3_hermite_to_monomial } from "./spline3_hermite_to_monomial.js";
|
|
4
5
|
|
|
5
6
|
/*
|
|
@@ -39,11 +40,6 @@ const MAX_DIM = 16;
|
|
|
39
40
|
const _a_mono = new Float64Array(4 * MAX_DIM);
|
|
40
41
|
const _b_mono = new Float64Array(4 * MAX_DIM);
|
|
41
42
|
|
|
42
|
-
const _newton_FG = new Float64Array(2);
|
|
43
|
-
const _newton_J = new Float64Array(4);
|
|
44
|
-
const _newton_J_scratch = new Float64Array(4);
|
|
45
|
-
const _newton_RHS = new Float64Array(2);
|
|
46
|
-
|
|
47
43
|
const _candidate_st = new Float64Array(2);
|
|
48
44
|
const _edge_fixed_point = new Float64Array(MAX_DIM);
|
|
49
45
|
|
|
@@ -61,108 +57,116 @@ const CRITICAL_POINT_DEDUPE_TOLERANCE = 1e-7;
|
|
|
61
57
|
const _seen_s = new Float64Array(GRID_SIDE * GRID_SIDE + 8);
|
|
62
58
|
const _seen_t = new Float64Array(GRID_SIDE * GRID_SIDE + 8);
|
|
63
59
|
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return coeffs4[base] + x * (coeffs4[base + 1] + x * (coeffs4[base + 2] + x * coeffs4[base + 3]));
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function poly3_deriv(coeffs4, base, x) {
|
|
71
|
-
return coeffs4[base + 1] + x * (2 * coeffs4[base + 2] + x * 3 * coeffs4[base + 3]);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function poly3_second_deriv(coeffs4, base, x) {
|
|
75
|
-
return 2 * coeffs4[base + 2] + 6 * coeffs4[base + 3] * x;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ── core: F, G, and Jacobian at (s, t) ─────────────────────────────────────
|
|
79
|
-
|
|
80
|
-
function eval_FG(dim, s, t, out) {
|
|
81
|
-
let F = 0, G = 0;
|
|
82
|
-
for (let d = 0; d < dim; d++) {
|
|
83
|
-
const base = 4 * d;
|
|
84
|
-
const A = poly3_eval(_a_mono, base, s);
|
|
85
|
-
const Ap = poly3_deriv(_a_mono, base, s);
|
|
86
|
-
const B = poly3_eval(_b_mono, base, t);
|
|
87
|
-
const Bp = poly3_deriv(_b_mono, base, t);
|
|
88
|
-
const diff = A - B;
|
|
89
|
-
F += diff * Ap;
|
|
90
|
-
G -= diff * Bp;
|
|
91
|
-
}
|
|
92
|
-
out[0] = F;
|
|
93
|
-
out[1] = G;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function eval_jacobian(dim, s, t, out_J) {
|
|
97
|
-
let Jss = 0, Jst = 0, Jts = 0, Jtt = 0;
|
|
98
|
-
for (let d = 0; d < dim; d++) {
|
|
99
|
-
const base = 4 * d;
|
|
100
|
-
const A = poly3_eval(_a_mono, base, s);
|
|
101
|
-
const Ap = poly3_deriv(_a_mono, base, s);
|
|
102
|
-
const App = poly3_second_deriv(_a_mono, base, s);
|
|
103
|
-
const B = poly3_eval(_b_mono, base, t);
|
|
104
|
-
const Bp = poly3_deriv(_b_mono, base, t);
|
|
105
|
-
const Bpp = poly3_second_deriv(_b_mono, base, t);
|
|
106
|
-
const diff = A - B;
|
|
107
|
-
|
|
108
|
-
Jss += Ap * Ap + diff * App;
|
|
109
|
-
Jst += -Bp * Ap;
|
|
110
|
-
Jts += -Ap * Bp;
|
|
111
|
-
Jtt += Bp * Bp - diff * Bpp;
|
|
112
|
-
}
|
|
113
|
-
// Row-major 2x2: [Jss, Jst; Jts, Jtt]
|
|
114
|
-
out_J[0] = Jss;
|
|
115
|
-
out_J[1] = Jst;
|
|
116
|
-
out_J[2] = Jts;
|
|
117
|
-
out_J[3] = Jtt;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function eval_phi(dim, s, t) {
|
|
121
|
-
let acc = 0;
|
|
122
|
-
for (let d = 0; d < dim; d++) {
|
|
123
|
-
const base = 4 * d;
|
|
124
|
-
const A = poly3_eval(_a_mono, base, s);
|
|
125
|
-
const B = poly3_eval(_b_mono, base, t);
|
|
126
|
-
const diff = A - B;
|
|
127
|
-
acc += diff * diff;
|
|
128
|
-
}
|
|
129
|
-
return acc;
|
|
130
|
-
}
|
|
60
|
+
// The gradient system (F, G) = (½ ∂Φ/∂s, ½ ∂Φ/∂t) and the 2×2 Jacobian
|
|
61
|
+
// of that gradient are inlined directly into `newton_2d`'s hot loop — see
|
|
62
|
+
// the module preamble for the algebraic definitions of F, G, and J.
|
|
131
63
|
|
|
132
64
|
/**
|
|
133
65
|
* 2D Newton on (F, G) from a starting (s, t). Writes the converged (s, t) into
|
|
134
66
|
* `out` and returns true iff it converged inside [0, 1]² with small gradient.
|
|
135
67
|
*/
|
|
68
|
+
// Tolerance for declaring the 2x2 Jacobian singular during the inlined
|
|
69
|
+
// Newton solve. Matches `256 * FLT_EPSILON_64` used by
|
|
70
|
+
// solve_linear_system_GEPP_2x2 to keep behaviour identical on edge cases.
|
|
71
|
+
const NEWTON_SINGULAR_TOLERANCE = 256 * 1.1102230246251565e-16;
|
|
72
|
+
|
|
136
73
|
function newton_2d(dim, s_init, t_init, out) {
|
|
137
74
|
let s = s_init;
|
|
138
75
|
let t = t_init;
|
|
139
76
|
|
|
77
|
+
// F, G at the current (s, t) — promoted out of the heap-resident
|
|
78
|
+
// `_newton_FG` scratch into iteration-local doubles.
|
|
79
|
+
let F = 0, G = 0;
|
|
80
|
+
let fg_valid_at_current_st = false;
|
|
81
|
+
|
|
140
82
|
for (let iter = 0; iter < NEWTON_MAX_ITER; iter++) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
83
|
+
// ── fused F/G + Jacobian over all dimensions ──
|
|
84
|
+
// A single per-iteration sweep over dims computes the gradient
|
|
85
|
+
// (F, G) and the symmetric Hessian (Jss, J_cross, Jtt) from one
|
|
86
|
+
// load of each cubic's 4 coefficients. Eagerly computing the
|
|
87
|
+
// Hessian costs us one extra second-derivative + 3 accumulations
|
|
88
|
+
// per dim on the iteration that ends up converging — cheap insurance
|
|
89
|
+
// for skipping a duplicate cubic-eval sweep on every non-converging
|
|
90
|
+
// iteration. J_st = J_ts so the symmetric cross term is computed
|
|
91
|
+
// once into J_cross.
|
|
92
|
+
F = 0;
|
|
93
|
+
G = 0;
|
|
94
|
+
let Jss = 0, J_cross = 0, Jtt = 0;
|
|
95
|
+
|
|
96
|
+
for (let d = 0; d < dim; d++) {
|
|
97
|
+
const base = 4 * d;
|
|
98
|
+
const a0 = _a_mono[base];
|
|
99
|
+
const a1 = _a_mono[base + 1];
|
|
100
|
+
const a2 = _a_mono[base + 2];
|
|
101
|
+
const a3 = _a_mono[base + 3];
|
|
102
|
+
const b0 = _b_mono[base];
|
|
103
|
+
const b1 = _b_mono[base + 1];
|
|
104
|
+
const b2 = _b_mono[base + 2];
|
|
105
|
+
const b3 = _b_mono[base + 3];
|
|
106
|
+
|
|
107
|
+
const A_v = a0 + s * (a1 + s * (a2 + s * a3));
|
|
108
|
+
const A_p = a1 + s * (2 * a2 + s * 3 * a3);
|
|
109
|
+
const A_pp = 2 * a2 + 6 * a3 * s;
|
|
110
|
+
const B_v = b0 + t * (b1 + t * (b2 + t * b3));
|
|
111
|
+
const B_p = b1 + t * (2 * b2 + t * 3 * b3);
|
|
112
|
+
const B_pp = 2 * b2 + 6 * b3 * t;
|
|
113
|
+
|
|
114
|
+
const diff = A_v - B_v;
|
|
115
|
+
F += diff * A_p;
|
|
116
|
+
G -= diff * B_p;
|
|
117
|
+
Jss += A_p * A_p + diff * A_pp;
|
|
118
|
+
J_cross += -A_p * B_p;
|
|
119
|
+
Jtt += B_p * B_p - diff * B_pp;
|
|
120
|
+
}
|
|
121
|
+
fg_valid_at_current_st = true;
|
|
144
122
|
|
|
145
123
|
if (Math.abs(F) < NEWTON_GRADIENT_TOLERANCE && Math.abs(G) < NEWTON_GRADIENT_TOLERANCE) {
|
|
146
124
|
break;
|
|
147
125
|
}
|
|
148
126
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
|
|
127
|
+
// ── inline solve_linear_system_GEPP_2x2 on column-major J ──
|
|
128
|
+
// J = [a00, a10; a01, a11] = [Jss, J_cross; J_cross, Jtt]; rhs = [F, G]
|
|
129
|
+
// Partial pivoting on column 0, then forward eliminate, then back-sub.
|
|
130
|
+
// The "exact zero" special cases handled by the full solver are skipped:
|
|
131
|
+
// for a smooth residual Newton, exact zeros essentially never arise
|
|
132
|
+
// (random + analytic inputs), and a singular Jacobian gets rejected
|
|
133
|
+
// below the same way the full solver would.
|
|
134
|
+
let a00 = Jss, a10 = J_cross, a01 = J_cross, a11 = Jtt;
|
|
135
|
+
let b0 = F, b1 = G;
|
|
136
|
+
if (Math.abs(a10) > Math.abs(a00)) {
|
|
137
|
+
// Row swap
|
|
138
|
+
let tmp = a00; a00 = a10; a10 = tmp;
|
|
139
|
+
tmp = a01; a01 = a11; a11 = tmp;
|
|
140
|
+
tmp = b0; b0 = b1; b1 = tmp;
|
|
141
|
+
}
|
|
142
|
+
if (a00 === 0) {
|
|
143
|
+
return false; // singular column 0
|
|
144
|
+
}
|
|
145
|
+
const f = -a10 / a00;
|
|
146
|
+
a11 += a01 * f;
|
|
147
|
+
b1 += b0 * f;
|
|
148
|
+
if (Math.abs(a11) < NEWTON_SINGULAR_TOLERANCE) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
const dt = b1 / a11;
|
|
152
|
+
const ds = (b0 - a01 * dt) / a00;
|
|
153
|
+
if (!Number.isFinite(ds) || !Number.isFinite(dt)) {
|
|
157
154
|
return false;
|
|
158
155
|
}
|
|
159
|
-
|
|
160
|
-
const ds = _newton_RHS[0];
|
|
161
|
-
const dt = _newton_RHS[1];
|
|
162
156
|
|
|
163
157
|
s -= ds;
|
|
164
158
|
t -= dt;
|
|
165
159
|
|
|
160
|
+
// (s, t) has just changed → cached F, G no longer match.
|
|
161
|
+
fg_valid_at_current_st = false;
|
|
162
|
+
|
|
163
|
+
// Early bail: if (s, t) has wandered well outside [0, 1] the start is
|
|
164
|
+
// diverging or homed in on a critical point of the gradient system
|
|
165
|
+
// that lies far from the parameter square. Newton won't reel it back.
|
|
166
|
+
if (s < -0.5 || s > 1.5 || t < -0.5 || t > 1.5) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
|
|
166
170
|
if (Math.abs(ds) < NEWTON_STEP_TOLERANCE && Math.abs(dt) < NEWTON_STEP_TOLERANCE) {
|
|
167
171
|
break;
|
|
168
172
|
}
|
|
@@ -171,8 +175,36 @@ function newton_2d(dim, s_init, t_init, out) {
|
|
|
171
175
|
if (s < -1e-9 || s > 1 + 1e-9) return false;
|
|
172
176
|
if (t < -1e-9 || t > 1 + 1e-9) return false;
|
|
173
177
|
|
|
174
|
-
|
|
175
|
-
|
|
178
|
+
// Validate gradient at the final (s, t). When `fg_valid_at_current_st`
|
|
179
|
+
// is true we exited the loop via the gradient-tolerance break and the
|
|
180
|
+
// validation already passed (tolerance 1e-13 < 1e-6); otherwise we
|
|
181
|
+
// exited via the step-tolerance break or maxed out — re-evaluate to
|
|
182
|
+
// confirm.
|
|
183
|
+
if (!fg_valid_at_current_st) {
|
|
184
|
+
F = 0;
|
|
185
|
+
G = 0;
|
|
186
|
+
for (let d = 0; d < dim; d++) {
|
|
187
|
+
const base = 4 * d;
|
|
188
|
+
const a0 = _a_mono[base];
|
|
189
|
+
const a1 = _a_mono[base + 1];
|
|
190
|
+
const a2 = _a_mono[base + 2];
|
|
191
|
+
const a3 = _a_mono[base + 3];
|
|
192
|
+
const b0 = _b_mono[base];
|
|
193
|
+
const b1 = _b_mono[base + 1];
|
|
194
|
+
const b2 = _b_mono[base + 2];
|
|
195
|
+
const b3 = _b_mono[base + 3];
|
|
196
|
+
|
|
197
|
+
const A_v = a0 + s * (a1 + s * (a2 + s * a3));
|
|
198
|
+
const A_p = a1 + s * (2 * a2 + s * 3 * a3);
|
|
199
|
+
const B_v = b0 + t * (b1 + t * (b2 + t * b3));
|
|
200
|
+
const B_p = b1 + t * (2 * b2 + t * 3 * b3);
|
|
201
|
+
|
|
202
|
+
const diff = A_v - B_v;
|
|
203
|
+
F += diff * A_p;
|
|
204
|
+
G -= diff * B_p;
|
|
205
|
+
}
|
|
206
|
+
if (Math.abs(F) > 1e-6 || Math.abs(G) > 1e-6) return false;
|
|
207
|
+
}
|
|
176
208
|
|
|
177
209
|
out[0] = s < 0 ? 0 : (s > 1 ? 1 : s);
|
|
178
210
|
out[1] = t < 0 ? 0 : (t > 1 ? 1 : t);
|
|
@@ -193,46 +225,46 @@ function newton_2d(dim, s_init, t_init, out) {
|
|
|
193
225
|
* Writes `[t_min, dist²]` into `out` (length ≥ 2).
|
|
194
226
|
*/
|
|
195
227
|
function nearest_t_to_fixed_point(curve_mono, dim, point, point_offset, out) {
|
|
196
|
-
for (let i = 0; i < EDGE_QUINTIC_LEN; i++)
|
|
228
|
+
for (let i = 0; i < EDGE_QUINTIC_LEN; i++){
|
|
229
|
+
_edge_quintic[i] = 0;
|
|
230
|
+
}
|
|
197
231
|
|
|
198
232
|
for (let d = 0; d < dim; d++) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const dx2 = curve_mono[base + 2];
|
|
203
|
-
const dx3 = curve_mono[base + 3];
|
|
204
|
-
// derivative coefficients
|
|
205
|
-
const e0 = dx1, e1 = 2 * dx2, e2 = 3 * dx3;
|
|
206
|
-
|
|
207
|
-
// (dx0 + dx1 t + dx2 t² + dx3 t³) · (e0 + e1 t + e2 t²) accumulated
|
|
208
|
-
_edge_quintic[0] += dx0 * e0;
|
|
209
|
-
_edge_quintic[1] += dx0 * e1 + dx1 * e0;
|
|
210
|
-
_edge_quintic[2] += dx0 * e2 + dx1 * e1 + dx2 * e0;
|
|
211
|
-
_edge_quintic[3] += dx1 * e2 + dx2 * e1 + dx3 * e0;
|
|
212
|
-
_edge_quintic[4] += dx2 * e2 + dx3 * e1;
|
|
213
|
-
_edge_quintic[5] += dx3 * e2;
|
|
233
|
+
cubic_residual_times_derivative_accumulate(
|
|
234
|
+
_edge_quintic, curve_mono, 4 * d, point[point_offset + d]
|
|
235
|
+
);
|
|
214
236
|
}
|
|
215
237
|
|
|
238
|
+
// Aberth iteration cap of 32 is plenty for the degree-5 quintic that
|
|
239
|
+
// comes out of `(p(t) - offset)·p'(t)` on a smooth Hermite cubic — the
|
|
240
|
+
// routine's own convergence check still fires early in the common case.
|
|
241
|
+
// Default cap (80) is way more than needed and is the worst-case work
|
|
242
|
+
// budget; lowering it is a flat ~10-20% saving on degenerate inputs.
|
|
216
243
|
const root_count = polynomial_real_roots_in_interval(
|
|
217
|
-
_edge_quintic, 5, 0, 1, _edge_roots, 0
|
|
244
|
+
_edge_quintic, 5, 0, 1, _edge_roots, 0,
|
|
245
|
+
32
|
|
218
246
|
);
|
|
219
247
|
|
|
220
248
|
let best_t = 0;
|
|
221
249
|
let best_d2 = Number.POSITIVE_INFINITY;
|
|
222
250
|
|
|
223
251
|
for (let i = -2; i < root_count; i++) {
|
|
252
|
+
|
|
224
253
|
const t = i === -2 ? 0 : (i === -1 ? 1 : _edge_roots[i]);
|
|
225
254
|
let d2 = 0;
|
|
255
|
+
|
|
226
256
|
for (let d = 0; d < dim; d++) {
|
|
227
257
|
const base = 4 * d;
|
|
228
|
-
const v =
|
|
258
|
+
const v = polynomial_cubic_horner_eval(curve_mono, base, t);
|
|
229
259
|
const dv = v - point[point_offset + d];
|
|
230
260
|
d2 += dv * dv;
|
|
231
261
|
}
|
|
262
|
+
|
|
232
263
|
if (d2 < best_d2) {
|
|
233
264
|
best_d2 = d2;
|
|
234
265
|
best_t = t;
|
|
235
266
|
}
|
|
267
|
+
|
|
236
268
|
}
|
|
237
269
|
|
|
238
270
|
out[0] = best_t;
|
|
@@ -242,14 +274,41 @@ function nearest_t_to_fixed_point(curve_mono, dim, point, point_offset, out) {
|
|
|
242
274
|
// ── public ────────────────────────────────────────────────────────────────
|
|
243
275
|
|
|
244
276
|
/**
|
|
245
|
-
*
|
|
277
|
+
* Upper bound on the number of (s, t) pairs the ND variant can return:
|
|
278
|
+
* one per starting point of the GRID_SIDE × GRID_SIDE grid Newton, plus the
|
|
279
|
+
* four boundary edges, plus a small slack. The corresponding result-buffer
|
|
280
|
+
* size in floats is `2 * ND_MAX_ROOTS`.
|
|
281
|
+
*
|
|
282
|
+
* @type {number}
|
|
283
|
+
*/
|
|
284
|
+
export const ND_MAX_ROOTS = GRID_SIDE * GRID_SIDE + 8;
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Critical-point enumerator for the ND Hermite curve-pair intersection
|
|
288
|
+
* problem (dim ≥ 2, optimal for dim ≥ 3). Writes (s, t) pairs sequentially
|
|
289
|
+
* into `result` starting at `result_offset` and returns the count.
|
|
290
|
+
*
|
|
291
|
+
* What is reported (deduplicated within
|
|
292
|
+
* CRITICAL_POINT_DEDUPE_TOLERANCE = 1e-7 in each parameter):
|
|
293
|
+
* - Interior critical points of squared distance found by 2D Newton
|
|
294
|
+
* started from a GRID_SIDE × GRID_SIDE grid in [0,1]² and accepted
|
|
295
|
+
* when they converge inside [0,1]² with small gradient.
|
|
296
|
+
* - Four boundary closest-approach pairs, one per edge of [0,1]², each
|
|
297
|
+
* coming from a quintic root-find of (curve − fixed point)·curve′.
|
|
298
|
+
*
|
|
299
|
+
* Caller is responsible for evaluating both curves at each (s, t) and
|
|
300
|
+
* picking whichever pair(s) they care about (closest, within threshold,
|
|
301
|
+
* etc.).
|
|
302
|
+
*
|
|
303
|
+
* Required buffer size:
|
|
304
|
+
* `result.length >= result_offset + 2 * ND_MAX_ROOTS` floats (currently 178).
|
|
246
305
|
*
|
|
247
306
|
* @param {Float64Array|number[]} a length 4*dim
|
|
248
307
|
* @param {Float64Array|number[]} b length 4*dim
|
|
249
|
-
* @param {number} dim ≥
|
|
250
|
-
* @param {Float64Array|number[]} result
|
|
308
|
+
* @param {number} dim ≥ 2 (also correct for dim ≥ 2 but slower than the 2D path)
|
|
309
|
+
* @param {Float64Array|number[]} result length >= result_offset + 2 * ND_MAX_ROOTS
|
|
251
310
|
* @param {number} result_offset
|
|
252
|
-
* @returns {number}
|
|
311
|
+
* @returns {number} number of (s, t) pairs written
|
|
253
312
|
*/
|
|
254
313
|
export function spline3_hermite_intersection_spline3_hermite_nd(
|
|
255
314
|
a, b, dim,
|
|
@@ -266,29 +325,24 @@ export function spline3_hermite_intersection_spline3_hermite_nd(
|
|
|
266
325
|
spline3_hermite_to_monomial(_b_mono, off, 1, b[off], b[off + 1], b[off + 2], b[off + 3]);
|
|
267
326
|
}
|
|
268
327
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
let
|
|
328
|
+
// We dedupe near-identical critical points discovered from different grid
|
|
329
|
+
// starts. _seen_s / _seen_t double as the "candidates written so far" and
|
|
330
|
+
// are mirrored into the caller's `result` buffer as we go.
|
|
331
|
+
let count = 0;
|
|
332
|
+
let write = result_offset;
|
|
273
333
|
|
|
274
334
|
const try_candidate = (s, t) => {
|
|
275
|
-
|
|
276
|
-
for (let i = 0; i < seen_count; i++) {
|
|
335
|
+
for (let i = 0; i < count; i++) {
|
|
277
336
|
if (Math.abs(_seen_s[i] - s) < CRITICAL_POINT_DEDUPE_TOLERANCE
|
|
278
337
|
&& Math.abs(_seen_t[i] - t) < CRITICAL_POINT_DEDUPE_TOLERANCE) {
|
|
279
338
|
return;
|
|
280
339
|
}
|
|
281
340
|
}
|
|
282
|
-
_seen_s[
|
|
283
|
-
_seen_t[
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (d2 < best_d2) {
|
|
288
|
-
best_d2 = d2;
|
|
289
|
-
best_s = s;
|
|
290
|
-
best_t = t;
|
|
291
|
-
}
|
|
341
|
+
_seen_s[count] = s;
|
|
342
|
+
_seen_t[count] = t;
|
|
343
|
+
result[write++] = s;
|
|
344
|
+
result[write++] = t;
|
|
345
|
+
count++;
|
|
292
346
|
};
|
|
293
347
|
|
|
294
348
|
// Interior critical points via Newton from a grid.
|
|
@@ -308,7 +362,9 @@ export function spline3_hermite_intersection_spline3_hermite_nd(
|
|
|
308
362
|
const tmp_pt = _edge_fixed_point;
|
|
309
363
|
|
|
310
364
|
// Edge s = 0: fixed point is A(0); minimise over t on B.
|
|
311
|
-
for (let d = 0; d < dim; d++)
|
|
365
|
+
for (let d = 0; d < dim; d++){
|
|
366
|
+
tmp_pt[d] = _a_mono[4 * d]; // α0
|
|
367
|
+
}
|
|
312
368
|
nearest_t_to_fixed_point(_b_mono, dim, tmp_pt, 0, _candidate_st);
|
|
313
369
|
try_candidate(0, _candidate_st[0]);
|
|
314
370
|
|
|
@@ -321,7 +377,9 @@ export function spline3_hermite_intersection_spline3_hermite_nd(
|
|
|
321
377
|
try_candidate(1, _candidate_st[0]);
|
|
322
378
|
|
|
323
379
|
// Edge t = 0: fixed point is B(0); minimise over s on A.
|
|
324
|
-
for (let d = 0; d < dim; d++)
|
|
380
|
+
for (let d = 0; d < dim; d++){
|
|
381
|
+
tmp_pt[d] = _b_mono[4 * d];
|
|
382
|
+
}
|
|
325
383
|
nearest_t_to_fixed_point(_a_mono, dim, tmp_pt, 0, _candidate_st);
|
|
326
384
|
try_candidate(_candidate_st[0], 0);
|
|
327
385
|
|
|
@@ -333,7 +391,5 @@ export function spline3_hermite_intersection_spline3_hermite_nd(
|
|
|
333
391
|
nearest_t_to_fixed_point(_a_mono, dim, tmp_pt, 0, _candidate_st);
|
|
334
392
|
try_candidate(_candidate_st[0], 1);
|
|
335
393
|
|
|
336
|
-
|
|
337
|
-
result[result_offset + 1] = best_t;
|
|
338
|
-
return best_d2;
|
|
394
|
+
return count;
|
|
339
395
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Boolean intersection test for two cubic Hermite curves.
|
|
3
3
|
*
|
|
4
|
-
* Returns `true` if
|
|
5
|
-
*
|
|
6
|
-
* intersection.
|
|
4
|
+
* Returns `true` if any critical point of the squared-distance function
|
|
5
|
+
* over [0,1]² (interior or boundary) is within `tolerance` Euclidean
|
|
6
|
+
* distance. Tolerance = 0 reduces to "any true intersection exists".
|
|
7
|
+
*
|
|
8
|
+
* Internally: enumerates every candidate (s, t) pair via the dispatcher,
|
|
9
|
+
* evaluates both curves at each pair, computes squared distance, and
|
|
10
|
+
* short-circuits as soon as one pair clears the tolerance bound.
|
|
7
11
|
*
|
|
8
12
|
* @param {Float64Array|number[]} a length 4*dim, layout described in {@link spline3_hermite_intersection_spline3_hermite}
|
|
9
13
|
* @param {Float64Array|number[]} b same layout
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spline3_hermite_intersects_spline3_hermite.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_intersects_spline3_hermite.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"spline3_hermite_intersects_spline3_hermite.d.ts","sourceRoot":"","sources":["../../../../../src/core/math/spline/spline3_hermite_intersects_spline3_hermite.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AACH,8DANW,YAAY,GAAC,MAAM,EAAE,KACrB,YAAY,GAAC,MAAM,EAAE,OACrB,MAAM,aACN,MAAM,GACJ,OAAO,CA4BnB"}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
+
import { spline3_hermite } from "./spline3_hermite.js";
|
|
1
2
|
import { spline3_hermite_intersection_spline3_hermite } from "./spline3_hermite_intersection_spline3_hermite.js";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
// Sized for the largest variant (ND, up to 89 (s, t) pairs = 178 floats).
|
|
5
|
+
const _scratch_roots = new Float64Array(178);
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Boolean intersection test for two cubic Hermite curves.
|
|
7
9
|
*
|
|
8
|
-
* Returns `true` if
|
|
9
|
-
*
|
|
10
|
-
* intersection.
|
|
10
|
+
* Returns `true` if any critical point of the squared-distance function
|
|
11
|
+
* over [0,1]² (interior or boundary) is within `tolerance` Euclidean
|
|
12
|
+
* distance. Tolerance = 0 reduces to "any true intersection exists".
|
|
13
|
+
*
|
|
14
|
+
* Internally: enumerates every candidate (s, t) pair via the dispatcher,
|
|
15
|
+
* evaluates both curves at each pair, computes squared distance, and
|
|
16
|
+
* short-circuits as soon as one pair clears the tolerance bound.
|
|
11
17
|
*
|
|
12
18
|
* @param {Float64Array|number[]} a length 4*dim, layout described in {@link spline3_hermite_intersection_spline3_hermite}
|
|
13
19
|
* @param {Float64Array|number[]} b same layout
|
|
@@ -16,6 +22,29 @@ const _scratch_st = new Float64Array(2);
|
|
|
16
22
|
* @returns {boolean}
|
|
17
23
|
*/
|
|
18
24
|
export function spline3_hermite_intersects_spline3_hermite(a, b, dim, tolerance) {
|
|
19
|
-
const
|
|
20
|
-
|
|
25
|
+
const tolerance_sq = tolerance * tolerance;
|
|
26
|
+
|
|
27
|
+
const root_count = spline3_hermite_intersection_spline3_hermite(
|
|
28
|
+
a, b, dim, _scratch_roots, 0
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
for (let k = 0; k < root_count; k++) {
|
|
32
|
+
const s = _scratch_roots[2 * k];
|
|
33
|
+
const t = _scratch_roots[2 * k + 1];
|
|
34
|
+
|
|
35
|
+
let d2 = 0;
|
|
36
|
+
for (let d = 0; d < dim; d++) {
|
|
37
|
+
const off = 4 * d;
|
|
38
|
+
const va = spline3_hermite(s, a[off], a[off + 1], a[off + 2], a[off + 3]);
|
|
39
|
+
const vb = spline3_hermite(t, b[off], b[off + 1], b[off + 2], b[off + 3]);
|
|
40
|
+
const diff = va - vb;
|
|
41
|
+
d2 += diff * diff;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (d2 <= tolerance_sq) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return false;
|
|
21
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CalcTexArea.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/geometry/MikkT/CalcTexArea.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CalcTexArea.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/geometry/MikkT/CalcTexArea.js"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,mEAJW,MAAM,EAAE,kBACR,MAAM,GACJ,MAAM,CAiBlB"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { vec3 } from "gl-matrix";
|
|
2
2
|
import { GetTexCoord } from "./GetTexCoord.js";
|
|
3
|
-
import { fabsf } from "../../../../core/math/fabsf.js";
|
|
4
3
|
|
|
5
4
|
const t1 = vec3.create();
|
|
6
5
|
const t2 = vec3.create();
|
|
@@ -27,5 +26,5 @@ export function CalcTexArea(pContext, indices, indices_offset) {
|
|
|
27
26
|
|
|
28
27
|
const fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
|
|
29
28
|
|
|
30
|
-
return
|
|
29
|
+
return Math.abs(fSignedAreaSTx2);
|
|
31
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InitTriInfo.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/geometry/MikkT/InitTriInfo.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"InitTriInfo.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/geometry/MikkT/InitTriInfo.js"],"names":[],"mappings":"AA2BA;;;;;;;GAOG;AACH,uCANW,UAAU,eACV,MAAM,EAAE,GAAC,UAAU,gDAEnB,MAAM,GACJ,IAAI,CAgJhB"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { GROUP_WITH_ANY } from "./constants/GROUP_WITH_ANY.js";
|
|
2
1
|
import { vec3 } from "gl-matrix";
|
|
2
|
+
import { BuildNeighborsFast } from "./BuildNeighborsFast.js";
|
|
3
|
+
import { CalcTexArea } from "./CalcTexArea.js";
|
|
4
|
+
import { GROUP_WITH_ANY } from "./constants/GROUP_WITH_ANY.js";
|
|
5
|
+
import { MARK_DEGENERATE } from "./constants/MARK_DEGENERATE.js";
|
|
6
|
+
import { ORIENT_PRESERVING } from "./constants/ORIENT_PRESERVING.js";
|
|
3
7
|
import { GetPosition } from "./GetPosition.js";
|
|
4
8
|
import { GetTexCoord } from "./GetTexCoord.js";
|
|
5
|
-
import { ORIENT_PRESERVING } from "./constants/ORIENT_PRESERVING.js";
|
|
6
9
|
import { NotZero } from "./NotZero.js";
|
|
7
|
-
import { fabsf } from "../../../../core/math/fabsf.js";
|
|
8
|
-
import { MARK_DEGENERATE } from "./constants/MARK_DEGENERATE.js";
|
|
9
|
-
import { CalcTexArea } from "./CalcTexArea.js";
|
|
10
|
-
import { BuildNeighborsFast } from "./BuildNeighborsFast.js";
|
|
11
10
|
|
|
12
11
|
const t1 = vec3.create();
|
|
13
12
|
const t2 = vec3.create();
|
|
@@ -102,7 +101,7 @@ export function InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn) {
|
|
|
102
101
|
tri_info.iFlag |= (fSignedAreaSTx2 > 0 ? ORIENT_PRESERVING : 0);
|
|
103
102
|
|
|
104
103
|
if (NotZero(fSignedAreaSTx2)) {
|
|
105
|
-
const fAbsArea =
|
|
104
|
+
const fAbsArea = Math.abs(fSignedAreaSTx2);
|
|
106
105
|
|
|
107
106
|
const fLenOs = vec3.length(vOs);
|
|
108
107
|
const fLenOt = vec3.length(vOt);
|