@ifc-lite/export 2.3.0 → 2.4.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/merged-exporter.d.ts +117 -16
- package/dist/merged-exporter.d.ts.map +1 -1
- package/dist/merged-exporter.js +272 -65
- package/dist/merged-exporter.js.map +1 -1
- package/dist/unit-normalize.d.ts +62 -0
- package/dist/unit-normalize.d.ts.map +1 -0
- package/dist/unit-normalize.js +346 -0
- package/dist/unit-normalize.js.map +1 -0
- package/package.json +6 -6
|
@@ -75,11 +75,49 @@ export interface MergeExportOptions {
|
|
|
75
75
|
* (a deliberate relaxation of the IfcSingleProjectInstance rule, flagged in
|
|
76
76
|
* `stats.warnings`) — the only way to preserve mixed units in one file
|
|
77
77
|
* without rewriting every length-valued attribute.
|
|
78
|
+
* - `'normalize'`: single-unit merge. A model with a *different* length unit
|
|
79
|
+
* is *rescaled* — every length-valued datum (all `IfcCartesianPoint`
|
|
80
|
+
* coordinates, extrusion depths, profile dimensions, radii, thicknesses,
|
|
81
|
+
* storey elevations, placement offsets, `IfcLengthMeasure` property values,
|
|
82
|
+
* `IfcQuantityLength`/`Area`/`Volume`, …) is converted from its own unit
|
|
83
|
+
* into the first model's unit — and then unified into the single first
|
|
84
|
+
* `IfcProject` (its `IfcUnitAssignment` and contexts deduplicated). The
|
|
85
|
+
* output is one ordinary single-unit IFC that opens correctly everywhere
|
|
86
|
+
* (BIM Vision included). Angles, ratios, counts and georeferencing offsets
|
|
87
|
+
* are left as-is. Area/volume values assume the SI-derived unit
|
|
88
|
+
* (square/cube of the length unit). See {@link ./unit-normalize.ts} for the
|
|
89
|
+
* exact set of rescaled attributes.
|
|
78
90
|
* - `'assume-shared'`: treat every model as sharing the first model's unit
|
|
79
91
|
* (the pre-1332 behaviour). Use only when the caller has already
|
|
80
92
|
* normalised units; mixing real units under this mode mis-scales geometry.
|
|
81
93
|
*/
|
|
82
|
-
unitReconciliation?: 'auto' | 'assume-shared';
|
|
94
|
+
unitReconciliation?: 'auto' | 'normalize' | 'assume-shared';
|
|
95
|
+
/**
|
|
96
|
+
* How IfcSite instances are matched across models for spatial unification
|
|
97
|
+
* (mirrors IfcOpenShell/BlenderBIM's "Merge Projects" recipe). Omitted
|
|
98
|
+
* (default) keeps today's combined heuristic: match by Name
|
|
99
|
+
* (case-insensitive), else unify when both models contribute exactly one
|
|
100
|
+
* site.
|
|
101
|
+
*
|
|
102
|
+
* - `'single'`: unify only when each model contributes exactly one
|
|
103
|
+
* IfcSite — Name is ignored entirely.
|
|
104
|
+
* - `'by-name'`: unify only sites with a matching Name; a lone,
|
|
105
|
+
* differently-named site in each model is kept as two separate roots.
|
|
106
|
+
*/
|
|
107
|
+
mergeSites?: 'single' | 'by-name';
|
|
108
|
+
/** Same matching strategy as {@link mergeSites}, applied to IfcBuilding. */
|
|
109
|
+
mergeBuildings?: 'single' | 'by-name';
|
|
110
|
+
/**
|
|
111
|
+
* How IfcBuildingStorey instances are matched across models. Omitted
|
|
112
|
+
* (default) is `'by-name-then-elevation'` — today's behavior.
|
|
113
|
+
*
|
|
114
|
+
* - `'by-name'`: match only by Name (case-insensitive); no elevation
|
|
115
|
+
* fallback.
|
|
116
|
+
* - `'by-elevation'`: match only by Elevation (±0.5 model-unit tolerance,
|
|
117
|
+
* same as today), ignoring Name entirely.
|
|
118
|
+
* - `'by-name-then-elevation'`: try Name first, fall back to Elevation.
|
|
119
|
+
*/
|
|
120
|
+
mergeStoreys?: 'by-name' | 'by-elevation' | 'by-name-then-elevation';
|
|
83
121
|
/** Apply visibility filtering to each model before merging */
|
|
84
122
|
visibleOnly?: boolean;
|
|
85
123
|
/** Hidden entity IDs per model (local expressIds) */
|
|
@@ -123,6 +161,12 @@ export interface MergeExportResult {
|
|
|
123
161
|
* unit differed from the first model's. 0 means a single unified project.
|
|
124
162
|
*/
|
|
125
163
|
federatedModelCount: number;
|
|
164
|
+
/**
|
|
165
|
+
* Number of models whose length-valued data was rescaled into the first
|
|
166
|
+
* model's unit under `unitReconciliation: 'normalize'`. 0 for the other
|
|
167
|
+
* modes (or when every model already shared the first model's unit).
|
|
168
|
+
*/
|
|
169
|
+
normalizedModelCount: number;
|
|
126
170
|
/**
|
|
127
171
|
* Human-readable advisories about the merge (empty on a clean single-unit
|
|
128
172
|
* merge). Notably flags when federation produced more than one IfcProject,
|
|
@@ -154,14 +198,15 @@ export interface MergeExportResult {
|
|
|
154
198
|
* fresh deterministic GlobalId so the file has no duplicate-GlobalId errors
|
|
155
199
|
* and no relationship membership is lost.
|
|
156
200
|
*
|
|
157
|
-
* Conformance trade-off: when federation triggers
|
|
158
|
-
* one IfcProject, which intentionally relaxes the
|
|
159
|
-
* EXPRESS rule (SIZEOF(IfcProject) <= 1). This
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* `
|
|
163
|
-
*
|
|
164
|
-
*
|
|
201
|
+
* Conformance trade-off: when federation triggers (under the default `'auto'`),
|
|
202
|
+
* the file contains more than one IfcProject, which intentionally relaxes the
|
|
203
|
+
* IfcSingleProjectInstance EXPRESS rule (SIZEOF(IfcProject) <= 1). This preserves
|
|
204
|
+
* both units without rewriting coordinates, and is strictly better than a silent
|
|
205
|
+
* mis-scale. `MergeExportResult.stats.warnings` flags it. To instead get one
|
|
206
|
+
* ordinary single-unit IfcProject, pass `unitReconciliation: 'normalize'` — it
|
|
207
|
+
* rescales every length-valued datum of the differing-unit models into the first
|
|
208
|
+
* model's unit (see {@link ./unit-normalize.ts}). Use `'assume-shared'` only when
|
|
209
|
+
* the caller has already normalised units.
|
|
165
210
|
*
|
|
166
211
|
* Limitation: federation only unifies a model against the *first* model's unit
|
|
167
212
|
* group. Two non-first models that share a unit different from the first are
|
|
@@ -192,6 +237,13 @@ export declare class MergedExporter {
|
|
|
192
237
|
* Assemble the result stats, including any federation conformance warnings.
|
|
193
238
|
*/
|
|
194
239
|
private buildStats;
|
|
240
|
+
/**
|
|
241
|
+
* Record advisories for a model being normalized. The rescaler derives its
|
|
242
|
+
* length-attribute map from the IFC4 schema registry, so it may not cover
|
|
243
|
+
* length attributes introduced by newer schemas (IFC4X3 alignment / linear
|
|
244
|
+
* referencing), and it deliberately leaves georeferencing untouched.
|
|
245
|
+
*/
|
|
246
|
+
private collectNormalizeCaveats;
|
|
195
247
|
/**
|
|
196
248
|
* Build the ifc-lite provenance header. Merged files have no single source
|
|
197
249
|
* header to round-trip, so we deliberately emit our own rather than picking
|
|
@@ -203,6 +255,36 @@ export declare class MergedExporter {
|
|
|
203
255
|
* per-model id offsets and the primary model's project/infra/spatial/unit info.
|
|
204
256
|
*/
|
|
205
257
|
private buildMergeSetup;
|
|
258
|
+
/**
|
|
259
|
+
* Decide how one model folds into the merge from its length unit and the
|
|
260
|
+
* reconciliation mode.
|
|
261
|
+
*
|
|
262
|
+
* - The primary model, `assume-shared`, and any model that already shares the
|
|
263
|
+
* primary unit are unified with no rescale.
|
|
264
|
+
* - Under `normalize`, a differing-unit model is unified *and* rescaled: every
|
|
265
|
+
* length-valued datum is multiplied by `primaryScale`-relative factor so its
|
|
266
|
+
* geometry stays correct under the single shared unit.
|
|
267
|
+
* - Otherwise (`auto`) a differing-unit model is federated (kept as its own
|
|
268
|
+
* project + units), leaving its raw coordinates untouched.
|
|
269
|
+
*
|
|
270
|
+
* Area/volume reconciliation is gated on the length unit differing: a model that
|
|
271
|
+
* shares the primary's length unit is treated as fully compatible (factors 1).
|
|
272
|
+
* A model that pairs a matching length unit with a *divergent* area/volume unit
|
|
273
|
+
* (a non-conformant combination no mainstream exporter emits) is not rescaled.
|
|
274
|
+
*/
|
|
275
|
+
private resolveModelMode;
|
|
276
|
+
/**
|
|
277
|
+
* Resolve a model's declared AREAUNIT / VOLUMEUNIT scale (SI m² / m³ per unit)
|
|
278
|
+
* by walking IfcProject → IfcUnitAssignment. Falls back to the length-derived
|
|
279
|
+
* unit (`lengthScale ** power`) when the model declares no explicit area/volume
|
|
280
|
+
* unit — the IFC default. A prefixed SI area/volume unit (rare) applies the
|
|
281
|
+
* prefix once (buildingSMART / IfcOpenShell convention).
|
|
282
|
+
*/
|
|
283
|
+
private resolveDerivedUnitScale;
|
|
284
|
+
/** Uppercase an enum token, stripping the STEP `.ENUM.` dots. `''` for nullish. */
|
|
285
|
+
private normalizeEnum;
|
|
286
|
+
/** Extract the number from a bare real or a typed measure token (`IFCAREAMEASURE(0.09)`). */
|
|
287
|
+
private parseMeasureNumber;
|
|
206
288
|
/**
|
|
207
289
|
* Resolve a model's length unit scale (raw IFC length → metres). Prefers an
|
|
208
290
|
* explicit `lengthUnitScale` on the input, else the value the parser stamped
|
|
@@ -220,10 +302,10 @@ export declare class MergedExporter {
|
|
|
220
302
|
* Plan how a model's entities are remapped, skipped, or re-stamped, given
|
|
221
303
|
* whether it shares the primary model's length unit (`compatible`).
|
|
222
304
|
*
|
|
223
|
-
* Compatible (
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
* unified to that one instance.
|
|
305
|
+
* Compatible models (same unit, `assume-shared`, or `normalize`d into the
|
|
306
|
+
* primary unit) are unified into the primary project: their IfcProject, shared
|
|
307
|
+
* infrastructure, and matching spatial structure are deduplicated, and a rooted
|
|
308
|
+
* entity repeating an already-emitted GlobalId is unified to that one instance.
|
|
227
309
|
*
|
|
228
310
|
* Incompatible (federated) models keep their own project, units, contexts and
|
|
229
311
|
* spatial structure so their coordinates stay correctly scaled; a rooted
|
|
@@ -293,11 +375,30 @@ export declare class MergedExporter {
|
|
|
293
375
|
* to the first model's equivalents. Matched entities are remapped and
|
|
294
376
|
* their duplicate entity is skipped from output.
|
|
295
377
|
*
|
|
296
|
-
* Matching strategy
|
|
297
|
-
*
|
|
298
|
-
*
|
|
378
|
+
* Matching strategy per container type is driven by
|
|
379
|
+
* {@link MergeExportOptions.mergeSites} / `mergeBuildings` / `mergeStoreys`
|
|
380
|
+
* (all optional; omitted keeps the pre-existing combined heuristic):
|
|
381
|
+
* - Sites/Buildings: `'single'` (ignore name, unify iff exactly one in each
|
|
382
|
+
* model), `'by-name'` (name only, no fallback), or omitted — name first,
|
|
383
|
+
* else single-instance fallback.
|
|
384
|
+
* - Storeys: `'by-name'`, `'by-elevation'` (tolerance ±0.5 model units), or
|
|
385
|
+
* `'by-name-then-elevation'` (default, also the omitted behavior).
|
|
299
386
|
*/
|
|
300
387
|
private unifySpatialEntities;
|
|
388
|
+
/**
|
|
389
|
+
* Match one IfcSite/IfcBuilding instance against the first model's
|
|
390
|
+
* equivalents, per {@link mergeMode}:
|
|
391
|
+
* - `'single'`: ignore name — unify iff both models contribute exactly one.
|
|
392
|
+
* - `'by-name'`: name match only, no single-instance fallback.
|
|
393
|
+
* - omitted: name match, else single-instance fallback (pre-existing heuristic).
|
|
394
|
+
*
|
|
395
|
+
* `matchedFirst` excludes first-model targets already claimed by an earlier
|
|
396
|
+
* entity in this same model's loop — without it, two of this model's sites
|
|
397
|
+
* (or buildings) sharing a name/being the sole instance would both resolve
|
|
398
|
+
* to the same target, and the second would be dropped (skipped + remapped)
|
|
399
|
+
* rather than kept as its own root.
|
|
400
|
+
*/
|
|
401
|
+
private matchRootContainer;
|
|
301
402
|
/**
|
|
302
403
|
* Skip IfcRelAggregates that become fully redundant after spatial unification.
|
|
303
404
|
*
|
|
@@ -1 +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;AAIrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"merged-exporter.d.ts","sourceRoot":"","sources":["../src/merged-exporter.ts"],"names":[],"mappings":"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"}
|