@ifc-lite/parser 5.1.0 → 6.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 (199) hide show
  1. package/dist/classification-resolver.d.ts.map +1 -1
  2. package/dist/classification-resolver.js +35 -10
  3. package/dist/classification-resolver.js.map +1 -1
  4. package/dist/columnar-entity-preparation.d.ts +25 -0
  5. package/dist/columnar-entity-preparation.d.ts.map +1 -0
  6. package/dist/columnar-entity-preparation.js +282 -0
  7. package/dist/columnar-entity-preparation.js.map +1 -0
  8. package/dist/columnar-parser-indexes.d.ts +17 -1
  9. package/dist/columnar-parser-indexes.d.ts.map +1 -1
  10. package/dist/columnar-parser-indexes.js +31 -21
  11. package/dist/columnar-parser-indexes.js.map +1 -1
  12. package/dist/columnar-parser-root-attributes.d.ts +66 -0
  13. package/dist/columnar-parser-root-attributes.d.ts.map +1 -0
  14. package/dist/columnar-parser-root-attributes.js +245 -0
  15. package/dist/columnar-parser-root-attributes.js.map +1 -0
  16. package/dist/columnar-parser.d.ts +26 -63
  17. package/dist/columnar-parser.d.ts.map +1 -1
  18. package/dist/columnar-parser.js +384 -751
  19. package/dist/columnar-parser.js.map +1 -1
  20. package/dist/compact-entity-index-columns.d.ts +17 -0
  21. package/dist/compact-entity-index-columns.d.ts.map +1 -0
  22. package/dist/compact-entity-index-columns.js +15 -0
  23. package/dist/compact-entity-index-columns.js.map +1 -0
  24. package/dist/compact-entity-index-transport.d.ts +2 -12
  25. package/dist/compact-entity-index-transport.d.ts.map +1 -1
  26. package/dist/compact-entity-index-transport.js +1 -11
  27. package/dist/compact-entity-index-transport.js.map +1 -1
  28. package/dist/compact-entity-index.d.ts +6 -0
  29. package/dist/compact-entity-index.d.ts.map +1 -1
  30. package/dist/compact-entity-index.js +12 -20
  31. package/dist/compact-entity-index.js.map +1 -1
  32. package/dist/cost-extractor.d.ts +10 -0
  33. package/dist/cost-extractor.d.ts.map +1 -0
  34. package/dist/cost-extractor.js +369 -0
  35. package/dist/cost-extractor.js.map +1 -0
  36. package/dist/cost-schedule-2x3.d.ts +31 -0
  37. package/dist/cost-schedule-2x3.d.ts.map +1 -0
  38. package/dist/cost-schedule-2x3.js +75 -0
  39. package/dist/cost-schedule-2x3.js.map +1 -0
  40. package/dist/cost-types.d.ts +105 -0
  41. package/dist/cost-types.d.ts.map +1 -0
  42. package/dist/cost-types.js +5 -0
  43. package/dist/cost-types.js.map +1 -0
  44. package/dist/data-store-transport.d.ts +3 -2
  45. package/dist/data-store-transport.d.ts.map +1 -1
  46. package/dist/data-store-transport.js +10 -34
  47. package/dist/data-store-transport.js.map +1 -1
  48. package/dist/drop-census.d.ts +136 -0
  49. package/dist/drop-census.d.ts.map +1 -0
  50. package/dist/drop-census.js +53 -0
  51. package/dist/drop-census.js.map +1 -0
  52. package/dist/entity-refs-from-index.d.ts +10 -0
  53. package/dist/entity-refs-from-index.d.ts.map +1 -1
  54. package/dist/entity-refs-from-index.js +52 -36
  55. package/dist/entity-refs-from-index.js.map +1 -1
  56. package/dist/entity-scanner.d.ts +5 -0
  57. package/dist/entity-scanner.d.ts.map +1 -1
  58. package/dist/entity-scanner.js +30 -12
  59. package/dist/entity-scanner.js.map +1 -1
  60. package/dist/entity-type-byte-interner.d.ts +12 -0
  61. package/dist/entity-type-byte-interner.d.ts.map +1 -0
  62. package/dist/entity-type-byte-interner.js +66 -0
  63. package/dist/entity-type-byte-interner.js.map +1 -0
  64. package/dist/generated/ifc2x3/schema-registry.d.ts +50 -0
  65. package/dist/generated/ifc2x3/schema-registry.d.ts.map +1 -0
  66. package/dist/generated/ifc2x3/schema-registry.js +50052 -0
  67. package/dist/generated/ifc2x3/schema-registry.js.map +1 -0
  68. package/dist/generated/ifc4x3/schema-registry.d.ts +50 -0
  69. package/dist/generated/ifc4x3/schema-registry.d.ts.map +1 -0
  70. package/dist/generated/ifc4x3/schema-registry.js +71299 -0
  71. package/dist/generated/ifc4x3/schema-registry.js.map +1 -0
  72. package/dist/generated/schema-registry-by-version.d.ts +61 -0
  73. package/dist/generated/schema-registry-by-version.d.ts.map +1 -0
  74. package/dist/generated/schema-registry-by-version.js +86 -0
  75. package/dist/generated/schema-registry-by-version.js.map +1 -0
  76. package/dist/group-assignment-factor.d.ts +13 -0
  77. package/dist/group-assignment-factor.d.ts.map +1 -0
  78. package/dist/group-assignment-factor.js +30 -0
  79. package/dist/group-assignment-factor.js.map +1 -0
  80. package/dist/ifczip.d.ts +6 -0
  81. package/dist/ifczip.d.ts.map +1 -1
  82. package/dist/ifczip.js +20 -11
  83. package/dist/ifczip.js.map +1 -1
  84. package/dist/index.d.ts +10 -6
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +17 -7
  87. package/dist/index.js.map +1 -1
  88. package/dist/on-demand-extractors.d.ts +1 -0
  89. package/dist/on-demand-extractors.d.ts.map +1 -1
  90. package/dist/on-demand-extractors.js +2 -1
  91. package/dist/on-demand-extractors.js.map +1 -1
  92. package/dist/parser.worker.d.ts +6 -3
  93. package/dist/parser.worker.d.ts.map +1 -1
  94. package/dist/parser.worker.js +24 -12
  95. package/dist/parser.worker.js.map +1 -1
  96. package/dist/prepass-source-fingerprint.d.ts +3 -0
  97. package/dist/prepass-source-fingerprint.d.ts.map +1 -0
  98. package/dist/prepass-source-fingerprint.js +13 -0
  99. package/dist/prepass-source-fingerprint.js.map +1 -0
  100. package/dist/property-value-parser.d.ts +10 -0
  101. package/dist/property-value-parser.d.ts.map +1 -1
  102. package/dist/property-value-parser.js +40 -1
  103. package/dist/property-value-parser.js.map +1 -1
  104. package/dist/scan-entities-balanced.d.ts.map +1 -1
  105. package/dist/scan-entities-balanced.js +8 -6
  106. package/dist/scan-entities-balanced.js.map +1 -1
  107. package/dist/scan-worker-lexing.d.ts +14 -0
  108. package/dist/scan-worker-lexing.d.ts.map +1 -0
  109. package/dist/scan-worker-lexing.js +101 -0
  110. package/dist/scan-worker-lexing.js.map +1 -0
  111. package/dist/scan-worker-source.d.ts +1 -1
  112. package/dist/scan-worker-source.d.ts.map +1 -1
  113. package/dist/scan-worker-source.js +61 -59
  114. package/dist/scan-worker-source.js.map +1 -1
  115. package/dist/schedule-extractor.d.ts +2 -80
  116. package/dist/schedule-extractor.d.ts.map +1 -1
  117. package/dist/schedule-extractor.js +100 -225
  118. package/dist/schedule-extractor.js.map +1 -1
  119. package/dist/schedule-serializer-builders.d.ts +28 -0
  120. package/dist/schedule-serializer-builders.d.ts.map +1 -0
  121. package/dist/schedule-serializer-builders.js +163 -0
  122. package/dist/schedule-serializer-builders.js.map +1 -0
  123. package/dist/schedule-serializer.d.ts +6 -0
  124. package/dist/schedule-serializer.d.ts.map +1 -1
  125. package/dist/schedule-serializer.js +26 -165
  126. package/dist/schedule-serializer.js.map +1 -1
  127. package/dist/schedule-types.d.ts +211 -0
  128. package/dist/schedule-types.d.ts.map +1 -0
  129. package/dist/schedule-types.js +221 -0
  130. package/dist/schedule-types.js.map +1 -0
  131. package/dist/select-entity-columns.d.ts +7 -0
  132. package/dist/select-entity-columns.d.ts.map +1 -0
  133. package/dist/select-entity-columns.js +43 -0
  134. package/dist/select-entity-columns.js.map +1 -0
  135. package/dist/spatial-hierarchy-ambiguity.d.ts +39 -0
  136. package/dist/spatial-hierarchy-ambiguity.d.ts.map +1 -0
  137. package/dist/spatial-hierarchy-ambiguity.js +25 -0
  138. package/dist/spatial-hierarchy-ambiguity.js.map +1 -0
  139. package/dist/spatial-hierarchy-attributes.d.ts +54 -0
  140. package/dist/spatial-hierarchy-attributes.d.ts.map +1 -0
  141. package/dist/spatial-hierarchy-attributes.js +145 -0
  142. package/dist/spatial-hierarchy-attributes.js.map +1 -0
  143. package/dist/spatial-hierarchy-builder.d.ts +6 -38
  144. package/dist/spatial-hierarchy-builder.d.ts.map +1 -1
  145. package/dist/spatial-hierarchy-builder.js +48 -166
  146. package/dist/spatial-hierarchy-builder.js.map +1 -1
  147. package/dist/spatial-hierarchy-canonical-parent.d.ts +86 -0
  148. package/dist/spatial-hierarchy-canonical-parent.d.ts.map +1 -0
  149. package/dist/spatial-hierarchy-canonical-parent.js +212 -0
  150. package/dist/spatial-hierarchy-canonical-parent.js.map +1 -0
  151. package/dist/step-lexing.d.ts +1 -1
  152. package/dist/step-lexing.d.ts.map +1 -1
  153. package/dist/step-lexing.js +1 -56
  154. package/dist/step-lexing.js.map +1 -1
  155. package/dist/step-record-boundary.d.ts +28 -0
  156. package/dist/step-record-boundary.d.ts.map +1 -0
  157. package/dist/step-record-boundary.js +108 -0
  158. package/dist/step-record-boundary.js.map +1 -0
  159. package/dist/step-record-boundary.vectors.d.ts +58 -0
  160. package/dist/step-record-boundary.vectors.d.ts.map +1 -0
  161. package/dist/step-record-boundary.vectors.js +80 -0
  162. package/dist/step-record-boundary.vectors.js.map +1 -0
  163. package/dist/structural-extractor.d.ts +9 -0
  164. package/dist/structural-extractor.d.ts.map +1 -0
  165. package/dist/structural-extractor.js +310 -0
  166. package/dist/structural-extractor.js.map +1 -0
  167. package/dist/structural-load-extractor.d.ts +147 -0
  168. package/dist/structural-load-extractor.d.ts.map +1 -0
  169. package/dist/structural-load-extractor.js +178 -0
  170. package/dist/structural-load-extractor.js.map +1 -0
  171. package/dist/structural-step-values.d.ts +51 -0
  172. package/dist/structural-step-values.d.ts.map +1 -0
  173. package/dist/structural-step-values.js +109 -0
  174. package/dist/structural-step-values.js.map +1 -0
  175. package/dist/structural-types.d.ts +145 -0
  176. package/dist/structural-types.d.ts.map +1 -0
  177. package/dist/structural-types.js +5 -0
  178. package/dist/structural-types.js.map +1 -0
  179. package/dist/tokenizer.d.ts +11 -5
  180. package/dist/tokenizer.d.ts.map +1 -1
  181. package/dist/tokenizer.js +75 -21
  182. package/dist/tokenizer.js.map +1 -1
  183. package/dist/wasm-init-retry.d.ts +6 -42
  184. package/dist/wasm-init-retry.d.ts.map +1 -1
  185. package/dist/wasm-init-retry.js +6 -99
  186. package/dist/wasm-init-retry.js.map +1 -1
  187. package/dist/wasm-panic-forward.d.ts +7 -63
  188. package/dist/wasm-panic-forward.d.ts.map +1 -1
  189. package/dist/wasm-panic-forward.js +7 -100
  190. package/dist/wasm-panic-forward.js.map +1 -1
  191. package/dist/worker-index-publication.d.ts +43 -0
  192. package/dist/worker-index-publication.d.ts.map +1 -0
  193. package/dist/worker-index-publication.js +129 -0
  194. package/dist/worker-index-publication.js.map +1 -0
  195. package/dist/worker-parser.d.ts +5 -2
  196. package/dist/worker-parser.d.ts.map +1 -1
  197. package/dist/worker-parser.js +22 -10
  198. package/dist/worker-parser.js.map +1 -1
  199. package/package.json +5 -4
