@ifc-lite/export 1.7.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/dist/index.d.ts CHANGED
@@ -6,4 +6,6 @@ export { ParquetExporter, type ParquetExportOptions } from './parquet-exporter.j
6
6
  export { CSVExporter, type CSVExportOptions } from './csv-exporter.js';
7
7
  export { JSONLDExporter, type JSONLDExportOptions } from './jsonld-exporter.js';
8
8
  export { StepExporter, exportToStep, type StepExportOptions, type StepExportResult } from './step-exporter.js';
9
+ export { MergedExporter, type MergeModelInput, type MergeExportOptions, type MergeExportResult } from './merged-exporter.js';
10
+ export { collectReferencedEntityIds, getVisibleEntityIds, collectStyleEntities } from './reference-collector.js';
9
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC/G,OAAO,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC7H,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -9,4 +9,6 @@ export { ParquetExporter } from './parquet-exporter.js';
9
9
  export { CSVExporter } from './csv-exporter.js';
10
10
  export { JSONLDExporter } from './jsonld-exporter.js';
11
11
  export { StepExporter, exportToStep } from './step-exporter.js';
12
+ export { MergedExporter } from './merged-exporter.js';
13
+ export { collectReferencedEntityIds, getVisibleEntityIds, collectStyleEntities } from './reference-collector.js';
12
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;GAEG;AAEH,OAAO,EAAE,YAAY,EAA0B,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAA6B,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAyB,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,cAAc,EAA4B,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAiD,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;GAEG;AAEH,OAAO,EAAE,YAAY,EAA0B,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,eAAe,EAA6B,MAAM,uBAAuB,CAAC;AACnF,OAAO,EAAE,WAAW,EAAyB,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,cAAc,EAA4B,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,YAAY,EAAiD,MAAM,oBAAoB,CAAC;AAC/G,OAAO,EAAE,cAAc,EAAyE,MAAM,sBAAsB,CAAC;AAC7H,OAAO,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Merged IFC STEP exporter
3
+ *
4
+ * Combines multiple IFC models into a single STEP file, similar to
5
+ * IfcOpenShell's MergeProjects recipe. Handles ID remapping, spatial
6
+ * structure unification, and infrastructure deduplication.
7
+ */
8
+ import type { IfcDataStore } from '@ifc-lite/parser';
9
+ /**
10
+ * A model to be included in the merge, with its data store and metadata.
11
+ */
12
+ export interface MergeModelInput {
13
+ /** Unique model identifier */
14
+ id: string;
15
+ /** Display name */
16
+ name: string;
17
+ /** Parsed IFC data store (must have source buffer) */
18
+ dataStore: IfcDataStore;
19
+ }
20
+ /**
21
+ * Options for merged STEP export
22
+ */
23
+ export interface MergeExportOptions {
24
+ /** IFC schema version for the output file */
25
+ schema: 'IFC2X3' | 'IFC4' | 'IFC4X3';
26
+ /** File description */
27
+ description?: string;
28
+ /** Author name */
29
+ author?: string;
30
+ /** Organization name */
31
+ organization?: string;
32
+ /** Application name (defaults to 'ifc-lite') */
33
+ application?: string;
34
+ /** Output filename */
35
+ filename?: string;
36
+ /**
37
+ * Strategy for merging the project hierarchy.
38
+ * - 'keep-first': Keep the first model's IfcProject as the root
39
+ */
40
+ projectStrategy?: 'keep-first';
41
+ /** Apply visibility filtering to each model before merging */
42
+ visibleOnly?: boolean;
43
+ /** Hidden entity IDs per model (local expressIds) */
44
+ hiddenEntityIdsByModel?: Map<string, Set<number>>;
45
+ /** Isolated entity IDs per model (null = no isolation) */
46
+ isolatedEntityIdsByModel?: Map<string, Set<number> | null>;
47
+ }
48
+ /**
49
+ * Result of merged STEP export
50
+ */
51
+ export interface MergeExportResult {
52
+ /** STEP file content */
53
+ content: string;
54
+ /** Statistics */
55
+ stats: {
56
+ /** Number of models merged */
57
+ modelCount: number;
58
+ /** Total entities in the output */
59
+ totalEntityCount: number;
60
+ /** File size in bytes */
61
+ fileSize: number;
62
+ };
63
+ }
64
+ /**
65
+ * Merges multiple IFC models into a single STEP file.
66
+ *
67
+ * Uses the same approach as IfcOpenShell's MergeProjects recipe, extended
68
+ * with spatial hierarchy unification:
69
+ * 1. First model's entities use their original IDs
70
+ * 2. Subsequent models' IDs are offset to avoid collisions
71
+ * 3. IfcProject is unified — all references remapped to the first model's project
72
+ * 4. Spatial structure (Site, Building, Storey) is unified by name/elevation:
73
+ * matching entities are remapped to the first model's equivalents so that
74
+ * products from all models end up in the same unified tree
75
+ * 5. Duplicate entities and shared infrastructure (units, contexts) are skipped
76
+ */
77
+ export declare class MergedExporter {
78
+ private models;
79
+ constructor(models: MergeModelInput[]);
80
+ export(options: MergeExportOptions): MergeExportResult;
81
+ /**
82
+ * Remap all #ID references in a STEP entity line.
83
+ * Applies offset to all IDs, then overrides with specific remappings.
84
+ */
85
+ private remapEntityText;
86
+ /**
87
+ * Find entity IDs of shared infrastructure types in a data store.
88
+ * Returns a map of uppercase type name → array of expressIds.
89
+ */
90
+ private findInfrastructureEntities;
91
+ /**
92
+ * Find entity IDs of a specific type in a data store.
93
+ */
94
+ private findEntitiesByType;
95
+ /**
96
+ * Build lookup tables from the first model's spatial entities for
97
+ * matching against subsequent models during merge.
98
+ */
99
+ private buildSpatialLookup;
100
+ /**
101
+ * Match a subsequent model's spatial entities (Site, Building, Storey)
102
+ * to the first model's equivalents. Matched entities are remapped and
103
+ * their duplicate entity is skipped from output.
104
+ *
105
+ * Matching strategy:
106
+ * - Sites/Buildings: by name (case-insensitive), or if only one in each model
107
+ * - Storeys: by name first, then by elevation (tolerance ±0.5 model units)
108
+ */
109
+ private unifySpatialEntities;
110
+ /**
111
+ * Skip IfcRelAggregates that become fully redundant after spatial unification.
112
+ *
113
+ * When Model2's `IfcRelAggregates(Project, (Site))` gets remapped to
114
+ * `IfcRelAggregates(FirstProject, (FirstSite))`, it duplicates Model1's
115
+ * existing relationship, causing viewers to show Site multiple times.
116
+ *
117
+ * An IfcRelAggregates is redundant if both its RelatingObject (attr 4)
118
+ * and ALL its RelatedObjects (attr 5) were remapped via sharedRemap.
119
+ */
120
+ private skipRedundantRelAggregates;
121
+ /**
122
+ * Extract the Name attribute (index 2) from a STEP entity.
123
+ */
124
+ private extractEntityName;
125
+ /**
126
+ * Extract the Elevation attribute (index 9) from an IfcBuildingStorey.
127
+ */
128
+ private extractStoreyElevation;
129
+ /**
130
+ * Extract a specific attribute (by 0-based index) from a STEP entity's
131
+ * raw text. Returns the raw string value (e.g., "'Name'", "$", "#123").
132
+ */
133
+ private extractStepAttribute;
134
+ }
135
+ //# sourceMappingURL=merged-exporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merged-exporter.d.ts","sourceRoot":"","sources":["../src/merged-exporter.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAwBrD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,SAAS,EAAE,YAAY,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACrC,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,eAAe,CAAC,EAAE,YAAY,CAAC;IAE/B,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,qDAAqD;IACrD,sBAAsB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,0DAA0D;IAC1D,wBAAwB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wBAAwB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,KAAK,EAAE;QACL,8BAA8B;QAC9B,UAAU,EAAE,MAAM,CAAC;QACnB,mCAAmC;QACnC,gBAAgB,EAAE,MAAM,CAAC;QACzB,yBAAyB;QACzB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED;;;;;;;;;;;;GAYG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAoB;gBAEtB,MAAM,EAAE,eAAe,EAAE;IAOrC,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,iBAAiB;IAkJtD;;;OAGG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAelC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAkC1B;;;;;;;;OAQG;IACH,OAAO,CAAC,oBAAoB;IA4E5B;;;;;;;;;OASG;IACH,OAAO,CAAC,0BAA0B;IA+BlC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAazB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAc9B;;;OAGG;IACH,OAAO,CAAC,oBAAoB;CA2D7B"}
@@ -0,0 +1,415 @@
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 { generateHeader } from '@ifc-lite/parser';
5
+ import { collectReferencedEntityIds, getVisibleEntityIds, collectStyleEntities } from './reference-collector.js';
6
+ /** Regex to match #ID references in STEP entity text. */
7
+ const STEP_REF_REGEX = /#(\d+)/g;
8
+ /** Entity types forming shared infrastructure (deduplicated across models). */
9
+ const SHARED_INFRASTRUCTURE_TYPES = new Set([
10
+ 'IFCUNITASSIGNMENT',
11
+ 'IFCGEOMETRICREPRESENTATIONCONTEXT',
12
+ 'IFCGEOMETRICREPRESENTATIONSUBCONTEXT',
13
+ ]);
14
+ /**
15
+ * Merges multiple IFC models into a single STEP file.
16
+ *
17
+ * Uses the same approach as IfcOpenShell's MergeProjects recipe, extended
18
+ * with spatial hierarchy unification:
19
+ * 1. First model's entities use their original IDs
20
+ * 2. Subsequent models' IDs are offset to avoid collisions
21
+ * 3. IfcProject is unified — all references remapped to the first model's project
22
+ * 4. Spatial structure (Site, Building, Storey) is unified by name/elevation:
23
+ * matching entities are remapped to the first model's equivalents so that
24
+ * products from all models end up in the same unified tree
25
+ * 5. Duplicate entities and shared infrastructure (units, contexts) are skipped
26
+ */
27
+ export class MergedExporter {
28
+ models;
29
+ constructor(models) {
30
+ if (models.length === 0) {
31
+ throw new Error('MergedExporter requires at least one model');
32
+ }
33
+ this.models = models;
34
+ }
35
+ export(options) {
36
+ const schema = options.schema || 'IFC4';
37
+ // Generate header
38
+ const header = generateHeader({
39
+ schema,
40
+ description: options.description || `Merged export of ${this.models.length} models from ifc-lite`,
41
+ author: options.author || '',
42
+ organization: options.organization || '',
43
+ application: options.application || 'ifc-lite',
44
+ filename: options.filename || 'merged.ifc',
45
+ });
46
+ const allEntityLines = [];
47
+ const decoder = new TextDecoder();
48
+ // Track ID offsets per model
49
+ let nextAvailableId = 1;
50
+ const modelOffsets = new Map();
51
+ // First pass: determine ID offsets
52
+ for (const model of this.models) {
53
+ modelOffsets.set(model.id, nextAvailableId - 1); // offset = nextAvailableId - 1 so IDs start at nextAvailableId
54
+ let maxId = 0;
55
+ for (const [id] of model.dataStore.entityIndex.byId) {
56
+ if (id > maxId)
57
+ maxId = id;
58
+ }
59
+ nextAvailableId += maxId;
60
+ }
61
+ // Collect first model's info for deduplication
62
+ const firstModel = this.models[0];
63
+ const firstModelOffset = modelOffsets.get(firstModel.id);
64
+ const firstModelInfraMap = this.findInfrastructureEntities(firstModel.dataStore);
65
+ const firstProjectIds = this.findEntitiesByType(firstModel.dataStore, 'IFCPROJECT');
66
+ // Build spatial lookup from first model for Site/Building/Storey unification
67
+ const spatialLookup = this.buildSpatialLookup(firstModel.dataStore, decoder);
68
+ // Process each model
69
+ let isFirstModel = true;
70
+ for (const model of this.models) {
71
+ const offset = modelOffsets.get(model.id);
72
+ const source = model.dataStore.source;
73
+ if (!source || source.length === 0)
74
+ continue;
75
+ // Determine which entities to include
76
+ let includedEntityIds = null;
77
+ if (options.visibleOnly) {
78
+ const hiddenIds = options.hiddenEntityIdsByModel?.get(model.id) ?? new Set();
79
+ const isolatedIds = options.isolatedEntityIdsByModel?.get(model.id) ?? null;
80
+ const { roots, hiddenProductIds } = getVisibleEntityIds(model.dataStore, hiddenIds, isolatedIds);
81
+ includedEntityIds = collectReferencedEntityIds(roots, source, model.dataStore.entityIndex.byId, hiddenProductIds);
82
+ // Second pass: collect style entities that reference included geometry
83
+ collectStyleEntities(includedEntityIds, source, model.dataStore.entityIndex);
84
+ }
85
+ // Build remap table (references to remap) and skip set (entities to omit)
86
+ const sharedRemap = new Map();
87
+ const skipEntityIds = new Set();
88
+ if (!isFirstModel) {
89
+ // Remap this model's IfcProject references → first model's IfcProject.
90
+ const projectIds = this.findEntitiesByType(model.dataStore, 'IFCPROJECT');
91
+ if (firstProjectIds.length > 0) {
92
+ for (const pid of projectIds) {
93
+ sharedRemap.set(pid, firstProjectIds[0] + firstModelOffset);
94
+ skipEntityIds.add(pid);
95
+ }
96
+ }
97
+ // Remap and skip duplicate infrastructure (units, contexts)
98
+ const modelInfra = this.findInfrastructureEntities(model.dataStore);
99
+ for (const [type, firstIds] of firstModelInfraMap) {
100
+ const thisIds = modelInfra.get(type);
101
+ if (thisIds && firstIds.length > 0 && thisIds.length > 0) {
102
+ sharedRemap.set(thisIds[0], firstIds[0] + firstModelOffset);
103
+ skipEntityIds.add(thisIds[0]);
104
+ }
105
+ }
106
+ // Unify spatial hierarchy: match Site, Building, Storey to first model
107
+ this.unifySpatialEntities(model.dataStore, decoder, spatialLookup, firstModelOffset, sharedRemap, skipEntityIds);
108
+ // Skip IfcRelAggregates that become fully redundant after unification.
109
+ // e.g. Model2's Project→Site becomes FirstProject→FirstSite which
110
+ // already exists from Model1, causing duplicate tree nodes.
111
+ this.skipRedundantRelAggregates(model.dataStore, decoder, sharedRemap, skipEntityIds);
112
+ }
113
+ // Emit entities for this model
114
+ for (const [expressId, entityRef] of model.dataStore.entityIndex.byId) {
115
+ // Skip entities outside the visible closure
116
+ if (includedEntityIds !== null && !includedEntityIds.has(expressId)) {
117
+ continue;
118
+ }
119
+ // Skip duplicate entities (project, infrastructure)
120
+ if (skipEntityIds.has(expressId)) {
121
+ continue;
122
+ }
123
+ // Get original entity text
124
+ const entityText = decoder.decode(source.subarray(entityRef.byteOffset, entityRef.byteOffset + entityRef.byteLength));
125
+ // Remap IDs if this is not the first model or if offset is non-zero
126
+ if (offset === 0 && sharedRemap.size === 0) {
127
+ allEntityLines.push(entityText);
128
+ }
129
+ else {
130
+ const remapped = this.remapEntityText(entityText, offset, sharedRemap);
131
+ allEntityLines.push(remapped);
132
+ }
133
+ }
134
+ isFirstModel = false;
135
+ }
136
+ // Assemble final file
137
+ const dataSection = allEntityLines.join('\n');
138
+ const content = `${header}DATA;\n${dataSection}\nENDSEC;\nEND-ISO-10303-21;\n`;
139
+ const fileSize = new TextEncoder().encode(content).length;
140
+ return {
141
+ content,
142
+ stats: {
143
+ modelCount: this.models.length,
144
+ totalEntityCount: allEntityLines.length,
145
+ fileSize,
146
+ },
147
+ };
148
+ }
149
+ /**
150
+ * Remap all #ID references in a STEP entity line.
151
+ * Applies offset to all IDs, then overrides with specific remappings.
152
+ */
153
+ remapEntityText(entityText, offset, sharedRemap) {
154
+ return entityText.replace(STEP_REF_REGEX, (_match, idStr) => {
155
+ const originalId = parseInt(idStr, 10);
156
+ // Check if this ID has a specific remap (project, shared infrastructure)
157
+ const remapped = sharedRemap.get(originalId);
158
+ if (remapped !== undefined) {
159
+ return `#${remapped}`;
160
+ }
161
+ // Apply offset
162
+ return `#${originalId + offset}`;
163
+ });
164
+ }
165
+ /**
166
+ * Find entity IDs of shared infrastructure types in a data store.
167
+ * Returns a map of uppercase type name → array of expressIds.
168
+ */
169
+ findInfrastructureEntities(dataStore) {
170
+ const result = new Map();
171
+ for (const type of SHARED_INFRASTRUCTURE_TYPES) {
172
+ const ids = dataStore.entityIndex.byType.get(type) ?? [];
173
+ if (ids.length > 0) {
174
+ result.set(type, [...ids]);
175
+ }
176
+ }
177
+ return result;
178
+ }
179
+ /**
180
+ * Find entity IDs of a specific type in a data store.
181
+ */
182
+ findEntitiesByType(dataStore, typeUpper) {
183
+ return dataStore.entityIndex.byType.get(typeUpper) ?? [];
184
+ }
185
+ /**
186
+ * Build lookup tables from the first model's spatial entities for
187
+ * matching against subsequent models during merge.
188
+ */
189
+ buildSpatialLookup(dataStore, decoder) {
190
+ const lookup = {
191
+ sitesByName: new Map(),
192
+ buildingsByName: new Map(),
193
+ storeysByName: new Map(),
194
+ storeysByElevation: [],
195
+ siteIds: [],
196
+ buildingIds: [],
197
+ };
198
+ for (const id of this.findEntitiesByType(dataStore, 'IFCSITE')) {
199
+ lookup.siteIds.push(id);
200
+ const name = this.extractEntityName(id, dataStore, decoder);
201
+ if (name)
202
+ lookup.sitesByName.set(name.toLowerCase(), id);
203
+ }
204
+ for (const id of this.findEntitiesByType(dataStore, 'IFCBUILDING')) {
205
+ lookup.buildingIds.push(id);
206
+ const name = this.extractEntityName(id, dataStore, decoder);
207
+ if (name)
208
+ lookup.buildingsByName.set(name.toLowerCase(), id);
209
+ }
210
+ for (const id of this.findEntitiesByType(dataStore, 'IFCBUILDINGSTOREY')) {
211
+ const name = this.extractEntityName(id, dataStore, decoder);
212
+ if (name)
213
+ lookup.storeysByName.set(name.toLowerCase(), id);
214
+ const elevation = this.extractStoreyElevation(id, dataStore, decoder);
215
+ if (elevation !== undefined) {
216
+ lookup.storeysByElevation.push({ expressId: id, elevation });
217
+ }
218
+ }
219
+ return lookup;
220
+ }
221
+ /**
222
+ * Match a subsequent model's spatial entities (Site, Building, Storey)
223
+ * to the first model's equivalents. Matched entities are remapped and
224
+ * their duplicate entity is skipped from output.
225
+ *
226
+ * Matching strategy:
227
+ * - Sites/Buildings: by name (case-insensitive), or if only one in each model
228
+ * - Storeys: by name first, then by elevation (tolerance ±0.5 model units)
229
+ */
230
+ unifySpatialEntities(dataStore, decoder, lookup, firstModelOffset, sharedRemap, skipEntityIds) {
231
+ // Unify IfcSite
232
+ const sites = this.findEntitiesByType(dataStore, 'IFCSITE');
233
+ for (const id of sites) {
234
+ const name = this.extractEntityName(id, dataStore, decoder);
235
+ let match;
236
+ if (name)
237
+ match = lookup.sitesByName.get(name.toLowerCase());
238
+ // If single site in both models, unify regardless of name
239
+ if (match === undefined && sites.length === 1 && lookup.siteIds.length === 1) {
240
+ match = lookup.siteIds[0];
241
+ }
242
+ if (match !== undefined) {
243
+ sharedRemap.set(id, match + firstModelOffset);
244
+ skipEntityIds.add(id);
245
+ }
246
+ }
247
+ // Unify IfcBuilding
248
+ const buildings = this.findEntitiesByType(dataStore, 'IFCBUILDING');
249
+ for (const id of buildings) {
250
+ const name = this.extractEntityName(id, dataStore, decoder);
251
+ let match;
252
+ if (name)
253
+ match = lookup.buildingsByName.get(name.toLowerCase());
254
+ if (match === undefined && buildings.length === 1 && lookup.buildingIds.length === 1) {
255
+ match = lookup.buildingIds[0];
256
+ }
257
+ if (match !== undefined) {
258
+ sharedRemap.set(id, match + firstModelOffset);
259
+ skipEntityIds.add(id);
260
+ }
261
+ }
262
+ // Unify IfcBuildingStorey — name match first, then elevation fallback
263
+ const matchedFirstStoreys = new Set();
264
+ for (const id of this.findEntitiesByType(dataStore, 'IFCBUILDINGSTOREY')) {
265
+ const name = this.extractEntityName(id, dataStore, decoder);
266
+ let match;
267
+ // Try name match
268
+ if (name) {
269
+ const candidate = lookup.storeysByName.get(name.toLowerCase());
270
+ if (candidate !== undefined && !matchedFirstStoreys.has(candidate)) {
271
+ match = candidate;
272
+ }
273
+ }
274
+ // Fallback: match by elevation
275
+ if (match === undefined) {
276
+ const elevation = this.extractStoreyElevation(id, dataStore, decoder);
277
+ if (elevation !== undefined) {
278
+ for (const entry of lookup.storeysByElevation) {
279
+ if (matchedFirstStoreys.has(entry.expressId))
280
+ continue;
281
+ const tolerance = Math.max(0.5, Math.abs(entry.elevation) * 0.01);
282
+ if (Math.abs(elevation - entry.elevation) <= tolerance) {
283
+ match = entry.expressId;
284
+ break;
285
+ }
286
+ }
287
+ }
288
+ }
289
+ if (match !== undefined) {
290
+ matchedFirstStoreys.add(match);
291
+ sharedRemap.set(id, match + firstModelOffset);
292
+ skipEntityIds.add(id);
293
+ }
294
+ }
295
+ }
296
+ /**
297
+ * Skip IfcRelAggregates that become fully redundant after spatial unification.
298
+ *
299
+ * When Model2's `IfcRelAggregates(Project, (Site))` gets remapped to
300
+ * `IfcRelAggregates(FirstProject, (FirstSite))`, it duplicates Model1's
301
+ * existing relationship, causing viewers to show Site multiple times.
302
+ *
303
+ * An IfcRelAggregates is redundant if both its RelatingObject (attr 4)
304
+ * and ALL its RelatedObjects (attr 5) were remapped via sharedRemap.
305
+ */
306
+ skipRedundantRelAggregates(dataStore, decoder, sharedRemap, skipEntityIds) {
307
+ for (const relId of this.findEntitiesByType(dataStore, 'IFCRELAGGREGATES')) {
308
+ // RelatingObject is attr 4 — single #ref
309
+ const relatingAttr = this.extractStepAttribute(relId, dataStore, decoder, 4);
310
+ if (!relatingAttr)
311
+ continue;
312
+ const relatingRef = relatingAttr.match(/^#(\d+)$/);
313
+ if (!relatingRef || !sharedRemap.has(parseInt(relatingRef[1], 10)))
314
+ continue;
315
+ // RelatedObjects is attr 5 — list of #refs like (#2,#3)
316
+ const relatedAttr = this.extractStepAttribute(relId, dataStore, decoder, 5);
317
+ if (!relatedAttr)
318
+ continue;
319
+ const refs = [];
320
+ const refRegex = /#(\d+)/g;
321
+ let m;
322
+ while ((m = refRegex.exec(relatedAttr)) !== null) {
323
+ refs.push(parseInt(m[1], 10));
324
+ }
325
+ if (refs.length === 0)
326
+ continue;
327
+ // If ALL related objects were also remapped, this rel is fully redundant
328
+ if (refs.every(ref => sharedRemap.has(ref))) {
329
+ skipEntityIds.add(relId);
330
+ }
331
+ }
332
+ }
333
+ /**
334
+ * Extract the Name attribute (index 2) from a STEP entity.
335
+ */
336
+ extractEntityName(expressId, dataStore, decoder) {
337
+ const attr = this.extractStepAttribute(expressId, dataStore, decoder, 2);
338
+ if (!attr || attr === '$')
339
+ return null;
340
+ if (attr.startsWith("'") && attr.endsWith("'")) {
341
+ return attr.slice(1, -1).replace(/''/g, "'");
342
+ }
343
+ return null;
344
+ }
345
+ /**
346
+ * Extract the Elevation attribute (index 9) from an IfcBuildingStorey.
347
+ */
348
+ extractStoreyElevation(expressId, dataStore, decoder) {
349
+ const attr = this.extractStepAttribute(expressId, dataStore, decoder, 9);
350
+ if (!attr || attr === '$')
351
+ return undefined;
352
+ // Handle typed value like IFCLENGTHMEASURE(3000.)
353
+ const typedMatch = attr.match(/^[A-Z_]+\(([^)]+)\)$/i);
354
+ const numStr = typedMatch ? typedMatch[1] : attr;
355
+ const num = parseFloat(numStr);
356
+ return isNaN(num) ? undefined : num;
357
+ }
358
+ /**
359
+ * Extract a specific attribute (by 0-based index) from a STEP entity's
360
+ * raw text. Returns the raw string value (e.g., "'Name'", "$", "#123").
361
+ */
362
+ extractStepAttribute(expressId, dataStore, decoder, attrIndex) {
363
+ const source = dataStore.source;
364
+ if (!source)
365
+ return null;
366
+ const ref = dataStore.entityIndex.byId.get(expressId);
367
+ if (!ref)
368
+ return null;
369
+ const entityText = decoder.decode(source.subarray(ref.byteOffset, ref.byteOffset + ref.byteLength));
370
+ // Find opening paren after type name
371
+ const openParen = entityText.indexOf('(');
372
+ if (openParen === -1)
373
+ return null;
374
+ let depth = 0;
375
+ let attrCount = 0;
376
+ let attrStart = openParen + 1;
377
+ let inString = false;
378
+ for (let i = openParen + 1; i < entityText.length; i++) {
379
+ const ch = entityText[i];
380
+ if (ch === "'" && !inString) {
381
+ inString = true;
382
+ }
383
+ else if (ch === "'" && inString) {
384
+ // Check for escaped quote ''
385
+ if (i + 1 < entityText.length && entityText[i + 1] === "'") {
386
+ i++;
387
+ continue;
388
+ }
389
+ inString = false;
390
+ }
391
+ else if (!inString) {
392
+ if (ch === '(') {
393
+ depth++;
394
+ }
395
+ else if (ch === ')') {
396
+ if (depth === 0) {
397
+ return attrCount === attrIndex
398
+ ? entityText.substring(attrStart, i).trim()
399
+ : null;
400
+ }
401
+ depth--;
402
+ }
403
+ else if (ch === ',' && depth === 0) {
404
+ if (attrCount === attrIndex) {
405
+ return entityText.substring(attrStart, i).trim();
406
+ }
407
+ attrCount++;
408
+ attrStart = i + 1;
409
+ }
410
+ }
411
+ }
412
+ return null;
413
+ }
414
+ }
415
+ //# sourceMappingURL=merged-exporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merged-exporter.js","sourceRoot":"","sources":["../src/merged-exporter.ts"],"names":[],"mappings":"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"}