@ifc-lite/clash 1.7.0 → 1.8.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/dist/analysis.d.ts +10 -1
- package/dist/analysis.d.ts.map +1 -1
- package/dist/analysis.js +20 -0
- package/dist/analysis.js.map +1 -1
- package/dist/contact/narrow-phase.d.ts +3 -2
- package/dist/contact/narrow-phase.d.ts.map +1 -1
- package/dist/contact/narrow-phase.js +32 -14
- package/dist/contact/narrow-phase.js.map +1 -1
- package/dist/contact/tri-tri.d.ts +33 -7
- package/dist/contact/tri-tri.d.ts.map +1 -1
- package/dist/contact/tri-tri.js +37 -14
- package/dist/contact/tri-tri.js.map +1 -1
- package/dist/duplicate-metric.d.ts +26 -8
- package/dist/duplicate-metric.d.ts.map +1 -1
- package/dist/duplicate-metric.js +26 -8
- package/dist/duplicate-metric.js.map +1 -1
- package/dist/duplicates.d.ts +9 -0
- package/dist/duplicates.d.ts.map +1 -1
- package/dist/duplicates.js +53 -18
- package/dist/duplicates.js.map +1 -1
- package/dist/engine-ts/depth.d.ts +99 -0
- package/dist/engine-ts/depth.d.ts.map +1 -0
- package/dist/engine-ts/depth.js +172 -0
- package/dist/engine-ts/depth.js.map +1 -0
- package/dist/engine-ts/kernel.d.ts +3 -1
- package/dist/engine-ts/kernel.d.ts.map +1 -1
- package/dist/engine-ts/narrow.d.ts +7 -1
- package/dist/engine-ts/narrow.d.ts.map +1 -1
- package/dist/engine-ts/narrow.js +53 -95
- package/dist/engine-ts/narrow.js.map +1 -1
- package/dist/engine-ts/obb.d.ts +116 -0
- package/dist/engine-ts/obb.d.ts.map +1 -0
- package/dist/engine-ts/obb.js +331 -0
- package/dist/engine-ts/obb.js.map +1 -0
- package/dist/engine-ts/orchestrator.d.ts.map +1 -1
- package/dist/engine-ts/orchestrator.js +3 -13
- package/dist/engine-ts/orchestrator.js.map +1 -1
- package/dist/engine-ts/tri-mesh.d.ts +84 -22
- package/dist/engine-ts/tri-mesh.d.ts.map +1 -1
- package/dist/engine-ts/tri-mesh.js +151 -48
- 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 +7 -0
- package/dist/engine-wasm/wasm-kernel.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/math/aabb.d.ts +10 -1
- package/dist/math/aabb.d.ts.map +1 -1
- package/dist/math/aabb.js +33 -13
- package/dist/math/aabb.js.map +1 -1
- package/dist/triage.d.ts.map +1 -1
- package/dist/triage.js +11 -3
- package/dist/triage.js.map +1 -1
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
package/dist/duplicates.js
CHANGED
|
@@ -34,6 +34,7 @@ import { center, overlapBounds } from './math/aabb.js';
|
|
|
34
34
|
import { boxDistance, boxesTouch, minExtent, similarity } from './duplicate-metric.js';
|
|
35
35
|
import { sameShape, shapeSignature } from './shape-signature.js';
|
|
36
36
|
import { isExcluded, qualifiedKey } from './exclude.js';
|
|
37
|
+
import { summarizeClashes } from './analysis.js';
|
|
37
38
|
const DEFAULTS = {
|
|
38
39
|
positionTolerance: 0.01,
|
|
39
40
|
exactTolerance: 0.001,
|
|
@@ -51,18 +52,6 @@ export const DUPLICATES_RULE = {
|
|
|
51
52
|
function toRef(el) {
|
|
52
53
|
return { key: el.key, ref: el.ref, model: el.model, tag: el.tag, name: el.name };
|
|
53
54
|
}
|
|
54
|
-
function buildSummary(clashes) {
|
|
55
|
-
const byRule = {};
|
|
56
|
-
const byTypePair = {};
|
|
57
|
-
const bySeverity = { critical: 0, major: 0, minor: 0, info: 0 };
|
|
58
|
-
for (const c of clashes) {
|
|
59
|
-
byRule[c.rule] = (byRule[c.rule] ?? 0) + 1;
|
|
60
|
-
const pair = [c.a.tag, c.b.tag].sort().join(' vs ');
|
|
61
|
-
byTypePair[pair] = (byTypePair[pair] ?? 0) + 1;
|
|
62
|
-
bySeverity[c.severity] += 1;
|
|
63
|
-
}
|
|
64
|
-
return { total: clashes.length, byRule, byTypePair, bySeverity };
|
|
65
|
-
}
|
|
66
55
|
/**
|
|
67
56
|
* Find duplicate / fully-overlapping elements. Returns a {@link ClashResult}
|
|
68
57
|
* where each clash is a near-coincident pair. `settings.tolerance` is
|
|
@@ -233,7 +222,23 @@ export function findDuplicates(elements, options = {}) {
|
|
|
233
222
|
if (!boxesTouch(elA.bounds, elB.bounds))
|
|
234
223
|
return;
|
|
235
224
|
const dist = boxDistance(elA.bounds, elB.bounds);
|
|
236
|
-
|
|
225
|
+
// Written as an acceptance (`!(dist <= tol)`), not a rejection
|
|
226
|
+
// (`dist > tol`), so a non-comparable distance abstains instead of
|
|
227
|
+
// asserting a pair. NaN fails every comparison, so bounds carrying NaN
|
|
228
|
+
// pass `boxesTouch` (its own comparisons are false too) and would fall
|
|
229
|
+
// through a `>` rejection and be reported as coincident with elements
|
|
230
|
+
// hundreds of metres away.
|
|
231
|
+
//
|
|
232
|
+
// The deprecated `iouThreshold` branch above is NOT a model for this: it
|
|
233
|
+
// is a rejection (`sim < iouThreshold`), and it happens to abstain on two
|
|
234
|
+
// NaN boxes only because `similarity` clamps them to 0 rather than
|
|
235
|
+
// returning NaN. It does not abstain in general — against a degenerate
|
|
236
|
+
// (zero-volume) element it takes the `aabbApproxEqual` fallback, whose
|
|
237
|
+
// per-axis comparisons are all false against NaN, so it returns 1 and
|
|
238
|
+
// reports the pair even at the default 0.9; and at `iouThreshold` 0 the
|
|
239
|
+
// rejection is false for every pair. That branch is deprecated and
|
|
240
|
+
// unchanged here; the two gates do not agree on non-finite bounds.
|
|
241
|
+
if (!(dist <= positionTolerance))
|
|
237
242
|
return;
|
|
238
243
|
exact = dist <= exactTolerance;
|
|
239
244
|
}
|
|
@@ -276,7 +281,10 @@ export function findDuplicates(elements, options = {}) {
|
|
|
276
281
|
status: 'hard',
|
|
277
282
|
// Coincident solids fully embed each other; report the embedded depth so
|
|
278
283
|
// they read as real overlaps (not zero-distance contacts) and sort first.
|
|
284
|
+
// This is a box dimension, not a mesh measurement, so it is labelled the
|
|
285
|
+
// same as the narrow-phase AABB fallback.
|
|
279
286
|
distance: -Math.max(0, minExtent(bounds)),
|
|
287
|
+
distanceKind: 'estimate',
|
|
280
288
|
point: center(bounds),
|
|
281
289
|
bounds,
|
|
282
290
|
severity,
|
|
@@ -287,9 +295,15 @@ export function findDuplicates(elements, options = {}) {
|
|
|
287
295
|
// objects offset by a few metres (still inside a metre-scale tolerance) are
|
|
288
296
|
// never skipped just because many small elements shrank an average cell size.
|
|
289
297
|
// Sweep along the axis with the widest spread of box minima so the active set
|
|
290
|
-
// (and thus the comparison count) stays small. Eviction
|
|
291
|
-
//
|
|
292
|
-
// that does not touch is rejected by
|
|
298
|
+
// (and thus the comparison count) stays small. Eviction drops only boxes that
|
|
299
|
+
// no longer touch on `axis`, which is lossless for the DEFAULT gate — a pair
|
|
300
|
+
// that does not touch is rejected by `boxesTouch` anyway. It is NOT lossless
|
|
301
|
+
// for the deprecated `iouThreshold` branch: `similarity`'s degenerate fallback
|
|
302
|
+
// matches disjoint boxes that are within `tol` per axis, so in legacy mode the
|
|
303
|
+
// sweep can evict a pair that gate would have reported, and whether it does
|
|
304
|
+
// depends on which axis has the widest spread of minima — i.e. on the rest of
|
|
305
|
+
// the model. That axis-dependence predates the distance gate (the sweep is
|
|
306
|
+
// unchanged), so `iouThreshold` still restores the pre-1.7 gate as documented.
|
|
293
307
|
let axis = 0;
|
|
294
308
|
let bestSpread = -Infinity;
|
|
295
309
|
for (let a = 0; a < 3; a += 1) {
|
|
@@ -308,7 +322,28 @@ export function findDuplicates(elements, options = {}) {
|
|
|
308
322
|
axis = a;
|
|
309
323
|
}
|
|
310
324
|
}
|
|
311
|
-
|
|
325
|
+
// The sweep key must be a TOTAL order, so it is compared, never subtracted.
|
|
326
|
+
// `a - b` returns NaN for any pair involving a non-finite minimum — NaN bounds
|
|
327
|
+
// from a direct SDK caller, and `+Infinity` from `fromPositions` when no vertex
|
|
328
|
+
// on an axis was finite (it returns the box inverted). A comparator that
|
|
329
|
+
// answers NaN violates the contract `Array.prototype.sort` requires, and V8's
|
|
330
|
+
// TimSort then merges runs against that answer and emits an arbitrary
|
|
331
|
+
// permutation of the WHOLE array: the sweep's eviction sees minima going
|
|
332
|
+
// backwards, drops boxes that are still live, and real duplicates elsewhere in
|
|
333
|
+
// the model silently disappear. One unjudgeable element must cost only itself.
|
|
334
|
+
// Non-finite minima sort last, after every finite one, which is what the gate
|
|
335
|
+
// already does with them — `consider` abstains on a distance it cannot
|
|
336
|
+
// compare, so they contribute nothing wherever they sit, and putting them at
|
|
337
|
+
// the end keeps them out of the active set for the whole finite sweep.
|
|
338
|
+
const sweepKey = (i) => {
|
|
339
|
+
const v = elements[i].bounds.min[axis];
|
|
340
|
+
return Number.isFinite(v) ? v : Number.POSITIVE_INFINITY;
|
|
341
|
+
};
|
|
342
|
+
const order = elements.map((_, i) => i).sort((x, y) => {
|
|
343
|
+
const kx = sweepKey(x);
|
|
344
|
+
const ky = sweepKey(y);
|
|
345
|
+
return kx < ky ? -1 : kx > ky ? 1 : 0;
|
|
346
|
+
});
|
|
312
347
|
// `active` holds indices whose box still extends past the current box's start
|
|
313
348
|
// on `axis`; only those can overlap, so we compare against just them.
|
|
314
349
|
const active = [];
|
|
@@ -328,7 +363,7 @@ export function findDuplicates(elements, options = {}) {
|
|
|
328
363
|
clashes.sort((x, y) => (x.id < y.id ? -1 : x.id > y.id ? 1 : 0));
|
|
329
364
|
return {
|
|
330
365
|
clashes,
|
|
331
|
-
summary:
|
|
366
|
+
summary: summarizeClashes(clashes),
|
|
332
367
|
rulesRun: [DUPLICATES_RULE],
|
|
333
368
|
ruleCoverage: [{ rule: DUPLICATES_RULE.id, matchedA: elements.length, matchedB: null }],
|
|
334
369
|
settings: { tolerance: positionTolerance, excludeVoidsAndHosts: exclusions != null },
|
package/dist/duplicates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicates.js","sourceRoot":"","sources":["../src/duplicates.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACvF,OAAO,EAAE,SAAS,EAAE,cAAc,EAAuB,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"duplicates.js","sourceRoot":"","sources":["../src/duplicates.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Depth measurement and the f32-precision floor for the narrow phase
|
|
3
|
+
* (`narrow.ts`). Split out to keep `narrow.ts` under the ~400-line module
|
|
4
|
+
* rule; mirrors `rust/clash/src/depth.rs` structurally so the two kernels
|
|
5
|
+
* stay easy to diff.
|
|
6
|
+
*/
|
|
7
|
+
import type { AABB, ClashElement, ClashRule, Vec3 } from '../types.js';
|
|
8
|
+
import type { TriMesh } from './tri-mesh.js';
|
|
9
|
+
import type { NarrowResult } from './narrow.js';
|
|
10
|
+
/**
|
|
11
|
+
* Exact box-box penetration when BOTH meshes are (within tolerance)
|
|
12
|
+
* rectangular boxes, else `null`. `mtd` is the only source of a `'mesh'`
|
|
13
|
+
* label for a distance that used to come from `TriMesh.maxPenetrationInto` —
|
|
14
|
+
* a nearest-crossing-vertex sampling probe that converges to 0 under
|
|
15
|
+
* retessellation instead of to the true depth (see `obb.ts`, `obb.test.ts`).
|
|
16
|
+
*
|
|
17
|
+
* `through` flags a THROUGH-PENETRATION pair — a thin member piercing clean
|
|
18
|
+
* through the other, e.g. a duct through a wall. There, the minimum-
|
|
19
|
+
* translation-distance `obb.ts` computes is dominated by the piercing
|
|
20
|
+
* member's own extent along the shared axis, not by the material actually
|
|
21
|
+
* crossed (review: #2536, reproduced a 5.5x inflation on exactly this
|
|
22
|
+
* shape), so `depthClashResult` reports the caller's AABB estimate for that
|
|
23
|
+
* shape — matching what `main` did before the box-exact metric existed, and
|
|
24
|
+
* honest about not being a measurement. The MTD is still returned (not
|
|
25
|
+
* discarded here) because the f32 floor must see it: which number gets
|
|
26
|
+
* REPORTED is a separate, later decision from whether the pair is
|
|
27
|
+
* measurable at all (see `depthClashResult`).
|
|
28
|
+
*/
|
|
29
|
+
export interface BoxPenetration {
|
|
30
|
+
/** Exact box-box minimum-translation depth (Gottschalk 15-axis SAT). */
|
|
31
|
+
mtd: number;
|
|
32
|
+
/** The MTD is inflated by the piercing member's own extent; report the
|
|
33
|
+
* AABB estimate instead (see `isThroughPenetration`). */
|
|
34
|
+
through: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare function boxPenetration(small: TriMesh, large: TriMesh): BoxPenetration | null;
|
|
37
|
+
/**
|
|
38
|
+
* Deepest penetration of `mesh`'s crossing-triangle VERTICES into `other`:
|
|
39
|
+
* the maximum distance-to-surface of `other` over the vertices of the
|
|
40
|
+
* triangles flagged in `crossFlags` (the pairs the narrow phase saw
|
|
41
|
+
* genuinely crossing `other`) that lie inside `other`. Each vertex is
|
|
42
|
+
* visited once (deduped by vertex index, in index order — bit-identical to
|
|
43
|
+
* the Rust `crossing_vertex_penetration`). Returns 0 when no flagged vertex
|
|
44
|
+
* is inside.
|
|
45
|
+
*
|
|
46
|
+
* This is NOT a depth metric and must never be reported as one — it is the
|
|
47
|
+
* sampling probe PR #2536 was held over (`maxPenetrationInto`): its value is
|
|
48
|
+
* an O(edge length) artifact that converges to 0 under retessellation
|
|
49
|
+
* instead of to the true depth. It survives with exactly one client: the
|
|
50
|
+
* f32 noise-floor gate for a CONTAINED pair (`depthClashResult`), where the
|
|
51
|
+
* question is not "how deep?" but "is any mesh-level penetration measurably
|
|
52
|
+
* above the floor at all?" — sub-floor here means every crossing vertex sits
|
|
53
|
+
* within f32 rounding noise of the other surface, i.e. surfaces authored
|
|
54
|
+
* flush, which no amount of retessellation turns into a real overlap. For
|
|
55
|
+
* that yes/no question the probe's underestimation is harmless:
|
|
56
|
+
* underestimating can only keep a pair BELOW the floor, and the floor is
|
|
57
|
+
* the very thing being tested.
|
|
58
|
+
*/
|
|
59
|
+
export declare function crossingVertexPenetration(mesh: TriMesh, other: TriMesh, crossFlags: Uint8Array): number;
|
|
60
|
+
/**
|
|
61
|
+
* Turns the candidate penetration depths into the final `(status,
|
|
62
|
+
* distanceKind, distance)` triple. This is the ONLY place in the narrow
|
|
63
|
+
* phase allowed to build a `'mesh'`- or `'estimate'`-labelled `hard` result
|
|
64
|
+
* off a depth number — every branch in `narrow.ts` that can label a result
|
|
65
|
+
* `'mesh'` off `boxPenetration` (or its AABB-estimate fallback) MUST route
|
|
66
|
+
* through here rather than building the `NarrowResult` literal itself. That
|
|
67
|
+
* is what makes the f32 floor apply to all of them, and what enforces its
|
|
68
|
+
* precedence.
|
|
69
|
+
*
|
|
70
|
+
* THE FLOOR WINS (#2536 rebase decision): a pair below the f32 noise floor
|
|
71
|
+
* is `touch` regardless of how its depth was derived — at that magnitude the
|
|
72
|
+
* number is not measurable either way — so the floor is tested against EVERY
|
|
73
|
+
* candidate depth the pair has, not against whichever one the estimate-vs-
|
|
74
|
+
* mesh selection would report. Three candidates exist:
|
|
75
|
+
*
|
|
76
|
+
* - the AABB `estimate` (always present);
|
|
77
|
+
* - the box MTD, when both elements are certified boxes (`box`);
|
|
78
|
+
* - the crossing-vertex penetration, for a CONTAINED pair with a crossing
|
|
79
|
+
* vertex inside the other solid (`meshEvidence`) — evidence for this gate
|
|
80
|
+
* only, never a reported depth (see `crossingVertexPenetration`).
|
|
81
|
+
*
|
|
82
|
+
* The pair is `hard` only when the SMALLEST available candidate clears the
|
|
83
|
+
* floor. That is what makes the floor unreachable by depth-source selection:
|
|
84
|
+
* a sub-floor box MTD cannot be promoted by the through-penetration guard
|
|
85
|
+
* swapping in a larger AABB estimate; a sub-floor crossing-vertex
|
|
86
|
+
* penetration on a contained pair (surfaces authored flush — the eight
|
|
87
|
+
* Infra-Bridge pairs that moved #2594's 50-hard-clash pin to 58 when this
|
|
88
|
+
* PR's depth rework replaced their noise-scale mesh depth with the
|
|
89
|
+
* fabricated 4 m AABB estimate) cannot be promoted by that estimate; and a
|
|
90
|
+
* sub-floor AABB estimate cannot be promoted by a larger MTD (a through-
|
|
91
|
+
* penetration far from the origin, where the MTD is inflated by the
|
|
92
|
+
* piercing member's own extent). Only a pair already above the floor
|
|
93
|
+
* reaches the selection below, which then merely picks WHICH above-floor
|
|
94
|
+
* reportable number is used and how it is labelled — so a `hard` result's
|
|
95
|
+
* distance clears the floor by construction, whichever quantity it came
|
|
96
|
+
* from.
|
|
97
|
+
*/
|
|
98
|
+
export declare function depthClashResult(box: BoxPenetration | null, estimate: number, meshEvidence: number | null, elA: ClashElement, elB: ClashElement, rule: ClashRule, point: Vec3, bounds: AABB): NarrowResult | null;
|
|
99
|
+
//# sourceMappingURL=depth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"depth.d.ts","sourceRoot":"","sources":["../../src/engine-ts/depth.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,cAAc;IAC7B,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ;6DACyD;IACzD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,IAAI,CAOpF;AAsDD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG,MAAM,CAevG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,cAAc,GAAG,IAAI,EAC1B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GAAG,IAAI,EAC3B,GAAG,EAAE,YAAY,EACjB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,IAAI,EACX,MAAM,EAAE,IAAI,GACX,YAAY,GAAG,IAAI,CAsBrB"}
|
|
@@ -0,0 +1,172 @@
|
|
|
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 { isThroughPenetration, obbPenetrationDepth } from './obb.js';
|
|
5
|
+
export function boxPenetration(small, large) {
|
|
6
|
+
const oa = small.getObb();
|
|
7
|
+
const ob = large.getObb();
|
|
8
|
+
if (!oa || !ob)
|
|
9
|
+
return null;
|
|
10
|
+
const mtd = obbPenetrationDepth(oa, ob);
|
|
11
|
+
if (mtd == null)
|
|
12
|
+
return null;
|
|
13
|
+
return { mtd, through: isThroughPenetration(oa, ob) };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* f32-ULP scale factor for a "worst-case" single-precision coordinate: for a
|
|
17
|
+
* value with magnitude in `[2, 4)` the true float32 ULP is `2^-22`, and for
|
|
18
|
+
* larger magnitudes the ULP only grows. Same `2^-22` term (and reasoning) as
|
|
19
|
+
* `near_band_from_extent` in `rust/geometry/src/kernel/mesh_bridge.rs` — see
|
|
20
|
+
* that function's doc for the derivation; kept here rather than shared
|
|
21
|
+
* because the two live in different language runtimes.
|
|
22
|
+
*/
|
|
23
|
+
const F32_ULP_SCALE = 1 / 4_194_304; // 2^-22
|
|
24
|
+
/**
|
|
25
|
+
* Penetration-depth floor below which a computed overlap cannot be
|
|
26
|
+
* distinguished from float32 rounding noise, scaled to the pair's own
|
|
27
|
+
* coordinate magnitude (not a fixed constant — infra models sit far from the
|
|
28
|
+
* origin, where a fixed epsilon would be far too tight, and small models sit
|
|
29
|
+
* near it, where a fixed epsilon would be far too loose).
|
|
30
|
+
*
|
|
31
|
+
* `rust/clash/src/tri_mesh.rs` ingests geometry from f32 buffers and stores/
|
|
32
|
+
* queries it in f64, so f64 arithmetic cannot recover precision the source
|
|
33
|
+
* data never had: two surfaces authored to be flush round to adjacent f32
|
|
34
|
+
* values, and the resulting "penetration" is bit-noise at the ULP of
|
|
35
|
+
* whichever operand coordinate is largest, not a measured overlap. Extent is
|
|
36
|
+
* the max abs coordinate over both elements' AABBs (world space, matching
|
|
37
|
+
* `near_band_from_extent`'s use of the actual compared coordinates) with a
|
|
38
|
+
* floor of 1.0 so a model near the origin still gets the single-unit ULP,
|
|
39
|
+
* not zero.
|
|
40
|
+
*
|
|
41
|
+
* The floor grows linearly with the pair's distance from the origin — that
|
|
42
|
+
* is the point, since f32 precision itself degrades the same way. The
|
|
43
|
+
* consequence: on a georeferenced model whose elements sit at real map
|
|
44
|
+
* coordinates (hundreds of kilometres out, which real IFC files do), the
|
|
45
|
+
* floor reaches decimetre scale, and a genuine clash below that threshold
|
|
46
|
+
* reclassifies as `touch`. That is not a bug in this function — at those
|
|
47
|
+
* magnitudes f32 genuinely cannot represent a finer distinction, so the
|
|
48
|
+
* "penetration" is not reliably measurable either way — but it means the
|
|
49
|
+
* floor tracks a limitation of the source data, not of clash detection.
|
|
50
|
+
* The fix for a model in that position is ingesting geometry closer to the
|
|
51
|
+
* origin (or in f64), not lowering this floor.
|
|
52
|
+
*/
|
|
53
|
+
function precisionFloor(elA, elB) {
|
|
54
|
+
let extent = 1.0;
|
|
55
|
+
for (const b of [elA.bounds, elB.bounds]) {
|
|
56
|
+
for (const v of [b.min, b.max]) {
|
|
57
|
+
for (const c of v) {
|
|
58
|
+
const a = Math.abs(c);
|
|
59
|
+
if (a > extent)
|
|
60
|
+
extent = a;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return extent * F32_ULP_SCALE;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Deepest penetration of `mesh`'s crossing-triangle VERTICES into `other`:
|
|
68
|
+
* the maximum distance-to-surface of `other` over the vertices of the
|
|
69
|
+
* triangles flagged in `crossFlags` (the pairs the narrow phase saw
|
|
70
|
+
* genuinely crossing `other`) that lie inside `other`. Each vertex is
|
|
71
|
+
* visited once (deduped by vertex index, in index order — bit-identical to
|
|
72
|
+
* the Rust `crossing_vertex_penetration`). Returns 0 when no flagged vertex
|
|
73
|
+
* is inside.
|
|
74
|
+
*
|
|
75
|
+
* This is NOT a depth metric and must never be reported as one — it is the
|
|
76
|
+
* sampling probe PR #2536 was held over (`maxPenetrationInto`): its value is
|
|
77
|
+
* an O(edge length) artifact that converges to 0 under retessellation
|
|
78
|
+
* instead of to the true depth. It survives with exactly one client: the
|
|
79
|
+
* f32 noise-floor gate for a CONTAINED pair (`depthClashResult`), where the
|
|
80
|
+
* question is not "how deep?" but "is any mesh-level penetration measurably
|
|
81
|
+
* above the floor at all?" — sub-floor here means every crossing vertex sits
|
|
82
|
+
* within f32 rounding noise of the other surface, i.e. surfaces authored
|
|
83
|
+
* flush, which no amount of retessellation turns into a real overlap. For
|
|
84
|
+
* that yes/no question the probe's underestimation is harmless:
|
|
85
|
+
* underestimating can only keep a pair BELOW the floor, and the floor is
|
|
86
|
+
* the very thing being tested.
|
|
87
|
+
*/
|
|
88
|
+
export function crossingVertexPenetration(mesh, other, crossFlags) {
|
|
89
|
+
const seen = new Uint8Array(mesh.vertexCount());
|
|
90
|
+
let depth = 0;
|
|
91
|
+
for (let t = 0; t < mesh.count; t += 1) {
|
|
92
|
+
if (crossFlags[t] === 0)
|
|
93
|
+
continue;
|
|
94
|
+
for (const vi of mesh.triIndices(t)) {
|
|
95
|
+
if (seen[vi] === 1)
|
|
96
|
+
continue;
|
|
97
|
+
seen[vi] = 1;
|
|
98
|
+
const v = mesh.vertex(vi);
|
|
99
|
+
if (!other.containsPoint(v))
|
|
100
|
+
continue;
|
|
101
|
+
const d = other.distanceToSurface(v);
|
|
102
|
+
if (d > depth)
|
|
103
|
+
depth = d;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return depth;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Turns the candidate penetration depths into the final `(status,
|
|
110
|
+
* distanceKind, distance)` triple. This is the ONLY place in the narrow
|
|
111
|
+
* phase allowed to build a `'mesh'`- or `'estimate'`-labelled `hard` result
|
|
112
|
+
* off a depth number — every branch in `narrow.ts` that can label a result
|
|
113
|
+
* `'mesh'` off `boxPenetration` (or its AABB-estimate fallback) MUST route
|
|
114
|
+
* through here rather than building the `NarrowResult` literal itself. That
|
|
115
|
+
* is what makes the f32 floor apply to all of them, and what enforces its
|
|
116
|
+
* precedence.
|
|
117
|
+
*
|
|
118
|
+
* THE FLOOR WINS (#2536 rebase decision): a pair below the f32 noise floor
|
|
119
|
+
* is `touch` regardless of how its depth was derived — at that magnitude the
|
|
120
|
+
* number is not measurable either way — so the floor is tested against EVERY
|
|
121
|
+
* candidate depth the pair has, not against whichever one the estimate-vs-
|
|
122
|
+
* mesh selection would report. Three candidates exist:
|
|
123
|
+
*
|
|
124
|
+
* - the AABB `estimate` (always present);
|
|
125
|
+
* - the box MTD, when both elements are certified boxes (`box`);
|
|
126
|
+
* - the crossing-vertex penetration, for a CONTAINED pair with a crossing
|
|
127
|
+
* vertex inside the other solid (`meshEvidence`) — evidence for this gate
|
|
128
|
+
* only, never a reported depth (see `crossingVertexPenetration`).
|
|
129
|
+
*
|
|
130
|
+
* The pair is `hard` only when the SMALLEST available candidate clears the
|
|
131
|
+
* floor. That is what makes the floor unreachable by depth-source selection:
|
|
132
|
+
* a sub-floor box MTD cannot be promoted by the through-penetration guard
|
|
133
|
+
* swapping in a larger AABB estimate; a sub-floor crossing-vertex
|
|
134
|
+
* penetration on a contained pair (surfaces authored flush — the eight
|
|
135
|
+
* Infra-Bridge pairs that moved #2594's 50-hard-clash pin to 58 when this
|
|
136
|
+
* PR's depth rework replaced their noise-scale mesh depth with the
|
|
137
|
+
* fabricated 4 m AABB estimate) cannot be promoted by that estimate; and a
|
|
138
|
+
* sub-floor AABB estimate cannot be promoted by a larger MTD (a through-
|
|
139
|
+
* penetration far from the origin, where the MTD is inflated by the
|
|
140
|
+
* piercing member's own extent). Only a pair already above the floor
|
|
141
|
+
* reaches the selection below, which then merely picks WHICH above-floor
|
|
142
|
+
* reportable number is used and how it is labelled — so a `hard` result's
|
|
143
|
+
* distance clears the floor by construction, whichever quantity it came
|
|
144
|
+
* from.
|
|
145
|
+
*/
|
|
146
|
+
export function depthClashResult(box, estimate, meshEvidence, elA, elB, rule, point, bounds) {
|
|
147
|
+
let floorDepth = estimate;
|
|
148
|
+
if (box != null && box.mtd < floorDepth)
|
|
149
|
+
floorDepth = box.mtd;
|
|
150
|
+
if (meshEvidence != null && meshEvidence < floorDepth)
|
|
151
|
+
floorDepth = meshEvidence;
|
|
152
|
+
if (floorDepth <= precisionFloor(elA, elB)) {
|
|
153
|
+
if (!rule.reportTouch)
|
|
154
|
+
return null;
|
|
155
|
+
// distance is exactly 0 here (the classification, not a measurement, is
|
|
156
|
+
// what changed), so `mesh` — consistent with the other exact-distance
|
|
157
|
+
// `touch` result.
|
|
158
|
+
return { status: 'touch', distance: 0, distanceKind: 'mesh', point, bounds };
|
|
159
|
+
}
|
|
160
|
+
// Estimate-vs-mesh selection, reachable only above the floor: the box MTD
|
|
161
|
+
// is certified (`mesh`) unless the pair is a through-penetration, where
|
|
162
|
+
// the AABB estimate is the honest number (see `boxPenetration`).
|
|
163
|
+
const measured = box != null && !box.through;
|
|
164
|
+
return {
|
|
165
|
+
status: 'hard',
|
|
166
|
+
distance: -(measured ? box.mtd : estimate),
|
|
167
|
+
distanceKind: measured ? 'mesh' : 'estimate',
|
|
168
|
+
point,
|
|
169
|
+
bounds,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=depth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"depth.js","sourceRoot":"","sources":["../../src/engine-ts/depth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AABB, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
1
|
+
import type { AABB, ClashDistanceKind, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
2
2
|
/**
|
|
3
3
|
* One detected clash, in kernel terms: a pair of GLOBAL element indices plus the
|
|
4
4
|
* geometric verdict. The orchestrator turns this into a `Clash` (identity,
|
|
@@ -12,6 +12,8 @@ export interface NarrowRecord {
|
|
|
12
12
|
b: number;
|
|
13
13
|
status: ClashStatus;
|
|
14
14
|
distance: number;
|
|
15
|
+
/** Whether `distance` was measured on the meshes or estimated from the AABBs. */
|
|
16
|
+
distanceKind: ClashDistanceKind;
|
|
15
17
|
point: Vec3;
|
|
16
18
|
bounds: AABB;
|
|
17
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/engine-ts/kernel.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/engine-ts/kernel.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEvG;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,CAAC,EAAE,MAAM,CAAC;IACV,uDAAuD;IACvD,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,YAAY,EAAE,iBAAiB,CAAC;IAChC,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,mFAAmF;IACnF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,OAAO,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IACxC;;;;OAIG;IACH,UAAU,CACR,QAAQ,EAAE,YAAY,EAAE,EACxB,MAAM,EAAE,MAAM,EAAE,EAChB,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EACvB,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM;IAChB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,WAAW;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACjD,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC1C,6DAA6D;IAC7D,OAAO,CAAC,IAAI,IAAI,CAAC;CAClB"}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type { AABB, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
1
|
+
import type { AABB, ClashDistanceKind, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
|
|
2
2
|
import type { TriMesh } from './tri-mesh.js';
|
|
3
3
|
export interface NarrowResult {
|
|
4
4
|
status: ClashStatus;
|
|
5
5
|
distance: number;
|
|
6
|
+
/**
|
|
7
|
+
* Whether `distance` was measured on the meshes or estimated from the AABBs.
|
|
8
|
+
* Set on every result, so a caller never has to guess which of the two very
|
|
9
|
+
* different quantities it is holding.
|
|
10
|
+
*/
|
|
11
|
+
distanceKind: ClashDistanceKind;
|
|
6
12
|
point: Vec3;
|
|
7
13
|
bounds: AABB;
|
|
8
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"narrow.d.ts","sourceRoot":"","sources":["../../src/engine-ts/narrow.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"narrow.d.ts","sourceRoot":"","sources":["../../src/engine-ts/narrow.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAKvG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,YAAY,EAAE,iBAAiB,CAAC;IAChC,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;CACd;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,GAChB,YAAY,GAAG,IAAI,CA8PrB"}
|