@@ -1,10 +1,11 @@
1
1
  /* This Source Code Form is subject to the terms of the Mozilla Public
2
2
  * License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
- import { IfcTypeEnum, RelationshipType, createLogger, isBuildingLikeSpatialType, isSpaceLikeSpatialType, isSpatialStructureType, isStoreyLikeSpatialType, IFC_BUILDING_STOREY_ELEVATION_INDEX, IFC_BUILDING_STOREY_PLACEMENT_INDEX, findStoreyByElevation, } from '@ifc-lite/data';
4
+ import { IfcTypeEnum, RelationshipType, isBuildingLikeSpatialType, isSpaceLikeSpatialType, isSpatialStructureType, isStoreyLikeSpatialType, findStoreyByElevation, spatialLookups, } from '@ifc-lite/data';
5
5
  import { EntityExtractor } from './entity-extractor.js';
6
- import { getAttributeNamesAcrossSchemas } from './ifc-schema.js';
7
- const log = createLogger('SpatialHierarchy');
6
+ import { computeCanonicalParent, computeReachableSpatialNodes } from './spatial-hierarchy-canonical-parent.js';
7
+ import { extractLongName, extractElevation, extractPlacementElevation, } from './spatial-hierarchy-attributes.js';
8
+ import { computeAmbiguousStorey } from './spatial-hierarchy-ambiguity.js';
8
9
  export class SpatialHierarchyBuilder {
9
10
  /**
10
11
  * Fresh-parse build. Extracts storey elevations from the source buffer.
@@ -36,6 +37,8 @@ export class SpatialHierarchyBuilder {
36
37
  elementToStorey: new Map(),
37
38
  elementToContainer: new Map(),
38
39
  visited: new Set(),
40
+ canonicalParent: computeCanonicalParent(entities, relationships),
41
+ reachableSpatialNodes: new Set(), // filled in below once IfcProject is known
39
42
  attrSource,
40
43
  attrExtractor: attrSource ? new EntityExtractor(attrSource.source) : undefined,
41
44
  };
@@ -47,6 +50,10 @@ export class SpatialHierarchyBuilder {
47
50
  }
48
51
  return undefined;
49
52
  }
53
+ // Which storeys buildNode will actually recurse into, computed up front
54
+ // so ContainsElements resolution below never depends on this node's own
55
+ // position in the traversal (#4310) - see computeReachableSpatialNodes.
56
+ ctx.reachableSpatialNodes = computeReachableSpatialNodes(projectIds[0], ctx.canonicalParent);
50
57
  const projectNode = this.buildNode(projectIds[0], ctx);
51
58
  if (ctx.byStorey.size === 0) {
52
59
  console.warn('[SpatialHierarchyBuilder] No storeys found in spatial hierarchy');
@@ -55,13 +62,6 @@ export class SpatialHierarchyBuilder {
55
62
  console.warn('[SpatialHierarchyBuilder] No buildings found in spatial hierarchy');
56
63
  }
57
64
  const { byStorey, byBuilding, bySite, bySpace, storeyElevations, elementToStorey, elementToContainer } = ctx;
58
- // Pre-build the element -> space lookup for O(1) getContainingSpace.
59
- const elementToSpace = new Map();
60
- for (const [spaceId, elementIds] of bySpace) {
61
- for (const elementId of elementIds) {
62
- elementToSpace.set(elementId, spaceId);
63
- }
64
- }
65
65
  return {
66
66
  project: projectNode,
67
67
  byStorey,
@@ -73,6 +73,7 @@ export class SpatialHierarchyBuilder {
73
73
  storeyHeights: new Map(),
74
74
  elementToStorey,
75
75
  elementToContainer,
76
+ ambiguousStorey: computeAmbiguousStorey(byStorey), // #4311
76
77
  getStoreyElements(storeyId) {
77
78
  return byStorey.get(storeyId) ?? [];
78
79
  },
@@ -82,29 +83,7 @@ export class SpatialHierarchyBuilder {
82
83
  // Z can never resolve to a different storey depending on entry path.
83
84
  return findStoreyByElevation(storeyElevations, z);
84
85
  },
85
- getContainingSpace(elementId) {
86
- return elementToSpace.get(elementId) ?? null;
87
- },
88
- getPath(elementId) {
89
- const path = [];
90
- const findPath = (node, targetId) => {
91
- path.push(node);
92
- // Match the node itself (so a promoted space/zone resolves) or one of
93
- // its contained elements.
94
- if (node.expressId === targetId || node.elements.includes(targetId)) {
95
- return true;
96
- }
97
- for (const child of node.children) {
98
- if (findPath(child, targetId)) {
99
- return true;
100
- }
101
- }
102
- path.pop();
103
- return false;
104
- };
105
- findPath(projectNode, elementId);
106
- return path;
107
- },
86
+ ...spatialLookups(projectNode, bySpace, elementToContainer),
108
87
  };
109
88
  }
110
89
  buildNode(expressId, ctx) {
@@ -116,17 +95,23 @@ export class SpatialHierarchyBuilder {
116
95
  // show both (issue #1634). It lives only in the raw record, so it needs the
117
96
  // source bytes; the source-less buildFromCache fallback leaves it undefined,
118
97
  // exactly like storey elevation.
119
- const rawLongName = this.extractLongName(expressId, ctx);
98
+ const rawLongName = extractLongName(expressId, ctx.attrSource, ctx.attrExtractor);
120
99
  // Fall back to LongName when Name is empty (common for IfcSpace). Left
121
100
  // empty, not a fabricated `Entity #<id>` — it flows into the export layer.
122
101
  const name = rawName || rawLongName || '';
123
102
  // Only keep LongName as a distinct descriptor when it adds something beyond
124
103
  // the primary label (never duplicate it into the secondary slot).
125
104
  const longName = rawLongName && rawLongName !== name ? rawLongName : undefined;
126
- // Guard against cyclic IfcRelAggregates chains (A aggregates B, B aggregates
127
- // A), which would otherwise recurse unbounded and overflow the stack. A
128
- // revisited node is returned as a leaf so the rest of the hierarchy still
129
- // builds.
105
+ // This is NOT what actually prevents unbounded recursion on a cyclic
106
+ // IfcRelAggregates chain (A aggregates B, B aggregates A) - it never
107
+ // fires today. Recursion here only ever follows a node's ONE canonical
108
+ // parent (computeCanonicalParent in spatial-hierarchy-canonical-parent.ts
109
+ // picks exactly one, and skips any candidate that would close a cycle
110
+ // back through the child, #4246), so a cycle can supply at most one
111
+ // recursion edge into any node - which structurally cannot loop. Kept as
112
+ // defence in depth in case that single-parent invariant is ever
113
+ // weakened; if it does fire, a revisited node is returned as a leaf so
114
+ // the rest of the hierarchy still builds.
130
115
  if (ctx.visited.has(expressId)) {
131
116
  return { expressId, type: typeEnum, name, longName, elevation: undefined, children: [], elements: [] };
132
117
  }
@@ -135,12 +120,12 @@ export class SpatialHierarchyBuilder {
135
120
  let elevation;
136
121
  if (typeEnum === IfcTypeEnum.IfcBuildingStorey && ctx.attrSource) {
137
122
  const { source, entityIndex, lengthUnitScale } = ctx.attrSource;
138
- let rawElevation = this.extractElevation(expressId, source, entityIndex);
123
+ let rawElevation = extractElevation(expressId, source, entityIndex);
139
124
  if (rawElevation === undefined) {
140
125
  // Elevation is optional and frequently null (Revit / ArchiCAD). Fall back
141
126
  // to the storey's Z from its ObjectPlacement so it still orders + lifts in
142
127
  // Exploded mode instead of collapsing to a single floor (#1289).
143
- rawElevation = this.extractPlacementElevation(expressId, source, entityIndex);
128
+ rawElevation = extractPlacementElevation(expressId, source, entityIndex);
144
129
  }
145
130
  if (rawElevation !== undefined) {
146
131
  elevation = rawElevation * lengthUnitScale;
@@ -177,6 +162,8 @@ export class SpatialHierarchyBuilder {
177
162
  return;
178
163
  const childType = entities.getTypeEnum(childId);
179
164
  if (isSpatialStructureType(childType) && childType !== IfcTypeEnum.IfcProject) {
165
+ if (ctx.canonicalParent.get(childId) !== expressId)
166
+ return; // canonical parent only, no phantom stub (#4095)
180
167
  spatialChildIds.add(childId);
181
168
  childNodes.push(this.buildNode(childId, ctx));
182
169
  }
@@ -201,6 +188,27 @@ export class SpatialHierarchyBuilder {
201
188
  }
202
189
  if (isStoreyLikeSpatialType(typeEnum)) {
203
190
  for (const elementId of containedElements) {
191
+ // First-declared wins on duplicate containment, matching containedIn()
192
+ // (#4248) - but only among storeys buildNode actually visits. A
193
+ // first-declared edge naming an unreachable storey (no path back to
194
+ // IfcProject, e.g. missing its own IfcRelAggregates edge) is not a
195
+ // real competing answer: buildNode never runs that storey's own
196
+ // branch, so nothing would ever claim the element there, and the
197
+ // element must not be dropped just because a later-declared but
198
+ // VIABLE storey lost a tie to a candidate that can't win (#4310).
199
+ // Only storey-like containers compete: a reachable IfcSpace edge
200
+ // declared first is not a storey answer, and letting it win here
201
+ // would leave the element with no elementToStorey entry at all
202
+ // (spaces never run this branch).
203
+ const containerEdges = relationships.inverse.getEdges(elementId, RelationshipType.ContainsElements);
204
+ const firstViableContainer = containerEdges.find((edge) => ctx.reachableSpatialNodes.has(edge.target) && isStoreyLikeSpatialType(entities.getTypeEnum(edge.target)));
205
+ // expressId is always reachable here (buildNode only runs on reachable
206
+ // nodes) and always has an edge to elementId (elementId came from THIS
207
+ // storey's own containedElements), so firstViableContainer is always
208
+ // defined - it can never fall through to the pre-#4310 "assign
209
+ // unconditionally" behavior by surprise.
210
+ if (firstViableContainer && firstViableContainer.target !== expressId)
211
+ continue; // a viable earlier-declared storey wins instead
204
212
  ctx.elementToStorey.set(elementId, expressId);
205
213
  // Propagate the storey assignment to aggregated descendants (e.g. an
206
214
  // IfcBuildingElementPart child of an IfcWall). Without this, parts have no
@@ -262,131 +270,5 @@ export class SpatialHierarchyBuilder {
262
270
  }
263
271
  return { expressId, type: typeEnum, name, longName, elevation, children: childNodes, elements: containedElements };
264
272
  }
265
- /**
266
- * Read an entity's LongName by schema attribute *name*. IfcSite / IfcBuilding /
267
- * IfcBuildingStorey / IfcSpace (and the IFC4.3 facility/infra containers)
268
- * declare LongName at index 7, but IfcProject carries it at a different slot,
269
- * so resolving by name (not a fixed index) stays correct across the IfcRoot
270
- * family. The lookup spans every bundled schema, so IFC4.3 leaves outside the
271
- * parser's IFC4 codegen pin resolve too. Returns the trimmed value, or
272
- * undefined when the type declares no LongName, it is empty, or no source
273
- * buffer is available (the buildFromCache path).
274
- */
275
- extractLongName(expressId, ctx) {
276
- if (!ctx.attrSource || !ctx.attrExtractor)
277
- return undefined;
278
- const ref = ctx.attrSource.entityIndex.byId.get(expressId);
279
- if (!ref)
280
- return undefined;
281
- try {
282
- const entity = ctx.attrExtractor.extractEntity(ref);
283
- if (!entity)
284
- return undefined;
285
- const idx = getAttributeNamesAcrossSchemas(entity.type).indexOf('LongName');
286
- if (idx < 0)
287
- return undefined;
288
- const raw = (entity.attributes || [])[idx];
289
- const value = typeof raw === 'string' ? raw.trim() : '';
290
- return value.length > 0 ? value : undefined;
291
- }
292
- catch (error) {
293
- log.caught('Failed to extract LongName', error, {
294
- operation: 'extractLongName',
295
- entityId: expressId,
296
- });
297
- return undefined;
298
- }
299
- }
300
- /**
301
- * Extract elevation from an IfcBuildingStorey. Elevation is attribute index 9
302
- * in both IFC2x3 and IFC4 (GlobalId, OwnerHistory, Name, Description,
303
- * ObjectType, ObjectPlacement, Representation, LongName, CompositionType,
304
- * Elevation).
305
- */
306
- extractElevation(expressId, source, entityIndex) {
307
- const ref = entityIndex.byId.get(expressId);
308
- if (!ref)
309
- return undefined;
310
- try {
311
- const extractor = new EntityExtractor(source);
312
- const entity = extractor.extractEntity(ref);
313
- if (!entity)
314
- return undefined;
315
- const attrs = entity.attributes || [];
316
- // Number from a raw value or a typed value like ['IFCLENGTHMEASURE', 3.0].
317
- const extractNumber = (val) => {
318
- if (typeof val === 'number')
319
- return val;
320
- if (Array.isArray(val) && val.length === 2 && typeof val[1] === 'number') {
321
- return val[1];
322
- }
323
- return undefined;
324
- };
325
- // Read ONLY the Elevation slot: a previous "scan every attribute for a
326
- // number < 10000" fallback wrongly treated reference attributes (parsed as
327
- // bare express-id numbers, e.g. OwnerHistory #3628 -> 3628) as elevations,
328
- // so a storey with a null Elevation got a garbage value instead of falling
329
- // through to the ObjectPlacement-Z fallback below (#1289).
330
- if (attrs.length > IFC_BUILDING_STOREY_ELEVATION_INDEX) {
331
- return extractNumber(attrs[IFC_BUILDING_STOREY_ELEVATION_INDEX]);
332
- }
333
- }
334
- catch (error) {
335
- log.caught('Failed to extract elevation', error, {
336
- operation: 'extractElevation',
337
- entityId: expressId,
338
- entityType: 'IfcBuildingStorey',
339
- });
340
- }
341
- return undefined;
342
- }
343
- /**
344
- * Resolve a storey's elevation from its ObjectPlacement, used as a fallback when
345
- * the Elevation attribute is null. Walks
346
- * IfcBuildingStorey.ObjectPlacement (IfcLocalPlacement)
347
- * -> RelativePlacement (IfcAxis2Placement3D)
348
- * -> Location (IfcCartesianPoint).Coordinates[2]
349
- * i.e. the storey's Z relative to its parent spatial container, which matches
350
- * the semantics of the Elevation attribute and avoids folding in any site-level
351
- * georeferencing Z. Returns the raw (unscaled) Z, or undefined when the chain
352
- * can't be resolved.
353
- */
354
- extractPlacementElevation(expressId, source, entityIndex) {
355
- try {
356
- const extractor = new EntityExtractor(source);
357
- const readAttrs = (id) => {
358
- const ref = entityIndex.byId.get(id);
359
- if (!ref)
360
- return undefined;
361
- return extractor.extractEntity(ref)?.attributes ?? undefined;
362
- };
363
- const placementId = readAttrs(expressId)?.[IFC_BUILDING_STOREY_PLACEMENT_INDEX];
364
- if (typeof placementId !== 'number')
365
- return undefined;
366
- // IfcLocalPlacement(PlacementRelTo, RelativePlacement) - RelativePlacement
367
- // (index 1) is the IfcAxis2Placement3D carrying this storey's own offset.
368
- const axisId = readAttrs(placementId)?.[1];
369
- if (typeof axisId !== 'number')
370
- return undefined;
371
- // IfcAxis2Placement3D(Location, Axis, RefDirection) - Location (index 0) is
372
- // an IfcCartesianPoint.
373
- const locationId = readAttrs(axisId)?.[0];
374
- if (typeof locationId !== 'number')
375
- return undefined;
376
- // IfcCartesianPoint.Coordinates (index 0) is a list [x, y, z].
377
- const coords = readAttrs(locationId)?.[0];
378
- if (Array.isArray(coords) && coords.length >= 3 && typeof coords[2] === 'number') {
379
- return coords[2];
380
- }
381
- }
382
- catch (error) {
383
- log.caught('Failed to extract placement elevation', error, {
384
- operation: 'extractPlacementElevation',
385
- entityId: expressId,
386
- entityType: 'IfcBuildingStorey',
387
- });
388
- }
389
- return undefined;
390
- }
391
273
  }
