@ifc-lite/clash 1.8.0 → 1.9.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/README.md CHANGED
@@ -32,6 +32,24 @@ const result = await engine.run(elements, [
32
32
  console.log(result.summary.total, 'clashes');
33
33
  ```
34
34
 
35
+ If your host has already shifted `mesh.expressId` into a federated global id
36
+ space (as the viewer's loader does for every model past the first) while the
37
+ `IfcDataStore` keeps local ids, pass that shift as `meshIdOffset` so the adapter
38
+ can address the store correctly:
39
+
40
+ ```ts
41
+ elementsFromStep({ store, meshes, modelId, federation, meshIdOffset: model.idOffset });
42
+ ```
43
+
44
+ `ClashElement.key` is the element's IFC GlobalId. An element that has none — a
45
+ malformed root, or every element of a GLB-sourced model, whose store carries no
46
+ IFC entities — falls back to `expressid:<encoded modelId>:<expressId>`. Express
47
+ ids are only unique within a model, so the model id is part of that key:
48
+ `clashReviewKey` and the viewer's element-pair exclusions key on the element key
49
+ alone, and an unqualified fallback would let a review or an exclusion set on one
50
+ model apply to another model's element. That fallback is stable only for as long
51
+ as the host's `modelId` is (in the viewer it is a per-load uuid).
52
+
35
53
  Includes the TypeScript reference engine, a Rust→WASM kernel kept in lockstep by a
36
54
  differential test (opt-in via `@ifc-lite/clash/wasm`; `backend: 'auto'` currently
37
55
  resolves to the TS engine), STEP and IFC5/USD source adapters, spatial grouping,
@@ -1 +1 @@
1
- {"version":3,"file":"ifcx.d.ts","sourceRoot":"","sources":["../../src/adapters/ifcx.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;;;;GAOG;AACH,UAAU,gBAAgB;IACxB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACxC;AACD,UAAU,gBAAgB;IACxB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4D9F;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,gBAAgB,EAC/B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GACrC,YAAY,CAoBd"}
1
+ {"version":3,"file":"ifcx.d.ts","sourceRoot":"","sources":["../../src/adapters/ifcx.ts"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG9D;;;;;;;GAOG;AACH,UAAU,gBAAgB;IACxB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;CACxC;AACD,UAAU,gBAAgB;IACxB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,OAAO,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,kCAAkC;IAClC,MAAM,EAAE,WAAW,CAAC;IACpB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAqE9F;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,gBAAgB,EAC/B,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GACrC,YAAY,CAoBd"}
@@ -29,12 +29,22 @@
29
29
  * builds from the USD `children` structure). This is the IFCX analogue of the
30
30
  * STEP void/host/assembly exclusions; it fabricates no relationships.
31
31
  *
32
- * This module is reached via the `@ifc-lite/clash/ifcx` subpath so the core
33
- * stays representation- and parser-neutral.
32
+ * Non-clashable classes (openings, spaces, grids, materials, type objects,
33
+ * spatial containers) are dropped before they become candidates, and every
34
+ * mesh belonging to one durable prim path is coalesced into a single
35
+ * `ClashElement` — both via `./shared.ts`, so this adapter and `step.ts`
36
+ * agree on the same predicate/merge instead of maintaining separate copies.
37
+ * See `shared.ts`'s doc comment for the full rationale, including why it
38
+ * imports `@ifc-lite/parser` for the spatial-container schema walk.
39
+ *
40
+ * This module is reached via the `@ifc-lite/clash/ifcx` subpath so the CORE
41
+ * clash engine (`engine.ts`/`types.ts`) stays representation-neutral — this
42
+ * adapter itself is not required to avoid every non-core dependency.
34
43
  */
35
44
  import { parseIfcx } from '@ifc-lite/ifcx';
36
45
  import { makeExclusionSet, qualifiedKey } from '../exclude.js';
37
46
  import { fromPositions } from '../math/aabb.js';
47
+ import { isNonClashableTag, mergeMeshes } from './shared.js';
38
48
  /**
39
49
  * Parse an IFCX buffer and project its pre-tessellated meshes into
40
50
  * `ClashElement`s. Async because `parseIfcx` is async.
@@ -76,12 +86,20 @@ export async function elementsFromIfcx(options) {
76
86
  const key = idToPath.get(expressId);
77
87
  if (!key)
78
88
  continue;
89
+ // Drop non-physical / container classes before they become clash
90
+ // candidates — the IFCX analogue of `step.ts`'s #1464 filter. `tag` here
91
+ // is the real IFC class code (see `resolveTag` below), spelled
92
+ // identically to STEP's `node.type`, so the SAME shared predicate applies
93
+ // verbatim. (#1464)
94
+ const tag = resolveTag(group[0], entities, expressId);
95
+ if (isNonClashableTag(tag))
96
+ continue;
79
97
  const merged = mergeMeshes(group);
80
98
  const element = {
81
99
  key,
82
100
  ref: refFromPath(key),
83
101
  model: modelId,
84
- tag: resolveTag(group[0], entities, expressId),
102
+ tag,
85
103
  name: resolveName(entities, expressId),
86
104
  bounds: fromPositions(merged.positions),
87
105
  positions: merged.positions,
@@ -141,39 +159,7 @@ function resolveName(entities, expressId) {
141
159
  const name = entities.getName(expressId);
142
160
  return name && name.length > 0 ? name : undefined;
143
161
  }
144
- /**
145
- * Concatenate a group of meshes (all belonging to the same entity) into a
146
- * single position/index buffer. Each subsequent mesh's indices are offset by
147
- * the running vertex count so the merged index buffer addresses the combined
148
- * vertex array. A single mesh is returned as-is (no copy) for the common case.
149
- */
150
- function mergeMeshes(group) {
151
- if (group.length === 1) {
152
- return { positions: group[0].positions, indices: group[0].indices };
153
- }
154
- let totalPositions = 0;
155
- let totalIndices = 0;
156
- for (const mesh of group) {
157
- totalPositions += mesh.positions.length;
158
- totalIndices += mesh.indices.length;
159
- }
160
- const positions = new Float32Array(totalPositions);
161
- const indices = new Uint32Array(totalIndices);
162
- let positionOffset = 0;
163
- let indexOffset = 0;
164
- let vertexBase = 0;
165
- for (const mesh of group) {
166
- positions.set(mesh.positions, positionOffset);
167
- for (let i = 0; i < mesh.indices.length; i++) {
168
- indices[indexOffset + i] = mesh.indices[i] + vertexBase;
169
- }
170
- positionOffset += mesh.positions.length;
171
- indexOffset += mesh.indices.length;
172
- // 3 floats per vertex; the next mesh's indices start after these vertices.
173
- vertexBase += mesh.positions.length / 3;
174
- }
175
- return { positions, indices };
176
- }
162
+ // `mergeMeshes` now lives in `./shared.ts`, shared verbatim with `step.ts`.
177
163
  /**
178
164
  * Deterministic non-negative 31-bit ref derived purely from the prim path via
179
165
  * FNV-1a over the UTF-16 code units. No clock, no randomness: the same path
@@ -1 +1 @@
1
- {"version":3,"file":"ifcx.js","sourceRoot":"","sources":["../../src/adapters/ifcx.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ifcx.js","sourceRoot":"","sources":["../../src/adapters/ifcx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Types that are never physical clash candidates: voids, virtual/reference
3
+ * geometry, and non-product material associations. Including them produced
4
+ * phantom clashes (IfcVirtualElement, IfcOpeningElement, even
5
+ * IfcMaterialConstituent) that no clash rule referenced - they are dropped
6
+ * from the candidate set entirely, so "detect all" and per-rule runs only
7
+ * ever consider real building elements. (#1464)
8
+ *
9
+ * Spatial containers are handled separately by {@link isSpatialContainerTag},
10
+ * which derives them from the schema rather than from a list.
11
+ */
12
+ export declare const NON_CLASHABLE_TAGS: ReadonlySet<string>;
13
+ /**
14
+ * True for spatial *containers* - the entities whose geometry describes an
15
+ * extent that, by construction, encloses the elements assigned to it. A
16
+ * storey against the slab it contains is not a coordination problem, and
17
+ * IFC4.3 infrastructure exports routinely give IfcBuildingStorey / IfcRoad /
18
+ * IfcBridge tessellated bodies, so every contained element clashed with its
19
+ * own container. (follow-up to #1464)
20
+ *
21
+ * Derived from the schema, not enumerated: `getInheritanceChainAcrossSchemas`
22
+ * walks the bundled IFC2X3 + IFC4 + IFC4X3 union, so the IFC4.3 facility
23
+ * leaves (IfcRoad, IfcBridge, IfcFacilityPart, ...) resolve even though the
24
+ * parser's own codegen pin is IFC4_ADD2_TC1 and would return an empty chain
25
+ * for them. Both supertypes are checked because IFC2X3 has no
26
+ * `IfcSpatialElement` - `IfcSpatialStructureElement` descends straight from
27
+ * `IfcProduct` there. This subsumes the IfcSpace / IfcSpatialZone entries
28
+ * that #1464 listed by hand.
29
+ */
30
+ export declare function isSpatialContainerTag(tag: string): boolean;
31
+ /**
32
+ * Whether an element carrying this IFC class `tag` should never become a
33
+ * clash candidate: non-physical/reference geometry, a spatial container, or
34
+ * a type/style object (a template, not an occurrence — see `step.ts`'s
35
+ * original comment on `isIfcTypeLikeEntity` for why type geometry sails
36
+ * through the mesher and lands on top of the occurrences that use it).
37
+ */
38
+ export declare function isNonClashableTag(tag: string): boolean;
39
+ /** A mesh-shaped input to {@link mergeMeshes}: just the two buffers it needs. */
40
+ export interface MergeableMesh {
41
+ positions: Float32Array;
42
+ indices: Uint32Array;
43
+ }
44
+ /**
45
+ * Concatenate a group of meshes (all belonging to the same durable entity)
46
+ * into a single position/index buffer, so one entity with several mesh
47
+ * representations (e.g. Body + Axis, or several sub-meshes) becomes exactly
48
+ * ONE `ClashElement` instead of several aliasing elements that share a
49
+ * key/ref. Each subsequent mesh's indices are offset by the running vertex
50
+ * count so the merged index buffer addresses the combined vertex array.
51
+ * Bounds are then derived from the MERGED positions by the caller
52
+ * (`fromPositions` already scans the whole buffer), so the union is correct
53
+ * for free — there is no separate "combine bounds" step to get wrong.
54
+ *
55
+ * A single mesh is returned as-is (no copy) for the common case.
56
+ */
57
+ export declare function mergeMeshes(group: MergeableMesh[]): {
58
+ positions: Float32Array;
59
+ indices: Uint32Array;
60
+ };
61
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"AA2CA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAUjD,CAAC;AAKH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAS1D;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMtD;AAED,iFAAiF;AACjF,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG;IAAE,SAAS,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CA6BrG"}
@@ -0,0 +1,143 @@
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
+ * Format-independent logic shared by `adapters/step.ts` and `adapters/ifcx.ts`.
6
+ *
7
+ * Both adapters turn a source-specific representation into `ClashElement`s,
8
+ * and both need the SAME two things done to get there correctly:
9
+ *
10
+ * 1. Drop non-physical / container classes before they become clash
11
+ * candidates (openings, spaces, grids, materials, type objects, and
12
+ * spatial containers whose geometry encloses — rather than physically
13
+ * touches — what it contains). (#1464 and its follow-up.)
14
+ * 2. Coalesce every mesh belonging to one durable entity into exactly ONE
15
+ * `ClashElement`, so an entity with multiple representations (e.g.
16
+ * Body + Axis) never aliases into several clash candidates that share
17
+ * one identity.
18
+ *
19
+ * Both are expressed purely in terms of IFC class names / merged geometry
20
+ * buffers — nothing here is STEP- or IFCX-specific. `elementsFromIfcx`'s
21
+ * `tag` is the real IFC class code (`bsi::ifc::class`) or the resolved
22
+ * entity-table type name, so it is spelled identically to `node.type` on the
23
+ * STEP side (`IfcWall`, `IfcSpace`, `IfcOpeningElement`, ...) — verified by
24
+ * `ifcx.ts`'s `resolveTag`. There is nothing format-specific to branch on, so
25
+ * this lives in ONE place both adapters call instead of two copies that can
26
+ * (and did) drift apart.
27
+ *
28
+ * `isSpatialContainerTag` needs `@ifc-lite/parser`'s schema-union inheritance
29
+ * walk to catch IFC4.3 leaves (IfcRoad, IfcBridge, ...) that are not in any
30
+ * hand-maintained list — the exact gap the original #1464 follow-up closed
31
+ * for STEP. `@ifc-lite/parser` is already a full dependency of
32
+ * `@ifc-lite/clash` (see package.json), so importing it here does not add a
33
+ * new package to the graph; it only makes explicit, in the file that needs
34
+ * it, a dependency the package already carries. `elementsFromIfcx`'s own
35
+ * module doc describes the CORE clash engine as representation- and
36
+ * parser-neutral — that claim is about `engine.ts`/`types.ts`, not about this
37
+ * filtering utility, which is allowed to lean on the schema registry both
38
+ * formats already agree on.
39
+ */
40
+ import { getInheritanceChainAcrossSchemas, isIfcTypeLikeEntity } from '@ifc-lite/parser';
41
+ /**
42
+ * Types that are never physical clash candidates: voids, virtual/reference
43
+ * geometry, and non-product material associations. Including them produced
44
+ * phantom clashes (IfcVirtualElement, IfcOpeningElement, even
45
+ * IfcMaterialConstituent) that no clash rule referenced - they are dropped
46
+ * from the candidate set entirely, so "detect all" and per-rule runs only
47
+ * ever consider real building elements. (#1464)
48
+ *
49
+ * Spatial containers are handled separately by {@link isSpatialContainerTag},
50
+ * which derives them from the schema rather than from a list.
51
+ */
52
+ export const NON_CLASHABLE_TAGS = new Set([
53
+ 'IfcOpeningElement',
54
+ 'IfcOpeningStandardCase',
55
+ 'IfcVirtualElement',
56
+ 'IfcGrid',
57
+ 'IfcGridAxis',
58
+ 'IfcAnnotation',
59
+ 'IfcMaterial',
60
+ 'IfcMaterialConstituent',
61
+ 'IfcMaterialLayer',
62
+ ]);
63
+ /** Memoizes the schema walk below; IFC type names are a bounded vocabulary. */
64
+ const spatialContainerByTag = new Map();
65
+ /**
66
+ * True for spatial *containers* - the entities whose geometry describes an
67
+ * extent that, by construction, encloses the elements assigned to it. A
68
+ * storey against the slab it contains is not a coordination problem, and
69
+ * IFC4.3 infrastructure exports routinely give IfcBuildingStorey / IfcRoad /
70
+ * IfcBridge tessellated bodies, so every contained element clashed with its
71
+ * own container. (follow-up to #1464)
72
+ *
73
+ * Derived from the schema, not enumerated: `getInheritanceChainAcrossSchemas`
74
+ * walks the bundled IFC2X3 + IFC4 + IFC4X3 union, so the IFC4.3 facility
75
+ * leaves (IfcRoad, IfcBridge, IfcFacilityPart, ...) resolve even though the
76
+ * parser's own codegen pin is IFC4_ADD2_TC1 and would return an empty chain
77
+ * for them. Both supertypes are checked because IFC2X3 has no
78
+ * `IfcSpatialElement` - `IfcSpatialStructureElement` descends straight from
79
+ * `IfcProduct` there. This subsumes the IfcSpace / IfcSpatialZone entries
80
+ * that #1464 listed by hand.
81
+ */
82
+ export function isSpatialContainerTag(tag) {
83
+ const cached = spatialContainerByTag.get(tag);
84
+ if (cached !== undefined)
85
+ return cached;
86
+ const chain = getInheritanceChainAcrossSchemas(tag);
87
+ const spatial = chain.some((a) => a === 'IfcSpatialElement' || a === 'IfcSpatialStructureElement');
88
+ spatialContainerByTag.set(tag, spatial);
89
+ return spatial;
90
+ }
91
+ /**
92
+ * Whether an element carrying this IFC class `tag` should never become a
93
+ * clash candidate: non-physical/reference geometry, a spatial container, or
94
+ * a type/style object (a template, not an occurrence — see `step.ts`'s
95
+ * original comment on `isIfcTypeLikeEntity` for why type geometry sails
96
+ * through the mesher and lands on top of the occurrences that use it).
97
+ */
98
+ export function isNonClashableTag(tag) {
99
+ return (NON_CLASHABLE_TAGS.has(tag) ||
100
+ isSpatialContainerTag(tag) ||
101
+ isIfcTypeLikeEntity(tag.toUpperCase()));
102
+ }
103
+ /**
104
+ * Concatenate a group of meshes (all belonging to the same durable entity)
105
+ * into a single position/index buffer, so one entity with several mesh
106
+ * representations (e.g. Body + Axis, or several sub-meshes) becomes exactly
107
+ * ONE `ClashElement` instead of several aliasing elements that share a
108
+ * key/ref. Each subsequent mesh's indices are offset by the running vertex
109
+ * count so the merged index buffer addresses the combined vertex array.
110
+ * Bounds are then derived from the MERGED positions by the caller
111
+ * (`fromPositions` already scans the whole buffer), so the union is correct
112
+ * for free — there is no separate "combine bounds" step to get wrong.
113
+ *
114
+ * A single mesh is returned as-is (no copy) for the common case.
115
+ */
116
+ export function mergeMeshes(group) {
117
+ if (group.length === 1) {
118
+ return { positions: group[0].positions, indices: group[0].indices };
119
+ }
120
+ let totalPositions = 0;
121
+ let totalIndices = 0;
122
+ for (const mesh of group) {
123
+ totalPositions += mesh.positions.length;
124
+ totalIndices += mesh.indices.length;
125
+ }
126
+ const positions = new Float32Array(totalPositions);
127
+ const indices = new Uint32Array(totalIndices);
128
+ let positionOffset = 0;
129
+ let indexOffset = 0;
130
+ let vertexBase = 0;
131
+ for (const mesh of group) {
132
+ positions.set(mesh.positions, positionOffset);
133
+ for (let i = 0; i < mesh.indices.length; i++) {
134
+ indices[indexOffset + i] = mesh.indices[i] + vertexBase;
135
+ }
136
+ positionOffset += mesh.positions.length;
137
+ indexOffset += mesh.indices.length;
138
+ // 3 floats per vertex; the next mesh's indices start after these vertices.
139
+ vertexBase += mesh.positions.length / 3;
140
+ }
141
+ return { positions, indices };
142
+ }
143
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/adapters/shared.ts"],"names":[],"mappings":"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"}
@@ -3,9 +3,11 @@
3
3
  * into representation-agnostic `ClashElement`s, and precompute the
4
4
  * void/host/assembly pair exclusions from IFC relationships.
5
5
  *
6
- * This module is the only part of the package that depends on
6
+ * This module (along with `ifcx.ts`, via `shared.ts`) depends on
7
7
  * `@ifc-lite/parser` / `@ifc-lite/query`; it is reached via the
8
- * `@ifc-lite/clash/step` subpath so the core stays version-neutral.
8
+ * `@ifc-lite/clash/step` subpath so the core stays version-neutral. The
9
+ * non-clashable-tag filter and per-entity mesh coalescing are shared with
10
+ * `ifcx.ts` through `./shared.ts` — see that module's doc comment for why.
9
11
  */
10
12
  import { type IfcDataStore } from '@ifc-lite/parser';
11
13
  import type { MeshData } from '@ifc-lite/geometry';
@@ -21,6 +23,63 @@ export interface StepAdapterOptions {
21
23
  modelId: string;
22
24
  /** When provided, `ref` is the federated globalId; otherwise the expressId. */
23
25
  federation?: FederationLike;
26
+ /**
27
+ * The federation offset the HOST has ALREADY added to every `mesh.expressId`,
28
+ * so this adapter can subtract it back out and address `store` in its own
29
+ * (local) id space. Default 0 — meshes are local.
30
+ *
31
+ * The viewer's loader shifts meshes into the global id space in place
32
+ * (`useIfcLoader`: `mesh.expressId = mesh.expressId + idOffset`) while
33
+ * `IfcDataStore` keeps LOCAL ids, so for every federated model past the first
34
+ * `mesh.expressId` is NOT a key into `store`. Without this, every lookup in
35
+ * the loop below misses: `key` degrades to the synthetic fallback, `tag`
36
+ * reads `Unknown`, name/storey come back empty, and `buildStepExclusions`
37
+ * finds no relationships at all — so void/host/assembly pairs silently stop
38
+ * being excluded. `ref` was wrong in the other direction, with
39
+ * `federation.toGlobalId` adding the offset a second time.
40
+ *
41
+ * `tag` degrades with the rest, despite the `node.type || mesh.ifcType`
42
+ * expression below reading as though the mesh could rescue it: every
43
+ * production `EntityTable` returns the literal string `'Unknown'` from
44
+ * `getTypeName` on a miss, and `'Unknown'` is truthy, so the `mesh.ifcType`
45
+ * arm is unreachable on a store lookup that missed. `Unknown` next to a blank
46
+ * name is the loudest on-screen symptom of this bug.
47
+ *
48
+ * The viewer's own compare path (`lib/compare/buildFingerprints.ts`) does the
49
+ * same subtraction for the same reason. The CLI / MCP / playground callers
50
+ * hand over local meshes and leave this at its `0` default.
51
+ *
52
+ * ## Optional ON PURPOSE — not an oversight
53
+ *
54
+ * The obvious hardening is to make this REQUIRED, and the repo has the
55
+ * precedent: `buildFingerprints.ts` declares `idOffset: number` and does this
56
+ * exact subtraction, which is why compare never had this bug. It is
57
+ * deliberately NOT copied here. `buildFingerprints` is app-internal
58
+ * (`apps/viewer`), free to break at will; `elementsFromStep` is published API
59
+ * — `@ifc-lite/clash` exposes it as the `./step` subpath export — so
60
+ * requiring the member is a breaking change for every external caller, all of
61
+ * which legitimately pass local meshes and would have to add a `0` to keep
62
+ * compiling. That is a major bump to harden one in-repo call site, on a
63
+ * patch-level bugfix.
64
+ *
65
+ * What covers the gap instead, since the optional signature is exactly what
66
+ * let the viewer wiring be deleted and stay green:
67
+ * - `apps/viewer/src/hooks/useClash.federated-id-offset.test.tsx` pins the
68
+ * viewer's call at the level that actually broke (it fails if
69
+ * `meshIdOffset` is dropped from `gatherElements`);
70
+ * - the total-miss `console.warn` at the end of `elementsFromStep` reports
71
+ * a forgotten offset at RUNTIME, in any host, including new ones — for
72
+ * any model whose store actually holds GlobalIds. It stays silent for a
73
+ * store that holds none (a GLB import), where a total miss is the normal
74
+ * state and warning would only teach the reader to ignore the message.
75
+ *
76
+ * A dev-only `expressId < 0` assert was considered and rejected: it fires
77
+ * only when the subtrahend is too LARGE, whereas the failure that shipped was
78
+ * a forgotten offset, i.e. a subtrahend of 0 producing positive, plausible,
79
+ * entirely wrong ids. It would not have caught this bug. The total-miss check
80
+ * keys on the damage instead, so it catches both directions.
81
+ */
82
+ meshIdOffset?: number;
24
83
  /** Aligns this model into the common world frame (RTC + building rotation). */
25
84
  worldTransform?: Mat4;
26
85
  /** Precompute void/host/assembly exclusions. Default true. */
@@ -40,5 +99,5 @@ export declare function elementsFromStep(options: StepAdapterOptions): StepAdapt
40
99
  * - element vs its own (meshed) opening
41
100
  * - members of the same `IfcRelAggregates` assembly
42
101
  */
43
- export declare function buildStepExclusions(store: IfcDataStore, byExpressId: Map<number, ClashElement>): ExclusionSet;
102
+ export declare function buildStepExclusions(store: IfcDataStore, byExpressId: Map<number, ClashElement[]>): ExclusionSet;
44
103
  //# sourceMappingURL=step.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/adapters/step.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEpE,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CACxD;AAuDD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,+EAA+E;IAC/E,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,8DAA8D;IAC9D,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAiBD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CAoF/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GACrC,YAAY,CAiCd"}
1
+ {"version":3,"file":"step.d.ts","sourceRoot":"","sources":["../../src/adapters/step.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGpE,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CACxD;AAMD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAuDG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,8DAA8D;IAC9D,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAiED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB,CA6L/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,YAAY,EACnB,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,GACvC,YAAY,CAuCd"}