@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.
Files changed (107) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +32 -0
  3. package/dist/adapters/ifcx.d.ts +44 -0
  4. package/dist/adapters/ifcx.d.ts.map +1 -0
  5. package/dist/adapters/ifcx.js +198 -0
  6. package/dist/adapters/ifcx.js.map +1 -0
  7. package/dist/adapters/step.d.ts +42 -0
  8. package/dist/adapters/step.d.ts.map +1 -0
  9. package/dist/adapters/step.js +77 -0
  10. package/dist/adapters/step.js.map +1 -0
  11. package/dist/bcf-bridge.d.ts +51 -0
  12. package/dist/bcf-bridge.d.ts.map +1 -0
  13. package/dist/bcf-bridge.js +298 -0
  14. package/dist/bcf-bridge.js.map +1 -0
  15. package/dist/deterministic-uuid.d.ts +9 -0
  16. package/dist/deterministic-uuid.d.ts.map +1 -0
  17. package/dist/deterministic-uuid.js +87 -0
  18. package/dist/deterministic-uuid.js.map +1 -0
  19. package/dist/disciplines.d.ts +33 -0
  20. package/dist/disciplines.d.ts.map +1 -0
  21. package/dist/disciplines.js +148 -0
  22. package/dist/disciplines.js.map +1 -0
  23. package/dist/engine-ts/broad.d.ts +11 -0
  24. package/dist/engine-ts/broad.d.ts.map +1 -0
  25. package/dist/engine-ts/broad.js +61 -0
  26. package/dist/engine-ts/broad.js.map +1 -0
  27. package/dist/engine-ts/index.d.ts +16 -0
  28. package/dist/engine-ts/index.d.ts.map +1 -0
  29. package/dist/engine-ts/index.js +17 -0
  30. package/dist/engine-ts/index.js.map +1 -0
  31. package/dist/engine-ts/kernel.d.ts +50 -0
  32. package/dist/engine-ts/kernel.d.ts.map +1 -0
  33. package/dist/engine-ts/kernel.js +5 -0
  34. package/dist/engine-ts/kernel.js.map +1 -0
  35. package/dist/engine-ts/narrow.d.ts +23 -0
  36. package/dist/engine-ts/narrow.d.ts.map +1 -0
  37. package/dist/engine-ts/narrow.js +127 -0
  38. package/dist/engine-ts/narrow.js.map +1 -0
  39. package/dist/engine-ts/orchestrator.d.ts +11 -0
  40. package/dist/engine-ts/orchestrator.d.ts.map +1 -0
  41. package/dist/engine-ts/orchestrator.js +127 -0
  42. package/dist/engine-ts/orchestrator.js.map +1 -0
  43. package/dist/engine-ts/tri-mesh.d.ts +33 -0
  44. package/dist/engine-ts/tri-mesh.d.ts.map +1 -0
  45. package/dist/engine-ts/tri-mesh.js +125 -0
  46. package/dist/engine-ts/tri-mesh.js.map +1 -0
  47. package/dist/engine-ts/ts-kernel.d.ts +14 -0
  48. package/dist/engine-ts/ts-kernel.d.ts.map +1 -0
  49. package/dist/engine-ts/ts-kernel.js +85 -0
  50. package/dist/engine-ts/ts-kernel.js.map +1 -0
  51. package/dist/engine-wasm/index.d.ts +21 -0
  52. package/dist/engine-wasm/index.d.ts.map +1 -0
  53. package/dist/engine-wasm/index.js +40 -0
  54. package/dist/engine-wasm/index.js.map +1 -0
  55. package/dist/engine-wasm/wasm-kernel.d.ts +20 -0
  56. package/dist/engine-wasm/wasm-kernel.d.ts.map +1 -0
  57. package/dist/engine-wasm/wasm-kernel.js +106 -0
  58. package/dist/engine-wasm/wasm-kernel.js.map +1 -0
  59. package/dist/engine.d.ts +14 -0
  60. package/dist/engine.d.ts.map +1 -0
  61. package/dist/engine.js +20 -0
  62. package/dist/engine.js.map +1 -0
  63. package/dist/exclude.d.ts +15 -0
  64. package/dist/exclude.d.ts.map +1 -0
  65. package/dist/exclude.js +38 -0
  66. package/dist/exclude.js.map +1 -0
  67. package/dist/grouping.d.ts +16 -0
  68. package/dist/grouping.d.ts.map +1 -0
  69. package/dist/grouping.js +311 -0
  70. package/dist/grouping.js.map +1 -0
  71. package/dist/index.d.ts +18 -0
  72. package/dist/index.d.ts.map +1 -0
  73. package/dist/index.js +21 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/lifecycle.d.ts +41 -0
  76. package/dist/lifecycle.d.ts.map +1 -0
  77. package/dist/lifecycle.js +70 -0
  78. package/dist/lifecycle.js.map +1 -0
  79. package/dist/math/aabb.d.ts +27 -0
  80. package/dist/math/aabb.d.ts.map +1 -0
  81. package/dist/math/aabb.js +127 -0
  82. package/dist/math/aabb.js.map +1 -0
  83. package/dist/math/triangle-distance.d.ts +29 -0
  84. package/dist/math/triangle-distance.d.ts.map +1 -0
  85. package/dist/math/triangle-distance.js +149 -0
  86. package/dist/math/triangle-distance.js.map +1 -0
  87. package/dist/math/triangle-intersect.d.ts +13 -0
  88. package/dist/math/triangle-intersect.d.ts.map +1 -0
  89. package/dist/math/triangle-intersect.js +55 -0
  90. package/dist/math/triangle-intersect.js.map +1 -0
  91. package/dist/math/vec3.d.ts +11 -0
  92. package/dist/math/vec3.d.ts.map +1 -0
  93. package/dist/math/vec3.js +38 -0
  94. package/dist/math/vec3.js.map +1 -0
  95. package/dist/selectors.d.ts +12 -0
  96. package/dist/selectors.d.ts.map +1 -0
  97. package/dist/selectors.js +53 -0
  98. package/dist/selectors.js.map +1 -0
  99. package/dist/triage.d.ts +19 -0
  100. package/dist/triage.d.ts.map +1 -0
  101. package/dist/triage.js +99 -0
  102. package/dist/triage.js.map +1 -0
  103. package/dist/types.d.ts +145 -0
  104. package/dist/types.d.ts.map +1 -0
  105. package/dist/types.js +8 -0
  106. package/dist/types.js.map +1 -0
  107. package/package.json +72 -0
