@ifc-lite/export 2.5.3 → 2.7.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 (41) hide show
  1. package/dist/attribute-real-slots.d.ts +53 -0
  2. package/dist/attribute-real-slots.d.ts.map +1 -0
  3. package/dist/attribute-real-slots.js +99 -0
  4. package/dist/attribute-real-slots.js.map +1 -0
  5. package/dist/demesh-prune.d.ts +24 -0
  6. package/dist/demesh-prune.d.ts.map +1 -0
  7. package/dist/demesh-prune.js +185 -0
  8. package/dist/demesh-prune.js.map +1 -0
  9. package/dist/demesh-session.d.ts +136 -0
  10. package/dist/demesh-session.d.ts.map +1 -0
  11. package/dist/demesh-session.js +273 -0
  12. package/dist/demesh-session.js.map +1 -0
  13. package/dist/demesh-writer.d.ts +84 -0
  14. package/dist/demesh-writer.d.ts.map +1 -0
  15. package/dist/demesh-writer.js +240 -0
  16. package/dist/demesh-writer.js.map +1 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +2 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/reference-collector.d.ts +6 -0
  22. package/dist/reference-collector.d.ts.map +1 -1
  23. package/dist/reference-collector.js +36 -1
  24. package/dist/reference-collector.js.map +1 -1
  25. package/dist/schema-converter.d.ts +22 -1
  26. package/dist/schema-converter.d.ts.map +1 -1
  27. package/dist/schema-converter.js +5 -2
  28. package/dist/schema-converter.js.map +1 -1
  29. package/dist/select-qualification.d.ts +9 -0
  30. package/dist/select-qualification.d.ts.map +1 -0
  31. package/dist/select-qualification.js +156 -0
  32. package/dist/select-qualification.js.map +1 -0
  33. package/dist/step-exporter.d.ts +34 -1
  34. package/dist/step-exporter.d.ts.map +1 -1
  35. package/dist/step-exporter.js +44 -19
  36. package/dist/step-exporter.js.map +1 -1
  37. package/dist/step-serialization.d.ts +39 -6
  38. package/dist/step-serialization.d.ts.map +1 -1
  39. package/dist/step-serialization.js +129 -10
  40. package/dist/step-serialization.js.map +1 -1
  41. package/package.json +8 -8
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Schema-aware detection of REAL-typed STEP attribute slots.
3
+ *
4
+ * ISO 10303-21 requires a REAL-typed attribute (`IfcLengthMeasure` and every
5
+ * other `<real>`-backed defined type) to carry a decimal point — `450.`, never
6
+ * `450`. A bare JavaScript number is ambiguous at the value level (it could be
7
+ * an `IfcInteger`), so `serializeStepValue` defaults to emitting whole numbers
8
+ * as STEP INTEGER literals. That default silently produces strict-invalid files
9
+ * whenever a whole number lands in a REAL slot — the natural
10
+ * `setPositionalAttribute(profId, 3, 450)` call, `addEntity` args, and the
11
+ * geometry the in-store builders emit themselves (millimetre models round to
12
+ * whole numbers, making this the common case). See LTplus-AG/ifc-lite#1839.
13
+ *
14
+ * The slot's declared type is statically known from the schema registry, so we
15
+ * resolve it once per (entity, version) and force a REAL literal on those slots
16
+ * at serialization time — no caller change, no `{ real }` marker required.
17
+ */
18
+ import type { IfcAttributeValue } from '@ifc-lite/parser';
19
+ import type { IfcSchemaVersion } from './schema-converter.js';
20
+ /**
21
+ * True for the write-only `{ real }` / `{ typed }` markers — an explicit caller
22
+ * intent that `serializeStepValue` handles directly and that must bypass the
23
+ * schema-driven SELECT/REAL inference below.
24
+ */
25
+ export declare function isTypedMarker(value: IfcAttributeValue): boolean;
26
+ /**
27
+ * Serialize one positional attribute slot to its STEP token, composing the
28
+ * schema-aware passes in priority order:
29
+ * 1. an explicit `{ real }` / `{ typed }` marker wins outright;
30
+ * 2. a SELECT slot auto-qualifies an unambiguous bare value (`IFCBOOLEAN(.T.)`);
31
+ * 3. otherwise a REAL-backed slot forces a decimal point (#1839);
32
+ * 4. otherwise the default value serialization.
33
+ */
34
+ export declare function serializeAttributeSlot(entityType: string, index: number, value: IfcAttributeValue, version: IfcSchemaVersion): string;
35
+ /**
36
+ * The set of zero-based positional attribute indices on `entityType` whose
37
+ * declared type is unambiguously REAL-backed (`xs:double`, and NOT also
38
+ * `xs:integer`). An index that also admits an integer — a genuine
39
+ * `SELECT(IfcInteger, IfcReal)` — stays out of the set: it is truly ambiguous,
40
+ * and the explicit `{ real }` marker is the caller's way to disambiguate it.
41
+ *
42
+ * Returns an empty set for entities the registry does not know (vendor
43
+ * extensions, unmapped schema), preserving the historical default there.
44
+ */
45
+ export declare function getRealTypedSlots(entityType: string, version: IfcSchemaVersion): Set<number>;
46
+ /**
47
+ * Serialize a full positional attribute list for an entity to a STEP body,
48
+ * schema-aware per slot (SELECT qualification + REAL forcing). Used for
49
+ * freshly-emitted overlay entities (`addEntity`, the in-store builders) whose
50
+ * numbers never pass through a source token.
51
+ */
52
+ export declare function serializeEntityArgs(entityType: string, values: readonly IfcAttributeValue[], version: IfcSchemaVersion): string;
53
+ //# sourceMappingURL=attribute-real-slots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-real-slots.d.ts","sourceRoot":"","sources":["../src/attribute-real-slots.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAI9D;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAO/D;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,iBAAiB,EACxB,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAKR;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,GAAG,CAAC,MAAM,CAAC,CAsB5F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,SAAS,iBAAiB,EAAE,EACpC,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAER"}
@@ -0,0 +1,99 @@
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 { getAttributeNamesAcrossSchemas } from '@ifc-lite/parser';
5
+ import { getAttributeXsdTypes } from '@ifc-lite/data';
6
+ import { serializeStepValue } from './step-serialization.js';
7
+ import { serializeQualifiedSelectSlot } from './select-qualification.js';
8
+ /**
9
+ * True for the write-only `{ real }` / `{ typed }` markers — an explicit caller
10
+ * intent that `serializeStepValue` handles directly and that must bypass the
11
+ * schema-driven SELECT/REAL inference below.
12
+ */
13
+ export function isTypedMarker(value) {
14
+ return (typeof value === 'object' &&
15
+ value !== null &&
16
+ !Array.isArray(value) &&
17
+ ('real' in value || 'typed' in value));
18
+ }
19
+ /**
20
+ * Serialize one positional attribute slot to its STEP token, composing the
21
+ * schema-aware passes in priority order:
22
+ * 1. an explicit `{ real }` / `{ typed }` marker wins outright;
23
+ * 2. a SELECT slot auto-qualifies an unambiguous bare value (`IFCBOOLEAN(.T.)`);
24
+ * 3. otherwise a REAL-backed slot forces a decimal point (#1839);
25
+ * 4. otherwise the default value serialization.
26
+ */
27
+ export function serializeAttributeSlot(entityType, index, value, version) {
28
+ if (isTypedMarker(value))
29
+ return serializeStepValue(value);
30
+ const qualified = serializeQualifiedSelectSlot(entityType, index, value);
31
+ if (qualified !== null)
32
+ return qualified;
33
+ return serializeStepValue(value, getRealTypedSlots(entityType, version).has(index));
34
+ }
35
+ /**
36
+ * Map the exporter's schema tag to the version the attribute XSD index is keyed
37
+ * by. `IFC4X3_ADD2` is not an exporter tag; `IFC5` has no bundled XSD table.
38
+ * REAL-vs-INTEGER of a geometry slot is version-invariant, so any unmapped tag
39
+ * falls back to IFC4 — a slot missing from that version simply won't be forced.
40
+ */
41
+ function toDataSchemaVersion(v) {
42
+ switch (v) {
43
+ case 'IFC2X3':
44
+ return 'IFC2X3';
45
+ case 'IFC4X3':
46
+ return 'IFC4X3';
47
+ case 'IFC4':
48
+ return 'IFC4';
49
+ default:
50
+ return 'IFC4';
51
+ }
52
+ }
53
+ // Memoized `version|ENTITY` → set of positional slot indices that are
54
+ // unambiguously REAL-backed. Keyed by upper-case type so `IfcColumn`/`IFCCOLUMN`
55
+ // collapse to one entry.
56
+ const realSlotCache = new Map();
57
+ /**
58
+ * The set of zero-based positional attribute indices on `entityType` whose
59
+ * declared type is unambiguously REAL-backed (`xs:double`, and NOT also
60
+ * `xs:integer`). An index that also admits an integer — a genuine
61
+ * `SELECT(IfcInteger, IfcReal)` — stays out of the set: it is truly ambiguous,
62
+ * and the explicit `{ real }` marker is the caller's way to disambiguate it.
63
+ *
64
+ * Returns an empty set for entities the registry does not know (vendor
65
+ * extensions, unmapped schema), preserving the historical default there.
66
+ */
67
+ export function getRealTypedSlots(entityType, version) {
68
+ const dataVersion = toDataSchemaVersion(version);
69
+ const upperType = entityType.toUpperCase();
70
+ const key = `${dataVersion}|${upperType}`;
71
+ const cached = realSlotCache.get(key);
72
+ if (cached)
73
+ return cached;
74
+ // Resolve positional names across the bundled schema union (2X3 + 4 + 4X3),
75
+ // not just the parser's IFC4-pinned registry — otherwise IFC4X3-only leaves
76
+ // (IfcAlignmentHorizontalSegment and the civil/alignment geometry this fix
77
+ // targets) return no names, and their REAL slots (StartDirection,
78
+ // SegmentLength, …) would still emit bare INTEGER literals.
79
+ const names = getAttributeNamesAcrossSchemas(entityType);
80
+ const slots = new Set();
81
+ for (let i = 0; i < names.length; i++) {
82
+ const xsd = getAttributeXsdTypes(dataVersion, upperType, names[i]);
83
+ if (xsd && xsd.includes('xs:double') && !xsd.includes('xs:integer')) {
84
+ slots.add(i);
85
+ }
86
+ }
87
+ realSlotCache.set(key, slots);
88
+ return slots;
89
+ }
90
+ /**
91
+ * Serialize a full positional attribute list for an entity to a STEP body,
92
+ * schema-aware per slot (SELECT qualification + REAL forcing). Used for
93
+ * freshly-emitted overlay entities (`addEntity`, the in-store builders) whose
94
+ * numbers never pass through a source token.
95
+ */
96
+ export function serializeEntityArgs(entityType, values, version) {
97
+ return values.map((value, i) => serializeAttributeSlot(entityType, i, value, version)).join(',');
98
+ }
99
+ //# sourceMappingURL=attribute-real-slots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attribute-real-slots.js","sourceRoot":"","sources":["../src/attribute-real-slots.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Demesher prune: ONE global reverse-reference mark-and-sweep over the
3
+ * replaced products' detached geometry subgraphs (see `demesh-writer.ts` for
4
+ * the authoring side). An old geometry entity is tombstoned only when every
5
+ * entity that references it is itself being tombstoned, so shared
6
+ * representations (`IfcMappedItem` sources, an `IfcProductDefinitionShape`
7
+ * shared by several products) and type-library geometry survive partial
8
+ * selections by construction.
9
+ *
10
+ * The reverse index is built from the UNMODIFIED source bytes via the
11
+ * string-literal-aware `#N` scanner in `reference-collector.ts`; overlay
12
+ * entities added by the writer are invisible to it, which is why shared
13
+ * infrastructure (`PROTECTED_TYPES`) must never fall even when orphaned.
14
+ */
15
+ import { type IfcDataStore } from '@ifc-lite/parser';
16
+ import type { DemeshApplyReport, DemeshEditorLike } from './demesh-writer.js';
17
+ /**
18
+ * Global reverse-reference mark-and-sweep over the replaced products' old
19
+ * geometry subgraphs (see the module doc). Also strips void relationships
20
+ * for replaced hosts and filters `IfcPresentationLayerAssignment` item
21
+ * lists that pointed at pruned geometry.
22
+ */
23
+ export declare function pruneReplacedSubgraphs(store: IfcDataStore, editor: DemeshEditorLike, replacedOldRep: Map<number, number | null>, stripOpenings: boolean, report: DemeshApplyReport): void;
24
+ //# sourceMappingURL=demesh-prune.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demesh-prune.d.ts","sourceRoot":"","sources":["../src/demesh-prune.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAqB9E;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,gBAAgB,EACxB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAC1C,aAAa,EAAE,OAAO,EACtB,MAAM,EAAE,iBAAiB,GACxB,IAAI,CAqIN"}
@@ -0,0 +1,185 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Demesher prune: ONE global reverse-reference mark-and-sweep over the
6
+ * replaced products' detached geometry subgraphs (see `demesh-writer.ts` for
7
+ * the authoring side). An old geometry entity is tombstoned only when every
8
+ * entity that references it is itself being tombstoned, so shared
9
+ * representations (`IfcMappedItem` sources, an `IfcProductDefinitionShape`
10
+ * shared by several products) and type-library geometry survive partial
11
+ * selections by construction.
12
+ *
13
+ * The reverse index is built from the UNMODIFIED source bytes via the
14
+ * string-literal-aware `#N` scanner in `reference-collector.ts`; overlay
15
+ * entities added by the writer are invisible to it, which is why shared
16
+ * infrastructure (`PROTECTED_TYPES`) must never fall even when orphaned.
17
+ */
18
+ import { EntityExtractor } from '@ifc-lite/parser';
19
+ import { collectReferencedEntityIds, collectRefsInByteRange } from './reference-collector.js';
20
+ /**
21
+ * Entity types the sweep must never tombstone even when they fall inside a
22
+ * replaced subgraph's closure: shared model infrastructure that the NEW
23
+ * overlay entities (invisible to the source-byte reverse index) or the rest
24
+ * of the file may reference.
25
+ */
26
+ const PROTECTED_TYPES = new Set([
27
+ 'IFCGEOMETRICREPRESENTATIONCONTEXT',
28
+ 'IFCGEOMETRICREPRESENTATIONSUBCONTEXT',
29
+ 'IFCUNITASSIGNMENT',
30
+ 'IFCSIUNIT',
31
+ 'IFCCONVERSIONBASEDUNIT',
32
+ 'IFCOWNERHISTORY',
33
+ 'IFCPERSON',
34
+ 'IFCORGANIZATION',
35
+ 'IFCPERSONANDORGANIZATION',
36
+ 'IFCAPPLICATION',
37
+ ]);
38
+ /**
39
+ * Global reverse-reference mark-and-sweep over the replaced products' old
40
+ * geometry subgraphs (see the module doc). Also strips void relationships
41
+ * for replaced hosts and filters `IfcPresentationLayerAssignment` item
42
+ * lists that pointed at pruned geometry.
43
+ */
44
+ export function pruneReplacedSubgraphs(store, editor, replacedOldRep, stripOpenings, report) {
45
+ const source = store.source;
46
+ const byId = store.entityIndex.byId;
47
+ const extractor = new EntityExtractor(source);
48
+ const indexAdapter = {
49
+ get: (id) => byId.get(id),
50
+ has: (id) => byId.has(id),
51
+ };
52
+ // -- Roots: the detached representation subgraphs.
53
+ const roots = new Set();
54
+ for (const oldRep of replacedOldRep.values()) {
55
+ if (oldRep !== null && byId.has(oldRep))
56
+ roots.add(oldRep);
57
+ }
58
+ // -- Openings of replaced hosts: the rel is deleted outright (its cut is
59
+ // baked into the new mesh); the opening element and its geometry join the
60
+ // candidate closure and fall to the ordinary sweep.
61
+ const deleted = new Set();
62
+ if (stripOpenings) {
63
+ for (const [id, ref] of byId) {
64
+ if (ref.type.toUpperCase() !== 'IFCRELVOIDSELEMENT')
65
+ continue;
66
+ const rel = extractor.extractEntity(ref);
67
+ const relating = rel?.attributes?.[4];
68
+ const opening = rel?.attributes?.[5];
69
+ if (typeof relating !== 'number' || !replacedOldRep.has(relating))
70
+ continue;
71
+ deleted.add(id);
72
+ if (typeof opening === 'number' && byId.has(opening)) {
73
+ roots.add(opening);
74
+ }
75
+ }
76
+ }
77
+ if (roots.size === 0 && deleted.size === 0)
78
+ return;
79
+ // -- Candidate closure: everything transitively reachable from the roots.
80
+ const closure = collectReferencedEntityIds(roots, source, indexAdapter);
81
+ // Style/annotation entities hang OFF the geometry (IfcStyledItem.Item →
82
+ // geometry item), so forward reachability misses them; pull in styled
83
+ // items whose target is in the closure, plus what they reference (shared
84
+ // surface styles survive via their other referrers).
85
+ const styledItemRoots = new Set();
86
+ for (const [id, ref] of byId) {
87
+ if (closure.has(id) || ref.type.toUpperCase() !== 'IFCSTYLEDITEM')
88
+ continue;
89
+ const refs = collectRefsInByteRange(source, ref.byteOffset, ref.byteLength);
90
+ if (refs.some((target) => target !== id && closure.has(target))) {
91
+ styledItemRoots.add(id);
92
+ }
93
+ }
94
+ if (styledItemRoots.size > 0) {
95
+ for (const id of collectReferencedEntityIds(styledItemRoots, source, indexAdapter)) {
96
+ closure.add(id);
97
+ }
98
+ }
99
+ // -- Reverse-reference index, restricted to edges INTO the closure.
100
+ const referrers = new Map();
101
+ for (const [id, ref] of byId) {
102
+ // Presentation layers ANNOTATE geometry, they don't own it: counting
103
+ // their edges as referrers would keep replaced geometry alive forever
104
+ // (the layer itself is outside the closure and never falls), defeating
105
+ // the AssignedItems filtering below. Skip them so layer-only-referenced
106
+ // geometry prunes and the filter then cleans the surviving layer's list.
107
+ if (ref.type.toUpperCase() === 'IFCPRESENTATIONLAYERASSIGNMENT')
108
+ continue;
109
+ const refs = collectRefsInByteRange(source, ref.byteOffset, ref.byteLength);
110
+ for (const target of refs) {
111
+ if (target === id || !closure.has(target))
112
+ continue;
113
+ let set = referrers.get(target);
114
+ if (!set) {
115
+ set = new Set();
116
+ referrers.set(target, set);
117
+ }
118
+ set.add(id);
119
+ }
120
+ }
121
+ // The representation swap detached product → old-PDS: remove those edges
122
+ // (the reverse index was built from the unmodified source bytes).
123
+ for (const [productId, oldRep] of replacedOldRep) {
124
+ if (oldRep !== null)
125
+ referrers.get(oldRep)?.delete(productId);
126
+ }
127
+ // -- Sweep to fixpoint: tombstone an entity once every referrer is
128
+ // tombstoned. Protected infrastructure never falls, even if orphaned.
129
+ let changed = true;
130
+ while (changed) {
131
+ changed = false;
132
+ for (const id of closure) {
133
+ if (deleted.has(id))
134
+ continue;
135
+ const ref = byId.get(id);
136
+ if (!ref || PROTECTED_TYPES.has(ref.type.toUpperCase()))
137
+ continue;
138
+ const incoming = referrers.get(id);
139
+ let live = false;
140
+ if (incoming) {
141
+ for (const from of incoming) {
142
+ if (!deleted.has(from)) {
143
+ live = true;
144
+ break;
145
+ }
146
+ }
147
+ }
148
+ if (!live) {
149
+ deleted.add(id);
150
+ changed = true;
151
+ }
152
+ }
153
+ }
154
+ // -- Apply tombstones.
155
+ let openingCount = 0;
156
+ for (const id of deleted) {
157
+ const type = byId.get(id)?.type.toUpperCase();
158
+ if (type === 'IFCRELVOIDSELEMENT' || type === 'IFCOPENINGELEMENT')
159
+ openingCount++;
160
+ if (editor.removeEntity(id))
161
+ report.prunedEntityCount++;
162
+ }
163
+ report.strippedOpeningCount = openingCount;
164
+ // -- Presentation layers: filter tombstoned items out of AssignedItems;
165
+ // a layer left empty is tombstoned too (an empty list is schema-invalid).
166
+ for (const [id, ref] of byId) {
167
+ if (deleted.has(id) || ref.type.toUpperCase() !== 'IFCPRESENTATIONLAYERASSIGNMENT')
168
+ continue;
169
+ const layer = extractor.extractEntity(ref);
170
+ const items = layer?.attributes?.[2];
171
+ if (!Array.isArray(items))
172
+ continue;
173
+ const kept = items.filter((item) => typeof item === 'number' && !deleted.has(item));
174
+ if (kept.length === items.length)
175
+ continue;
176
+ if (kept.length === 0) {
177
+ if (editor.removeEntity(id))
178
+ report.prunedEntityCount++;
179
+ }
180
+ else {
181
+ editor.setPositionalAttribute(id, 2, kept.map((item) => `#${item}`));
182
+ }
183
+ }
184
+ }
185
+ //# sourceMappingURL=demesh-prune.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demesh-prune.js","sourceRoot":"","sources":["../src/demesh-prune.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,136 @@
1
+ /**
2
+ * DemeshSession — interactive selective mesh simplification with deferred
3
+ * IFC export (the "demesher").
4
+ *
5
+ * Workflow (one session per loaded model):
6
+ * 1. `simplify(expressIds)` — each call escalates the selection one level
7
+ * (1-4 = cavity removal + vertex-clustering decimation at
8
+ * 0.5/0.25/0.10/0.03 triangle ratio, 5 = bounding box). Simplification
9
+ * ALWAYS re-runs from the ORIGINAL meshes at the new level — quality
10
+ * never degrades cumulatively, and `reset()` is trivial. The returned
11
+ * render meshes go straight into the scene:
12
+ * `scene.removeMeshesForEntities(ids)` + `scene.addMeshes(renderMeshes)`.
13
+ * 2. `exportIfc()` — separately, when the user is done: loads the original
14
+ * bytes into a store, swaps each simplified element's representation
15
+ * for an `IfcTriangulatedFaceSet` (via `applySimplifiedGeometry`),
16
+ * prunes the orphaned geometry, and writes the lighter IFC. IFC2X3
17
+ * sources are upconverted to IFC4 first (`IfcTriangulatedFaceSet` is
18
+ * IFC4+).
19
+ *
20
+ * The model file is parsed at most twice per session (once for meshes unless
21
+ * the caller supplies the ones it already holds, once at export); button
22
+ * presses between those touch only mesh data in wasm.
23
+ */
24
+ import { GeometryProcessor, type MeshData } from '@ifc-lite/geometry';
25
+ import { type DemeshApplyReport } from './demesh-writer.js';
26
+ export interface DemeshSessionOptions {
27
+ /**
28
+ * Already-produced meshes for this model (the viewer's `MeshData[]`) —
29
+ * supply them together with `originShift` from the load's
30
+ * `coordinateInfo` to skip the session's own meshing pass. When omitted,
31
+ * the session meshes the bytes itself on first use.
32
+ */
33
+ meshes?: MeshData[];
34
+ /** `coordinateInfo.originShift` of the load that produced `meshes`. */
35
+ originShift?: {
36
+ x: number;
37
+ y: number;
38
+ z: number;
39
+ };
40
+ /** Metres per project length unit; extracted from the file when omitted. */
41
+ unitScale?: number;
42
+ /** Reuse the app's initialized GeometryProcessor instead of creating one. */
43
+ geometryProcessor?: GeometryProcessor;
44
+ }
45
+ export interface DemeshSimplifyResult {
46
+ /** Replacement render meshes for the scene (one per simplified element). */
47
+ renderMeshes: MeshData[];
48
+ /** Per-element outcome, including the level now applied. */
49
+ elements: Array<{
50
+ expressId: number;
51
+ level: number;
52
+ trisBefore: number;
53
+ trisAfter: number;
54
+ cavitiesDropped: number;
55
+ }>;
56
+ /** Elements that could not be simplified (keep their original meshes). */
57
+ skipped: Array<{
58
+ expressId: number;
59
+ reason: string;
60
+ }>;
61
+ }
62
+ export interface DemeshExportResult {
63
+ bytes: Uint8Array;
64
+ report: DemeshApplyReport;
65
+ /** True when an IFC2X3 source was upconverted to IFC4 for the export. */
66
+ upconverted: boolean;
67
+ bytesBefore: number;
68
+ bytesAfter: number;
69
+ }
70
+ export declare class DemeshSession {
71
+ private readonly source;
72
+ private readonly options;
73
+ private gp;
74
+ private ownsGp;
75
+ private meshes;
76
+ private originShift;
77
+ private unitScale;
78
+ private gpPromise;
79
+ private meshesPromise;
80
+ private unitScalePromise;
81
+ /** expressId -> state of the CURRENT simplification (from-original). */
82
+ private readonly applied;
83
+ constructor(source: Uint8Array | ArrayBuffer, options?: DemeshSessionOptions);
84
+ /** The level currently applied to an element (0 = untouched). */
85
+ levelOf(expressId: number): number;
86
+ /**
87
+ * The coordinate-frame shift of the meshes this session works with (the
88
+ * supplied `originShift`, or the session's own load's after self-meshing).
89
+ * A viewer whose scene uses a different anchor (multi-model federation
90
+ * with a shared RTC) translates render-mesh origins by the difference.
91
+ */
92
+ getOriginShift(): {
93
+ x: number;
94
+ y: number;
95
+ z: number;
96
+ };
97
+ /**
98
+ * The ORIGINAL mesh records of `expressIds` (session frame, untouched by
99
+ * any simplification) — lets a viewer restore an element's real geometry
100
+ * in the scene after `reset()`. Meshes the source on first use.
101
+ */
102
+ originalMeshesFor(expressIds: number[]): Promise<MeshData[]>;
103
+ /** Express ids currently carrying simplified geometry. */
104
+ simplifiedIds(): number[];
105
+ /**
106
+ * Simplify `expressIds` at `level`, or — when `level` is omitted — one
107
+ * level past each element's current one (the button behavior: press,
108
+ * press again, ...; capped at 5).
109
+ */
110
+ simplify(expressIds: number[], level?: number): Promise<DemeshSimplifyResult>;
111
+ /**
112
+ * Forget the simplification state for `expressIds` (all when omitted).
113
+ * The caller restores the elements' original meshes in the scene.
114
+ */
115
+ reset(expressIds?: number[]): void;
116
+ /**
117
+ * The `n` heaviest elements by triangle count — demesh candidates for the
118
+ * UI. Requires meshes (supplied or produced on first `simplify`).
119
+ */
120
+ heaviest(n: number): Promise<Array<{
121
+ expressId: number;
122
+ triangles: number;
123
+ }>>;
124
+ /**
125
+ * Write the lighter IFC: original bytes + tessellated replacements for
126
+ * every currently simplified element. Does not mutate session state — the
127
+ * user can keep simplifying and export again.
128
+ */
129
+ exportIfc(): Promise<DemeshExportResult>;
130
+ /** Release the session's own GeometryProcessor (a shared one is untouched). */
131
+ destroy(): void;
132
+ private ensureProcessor;
133
+ private ensureMeshes;
134
+ private ensureUnitScale;
135
+ }
136
+ //# sourceMappingURL=demesh-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demesh-session.d.ts","sourceRoot":"","sources":["../src/demesh-session.ts"],"names":[],"mappings":"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"}