392
274
  //# sourceMappingURL=spatial-hierarchy-builder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spatial-hierarchy-builder.js","sourceRoot":"","sources":["../src/spatial-hierarchy-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spatial-hierarchy-builder.js","sourceRoot":"","sources":["../src/spatial-hierarchy-builder.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAc/D,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,yBAAyB,EACzB,sBAAsB,EACtB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,yCAAyC,CAAC;AAC/G,OAAO,EAEL,eAAe,EACf,gBAAgB,EAChB,yBAAyB,GAC1B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAyB1E,MAAM,OAAO,uBAAuB;IAClC;;;;;OAKG;IACH,KAAK,CACH,QAAqB,EACrB,aAAgC,EAChC,QAAqB,EACrB,MAAmC,EACnC,WAAwE,EACxE,kBAA0B,GAAG;QAE7B,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,IAAI,CAAC,CAAC;QACzG,kEAAkE;QAClE,OAAO,SAA6B,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,cAAc,CACZ,QAAqB,EACrB,aAAgC;QAEhC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC;IAEO,QAAQ,CACd,QAAqB,EACrB,aAAgC,EAChC,UAAuC,EACvC,gBAAyB;QAEzB,MAAM,GAAG,GAAiB;YACxB,QAAQ;YACR,aAAa;YACb,QAAQ,EAAE,IAAI,GAAG,EAAE;YACnB,UAAU,EAAE,IAAI,GAAG,EAAE;YACrB,MAAM,EAAE,IAAI,GAAG,EAAE;YACjB,OAAO,EAAE,IAAI,GAAG,EAAE;YAClB,gBAAgB,EAAE,IAAI,GAAG,EAAE;YAC3B,eAAe,EAAE,IAAI,GAAG,EAAE;YAC1B,kBAAkB,EAAE,IAAI,GAAG,EAAE;YAC7B,OAAO,EAAE,IAAI,GAAG,EAAE;YAClB,eAAe,EAAE,sBAAsB,CAAC,QAAQ,EAAE,aAAa,CAAC;YAChE,qBAAqB,EAAE,IAAI,GAAG,EAAE,EAAE,2CAA2C;YAC7E,UAAU;YACV,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;SAC/E,CAAC;QAEF,MAAM,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC9D,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;YAC1E,IAAI,gBAAgB,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACrD,CAAC;YACD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,wEAAwE;QACxE,wEAAwE;QACxE,wEAAwE;QACxE,GAAG,CAAC,qBAAqB,GAAG,4BAA4B,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,eAAe,CAAC,CAAC;QAE7F,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAEvD,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;QACpF,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,kBAAkB,EAAE,GAAG,GAAG,CAAC;QAG7G,OAAO;YACL,OAAO,EAAE,WAAW;YACpB,QAAQ;YACR,UAAU;YACV,MAAM;YACN,OAAO;YACP,gBAAgB;YAChB,2EAA2E;YAC3E,aAAa,EAAE,IAAI,GAAG,EAAkB;YACxC,eAAe;YACf,kBAAkB;YAClB,eAAe,EAAE,sBAAsB,CAAC,QAAQ,CAAC,EAAE,QAAQ;YAE3D,iBAAiB,CAAC,QAAgB;gBAChC,OAAO,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACtC,CAAC;YAED,oBAAoB,CAAC,CAAS;gBAC5B,qEAAqE;gBACrE,uEAAuE;gBACvE,qEAAqE;gBACrE,OAAO,qBAAqB,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC;YACpD,CAAC;YAED,GAAG,cAAc,CAAC,WAAW,EAAE,OAAO,EAAE,kBAAkB,CAAC;SAC5D,CAAC;IACJ,CAAC;IAEO,SAAS,CAAC,SAAiB,EAAE,GAAiB;QACpD,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;QACxC,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC5C,4EAA4E;QAC5E,8EAA8E;QAC9E,4EAA4E;QAC5E,6EAA6E;QAC7E,iCAAiC;QACjC,MAAM,WAAW,GAAG,eAAe,CAAC,SAAS,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;QAClF,uEAAuE;QACvE,2EAA2E;QAC3E,MAAM,IAAI,GAAG,OAAO,IAAI,WAAW,IAAI,EAAE,CAAC;QAC1C,4EAA4E;QAC5E,kEAAkE;QAClE,MAAM,QAAQ,GAAG,WAAW,IAAI,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;QAE/E,qEAAqE;QACrE,qEAAqE;QACrE,uEAAuE;QACvE,0EAA0E;QAC1E,sEAAsE;QACtE,oEAAoE;QACpE,yEAAyE;QACzE,gEAAgE;QAChE,uEAAuE;QACvE,0CAA0C;QAC1C,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QACzG,CAAC;QACD,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAE3B,6EAA6E;QAC7E,IAAI,SAA6B,CAAC;QAClC,IAAI,QAAQ,KAAK,WAAW,CAAC,iBAAiB,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YACjE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC;YAChE,IAAI,YAAY,GAAG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;YACpE,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,0EAA0E;gBAC1E,2EAA2E;gBAC3E,iEAAiE;gBACjE,YAAY,GAAG,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;gBAC/B,SAAS,GAAG,YAAY,GAAG,eAAe,CAAC;gBAC3C,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QAED,mEAAmE;QACnE,MAAM,oBAAoB,GAAG,aAAa,CAAC,UAAU,CAAC,SAAS,EAAE,gBAAgB,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC;QAE/G,6EAA6E;QAC7E,8EAA8E;QAC9E,4EAA4E;QAC5E,4EAA4E;QAC5E,8EAA8E;QAC9E,mEAAmE;QACnE,MAAM,iBAAiB,GAAa,EAAE,CAAC;QACvC,MAAM,wBAAwB,GAAa,EAAE,CAAC;QAC9C,KAAK,MAAM,EAAE,IAAI,oBAAoB,EAAE,CAAC;YACtC,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC3C,IAAI,sBAAsB,CAAC,SAAS,CAAC,IAAI,SAAS,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;gBAC9E,wBAAwB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpC,CAAC;iBAAM,CAAC;gBACN,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAED,8DAA8D;QAC9D,MAAM,kBAAkB,GAAG,aAAa,CAAC,UAAU,CAAC,SAAS,EAAE,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAEvG,8EAA8E;QAC9E,4DAA4D;QAC5D,MAAM,UAAU,GAAkB,EAAE,CAAC;QACrC,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;QAC1C,MAAM,eAAe,GAAG,CAAC,OAAe,EAAE,EAAE;YAC1C,IAAI,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC;gBAAE,OAAO;YACzC,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YAChD,IAAI,sBAAsB,CAAC,SAAS,CAAC,IAAI,SAAS,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;gBAC9E,IAAI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS;oBAAE,OAAO,CAAC,iDAAiD;gBAC7G,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAC7B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAChD,CAAC;QACH,CAAC,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,kBAAkB;YAAE,eAAe,CAAC,OAAO,CAAC,CAAC;QACnE,KAAK,MAAM,OAAO,IAAI,wBAAwB;YAAE,eAAe,CAAC,OAAO,CAAC,CAAC;QAEzE,qDAAqD;QACrD,IAAI,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QACjD,CAAC;aAAM,IAAI,yBAAyB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QACnD,CAAC;aAAM,IAAI,QAAQ,KAAK,WAAW,CAAC,OAAO,EAAE,CAAC;YAC5C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QAC/C,CAAC;aAAM,IAAI,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5C,0EAA0E;YAC1E,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QAChD,CAAC;QAED,IAAI,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;YACtC,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;gBAC1C,uEAAuE;gBACvE,gEAAgE;gBAChE,oEAAoE;gBACpE,mEAAmE;gBACnE,gEAAgE;gBAChE,iEAAiE;gBACjE,gEAAgE;gBAChE,kEAAkE;gBAClE,iEAAiE;gBACjE,iEAAiE;gBACjE,+DAA+D;gBAC/D,kCAAkC;gBAClC,MAAM,cAAc,GAAG,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;gBACpG,MAAM,oBAAoB,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CACxD,GAAG,CAAC,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,uBAAuB,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBAC5G,uEAAuE;gBACvE,uEAAuE;gBACvE,qEAAqE;gBACrE,+DAA+D;gBAC/D,yCAAyC;gBACzC,IAAI,oBAAoB,IAAI,oBAAoB,CAAC,MAAM,KAAK,SAAS;oBAAE,SAAS,CAAC,gDAAgD;gBACjI,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;gBAC9C,qEAAqE;gBACrE,2EAA2E;gBAC3E,yEAAyE;gBACzE,2EAA2E;gBAC3E,0CAA0C;gBAC1C,MAAM,KAAK,GAAa,CAAC,SAAS,CAAC,CAAC;gBACpC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC1C,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,EAAY,CAAC;oBACtC,MAAM,cAAc,GAAG,aAAa,CAAC,UAAU,CAAC,OAAO,EAAE,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;oBACjG,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;wBACjC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;4BAAE,SAAS;wBAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;wBACd,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;4BAClC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;wBAC1C,CAAC;wBACD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAClB,CAAC;gBACH,CAAC;YACH,CAAC;YACD,8EAA8E;YAC9E,0EAA0E;YAC1E,0CAA0C;YAC1C,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;gBACtC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;oBACtC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBAC9C,CAAC;YACH,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,2EAA2E;QAC3E,yEAAyE;QACzE,4EAA4E;QAC5E,qEAAqE;QACrE,4EAA4E;QAC5E,wEAAwE;QACxE,0DAA0D;QAC1D,IAAI,QAAQ,KAAK,WAAW,CAAC,UAAU,EAAE,CAAC;YACxC,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;gBAC1C,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;gBACjD,MAAM,KAAK,GAAa,CAAC,SAAS,CAAC,CAAC;gBACpC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAS,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC1C,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACxB,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,EAAY,CAAC;oBACtC,MAAM,cAAc,GAAG,aAAa,CAAC,UAAU,CAAC,OAAO,EAAE,gBAAgB,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;oBACjG,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;wBACjC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;4BAAE,SAAS;wBAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;wBACd,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;4BACrC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;wBAC7C,CAAC;wBACD,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAClB,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IACrH,CAAC;CACF"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Canonical-parent resolution for `SpatialHierarchyBuilder` (split out to stay
