@ifc-lite/clash 2.3.1 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/step.js +1 -0
- package/dist/adapters/step.js.map +1 -1
- package/dist/analysis.d.ts +6 -6
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +30 -29
- package/dist/analysis.js.map +1 -1
- package/dist/contact/narrow-phase.js +1 -1
- package/dist/engine-ts/broad.d.ts.map +1 -1
- package/dist/engine-ts/broad.js +11 -10
- package/dist/engine-ts/broad.js.map +1 -1
- package/dist/engine-ts/depth.d.ts +83 -11
- package/dist/engine-ts/depth.d.ts.map +1 -1
- package/dist/engine-ts/depth.js +134 -67
- package/dist/engine-ts/depth.js.map +1 -1
- package/dist/engine-ts/kernel.d.ts +2 -0
- package/dist/engine-ts/kernel.d.ts.map +1 -1
- package/dist/engine-ts/narrow.d.ts +8 -0
- package/dist/engine-ts/narrow.d.ts.map +1 -1
- package/dist/engine-ts/narrow.js +24 -15
- package/dist/engine-ts/narrow.js.map +1 -1
- package/dist/engine-ts/obb-detect.d.ts +3 -0
- package/dist/engine-ts/obb-detect.d.ts.map +1 -0
- package/dist/engine-ts/obb-detect.js +298 -0
- package/dist/engine-ts/obb-detect.js.map +1 -0
- package/dist/engine-ts/obb.d.ts +14 -23
- package/dist/engine-ts/obb.d.ts.map +1 -1
- package/dist/engine-ts/obb.js +35 -140
- package/dist/engine-ts/obb.js.map +1 -1
- package/dist/engine-ts/orchestrator.d.ts.map +1 -1
- package/dist/engine-ts/orchestrator.js +59 -15
- package/dist/engine-ts/orchestrator.js.map +1 -1
- package/dist/engine-ts/tri-mesh.d.ts +10 -7
- package/dist/engine-ts/tri-mesh.d.ts.map +1 -1
- package/dist/engine-ts/tri-mesh.js +34 -28
- package/dist/engine-ts/tri-mesh.js.map +1 -1
- package/dist/engine-ts/ts-kernel.d.ts.map +1 -1
- package/dist/engine-ts/ts-kernel.js +1 -0
- package/dist/engine-ts/ts-kernel.js.map +1 -1
- package/dist/engine-wasm/wasm-kernel.d.ts.map +1 -1
- package/dist/engine-wasm/wasm-kernel.js +10 -1
- package/dist/engine-wasm/wasm-kernel.js.map +1 -1
- package/dist/math/aabb.d.ts +9 -0
- package/dist/math/aabb.d.ts.map +1 -1
- package/dist/math/aabb.js +13 -0
- package/dist/math/aabb.js.map +1 -1
- package/dist/math/generated/plato.g.d.ts +11 -2
- package/dist/math/generated/plato.g.d.ts.map +1 -1
- package/dist/math/generated/plato.g.js +347 -190
- package/dist/math/generated/plato.g.js.map +1 -1
- package/dist/math/triangle-intersect.d.ts +12 -6
- package/dist/math/triangle-intersect.d.ts.map +1 -1
- package/dist/math/triangle-intersect.js +12 -6
- package/dist/math/triangle-intersect.js.map +1 -1
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +10 -10
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
import { sub, cross, dot, scale } from '../math/vec3.js';
|
|
5
|
+
import { OBB_EPS } from './obb.js';
|
|
6
|
+
function normalize(v) {
|
|
7
|
+
const len = Math.sqrt(dot(v, v));
|
|
8
|
+
if (!(len > OBB_EPS))
|
|
9
|
+
return null;
|
|
10
|
+
return [v[0] / len, v[1] / len, v[2] / len];
|
|
11
|
+
}
|
|
12
|
+
/** Flip `n` so its largest-magnitude component is positive, so a face and its
|
|
13
|
+
* antipodal opposite face collapse to the same canonical axis direction. Ties
|
|
14
|
+
* broken in x, y, z order — identical to the Rust `canonical`. */
|
|
15
|
+
function canonical(n) {
|
|
16
|
+
const ax = Math.abs(n[0]);
|
|
17
|
+
const ay = Math.abs(n[1]);
|
|
18
|
+
const az = Math.abs(n[2]);
|
|
19
|
+
let idx = 0;
|
|
20
|
+
if (ay > ax && ay >= az)
|
|
21
|
+
idx = 1;
|
|
22
|
+
else if (az > ax && az > ay)
|
|
23
|
+
idx = 2;
|
|
24
|
+
return n[idx] < 0 ? [-n[0], -n[1], -n[2]] : n;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* f32-ULP scale factor for a "worst-case" single-precision coordinate: for a
|
|
28
|
+
* value with magnitude in `[2, 4)` the true float32 ULP is `2^-22`, and for
|
|
29
|
+
* larger magnitudes the ULP only grows. Same constant (and reasoning) as
|
|
30
|
+
* `F32_ULP_SCALE` in `./depth.js`, and unlike the copies in `../contact/` it
|
|
31
|
+
* really is scaling the same quantity — the f32 quantisation of the same
|
|
32
|
+
* vertex buffer. It is still local because `./depth.js` imports THIS module
|
|
33
|
+
* (`obbPenetration`, `isThroughPenetration`), so importing the constant
|
|
34
|
+
* back out of it would close an import cycle for a one-line literal.
|
|
35
|
+
*/
|
|
36
|
+
const F32_ULP_SCALE = 1 / 4_194_304; // 2^-22
|
|
37
|
+
/**
|
|
38
|
+
* Bound, in radians, on the direction error of a face normal computed as
|
|
39
|
+
* `cross(b - a, c - a)` from vertices that arrived as f32.
|
|
40
|
+
*
|
|
41
|
+
* The vertices carry an absolute coordinate error of about
|
|
42
|
+
* `max|coord| * 2^-22` (`F32_ULP_SCALE`, the same f32-ULP bound the
|
|
43
|
+
* penetration floor uses), so each edge does too. `|cross| = |e1||e2|sin t`,
|
|
44
|
+
* and perturbing the edges by `d` tilts the normal by at most
|
|
45
|
+
* `d * (|e1| + |e2|) / |cross|`. The denominator makes this a property of the
|
|
46
|
+
* TRIANGLE's conditioning rather than a constant: a sliver, or a face with
|
|
47
|
+
* one very short edge, resolves its normal far less sharply than a
|
|
48
|
+
* well-shaped one at the same distance from the origin.
|
|
49
|
+
*
|
|
50
|
+
* This is the quantity an absolute `OBB_EPS` was standing in for, and a fixed
|
|
51
|
+
* bound is simultaneously too loose near the origin and far too tight away
|
|
52
|
+
* from it: a 0.05 m thick panel 1 km out resolves its normals to ~2.7e-4, so
|
|
53
|
+
* `|dot|` between two genuinely perpendicular faces exceeded `1e-6` and the
|
|
54
|
+
* box stopped being recognised as a box purely because it had been
|
|
55
|
+
* translated (#5355).
|
|
56
|
+
*/
|
|
57
|
+
function normalAngleError(a, b, c) {
|
|
58
|
+
const e1 = sub(b, a);
|
|
59
|
+
const e2 = sub(c, a);
|
|
60
|
+
let maxAbs = 0;
|
|
61
|
+
for (const v of [a, b, c]) {
|
|
62
|
+
for (const k of v) {
|
|
63
|
+
const m = Math.abs(k);
|
|
64
|
+
if (m > maxAbs)
|
|
65
|
+
maxAbs = m;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const coordErr = Math.max(maxAbs, 1) * F32_ULP_SCALE;
|
|
69
|
+
const n = cross(e1, e2);
|
|
70
|
+
const nLen = Math.sqrt(dot(n, n));
|
|
71
|
+
if (!(nLen > 0))
|
|
72
|
+
return [Infinity, coordErr];
|
|
73
|
+
const e1Len = Math.sqrt(dot(e1, e1));
|
|
74
|
+
const e2Len = Math.sqrt(dot(e2, e2));
|
|
75
|
+
return [(coordErr * (e1Len + e2Len)) / nLen, coordErr];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Detect whether `mesh` is a rectangular box: every (non-degenerate)
|
|
79
|
+
* triangle's normal falls into exactly 3 mutually orthogonal canonical
|
|
80
|
+
* directions, and every vertex of the triangles in a direction group lies on
|
|
81
|
+
* one of exactly two offset planes along that direction. That combination —
|
|
82
|
+
* 3 orthogonal face families, 2 planes each — forces the mesh to be a closed
|
|
83
|
+
* rectangular box (it rejects, for example, an axis-aligned L-shape, whose
|
|
84
|
+
* notch adds a third offset plane on two of the axes). Triangulation-
|
|
85
|
+
* independent: subdividing a box's faces adds triangles but never a new
|
|
86
|
+
* canonical direction or a third offset plane, so the detection (and the
|
|
87
|
+
* resulting `Obb`) is identical at any tessellation.
|
|
88
|
+
*
|
|
89
|
+
* Returns `null` — not a best-effort guess — when the check fails, so a
|
|
90
|
+
* caller that only trusts a non-null result never certifies a shape this
|
|
91
|
+
* function could not confirm.
|
|
92
|
+
*/
|
|
93
|
+
/**
|
|
94
|
+
* Largest angle (radians) that f32 noise may widen a box-recognition
|
|
95
|
+
* tolerance to (#5474). The noise bounds are worst cases: for a thin face far
|
|
96
|
+
* from the origin they can exceed the 45 deg at which a box's perpendicular
|
|
97
|
+
* face families stop being told apart at all. Noise may widen a tolerance
|
|
98
|
+
* only up to this angle; data that disagrees by more is not certified a box
|
|
99
|
+
* (the conservative outcome: the caller falls back to the labelled AABB
|
|
100
|
+
* estimate). Exact data far out still certifies, because the tests compare
|
|
101
|
+
* the MEASURED agreement against the tolerance. Same literal as the Rust
|
|
102
|
+
* `MAX_NOISE_ANGLE`.
|
|
103
|
+
*/
|
|
104
|
+
const MAX_NOISE_ANGLE = 0.1;
|
|
105
|
+
export function detectObb(mesh) {
|
|
106
|
+
if (mesh.count === 0)
|
|
107
|
+
return null;
|
|
108
|
+
// Everything position-dependent is measured from a point ON the mesh, not
|
|
109
|
+
// from the world origin (#5474). The box's centre used to be rebuilt as
|
|
110
|
+
// `sum_i c_i * axis_i` from offsets `dot(v, axis_i)` of ABSOLUTE vertex
|
|
111
|
+
// coordinates, so any error in the axes was multiplied by the element's
|
|
112
|
+
// distance from the origin: a 0.05 m panel 123 m out reported a 23 mm depth
|
|
113
|
+
// for a 20 mm overlap, and 1 km out a 65 mm one. Measured from `p0`, the
|
|
114
|
+
// lever arm is the element's own size.
|
|
115
|
+
const p0 = mesh.tri(0)[0];
|
|
116
|
+
const groups = [];
|
|
117
|
+
// Per family: the direction error bound of its representative (the first
|
|
118
|
+
// triangle's normal, used only to decide membership), and the area-weighted
|
|
119
|
+
// sum of its triangles' normals with the numerator of that sum's direction
|
|
120
|
+
// error bound (see `familyAxes`).
|
|
121
|
+
const repErr = [];
|
|
122
|
+
const sums = [];
|
|
123
|
+
const errNum = [];
|
|
124
|
+
const groupOfTri = new Array(mesh.count).fill(-1);
|
|
125
|
+
let coordErr = 0;
|
|
126
|
+
let reach = 0;
|
|
127
|
+
for (let t = 0; t < mesh.count; t += 1) {
|
|
128
|
+
const [a, b, c] = mesh.tri(t);
|
|
129
|
+
for (const v of [a, b, c]) {
|
|
130
|
+
const d = sub(v, p0);
|
|
131
|
+
const r = Math.sqrt(dot(d, d));
|
|
132
|
+
if (r > reach)
|
|
133
|
+
reach = r;
|
|
134
|
+
}
|
|
135
|
+
const raw = cross(sub(b, a), sub(c, a));
|
|
136
|
+
const n = normalize(raw);
|
|
137
|
+
if (!n)
|
|
138
|
+
continue; // degenerate triangle: contributes no face-normal evidence
|
|
139
|
+
const cn = canonical(n);
|
|
140
|
+
const [err, triCoordErr] = normalAngleError(a, b, c);
|
|
141
|
+
if (triCoordErr > coordErr)
|
|
142
|
+
coordErr = triCoordErr;
|
|
143
|
+
let gi = -1;
|
|
144
|
+
for (let g = 0; g < groups.length; g += 1) {
|
|
145
|
+
// Two normals of the same face agree to within the sum of their own
|
|
146
|
+
// direction errors (`1 - cos e <= e^2 / 2`). `OBB_EPS` stays as the
|
|
147
|
+
// floor, so a mesh at the origin groups exactly as before; far out, a
|
|
148
|
+
// thin face's triangles no longer split into a 4th "family" and
|
|
149
|
+
// decertify a perfect box (#5474).
|
|
150
|
+
const e = Math.min(repErr[g] + err, MAX_NOISE_ANGLE);
|
|
151
|
+
if (1 - dot(groups[g], cn) <= Math.max(OBB_EPS, 0.5 * e * e)) {
|
|
152
|
+
gi = g;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (gi === -1) {
|
|
157
|
+
if (groups.length >= 3)
|
|
158
|
+
return null; // a 4th face-normal family: not a box
|
|
159
|
+
groups.push(cn);
|
|
160
|
+
repErr.push(err);
|
|
161
|
+
sums.push([0, 0, 0]);
|
|
162
|
+
errNum.push(0);
|
|
163
|
+
gi = groups.length - 1;
|
|
164
|
+
}
|
|
165
|
+
// `raw` is twice the triangle's area along its normal, so the sum is
|
|
166
|
+
// area-weighted; oriented to the representative so opposite faces add
|
|
167
|
+
// rather than cancel.
|
|
168
|
+
const sign = dot(raw, groups[gi]) < 0 ? -1 : 1;
|
|
169
|
+
const sum = sums[gi];
|
|
170
|
+
for (let k = 0; k < 3; k += 1)
|
|
171
|
+
sum[k] += sign * raw[k];
|
|
172
|
+
errNum[gi] += err * Math.sqrt(dot(raw, raw));
|
|
173
|
+
groupOfTri[t] = gi;
|
|
174
|
+
}
|
|
175
|
+
if (groups.length !== 3)
|
|
176
|
+
return null;
|
|
177
|
+
const frame = familyAxes(sums, errNum);
|
|
178
|
+
if (!frame)
|
|
179
|
+
return null;
|
|
180
|
+
const [axes, axisErr] = frame;
|
|
181
|
+
for (let i = 0; i < 3; i += 1) {
|
|
182
|
+
for (let j = i + 1; j < 3; j += 1) {
|
|
183
|
+
// The families' own normals must be perpendicular, to within the sum of
|
|
184
|
+
// their direction errors; `OBB_EPS` stays as a FLOOR so a mesh at the
|
|
185
|
+
// origin is judged as strictly as before #5355.
|
|
186
|
+
const ni = scale(sums[i], 1 / Math.sqrt(dot(sums[i], sums[i])));
|
|
187
|
+
const nj = scale(sums[j], 1 / Math.sqrt(dot(sums[j], sums[j])));
|
|
188
|
+
const tol = Math.max(Math.min(axisErr[i] + axisErr[j], MAX_NOISE_ANGLE), OBB_EPS);
|
|
189
|
+
if (Math.abs(dot(ni, nj)) > tol)
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const minOff = [Infinity, Infinity, Infinity];
|
|
194
|
+
const maxOff = [-Infinity, -Infinity, -Infinity];
|
|
195
|
+
for (let t = 0; t < mesh.count; t += 1) {
|
|
196
|
+
const gi = groupOfTri[t];
|
|
197
|
+
if (gi === -1)
|
|
198
|
+
continue;
|
|
199
|
+
const [a, b, c] = mesh.tri(t);
|
|
200
|
+
for (const v of [a, b, c]) {
|
|
201
|
+
const o = dot(sub(v, p0), axes[gi]);
|
|
202
|
+
if (o < minOff[gi])
|
|
203
|
+
minOff[gi] = o;
|
|
204
|
+
if (o > maxOff[gi])
|
|
205
|
+
maxOff[gi] = o;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Reject a 3rd offset plane on any axis (e.g. an L-shaped footprint). A
|
|
209
|
+
// vertex on one of the two planes is off it by its own f32 rounding
|
|
210
|
+
// (`coordErr` bounds the difference of two vertices' roundings) plus the
|
|
211
|
+
// axis's direction error across the mesh (`reach` from `p0`); the relative
|
|
212
|
+
// `OBB_EPS` term is the floor that applied before #5474.
|
|
213
|
+
for (let t = 0; t < mesh.count; t += 1) {
|
|
214
|
+
const gi = groupOfTri[t];
|
|
215
|
+
if (gi === -1)
|
|
216
|
+
continue;
|
|
217
|
+
const [a, b, c] = mesh.tri(t);
|
|
218
|
+
const scaleOff = Math.max(Math.max(1, Math.abs(minOff[gi])), Math.abs(maxOff[gi]));
|
|
219
|
+
const tol = Math.max(OBB_EPS * scaleOff, coordErr + Math.min(axisErr[gi], MAX_NOISE_ANGLE) * reach);
|
|
220
|
+
for (const v of [a, b, c]) {
|
|
221
|
+
const o = dot(sub(v, p0), axes[gi]);
|
|
222
|
+
const nearMin = Math.abs(o - minOff[gi]) <= tol;
|
|
223
|
+
const nearMax = Math.abs(o - maxOff[gi]) <= tol;
|
|
224
|
+
if (!nearMin && !nearMax)
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const half = [0, 0, 0];
|
|
229
|
+
const c0 = [0, 0, 0];
|
|
230
|
+
for (let i = 0; i < 3; i += 1) {
|
|
231
|
+
half[i] = (maxOff[i] - minOff[i]) / 2;
|
|
232
|
+
c0[i] = (maxOff[i] + minOff[i]) / 2;
|
|
233
|
+
// Reject a zero-thickness "box": a face family whose triangles are all
|
|
234
|
+
// coplanar passes the 2-plane test above (`minOff === maxOff`) with no
|
|
235
|
+
// positive extent along that axis — an open shell (review: #2536).
|
|
236
|
+
if (!(half[i] > OBB_EPS))
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
const center = [
|
|
240
|
+
p0[0] + c0[0] * axes[0][0] + c0[1] * axes[1][0] + c0[2] * axes[2][0],
|
|
241
|
+
p0[1] + c0[0] * axes[0][1] + c0[1] * axes[1][1] + c0[2] * axes[2][1],
|
|
242
|
+
p0[2] + c0[0] * axes[0][2] + c0[1] * axes[1][2] + c0[2] * axes[2][2],
|
|
243
|
+
];
|
|
244
|
+
return { center, axes: [axes[0], axes[1], axes[2]], half };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* The box frame from the three families' area-weighted normal sums, with a
|
|
248
|
+
* direction error bound per axis (#5474).
|
|
249
|
+
*
|
|
250
|
+
* Each family's sum is dominated by its largest faces, which resolve their
|
|
251
|
+
* normal most sharply (`errNum / |sum|` is the area-weighted mean of the
|
|
252
|
+
* triangles' `normalAngleError`). The frame is then made EXACTLY orthonormal,
|
|
253
|
+
* most precise family first: its axis is its own normalised sum, the next is
|
|
254
|
+
* Gram-Schmidt'ed against it, the last is their cross product. A thin panel's
|
|
255
|
+
* 5 cm side faces therefore inherit the precision of its 3 m faces instead of
|
|
256
|
+
* contributing their own, and a centre rebuilt from the frame cannot pick up
|
|
257
|
+
* a non-orthogonality error. Ties in precision keep family order, so the
|
|
258
|
+
* frame is deterministic. Bit-identical to the Rust `family_axes`.
|
|
259
|
+
*/
|
|
260
|
+
function familyAxes(sums, errNum) {
|
|
261
|
+
const err = [0, 0, 0];
|
|
262
|
+
for (let g = 0; g < 3; g += 1) {
|
|
263
|
+
const len = Math.sqrt(dot(sums[g], sums[g]));
|
|
264
|
+
if (!(len > 0))
|
|
265
|
+
return null;
|
|
266
|
+
err[g] = errNum[g] / len;
|
|
267
|
+
}
|
|
268
|
+
const order = [0, 1, 2];
|
|
269
|
+
// Stable insertion sort on the error bound (3 elements).
|
|
270
|
+
for (let i = 1; i < 3; i += 1) {
|
|
271
|
+
let j = i;
|
|
272
|
+
while (j > 0 && err[order[j]] < err[order[j - 1]]) {
|
|
273
|
+
[order[j], order[j - 1]] = [order[j - 1], order[j]];
|
|
274
|
+
j -= 1;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const [f0, f1, f2] = order;
|
|
278
|
+
const a0 = normalize(sums[f0]);
|
|
279
|
+
if (!a0)
|
|
280
|
+
return null;
|
|
281
|
+
const a1 = normalize(sub(sums[f1], scale(a0, dot(sums[f1], a0))));
|
|
282
|
+
if (!a1)
|
|
283
|
+
return null;
|
|
284
|
+
let a2 = cross(a0, a1);
|
|
285
|
+
if (dot(a2, sums[f2]) < 0)
|
|
286
|
+
a2 = scale(a2, -1);
|
|
287
|
+
const axes = [];
|
|
288
|
+
axes[f0] = a0;
|
|
289
|
+
axes[f1] = a1;
|
|
290
|
+
axes[f2] = a2;
|
|
291
|
+
// An orthogonalised axis is as precise as the axes it was built from.
|
|
292
|
+
const axisErr = [0, 0, 0];
|
|
293
|
+
axisErr[f0] = err[f0];
|
|
294
|
+
axisErr[f1] = err[f0] + err[f1];
|
|
295
|
+
axisErr[f2] = err[f0] + err[f1];
|
|
296
|
+
return [axes, axisErr];
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=obb-detect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"obb-detect.js","sourceRoot":"","sources":["../../src/engine-ts/obb-detect.ts"],"names":[],"mappings":"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"}
|
package/dist/engine-ts/obb.d.ts
CHANGED
|
@@ -32,31 +32,21 @@ export interface MeshLike {
|
|
|
32
32
|
readonly count: number;
|
|
33
33
|
tri(t: number): [Vec3, Vec3, Vec3];
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Detect whether `mesh` is a rectangular box: every (non-degenerate)
|
|
37
|
-
* triangle's normal falls into exactly 3 mutually orthogonal canonical
|
|
38
|
-
* directions, and every vertex of the triangles in a direction group lies on
|
|
39
|
-
* one of exactly two offset planes along that direction. That combination —
|
|
40
|
-
* 3 orthogonal face families, 2 planes each — forces the mesh to be a closed
|
|
41
|
-
* rectangular box (it rejects, for example, an axis-aligned L-shape, whose
|
|
42
|
-
* notch adds a third offset plane on two of the axes). Triangulation-
|
|
43
|
-
* independent: subdividing a box's faces adds triangles but never a new
|
|
44
|
-
* canonical direction or a third offset plane, so the detection (and the
|
|
45
|
-
* resulting `Obb`) is identical at any tessellation.
|
|
46
|
-
*
|
|
47
|
-
* Returns `null` — not a best-effort guess — when the check fails, so a
|
|
48
|
-
* caller that only trusts a non-null result never certifies a shape this
|
|
49
|
-
* function could not confirm.
|
|
50
|
-
*/
|
|
51
|
-
export declare function detectObb(mesh: MeshLike): Obb | null;
|
|
52
35
|
/**
|
|
53
36
|
* Bound, in f64 ulps, on the absolute error of one component of the cross
|
|
54
37
|
* product of two UNIT vectors (each component is a product-difference of
|
|
55
38
|
* magnitude-<=1 terms: ~2 ulps), with headroom for the normalisation and the
|
|
56
39
|
* per-projection dot rounding it feeds. Shared by the axis noise bound in
|
|
57
|
-
* {@link
|
|
40
|
+
* {@link obbPenetration}; same literal in the Rust kernel.
|
|
58
41
|
*/
|
|
59
42
|
export declare const AXIS_NOISE_ULPS = 8;
|
|
43
|
+
/** An OBB-OBB minimum translation depth and the UNIT axis it was measured
|
|
44
|
+
* along: the depth's precision floor is the pair's f32 noise projected onto
|
|
45
|
+
* that axis (#5405). Mirrors the Rust `ObbPenetration`. */
|
|
46
|
+
export interface ObbPenetration {
|
|
47
|
+
depth: number;
|
|
48
|
+
axis: Vec3;
|
|
49
|
+
}
|
|
60
50
|
/**
|
|
61
51
|
* Exact penetration depth between two oriented boxes: the minimum overlap
|
|
62
52
|
* over the 15 canonical OBB-OBB separating-axis candidates (each box's 3 face
|
|
@@ -70,8 +60,9 @@ export declare const AXIS_NOISE_ULPS = 8;
|
|
|
70
60
|
* the ~ulp-level absolute error of the cross product into a direction error
|
|
71
61
|
* of up to `AXIS_NOISE_ULPS * EPS / |L|` radians. Each candidate's verdict
|
|
72
62
|
* therefore carries a SCALE-RELATIVE noise bound (see `testAxis`), and a
|
|
73
|
-
* verdict inside its own noise band is
|
|
74
|
-
*
|
|
63
|
+
* verdict inside its own noise band is never trusted to separate, and
|
|
64
|
+
* contributes a depth candidate of zero rather than being dropped from the
|
|
65
|
+
* minimum (#5355) (review: #2536; the same
|
|
75
66
|
* tolerance-from-the-wrong-quantity class as #2598/#2600/#2529 — an earlier
|
|
76
67
|
* ABSOLUTE `len > 1e-6` guard here both divided by lengths whose noise
|
|
77
68
|
* dwarfs a thin overlap at large operand scale, and hard-dropped axes that
|
|
@@ -86,7 +77,7 @@ export declare const AXIS_NOISE_ULPS = 8;
|
|
|
86
77
|
* `null` (caller falls back to the AABB estimate) rather than reporting a
|
|
87
78
|
* wrong depth.
|
|
88
79
|
*/
|
|
89
|
-
export declare function
|
|
80
|
+
export declare function obbPenetration(a: Obb, b: Obb): ObbPenetration | null;
|
|
90
81
|
/**
|
|
91
82
|
* Whether `a` and `b` are in a THROUGH-PENETRATION configuration: one box's
|
|
92
83
|
* cross-section, in the plane perpendicular to one of ITS OWN axes, is fully
|
|
@@ -96,7 +87,7 @@ export declare function obbPenetrationDepth(a: Obb, b: Obb): number | null;
|
|
|
96
87
|
* ways, so it also holds for the MUTUAL case: two walls crossing at an
|
|
97
88
|
* X-junction, each piercing the other clean through in thickness.
|
|
98
89
|
*
|
|
99
|
-
* This matters because {@link
|
|
90
|
+
* This matters because {@link obbPenetration} reports the minimum
|
|
100
91
|
* TRANSLATION distance to separate the pair, which for this shape is
|
|
101
92
|
* dominated by the piercing member's own extent along the piercing axis, not
|
|
102
93
|
* by how much material it actually crossed (review: #2536 — a 2 m duct
|
|
@@ -105,7 +96,7 @@ export declare function obbPenetrationDepth(a: Obb, b: Obb): number | null;
|
|
|
105
96
|
*
|
|
106
97
|
* Tests containment against EACH box's own axes independently (via
|
|
107
98
|
* {@link piercesAlong}'s general per-axis projection, the same projection
|
|
108
|
-
* {@link
|
|
99
|
+
* {@link obbPenetration} already computes for its 15 SAT candidates) —
|
|
109
100
|
* unlike an earlier version restricted to a frame shared by both boxes'
|
|
110
101
|
* axes up to sign, this also catches a member piercing through at a generic
|
|
111
102
|
* relative rotation (e.g. a duct crossing a wall at 15 degrees, review:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obb.d.ts","sourceRoot":"","sources":["../../src/engine-ts/obb.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC;+DAC+D;AAC/D,eAAO,MAAM,OAAO,WAAO,CAAC;AAE5B,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,IAAI,CAAC;IACb,2CAA2C;IAC3C,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACzB,6DAA6D;IAC7D,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;yDACyD;AACzD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;CACpC;
|
|
1
|
+
{"version":3,"file":"obb.d.ts","sourceRoot":"","sources":["../../src/engine-ts/obb.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC;+DAC+D;AAC/D,eAAO,MAAM,OAAO,WAAO,CAAC;AAE5B,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,IAAI,CAAC;IACb,2CAA2C;IAC3C,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACzB,6DAA6D;IAC7D,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;yDACyD;AACzD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;CACpC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC;;4DAE4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,cAAc,GAAG,IAAI,CAsFpE;AAkED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAK5D"}
|
package/dist/engine-ts/obb.js
CHANGED
|
@@ -1,138 +1,16 @@
|
|
|
1
1
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
-
import {
|
|
4
|
+
import { cross, dot } from '../math/vec3.js';
|
|
5
5
|
/** Tolerance for normal-direction dedup and offset-plane clustering. Same
|
|
6
6
|
* literal in the Rust kernel — see `rust/clash/src/obb.rs`. */
|
|
7
7
|
export const OBB_EPS = 1e-6;
|
|
8
|
-
function normalize(v) {
|
|
9
|
-
const len = Math.sqrt(dot(v, v));
|
|
10
|
-
if (!(len > OBB_EPS))
|
|
11
|
-
return null;
|
|
12
|
-
return [v[0] / len, v[1] / len, v[2] / len];
|
|
13
|
-
}
|
|
14
|
-
/** Flip `n` so its largest-magnitude component is positive, so a face and its
|
|
15
|
-
* antipodal opposite face collapse to the same canonical axis direction. Ties
|
|
16
|
-
* broken in x, y, z order — identical to the Rust `canonical`. */
|
|
17
|
-
function canonical(n) {
|
|
18
|
-
const ax = Math.abs(n[0]);
|
|
19
|
-
const ay = Math.abs(n[1]);
|
|
20
|
-
const az = Math.abs(n[2]);
|
|
21
|
-
let idx = 0;
|
|
22
|
-
if (ay > ax && ay >= az)
|
|
23
|
-
idx = 1;
|
|
24
|
-
else if (az > ax && az > ay)
|
|
25
|
-
idx = 2;
|
|
26
|
-
return n[idx] < 0 ? [-n[0], -n[1], -n[2]] : n;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Detect whether `mesh` is a rectangular box: every (non-degenerate)
|
|
30
|
-
* triangle's normal falls into exactly 3 mutually orthogonal canonical
|
|
31
|
-
* directions, and every vertex of the triangles in a direction group lies on
|
|
32
|
-
* one of exactly two offset planes along that direction. That combination —
|
|
33
|
-
* 3 orthogonal face families, 2 planes each — forces the mesh to be a closed
|
|
34
|
-
* rectangular box (it rejects, for example, an axis-aligned L-shape, whose
|
|
35
|
-
* notch adds a third offset plane on two of the axes). Triangulation-
|
|
36
|
-
* independent: subdividing a box's faces adds triangles but never a new
|
|
37
|
-
* canonical direction or a third offset plane, so the detection (and the
|
|
38
|
-
* resulting `Obb`) is identical at any tessellation.
|
|
39
|
-
*
|
|
40
|
-
* Returns `null` — not a best-effort guess — when the check fails, so a
|
|
41
|
-
* caller that only trusts a non-null result never certifies a shape this
|
|
42
|
-
* function could not confirm.
|
|
43
|
-
*/
|
|
44
|
-
export function detectObb(mesh) {
|
|
45
|
-
if (mesh.count === 0)
|
|
46
|
-
return null;
|
|
47
|
-
const groups = [];
|
|
48
|
-
const groupOfTri = new Array(mesh.count).fill(-1);
|
|
49
|
-
for (let t = 0; t < mesh.count; t += 1) {
|
|
50
|
-
const [a, b, c] = mesh.tri(t);
|
|
51
|
-
const n = normalize(cross(sub(b, a), sub(c, a)));
|
|
52
|
-
if (!n)
|
|
53
|
-
continue; // degenerate triangle: contributes no face-normal evidence
|
|
54
|
-
const cn = canonical(n);
|
|
55
|
-
let gi = -1;
|
|
56
|
-
for (let g = 0; g < groups.length; g += 1) {
|
|
57
|
-
if (dot(groups[g], cn) > 1 - OBB_EPS) {
|
|
58
|
-
gi = g;
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (gi === -1) {
|
|
63
|
-
if (groups.length >= 3)
|
|
64
|
-
return null; // a 4th face-normal family: not a box
|
|
65
|
-
groups.push(cn);
|
|
66
|
-
gi = groups.length - 1;
|
|
67
|
-
}
|
|
68
|
-
groupOfTri[t] = gi;
|
|
69
|
-
}
|
|
70
|
-
if (groups.length !== 3)
|
|
71
|
-
return null;
|
|
72
|
-
for (let i = 0; i < 3; i += 1) {
|
|
73
|
-
for (let j = i + 1; j < 3; j += 1) {
|
|
74
|
-
if (Math.abs(dot(groups[i], groups[j])) > OBB_EPS)
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
const minOff = [Infinity, Infinity, Infinity];
|
|
79
|
-
const maxOff = [-Infinity, -Infinity, -Infinity];
|
|
80
|
-
for (let t = 0; t < mesh.count; t += 1) {
|
|
81
|
-
const gi = groupOfTri[t];
|
|
82
|
-
if (gi === -1)
|
|
83
|
-
continue;
|
|
84
|
-
const [a, b, c] = mesh.tri(t);
|
|
85
|
-
for (const v of [a, b, c]) {
|
|
86
|
-
const o = dot(v, groups[gi]);
|
|
87
|
-
if (o < minOff[gi])
|
|
88
|
-
minOff[gi] = o;
|
|
89
|
-
if (o > maxOff[gi])
|
|
90
|
-
maxOff[gi] = o;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Reject a 3rd offset plane on any axis (e.g. an L-shaped footprint).
|
|
94
|
-
for (let t = 0; t < mesh.count; t += 1) {
|
|
95
|
-
const gi = groupOfTri[t];
|
|
96
|
-
if (gi === -1)
|
|
97
|
-
continue;
|
|
98
|
-
const [a, b, c] = mesh.tri(t);
|
|
99
|
-
for (const v of [a, b, c]) {
|
|
100
|
-
const o = dot(v, groups[gi]);
|
|
101
|
-
const scale = Math.max(1, Math.abs(minOff[gi]), Math.abs(maxOff[gi]));
|
|
102
|
-
const nearMin = Math.abs(o - minOff[gi]) <= OBB_EPS * scale;
|
|
103
|
-
const nearMax = Math.abs(o - maxOff[gi]) <= OBB_EPS * scale;
|
|
104
|
-
if (!nearMin && !nearMax)
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
const half = [0, 0, 0];
|
|
109
|
-
const c0 = [0, 0, 0];
|
|
110
|
-
for (let i = 0; i < 3; i += 1) {
|
|
111
|
-
half[i] = (maxOff[i] - minOff[i]) / 2;
|
|
112
|
-
c0[i] = (maxOff[i] + minOff[i]) / 2;
|
|
113
|
-
// Reject a zero-thickness "box": a face family whose triangles are all
|
|
114
|
-
// coplanar passes the 2-plane test above (minOff == maxOff, so both
|
|
115
|
-
// `nearMin` and `nearMax` hold for every vertex) with no positive
|
|
116
|
-
// extent along that axis. An open shell (a slab exported without its
|
|
117
|
-
// top face, or partial `IfcTriangulatedFaceSet` geometry) can produce
|
|
118
|
-
// exactly this — 3 orthogonal families, but one degenerate — and must
|
|
119
|
-
// not be certified as a box (review: #2536).
|
|
120
|
-
if (!(half[i] > OBB_EPS))
|
|
121
|
-
return null;
|
|
122
|
-
}
|
|
123
|
-
const center = [
|
|
124
|
-
c0[0] * groups[0][0] + c0[1] * groups[1][0] + c0[2] * groups[2][0],
|
|
125
|
-
c0[0] * groups[0][1] + c0[1] * groups[1][1] + c0[2] * groups[2][1],
|
|
126
|
-
c0[0] * groups[0][2] + c0[1] * groups[1][2] + c0[2] * groups[2][2],
|
|
127
|
-
];
|
|
128
|
-
return { center, axes: [groups[0], groups[1], groups[2]], half };
|
|
129
|
-
}
|
|
130
8
|
/**
|
|
131
9
|
* Bound, in f64 ulps, on the absolute error of one component of the cross
|
|
132
10
|
* product of two UNIT vectors (each component is a product-difference of
|
|
133
11
|
* magnitude-<=1 terms: ~2 ulps), with headroom for the normalisation and the
|
|
134
12
|
* per-projection dot rounding it feeds. Shared by the axis noise bound in
|
|
135
|
-
* {@link
|
|
13
|
+
* {@link obbPenetration}; same literal in the Rust kernel.
|
|
136
14
|
*/
|
|
137
15
|
export const AXIS_NOISE_ULPS = 8;
|
|
138
16
|
/**
|
|
@@ -148,8 +26,9 @@ export const AXIS_NOISE_ULPS = 8;
|
|
|
148
26
|
* the ~ulp-level absolute error of the cross product into a direction error
|
|
149
27
|
* of up to `AXIS_NOISE_ULPS * EPS / |L|` radians. Each candidate's verdict
|
|
150
28
|
* therefore carries a SCALE-RELATIVE noise bound (see `testAxis`), and a
|
|
151
|
-
* verdict inside its own noise band is
|
|
152
|
-
*
|
|
29
|
+
* verdict inside its own noise band is never trusted to separate, and
|
|
30
|
+
* contributes a depth candidate of zero rather than being dropped from the
|
|
31
|
+
* minimum (#5355) (review: #2536; the same
|
|
153
32
|
* tolerance-from-the-wrong-quantity class as #2598/#2600/#2529 — an earlier
|
|
154
33
|
* ABSOLUTE `len > 1e-6` guard here both divided by lengths whose noise
|
|
155
34
|
* dwarfs a thin overlap at large operand scale, and hard-dropped axes that
|
|
@@ -164,7 +43,7 @@ export const AXIS_NOISE_ULPS = 8;
|
|
|
164
43
|
* `null` (caller falls back to the AABB estimate) rather than reporting a
|
|
165
44
|
* wrong depth.
|
|
166
45
|
*/
|
|
167
|
-
export function
|
|
46
|
+
export function obbPenetration(a, b) {
|
|
168
47
|
const T = [b.center[0] - a.center[0], b.center[1] - a.center[1], b.center[2] - a.center[2]];
|
|
169
48
|
// Operand scale for the per-axis noise bound: the sum of BOTH boxes' three
|
|
170
49
|
// half-extents plus the center offset's components. A direction error of
|
|
@@ -183,6 +62,7 @@ export function obbPenetrationDepth(a, b) {
|
|
|
183
62
|
b.half[0] + b.half[1] + b.half[2] +
|
|
184
63
|
Math.abs(T[0]) + Math.abs(T[1]) + Math.abs(T[2]);
|
|
185
64
|
let depth = Infinity;
|
|
65
|
+
let depthAxis = [0, 0, 0];
|
|
186
66
|
function testAxis(L) {
|
|
187
67
|
const len = Math.sqrt(dot(L, L));
|
|
188
68
|
// Exactly parallel axes: the cross product is zero and the candidate
|
|
@@ -205,22 +85,37 @@ export function obbPenetrationDepth(a, b) {
|
|
|
205
85
|
// `AXIS_NOISE_ULPS * EPS / len` radians (cancellation shrinks `|L|` to
|
|
206
86
|
// sin(angle) but leaves the cross product's ~ulp absolute error intact),
|
|
207
87
|
// so `overlap` is uncertain by up to `extentSum` times that. A verdict
|
|
208
|
-
// inside the band
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
// (it may keep a clash a perfect test would separate, but never
|
|
213
|
-
// separates a genuine overlap). Do not "harden" this into returning
|
|
214
|
-
// false: that would turn unresolvable noise into a fabricated
|
|
88
|
+
// inside the band may not SEPARATE: in a separating-axis test, declining
|
|
89
|
+
// to separate can only fail to find a separation, never invent one, so
|
|
90
|
+
// the boolean result stays conservative. Do not "harden" this into
|
|
91
|
+
// returning false: that would turn unresolvable noise into a fabricated
|
|
215
92
|
// separation. Verdicts OUTSIDE the band are kept whatever `len` is —
|
|
216
93
|
// their own magnitude proves the noise did not decide them.
|
|
94
|
+
//
|
|
95
|
+
// It DOES still contribute a depth candidate, of zero (#5355). The depth
|
|
96
|
+
// is a MINIMUM over candidates, so an axis whose overlap is
|
|
97
|
+
// indistinguishable from zero is the smallest candidate present;
|
|
98
|
+
// dropping it hands the minimum to the next-smallest axis, which for two
|
|
99
|
+
// boxes in flush face contact is a FACE DIMENSION of one of them. #2536
|
|
100
|
+
// fixed WHICH axes fall in the band (an absolute `len > 1e-6` dropped
|
|
101
|
+
// axes that were fine, over-reporting a 0.02 m edge contact as 0.45 m);
|
|
102
|
+
// the remaining half was what dropping does to the minimum, which still
|
|
103
|
+
// reported 0.85 m for a 0.05 m curtain-wall panel lying flush against a
|
|
104
|
+
// mullion.
|
|
217
105
|
const noise = extentSum * ((AXIS_NOISE_ULPS * Number.EPSILON) / len);
|
|
218
|
-
if (Math.abs(overlap) <= noise)
|
|
106
|
+
if (Math.abs(overlap) <= noise) {
|
|
107
|
+
if (depth > 0) {
|
|
108
|
+
depth = 0;
|
|
109
|
+
depthAxis = u;
|
|
110
|
+
}
|
|
219
111
|
return true;
|
|
112
|
+
}
|
|
220
113
|
if (overlap <= 0)
|
|
221
114
|
return false;
|
|
222
|
-
if (overlap < depth)
|
|
115
|
+
if (overlap < depth) {
|
|
223
116
|
depth = overlap;
|
|
117
|
+
depthAxis = u;
|
|
118
|
+
}
|
|
224
119
|
return true;
|
|
225
120
|
}
|
|
226
121
|
for (let i = 0; i < 3; i += 1)
|
|
@@ -235,11 +130,11 @@ export function obbPenetrationDepth(a, b) {
|
|
|
235
130
|
return null;
|
|
236
131
|
}
|
|
237
132
|
}
|
|
238
|
-
return depth === Infinity ? null : depth;
|
|
133
|
+
return depth === Infinity ? null : { depth, axis: depthAxis };
|
|
239
134
|
}
|
|
240
135
|
/**
|
|
241
136
|
* Projected radius of `o` onto unit axis `u`: half the length of `o`'s
|
|
242
|
-
* shadow on `u`. The same per-axis projection {@link
|
|
137
|
+
* shadow on `u`. The same per-axis projection {@link obbPenetration}'s
|
|
243
138
|
* `testAxis` computes for the 15-candidate SAT — factored out here so the
|
|
244
139
|
* through-penetration containment test below can reuse it for ANY axis, not
|
|
245
140
|
* only one drawn from a shared a/b frame.
|
|
@@ -306,7 +201,7 @@ function piercesAlong(p, q, centerDelta) {
|
|
|
306
201
|
* ways, so it also holds for the MUTUAL case: two walls crossing at an
|
|
307
202
|
* X-junction, each piercing the other clean through in thickness.
|
|
308
203
|
*
|
|
309
|
-
* This matters because {@link
|
|
204
|
+
* This matters because {@link obbPenetration} reports the minimum
|
|
310
205
|
* TRANSLATION distance to separate the pair, which for this shape is
|
|
311
206
|
* dominated by the piercing member's own extent along the piercing axis, not
|
|
312
207
|
* by how much material it actually crossed (review: #2536 — a 2 m duct
|
|
@@ -315,7 +210,7 @@ function piercesAlong(p, q, centerDelta) {
|
|
|
315
210
|
*
|
|
316
211
|
* Tests containment against EACH box's own axes independently (via
|
|
317
212
|
* {@link piercesAlong}'s general per-axis projection, the same projection
|
|
318
|
-
* {@link
|
|
213
|
+
* {@link obbPenetration} already computes for its 15 SAT candidates) —
|
|
319
214
|
* unlike an earlier version restricted to a frame shared by both boxes'
|
|
320
215
|
* axes up to sign, this also catches a member piercing through at a generic
|
|
321
216
|
* relative rotation (e.g. a duct crossing a wall at 15 degrees, review:
|