@@ -0,0 +1,148 @@
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
+ * BIM discipline definitions, IFC type mappings, and clash rule presets.
6
+ * Inspired by industry-standard discipline coordination workflows.
7
+ */
8
+ import { matchesSelector } from './selectors.js';
9
+ export const DISCIPLINES = {
10
+ ARCH: {
11
+ code: 'ARCH',
12
+ label: 'Architectural',
13
+ selector: 'IfcWall|IfcSlab|IfcRoof|IfcStair|IfcDoor|IfcWindow|IfcCurtainWall|IfcRailing',
14
+ },
15
+ STR: {
16
+ code: 'STR',
17
+ label: 'Structural',
18
+ selector: 'IfcBeam|IfcColumn|IfcSlab|IfcFooting|IfcPile|IfcWall',
19
+ },
20
+ MEP: {
21
+ code: 'MEP',
22
+ label: 'Mechanical / Plumbing',
23
+ selector: 'IfcPipe*|IfcPump|IfcValve*|IfcTank|IfcFlowTerminal',
24
+ },
25
+ HVAC: {
26
+ code: 'HVAC',
27
+ label: 'HVAC',
28
+ selector: 'IfcDuct*|IfcAirTerminal*|IfcUnitaryEquipment|IfcFan',
29
+ },
30
+ ELEC: {
31
+ code: 'ELEC',
32
+ label: 'Electrical',
33
+ selector: 'IfcCableSegment|IfcCableFitting|IfcCableCarrierSegment|IfcElectricDistributionBoard|IfcJunctionBox',
34
+ },
35
+ FIRE: {
36
+ code: 'FIRE',
37
+ label: 'Fire Protection',
38
+ selector: 'IfcFireSuppressionTerminal|IfcPipe*',
39
+ },
40
+ GEO: {
41
+ code: 'GEO',
42
+ label: 'Site / Geotechnical',
43
+ selector: 'IfcSite|IfcGeographicElement|IfcEarthworksElement',
44
+ },
45
+ };
46
+ export const CLASH_RULE_PRESETS = [
47
+ {
48
+ id: 'MEPxSTR',
49
+ name: 'MEP vs Structure',
50
+ description: 'Pipes and fittings clashing with beams, columns, and slabs',
51
+ severity: 'critical',
52
+ selectorA: 'IfcPipe*|IfcPump|IfcValve*|IfcTank',
53
+ selectorB: 'IfcBeam|IfcColumn|IfcSlab|IfcFooting',
54
+ },
55
+ {
56
+ id: 'HVACxSTR',
57
+ name: 'HVAC vs Structure',
58
+ description: 'Ducts clashing with structural elements',
59
+ severity: 'critical',
60
+ selectorA: 'IfcDuct*|IfcAirTerminal*|IfcUnitaryEquipment',
61
+ selectorB: 'IfcBeam|IfcColumn|IfcSlab',
62
+ },
63
+ {
64
+ id: 'HVACxARCH',
65
+ name: 'HVAC vs Architecture',
66
+ description: 'Ducts passing through walls and slabs (penetration sleeves needed)',
67
+ severity: 'major',
68
+ selectorA: 'IfcDuct*|IfcAirTerminal*',
69
+ selectorB: 'IfcWall|IfcSlab|IfcRoof',
70
+ },
71
+ {
72
+ id: 'MEPxARCH',
73
+ name: 'MEP vs Architecture',
74
+ description: 'Pipes passing through walls and slabs (penetration sleeves needed)',
75
+ severity: 'major',
76
+ selectorA: 'IfcPipe*|IfcPump|IfcValve*',
77
+ selectorB: 'IfcWall|IfcSlab|IfcRoof',
78
+ },
79
+ {
80
+ id: 'HVACxMEP',
81
+ name: 'HVAC vs MEP',
82
+ description: 'Ducts crossing pipes (routing conflicts)',
83
+ severity: 'major',
84
+ selectorA: 'IfcDuct*',
85
+ selectorB: 'IfcPipe*',
86
+ },
87
+ {
88
+ id: 'FIRExSTR',
89
+ name: 'Fire Protection vs Structure',
90
+ description: 'Sprinkler pipes clashing with structure',
91
+ severity: 'critical',
92
+ selectorA: 'IfcFireSuppressionTerminal|IfcPipe*',
93
+ selectorB: 'IfcBeam|IfcColumn|IfcSlab',
94
+ },
95
+ {
96
+ id: 'ELECxMEP',
97
+ name: 'Electrical vs MEP',
98
+ description: 'Cables too close to pipes (separation rules)',
99
+ severity: 'minor',
100
+ selectorA: 'IfcCableSegment|IfcCableFitting|IfcCableCarrierSegment',
101
+ selectorB: 'IfcPipe*|IfcDuct*',
102
+ },
103
+ ];
104
+ const SEVERITY_ORDER = {
105
+ critical: 0,
106
+ major: 1,
107
+ minor: 2,
108
+ info: 3,
109
+ };
110
+ /**
111
+ * Infer severity for a clash from the IFC types of the two elements, by matching
112
+ * against the discipline-pair presets. Returns the most severe matching rule.
113
+ */
114
+ export function inferClashSeverity(typeA, typeB) {
115
+ let best = 'info';
116
+ for (const preset of CLASH_RULE_PRESETS) {
117
+ const matchForward = matchesSelector(typeA, preset.selectorA) && matchesSelector(typeB, preset.selectorB);
118
+ const matchReverse = matchesSelector(typeA, preset.selectorB) && matchesSelector(typeB, preset.selectorA);
119
+ if ((matchForward || matchReverse) && SEVERITY_ORDER[preset.severity] < SEVERITY_ORDER[best]) {
120
+ best = preset.severity;
121
+ }
122
+ }
123
+ return best;
124
+ }
125
+ /** Turn the discipline presets into runnable clash rules (the clash matrix). */
126
+ /**
127
+ * Turn an arbitrary list of rule presets into runnable `ClashRule`s. Used by the
128
+ * built-in discipline matrix below and by the viewer to run a user-edited preset
129
+ * set. `clearance` is threaded onto each rule only in clearance mode (narrow.ts
130
+ * only reports clearance violations when `rule.clearance != null`); `reportTouch`
131
+ * is threaded onto every rule when set.
132
+ */
133
+ export function rulesFromPresets(presets, mode = 'hard', clearance, reportTouch) {
134
+ return presets.map((preset) => ({
135
+ id: preset.id,
136
+ name: preset.name,
137
+ a: preset.selectorA,
138
+ b: preset.selectorB,
139
+ mode,
140
+ severity: preset.severity,
141
+ ...(mode === 'clearance' && clearance != null ? { clearance } : {}),
142
+ ...(reportTouch ? { reportTouch: true } : {}),
143
+ }));
144
+ }
145
+ export function disciplineMatrixRules(mode = 'hard', clearance) {
146
+ return rulesFromPresets(CLASH_RULE_PRESETS, mode, clearance);
147
+ }
148
+ //# sourceMappingURL=disciplines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disciplines.js","sourceRoot":"","sources":["../src/disciplines.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { ClashElement } from '../types.js';
2
+ /**
3
+ * Broad-phase candidate pairs.
4
+ *
5
+ * Group pair (`groupB` provided): each returned `[i, j]` indexes
6
+ * `groupA[i]` × `groupB[j]`. Self-clash (`groupB === null`): both indices refer
7
+ * to `groupA`, with `i < j`. Query bounds are inflated by `margin` so clearance
8
+ * candidates (within the gap) are not missed.
9
+ */
10
+ export declare function candidatePairs(groupA: ClashElement[], groupB: ClashElement[] | null, margin: number): Array<[number, number]>;
11
+ //# sourceMappingURL=broad.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broad.d.ts","sourceRoot":"","sources":["../../src/engine-ts/broad.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EAAE,EACtB,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,EAC7B,MAAM,EAAE,MAAM,GACb,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsCzB"}
@@ -0,0 +1,61 @@
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 { inflate } from '../math/aabb.js';
6
+ /**
7
+ * Broad-phase candidate pairs.
8
+ *
9
+ * Group pair (`groupB` provided): each returned `[i, j]` indexes
10
+ * `groupA[i]` × `groupB[j]`. Self-clash (`groupB === null`): both indices refer
11
+ * to `groupA`, with `i < j`. Query bounds are inflated by `margin` so clearance
12
+ * candidates (within the gap) are not missed.
13
+ */
14
+ export function candidatePairs(groupA, groupB, margin) {
15
+ if (groupA.length === 0)
16
+ return [];
17
+ const items = groupA.map((e, i) => ({ bounds: e.bounds, expressId: i }));
18
+ const bvh = BVH.build(items);
19
+ const pairs = [];
20
+ if (groupB) {
21
+ const seen = new Set();
22
+ for (let j = 0; j < groupB.length; j += 1) {
23
+ const b = groupB[j];
24
+ const hits = bvh.queryAABB(inflate(b.bounds, margin));
25
+ for (const i of hits) {
26
+ const a = groupA[i];
27
+ if (a.key === b.key && a.model === b.model)
28
+ continue;
29
+ const dedup = orderKey(a.model, a.key, b.model, b.key);
30
+ if (seen.has(dedup))
31
+ continue;
32
+ seen.add(dedup);
33
+ pairs.push([i, j]);
34
+ }
35
+ }
36
+ }
37
+ else {
38
+ for (let i = 0; i < groupA.length; i += 1) {
39
+ const a = groupA[i];
40
+ const hits = bvh.queryAABB(inflate(a.bounds, margin));
41
+ for (const j of hits) {
42
+ if (j <= i)
43
+ continue;
44
+ const other = groupA[j];
45
+ // Skip same-entity pairs: an element split across several geometry
46
+ // sub-prims (common in IFC5/USD) produces multiple elements with the
47
+ // same durable key — that is one entity, not a self-clash.
48
+ if (a.key === other.key && a.model === other.model)
49
+ continue;
50
+ pairs.push([i, j]);
51
+ }
52
+ }
53
+ }
54
+ return pairs;
55
+ }
56
+ function orderKey(modelA, keyA, modelB, keyB) {
57
+ const a = `${modelA} ${keyA}`;
58
+ const b = `${modelB} ${keyB}`;
59
+ return a < b ? `${a} ${b}` : `${b} ${a}`;
60
+ }
61
+ //# sourceMappingURL=broad.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"broad.js","sourceRoot":"","sources":["../../src/engine-ts/broad.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ClashElement, ClashResult, ClashRule, ClashSettings } from '../types.js';
2
+ export type { ClashKernel, NarrowRecord, RuleDetection } from './kernel.js';
3
+ export { runClash } from './orchestrator.js';
4
+ export { TsKernel } from './ts-kernel.js';
5
+ /** A clash engine: a pure async function of (elements, rules, settings). */
6
+ export interface ClashEngine {
7
+ run(elements: ClashElement[], rules: ClashRule[], settings?: ClashSettings): Promise<ClashResult>;
8
+ }
9
+ /**
10
+ * Reference engine: the shared orchestrator driving the pure-TypeScript geometry
11
+ * kernel (spatial BVH broad phase + exact triangle narrow phase).
12
+ */
13
+ export declare class TsClashEngine implements ClashEngine {
14
+ run(elements: ClashElement[], rules: ClashRule[], settings?: ClashSettings): Promise<ClashResult>;
15
+ }
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine-ts/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIvF,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACnG;AAED;;;GAGG;AACH,qBAAa,aAAc,YAAW,WAAW;IAC/C,GAAG,CACD,QAAQ,EAAE,YAAY,EAAE,EACxB,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,GAAE,aAAkB,GAC3B,OAAO,CAAC,WAAW,CAAC;CAGxB"}
@@ -0,0 +1,17 @@
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 { runClash } from './orchestrator.js';
5
+ import { TsKernel } from './ts-kernel.js';
6
+ export { runClash } from './orchestrator.js';
7
+ export { TsKernel } from './ts-kernel.js';
8
+ /**
9
+ * Reference engine: the shared orchestrator driving the pure-TypeScript geometry
10
+ * kernel (spatial BVH broad phase + exact triangle narrow phase).
11
+ */
12
+ export class TsClashEngine {
13
+ run(elements, rules, settings = {}) {
14
+ return runClash(elements, rules, settings, new TsKernel());
15
+ }
16
+ }
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/engine-ts/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAG/D,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAO1C;;;GAGG;AACH,MAAM,OAAO,aAAa;IACxB,GAAG,CACD,QAAwB,EACxB,KAAkB,EAClB,WAA0B,EAAE;QAE5B,OAAO,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC;CACF"}
@@ -0,0 +1,50 @@
1
+ import type { AABB, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
2
+ /**
3
+ * One detected clash, in kernel terms: a pair of GLOBAL element indices plus the
4
+ * geometric verdict. The orchestrator turns this into a `Clash` (identity,
5
+ * severity, exclusions). This is the seam between orchestration (shared, pure
6
+ * TypeScript) and the geometry kernel (TypeScript today, Rust/WASM in Phase 3).
7
+ */
8
+ export interface NarrowRecord {
9
+ /** Global index into the ingested `elements` array. */
10
+ a: number;
11
+ /** Global index into the ingested `elements` array. */
12
+ b: number;
13
+ status: ClashStatus;
14
+ distance: number;
15
+ point: Vec3;
16
+ bounds: AABB;
17
+ }
18
+ export interface RuleDetection {
19
+ records: NarrowRecord[];
20
+ /** Candidate pairs actually examined — drives the run-global `maxPairs` budget. */
21
+ candidatesProcessed: number;
22
+ /** Candidate pairs skipped by the `maxPairs` cap (for transparency). */
23
+ candidatesDropped: number;
24
+ }
25
+ /**
26
+ * The geometry backend: broad phase + narrow phase for one rule. Implementations
27
+ * must be interchangeable — given the same elements and rule they produce the
28
+ * same records (modulo floating-point), which is what the differential test
29
+ * pins. Selection, exclusions, severity and identity live in the orchestrator,
30
+ * never here.
31
+ */
32
+ export interface ClashKernel {
33
+ /** Ingest the elements once (build any indices). */
34
+ prepare(elements: ClashElement[]): void;
35
+ /**
36
+ * Detect clashes for one rule. `groupA`/`groupB` are GLOBAL element indices;
37
+ * `groupB === null` means a self-clash within `groupA`. Returned records carry
38
+ * GLOBAL element indices. `maxPairs` caps candidate pairs (Infinity = no cap).
39
+ */
40
+ detectRule(elements: ClashElement[], groupA: number[], groupB: number[] | null, rule: ClashRule, tolerance: number, maxPairs: number, signal?: AbortSignal,
41
+ /**
42
+ * Reports narrow-phase progress as `(processedPairs, totalPairs)`. The TS
43
+ * kernel calls it periodically AND yields to the event loop between calls,
44
+ * so a long run on the main thread stays responsive and can paint progress.
45
+ */
46
+ onProgress?: (done: number, total: number) => void): RuleDetection | Promise<RuleDetection>;
47
+ /** Release any resources (e.g. a WASM session). Optional. */
48
+ dispose?(): void;
49
+ }
50
+ //# sourceMappingURL=kernel.d.ts.map
@@ -0,0 +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;AAEpF;;;;;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,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,EAChB,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"}
@@ -0,0 +1,5 @@
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
+ export {};
5
+ //# sourceMappingURL=kernel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kernel.js","sourceRoot":"","sources":["../../src/engine-ts/kernel.ts"],"names":[],"mappings":"AAAA;;+DAE+D"}
@@ -0,0 +1,23 @@
1
+ import type { AABB, ClashElement, ClashRule, ClashStatus, Vec3 } from '../types.js';
2
+ import type { TriMesh } from './tri-mesh.js';
3
+ export interface NarrowResult {
4
+ status: ClashStatus;
5
+ distance: number;
6
+ point: Vec3;
7
+ bounds: AABB;
8
+ }
9
+ /**
10
+ * Narrow-phase test for one candidate element pair.
11
+ *
12
+ * Gathers candidate triangle pairs through the per-element triangle BVHs (work
13
+ * stays proportional to actual overlap — no decimation), then:
14
+ * - a genuine non-coplanar triangle crossing ⇒ `hard` (pipe through beam, etc.);
15
+ * - surfaces that merely coincide/touch (no crossing) are disambiguated by AABB
16
+ * penetration, so a deep axis-aligned overlap — whose surface intersections
17
+ * are all coplanar — is still classified `hard`, while face contact is `touch`;
18
+ * - otherwise the exact triangle distance drives `clearance` / `touch` / no clash.
19
+ *
20
+ * Returns `null` for no clash.
21
+ */
22
+ export declare function testPair(elA: ClashElement, triA: TriMesh, elB: ClashElement, triB: TriMesh, rule: ClashRule, tolerance: number): NarrowResult | null;
23
+ //# sourceMappingURL=narrow.d.ts.map
@@ -0,0 +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;AAKpF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,EAAE,IAAI,CAAC;CACd;AAED;;;;;;;;;;;;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,CAgHrB"}
@@ -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 { aabbContains, boundsOfPoints, center, inflate, overlapBounds, signedGap } from '../math/aabb.js';
5
+ import { centroid, mid } from '../math/vec3.js';
6
+ import { triTriIntersect } from '../math/triangle-intersect.js';
7
+ import { triTriDistance } from '../math/triangle-distance.js';
8
+ /**
9
+ * Narrow-phase test for one candidate element pair.
10
+ *
11
+ * Gathers candidate triangle pairs through the per-element triangle BVHs (work
12
+ * stays proportional to actual overlap — no decimation), then:
13
+ * - a genuine non-coplanar triangle crossing ⇒ `hard` (pipe through beam, etc.);
14
+ * - surfaces that merely coincide/touch (no crossing) are disambiguated by AABB
15
+ * penetration, so a deep axis-aligned overlap — whose surface intersections
16
+ * are all coplanar — is still classified `hard`, while face contact is `touch`;
17
+ * - otherwise the exact triangle distance drives `clearance` / `touch` / no clash.
18
+ *
19
+ * Returns `null` for no clash.
20
+ */
21
+ export function testPair(elA, triA, elB, triB, rule, tolerance) {
22
+ const margin = Math.max(tolerance, rule.clearance ?? 0);
23
+ // Iterate the smaller mesh, querying the larger one's BVH.
24
+ const aSmaller = triA.count <= triB.count;
25
+ const small = aSmaller ? triA : triB;
26
+ const large = aSmaller ? triB : triA;
27
+ let intersects = false;
28
+ let contactSumX = 0;
29
+ let contactSumY = 0;
30
+ let contactSumZ = 0;
31
+ let contactN = 0;
32
+ let minDist = Infinity;
33
+ let closestA = elA.bounds.min;
34
+ let closestB = elB.bounds.min;
35
+ for (let ts = 0; ts < small.count; ts += 1) {
36
+ const sb = small.triBounds(ts);
37
+ const hits = large.queryTris(inflate(sb, margin));
38
+ if (hits.length === 0)
39
+ continue;
40
+ const [s0, s1, s2] = small.tri(ts);
41
+ for (const tl of hits) {
42
+ const [l0, l1, l2] = large.tri(tl);
43
+ if (triTriIntersect(s0, s1, s2, l0, l1, l2)) {
44
+ intersects = true;
45
+ const c = mid(centroid(s0, s1, s2), centroid(l0, l1, l2));
46
+ contactSumX += c[0];
47
+ contactSumY += c[1];
48
+ contactSumZ += c[2];
49
+ contactN += 1;
50
+ }
51
+ else if (!intersects) {
52
+ // Distance only matters while we still might be a clearance/touch case.
53
+ const d = triTriDistance(s0, s1, s2, l0, l1, l2);
54
+ if (d.dist < minDist) {
55
+ minDist = d.dist;
56
+ closestA = d.pA;
57
+ closestB = d.pB;
58
+ }
59
+ }
60
+ }
61
+ }
62
+ const overlap = overlapBounds(elA.bounds, elB.bounds);
63
+ if (intersects) {
64
+ const point = contactN > 0
65
+ ? [contactSumX / contactN, contactSumY / contactN, contactSumZ / contactN]
66
+ : center(overlap);
67
+ // Phase-0 penetration estimate from AABB overlap; exact depth lands in Rust.
68
+ const penetration = Math.max(0, -signedGap(elA.bounds, elB.bounds));
69
+ return { status: 'hard', distance: -penetration, point, bounds: overlap };
70
+ }
71
+ // Fully-enclosed solid: no surface crossing, but one element's AABB is wholly
72
+ // inside the other's, so it may be buried (e.g. equipment inside a slab). With
73
+ // no surface crossing the inner solid is entirely inside OR entirely outside
74
+ // the other, so ray-casting ONE representative vertex of the contained mesh
75
+ // against the other solid decides it — and ray casting (not an AABB test)
76
+ // correctly returns "outside" when the inner sits in a concave notch.
77
+ // Test B-contains-A first, then A-contains-B, so the inner pick is
78
+ // deterministic (and identical to the Rust kernel) on equal AABBs.
79
+ if (aabbContains(elB.bounds, elA.bounds)) {
80
+ if (triA.count > 0 && triB.containsPoint(triA.tri(0)[0])) {
81
+ return { status: 'hard', distance: signedGap(elA.bounds, elB.bounds), point: center(overlap), bounds: overlap };
82
+ }
83
+ }
84
+ else if (aabbContains(elA.bounds, elB.bounds)) {
85
+ if (triB.count > 0 && triA.containsPoint(triB.tri(0)[0])) {
86
+ return { status: 'hard', distance: signedGap(elA.bounds, elB.bounds), point: center(overlap), bounds: overlap };
87
+ }
88
+ }
89
+ if (minDist === Infinity) {
90
+ // Broad-phase candidate with no triangle-level proximity — not a clash.
91
+ return null;
92
+ }
93
+ // Surfaces coincide/touch with no genuine crossing, but the volumes overlap
94
+ // beyond tolerance (e.g. axis-aligned boxes, whose surface intersections are
95
+ // all coplanar) -> hard, via AABB penetration depth.
96
+ if (minDist <= tolerance) {
97
+ const gap = signedGap(elA.bounds, elB.bounds);
98
+ if (gap < -tolerance) {
99
+ return { status: 'hard', distance: gap, point: center(overlap), bounds: overlap };
100
+ }
101
+ }
102
+ // Clearance rule: ANY gap within the required clearance is a violation —
103
+ // including sub-tolerance, nearly-touching gaps, which are the MOST severe and
104
+ // must not be swallowed by the touch band below.
105
+ if (rule.mode === 'clearance' && rule.clearance != null && minDist <= rule.clearance) {
106
+ return {
107
+ status: 'clearance',
108
+ distance: minDist,
109
+ point: mid(closestA, closestB),
110
+ bounds: boundsOfPoints(closestA, closestB),
111
+ };
112
+ }
113
+ // Otherwise only bare contact within tolerance remains; suppressed unless the
114
+ // rule opts in. `<=` so an exact touch at tolerance 0 is still caught.
115
+ if (minDist <= tolerance) {
116
+ if (!rule.reportTouch)
117
+ return null;
118
+ return {
119
+ status: 'touch',
120
+ distance: minDist,
121
+ point: mid(closestA, closestB),
122
+ bounds: boundsOfPoints(closestA, closestB),
123
+ };
124
+ }
125
+ return null;
126
+ }
127
+ //# sourceMappingURL=narrow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narrow.js","sourceRoot":"","sources":["../../src/engine-ts/narrow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type ClashElement, type ClashResult, type ClashRule, type ClashSettings } from '../types.js';
2
+ import type { ClashKernel } from './kernel.js';
3
+ /**
4
+ * Backend-agnostic clash orchestration: selection, exclusions, severity, stable
5
+ * identity, dedup, ordering and summary. The geometry (broad + narrow phase) is
6
+ * delegated to a `ClashKernel` (TypeScript or Rust/WASM), so swapping backends
7
+ * changes nothing observable except speed — which is exactly what makes the two
8
+ * engines differentially comparable.
9
+ */
10
+ export declare function runClash(elements: ClashElement[], rules: ClashRule[], settings: ClashSettings, kernel: ClashKernel): Promise<ClashResult>;
11
+ //# sourceMappingURL=orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../src/engine-ts/orchestrator.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,YAAY,EAEjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,aAAa,EAGnB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,YAAY,EAAE,EACxB,KAAK,EAAE,SAAS,EAAE,EAClB,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,WAAW,CAAC,CAoGtB"}