3
+ * under the module-size budget, #4095).
4
+ */
5
+ import type { EntityTable, RelationshipGraph } from '@ifc-lite/data';
6
+ /**
7
+ * Is `candidateParent` reachable from `childId` by walking forward
8
+ * `IfcRelAggregates` edges (i.e. is `childId` an ANCESTOR of `candidateParent`
9
+ * in the raw, unresolved aggregation graph)? Used only to disqualify a tied
10
+ * candidate parent that would close a cycle back through the child itself -
11
+ * see the doc comment on `computeCanonicalParent` for why that specific shape
12
+ * needs a check at all. Bounded to `childId`'s own (raw) aggregation
13
+ * subtree, so it only costs anything on an already-malformed file where a
14
+ * child has more than one candidate Aggregates parent - the common case
15
+ * (one candidate) never calls this.
16
+ */
17
+ /**
18
+ * Upper bound on aggregate-graph node visits spent on back-edge cycle checks
19
+ * for one file. The check only runs for children named by MORE THAN ONE
20
+ * IfcRelAggregates (already malformed), and costs one descendant walk per
21
+ * such child - O(V+E) each - so a crafted file with thousands of contested
22
+ * children could otherwise burn O(C·(V+E)). Past the budget the resolver
23
+ * falls back to plain first-declared-wins (the pre-#4285 behaviour) and says
24
+ * so once, instead of stalling the parse.
25
+ */
26
+ export declare const CYCLE_CHECK_VISIT_BUDGET = 2000000;
27
+ /**
28
+ * Resolve each spatial-structure entity's ONE canonical parent, globally,
29
+ * before any recursion starts - so the result cannot depend on traversal
30
+ * order. Mirrors apps/server's `canonical_parent` (`spatial.rs`, #3973):
31
+ *
32
+ * 1. IfcRelAggregates always wins over mere containment. A child aggregated
33
+ * by more than one parent (a malformed file) resolves to the parent
34
+ * whose `IfcRelAggregates` was declared FIRST in the file - STEP does
35
+ * not require express ids to ascend with declaration position, so a
36
+ * lowest-express-id tie-break can disagree with declaration order (a
37
+ * legally-valid file can declare a high-id relationship before a
38
+ * low-id one). `relationships.inverse.getEdges` returns edges in
39
+ * declaration order: `RelationshipGraphBuilder.addEdge` is called by
40
+ * the parser while it scans `IfcRel*` records in file/byte order (see
41
+ * `columnar-parser.ts`'s relationship loop), and `buildCSR`'s counting
42
+ * sort is stable per key (`relationship-graph.ts`) - it scatters edges
43
+ * for the same child in the order they were appended, never
44
+ * reordering by id. So `edges[0]` for a given child is the
45
+ * first-declared parent edge; no id comparison is needed or correct -
46
+ * EXCEPT that a candidate closing a cycle back through the child is
47
+ * skipped first (see `aggregatedDescendants`, #4246): a mutual or
48
+ * longer aggregation back-edge cannot win a tie against a candidate that
49
+ * doesn't orphan the child's own subtree from itself. Each time that
50
+ * happens, a warning is logged (always-visible, like the existing
51
+ * "No storeys/buildings found" warnings below) naming the child and the
52
+ * disqualified candidate - the only signal a caller gets that a
53
+ * malformed back-edge was found and repaired, short of building a
54
+ * dedicated report (out of scope here; see the #4208 semantic drop
55
+ * census for that shape of reporting - a different layer: per-STEP-class
56
+ * scan/retain counts collected during columnar categorization, not a
57
+ * graph-repair event like this one).
58
+ * 2. Only when a child has NO aggregates edge at all does a containment edge
59
+ * (IfcRelContainedInSpatialStructure targeting a spatial-structure type -
60
+ * the Revit Family/Dynamo `IfcSpace`/`IfcSpatialZone` pattern, #1075)
61
+ * get to claim it, with the same first-declared tie-break.
62
+ *
63
+ * `SpatialHierarchyBuilder.buildNode`'s `addSpatialChild` then only recurses
64
+ * into a child from its canonical parent - every other parent that also
65
+ * names the child drops the edge instead of adding an empty-stub duplicate
66
+ * (#4095).
67
+ */
68
+ export declare function computeCanonicalParent(entities: EntityTable, relationships: RelationshipGraph, options?: {
69
+ cycleCheckVisitBudget?: number;
70
+ }): Map<number, number>;
71
+ /**
72
+ * Which spatial-structure nodes will `SpatialHierarchyBuilder.buildNode`
73
+ * actually visit, starting from `projectId`? Mirrors `addSpatialChild`
74
+ * exactly: a node is visited iff it is `projectId` itself, or its
75
+ * `canonicalParent` entry points to an already-visited node - the same
76
+ * check `addSpatialChild` makes before recursing (`canonicalParent.get
77
+ * (childId) === expressId`). Computed as one forward walk over
78
+ * `canonicalParent` (childId -> parentId) up front, so a storey's
79
+ * reachability never depends on where in the traversal it happens to sit
80
+ * (#4310): a node named only by an unreachable storey - one with no path
81
+ * back to `projectId`, e.g. a malformed file where a storey has no
82
+ * `IfcRelAggregates` edge at all - is never in this set, exactly as
83
+ * `buildNode` would never recurse into it.
84
+ */
85
+ export declare function computeReachableSpatialNodes(projectId: number, canonicalParent: Map<number, number>): Set<number>;
86
+ //# sourceMappingURL=spatial-hierarchy-canonical-parent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spatial-hierarchy-canonical-parent.d.ts","sourceRoot":"","sources":["../src/spatial-hierarchy-canonical-parent.ts"],"names":[],"mappings":"AAIA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAKrE;;;;;;;;;;GAUG;AACH;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,UAAY,CAAC;AA4BlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,WAAW,EACrB,aAAa,EAAE,iBAAiB,EAChC,OAAO,GAAE;IAAE,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/C,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA6FrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,GAAG,CAAC,MAAM,CAAC,CAsBb"}
@@ -0,0 +1,212 @@
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 { IfcTypeEnum, RelationshipType, createLogger, isSpatialStructureType } from '@ifc-lite/data';
5
+ const log = createLogger('SpatialHierarchy');
6
+ /**
7
+ * Is `candidateParent` reachable from `childId` by walking forward
8
+ * `IfcRelAggregates` edges (i.e. is `childId` an ANCESTOR of `candidateParent`
9
+ * in the raw, unresolved aggregation graph)? Used only to disqualify a tied
10
+ * candidate parent that would close a cycle back through the child itself -
11
+ * see the doc comment on `computeCanonicalParent` for why that specific shape
12
+ * needs a check at all. Bounded to `childId`'s own (raw) aggregation
13
+ * subtree, so it only costs anything on an already-malformed file where a
14
+ * child has more than one candidate Aggregates parent - the common case
15
+ * (one candidate) never calls this.
16
+ */
17
+ /**
18
+ * Upper bound on aggregate-graph node visits spent on back-edge cycle checks
19
+ * for one file. The check only runs for children named by MORE THAN ONE
20
+ * IfcRelAggregates (already malformed), and costs one descendant walk per
21
+ * such child - O(V+E) each - so a crafted file with thousands of contested
22
+ * children could otherwise burn O(C·(V+E)). Past the budget the resolver
23
+ * falls back to plain first-declared-wins (the pre-#4285 behaviour) and says
24
+ * so once, instead of stalling the parse.
25
+ */
26
+ export const CYCLE_CHECK_VISIT_BUDGET = 2_000_000;
27
+ /**
28
+ * Aggregated descendants of `childId` (transitive, forward `Aggregates`),
29
+ * charged against `budget`. Returns null when the budget ran out mid-walk
30
+ * (the partial set must not be used - a missing descendant reads as "no
31
+ * cycle", which is the wrong side to err on).
32
+ */
33
+ function aggregatedDescendants(childId, relationships, budget) {
34
+ const visited = new Set([childId]);
35
+ const stack = [childId];
36
+ while (stack.length > 0) {
37
+ const current = stack.pop();
38
+ for (const kid of relationships.getRelated(current, RelationshipType.Aggregates, 'forward')) {
39
+ if (--budget.visits < 0)
40
+ return null;
41
+ if (!visited.has(kid)) {
42
+ visited.add(kid);
43
+ stack.push(kid);
44
+ }
45
+ }
46
+ }
47
+ return visited;
48
+ }
49
+ /**
50
+ * Resolve each spatial-structure entity's ONE canonical parent, globally,
51
+ * before any recursion starts - so the result cannot depend on traversal
52
+ * order. Mirrors apps/server's `canonical_parent` (`spatial.rs`, #3973):
53
+ *
54
+ * 1. IfcRelAggregates always wins over mere containment. A child aggregated
55
+ * by more than one parent (a malformed file) resolves to the parent
56
+ * whose `IfcRelAggregates` was declared FIRST in the file - STEP does
57
+ * not require express ids to ascend with declaration position, so a
58
+ * lowest-express-id tie-break can disagree with declaration order (a
59
+ * legally-valid file can declare a high-id relationship before a
60
+ * low-id one). `relationships.inverse.getEdges` returns edges in
61
+ * declaration order: `RelationshipGraphBuilder.addEdge` is called by
62
+ * the parser while it scans `IfcRel*` records in file/byte order (see
63
+ * `columnar-parser.ts`'s relationship loop), and `buildCSR`'s counting
64
+ * sort is stable per key (`relationship-graph.ts`) - it scatters edges
65
+ * for the same child in the order they were appended, never
66
+ * reordering by id. So `edges[0]` for a given child is the
67
+ * first-declared parent edge; no id comparison is needed or correct -
68
+ * EXCEPT that a candidate closing a cycle back through the child is
69
+ * skipped first (see `aggregatedDescendants`, #4246): a mutual or
70
+ * longer aggregation back-edge cannot win a tie against a candidate that
71
+ * doesn't orphan the child's own subtree from itself. Each time that
72
+ * happens, a warning is logged (always-visible, like the existing
73
+ * "No storeys/buildings found" warnings below) naming the child and the
74
+ * disqualified candidate - the only signal a caller gets that a
75
+ * malformed back-edge was found and repaired, short of building a
76
+ * dedicated report (out of scope here; see the #4208 semantic drop
77
+ * census for that shape of reporting - a different layer: per-STEP-class
78
+ * scan/retain counts collected during columnar categorization, not a
79
+ * graph-repair event like this one).
80
+ * 2. Only when a child has NO aggregates edge at all does a containment edge
81
+ * (IfcRelContainedInSpatialStructure targeting a spatial-structure type -
82
+ * the Revit Family/Dynamo `IfcSpace`/`IfcSpatialZone` pattern, #1075)
83
+ * get to claim it, with the same first-declared tie-break.
84
+ *
85
+ * `SpatialHierarchyBuilder.buildNode`'s `addSpatialChild` then only recurses
86
+ * into a child from its canonical parent - every other parent that also
87
+ * names the child drops the edge instead of adding an empty-stub duplicate
88
+ * (#4095).
89
+ */
90
+ export function computeCanonicalParent(entities, relationships, options = {}) {
91
+ const canonicalParent = new Map();
92
+ const visitBudget = options.cycleCheckVisitBudget ?? CYCLE_CHECK_VISIT_BUDGET;
93
+ const cycleBudget = { visits: visitBudget };
94
+ let cycleBudgetExhausted = false;
95
+ const claimFirstDeclaredParent = (predicate, relType) => {
96
+ for (const childId of relationships.inverse.offsets.keys()) {
97
+ if (canonicalParent.has(childId) || !predicate(childId))
98
+ continue;
99
+ const edges = relationships.inverse.getEdges(childId, relType);
100
+ if (edges.length === 0)
101
+ continue;
102
+ // `edges[0]` is the first-declared edge of this type for this child -
103
+ // see the doc comment above for why the CSR preserves declaration
104
+ // order here. This mirrors apps/server's `canonical_parent`
105
+ // (`spatial.rs`), which does `entry(...).or_insert(...)` while
106
+ // iterating relationships in file-scan order: first occurrence wins.
107
+ let winner = edges[0];
108
+ if (relType === RelationshipType.Aggregates && edges.length > 1) {
109
+ // A child named as the target of more than one IfcRelAggregates is
110
+ // already a malformed file, but one shape needs a special rule: a
111
+ // BACK-EDGE, where a candidate parent P is itself a (possibly
112
+ // indirect) AGGREGATED DESCENDANT of this very child - i.e. taking P
113
+ // as childId's parent would close a cycle back through childId. That
114
+ // is the STEP-authoring-tool mistake of declaring an aggregation
115
+ // pair in both directions (#4246, the direct 2-node case; the same
116
+ // shape generalizes to a longer A->B->C->A chain). If the back-edge
117
+ // is declared before the real parent edge, plain first-declared-wins
118
+ // picks P as childId's canonical parent; P's own resolution (walking
119
+ // the SAME cycle) then independently lands back on a node inside the
120
+ // cycle too, so the whole cycle points at itself and none of it is
121
+ // reachable from IfcProject - orphaning whatever real subtree hung
122
+ // off any node in the cycle.
123
+ //
124
+ // Skip any candidate edge that closes a cycle through childId and
125
+ // take the first REMAINING candidate, still by declaration order -
126
+ // this changes nothing when a child has only one candidate (the
127
+ // overwhelmingly common case) or when none of its candidates close a
128
+ // cycle (the genuine multiple-real-parents case, #4095, which this
129
+ // loop never even sees more than one Aggregates edge for - #4095's
130
+ // contested child has exactly one Aggregates edge naming it; its
131
+ // OTHER "parent" only contains it). If EVERY candidate closes a
132
+ // cycle (a more degenerate file than anything observed), fall
133
+ // through to plain first-declared so the child is never left
134
+ // without a parent.
135
+ //
136
+ // One descendant walk per contested child (not per candidate), under a
137
+ // file-wide visit budget - see CYCLE_CHECK_VISIT_BUDGET.
138
+ const descendants = cycleBudgetExhausted ? null : aggregatedDescendants(childId, relationships, cycleBudget);
139
+ if (descendants === null) {
140
+ if (!cycleBudgetExhausted) {
141
+ cycleBudgetExhausted = true;
142
+ log.warn(`Aggregation back-edge cycle checks stopped after ${visitBudget} graph visits; ` +
143
+ 'remaining multi-parent children resolve to their first-declared IfcRelAggregates edge');
144
+ }
145
+ }
146
+ else {
147
+ const rejected = [];
148
+ const nonCyclic = edges.find((edge) => {
149
+ const cyclic = descendants.has(edge.target);
150
+ if (cyclic)
151
+ rejected.push(edge.target);
152
+ return !cyclic;
153
+ });
154
+ if (nonCyclic && nonCyclic !== winner) {
155
+ log.warn(`Ignored ${rejected.length} aggregation back-edge cycle(s): #${childId} kept parent #${nonCyclic.target}, ` +
156
+ `not ${rejected.map((id) => `#${id}`).join(', ')} (each would have closed a cycle back through #${childId})`);
157
+ winner = nonCyclic;
158
+ }
159
+ }
160
+ }
161
+ // Inverse edges flip source/target, so `target` here is the original
162
+ // relationship's `relating_id` (the parent).
163
+ canonicalParent.set(childId, winner.target);
164
+ }
165
+ };
166
+ // Pass 1: aggregation, unconditionally - it always wins.
167
+ claimFirstDeclaredParent(() => true, RelationshipType.Aggregates);
168
+ // Pass 2: promotion-by-containment, only for children aggregation left unclaimed.
169
+ claimFirstDeclaredParent((childId) => {
170
+ const childType = entities.getTypeEnum(childId);
171
+ return isSpatialStructureType(childType) && childType !== IfcTypeEnum.IfcProject;
172
+ }, RelationshipType.ContainsElements);
173
+ return canonicalParent;
174
+ }
175
+ /**
176
+ * Which spatial-structure nodes will `SpatialHierarchyBuilder.buildNode`
177
+ * actually visit, starting from `projectId`? Mirrors `addSpatialChild`
178
+ * exactly: a node is visited iff it is `projectId` itself, or its
179
+ * `canonicalParent` entry points to an already-visited node - the same
180
+ * check `addSpatialChild` makes before recursing (`canonicalParent.get
181
+ * (childId) === expressId`). Computed as one forward walk over
182
+ * `canonicalParent` (childId -> parentId) up front, so a storey's
183
+ * reachability never depends on where in the traversal it happens to sit
184
+ * (#4310): a node named only by an unreachable storey - one with no path
185
+ * back to `projectId`, e.g. a malformed file where a storey has no
186
+ * `IfcRelAggregates` edge at all - is never in this set, exactly as
187
+ * `buildNode` would never recurse into it.
188
+ */
189
+ export function computeReachableSpatialNodes(projectId, canonicalParent) {
190
+ const childrenOf = new Map();
191
+ for (const [childId, parentId] of canonicalParent) {
192
+ let siblings = childrenOf.get(parentId);
193
+ if (!siblings) {
194
+ siblings = [];
195
+ childrenOf.set(parentId, siblings);
196
+ }
197
+ siblings.push(childId);
198
+ }
199
+ const reachable = new Set([projectId]);
200
+ const stack = [projectId];
201
+ while (stack.length > 0) {
202
+ const current = stack.pop();
203
+ for (const childId of childrenOf.get(current) ?? []) {
204
+ if (reachable.has(childId))
205
+ continue; // also guards a canonicalParent cycle from looping forever
206
+ reachable.add(childId);
207
+ stack.push(childId);
208
+ }
209
+ }
210
+ return reachable;
211
+ }
212
+ //# sourceMappingURL=spatial-hierarchy-canonical-parent.js.map