@ifc-lite/export 2.5.3 → 2.6.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/demesh-prune.d.ts +24 -0
- package/dist/demesh-prune.d.ts.map +1 -0
- package/dist/demesh-prune.js +185 -0
- package/dist/demesh-prune.js.map +1 -0
- package/dist/demesh-session.d.ts +136 -0
- package/dist/demesh-session.d.ts.map +1 -0
- package/dist/demesh-session.js +273 -0
- package/dist/demesh-session.js.map +1 -0
- package/dist/demesh-writer.d.ts +84 -0
- package/dist/demesh-writer.d.ts.map +1 -0
- package/dist/demesh-writer.js +240 -0
- package/dist/demesh-writer.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/reference-collector.d.ts +6 -0
- package/dist/reference-collector.d.ts.map +1 -1
- package/dist/reference-collector.js +36 -1
- package/dist/reference-collector.js.map +1 -1
- package/dist/step-serialization.d.ts +9 -0
- package/dist/step-serialization.d.ts.map +1 -1
- package/dist/step-serialization.js +14 -0
- package/dist/step-serialization.js.map +1 -1
- package/package.json +6 -6
|
@@ -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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"}
|
|
@@ -0,0 +1,273 @@
|
|
|
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
|
+
* DemeshSession — interactive selective mesh simplification with deferred
|
|
6
|
+
* IFC export (the "demesher").
|
|
7
|
+
*
|
|
8
|
+
* Workflow (one session per loaded model):
|
|
9
|
+
* 1. `simplify(expressIds)` — each call escalates the selection one level
|
|
10
|
+
* (1-4 = cavity removal + vertex-clustering decimation at
|
|
11
|
+
* 0.5/0.25/0.10/0.03 triangle ratio, 5 = bounding box). Simplification
|
|
12
|
+
* ALWAYS re-runs from the ORIGINAL meshes at the new level — quality
|
|
13
|
+
* never degrades cumulatively, and `reset()` is trivial. The returned
|
|
14
|
+
* render meshes go straight into the scene:
|
|
15
|
+
* `scene.removeMeshesForEntities(ids)` + `scene.addMeshes(renderMeshes)`.
|
|
16
|
+
* 2. `exportIfc()` — separately, when the user is done: loads the original
|
|
17
|
+
* bytes into a store, swaps each simplified element's representation
|
|
18
|
+
* for an `IfcTriangulatedFaceSet` (via `applySimplifiedGeometry`),
|
|
19
|
+
* prunes the orphaned geometry, and writes the lighter IFC. IFC2X3
|
|
20
|
+
* sources are upconverted to IFC4 first (`IfcTriangulatedFaceSet` is
|
|
21
|
+
* IFC4+).
|
|
22
|
+
*
|
|
23
|
+
* The model file is parsed at most twice per session (once for meshes unless
|
|
24
|
+
* the caller supplies the ones it already holds, once at export); button
|
|
25
|
+
* presses between those touch only mesh data in wasm.
|
|
26
|
+
*/
|
|
27
|
+
import { GeometryProcessor, } from '@ifc-lite/geometry';
|
|
28
|
+
import { IfcParser } from '@ifc-lite/parser';
|
|
29
|
+
import { MutablePropertyView, StoreEditor } from '@ifc-lite/mutations';
|
|
30
|
+
import { StepExporter } from './step-exporter.js';
|
|
31
|
+
import { applySimplifiedGeometry, } from './demesh-writer.js';
|
|
32
|
+
export class DemeshSession {
|
|
33
|
+
source;
|
|
34
|
+
options;
|
|
35
|
+
gp = null;
|
|
36
|
+
ownsGp = false;
|
|
37
|
+
meshes = null;
|
|
38
|
+
originShift;
|
|
39
|
+
unitScale;
|
|
40
|
+
// Single-flight guards: concurrent calls (rapid button presses) must share
|
|
41
|
+
// ONE processor init / meshing pass / unit-scale scan. The promises are
|
|
42
|
+
// sticky on rejection too — a fatal wasm init failure stays terminal for
|
|
43
|
+
// the session instead of spawning a second doomed processor.
|
|
44
|
+
gpPromise = null;
|
|
45
|
+
meshesPromise = null;
|
|
46
|
+
unitScalePromise = null;
|
|
47
|
+
/** expressId -> state of the CURRENT simplification (from-original). */
|
|
48
|
+
applied = new Map();
|
|
49
|
+
constructor(source, options = {}) {
|
|
50
|
+
this.source = source instanceof Uint8Array ? source : new Uint8Array(source);
|
|
51
|
+
this.options = options;
|
|
52
|
+
this.meshes = options.meshes ?? null;
|
|
53
|
+
this.originShift = options.originShift ?? { x: 0, y: 0, z: 0 };
|
|
54
|
+
this.unitScale = options.unitScale ?? null;
|
|
55
|
+
}
|
|
56
|
+
/** The level currently applied to an element (0 = untouched). */
|
|
57
|
+
levelOf(expressId) {
|
|
58
|
+
return this.applied.get(expressId)?.level ?? 0;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The coordinate-frame shift of the meshes this session works with (the
|
|
62
|
+
* supplied `originShift`, or the session's own load's after self-meshing).
|
|
63
|
+
* A viewer whose scene uses a different anchor (multi-model federation
|
|
64
|
+
* with a shared RTC) translates render-mesh origins by the difference.
|
|
65
|
+
*/
|
|
66
|
+
getOriginShift() {
|
|
67
|
+
return { ...this.originShift };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* The ORIGINAL mesh records of `expressIds` (session frame, untouched by
|
|
71
|
+
* any simplification) — lets a viewer restore an element's real geometry
|
|
72
|
+
* in the scene after `reset()`. Meshes the source on first use.
|
|
73
|
+
*/
|
|
74
|
+
async originalMeshesFor(expressIds) {
|
|
75
|
+
const meshes = await this.ensureMeshes();
|
|
76
|
+
const wanted = new Set(expressIds);
|
|
77
|
+
return meshes.filter((m) => wanted.has(m.expressId));
|
|
78
|
+
}
|
|
79
|
+
/** Express ids currently carrying simplified geometry. */
|
|
80
|
+
simplifiedIds() {
|
|
81
|
+
return [...this.applied.keys()];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Simplify `expressIds` at `level`, or — when `level` is omitted — one
|
|
85
|
+
* level past each element's current one (the button behavior: press,
|
|
86
|
+
* press again, ...; capped at 5).
|
|
87
|
+
*/
|
|
88
|
+
async simplify(expressIds, level) {
|
|
89
|
+
const meshes = await this.ensureMeshes();
|
|
90
|
+
const unitScale = await this.ensureUnitScale();
|
|
91
|
+
const gp = await this.ensureProcessor();
|
|
92
|
+
const levels = new Map();
|
|
93
|
+
for (const id of expressIds) {
|
|
94
|
+
levels.set(id, Math.min(5, level ?? this.levelOf(id) + 1));
|
|
95
|
+
}
|
|
96
|
+
const targetIds = new Set(levels.keys());
|
|
97
|
+
// Always simplify from the ORIGINAL records of the selection.
|
|
98
|
+
const records = meshes.filter((m) => targetIds.has(m.expressId));
|
|
99
|
+
const out = gp.simplifyMeshes(records, levels, {
|
|
100
|
+
originShift: this.originShift,
|
|
101
|
+
unitScale,
|
|
102
|
+
});
|
|
103
|
+
if (!out) {
|
|
104
|
+
throw new Error('DemeshSession.simplify: geometry processor is not initialized');
|
|
105
|
+
}
|
|
106
|
+
const result = { renderMeshes: [], elements: [], skipped: out.skipped };
|
|
107
|
+
for (const el of out.elements) {
|
|
108
|
+
this.applied.set(el.expressId, el);
|
|
109
|
+
result.renderMeshes.push(el.render);
|
|
110
|
+
result.elements.push({
|
|
111
|
+
expressId: el.expressId,
|
|
112
|
+
level: el.level,
|
|
113
|
+
trisBefore: el.trisBefore,
|
|
114
|
+
trisAfter: el.trisAfter,
|
|
115
|
+
cavitiesDropped: el.cavitiesDropped,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Forget the simplification state for `expressIds` (all when omitted).
|
|
122
|
+
* The caller restores the elements' original meshes in the scene.
|
|
123
|
+
*/
|
|
124
|
+
reset(expressIds) {
|
|
125
|
+
if (!expressIds) {
|
|
126
|
+
this.applied.clear();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
for (const id of expressIds)
|
|
130
|
+
this.applied.delete(id);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* The `n` heaviest elements by triangle count — demesh candidates for the
|
|
134
|
+
* UI. Requires meshes (supplied or produced on first `simplify`).
|
|
135
|
+
*/
|
|
136
|
+
async heaviest(n) {
|
|
137
|
+
const meshes = await this.ensureMeshes();
|
|
138
|
+
const byElement = new Map();
|
|
139
|
+
for (const m of meshes) {
|
|
140
|
+
if ((m.geometryClass ?? 0) !== 0)
|
|
141
|
+
continue;
|
|
142
|
+
byElement.set(m.expressId, (byElement.get(m.expressId) ?? 0) + m.indices.length / 3);
|
|
143
|
+
}
|
|
144
|
+
return [...byElement.entries()]
|
|
145
|
+
.map(([expressId, triangles]) => ({ expressId, triangles }))
|
|
146
|
+
.sort((a, b) => b.triangles - a.triangles)
|
|
147
|
+
.slice(0, Math.max(0, n));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Write the lighter IFC: original bytes + tessellated replacements for
|
|
151
|
+
* every currently simplified element. Does not mutate session state — the
|
|
152
|
+
* user can keep simplifying and export again.
|
|
153
|
+
*/
|
|
154
|
+
async exportIfc() {
|
|
155
|
+
if (this.applied.size === 0) {
|
|
156
|
+
throw new Error('DemeshSession.exportIfc: nothing simplified yet');
|
|
157
|
+
}
|
|
158
|
+
// Load (and upconvert when needed) the store the mutations apply to.
|
|
159
|
+
let sourceBytes = this.source;
|
|
160
|
+
let upconverted = false;
|
|
161
|
+
let store = await new IfcParser().parseColumnar(toArrayBuffer(sourceBytes), {
|
|
162
|
+
disableWorkerScan: true,
|
|
163
|
+
});
|
|
164
|
+
if ((store.schemaVersion ?? 'IFC4').toUpperCase() === 'IFC2X3') {
|
|
165
|
+
// IfcTriangulatedFaceSet is IFC4+. The schema conversion is a
|
|
166
|
+
// line-faithful rewrite (express ids preserved), so the session's
|
|
167
|
+
// element ids stay valid against the converted buffer.
|
|
168
|
+
const converted = new StepExporter(store).export({ schema: 'IFC4' });
|
|
169
|
+
sourceBytes = converted.content;
|
|
170
|
+
store = await new IfcParser().parseColumnar(toArrayBuffer(sourceBytes), {
|
|
171
|
+
disableWorkerScan: true,
|
|
172
|
+
});
|
|
173
|
+
upconverted = true;
|
|
174
|
+
}
|
|
175
|
+
const view = new MutablePropertyView(null, 'default');
|
|
176
|
+
const editor = new StoreEditor(store, view);
|
|
177
|
+
const elements = [...this.applied.values()].map((el) => ({
|
|
178
|
+
expressId: el.expressId,
|
|
179
|
+
positions: el.localPositions,
|
|
180
|
+
indices: el.localIndices,
|
|
181
|
+
color: el.render.color,
|
|
182
|
+
}));
|
|
183
|
+
const report = applySimplifiedGeometry(store, editor, elements);
|
|
184
|
+
const schema = ((store.schemaVersion ?? 'IFC4').toUpperCase() === 'IFC2X3' ? 'IFC4' : (store.schemaVersion ?? 'IFC4'));
|
|
185
|
+
const result = new StepExporter(store, view).export({ schema, applyMutations: true });
|
|
186
|
+
return {
|
|
187
|
+
bytes: result.content,
|
|
188
|
+
report,
|
|
189
|
+
upconverted,
|
|
190
|
+
bytesBefore: this.source.byteLength,
|
|
191
|
+
bytesAfter: result.content.byteLength,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** Release the session's own GeometryProcessor (a shared one is untouched). */
|
|
195
|
+
destroy() {
|
|
196
|
+
if (this.ownsGp && this.gp) {
|
|
197
|
+
this.gp.dispose();
|
|
198
|
+
}
|
|
199
|
+
this.gp = null;
|
|
200
|
+
this.gpPromise = null;
|
|
201
|
+
this.meshes = null;
|
|
202
|
+
this.meshesPromise = null;
|
|
203
|
+
this.unitScalePromise = null;
|
|
204
|
+
this.applied.clear();
|
|
205
|
+
}
|
|
206
|
+
ensureProcessor() {
|
|
207
|
+
this.gpPromise ??= (async () => {
|
|
208
|
+
if (this.options.geometryProcessor) {
|
|
209
|
+
this.gp = this.options.geometryProcessor;
|
|
210
|
+
return this.gp;
|
|
211
|
+
}
|
|
212
|
+
const gp = new GeometryProcessor();
|
|
213
|
+
// Track before init so destroy() during a pending init still disposes.
|
|
214
|
+
this.gp = gp;
|
|
215
|
+
this.ownsGp = true;
|
|
216
|
+
await gp.init();
|
|
217
|
+
return gp;
|
|
218
|
+
})();
|
|
219
|
+
return this.gpPromise;
|
|
220
|
+
}
|
|
221
|
+
ensureMeshes() {
|
|
222
|
+
this.meshesPromise ??= (async () => {
|
|
223
|
+
if (this.meshes)
|
|
224
|
+
return this.meshes;
|
|
225
|
+
const gp = await this.ensureProcessor();
|
|
226
|
+
const meshes = [];
|
|
227
|
+
for await (const event of gp.processAdaptive(this.source, { sizeThreshold: 0 })) {
|
|
228
|
+
if (event.type === 'batch') {
|
|
229
|
+
meshes.push(...event.meshes);
|
|
230
|
+
if (event.coordinateInfo)
|
|
231
|
+
this.originShift = event.coordinateInfo.originShift;
|
|
232
|
+
}
|
|
233
|
+
else if (event.type === 'complete' && event.coordinateInfo) {
|
|
234
|
+
this.originShift = event.coordinateInfo.originShift;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
this.meshes = meshes;
|
|
238
|
+
return meshes;
|
|
239
|
+
})();
|
|
240
|
+
return this.meshesPromise;
|
|
241
|
+
}
|
|
242
|
+
ensureUnitScale() {
|
|
243
|
+
this.unitScalePromise ??= (async () => {
|
|
244
|
+
if (this.unitScale !== null)
|
|
245
|
+
return this.unitScale;
|
|
246
|
+
const { scanIfcEntities, extractLengthUnitScale } = await import('@ifc-lite/parser');
|
|
247
|
+
const { entityRefs } = await scanIfcEntities(toArrayBuffer(this.source));
|
|
248
|
+
const byId = new Map();
|
|
249
|
+
const byType = new Map();
|
|
250
|
+
for (const ref of entityRefs) {
|
|
251
|
+
byId.set(ref.expressId, ref);
|
|
252
|
+
const type = String(ref.type || '').toUpperCase();
|
|
253
|
+
const list = byType.get(type);
|
|
254
|
+
if (list)
|
|
255
|
+
list.push(ref.expressId);
|
|
256
|
+
else
|
|
257
|
+
byType.set(type, [ref.expressId]);
|
|
258
|
+
}
|
|
259
|
+
this.unitScale = extractLengthUnitScale(this.source, { byId, byType });
|
|
260
|
+
return this.unitScale;
|
|
261
|
+
})();
|
|
262
|
+
return this.unitScalePromise;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function toArrayBuffer(bytes) {
|
|
266
|
+
if (bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength && bytes.buffer instanceof ArrayBuffer) {
|
|
267
|
+
return bytes.buffer;
|
|
268
|
+
}
|
|
269
|
+
const copy = new ArrayBuffer(bytes.byteLength);
|
|
270
|
+
new Uint8Array(copy).set(bytes);
|
|
271
|
+
return copy;
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=demesh-session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"demesh-session.js","sourceRoot":"","sources":["../src/demesh-session.ts"],"names":[],"mappings":"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"}
|