@ifc-lite/clash 1.1.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/LICENSE +373 -0
- package/README.md +32 -0
- package/dist/adapters/ifcx.d.ts +44 -0
- package/dist/adapters/ifcx.d.ts.map +1 -0
- package/dist/adapters/ifcx.js +198 -0
- package/dist/adapters/ifcx.js.map +1 -0
- package/dist/adapters/step.d.ts +42 -0
- package/dist/adapters/step.d.ts.map +1 -0
- package/dist/adapters/step.js +77 -0
- package/dist/adapters/step.js.map +1 -0
- package/dist/bcf-bridge.d.ts +51 -0
- package/dist/bcf-bridge.d.ts.map +1 -0
- package/dist/bcf-bridge.js +298 -0
- package/dist/bcf-bridge.js.map +1 -0
- package/dist/deterministic-uuid.d.ts +9 -0
- package/dist/deterministic-uuid.d.ts.map +1 -0
- package/dist/deterministic-uuid.js +87 -0
- package/dist/deterministic-uuid.js.map +1 -0
- package/dist/disciplines.d.ts +33 -0
- package/dist/disciplines.d.ts.map +1 -0
- package/dist/disciplines.js +148 -0
- package/dist/disciplines.js.map +1 -0
- package/dist/engine-ts/broad.d.ts +11 -0
- package/dist/engine-ts/broad.d.ts.map +1 -0
- package/dist/engine-ts/broad.js +61 -0
- package/dist/engine-ts/broad.js.map +1 -0
- package/dist/engine-ts/index.d.ts +16 -0
- package/dist/engine-ts/index.d.ts.map +1 -0
- package/dist/engine-ts/index.js +17 -0
- package/dist/engine-ts/index.js.map +1 -0
- package/dist/engine-ts/kernel.d.ts +50 -0
- package/dist/engine-ts/kernel.d.ts.map +1 -0
- package/dist/engine-ts/kernel.js +5 -0
- package/dist/engine-ts/kernel.js.map +1 -0
- package/dist/engine-ts/narrow.d.ts +23 -0
- package/dist/engine-ts/narrow.d.ts.map +1 -0
- package/dist/engine-ts/narrow.js +127 -0
- package/dist/engine-ts/narrow.js.map +1 -0
- package/dist/engine-ts/orchestrator.d.ts +11 -0
- package/dist/engine-ts/orchestrator.d.ts.map +1 -0
- package/dist/engine-ts/orchestrator.js +127 -0
- package/dist/engine-ts/orchestrator.js.map +1 -0
- package/dist/engine-ts/tri-mesh.d.ts +33 -0
- package/dist/engine-ts/tri-mesh.d.ts.map +1 -0
- package/dist/engine-ts/tri-mesh.js +125 -0
- package/dist/engine-ts/tri-mesh.js.map +1 -0
- package/dist/engine-ts/ts-kernel.d.ts +14 -0
- package/dist/engine-ts/ts-kernel.d.ts.map +1 -0
- package/dist/engine-ts/ts-kernel.js +85 -0
- package/dist/engine-ts/ts-kernel.js.map +1 -0
- package/dist/engine-wasm/index.d.ts +21 -0
- package/dist/engine-wasm/index.d.ts.map +1 -0
- package/dist/engine-wasm/index.js +40 -0
- package/dist/engine-wasm/index.js.map +1 -0
- package/dist/engine-wasm/wasm-kernel.d.ts +20 -0
- package/dist/engine-wasm/wasm-kernel.d.ts.map +1 -0
- package/dist/engine-wasm/wasm-kernel.js +106 -0
- package/dist/engine-wasm/wasm-kernel.js.map +1 -0
- package/dist/engine.d.ts +14 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +20 -0
- package/dist/engine.js.map +1 -0
- package/dist/exclude.d.ts +15 -0
- package/dist/exclude.d.ts.map +1 -0
- package/dist/exclude.js +38 -0
- package/dist/exclude.js.map +1 -0
- package/dist/grouping.d.ts +16 -0
- package/dist/grouping.d.ts.map +1 -0
- package/dist/grouping.js +311 -0
- package/dist/grouping.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle.d.ts +41 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +70 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/math/aabb.d.ts +27 -0
- package/dist/math/aabb.d.ts.map +1 -0
- package/dist/math/aabb.js +127 -0
- package/dist/math/aabb.js.map +1 -0
- package/dist/math/triangle-distance.d.ts +29 -0
- package/dist/math/triangle-distance.d.ts.map +1 -0
- package/dist/math/triangle-distance.js +149 -0
- package/dist/math/triangle-distance.js.map +1 -0
- package/dist/math/triangle-intersect.d.ts +13 -0
- package/dist/math/triangle-intersect.d.ts.map +1 -0
- package/dist/math/triangle-intersect.js +55 -0
- package/dist/math/triangle-intersect.js.map +1 -0
- package/dist/math/vec3.d.ts +11 -0
- package/dist/math/vec3.d.ts.map +1 -0
- package/dist/math/vec3.js +38 -0
- package/dist/math/vec3.js.map +1 -0
- package/dist/selectors.d.ts +12 -0
- package/dist/selectors.d.ts.map +1 -0
- package/dist/selectors.js +53 -0
- package/dist/selectors.js.map +1 -0
- package/dist/triage.d.ts +19 -0
- package/dist/triage.d.ts.map +1 -0
- package/dist/triage.js +99 -0
- package/dist/triage.js.map +1 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,127 @@
|
|
|
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 { matchesSelector } from '../selectors.js';
|
|
5
|
+
import { inferClashSeverity } from '../disciplines.js';
|
|
6
|
+
import { isExcluded, qualifiedKey } from '../exclude.js';
|
|
7
|
+
import { DEFAULT_CLASH_SETTINGS, } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Backend-agnostic clash orchestration: selection, exclusions, severity, stable
|
|
10
|
+
* identity, dedup, ordering and summary. The geometry (broad + narrow phase) is
|
|
11
|
+
* delegated to a `ClashKernel` (TypeScript or Rust/WASM), so swapping backends
|
|
12
|
+
* changes nothing observable except speed — which is exactly what makes the two
|
|
13
|
+
* engines differentially comparable.
|
|
14
|
+
*/
|
|
15
|
+
export async function runClash(elements, rules, settings, kernel) {
|
|
16
|
+
const tolerance = settings.tolerance ?? DEFAULT_CLASH_SETTINGS.tolerance;
|
|
17
|
+
const excludeVoidsAndHosts = settings.excludeVoidsAndHosts ?? DEFAULT_CLASH_SETTINGS.excludeVoidsAndHosts;
|
|
18
|
+
const exclusions = excludeVoidsAndHosts ? settings.exclusions : undefined;
|
|
19
|
+
const maxPairs = settings.maxCandidatePairs ?? Infinity;
|
|
20
|
+
const clashes = [];
|
|
21
|
+
const seen = new Set();
|
|
22
|
+
let droppedPairs = 0;
|
|
23
|
+
// A single GLOBAL candidate-pair budget across the whole run (not per rule),
|
|
24
|
+
// so `maxCandidatePairs` is an honest end-to-end guardrail.
|
|
25
|
+
let remaining = maxPairs;
|
|
26
|
+
// `finally` guarantees the kernel is disposed even on abort / kernel error /
|
|
27
|
+
// a throw inside prepare() — otherwise a `WasmKernel`'s `ClashSession` (and
|
|
28
|
+
// its arenas) would leak.
|
|
29
|
+
try {
|
|
30
|
+
kernel.prepare(elements);
|
|
31
|
+
for (const rule of rules) {
|
|
32
|
+
if (settings.signal?.aborted) {
|
|
33
|
+
throw new DOMException('Clash run aborted', 'AbortError');
|
|
34
|
+
}
|
|
35
|
+
const groupA = [];
|
|
36
|
+
const groupB = rule.b ? [] : null;
|
|
37
|
+
for (let i = 0; i < elements.length; i += 1) {
|
|
38
|
+
const tag = elements[i].tag;
|
|
39
|
+
if (matchesSelector(tag, rule.a))
|
|
40
|
+
groupA.push(i);
|
|
41
|
+
if (groupB && matchesSelector(tag, rule.b))
|
|
42
|
+
groupB.push(i);
|
|
43
|
+
}
|
|
44
|
+
const ruleTolerance = rule.tolerance ?? tolerance;
|
|
45
|
+
settings.onProgress?.({ phase: 'broad', rule: rule.id, done: 0, total: 0 });
|
|
46
|
+
const { records, candidatesProcessed, candidatesDropped } = await kernel.detectRule(elements, groupA, groupB, rule, ruleTolerance, remaining, settings.signal, settings.onProgress
|
|
47
|
+
? (done, total) => settings.onProgress({ phase: 'narrow', rule: rule.id, done, total })
|
|
48
|
+
: undefined);
|
|
49
|
+
remaining = Math.max(0, remaining - candidatesProcessed);
|
|
50
|
+
droppedPairs += candidatesDropped;
|
|
51
|
+
for (const rec of records) {
|
|
52
|
+
if (settings.signal?.aborted) {
|
|
53
|
+
throw new DOMException('Clash run aborted', 'AbortError');
|
|
54
|
+
}
|
|
55
|
+
const elA = elements[rec.a];
|
|
56
|
+
const elB = elements[rec.b];
|
|
57
|
+
// Same durable key + model = one entity split across geometry sub-prims
|
|
58
|
+
// (common in IFC5/USD), not a self-clash. Filter here so every kernel —
|
|
59
|
+
// TS or WASM, regardless of how its broad phase dedups — behaves alike.
|
|
60
|
+
if (elA.key === elB.key && elA.model === elB.model)
|
|
61
|
+
continue;
|
|
62
|
+
if (exclusions &&
|
|
63
|
+
isExcluded(exclusions, qualifiedKey(elA.model, elA.key), qualifiedKey(elB.model, elB.key))) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const id = clashId(elA, elB, rule.id);
|
|
67
|
+
if (seen.has(id))
|
|
68
|
+
continue;
|
|
69
|
+
seen.add(id);
|
|
70
|
+
clashes.push({
|
|
71
|
+
id,
|
|
72
|
+
a: toRef(elA),
|
|
73
|
+
b: toRef(elB),
|
|
74
|
+
rule: rule.id,
|
|
75
|
+
status: rec.status,
|
|
76
|
+
distance: rec.distance,
|
|
77
|
+
point: rec.point,
|
|
78
|
+
bounds: rec.bounds,
|
|
79
|
+
severity: rule.severity ?? inferClashSeverity(elA.tag, elB.tag),
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
kernel.dispose?.();
|
|
86
|
+
}
|
|
87
|
+
clashes.sort(byKeyThenRule);
|
|
88
|
+
const result = {
|
|
89
|
+
clashes,
|
|
90
|
+
summary: buildSummary(clashes),
|
|
91
|
+
rulesRun: rules,
|
|
92
|
+
settings: { tolerance, excludeVoidsAndHosts },
|
|
93
|
+
};
|
|
94
|
+
if (droppedPairs > 0) {
|
|
95
|
+
result.truncated = { reason: 'maxCandidatePairs', droppedPairs };
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
function toRef(el) {
|
|
100
|
+
return { key: el.key, ref: el.ref, model: el.model, tag: el.tag, name: el.name };
|
|
101
|
+
}
|
|
102
|
+
/** Stable, deterministic clash identity from the two durable keys + rule. */
|
|
103
|
+
function clashId(a, b, ruleId) {
|
|
104
|
+
const ka = `${a.model} ${a.key}`;
|
|
105
|
+
const kb = `${b.model} ${b.key}`;
|
|
106
|
+
const [lo, hi] = ka < kb ? [ka, kb] : [kb, ka];
|
|
107
|
+
return `${ruleId} ${lo} ${hi}`;
|
|
108
|
+
}
|
|
109
|
+
function byKeyThenRule(x, y) {
|
|
110
|
+
return cmp(x.a.key, y.a.key) || cmp(x.b.key, y.b.key) || cmp(x.rule, y.rule);
|
|
111
|
+
}
|
|
112
|
+
function cmp(a, b) {
|
|
113
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
114
|
+
}
|
|
115
|
+
function buildSummary(clashes) {
|
|
116
|
+
const byRule = {};
|
|
117
|
+
const byTypePair = {};
|
|
118
|
+
const bySeverity = { critical: 0, major: 0, minor: 0, info: 0 };
|
|
119
|
+
for (const c of clashes) {
|
|
120
|
+
byRule[c.rule] = (byRule[c.rule] ?? 0) + 1;
|
|
121
|
+
const pair = [c.a.tag, c.b.tag].sort().join(' vs ');
|
|
122
|
+
byTypePair[pair] = (byTypePair[pair] ?? 0) + 1;
|
|
123
|
+
bySeverity[c.severity] += 1;
|
|
124
|
+
}
|
|
125
|
+
return { total: clashes.length, byRule, byTypePair, bySeverity };
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=orchestrator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../../src/engine-ts/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type AABB } from '@ifc-lite/spatial';
|
|
2
|
+
import type { Mat4, Vec3 } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* A triangle mesh with a per-triangle BVH for narrow-phase queries. Built once
|
|
5
|
+
* per element per run and cached by the engine, so each element's triangle
|
|
6
|
+
* index is paid for at most once even when it appears in several rules.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TriMesh {
|
|
9
|
+
readonly count: number;
|
|
10
|
+
private readonly positions;
|
|
11
|
+
private readonly indices;
|
|
12
|
+
private readonly transform?;
|
|
13
|
+
private readonly bvh;
|
|
14
|
+
constructor(positions: Float32Array, indices: Uint32Array, transform?: Mat4);
|
|
15
|
+
/** World-space vertex `i` (applies the element transform if present). */
|
|
16
|
+
vertex(i: number): Vec3;
|
|
17
|
+
/** The three world-space vertices of triangle `t`. */
|
|
18
|
+
tri(t: number): [Vec3, Vec3, Vec3];
|
|
19
|
+
triBounds(t: number): AABB;
|
|
20
|
+
/** Triangle indices whose bounds intersect `bounds`. */
|
|
21
|
+
queryTris(bounds: AABB): number[];
|
|
22
|
+
/**
|
|
23
|
+
* True when `p` is inside this closed mesh. Casts a fixed-direction ray and
|
|
24
|
+
* counts forward crossings against every triangle (Möller–Trumbore,
|
|
25
|
+
* double-sided so winding doesn't matter); an odd count means inside.
|
|
26
|
+
*
|
|
27
|
+
* Iterates all triangles in index order — deliberately NOT the BVH — so the
|
|
28
|
+
* result is bit-identical to the Rust `contains_point`. Only invoked in the
|
|
29
|
+
* rare enclosed-solid branch of the narrow phase, so the O(n) cost is fine.
|
|
30
|
+
*/
|
|
31
|
+
containsPoint(p: Vec3): boolean;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=tri-mesh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tri-mesh.d.ts","sourceRoot":"","sources":["../../src/engine-ts/tri-mesh.ts"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,IAAI,EAAuB,MAAM,mBAAmB,CAAC;AACxE,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAc9C;;;;GAIG;AACH,qBAAa,OAAO;IAClB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAO;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;gBAEd,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,IAAI;IAa3E,yEAAyE;IACzE,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAqBvB,sDAAsD;IACtD,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;IASlC,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAgB1B,wDAAwD;IACxD,SAAS,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,EAAE;IAKjC;;;;;;;;OAQG;IACH,aAAa,CAAC,CAAC,EAAE,IAAI,GAAG,OAAO;CAqBhC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
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 { BVH } from '@ifc-lite/spatial';
|
|
5
|
+
import { sub, cross, dot } from '../math/vec3.js';
|
|
6
|
+
/**
|
|
7
|
+
* Fixed ray direction for point-in-solid tests: `normalize([1, √3, √5])`.
|
|
8
|
+
* Deliberately NON-axis-aligned so the ray never grazes the edges/vertices of
|
|
9
|
+
* axis-aligned boxes (which would double-count crossings). Written as exact
|
|
10
|
+
* IEEE-754 literals (not computed via `normalize()`) so the Rust kernel uses
|
|
11
|
+
* byte-identical components — `|RAY_DIR| === 1` exactly.
|
|
12
|
+
*/
|
|
13
|
+
const RAY_DIR = [0.3333333333333333, 0.5773502691896257, 0.7453559924999299];
|
|
14
|
+
/** Parallel-reject + forward-crossing threshold. Same literal in the Rust kernel. */
|
|
15
|
+
const RAY_EPS = 1e-9;
|
|
16
|
+
/**
|
|
17
|
+
* A triangle mesh with a per-triangle BVH for narrow-phase queries. Built once
|
|
18
|
+
* per element per run and cached by the engine, so each element's triangle
|
|
19
|
+
* index is paid for at most once even when it appears in several rules.
|
|
20
|
+
*/
|
|
21
|
+
export class TriMesh {
|
|
22
|
+
count;
|
|
23
|
+
positions;
|
|
24
|
+
indices;
|
|
25
|
+
transform;
|
|
26
|
+
bvh;
|
|
27
|
+
constructor(positions, indices, transform) {
|
|
28
|
+
this.positions = positions;
|
|
29
|
+
this.indices = indices;
|
|
30
|
+
this.transform = transform;
|
|
31
|
+
this.count = Math.floor(indices.length / 3);
|
|
32
|
+
const items = [];
|
|
33
|
+
for (let t = 0; t < this.count; t += 1) {
|
|
34
|
+
items.push({ bounds: this.triBounds(t), expressId: t });
|
|
35
|
+
}
|
|
36
|
+
this.bvh = BVH.build(items);
|
|
37
|
+
}
|
|
38
|
+
/** World-space vertex `i` (applies the element transform if present). */
|
|
39
|
+
vertex(i) {
|
|
40
|
+
const o = i * 3;
|
|
41
|
+
const x = this.positions[o];
|
|
42
|
+
const y = this.positions[o + 1];
|
|
43
|
+
const z = this.positions[o + 2];
|
|
44
|
+
const m = this.transform;
|
|
45
|
+
if (!m)
|
|
46
|
+
return [x, y, z];
|
|
47
|
+
// Round the transformed coords to f32. The WASM kernel bakes the transform in
|
|
48
|
+
// JS f64 then packs the arena as a Float32Array (Rust widens f32→f64), so its
|
|
49
|
+
// world coords are f32-quantized. Match that here, or the two kernels would
|
|
50
|
+
// feed slightly different world-space vertices into the otherwise byte-
|
|
51
|
+
// identical narrow phase and diverge at a tolerance boundary. The no-transform
|
|
52
|
+
// path is already f32 (positions is a Float32Array), so this only bites the
|
|
53
|
+
// transformed path. See differential.test.ts "non-identity transform".
|
|
54
|
+
return [
|
|
55
|
+
Math.fround(m[0] * x + m[4] * y + m[8] * z + m[12]),
|
|
56
|
+
Math.fround(m[1] * x + m[5] * y + m[9] * z + m[13]),
|
|
57
|
+
Math.fround(m[2] * x + m[6] * y + m[10] * z + m[14]),
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
/** The three world-space vertices of triangle `t`. */
|
|
61
|
+
tri(t) {
|
|
62
|
+
const o = t * 3;
|
|
63
|
+
return [
|
|
64
|
+
this.vertex(this.indices[o]),
|
|
65
|
+
this.vertex(this.indices[o + 1]),
|
|
66
|
+
this.vertex(this.indices[o + 2]),
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
triBounds(t) {
|
|
70
|
+
const [a, b, c] = this.tri(t);
|
|
71
|
+
return {
|
|
72
|
+
min: [
|
|
73
|
+
Math.min(a[0], b[0], c[0]),
|
|
74
|
+
Math.min(a[1], b[1], c[1]),
|
|
75
|
+
Math.min(a[2], b[2], c[2]),
|
|
76
|
+
],
|
|
77
|
+
max: [
|
|
78
|
+
Math.max(a[0], b[0], c[0]),
|
|
79
|
+
Math.max(a[1], b[1], c[1]),
|
|
80
|
+
Math.max(a[2], b[2], c[2]),
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Triangle indices whose bounds intersect `bounds`. */
|
|
85
|
+
queryTris(bounds) {
|
|
86
|
+
if (this.count === 0)
|
|
87
|
+
return [];
|
|
88
|
+
return this.bvh.queryAABB(bounds);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* True when `p` is inside this closed mesh. Casts a fixed-direction ray and
|
|
92
|
+
* counts forward crossings against every triangle (Möller–Trumbore,
|
|
93
|
+
* double-sided so winding doesn't matter); an odd count means inside.
|
|
94
|
+
*
|
|
95
|
+
* Iterates all triangles in index order — deliberately NOT the BVH — so the
|
|
96
|
+
* result is bit-identical to the Rust `contains_point`. Only invoked in the
|
|
97
|
+
* rare enclosed-solid branch of the narrow phase, so the O(n) cost is fine.
|
|
98
|
+
*/
|
|
99
|
+
containsPoint(p) {
|
|
100
|
+
let crossings = 0;
|
|
101
|
+
for (let t = 0; t < this.count; t += 1) {
|
|
102
|
+
const [v0, v1, v2] = this.tri(t);
|
|
103
|
+
const e1 = sub(v1, v0);
|
|
104
|
+
const e2 = sub(v2, v0);
|
|
105
|
+
const pv = cross(RAY_DIR, e2);
|
|
106
|
+
const det = dot(e1, pv);
|
|
107
|
+
if (det > -RAY_EPS && det < RAY_EPS)
|
|
108
|
+
continue; // ray parallel to triangle
|
|
109
|
+
const inv = 1 / det;
|
|
110
|
+
const tv = sub(p, v0);
|
|
111
|
+
const u = dot(tv, pv) * inv;
|
|
112
|
+
if (u < 0 || u > 1)
|
|
113
|
+
continue;
|
|
114
|
+
const qv = cross(tv, e1);
|
|
115
|
+
const v = dot(RAY_DIR, qv) * inv;
|
|
116
|
+
if (v < 0 || u + v > 1)
|
|
117
|
+
continue;
|
|
118
|
+
const tHit = dot(e2, qv) * inv;
|
|
119
|
+
if (tHit > RAY_EPS)
|
|
120
|
+
crossings += 1; // strictly forward
|
|
121
|
+
}
|
|
122
|
+
return (crossings & 1) === 1;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=tri-mesh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tri-mesh.js","sourceRoot":"","sources":["../../src/engine-ts/tri-mesh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ClashElement } from '../types.js';
|
|
2
|
+
import type { ClashKernel, RuleDetection } from './kernel.js';
|
|
3
|
+
/**
|
|
4
|
+
* Pure-TypeScript geometry kernel: spatial BVH broad phase + exact
|
|
5
|
+
* triangle-triangle narrow phase. Also the reference oracle the Rust/WASM kernel
|
|
6
|
+
* is differentially tested against.
|
|
7
|
+
*/
|
|
8
|
+
export declare class TsKernel implements ClashKernel {
|
|
9
|
+
private readonly triCache;
|
|
10
|
+
prepare(): void;
|
|
11
|
+
private triFor;
|
|
12
|
+
detectRule(elements: ClashElement[], groupAIdx: number[], groupBIdx: number[] | null, rule: import('../types.js').ClashRule, tolerance: number, maxPairs: number, signal?: AbortSignal, onProgress?: (done: number, total: number) => void): Promise<RuleDetection>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=ts-kernel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ts-kernel.d.ts","sourceRoot":"","sources":["../../src/engine-ts/ts-kernel.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,OAAO,KAAK,EAAE,WAAW,EAAgB,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5E;;;;GAIG;AACH,qBAAa,QAAS,YAAW,WAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IAEjE,OAAO,IAAI,IAAI;IAKf,OAAO,CAAC,MAAM;IASR,UAAU,CACd,QAAQ,EAAE,YAAY,EAAE,EACxB,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,EAC1B,IAAI,EAAE,OAAO,aAAa,EAAE,SAAS,EACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACjD,OAAO,CAAC,aAAa,CAAC;CAmD1B"}
|
|
@@ -0,0 +1,85 @@
|
|
|
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 { candidatePairs } from './broad.js';
|
|
5
|
+
import { testPair } from './narrow.js';
|
|
6
|
+
import { TriMesh } from './tri-mesh.js';
|
|
7
|
+
/**
|
|
8
|
+
* Pure-TypeScript geometry kernel: spatial BVH broad phase + exact
|
|
9
|
+
* triangle-triangle narrow phase. Also the reference oracle the Rust/WASM kernel
|
|
10
|
+
* is differentially tested against.
|
|
11
|
+
*/
|
|
12
|
+
export class TsKernel {
|
|
13
|
+
triCache = new WeakMap();
|
|
14
|
+
prepare() {
|
|
15
|
+
// Triangle BVHs are built lazily per element on first use, and cached for
|
|
16
|
+
// the lifetime of this kernel so an element shared across rules pays once.
|
|
17
|
+
}
|
|
18
|
+
triFor(el) {
|
|
19
|
+
let mesh = this.triCache.get(el);
|
|
20
|
+
if (!mesh) {
|
|
21
|
+
mesh = new TriMesh(el.positions, el.indices, el.transform);
|
|
22
|
+
this.triCache.set(el, mesh);
|
|
23
|
+
}
|
|
24
|
+
return mesh;
|
|
25
|
+
}
|
|
26
|
+
async detectRule(elements, groupAIdx, groupBIdx, rule, tolerance, maxPairs, signal, onProgress) {
|
|
27
|
+
const groupA = groupAIdx.map((i) => elements[i]);
|
|
28
|
+
const groupB = groupBIdx ? groupBIdx.map((i) => elements[i]) : null;
|
|
29
|
+
const resolveB = groupB ?? groupA;
|
|
30
|
+
const resolveBIdx = groupBIdx ?? groupAIdx;
|
|
31
|
+
const margin = Math.max(tolerance, rule.clearance ?? 0);
|
|
32
|
+
const pairs = candidatePairs(groupA, groupB, margin);
|
|
33
|
+
const total = pairs.length;
|
|
34
|
+
const records = [];
|
|
35
|
+
let processed = 0;
|
|
36
|
+
let candidatesDropped = 0;
|
|
37
|
+
onProgress?.(0, total);
|
|
38
|
+
let lastYield = now();
|
|
39
|
+
for (const [i, j] of pairs) {
|
|
40
|
+
if (processed >= maxPairs) {
|
|
41
|
+
candidatesDropped = total - processed;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
// Every 1024 pairs: check cancellation, and if we've held the thread for
|
|
45
|
+
// more than a frame's worth of time, report progress and yield so the UI
|
|
46
|
+
// can repaint and stay responsive on large models.
|
|
47
|
+
if ((processed & 0x3ff) === 0) {
|
|
48
|
+
if (signal?.aborted) {
|
|
49
|
+
throw new DOMException('Clash run aborted', 'AbortError');
|
|
50
|
+
}
|
|
51
|
+
if (onProgress && now() - lastYield > YIELD_MS) {
|
|
52
|
+
onProgress(processed, total);
|
|
53
|
+
await yieldToEventLoop();
|
|
54
|
+
lastYield = now();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
processed += 1;
|
|
58
|
+
const elA = groupA[i];
|
|
59
|
+
const elB = resolveB[j];
|
|
60
|
+
const res = testPair(elA, this.triFor(elA), elB, this.triFor(elB), rule, tolerance);
|
|
61
|
+
if (!res)
|
|
62
|
+
continue;
|
|
63
|
+
records.push({
|
|
64
|
+
a: groupAIdx[i],
|
|
65
|
+
b: resolveBIdx[j],
|
|
66
|
+
status: res.status,
|
|
67
|
+
distance: res.distance,
|
|
68
|
+
point: res.point,
|
|
69
|
+
bounds: res.bounds,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
onProgress?.(processed, total);
|
|
73
|
+
return { records, candidatesProcessed: processed, candidatesDropped };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Hold the main thread no longer than this between yields (≈ a few frames). */
|
|
77
|
+
const YIELD_MS = 50;
|
|
78
|
+
function now() {
|
|
79
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
80
|
+
}
|
|
81
|
+
/** Yield to the event loop so the host can flush React renders / repaint. */
|
|
82
|
+
function yieldToEventLoop() {
|
|
83
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=ts-kernel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ts-kernel.js","sourceRoot":"","sources":["../../src/engine-ts/ts-kernel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM-backed clash engine (`@ifc-lite/clash/wasm`).
|
|
3
|
+
*
|
|
4
|
+
* Behind a subpath so `@ifc-lite/wasm` never enters the core import graph. The
|
|
5
|
+
* engine reuses the shared orchestrator with a `WasmKernel`, so its results are
|
|
6
|
+
* identical to the TS engine's (the differential test pins this).
|
|
7
|
+
*/
|
|
8
|
+
import { type InitInput } from '@ifc-lite/wasm';
|
|
9
|
+
import type { ClashEngine } from '../engine-ts/index.js';
|
|
10
|
+
import type { ClashElement, ClashResult, ClashRule, ClashSettings } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Initialize the WASM module once (idempotent). In a browser, call with no
|
|
13
|
+
* arguments — wasm-bindgen resolves the `.wasm` via `import.meta.url`. In Node
|
|
14
|
+
* (or any non-bundler host), pass the `.wasm` bytes (a `BufferSource`) or a URL.
|
|
15
|
+
*/
|
|
16
|
+
export declare function initClashWasm(input?: InitInput): Promise<void>;
|
|
17
|
+
export declare class WasmClashEngine implements ClashEngine {
|
|
18
|
+
run(elements: ClashElement[], rules: ClashRule[], settings?: ClashSettings): Promise<ClashResult>;
|
|
19
|
+
}
|
|
20
|
+
export { WasmKernel } from './wasm-kernel.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine-wasm/index.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAiB,EAAgB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKvF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAW9D;AAED,qBAAa,eAAgB,YAAW,WAAW;IAC3C,GAAG,CACP,QAAQ,EAAE,YAAY,EAAE,EACxB,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,GAAE,aAAkB,GAC3B,OAAO,CAAC,WAAW,CAAC;CAKxB;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
/**
|
|
5
|
+
* WASM-backed clash engine (`@ifc-lite/clash/wasm`).
|
|
6
|
+
*
|
|
7
|
+
* Behind a subpath so `@ifc-lite/wasm` never enters the core import graph. The
|
|
8
|
+
* engine reuses the shared orchestrator with a `WasmKernel`, so its results are
|
|
9
|
+
* identical to the TS engine's (the differential test pins this).
|
|
10
|
+
*/
|
|
11
|
+
import initWasm, { ClashSession } from '@ifc-lite/wasm';
|
|
12
|
+
import { runClash } from '../engine-ts/orchestrator.js';
|
|
13
|
+
import { WasmKernel } from './wasm-kernel.js';
|
|
14
|
+
let initPromise = null;
|
|
15
|
+
/**
|
|
16
|
+
* Initialize the WASM module once (idempotent). In a browser, call with no
|
|
17
|
+
* arguments — wasm-bindgen resolves the `.wasm` via `import.meta.url`. In Node
|
|
18
|
+
* (or any non-bundler host), pass the `.wasm` bytes (a `BufferSource`) or a URL.
|
|
19
|
+
*/
|
|
20
|
+
export function initClashWasm(input) {
|
|
21
|
+
if (!initPromise) {
|
|
22
|
+
const loaded = input === undefined ? initWasm() : initWasm({ module_or_path: input });
|
|
23
|
+
initPromise = loaded.then(() => undefined).catch((err) => {
|
|
24
|
+
// Never cache a failed init: a transient load error would otherwise
|
|
25
|
+
// permanently break the WASM backend for the whole process.
|
|
26
|
+
initPromise = null;
|
|
27
|
+
throw err;
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return initPromise;
|
|
31
|
+
}
|
|
32
|
+
export class WasmClashEngine {
|
|
33
|
+
async run(elements, rules, settings = {}) {
|
|
34
|
+
await initClashWasm();
|
|
35
|
+
const session = new ClashSession();
|
|
36
|
+
return runClash(elements, rules, settings, new WasmKernel(session));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export { WasmKernel } from './wasm-kernel.js';
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/engine-wasm/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;GAMG;AAEH,OAAO,QAAQ,EAAE,EAAE,YAAY,EAAkB,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAGxD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,IAAI,WAAW,GAAyB,IAAI,CAAC;AAE7C;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;QACtF,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YAChE,oEAAoE;YACpE,4DAA4D;YAC5D,WAAW,GAAG,IAAI,CAAC;YACnB,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,OAAO,eAAe;IAC1B,KAAK,CAAC,GAAG,CACP,QAAwB,EACxB,KAAkB,EAClB,WAA0B,EAAE;QAE5B,MAAM,aAAa,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;QACnC,OAAO,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IACtE,CAAC;CACF;AAED,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClashSession } from '@ifc-lite/wasm';
|
|
2
|
+
import type { ClashElement, ClashRule } from '../types.js';
|
|
3
|
+
import type { ClashKernel, RuleDetection } from '../engine-ts/kernel.js';
|
|
4
|
+
/**
|
|
5
|
+
* WASM geometry kernel: ingests element geometry into a Rust `ClashSession`
|
|
6
|
+
* (flat arenas) and runs each rule's broad + narrow phase in Rust. Produces the
|
|
7
|
+
* same `NarrowRecord`s as `TsKernel` — the orchestrator above is identical, so
|
|
8
|
+
* the two engines are differentially comparable.
|
|
9
|
+
*
|
|
10
|
+
* Any per-element `transform` is baked into the world-space arena here, because
|
|
11
|
+
* the Rust kernel consumes world-space geometry directly (no transform path).
|
|
12
|
+
*/
|
|
13
|
+
export declare class WasmKernel implements ClashKernel {
|
|
14
|
+
private readonly session;
|
|
15
|
+
constructor(session: ClashSession);
|
|
16
|
+
prepare(elements: ClashElement[]): void;
|
|
17
|
+
detectRule(_elements: ClashElement[], groupAIdx: number[], groupBIdx: number[] | null, rule: ClashRule, tolerance: number, _maxPairs: number, signal?: AbortSignal, onProgress?: (done: number, total: number) => void): Promise<RuleDetection>;
|
|
18
|
+
dispose(): void;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=wasm-kernel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm-kernel.d.ts","sourceRoot":"","sources":["../../src/engine-wasm/wasm-kernel.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAQ,YAAY,EAAE,SAAS,EAA2B,MAAM,aAAa,CAAC;AAC1F,OAAO,KAAK,EAAE,WAAW,EAAgB,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAavF;;;;;;;;GAQG;AACH,qBAAa,UAAW,YAAW,WAAW;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,YAAY;IAElD,OAAO,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IA2CjC,UAAU,CACd,SAAS,EAAE,YAAY,EAAE,EACzB,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,EAC1B,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GACjD,OAAO,CAAC,aAAa,CAAC;IA8CzB,OAAO,IAAI,IAAI;CAGhB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
const STATUS = ['hard', 'clearance', 'touch'];
|
|
5
|
+
/** Transform a point by a column-major 4x4 matrix. */
|
|
6
|
+
function applyMat4(m, x, y, z) {
|
|
7
|
+
return [
|
|
8
|
+
m[0] * x + m[4] * y + m[8] * z + m[12],
|
|
9
|
+
m[1] * x + m[5] * y + m[9] * z + m[13],
|
|
10
|
+
m[2] * x + m[6] * y + m[10] * z + m[14],
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* WASM geometry kernel: ingests element geometry into a Rust `ClashSession`
|
|
15
|
+
* (flat arenas) and runs each rule's broad + narrow phase in Rust. Produces the
|
|
16
|
+
* same `NarrowRecord`s as `TsKernel` — the orchestrator above is identical, so
|
|
17
|
+
* the two engines are differentially comparable.
|
|
18
|
+
*
|
|
19
|
+
* Any per-element `transform` is baked into the world-space arena here, because
|
|
20
|
+
* the Rust kernel consumes world-space geometry directly (no transform path).
|
|
21
|
+
*/
|
|
22
|
+
export class WasmKernel {
|
|
23
|
+
session;
|
|
24
|
+
constructor(session) {
|
|
25
|
+
this.session = session;
|
|
26
|
+
}
|
|
27
|
+
prepare(elements) {
|
|
28
|
+
const positions = [];
|
|
29
|
+
const posRanges = [];
|
|
30
|
+
const indices = [];
|
|
31
|
+
const idxRanges = [];
|
|
32
|
+
const aabbs = [];
|
|
33
|
+
for (const el of elements) {
|
|
34
|
+
const posOffset = positions.length;
|
|
35
|
+
const t = el.transform;
|
|
36
|
+
if (t) {
|
|
37
|
+
for (let i = 0; i + 2 < el.positions.length; i += 3) {
|
|
38
|
+
const [x, y, z] = applyMat4(t, el.positions[i], el.positions[i + 1], el.positions[i + 2]);
|
|
39
|
+
positions.push(x, y, z);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
for (let i = 0; i < el.positions.length; i += 1) {
|
|
44
|
+
positions.push(el.positions[i]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
posRanges.push(posOffset, el.positions.length);
|
|
48
|
+
const idxOffset = indices.length;
|
|
49
|
+
for (let i = 0; i < el.indices.length; i += 1) {
|
|
50
|
+
indices.push(el.indices[i]);
|
|
51
|
+
}
|
|
52
|
+
idxRanges.push(idxOffset, el.indices.length);
|
|
53
|
+
aabbs.push(el.bounds.min[0], el.bounds.min[1], el.bounds.min[2], el.bounds.max[0], el.bounds.max[1], el.bounds.max[2]);
|
|
54
|
+
}
|
|
55
|
+
this.session.ingest(Float32Array.from(positions), Uint32Array.from(posRanges), Uint32Array.from(indices), Uint32Array.from(idxRanges), Float32Array.from(aabbs));
|
|
56
|
+
}
|
|
57
|
+
async detectRule(_elements, groupAIdx, groupBIdx, rule, tolerance, _maxPairs, signal, onProgress) {
|
|
58
|
+
// The WASM backend runs every candidate pair in Rust, so it does NOT enforce
|
|
59
|
+
// the run-global maxCandidatePairs cap — that cap is a TS-engine guardrail.
|
|
60
|
+
if (signal?.aborted) {
|
|
61
|
+
throw new DOMException('Clash run aborted', 'AbortError');
|
|
62
|
+
}
|
|
63
|
+
const mode = rule.mode === 'clearance' ? 1 : 0;
|
|
64
|
+
const clearance = rule.clearance ?? 0;
|
|
65
|
+
const reportTouch = rule.reportTouch ?? false;
|
|
66
|
+
const groupA = Uint32Array.from(groupAIdx);
|
|
67
|
+
const groupB = groupBIdx ? Uint32Array.from(groupBIdx) : new Uint32Array(0);
|
|
68
|
+
const res = this.session.runRule(groupA, groupB, mode, tolerance, clearance, reportTouch);
|
|
69
|
+
const records = [];
|
|
70
|
+
try {
|
|
71
|
+
// Each getter returns a fresh copy; read once into locals.
|
|
72
|
+
const a = res.a;
|
|
73
|
+
const b = res.b;
|
|
74
|
+
const status = res.status;
|
|
75
|
+
const distance = res.distance;
|
|
76
|
+
const points = res.points;
|
|
77
|
+
const bounds = res.bounds;
|
|
78
|
+
for (let k = 0; k < a.length; k += 1) {
|
|
79
|
+
const bnds = {
|
|
80
|
+
min: [bounds[k * 6], bounds[k * 6 + 1], bounds[k * 6 + 2]],
|
|
81
|
+
max: [bounds[k * 6 + 3], bounds[k * 6 + 4], bounds[k * 6 + 5]],
|
|
82
|
+
};
|
|
83
|
+
records.push({
|
|
84
|
+
a: a[k],
|
|
85
|
+
b: b[k],
|
|
86
|
+
status: STATUS[status[k]] ?? 'hard',
|
|
87
|
+
distance: distance[k],
|
|
88
|
+
point: [points[k * 3], points[k * 3 + 1], points[k * 3 + 2]],
|
|
89
|
+
bounds: bnds,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
// Free the wasm-side result even if the mapping above throws.
|
|
95
|
+
res.free();
|
|
96
|
+
}
|
|
97
|
+
// Rust runs every pair in one fast call — no incremental progress, just
|
|
98
|
+
// report completion so the UI's bar lands at 100%.
|
|
99
|
+
onProgress?.(records.length, records.length);
|
|
100
|
+
return { records, candidatesProcessed: 0, candidatesDropped: 0 };
|
|
101
|
+
}
|
|
102
|
+
dispose() {
|
|
103
|
+
this.session.free();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=wasm-kernel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm-kernel.js","sourceRoot":"","sources":["../../src/engine-wasm/wasm-kernel.ts"],"names":[],"mappings":"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"}
|