@sequent-org/ifc-viewer 1.1.1-ci.20.0 → 1.2.3-ci.22.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/package.json +6 -10
- package/src/compat/IFCLoader.js +2657 -0
- package/src/ifc/IfcService.js +1 -1
- package/patches/web-ifc-three+0.0.126.patch +0 -27
|
@@ -0,0 +1,2657 @@
|
|
|
1
|
+
import * as WebIFC from 'web-ifc';
|
|
2
|
+
import { IFCSPACE, IFCOPENINGELEMENT, IFCPRODUCTDEFINITIONSHAPE, IFCRELAGGREGATES, IFCRELCONTAINEDINSPATIALSTRUCTURE, IFCRELDEFINESBYPROPERTIES, IFCRELASSOCIATESMATERIAL, IFCRELDEFINESBYTYPE, IFCPROJECT, IFCBUILDING } from 'web-ifc';
|
|
3
|
+
import { Mesh, Color, MeshLambertMaterial, DoubleSide, Matrix4, BufferGeometry, BufferAttribute, Loader, FileLoader } from 'three';
|
|
4
|
+
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
5
|
+
|
|
6
|
+
const nullIfcManagerErrorMessage = 'IfcManager is null!';
|
|
7
|
+
|
|
8
|
+
class IFCModel extends Mesh {
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
this.modelID = IFCModel.modelIdCounter++;
|
|
13
|
+
this.ifcManager = null;
|
|
14
|
+
this.mesh = this;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static dispose() {
|
|
18
|
+
IFCModel.modelIdCounter = 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
setIFCManager(manager) {
|
|
22
|
+
this.ifcManager = manager;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setWasmPath(path) {
|
|
26
|
+
if (this.ifcManager === null)
|
|
27
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
28
|
+
this.ifcManager.setWasmPath(path);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
close(scene) {
|
|
32
|
+
if (this.ifcManager === null)
|
|
33
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
34
|
+
this.ifcManager.close(this.modelID, scene);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
getExpressId(geometry, faceIndex) {
|
|
38
|
+
if (this.ifcManager === null)
|
|
39
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
40
|
+
return this.ifcManager.getExpressId(geometry, faceIndex);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getAllItemsOfType(type, verbose) {
|
|
44
|
+
if (this.ifcManager === null)
|
|
45
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
46
|
+
return this.ifcManager.getAllItemsOfType(this.modelID, type, verbose);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
getItemProperties(id, recursive = false) {
|
|
50
|
+
if (this.ifcManager === null)
|
|
51
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
52
|
+
return this.ifcManager.getItemProperties(this.modelID, id, recursive);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getPropertySets(id, recursive = false) {
|
|
56
|
+
if (this.ifcManager === null)
|
|
57
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
58
|
+
return this.ifcManager.getPropertySets(this.modelID, id, recursive);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getTypeProperties(id, recursive = false) {
|
|
62
|
+
if (this.ifcManager === null)
|
|
63
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
64
|
+
return this.ifcManager.getTypeProperties(this.modelID, id, recursive);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getIfcType(id) {
|
|
68
|
+
if (this.ifcManager === null)
|
|
69
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
70
|
+
return this.ifcManager.getIfcType(this.modelID, id);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
getSpatialStructure() {
|
|
74
|
+
if (this.ifcManager === null)
|
|
75
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
76
|
+
return this.ifcManager.getSpatialStructure(this.modelID);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
getSubset(material) {
|
|
80
|
+
if (this.ifcManager === null)
|
|
81
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
82
|
+
return this.ifcManager.getSubset(this.modelID, material);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
removeSubset(material, customID) {
|
|
86
|
+
if (this.ifcManager === null)
|
|
87
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
88
|
+
this.ifcManager.removeSubset(this.modelID, material, customID);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
createSubset(config) {
|
|
92
|
+
if (this.ifcManager === null)
|
|
93
|
+
throw new Error(nullIfcManagerErrorMessage);
|
|
94
|
+
const modelConfig = {
|
|
95
|
+
...config,
|
|
96
|
+
modelID: this.modelID
|
|
97
|
+
};
|
|
98
|
+
return this.ifcManager.createSubset(modelConfig);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
IFCModel.modelIdCounter = 0;
|
|
104
|
+
|
|
105
|
+
class IFCParser {
|
|
106
|
+
|
|
107
|
+
constructor(state, BVH) {
|
|
108
|
+
this.state = state;
|
|
109
|
+
this.BVH = BVH;
|
|
110
|
+
this.loadedModels = 0;
|
|
111
|
+
this.optionalCategories = {
|
|
112
|
+
[IFCSPACE]: true,
|
|
113
|
+
[IFCOPENINGELEMENT]: false
|
|
114
|
+
};
|
|
115
|
+
this.geometriesByMaterials = {};
|
|
116
|
+
this.loadingState = {
|
|
117
|
+
total: 0,
|
|
118
|
+
current: 0,
|
|
119
|
+
step: 0.1
|
|
120
|
+
};
|
|
121
|
+
this.currentWebIfcID = -1;
|
|
122
|
+
this.currentModelID = -1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async setupOptionalCategories(config) {
|
|
126
|
+
this.optionalCategories = config;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async parse(buffer, coordinationMatrix) {
|
|
130
|
+
if (this.state.api.wasmModule === undefined)
|
|
131
|
+
await this.state.api.Init();
|
|
132
|
+
await this.newIfcModel(buffer);
|
|
133
|
+
this.loadedModels++;
|
|
134
|
+
if (coordinationMatrix) {
|
|
135
|
+
await this.state.api.SetGeometryTransformation(this.currentWebIfcID, coordinationMatrix);
|
|
136
|
+
}
|
|
137
|
+
return this.loadAllGeometry(this.currentWebIfcID);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
getAndClearErrors(_modelId) {}
|
|
141
|
+
|
|
142
|
+
notifyProgress(loaded, total) {
|
|
143
|
+
if (this.state.onProgress)
|
|
144
|
+
this.state.onProgress({
|
|
145
|
+
loaded,
|
|
146
|
+
total
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async newIfcModel(buffer) {
|
|
151
|
+
const data = new Uint8Array(buffer);
|
|
152
|
+
this.currentWebIfcID = await this.state.api.OpenModel(data, this.state.webIfcSettings);
|
|
153
|
+
this.currentModelID = this.state.useJSON ? this.loadedModels : this.currentWebIfcID;
|
|
154
|
+
this.state.models[this.currentModelID] = {
|
|
155
|
+
modelID: this.currentModelID,
|
|
156
|
+
mesh: {},
|
|
157
|
+
types: {},
|
|
158
|
+
jsonData: {}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async loadAllGeometry(modelID) {
|
|
163
|
+
this.addOptionalCategories(modelID);
|
|
164
|
+
await this.initializeLoadingState(modelID);
|
|
165
|
+
this.state.api.StreamAllMeshes(modelID, (mesh) => {
|
|
166
|
+
this.updateLoadingState();
|
|
167
|
+
this.streamMesh(modelID, mesh);
|
|
168
|
+
});
|
|
169
|
+
this.notifyLoadingEnded();
|
|
170
|
+
const geometries = [];
|
|
171
|
+
const materials = [];
|
|
172
|
+
Object.keys(this.geometriesByMaterials).forEach((key) => {
|
|
173
|
+
const geometriesByMaterial = this.geometriesByMaterials[key].geometries;
|
|
174
|
+
const merged = mergeBufferGeometries(geometriesByMaterial);
|
|
175
|
+
materials.push(this.geometriesByMaterials[key].material);
|
|
176
|
+
geometries.push(merged);
|
|
177
|
+
});
|
|
178
|
+
const combinedGeometry = mergeBufferGeometries(geometries, true);
|
|
179
|
+
this.cleanUpGeometryMemory(geometries);
|
|
180
|
+
if (this.BVH)
|
|
181
|
+
this.BVH.applyThreeMeshBVH(combinedGeometry);
|
|
182
|
+
const model = new IFCModel(combinedGeometry, materials);
|
|
183
|
+
this.state.models[this.currentModelID].mesh = model;
|
|
184
|
+
return model;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async initializeLoadingState(modelID) {
|
|
188
|
+
const shapes = await this.state.api.GetLineIDsWithType(modelID, IFCPRODUCTDEFINITIONSHAPE);
|
|
189
|
+
this.loadingState.total = shapes.size();
|
|
190
|
+
this.loadingState.current = 0;
|
|
191
|
+
this.loadingState.step = 0.1;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
notifyLoadingEnded() {
|
|
195
|
+
this.notifyProgress(this.loadingState.total, this.loadingState.total);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
updateLoadingState() {
|
|
199
|
+
const realCurrentItem = Math.min(this.loadingState.current++, this.loadingState.total);
|
|
200
|
+
if (realCurrentItem / this.loadingState.total >= this.loadingState.step) {
|
|
201
|
+
const currentProgress = Math.ceil(this.loadingState.total * this.loadingState.step);
|
|
202
|
+
this.notifyProgress(currentProgress, this.loadingState.total);
|
|
203
|
+
this.loadingState.step += 0.1;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
addOptionalCategories(modelID) {
|
|
208
|
+
const optionalTypes = [];
|
|
209
|
+
for (let key in this.optionalCategories) {
|
|
210
|
+
if (this.optionalCategories.hasOwnProperty(key)) {
|
|
211
|
+
const category = parseInt(key);
|
|
212
|
+
if (this.optionalCategories[category])
|
|
213
|
+
optionalTypes.push(category);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
this.state.api.StreamAllMeshesWithTypes(this.currentWebIfcID, optionalTypes, (mesh) => {
|
|
217
|
+
this.streamMesh(modelID, mesh);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
streamMesh(modelID, mesh) {
|
|
222
|
+
const placedGeometries = mesh.geometries;
|
|
223
|
+
const size = placedGeometries.size();
|
|
224
|
+
for (let i = 0; i < size; i++) {
|
|
225
|
+
const placedGeometry = placedGeometries.get(i);
|
|
226
|
+
let itemMesh = this.getPlacedGeometry(modelID, mesh.expressID, placedGeometry);
|
|
227
|
+
let geom = itemMesh.geometry.applyMatrix4(itemMesh.matrix);
|
|
228
|
+
this.storeGeometryByMaterial(placedGeometry.color, geom);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
getPlacedGeometry(modelID, expressID, placedGeometry) {
|
|
233
|
+
const geometry = this.getBufferGeometry(modelID, expressID, placedGeometry);
|
|
234
|
+
const mesh = new Mesh(geometry);
|
|
235
|
+
mesh.matrix = this.getMeshMatrix(placedGeometry.flatTransformation);
|
|
236
|
+
mesh.matrixAutoUpdate = false;
|
|
237
|
+
return mesh;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
getBufferGeometry(modelID, expressID, placedGeometry) {
|
|
241
|
+
const geometry = this.state.api.GetGeometry(modelID, placedGeometry.geometryExpressID);
|
|
242
|
+
const verts = this.state.api.GetVertexArray(geometry.GetVertexData(), geometry.GetVertexDataSize());
|
|
243
|
+
const indices = this.state.api.GetIndexArray(geometry.GetIndexData(), geometry.GetIndexDataSize());
|
|
244
|
+
const buffer = this.ifcGeometryToBuffer(expressID, verts, indices);
|
|
245
|
+
geometry.delete();
|
|
246
|
+
return buffer;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
storeGeometryByMaterial(color, geometry) {
|
|
250
|
+
let colID = `${color.x}${color.y}${color.z}${color.w}`;
|
|
251
|
+
if (this.geometriesByMaterials[colID]) {
|
|
252
|
+
this.geometriesByMaterials[colID].geometries.push(geometry);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const col = new Color().setRGB(color.x, color.y, color.z, 'srgb');
|
|
256
|
+
const material = new MeshLambertMaterial({
|
|
257
|
+
color: col,
|
|
258
|
+
side: DoubleSide
|
|
259
|
+
});
|
|
260
|
+
material.transparent = color.w !== 1;
|
|
261
|
+
if (material.transparent)
|
|
262
|
+
material.opacity = color.w;
|
|
263
|
+
this.geometriesByMaterials[colID] = {
|
|
264
|
+
material,
|
|
265
|
+
geometries: [geometry]
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
getMeshMatrix(matrix) {
|
|
270
|
+
const mat = new Matrix4();
|
|
271
|
+
mat.fromArray(matrix);
|
|
272
|
+
return mat;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
ifcGeometryToBuffer(expressID, vertexData, indexData) {
|
|
276
|
+
const geometry = new BufferGeometry();
|
|
277
|
+
const posFloats = new Float32Array(vertexData.length / 2);
|
|
278
|
+
const normFloats = new Float32Array(vertexData.length / 2);
|
|
279
|
+
const idAttribute = new Uint32Array(vertexData.length / 6);
|
|
280
|
+
for (let i = 0; i < vertexData.length; i += 6) {
|
|
281
|
+
posFloats[i / 2] = vertexData[i];
|
|
282
|
+
posFloats[i / 2 + 1] = vertexData[i + 1];
|
|
283
|
+
posFloats[i / 2 + 2] = vertexData[i + 2];
|
|
284
|
+
normFloats[i / 2] = vertexData[i + 3];
|
|
285
|
+
normFloats[i / 2 + 1] = vertexData[i + 4];
|
|
286
|
+
normFloats[i / 2 + 2] = vertexData[i + 5];
|
|
287
|
+
idAttribute[i / 6] = expressID;
|
|
288
|
+
}
|
|
289
|
+
geometry.setAttribute('position', new BufferAttribute(posFloats, 3));
|
|
290
|
+
geometry.setAttribute('normal', new BufferAttribute(normFloats, 3));
|
|
291
|
+
geometry.setAttribute('expressID', new BufferAttribute(idAttribute, 1));
|
|
292
|
+
geometry.setIndex(new BufferAttribute(indexData, 1));
|
|
293
|
+
return geometry;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
cleanUpGeometryMemory(geometries) {
|
|
297
|
+
geometries.forEach(geometry => geometry.dispose());
|
|
298
|
+
Object.keys(this.geometriesByMaterials).forEach((materialID) => {
|
|
299
|
+
const geometriesByMaterial = this.geometriesByMaterials[materialID];
|
|
300
|
+
geometriesByMaterial.geometries.forEach(geometry => geometry.dispose());
|
|
301
|
+
geometriesByMaterial.geometries = [];
|
|
302
|
+
geometriesByMaterial.material = null;
|
|
303
|
+
});
|
|
304
|
+
this.geometriesByMaterials = {};
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
class ItemsMap {
|
|
310
|
+
|
|
311
|
+
constructor(state) {
|
|
312
|
+
this.state = state;
|
|
313
|
+
this.map = {};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
generateGeometryIndexMap(modelID) {
|
|
317
|
+
if (this.map[modelID])
|
|
318
|
+
return;
|
|
319
|
+
const geometry = this.getGeometry(modelID);
|
|
320
|
+
const items = this.newItemsMap(modelID, geometry);
|
|
321
|
+
for (const group of geometry.groups) {
|
|
322
|
+
this.fillItemsWithGroupInfo(group, geometry, items);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
getSubsetID(modelID, material, customID = 'DEFAULT') {
|
|
327
|
+
const baseID = modelID;
|
|
328
|
+
const materialID = material ? material.uuid : 'DEFAULT';
|
|
329
|
+
return `${baseID} - ${materialID} - ${customID}`;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
dispose() {
|
|
333
|
+
Object.values(this.map).forEach(model => {
|
|
334
|
+
model.indexCache = null;
|
|
335
|
+
model.map = null;
|
|
336
|
+
});
|
|
337
|
+
this.map = null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
getGeometry(modelID) {
|
|
341
|
+
const geometry = this.state.models[modelID].mesh.geometry;
|
|
342
|
+
if (!geometry)
|
|
343
|
+
throw new Error('Model without geometry.');
|
|
344
|
+
if (!geometry.index)
|
|
345
|
+
throw new Error('Geometry must be indexed');
|
|
346
|
+
return geometry;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
newItemsMap(modelID, geometry) {
|
|
350
|
+
const startIndices = geometry.index.array;
|
|
351
|
+
this.map[modelID] = {
|
|
352
|
+
indexCache: startIndices.slice(0, geometry.index.array.length),
|
|
353
|
+
map: new Map()
|
|
354
|
+
};
|
|
355
|
+
return this.map[modelID];
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
fillItemsWithGroupInfo(group, geometry, items) {
|
|
359
|
+
let prevExpressID = -1;
|
|
360
|
+
const materialIndex = group.materialIndex;
|
|
361
|
+
const materialStart = group.start;
|
|
362
|
+
const materialEnd = materialStart + group.count - 1;
|
|
363
|
+
let objectStart = -1;
|
|
364
|
+
let objectEnd = -1;
|
|
365
|
+
for (let i = materialStart; i <= materialEnd; i++) {
|
|
366
|
+
const index = geometry.index.array[i];
|
|
367
|
+
const bufferAttr = geometry.attributes.expressID;
|
|
368
|
+
const expressID = bufferAttr.array[index];
|
|
369
|
+
if (prevExpressID === -1) {
|
|
370
|
+
prevExpressID = expressID;
|
|
371
|
+
objectStart = i;
|
|
372
|
+
}
|
|
373
|
+
const isEndOfMaterial = i === materialEnd;
|
|
374
|
+
if (isEndOfMaterial) {
|
|
375
|
+
const store = this.getMaterialStore(items.map, expressID, materialIndex);
|
|
376
|
+
store.push(objectStart, materialEnd);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
if (prevExpressID === expressID)
|
|
380
|
+
continue;
|
|
381
|
+
const store = this.getMaterialStore(items.map, prevExpressID, materialIndex);
|
|
382
|
+
objectEnd = i - 1;
|
|
383
|
+
store.push(objectStart, objectEnd);
|
|
384
|
+
prevExpressID = expressID;
|
|
385
|
+
objectStart = i;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
getMaterialStore(map, id, matIndex) {
|
|
390
|
+
if (map.get(id) === undefined) {
|
|
391
|
+
map.set(id, {});
|
|
392
|
+
}
|
|
393
|
+
const storedIfcItem = map.get(id);
|
|
394
|
+
if (storedIfcItem === undefined)
|
|
395
|
+
throw new Error('Geometry map generation error');
|
|
396
|
+
if (storedIfcItem[matIndex] === undefined) {
|
|
397
|
+
storedIfcItem[matIndex] = [];
|
|
398
|
+
}
|
|
399
|
+
return storedIfcItem[matIndex];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
class SubsetUtils {
|
|
405
|
+
|
|
406
|
+
static getAllIndicesOfGroup(modelID, ids, materialIndex, items, flatten = true) {
|
|
407
|
+
const indicesByGroup = [];
|
|
408
|
+
for (const expressID of ids) {
|
|
409
|
+
const entry = items.map.get(expressID);
|
|
410
|
+
if (!entry)
|
|
411
|
+
continue;
|
|
412
|
+
const value = entry[materialIndex];
|
|
413
|
+
if (!value)
|
|
414
|
+
continue;
|
|
415
|
+
SubsetUtils.getIndexChunk(value, indicesByGroup, materialIndex, items, flatten);
|
|
416
|
+
}
|
|
417
|
+
return indicesByGroup;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
static getIndexChunk(value, indicesByGroup, materialIndex, items, flatten) {
|
|
421
|
+
const pairs = value.length / 2;
|
|
422
|
+
for (let pair = 0; pair < pairs; pair++) {
|
|
423
|
+
const pairIndex = pair * 2;
|
|
424
|
+
const start = value[pairIndex];
|
|
425
|
+
const end = value[pairIndex + 1];
|
|
426
|
+
for (let j = start; j <= end; j++) {
|
|
427
|
+
if (flatten)
|
|
428
|
+
indicesByGroup.push(items.indexCache[j]);
|
|
429
|
+
else {
|
|
430
|
+
if (!indicesByGroup[materialIndex])
|
|
431
|
+
indicesByGroup[materialIndex] = [];
|
|
432
|
+
indicesByGroup[materialIndex].push(items.indexCache[j]);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
class SubsetCreator {
|
|
441
|
+
|
|
442
|
+
constructor(state, items, subsets, BVH) {
|
|
443
|
+
this.state = state;
|
|
444
|
+
this.items = items;
|
|
445
|
+
this.subsets = subsets;
|
|
446
|
+
this.BVH = BVH;
|
|
447
|
+
this.tempIndex = [];
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
createSubset(config, subsetID) {
|
|
451
|
+
if (!this.items.map[config.modelID])
|
|
452
|
+
this.items.generateGeometryIndexMap(config.modelID);
|
|
453
|
+
if (!this.subsets[subsetID])
|
|
454
|
+
this.initializeSubset(config, subsetID);
|
|
455
|
+
this.filterIndices(config, subsetID);
|
|
456
|
+
this.constructSubsetByMaterial(config, subsetID);
|
|
457
|
+
config.ids.forEach(id => this.subsets[subsetID].ids.add(id));
|
|
458
|
+
this.subsets[subsetID].mesh.geometry.setIndex(this.tempIndex);
|
|
459
|
+
this.tempIndex.length = 0;
|
|
460
|
+
const subset = this.subsets[subsetID].mesh;
|
|
461
|
+
if (config.applyBVH)
|
|
462
|
+
this.BVH.applyThreeMeshBVH(subset.geometry);
|
|
463
|
+
if (config.scene)
|
|
464
|
+
config.scene.add(subset);
|
|
465
|
+
return this.subsets[subsetID].mesh;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
dispose() {
|
|
469
|
+
this.tempIndex = [];
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
initializeSubset(config, subsetID) {
|
|
473
|
+
const model = this.state.models[config.modelID].mesh;
|
|
474
|
+
const subsetGeom = new BufferGeometry();
|
|
475
|
+
this.initializeSubsetAttributes(subsetGeom, model);
|
|
476
|
+
if (!config.material)
|
|
477
|
+
this.initializeSubsetGroups(subsetGeom, model);
|
|
478
|
+
const mesh = new Mesh(subsetGeom, config.material || model.material);
|
|
479
|
+
mesh.modelID = config.modelID;
|
|
480
|
+
const bvh = Boolean(config.applyBVH);
|
|
481
|
+
this.subsets[subsetID] = {
|
|
482
|
+
ids: new Set(),
|
|
483
|
+
mesh,
|
|
484
|
+
bvh
|
|
485
|
+
};
|
|
486
|
+
model.add(mesh);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
initializeSubsetAttributes(subsetGeom, model) {
|
|
490
|
+
subsetGeom.setAttribute('position', model.geometry.attributes.position);
|
|
491
|
+
subsetGeom.setAttribute('normal', model.geometry.attributes.normal);
|
|
492
|
+
subsetGeom.setAttribute('expressID', model.geometry.attributes.expressID);
|
|
493
|
+
subsetGeom.setIndex([]);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
initializeSubsetGroups(subsetGeom, model) {
|
|
497
|
+
subsetGeom.groups = JSON.parse(JSON.stringify(model.geometry.groups));
|
|
498
|
+
this.resetGroups(subsetGeom);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
filterIndices(config, subsetID) {
|
|
502
|
+
const geometry = this.subsets[subsetID].mesh.geometry;
|
|
503
|
+
if (config.removePrevious) {
|
|
504
|
+
geometry.setIndex([]);
|
|
505
|
+
this.resetGroups(geometry);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const previousIndices = geometry.index.array;
|
|
509
|
+
const previousIDs = this.subsets[subsetID].ids;
|
|
510
|
+
config.ids = config.ids.filter(id => !previousIDs.has(id));
|
|
511
|
+
this.tempIndex = Array.from(previousIndices);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
constructSubsetByMaterial(config, subsetID) {
|
|
515
|
+
const model = this.state.models[config.modelID].mesh;
|
|
516
|
+
const newIndices = {
|
|
517
|
+
count: 0
|
|
518
|
+
};
|
|
519
|
+
for (let i = 0; i < model.geometry.groups.length; i++) {
|
|
520
|
+
this.insertNewIndices(config, subsetID, i, newIndices);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
insertNewIndices(config, subsetID, materialIndex, newIndices) {
|
|
525
|
+
const items = this.items.map[config.modelID];
|
|
526
|
+
const indicesOfOneMaterial = SubsetUtils.getAllIndicesOfGroup(config.modelID, config.ids, materialIndex, items);
|
|
527
|
+
if (!config.material) {
|
|
528
|
+
this.insertIndicesAtGroup(subsetID, indicesOfOneMaterial, materialIndex, newIndices);
|
|
529
|
+
} else {
|
|
530
|
+
indicesOfOneMaterial.forEach(index => this.tempIndex.push(index));
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
insertIndicesAtGroup(subsetID, indicesByGroup, index, newIndices) {
|
|
535
|
+
const currentGroup = this.getCurrentGroup(subsetID, index);
|
|
536
|
+
currentGroup.start += newIndices.count;
|
|
537
|
+
let newIndicesPosition = currentGroup.start + currentGroup.count;
|
|
538
|
+
newIndices.count += indicesByGroup.length;
|
|
539
|
+
if (indicesByGroup.length > 0) {
|
|
540
|
+
let position = newIndicesPosition;
|
|
541
|
+
const start = this.tempIndex.slice(0, position);
|
|
542
|
+
const end = this.tempIndex.slice(position);
|
|
543
|
+
this.tempIndex = Array.prototype.concat.apply([], [start, indicesByGroup, end]);
|
|
544
|
+
currentGroup.count += indicesByGroup.length;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
getCurrentGroup(subsetID, groupIndex) {
|
|
549
|
+
const geometry = this.subsets[subsetID].mesh.geometry;
|
|
550
|
+
return geometry.groups[groupIndex];
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
resetGroups(geometry) {
|
|
554
|
+
geometry.groups.forEach((group) => {
|
|
555
|
+
group.start = 0;
|
|
556
|
+
group.count = 0;
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
class SubsetManager {
|
|
563
|
+
|
|
564
|
+
constructor(state, BVH) {
|
|
565
|
+
this.subsets = {};
|
|
566
|
+
this.state = state;
|
|
567
|
+
this.items = new ItemsMap(state);
|
|
568
|
+
this.BVH = BVH;
|
|
569
|
+
this.subsetCreator = new SubsetCreator(state, this.items, this.subsets, this.BVH);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
getAllSubsets() {
|
|
573
|
+
return this.subsets;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
getSubset(modelID, material, customId) {
|
|
577
|
+
const subsetID = this.getSubsetID(modelID, material, customId);
|
|
578
|
+
return this.subsets[subsetID].mesh;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
removeSubset(modelID, material, customID) {
|
|
582
|
+
const subsetID = this.getSubsetID(modelID, material, customID);
|
|
583
|
+
const subset = this.subsets[subsetID];
|
|
584
|
+
if (!subset)
|
|
585
|
+
return;
|
|
586
|
+
if (subset.mesh.parent)
|
|
587
|
+
subset.mesh.removeFromParent();
|
|
588
|
+
subset.mesh.geometry.attributes = {};
|
|
589
|
+
subset.mesh.geometry.index = null;
|
|
590
|
+
subset.mesh.geometry.dispose();
|
|
591
|
+
subset.mesh.geometry = null;
|
|
592
|
+
delete this.subsets[subsetID];
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
createSubset(config) {
|
|
596
|
+
const subsetID = this.getSubsetID(config.modelID, config.material, config.customID);
|
|
597
|
+
return this.subsetCreator.createSubset(config, subsetID);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
removeFromSubset(modelID, ids, customID, material) {
|
|
601
|
+
const subsetID = this.getSubsetID(modelID, material, customID);
|
|
602
|
+
if (!this.subsets[subsetID])
|
|
603
|
+
return;
|
|
604
|
+
const previousIDs = this.subsets[subsetID].ids;
|
|
605
|
+
ids.forEach((id) => {
|
|
606
|
+
if (previousIDs.has(id))
|
|
607
|
+
previousIDs.delete(id);
|
|
608
|
+
});
|
|
609
|
+
return this.createSubset({
|
|
610
|
+
modelID,
|
|
611
|
+
removePrevious: true,
|
|
612
|
+
material,
|
|
613
|
+
customID,
|
|
614
|
+
applyBVH: this.subsets[subsetID].bvh,
|
|
615
|
+
ids: Array.from(previousIDs),
|
|
616
|
+
scene: this.subsets[subsetID].mesh.parent
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
clearSubset(modelID, customID, material) {
|
|
621
|
+
const subsetID = this.getSubsetID(modelID, material, customID);
|
|
622
|
+
if (!this.subsets[subsetID])
|
|
623
|
+
return;
|
|
624
|
+
this.subsets[subsetID].ids.clear();
|
|
625
|
+
const subset = this.getSubset(modelID, material, customID);
|
|
626
|
+
subset.geometry.setIndex([]);
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
dispose() {
|
|
630
|
+
this.items.dispose();
|
|
631
|
+
this.subsetCreator.dispose();
|
|
632
|
+
Object.values(this.subsets).forEach(subset => {
|
|
633
|
+
subset.ids = null;
|
|
634
|
+
subset.mesh.removeFromParent();
|
|
635
|
+
const mats = subset.mesh.material;
|
|
636
|
+
if (Array.isArray(mats))
|
|
637
|
+
mats.forEach(mat => mat.dispose());
|
|
638
|
+
else
|
|
639
|
+
mats.dispose();
|
|
640
|
+
subset.mesh.geometry.index = null;
|
|
641
|
+
subset.mesh.geometry.dispose();
|
|
642
|
+
const geom = subset.mesh.geometry;
|
|
643
|
+
if (geom.disposeBoundsTree)
|
|
644
|
+
geom.disposeBoundsTree();
|
|
645
|
+
subset.mesh = null;
|
|
646
|
+
});
|
|
647
|
+
this.subsets = null;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
getSubsetID(modelID, material, customID = 'DEFAULT') {
|
|
651
|
+
const baseID = modelID;
|
|
652
|
+
const materialID = material ? material.uuid : 'DEFAULT';
|
|
653
|
+
return `${baseID} - ${materialID} - ${customID}`;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
const IdAttrName = 'expressID';
|
|
659
|
+
const PropsNames = {
|
|
660
|
+
aggregates: {
|
|
661
|
+
name: IFCRELAGGREGATES,
|
|
662
|
+
relating: 'RelatingObject',
|
|
663
|
+
related: 'RelatedObjects',
|
|
664
|
+
key: 'children'
|
|
665
|
+
},
|
|
666
|
+
spatial: {
|
|
667
|
+
name: IFCRELCONTAINEDINSPATIALSTRUCTURE,
|
|
668
|
+
relating: 'RelatingStructure',
|
|
669
|
+
related: 'RelatedElements',
|
|
670
|
+
key: 'children'
|
|
671
|
+
},
|
|
672
|
+
psets: {
|
|
673
|
+
name: IFCRELDEFINESBYPROPERTIES,
|
|
674
|
+
relating: 'RelatingPropertyDefinition',
|
|
675
|
+
related: 'RelatedObjects',
|
|
676
|
+
key: 'hasPsets'
|
|
677
|
+
},
|
|
678
|
+
materials: {
|
|
679
|
+
name: IFCRELASSOCIATESMATERIAL,
|
|
680
|
+
relating: 'RelatingMaterial',
|
|
681
|
+
related: 'RelatedObjects',
|
|
682
|
+
key: 'hasMaterial'
|
|
683
|
+
},
|
|
684
|
+
type: {
|
|
685
|
+
name: IFCRELDEFINESBYTYPE,
|
|
686
|
+
relating: 'RelatingType',
|
|
687
|
+
related: 'RelatedObjects',
|
|
688
|
+
key: 'hasType'
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
class BasePropertyManager {
|
|
693
|
+
|
|
694
|
+
constructor(state) {
|
|
695
|
+
this.state = state;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
async getPropertySets(modelID, elementID, recursive = false) {
|
|
699
|
+
return await this.getProperty(modelID, elementID, recursive, PropsNames.psets);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
async getTypeProperties(modelID, elementID, recursive = false) {
|
|
703
|
+
return await this.getProperty(modelID, elementID, recursive, PropsNames.type);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
async getMaterialsProperties(modelID, elementID, recursive = false) {
|
|
707
|
+
return await this.getProperty(modelID, elementID, recursive, PropsNames.materials);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
async getSpatialNode(modelID, node, treeChunks, includeProperties) {
|
|
711
|
+
await this.getChildren(modelID, node, treeChunks, PropsNames.aggregates, includeProperties);
|
|
712
|
+
await this.getChildren(modelID, node, treeChunks, PropsNames.spatial, includeProperties);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
async getChildren(modelID, node, treeChunks, propNames, includeProperties) {
|
|
716
|
+
const children = treeChunks[node.expressID];
|
|
717
|
+
if (children == undefined)
|
|
718
|
+
return;
|
|
719
|
+
const prop = propNames.key;
|
|
720
|
+
const nodes = [];
|
|
721
|
+
for (let i = 0; i < children.length; i++) {
|
|
722
|
+
const child = children[i];
|
|
723
|
+
let node = this.newNode(modelID, child);
|
|
724
|
+
if (includeProperties) {
|
|
725
|
+
const properties = await this.getItemProperties(modelID, node.expressID);
|
|
726
|
+
node = {
|
|
727
|
+
...properties, ...node
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
await this.getSpatialNode(modelID, node, treeChunks, includeProperties);
|
|
731
|
+
nodes.push(node);
|
|
732
|
+
}
|
|
733
|
+
node[prop] = nodes;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
newNode(modelID, id) {
|
|
737
|
+
const typeName = this.getNodeType(modelID, id);
|
|
738
|
+
return {
|
|
739
|
+
expressID: id,
|
|
740
|
+
type: typeName,
|
|
741
|
+
children: []
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
async getSpatialTreeChunks(modelID) {
|
|
746
|
+
const treeChunks = {};
|
|
747
|
+
await this.getChunks(modelID, treeChunks, PropsNames.aggregates);
|
|
748
|
+
await this.getChunks(modelID, treeChunks, PropsNames.spatial);
|
|
749
|
+
return treeChunks;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
saveChunk(chunks, propNames, rel) {
|
|
753
|
+
const relating = rel[propNames.relating].value;
|
|
754
|
+
const related = rel[propNames.related].map((r) => r.value);
|
|
755
|
+
if (chunks[relating] == undefined) {
|
|
756
|
+
chunks[relating] = related;
|
|
757
|
+
} else {
|
|
758
|
+
chunks[relating] = chunks[relating].concat(related);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
getRelated(rel, propNames, IDs) {
|
|
763
|
+
const element = rel[propNames.relating];
|
|
764
|
+
if (!element) {
|
|
765
|
+
return console.warn(`The object with ID ${rel.expressID} has a broken reference.`);
|
|
766
|
+
}
|
|
767
|
+
if (!Array.isArray(element))
|
|
768
|
+
IDs.push(element.value);
|
|
769
|
+
else
|
|
770
|
+
element.forEach((ele) => IDs.push(ele.value));
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
static isRelated(id, rel, propNames) {
|
|
774
|
+
const relatedItems = rel[propNames.related];
|
|
775
|
+
if (Array.isArray(relatedItems)) {
|
|
776
|
+
const values = relatedItems.map((item) => item.value);
|
|
777
|
+
return values.includes(id);
|
|
778
|
+
}
|
|
779
|
+
return relatedItems.value === id;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
static newIfcProject(id) {
|
|
783
|
+
return {
|
|
784
|
+
expressID: id,
|
|
785
|
+
type: 'IFCPROJECT',
|
|
786
|
+
children: []
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
async getProperty(modelID, elementID, recursive = false, propName) {}
|
|
791
|
+
|
|
792
|
+
async getChunks(modelID, chunks, propNames) {}
|
|
793
|
+
|
|
794
|
+
async getItemProperties(modelID, expressID, recursive = false) {}
|
|
795
|
+
|
|
796
|
+
getNodeType(modelID, id) {}
|
|
797
|
+
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
class WebIfcPropertyManager extends BasePropertyManager {
|
|
801
|
+
|
|
802
|
+
async getItemProperties(modelID, id, recursive = false) {
|
|
803
|
+
return this.state.api.GetLine(modelID, id, recursive);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
async getHeaderLine(modelID, headerType) {
|
|
807
|
+
return this.state.api.GetHeaderLine(modelID, headerType);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
async getSpatialStructure(modelID, includeProperties) {
|
|
811
|
+
const chunks = await this.getSpatialTreeChunks(modelID);
|
|
812
|
+
const allLines = await this.state.api.GetLineIDsWithType(modelID, IFCPROJECT);
|
|
813
|
+
const projectID = allLines.get(0);
|
|
814
|
+
const project = WebIfcPropertyManager.newIfcProject(projectID);
|
|
815
|
+
await this.getSpatialNode(modelID, project, chunks, includeProperties);
|
|
816
|
+
return project;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
async getAllItemsOfType(modelID, type, verbose) {
|
|
820
|
+
let items = [];
|
|
821
|
+
const lines = await this.state.api.GetLineIDsWithType(modelID, type);
|
|
822
|
+
for (let i = 0; i < lines.size(); i++)
|
|
823
|
+
items.push(lines.get(i));
|
|
824
|
+
if (!verbose)
|
|
825
|
+
return items;
|
|
826
|
+
const result = [];
|
|
827
|
+
for (let i = 0; i < items.length; i++) {
|
|
828
|
+
result.push(await this.state.api.GetLine(modelID, items[i]));
|
|
829
|
+
}
|
|
830
|
+
return result;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
async getProperty(modelID, elementID, recursive = false, propName) {
|
|
834
|
+
const propSetIds = await this.getAllRelatedItemsOfType(modelID, elementID, propName);
|
|
835
|
+
const result = [];
|
|
836
|
+
for (let i = 0; i < propSetIds.length; i++) {
|
|
837
|
+
result.push(await this.state.api.GetLine(modelID, propSetIds[i], recursive));
|
|
838
|
+
}
|
|
839
|
+
return result;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
getNodeType(modelID, id) {
|
|
843
|
+
const typeID = this.state.models[modelID].types[id];
|
|
844
|
+
return this.state.api.GetNameFromTypeCode(typeID);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
async getChunks(modelID, chunks, propNames) {
|
|
848
|
+
const relation = await this.state.api.GetLineIDsWithType(modelID, propNames.name);
|
|
849
|
+
for (let i = 0; i < relation.size(); i++) {
|
|
850
|
+
const rel = await this.state.api.GetLine(modelID, relation.get(i), false);
|
|
851
|
+
this.saveChunk(chunks, propNames, rel);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
async getAllRelatedItemsOfType(modelID, id, propNames) {
|
|
856
|
+
const lines = await this.state.api.GetLineIDsWithType(modelID, propNames.name);
|
|
857
|
+
const IDs = [];
|
|
858
|
+
for (let i = 0; i < lines.size(); i++) {
|
|
859
|
+
const rel = await this.state.api.GetLine(modelID, lines.get(i));
|
|
860
|
+
const isRelated = BasePropertyManager.isRelated(id, rel, propNames);
|
|
861
|
+
if (isRelated)
|
|
862
|
+
this.getRelated(rel, propNames, IDs);
|
|
863
|
+
}
|
|
864
|
+
return IDs;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
class JSONPropertyManager extends BasePropertyManager {
|
|
870
|
+
|
|
871
|
+
async getItemProperties(modelID, id, recursive = false) {
|
|
872
|
+
return {
|
|
873
|
+
...this.state.models[modelID].jsonData[id]
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
async getHeaderLine(modelID) {
|
|
878
|
+
return {};
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async getSpatialStructure(modelID, includeProperties) {
|
|
882
|
+
const chunks = await this.getSpatialTreeChunks(modelID);
|
|
883
|
+
const projectsIDs = await this.getAllItemsOfType(modelID, IFCPROJECT, false);
|
|
884
|
+
const projectID = projectsIDs[0];
|
|
885
|
+
const project = JSONPropertyManager.newIfcProject(projectID);
|
|
886
|
+
await this.getSpatialNode(modelID, project, chunks, includeProperties);
|
|
887
|
+
return {
|
|
888
|
+
...project
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
async getAllItemsOfType(modelID, type, verbose) {
|
|
893
|
+
const data = this.state.models[modelID].jsonData;
|
|
894
|
+
const typeName = await this.state.api.GetNameFromTypeCode(type);
|
|
895
|
+
if (!typeName) {
|
|
896
|
+
throw new Error(`Type not found: ${type}`);
|
|
897
|
+
}
|
|
898
|
+
return this.filterItemsByType(data, typeName, verbose);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
async getProperty(modelID, elementID, recursive = false, propName) {
|
|
902
|
+
const resultIDs = await this.getAllRelatedItemsOfType(modelID, elementID, propName);
|
|
903
|
+
const result = this.getItemsByID(modelID, resultIDs);
|
|
904
|
+
if (recursive) {
|
|
905
|
+
result.forEach(result => this.getReferencesRecursively(modelID, result));
|
|
906
|
+
}
|
|
907
|
+
return result;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
getNodeType(modelID, id) {
|
|
911
|
+
return this.state.models[modelID].jsonData[id].type;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
async getChunks(modelID, chunks, propNames) {
|
|
915
|
+
const relation = await this.getAllItemsOfType(modelID, propNames.name, true);
|
|
916
|
+
relation.forEach(rel => {
|
|
917
|
+
this.saveChunk(chunks, propNames, rel);
|
|
918
|
+
});
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
filterItemsByType(data, typeName, verbose) {
|
|
922
|
+
const result = [];
|
|
923
|
+
Object.keys(data).forEach(key => {
|
|
924
|
+
const numKey = parseInt(key);
|
|
925
|
+
if (data[numKey].type.toUpperCase() === typeName) {
|
|
926
|
+
result.push(verbose ? {
|
|
927
|
+
...data[numKey]
|
|
928
|
+
} : numKey);
|
|
929
|
+
}
|
|
930
|
+
});
|
|
931
|
+
return result;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
async getAllRelatedItemsOfType(modelID, id, propNames) {
|
|
935
|
+
const lines = await this.getAllItemsOfType(modelID, propNames.name, true);
|
|
936
|
+
const IDs = [];
|
|
937
|
+
lines.forEach(line => {
|
|
938
|
+
const isRelated = JSONPropertyManager.isRelated(id, line, propNames);
|
|
939
|
+
if (isRelated)
|
|
940
|
+
this.getRelated(line, propNames, IDs);
|
|
941
|
+
});
|
|
942
|
+
return IDs;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
getItemsByID(modelID, ids) {
|
|
946
|
+
const data = this.state.models[modelID].jsonData;
|
|
947
|
+
const result = [];
|
|
948
|
+
ids.forEach(id => result.push({
|
|
949
|
+
...data[id]
|
|
950
|
+
}));
|
|
951
|
+
return result;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
getReferencesRecursively(modelID, jsonObject) {
|
|
955
|
+
if (jsonObject == undefined)
|
|
956
|
+
return;
|
|
957
|
+
const keys = Object.keys(jsonObject);
|
|
958
|
+
for (let i = 0; i < keys.length; i++) {
|
|
959
|
+
const key = keys[i];
|
|
960
|
+
this.getJSONItem(modelID, jsonObject, key);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
getJSONItem(modelID, jsonObject, key) {
|
|
965
|
+
if (Array.isArray(jsonObject[key])) {
|
|
966
|
+
return this.getMultipleJSONItems(modelID, jsonObject, key);
|
|
967
|
+
}
|
|
968
|
+
if (jsonObject[key] && jsonObject[key].type === 5) {
|
|
969
|
+
jsonObject[key] = this.getItemsByID(modelID, [jsonObject[key].value])[0];
|
|
970
|
+
this.getReferencesRecursively(modelID, jsonObject[key]);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
getMultipleJSONItems(modelID, jsonObject, key) {
|
|
975
|
+
jsonObject[key] = jsonObject[key].map((item) => {
|
|
976
|
+
if (item.type === 5) {
|
|
977
|
+
item = this.getItemsByID(modelID, [item.value])[0];
|
|
978
|
+
this.getReferencesRecursively(modelID, item);
|
|
979
|
+
}
|
|
980
|
+
return item;
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
const geometryTypes = new Set([
|
|
987
|
+
1123145078, 574549367, 1675464909, 2059837836, 3798115385, 32440307, 3125803723, 3207858831,
|
|
988
|
+
2740243338, 2624227202, 4240577450, 3615266464, 3724593414, 220341763, 477187591, 1878645084,
|
|
989
|
+
1300840506, 3303107099, 1607154358, 1878645084, 846575682, 1351298697, 2417041796, 3049322572,
|
|
990
|
+
3331915920, 1416205885, 776857604, 3285139300, 3958052878, 2827736869, 2732653382, 673634403,
|
|
991
|
+
3448662350, 4142052618, 2924175390, 803316827, 2556980723, 1809719519, 2205249479, 807026263,
|
|
992
|
+
3737207727, 1660063152, 2347385850, 3940055652, 2705031697, 3732776249, 2485617015, 2611217952,
|
|
993
|
+
1704287377, 2937912522, 2770003689, 1281925730, 1484403080, 3448662350, 4142052618, 3800577675,
|
|
994
|
+
4006246654, 3590301190, 1383045692, 2775532180, 2047409740, 370225590, 3593883385, 2665983363,
|
|
995
|
+
4124623270, 812098782, 3649129432, 987898635, 1105321065, 3510044353, 1635779807, 2603310189,
|
|
996
|
+
3406155212, 1310608509, 4261334040, 2736907675, 3649129432, 1136057603, 1260505505, 4182860854,
|
|
997
|
+
2713105998, 2898889636, 59481748, 3749851601, 3486308946, 3150382593, 1062206242, 3264961684,
|
|
998
|
+
15328376, 1485152156, 370225590, 1981873012, 2859738748, 45288368, 2614616156, 2732653382,
|
|
999
|
+
775493141, 2147822146, 2601014836, 2629017746, 1186437898, 2367409068, 1213902940, 3632507154,
|
|
1000
|
+
3900360178, 476780140, 1472233963, 2804161546, 3008276851, 738692330, 374418227, 315944413,
|
|
1001
|
+
3905492369, 3570813810, 2571569899, 178912537, 2294589976, 1437953363, 2133299955, 572779678,
|
|
1002
|
+
3092502836, 388784114, 2624227202, 1425443689, 3057273783, 2347385850, 1682466193, 2519244187,
|
|
1003
|
+
2839578677, 3958567839, 2513912981, 2830218821, 427810014
|
|
1004
|
+
]);
|
|
1005
|
+
|
|
1006
|
+
class PropertySerializer {
|
|
1007
|
+
|
|
1008
|
+
constructor(webIfc) {
|
|
1009
|
+
this.webIfc = webIfc;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
dispose() {
|
|
1013
|
+
this.webIfc = null;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
async serializeAllProperties(modelID, maxSize, event) {
|
|
1017
|
+
const blobs = [];
|
|
1018
|
+
await this.getPropertiesAsBlobs(modelID, blobs, maxSize, event);
|
|
1019
|
+
return blobs;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
async getPropertiesAsBlobs(modelID, blobs, maxSize, event) {
|
|
1023
|
+
const geometriesIDs = await this.getAllGeometriesIDs(modelID);
|
|
1024
|
+
let properties = await this.initializePropertiesObject(modelID);
|
|
1025
|
+
const allLinesIDs = await this.webIfc.GetAllLines(modelID);
|
|
1026
|
+
const linesCount = allLinesIDs.size();
|
|
1027
|
+
let lastEvent = 0.1;
|
|
1028
|
+
let counter = 0;
|
|
1029
|
+
for (let i = 0; i < linesCount; i++) {
|
|
1030
|
+
const id = allLinesIDs.get(i);
|
|
1031
|
+
if (!geometriesIDs.has(id)) {
|
|
1032
|
+
await this.getItemProperty(modelID, id, properties);
|
|
1033
|
+
counter++;
|
|
1034
|
+
}
|
|
1035
|
+
if (maxSize && counter > maxSize) {
|
|
1036
|
+
blobs.push(new Blob([JSON.stringify(properties)], {
|
|
1037
|
+
type: 'application/json'
|
|
1038
|
+
}));
|
|
1039
|
+
properties = {};
|
|
1040
|
+
counter = 0;
|
|
1041
|
+
}
|
|
1042
|
+
if (event && i / linesCount > lastEvent) {
|
|
1043
|
+
event(i, linesCount);
|
|
1044
|
+
lastEvent += 0.1;
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
blobs.push(new Blob([JSON.stringify(properties)], {
|
|
1048
|
+
type: 'application/json'
|
|
1049
|
+
}));
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
async getItemProperty(modelID, id, properties) {
|
|
1053
|
+
try {
|
|
1054
|
+
const props = await this.webIfc.GetLine(modelID, id);
|
|
1055
|
+
if (props.type) {
|
|
1056
|
+
props.type = this.webIfc.GetNameFromTypeCode(props.type);
|
|
1057
|
+
}
|
|
1058
|
+
this.formatItemProperties(props);
|
|
1059
|
+
properties[id] = props;
|
|
1060
|
+
} catch (e) {
|
|
1061
|
+
console.log(`There was a problem getting the properties of the item with ID ${id}`);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
formatItemProperties(props) {
|
|
1066
|
+
Object.keys(props).forEach((key) => {
|
|
1067
|
+
const value = props[key];
|
|
1068
|
+
if (value && value.value !== undefined)
|
|
1069
|
+
props[key] = value.value;
|
|
1070
|
+
else if (Array.isArray(value))
|
|
1071
|
+
props[key] = value.map((item) => {
|
|
1072
|
+
if (item && item.value)
|
|
1073
|
+
return item.value;
|
|
1074
|
+
return item;
|
|
1075
|
+
});
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
async initializePropertiesObject(modelID) {
|
|
1080
|
+
return {
|
|
1081
|
+
coordinationMatrix: await this.webIfc.GetCoordinationMatrix(modelID),
|
|
1082
|
+
globalHeight: await this.getBuildingHeight(modelID)
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
async getBuildingHeight(modelID) {
|
|
1087
|
+
const building = await this.getBuilding(modelID);
|
|
1088
|
+
let placement;
|
|
1089
|
+
const siteReference = building.ObjectPlacement.PlacementRelTo;
|
|
1090
|
+
if (siteReference)
|
|
1091
|
+
placement = siteReference.RelativePlacement.Location;
|
|
1092
|
+
else
|
|
1093
|
+
placement = building.ObjectPlacement.RelativePlacement.Location;
|
|
1094
|
+
const transform = placement.Coordinates.map((coord) => coord.value);
|
|
1095
|
+
return transform[2];
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
async getBuilding(modelID) {
|
|
1099
|
+
const allBuildingsIDs = await this.webIfc.GetLineIDsWithType(modelID, IFCBUILDING);
|
|
1100
|
+
const buildingID = allBuildingsIDs.get(0);
|
|
1101
|
+
return this.webIfc.GetLine(modelID, buildingID, true);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
async getAllGeometriesIDs(modelID) {
|
|
1105
|
+
const geometriesIDs = new Set();
|
|
1106
|
+
const geomTypesArray = Array.from(geometryTypes);
|
|
1107
|
+
for (let i = 0; i < geomTypesArray.length; i++) {
|
|
1108
|
+
const category = geomTypesArray[i];
|
|
1109
|
+
const ids = await this.webIfc.GetLineIDsWithType(modelID, category);
|
|
1110
|
+
const idsSize = ids.size();
|
|
1111
|
+
for (let j = 0; j < idsSize; j++) {
|
|
1112
|
+
geometriesIDs.add(ids.get(j));
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
return geometriesIDs;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
class PropertyManager {
|
|
1121
|
+
|
|
1122
|
+
constructor(state) {
|
|
1123
|
+
this.state = state;
|
|
1124
|
+
this.webIfcProps = new WebIfcPropertyManager(state);
|
|
1125
|
+
this.jsonProps = new JSONPropertyManager(state);
|
|
1126
|
+
this.currentProps = this.webIfcProps;
|
|
1127
|
+
this.serializer = new PropertySerializer(this.state.api);
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
getExpressId(geometry, faceIndex) {
|
|
1131
|
+
if (!geometry.index)
|
|
1132
|
+
throw new Error('Geometry does not have index information.');
|
|
1133
|
+
const geoIndex = geometry.index.array;
|
|
1134
|
+
const bufferAttr = geometry.attributes[IdAttrName];
|
|
1135
|
+
return bufferAttr.getX(geoIndex[3 * faceIndex]);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
async getHeaderLine(modelID, headerType) {
|
|
1139
|
+
this.updateCurrentProps();
|
|
1140
|
+
return this.currentProps.getHeaderLine(modelID, headerType);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
async getItemProperties(modelID, elementID, recursive = false) {
|
|
1144
|
+
this.updateCurrentProps();
|
|
1145
|
+
return this.currentProps.getItemProperties(modelID, elementID, recursive);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
async getAllItemsOfType(modelID, type, verbose) {
|
|
1149
|
+
this.updateCurrentProps();
|
|
1150
|
+
return this.currentProps.getAllItemsOfType(modelID, type, verbose);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
async getPropertySets(modelID, elementID, recursive = false) {
|
|
1154
|
+
this.updateCurrentProps();
|
|
1155
|
+
return this.currentProps.getPropertySets(modelID, elementID, recursive);
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
async getTypeProperties(modelID, elementID, recursive = false) {
|
|
1159
|
+
this.updateCurrentProps();
|
|
1160
|
+
return this.currentProps.getTypeProperties(modelID, elementID, recursive);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
async getMaterialsProperties(modelID, elementID, recursive = false) {
|
|
1164
|
+
this.updateCurrentProps();
|
|
1165
|
+
return this.currentProps.getMaterialsProperties(modelID, elementID, recursive);
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
async getSpatialStructure(modelID, includeProperties) {
|
|
1169
|
+
this.updateCurrentProps();
|
|
1170
|
+
if (!this.state.useJSON && includeProperties) {
|
|
1171
|
+
console.warn('Including properties in getSpatialStructure with the JSON workflow disabled can lead to poor performance.');
|
|
1172
|
+
}
|
|
1173
|
+
return await this.currentProps.getSpatialStructure(modelID, includeProperties);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
updateCurrentProps() {
|
|
1177
|
+
this.currentProps = this.state.useJSON ? this.jsonProps : this.webIfcProps;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
class TypeManager {
|
|
1183
|
+
|
|
1184
|
+
constructor(state) {
|
|
1185
|
+
this.state = state;
|
|
1186
|
+
this.state = state;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
async getAllTypes(worker) {
|
|
1190
|
+
for (let modelID in this.state.models) {
|
|
1191
|
+
if (this.state.models.hasOwnProperty(modelID)) {
|
|
1192
|
+
const types = this.state.models[modelID].types;
|
|
1193
|
+
if (Object.keys(types).length == 0) {
|
|
1194
|
+
await this.getAllTypesOfModel(parseInt(modelID), worker);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
async getAllTypesOfModel(modelID, worker) {
|
|
1201
|
+
const result = {};
|
|
1202
|
+
const elements = await this.state.api.GetIfcEntityList(modelID);
|
|
1203
|
+
for (let i = 0; i < elements.length; i++) {
|
|
1204
|
+
const element = elements[i];
|
|
1205
|
+
const lines = await this.state.api.GetLineIDsWithType(modelID, element);
|
|
1206
|
+
const size = lines.size();
|
|
1207
|
+
for (let i = 0; i < size; i++)
|
|
1208
|
+
result[lines.get(i)] = element;
|
|
1209
|
+
}
|
|
1210
|
+
if (this.state.worker.active && worker) {
|
|
1211
|
+
await worker.workerState.updateModelStateTypes(modelID, result);
|
|
1212
|
+
}
|
|
1213
|
+
this.state.models[modelID].types = result;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
class BvhManager {
|
|
1219
|
+
|
|
1220
|
+
initializeMeshBVH(computeBoundsTree, disposeBoundsTree, acceleratedRaycast) {
|
|
1221
|
+
this.computeBoundsTree = computeBoundsTree;
|
|
1222
|
+
this.disposeBoundsTree = disposeBoundsTree;
|
|
1223
|
+
this.acceleratedRaycast = acceleratedRaycast;
|
|
1224
|
+
this.setupThreeMeshBVH();
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
applyThreeMeshBVH(geometry) {
|
|
1228
|
+
if (this.computeBoundsTree)
|
|
1229
|
+
geometry.computeBoundsTree();
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
setupThreeMeshBVH() {
|
|
1233
|
+
if (!this.computeBoundsTree || !this.disposeBoundsTree || !this.acceleratedRaycast)
|
|
1234
|
+
return;
|
|
1235
|
+
BufferGeometry.prototype.computeBoundsTree = this.computeBoundsTree;
|
|
1236
|
+
BufferGeometry.prototype.disposeBoundsTree = this.disposeBoundsTree;
|
|
1237
|
+
Mesh.prototype.raycast = this.acceleratedRaycast;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
var WorkerActions;
|
|
1243
|
+
(function(WorkerActions) {
|
|
1244
|
+
WorkerActions["updateStateUseJson"] = "updateStateUseJson";
|
|
1245
|
+
WorkerActions["updateStateWebIfcSettings"] = "updateStateWebIfcSettings";
|
|
1246
|
+
WorkerActions["updateModelStateTypes"] = "updateModelStateTypes";
|
|
1247
|
+
WorkerActions["updateModelStateJsonData"] = "updateModelStateJsonData";
|
|
1248
|
+
WorkerActions["loadJsonDataFromWorker"] = "loadJsonDataFromWorker";
|
|
1249
|
+
WorkerActions["dispose"] = "dispose";
|
|
1250
|
+
WorkerActions["Close"] = "Close";
|
|
1251
|
+
WorkerActions["DisposeWebIfc"] = "DisposeWebIfc";
|
|
1252
|
+
WorkerActions["Init"] = "Init";
|
|
1253
|
+
WorkerActions["OpenModel"] = "OpenModel";
|
|
1254
|
+
WorkerActions["CreateModel"] = "CreateModel";
|
|
1255
|
+
WorkerActions["ExportFileAsIFC"] = "ExportFileAsIFC";
|
|
1256
|
+
WorkerActions["GetGeometry"] = "GetGeometry";
|
|
1257
|
+
WorkerActions["GetLine"] = "GetLine";
|
|
1258
|
+
WorkerActions["GetAndClearErrors"] = "GetAndClearErrors";
|
|
1259
|
+
WorkerActions["WriteLine"] = "WriteLine";
|
|
1260
|
+
WorkerActions["FlattenLine"] = "FlattenLine";
|
|
1261
|
+
WorkerActions["GetRawLineData"] = "GetRawLineData";
|
|
1262
|
+
WorkerActions["WriteRawLineData"] = "WriteRawLineData";
|
|
1263
|
+
WorkerActions["GetLineIDsWithType"] = "GetLineIDsWithType";
|
|
1264
|
+
WorkerActions["GetAllLines"] = "GetAllLines";
|
|
1265
|
+
WorkerActions["SetGeometryTransformation"] = "SetGeometryTransformation";
|
|
1266
|
+
WorkerActions["GetCoordinationMatrix"] = "GetCoordinationMatrix";
|
|
1267
|
+
WorkerActions["GetVertexArray"] = "GetVertexArray";
|
|
1268
|
+
WorkerActions["GetIndexArray"] = "GetIndexArray";
|
|
1269
|
+
WorkerActions["getSubArray"] = "getSubArray";
|
|
1270
|
+
WorkerActions["CloseModel"] = "CloseModel";
|
|
1271
|
+
WorkerActions["StreamAllMeshes"] = "StreamAllMeshes";
|
|
1272
|
+
WorkerActions["StreamAllMeshesWithTypes"] = "StreamAllMeshesWithTypes";
|
|
1273
|
+
WorkerActions["IsModelOpen"] = "IsModelOpen";
|
|
1274
|
+
WorkerActions["LoadAllGeometry"] = "LoadAllGeometry";
|
|
1275
|
+
WorkerActions["GetFlatMesh"] = "GetFlatMesh";
|
|
1276
|
+
WorkerActions["SetWasmPath"] = "SetWasmPath";
|
|
1277
|
+
WorkerActions["GetNameFromTypeCode"] = "GetNameFromTypeCode";
|
|
1278
|
+
WorkerActions["GetIfcEntityList"] = "GetIfcEntityList";
|
|
1279
|
+
WorkerActions["GetTypeCodeFromName"] = "GetTypeCodeFromName";
|
|
1280
|
+
WorkerActions["parse"] = "parse";
|
|
1281
|
+
WorkerActions["setupOptionalCategories"] = "setupOptionalCategories";
|
|
1282
|
+
WorkerActions["getExpressId"] = "getExpressId";
|
|
1283
|
+
WorkerActions["initializeProperties"] = "initializeProperties";
|
|
1284
|
+
WorkerActions["getAllItemsOfType"] = "getAllItemsOfType";
|
|
1285
|
+
WorkerActions["getItemProperties"] = "getItemProperties";
|
|
1286
|
+
WorkerActions["getMaterialsProperties"] = "getMaterialsProperties";
|
|
1287
|
+
WorkerActions["getPropertySets"] = "getPropertySets";
|
|
1288
|
+
WorkerActions["getSpatialStructure"] = "getSpatialStructure";
|
|
1289
|
+
WorkerActions["getTypeProperties"] = "getTypeProperties";
|
|
1290
|
+
WorkerActions["getHeaderLine"] = "getHeaderLine";
|
|
1291
|
+
})(WorkerActions || (WorkerActions = {}));
|
|
1292
|
+
var WorkerAPIs;
|
|
1293
|
+
(function(WorkerAPIs) {
|
|
1294
|
+
WorkerAPIs["workerState"] = "workerState";
|
|
1295
|
+
WorkerAPIs["webIfc"] = "webIfc";
|
|
1296
|
+
WorkerAPIs["properties"] = "properties";
|
|
1297
|
+
WorkerAPIs["parser"] = "parser";
|
|
1298
|
+
})(WorkerAPIs || (WorkerAPIs = {}));
|
|
1299
|
+
|
|
1300
|
+
class Vector {
|
|
1301
|
+
|
|
1302
|
+
constructor(vector) {
|
|
1303
|
+
this._data = {};
|
|
1304
|
+
this._size = vector.size;
|
|
1305
|
+
const keys = Object.keys(vector).filter((key) => key.indexOf('size') === -1).map(key => parseInt(key));
|
|
1306
|
+
keys.forEach((key) => this._data[key] = vector[key]);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
size() {
|
|
1310
|
+
return this._size;
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
get(index) {
|
|
1314
|
+
return this._data[index];
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
class IfcGeometry {
|
|
1320
|
+
|
|
1321
|
+
constructor(vector) {
|
|
1322
|
+
this._GetVertexData = vector.GetVertexData;
|
|
1323
|
+
this._GetVertexDataSize = vector.GetVertexDataSize;
|
|
1324
|
+
this._GetIndexData = vector.GetIndexData;
|
|
1325
|
+
this._GetIndexDataSize = vector.GetIndexDataSize;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
GetVertexData() {
|
|
1329
|
+
return this._GetVertexData;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
GetVertexDataSize() {
|
|
1333
|
+
return this._GetVertexDataSize;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
GetIndexData() {
|
|
1337
|
+
return this._GetIndexData;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
GetIndexDataSize() {
|
|
1341
|
+
return this._GetIndexDataSize;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
class FlatMesh {
|
|
1347
|
+
|
|
1348
|
+
constructor(serializer, flatMesh) {
|
|
1349
|
+
this.expressID = flatMesh.expressID;
|
|
1350
|
+
this.geometries = serializer.reconstructVector(flatMesh.geometries);
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
class FlatMeshVector {
|
|
1356
|
+
|
|
1357
|
+
constructor(serializer, vector) {
|
|
1358
|
+
this._data = {};
|
|
1359
|
+
this._size = vector.size;
|
|
1360
|
+
const keys = Object.keys(vector).filter((key) => key.indexOf('size') === -1).map(key => parseInt(key));
|
|
1361
|
+
keys.forEach(key => this._data[key] = serializer.reconstructFlatMesh(vector[key]));
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
size() {
|
|
1365
|
+
return this._size;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
get(index) {
|
|
1369
|
+
return this._data[index];
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
class SerializedMaterial {
|
|
1375
|
+
|
|
1376
|
+
constructor(material) {
|
|
1377
|
+
this.color = [material.color.r, material.color.g, material.color.b];
|
|
1378
|
+
this.opacity = material.opacity;
|
|
1379
|
+
this.transparent = material.transparent;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
class MaterialReconstructor {
|
|
1385
|
+
|
|
1386
|
+
static new(material) {
|
|
1387
|
+
return new MeshLambertMaterial({
|
|
1388
|
+
color: new Color(material.color[0], material.color[1], material.color[2]),
|
|
1389
|
+
opacity: material.opacity,
|
|
1390
|
+
transparent: material.transparent,
|
|
1391
|
+
side: DoubleSide
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
class SerializedGeometry {
|
|
1398
|
+
|
|
1399
|
+
constructor(geometry) {
|
|
1400
|
+
var _a,
|
|
1401
|
+
_b,
|
|
1402
|
+
_c,
|
|
1403
|
+
_d;
|
|
1404
|
+
this.position = ((_a = geometry.attributes.position) === null || _a === void 0 ? void 0 : _a.array) || [];
|
|
1405
|
+
this.normal = ((_b = geometry.attributes.normal) === null || _b === void 0 ? void 0 : _b.array) || [];
|
|
1406
|
+
this.expressID = ((_c = geometry.attributes.expressID) === null || _c === void 0 ? void 0 : _c.array) || [];
|
|
1407
|
+
this.index = ((_d = geometry.index) === null || _d === void 0 ? void 0 : _d.array) || [];
|
|
1408
|
+
this.groups = geometry.groups;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
class GeometryReconstructor {
|
|
1414
|
+
|
|
1415
|
+
static new(serialized) {
|
|
1416
|
+
const geom = new BufferGeometry();
|
|
1417
|
+
GeometryReconstructor.set(geom, 'expressID', new Uint32Array(serialized.expressID), 1);
|
|
1418
|
+
GeometryReconstructor.set(geom, 'position', new Float32Array(serialized.position), 3);
|
|
1419
|
+
GeometryReconstructor.set(geom, 'normal', new Float32Array(serialized.normal), 3);
|
|
1420
|
+
geom.setIndex(Array. from (serialized.index));
|
|
1421
|
+
geom.groups = serialized.groups;
|
|
1422
|
+
return geom;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
static set(geom, name, data, size) {
|
|
1426
|
+
if (data.length > 0) {
|
|
1427
|
+
geom.setAttribute(name, new BufferAttribute(data, size));
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
class SerializedMesh {
|
|
1434
|
+
|
|
1435
|
+
constructor(model) {
|
|
1436
|
+
this.materials = [];
|
|
1437
|
+
this.modelID = model.modelID;
|
|
1438
|
+
this.geometry = new SerializedGeometry(model.geometry);
|
|
1439
|
+
if (Array.isArray(model.material)) {
|
|
1440
|
+
model.material.forEach(mat => {
|
|
1441
|
+
this.materials.push(new SerializedMaterial(mat));
|
|
1442
|
+
});
|
|
1443
|
+
} else {
|
|
1444
|
+
this.materials.push(new SerializedMaterial(model.material));
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
class MeshReconstructor {
|
|
1451
|
+
|
|
1452
|
+
static new(serialized) {
|
|
1453
|
+
const model = new IFCModel();
|
|
1454
|
+
model.modelID = serialized.modelID;
|
|
1455
|
+
model.geometry = GeometryReconstructor.new(serialized.geometry);
|
|
1456
|
+
MeshReconstructor.getMaterials(serialized, model);
|
|
1457
|
+
return model;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
static getMaterials(serialized, model) {
|
|
1461
|
+
model.material = [];
|
|
1462
|
+
const mats = model.material;
|
|
1463
|
+
serialized.materials.forEach(mat => {
|
|
1464
|
+
mats.push(MaterialReconstructor.new(mat));
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
class Serializer {
|
|
1471
|
+
|
|
1472
|
+
serializeVector(vector) {
|
|
1473
|
+
const size = vector.size();
|
|
1474
|
+
const serialized = {
|
|
1475
|
+
size
|
|
1476
|
+
};
|
|
1477
|
+
for (let i = 0; i < size; i++) {
|
|
1478
|
+
serialized[i] = vector.get(i);
|
|
1479
|
+
}
|
|
1480
|
+
return serialized;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
reconstructVector(vector) {
|
|
1484
|
+
return new Vector(vector);
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
serializeIfcGeometry(geometry) {
|
|
1488
|
+
const GetVertexData = geometry.GetVertexData();
|
|
1489
|
+
const GetVertexDataSize = geometry.GetVertexDataSize();
|
|
1490
|
+
const GetIndexData = geometry.GetIndexData();
|
|
1491
|
+
const GetIndexDataSize = geometry.GetIndexDataSize();
|
|
1492
|
+
return {
|
|
1493
|
+
GetVertexData,
|
|
1494
|
+
GetVertexDataSize,
|
|
1495
|
+
GetIndexData,
|
|
1496
|
+
GetIndexDataSize
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
reconstructIfcGeometry(geometry) {
|
|
1501
|
+
return new IfcGeometry(geometry);
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
serializeFlatMesh(flatMesh) {
|
|
1505
|
+
return {
|
|
1506
|
+
expressID: flatMesh.expressID,
|
|
1507
|
+
geometries: this.serializeVector(flatMesh.geometries)
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
reconstructFlatMesh(flatMesh) {
|
|
1512
|
+
return new FlatMesh(this, flatMesh);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
serializeFlatMeshVector(vector) {
|
|
1516
|
+
const size = vector.size();
|
|
1517
|
+
const serialized = {
|
|
1518
|
+
size
|
|
1519
|
+
};
|
|
1520
|
+
for (let i = 0; i < size; i++) {
|
|
1521
|
+
const flatMesh = vector.get(i);
|
|
1522
|
+
serialized[i] = this.serializeFlatMesh(flatMesh);
|
|
1523
|
+
}
|
|
1524
|
+
return serialized;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
reconstructFlatMeshVector(vector) {
|
|
1528
|
+
return new FlatMeshVector(this, vector);
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
serializeIfcModel(model) {
|
|
1532
|
+
return new SerializedMesh(model);
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
reconstructIfcModel(model) {
|
|
1536
|
+
return MeshReconstructor.new(model);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
class PropertyHandler {
|
|
1542
|
+
|
|
1543
|
+
constructor(handler) {
|
|
1544
|
+
this.handler = handler;
|
|
1545
|
+
this.API = WorkerAPIs.properties;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
getExpressId(geometry, faceIndex) {
|
|
1549
|
+
if (!geometry.index)
|
|
1550
|
+
throw new Error('Geometry does not have index information.');
|
|
1551
|
+
const geoIndex = geometry.index.array;
|
|
1552
|
+
const bufferAttr = geometry.attributes[IdAttrName];
|
|
1553
|
+
return bufferAttr.getX(geoIndex[3 * faceIndex]);
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
getHeaderLine(modelID, headerType) {
|
|
1557
|
+
return this.handler.request(this.API, WorkerActions.getHeaderLine, {
|
|
1558
|
+
modelID,
|
|
1559
|
+
headerType
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
getAllItemsOfType(modelID, type, verbose) {
|
|
1564
|
+
return this.handler.request(this.API, WorkerActions.getAllItemsOfType, {
|
|
1565
|
+
modelID,
|
|
1566
|
+
type,
|
|
1567
|
+
verbose
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
getItemProperties(modelID, elementID, recursive) {
|
|
1572
|
+
return this.handler.request(this.API, WorkerActions.getItemProperties, {
|
|
1573
|
+
modelID,
|
|
1574
|
+
elementID,
|
|
1575
|
+
recursive
|
|
1576
|
+
});
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
getMaterialsProperties(modelID, elementID, recursive) {
|
|
1580
|
+
return this.handler.request(this.API, WorkerActions.getMaterialsProperties, {
|
|
1581
|
+
modelID,
|
|
1582
|
+
elementID,
|
|
1583
|
+
recursive
|
|
1584
|
+
});
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
getPropertySets(modelID, elementID, recursive) {
|
|
1588
|
+
return this.handler.request(this.API, WorkerActions.getPropertySets, {
|
|
1589
|
+
modelID,
|
|
1590
|
+
elementID,
|
|
1591
|
+
recursive
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
getTypeProperties(modelID, elementID, recursive) {
|
|
1596
|
+
return this.handler.request(this.API, WorkerActions.getTypeProperties, {
|
|
1597
|
+
modelID,
|
|
1598
|
+
elementID,
|
|
1599
|
+
recursive
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
getSpatialStructure(modelID, includeProperties) {
|
|
1604
|
+
return this.handler.request(this.API, WorkerActions.getSpatialStructure, {
|
|
1605
|
+
modelID,
|
|
1606
|
+
includeProperties
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
class WebIfcHandler {
|
|
1613
|
+
|
|
1614
|
+
constructor(handler, serializer) {
|
|
1615
|
+
this.handler = handler;
|
|
1616
|
+
this.serializer = serializer;
|
|
1617
|
+
this.API = WorkerAPIs.webIfc;
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
async Init() {
|
|
1621
|
+
this.wasmModule = true;
|
|
1622
|
+
return this.handler.request(this.API, WorkerActions.Init);
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
async OpenModel(data, settings) {
|
|
1626
|
+
return this.handler.request(this.API, WorkerActions.OpenModel, {
|
|
1627
|
+
data,
|
|
1628
|
+
settings
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
async CreateModel(model, settings) {
|
|
1633
|
+
return this.handler.request(this.API, WorkerActions.CreateModel, {
|
|
1634
|
+
model,
|
|
1635
|
+
settings
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
async ExportFileAsIFC(modelID) {
|
|
1640
|
+
return this.handler.request(this.API, WorkerActions.ExportFileAsIFC, {
|
|
1641
|
+
modelID
|
|
1642
|
+
});
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
async GetHeaderLine(modelID, headerType) {
|
|
1646
|
+
return this.handler.request(this.API, WorkerActions.getHeaderLine, {
|
|
1647
|
+
modelID,
|
|
1648
|
+
headerType
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
async GetGeometry(modelID, geometryExpressID) {
|
|
1653
|
+
this.handler.serializeHandlers[this.handler.requestID] = (geom) => {
|
|
1654
|
+
return this.serializer.reconstructIfcGeometry(geom);
|
|
1655
|
+
};
|
|
1656
|
+
return this.handler.request(this.API, WorkerActions.GetGeometry, {
|
|
1657
|
+
modelID,
|
|
1658
|
+
geometryExpressID
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
async GetLine(modelID, expressID, flatten) {
|
|
1663
|
+
return this.handler.request(this.API, WorkerActions.GetLine, {
|
|
1664
|
+
modelID,
|
|
1665
|
+
expressID,
|
|
1666
|
+
flatten
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
async GetAndClearErrors(modelID) {
|
|
1671
|
+
this.handler.serializeHandlers[this.handler.requestID] = (vector) => {
|
|
1672
|
+
return this.serializer.reconstructVector(vector);
|
|
1673
|
+
};
|
|
1674
|
+
return this.handler.request(this.API, WorkerActions.GetAndClearErrors, {
|
|
1675
|
+
modelID
|
|
1676
|
+
});
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
async GetNameFromTypeCode(type) {
|
|
1680
|
+
return this.handler.request(this.API, WorkerActions.GetNameFromTypeCode, {
|
|
1681
|
+
type
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
async GetIfcEntityList(modelID) {
|
|
1686
|
+
return this.handler.request(this.API, WorkerActions.GetIfcEntityList, {
|
|
1687
|
+
modelID
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
async GetTypeCodeFromName(modelID, typeName) {
|
|
1692
|
+
return this.handler.request(this.API, WorkerActions.GetTypeCodeFromName, {
|
|
1693
|
+
modelID,
|
|
1694
|
+
typeName
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
async WriteLine(modelID, lineObject) {
|
|
1699
|
+
return this.handler.request(this.API, WorkerActions.WriteLine, {
|
|
1700
|
+
modelID,
|
|
1701
|
+
lineObject
|
|
1702
|
+
});
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
async FlattenLine(modelID, line) {
|
|
1706
|
+
return this.handler.request(this.API, WorkerActions.FlattenLine, {
|
|
1707
|
+
modelID,
|
|
1708
|
+
line
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
async GetRawLineData(modelID, expressID) {
|
|
1713
|
+
return this.handler.request(this.API, WorkerActions.GetRawLineData, {
|
|
1714
|
+
modelID,
|
|
1715
|
+
expressID
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
async WriteRawLineData(modelID, data) {
|
|
1720
|
+
return this.handler.request(this.API, WorkerActions.WriteRawLineData, {
|
|
1721
|
+
modelID,
|
|
1722
|
+
data
|
|
1723
|
+
});
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
async GetLineIDsWithType(modelID, type) {
|
|
1727
|
+
this.handler.serializeHandlers[this.handler.requestID] = (vector) => {
|
|
1728
|
+
return this.serializer.reconstructVector(vector);
|
|
1729
|
+
};
|
|
1730
|
+
return this.handler.request(this.API, WorkerActions.GetLineIDsWithType, {
|
|
1731
|
+
modelID,
|
|
1732
|
+
type
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
async GetAllLines(modelID) {
|
|
1737
|
+
this.handler.serializeHandlers[this.handler.requestID] = (vector) => {
|
|
1738
|
+
return this.serializer.reconstructVector(vector);
|
|
1739
|
+
};
|
|
1740
|
+
return this.handler.request(this.API, WorkerActions.GetAllLines, {
|
|
1741
|
+
modelID
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
async SetGeometryTransformation(modelID, transformationMatrix) {
|
|
1746
|
+
return this.handler.request(this.API, WorkerActions.SetGeometryTransformation, {
|
|
1747
|
+
modelID,
|
|
1748
|
+
transformationMatrix
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
async GetCoordinationMatrix(modelID) {
|
|
1753
|
+
return this.handler.request(this.API, WorkerActions.GetCoordinationMatrix, {
|
|
1754
|
+
modelID
|
|
1755
|
+
});
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
async GetVertexArray(ptr, size) {
|
|
1759
|
+
return this.handler.request(this.API, WorkerActions.GetVertexArray, {
|
|
1760
|
+
ptr,
|
|
1761
|
+
size
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
async GetIndexArray(ptr, size) {
|
|
1766
|
+
return this.handler.request(this.API, WorkerActions.GetIndexArray, {
|
|
1767
|
+
ptr,
|
|
1768
|
+
size
|
|
1769
|
+
});
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
async getSubArray(heap, startPtr, sizeBytes) {
|
|
1773
|
+
return this.handler.request(this.API, WorkerActions.getSubArray, {
|
|
1774
|
+
heap,
|
|
1775
|
+
startPtr,
|
|
1776
|
+
sizeBytes
|
|
1777
|
+
});
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
async CloseModel(modelID) {
|
|
1781
|
+
return this.handler.request(this.API, WorkerActions.CloseModel, {
|
|
1782
|
+
modelID
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
async StreamAllMeshes(modelID, meshCallback) {
|
|
1787
|
+
this.handler.callbackHandlers[this.handler.requestID] = {
|
|
1788
|
+
action: meshCallback,
|
|
1789
|
+
serializer: this.serializer.reconstructFlatMesh
|
|
1790
|
+
};
|
|
1791
|
+
return this.handler.request(this.API, WorkerActions.StreamAllMeshes, {
|
|
1792
|
+
modelID
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
async StreamAllMeshesWithTypes(modelID, types, meshCallback) {
|
|
1797
|
+
this.handler.callbackHandlers[this.handler.requestID] = {
|
|
1798
|
+
action: meshCallback,
|
|
1799
|
+
serializer: this.serializer.reconstructFlatMesh
|
|
1800
|
+
};
|
|
1801
|
+
return this.handler.request(this.API, WorkerActions.StreamAllMeshesWithTypes, {
|
|
1802
|
+
modelID,
|
|
1803
|
+
types
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
async IsModelOpen(modelID) {
|
|
1808
|
+
return this.handler.request(this.API, WorkerActions.IsModelOpen, {
|
|
1809
|
+
modelID
|
|
1810
|
+
});
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
async LoadAllGeometry(modelID) {
|
|
1814
|
+
this.handler.serializeHandlers[this.handler.requestID] = (vector) => {
|
|
1815
|
+
return this.serializer.reconstructFlatMeshVector(vector);
|
|
1816
|
+
};
|
|
1817
|
+
return this.handler.request(this.API, WorkerActions.LoadAllGeometry, {
|
|
1818
|
+
modelID
|
|
1819
|
+
});
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
async GetFlatMesh(modelID, expressID) {
|
|
1823
|
+
this.handler.serializeHandlers[this.handler.requestID] = (flatMesh) => {
|
|
1824
|
+
return this.serializer.reconstructFlatMesh(flatMesh);
|
|
1825
|
+
};
|
|
1826
|
+
return this.handler.request(this.API, WorkerActions.GetFlatMesh, {
|
|
1827
|
+
modelID,
|
|
1828
|
+
expressID
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
async SetWasmPath(path) {
|
|
1833
|
+
return this.handler.request(this.API, WorkerActions.SetWasmPath, {
|
|
1834
|
+
path
|
|
1835
|
+
});
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
class WorkerStateHandler {
|
|
1841
|
+
|
|
1842
|
+
constructor(handler) {
|
|
1843
|
+
this.handler = handler;
|
|
1844
|
+
this.API = WorkerAPIs.workerState;
|
|
1845
|
+
this.state = this.handler.state;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
async updateStateUseJson() {
|
|
1849
|
+
const useJson = this.state.useJSON;
|
|
1850
|
+
return this.handler.request(this.API, WorkerActions.updateStateUseJson, {
|
|
1851
|
+
useJson
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
async updateStateWebIfcSettings() {
|
|
1856
|
+
const webIfcSettings = this.state.webIfcSettings;
|
|
1857
|
+
return this.handler.request(this.API, WorkerActions.updateStateWebIfcSettings, {
|
|
1858
|
+
webIfcSettings
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
async updateModelStateTypes(modelID, types) {
|
|
1863
|
+
return this.handler.request(this.API, WorkerActions.updateModelStateTypes, {
|
|
1864
|
+
modelID,
|
|
1865
|
+
types
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
async updateModelStateJsonData(modelID, jsonData) {
|
|
1870
|
+
return this.handler.request(this.API, WorkerActions.updateModelStateJsonData, {
|
|
1871
|
+
modelID,
|
|
1872
|
+
jsonData
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
async loadJsonDataFromWorker(modelID, path) {
|
|
1877
|
+
return this.handler.request(this.API, WorkerActions.loadJsonDataFromWorker, {
|
|
1878
|
+
modelID,
|
|
1879
|
+
path
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
var DBOperation;
|
|
1886
|
+
(function(DBOperation) {
|
|
1887
|
+
DBOperation[DBOperation["transferIfcModel"] = 0] = "transferIfcModel";
|
|
1888
|
+
DBOperation[DBOperation["transferIndividualItems"] = 1] = "transferIndividualItems";
|
|
1889
|
+
})(DBOperation || (DBOperation = {}));
|
|
1890
|
+
|
|
1891
|
+
class IndexedDatabase {
|
|
1892
|
+
|
|
1893
|
+
async save(item, id) {
|
|
1894
|
+
const open = IndexedDatabase.openOrCreateDB(id);
|
|
1895
|
+
this.createSchema(open, id);
|
|
1896
|
+
return new Promise((resolve, reject) => {
|
|
1897
|
+
open.onsuccess = () => this.saveItem(item, open, id, resolve);
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
async load(id) {
|
|
1902
|
+
const open = IndexedDatabase.openOrCreateDB(id);
|
|
1903
|
+
return new Promise((resolve, reject) => {
|
|
1904
|
+
open.onsuccess = () => this.loadItem(open, id, resolve);
|
|
1905
|
+
});
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
createSchema(open, id) {
|
|
1909
|
+
open.onupgradeneeded = function() {
|
|
1910
|
+
const db = open.result;
|
|
1911
|
+
db.createObjectStore(id.toString(), {
|
|
1912
|
+
keyPath: "id"
|
|
1913
|
+
});
|
|
1914
|
+
};
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
saveItem(item, open, id, resolve) {
|
|
1918
|
+
const {db, tx, store} = IndexedDatabase.getDBItems(open, id);
|
|
1919
|
+
item.id = id;
|
|
1920
|
+
store.put(item);
|
|
1921
|
+
tx.oncomplete = () => IndexedDatabase.closeDB(db, tx, resolve);
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
loadItem(open, id, resolve) {
|
|
1925
|
+
const {db, tx, store} = IndexedDatabase.getDBItems(open, id);
|
|
1926
|
+
const item = store.get(id);
|
|
1927
|
+
const callback = () => {
|
|
1928
|
+
delete item.result.id;
|
|
1929
|
+
resolve(item.result);
|
|
1930
|
+
};
|
|
1931
|
+
tx.oncomplete = () => IndexedDatabase.closeDB(db, tx, callback);
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
static getDBItems(open, id) {
|
|
1935
|
+
const db = open.result;
|
|
1936
|
+
const tx = db.transaction(id.toString(), "readwrite");
|
|
1937
|
+
const store = tx.objectStore(id.toString());
|
|
1938
|
+
return {
|
|
1939
|
+
db,
|
|
1940
|
+
tx,
|
|
1941
|
+
store
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
static openOrCreateDB(id) {
|
|
1946
|
+
return indexedDB.open(id.toString(), 1);
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
static closeDB(db, tx, resolve) {
|
|
1950
|
+
db.close();
|
|
1951
|
+
resolve("success");
|
|
1952
|
+
}
|
|
1953
|
+
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
class ParserHandler {
|
|
1957
|
+
|
|
1958
|
+
constructor(handler, serializer, BVH, IDB) {
|
|
1959
|
+
this.handler = handler;
|
|
1960
|
+
this.serializer = serializer;
|
|
1961
|
+
this.BVH = BVH;
|
|
1962
|
+
this.IDB = IDB;
|
|
1963
|
+
this.optionalCategories = {
|
|
1964
|
+
[IFCSPACE]: true,
|
|
1965
|
+
[IFCOPENINGELEMENT]: false
|
|
1966
|
+
};
|
|
1967
|
+
this.API = WorkerAPIs.parser;
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
async setupOptionalCategories(config) {
|
|
1971
|
+
this.optionalCategories = config;
|
|
1972
|
+
return this.handler.request(this.API, WorkerActions.setupOptionalCategories, {
|
|
1973
|
+
config
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
async parse(buffer, coordinationMatrix) {
|
|
1978
|
+
this.handler.onprogressHandlers[this.handler.requestID] = (progress) => {
|
|
1979
|
+
if (this.handler.state.onProgress)
|
|
1980
|
+
this.handler.state.onProgress(progress);
|
|
1981
|
+
};
|
|
1982
|
+
this.handler.serializeHandlers[this.handler.requestID] = async (result) => {
|
|
1983
|
+
this.updateState(result.modelID);
|
|
1984
|
+
return this.getModel();
|
|
1985
|
+
};
|
|
1986
|
+
return this.handler.request(this.API, WorkerActions.parse, {
|
|
1987
|
+
buffer,
|
|
1988
|
+
coordinationMatrix
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
getAndClearErrors(_modelId) {}
|
|
1993
|
+
|
|
1994
|
+
updateState(modelID) {
|
|
1995
|
+
this.handler.state.models[modelID] = {
|
|
1996
|
+
modelID: modelID,
|
|
1997
|
+
mesh: {},
|
|
1998
|
+
types: {},
|
|
1999
|
+
jsonData: {}
|
|
2000
|
+
};
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
async getModel() {
|
|
2004
|
+
const serializedModel = await this.IDB.load(DBOperation.transferIfcModel);
|
|
2005
|
+
const model = this.serializer.reconstructIfcModel(serializedModel);
|
|
2006
|
+
this.BVH.applyThreeMeshBVH(model.geometry);
|
|
2007
|
+
this.handler.state.models[model.modelID].mesh = model;
|
|
2008
|
+
return model;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
class IFCWorkerHandler {
|
|
2014
|
+
|
|
2015
|
+
constructor(state, BVH) {
|
|
2016
|
+
this.state = state;
|
|
2017
|
+
this.BVH = BVH;
|
|
2018
|
+
this.requestID = 0;
|
|
2019
|
+
this.rejectHandlers = {};
|
|
2020
|
+
this.resolveHandlers = {};
|
|
2021
|
+
this.serializeHandlers = {};
|
|
2022
|
+
this.callbackHandlers = {};
|
|
2023
|
+
this.onprogressHandlers = {};
|
|
2024
|
+
this.serializer = new Serializer();
|
|
2025
|
+
this.IDB = new IndexedDatabase();
|
|
2026
|
+
this.workerPath = this.state.worker.path;
|
|
2027
|
+
this.ifcWorker = new Worker(this.workerPath);
|
|
2028
|
+
this.ifcWorker.onmessage = (data) => this.handleResponse(data);
|
|
2029
|
+
this.properties = new PropertyHandler(this);
|
|
2030
|
+
this.parser = new ParserHandler(this, this.serializer, this.BVH, this.IDB);
|
|
2031
|
+
this.webIfc = new WebIfcHandler(this, this.serializer);
|
|
2032
|
+
this.workerState = new WorkerStateHandler(this);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
request(worker, action, args) {
|
|
2036
|
+
const data = {
|
|
2037
|
+
worker,
|
|
2038
|
+
action,
|
|
2039
|
+
args,
|
|
2040
|
+
id: this.requestID,
|
|
2041
|
+
result: undefined,
|
|
2042
|
+
onProgress: false
|
|
2043
|
+
};
|
|
2044
|
+
return new Promise((resolve, reject) => {
|
|
2045
|
+
this.resolveHandlers[this.requestID] = resolve;
|
|
2046
|
+
this.rejectHandlers[this.requestID] = reject;
|
|
2047
|
+
this.requestID++;
|
|
2048
|
+
this.ifcWorker.postMessage(data);
|
|
2049
|
+
});
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
async terminate() {
|
|
2053
|
+
await this.request(WorkerAPIs.workerState, WorkerActions.dispose);
|
|
2054
|
+
await this.request(WorkerAPIs.webIfc, WorkerActions.DisposeWebIfc);
|
|
2055
|
+
this.ifcWorker.terminate();
|
|
2056
|
+
}
|
|
2057
|
+
|
|
2058
|
+
async Close() {
|
|
2059
|
+
await this.request(WorkerAPIs.webIfc, WorkerActions.Close);
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
handleResponse(event) {
|
|
2063
|
+
const data = event.data;
|
|
2064
|
+
if (data.onProgress) {
|
|
2065
|
+
this.resolveOnProgress(data);
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
this.callHandlers(data);
|
|
2069
|
+
delete this.resolveHandlers[data.id];
|
|
2070
|
+
delete this.rejectHandlers[data.id];
|
|
2071
|
+
delete this.onprogressHandlers[data.id];
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
callHandlers(data) {
|
|
2075
|
+
try {
|
|
2076
|
+
this.resolveSerializations(data);
|
|
2077
|
+
this.resolveCallbacks(data);
|
|
2078
|
+
this.resolveHandlers[data.id](data.result);
|
|
2079
|
+
} catch (error) {
|
|
2080
|
+
this.rejectHandlers[data.id](error);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
|
|
2084
|
+
resolveOnProgress(data) {
|
|
2085
|
+
if (this.onprogressHandlers[data.id]) {
|
|
2086
|
+
data.result = this.onprogressHandlers[data.id](data.result);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
resolveSerializations(data) {
|
|
2091
|
+
if (this.serializeHandlers[data.id]) {
|
|
2092
|
+
data.result = this.serializeHandlers[data.id](data.result);
|
|
2093
|
+
delete this.serializeHandlers[data.id];
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
resolveCallbacks(data) {
|
|
2098
|
+
if (this.callbackHandlers[data.id]) {
|
|
2099
|
+
let callbackParameter = data.result;
|
|
2100
|
+
if (this.callbackHandlers[data.id].serializer) {
|
|
2101
|
+
callbackParameter = this.callbackHandlers[data.id].serializer(data.result);
|
|
2102
|
+
}
|
|
2103
|
+
this.callbackHandlers[data.id].action(callbackParameter);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
class MemoryCleaner {
|
|
2110
|
+
|
|
2111
|
+
constructor(state) {
|
|
2112
|
+
this.state = state;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
async dispose() {
|
|
2116
|
+
Object.keys(this.state.models).forEach(modelID => {
|
|
2117
|
+
const model = this.state.models[parseInt(modelID, 10)];
|
|
2118
|
+
model.mesh.removeFromParent();
|
|
2119
|
+
const geom = model.mesh.geometry;
|
|
2120
|
+
if (geom.disposeBoundsTree)
|
|
2121
|
+
geom.disposeBoundsTree();
|
|
2122
|
+
geom.dispose();
|
|
2123
|
+
if (!Array.isArray(model.mesh.material))
|
|
2124
|
+
model.mesh.material.dispose();
|
|
2125
|
+
else
|
|
2126
|
+
model.mesh.material.forEach(mat => mat.dispose());
|
|
2127
|
+
model.mesh = null;
|
|
2128
|
+
model.types = null;
|
|
2129
|
+
model.jsonData = null;
|
|
2130
|
+
});
|
|
2131
|
+
this.state.api = null;
|
|
2132
|
+
this.state.models = null;
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
class IFCUtils {
|
|
2138
|
+
|
|
2139
|
+
constructor(state) {
|
|
2140
|
+
this.state = state;
|
|
2141
|
+
this.map = {};
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
isA(entity, entity_class) {
|
|
2145
|
+
var test = false;
|
|
2146
|
+
if (entity_class) {
|
|
2147
|
+
if (this.state.api.GetNameFromTypeCode(entity.type) === entity_class.toUpperCase()) {
|
|
2148
|
+
test = true;
|
|
2149
|
+
}
|
|
2150
|
+
return test;
|
|
2151
|
+
} else {
|
|
2152
|
+
return this.state.api.GetNameFromTypeCode(entity.type);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
|
|
2156
|
+
async byId(modelID, id) {
|
|
2157
|
+
return this.state.api.GetLine(modelID, id);
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
async idsByType(modelID, entity_class) {
|
|
2161
|
+
let entities_ids = await this.state.api.GetLineIDsWithType(modelID, Number(this.state.api.GetTypeCodeFromName(modelID, entity_class.toUpperCase())));
|
|
2162
|
+
return entities_ids;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
async byType(modelID, entity_class) {
|
|
2166
|
+
let entities_ids = await this.idsByType(modelID, entity_class);
|
|
2167
|
+
if (entities_ids !== null) {
|
|
2168
|
+
let items = [];
|
|
2169
|
+
for (let i = 0; i < entities_ids.size(); i++) {
|
|
2170
|
+
let entity = await this.byId(modelID, entities_ids.get(i));
|
|
2171
|
+
items.push(entity);
|
|
2172
|
+
}
|
|
2173
|
+
return items;
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
class Data {
|
|
2180
|
+
|
|
2181
|
+
constructor(state) {
|
|
2182
|
+
this.state = state;
|
|
2183
|
+
this.isLoaded = false;
|
|
2184
|
+
this.workPlans = {};
|
|
2185
|
+
this.workSchedules = {};
|
|
2186
|
+
this.workCalendars = {};
|
|
2187
|
+
this.workTimes = {};
|
|
2188
|
+
this.recurrencePatterns = {};
|
|
2189
|
+
this.timePeriods = {};
|
|
2190
|
+
this.tasks = {};
|
|
2191
|
+
this.taskTimes = {};
|
|
2192
|
+
this.lagTimes = {};
|
|
2193
|
+
this.sequences = {};
|
|
2194
|
+
this.utils = new IFCUtils(this.state);
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
async load(modelID) {
|
|
2198
|
+
await this.loadTasks(modelID);
|
|
2199
|
+
await this.loadWorkSchedules(modelID);
|
|
2200
|
+
await this.loadWorkCalendars(modelID);
|
|
2201
|
+
await this.loadWorkTimes(modelID);
|
|
2202
|
+
await this.loadTimePeriods(modelID);
|
|
2203
|
+
this.isLoaded = true;
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
async loadWorkSchedules(modelID) {
|
|
2207
|
+
let workSchedules = await this.utils.byType(modelID, "IfcWorkSchedule");
|
|
2208
|
+
for (let i = 0; i < workSchedules.length; i++) {
|
|
2209
|
+
let workSchedule = workSchedules[i];
|
|
2210
|
+
this.workSchedules[workSchedule.expressID] = {
|
|
2211
|
+
"Id": workSchedule.expressID,
|
|
2212
|
+
"Name": workSchedule.Name.value,
|
|
2213
|
+
"Description": ((workSchedule.Description) ? workSchedule.Description.value : ""),
|
|
2214
|
+
"Creators": [],
|
|
2215
|
+
"CreationDate": ((workSchedule.CreationDate) ? workSchedule.CreationDate.value : ""),
|
|
2216
|
+
"StartTime": ((workSchedule.StartTime) ? workSchedule.StartTime.value : ""),
|
|
2217
|
+
"FinishTime": ((workSchedule.FinishTime) ? workSchedule.FinishTime.value : ""),
|
|
2218
|
+
"TotalFloat": ((workSchedule.TotalFloat) ? workSchedule.TotalFloat.value : ""),
|
|
2219
|
+
"RelatedObjects": [],
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
this.loadWorkScheduleRelatedObjects(modelID);
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
async loadWorkScheduleRelatedObjects(modelID) {
|
|
2226
|
+
let relsControls = await this.utils.byType(modelID, "IfcRelAssignsToControl");
|
|
2227
|
+
for (let i = 0; i < relsControls.length; i++) {
|
|
2228
|
+
let relControls = relsControls[i];
|
|
2229
|
+
let relatingControl = await this.utils.byId(modelID, relControls.RelatingControl.value);
|
|
2230
|
+
let relatedObjects = relControls.RelatedObjects;
|
|
2231
|
+
if (this.utils.isA(relatingControl, "IfcWorkSchedule")) {
|
|
2232
|
+
for (var objectIndex = 0; objectIndex < relatedObjects.length; objectIndex++) {
|
|
2233
|
+
this.workSchedules[relatingControl.expressID]["RelatedObjects"].push(relatedObjects[objectIndex].value);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
async loadTasks(modelID) {
|
|
2240
|
+
let tasks = await this.utils.byType(modelID, "IfcTask");
|
|
2241
|
+
for (let i = 0; i < tasks.length; i++) {
|
|
2242
|
+
let task = tasks[i];
|
|
2243
|
+
this.tasks[task.expressID] = {
|
|
2244
|
+
"Id": task.expressID,
|
|
2245
|
+
"Name": ((task.Name) ? task.Name.value : ""),
|
|
2246
|
+
"PredefinedType": ((task.PredefinedType) ? task.PredefinedType.value : ""),
|
|
2247
|
+
"TaskTime": ((task.TaskTime) ? await this.utils.byId(modelID, task.TaskTime.value) : ""),
|
|
2248
|
+
"Identification": ((task.Identification) ? task.Identification.value : ""),
|
|
2249
|
+
"IsMilestone": ((task.IsMilestone) ? task.IsMilestone.value : ""),
|
|
2250
|
+
"IsPredecessorTo": [],
|
|
2251
|
+
"IsSucessorFrom": [],
|
|
2252
|
+
"Inputs": [],
|
|
2253
|
+
"Resources": [],
|
|
2254
|
+
"Outputs": [],
|
|
2255
|
+
"Controls": [],
|
|
2256
|
+
"Nests": [],
|
|
2257
|
+
"IsNestedBy": [],
|
|
2258
|
+
"OperatesOn": [],
|
|
2259
|
+
"HasAssignmentsWorkCalendars": [],
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
await this.loadTaskSequence(modelID);
|
|
2263
|
+
await this.loadTaskOutputs(modelID);
|
|
2264
|
+
await this.loadTaskNesting(modelID);
|
|
2265
|
+
await this.loadTaskOperations(modelID);
|
|
2266
|
+
await this.loadAssignementsWorkCalendar(modelID);
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
async loadTaskSequence(modelID) {
|
|
2270
|
+
let relsSequence = await this.utils.idsByType(modelID, "IfcRelSequence");
|
|
2271
|
+
for (let i = 0; i < relsSequence.size(); i++) {
|
|
2272
|
+
let relSequenceId = relsSequence.get(i);
|
|
2273
|
+
if (relSequenceId !== 0) {
|
|
2274
|
+
let relSequence = await this.utils.byId(modelID, relSequenceId);
|
|
2275
|
+
let related_process = relSequence.RelatedProcess.value;
|
|
2276
|
+
let relatingProcess = relSequence.RelatingProcess.value;
|
|
2277
|
+
this.tasks[relatingProcess]["IsPredecessorTo"].push(relSequence.expressID);
|
|
2278
|
+
this.tasks[related_process]["IsSucessorFrom"].push(relSequence.expressID);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
async loadTaskOutputs(modelID) {
|
|
2284
|
+
let rels_assigns_to_product = await this.utils.byType(modelID, "IfcRelAssignsToProduct");
|
|
2285
|
+
for (let i = 0; i < rels_assigns_to_product.length; i++) {
|
|
2286
|
+
let relAssignsToProduct = rels_assigns_to_product[i];
|
|
2287
|
+
let relatedObject = await this.utils.byId(modelID, relAssignsToProduct.RelatedObjects[0].value);
|
|
2288
|
+
if (this.utils.isA(relatedObject, "IfcTask")) {
|
|
2289
|
+
let relatingProduct = await this.utils.byId(modelID, relAssignsToProduct.RelatingProduct.value);
|
|
2290
|
+
this.tasks[relatedObject.expressID]["Outputs"].push(relatingProduct.expressID);
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
async loadTaskNesting(modelID) {
|
|
2296
|
+
let rels_nests = await this.utils.byType(modelID, "IfcRelNests");
|
|
2297
|
+
for (let i = 0; i < rels_nests.length; i++) {
|
|
2298
|
+
let relNests = rels_nests[i];
|
|
2299
|
+
let relating_object = await this.utils.byId(modelID, relNests.RelatingObject.value);
|
|
2300
|
+
if (this.utils.isA(relating_object, "IfcTask")) {
|
|
2301
|
+
let relatedObjects = relNests.RelatedObjects;
|
|
2302
|
+
for (var object_index = 0; object_index < relatedObjects.length; object_index++) {
|
|
2303
|
+
this.tasks[relating_object.expressID]["IsNestedBy"].push(relatedObjects[object_index].value);
|
|
2304
|
+
this.tasks[relatedObjects[object_index].value]["Nests"].push(relating_object.expressID);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
async loadTaskOperations(modelID) {
|
|
2311
|
+
let relsAssignsToProcess = await this.utils.byType(modelID, "IfcRelAssignsToProcess");
|
|
2312
|
+
for (let i = 0; i < relsAssignsToProcess.length; i++) {
|
|
2313
|
+
let relAssignToProcess = relsAssignsToProcess[i];
|
|
2314
|
+
let relatingProcess = await this.utils.byId(modelID, relAssignToProcess.RelatingProcess.value);
|
|
2315
|
+
if (this.utils.isA(relatingProcess, "IfcTask")) {
|
|
2316
|
+
let relatedObjects = relAssignToProcess.RelatedObjects;
|
|
2317
|
+
for (var object_index = 0; object_index < relatedObjects.length; object_index++) {
|
|
2318
|
+
this.tasks[relatingProcess.expressID]["OperatesOn"].push(relatedObjects[object_index].value);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
async loadAssignementsWorkCalendar(modelID) {
|
|
2325
|
+
let relsAssignsToControl = await this.utils.byType(modelID, "IfcRelAssignsToControl");
|
|
2326
|
+
for (let i = 0; i < relsAssignsToControl.length; i++) {
|
|
2327
|
+
let relAssignsToControl = relsAssignsToControl[i];
|
|
2328
|
+
let relatingControl = await this.utils.byId(modelID, relAssignsToControl.RelatingControl.value);
|
|
2329
|
+
if (this.utils.isA(relatingControl, "IfcWorkCalendar")) {
|
|
2330
|
+
let relatedObjects = relAssignsToControl.RelatedObjects;
|
|
2331
|
+
for (var object_index = 0; object_index < relatedObjects.length; object_index++) {
|
|
2332
|
+
this.tasks[relatedObjects[object_index].value]["HasAssignmentsWorkCalendars"].push(relatingControl.expressID);
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
|
|
2338
|
+
async loadWorkCalendars(modelID) {
|
|
2339
|
+
let workCalendars = await this.utils.byType(modelID, "IfcWorkCalendar");
|
|
2340
|
+
for (let i = 0; i < workCalendars.length; i++) {
|
|
2341
|
+
let workCalendar = workCalendars[i];
|
|
2342
|
+
let workCalenderData = {
|
|
2343
|
+
"Id": workCalendar.expressID,
|
|
2344
|
+
"Name": ((workCalendar.Name) ? workCalendar.Name.value : ""),
|
|
2345
|
+
"Description": ((workCalendar.Description) ? workCalendar.Description.value : ""),
|
|
2346
|
+
"WorkingTimes": ((workCalendar.WorkingTimes) ? workCalendar.WorkingTimes : []),
|
|
2347
|
+
"ExceptionTimes": ((workCalendar.ExceptionTimes) ? workCalendar.ExceptionTimes : []),
|
|
2348
|
+
};
|
|
2349
|
+
this.workCalendars[workCalendar.expressID] = workCalenderData;
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
async loadWorkTimes(modelID) {
|
|
2354
|
+
let workTimes = await this.utils.byType(modelID, "IfcWorkTime");
|
|
2355
|
+
for (let i = 0; i < workTimes.length; i++) {
|
|
2356
|
+
let workTime = workTimes[i];
|
|
2357
|
+
let workTimeData = {
|
|
2358
|
+
"Name": ((workTime.Name) ? workTime.Name.value : ""),
|
|
2359
|
+
"RecurrencePattern": ((workTime.RecurrencePattern) ? await this.utils.byId(modelID, workTime.RecurrencePattern.value) : ""),
|
|
2360
|
+
"Start": ((workTime.Start) ? new Date(workTime.Start.value) : ""),
|
|
2361
|
+
"Finish": ((workTime.Finish) ? new Date(workTime.Finish.value) : ""),
|
|
2362
|
+
};
|
|
2363
|
+
this.workTimes[workTime.expressID] = workTimeData;
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
async loadTimePeriods(modelID) {
|
|
2368
|
+
let timePeriods = await this.utils.byType(modelID, "IfcTimePeriod");
|
|
2369
|
+
for (let i = 0; i < timePeriods.length; i++) {
|
|
2370
|
+
let timePeriod = timePeriods[i];
|
|
2371
|
+
let workTimeData = {
|
|
2372
|
+
"StartTime": ((timePeriod.StartTime) ? new Date(timePeriod.StartTime.value) : ""),
|
|
2373
|
+
"EndTime": ((timePeriod.EndTime) ? new Date(timePeriod.EndTime.value) : ""),
|
|
2374
|
+
};
|
|
2375
|
+
this.timePeriods[timePeriod.expressID] = workTimeData;
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
class IFCManager {
|
|
2382
|
+
|
|
2383
|
+
constructor() {
|
|
2384
|
+
this.state = {
|
|
2385
|
+
models: [],
|
|
2386
|
+
api: new WebIFC.IfcAPI(),
|
|
2387
|
+
useJSON: false,
|
|
2388
|
+
worker: {
|
|
2389
|
+
active: false,
|
|
2390
|
+
path: ''
|
|
2391
|
+
}
|
|
2392
|
+
};
|
|
2393
|
+
this.BVH = new BvhManager();
|
|
2394
|
+
this.parser = new IFCParser(this.state, this.BVH);
|
|
2395
|
+
this.subsets = new SubsetManager(this.state, this.BVH);
|
|
2396
|
+
this.utils = new IFCUtils(this.state);
|
|
2397
|
+
this.sequenceData = new Data(this.state);
|
|
2398
|
+
this.properties = new PropertyManager(this.state);
|
|
2399
|
+
this.types = new TypeManager(this.state);
|
|
2400
|
+
this.useFragments = false;
|
|
2401
|
+
this.cleaner = new MemoryCleaner(this.state);
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
get ifcAPI() {
|
|
2405
|
+
return this.state.api;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
async parse(buffer) {
|
|
2409
|
+
var _a;
|
|
2410
|
+
let model = await this.parser.parse(buffer, (_a = this.state.coordinationMatrix) === null || _a === void 0 ? void 0 : _a.toArray());
|
|
2411
|
+
model.setIFCManager(this);
|
|
2412
|
+
try {
|
|
2413
|
+
await this.types.getAllTypes(this.worker);
|
|
2414
|
+
} catch (e) {
|
|
2415
|
+
console.log("Could not get all types of model.");
|
|
2416
|
+
}
|
|
2417
|
+
return model;
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
async setWasmPath(path) {
|
|
2421
|
+
this.state.api.SetWasmPath(path);
|
|
2422
|
+
this.state.wasmPath = path;
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
setupThreeMeshBVH(computeBoundsTree, disposeBoundsTree, acceleratedRaycast) {
|
|
2426
|
+
this.BVH.initializeMeshBVH(computeBoundsTree, disposeBoundsTree, acceleratedRaycast);
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
setOnProgress(onProgress) {
|
|
2430
|
+
this.state.onProgress = onProgress;
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
setupCoordinationMatrix(matrix) {
|
|
2434
|
+
this.state.coordinationMatrix = matrix;
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
clearCoordinationMatrix() {
|
|
2438
|
+
delete this.state.coordinationMatrix;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
async applyWebIfcConfig(settings) {
|
|
2442
|
+
this.state.webIfcSettings = settings;
|
|
2443
|
+
if (this.state.worker.active && this.worker) {
|
|
2444
|
+
await this.worker.workerState.updateStateWebIfcSettings();
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
async useWebWorkers(active, path) {
|
|
2449
|
+
if (this.state.worker.active === active)
|
|
2450
|
+
return;
|
|
2451
|
+
this.state.api = null;
|
|
2452
|
+
if (active) {
|
|
2453
|
+
if (!path)
|
|
2454
|
+
throw new Error('You must provide a path to the web worker.');
|
|
2455
|
+
this.state.worker.active = active;
|
|
2456
|
+
this.state.worker.path = path;
|
|
2457
|
+
await this.initializeWorkers();
|
|
2458
|
+
const wasm = this.state.wasmPath;
|
|
2459
|
+
if (wasm)
|
|
2460
|
+
await this.setWasmPath(wasm);
|
|
2461
|
+
} else {
|
|
2462
|
+
this.state.api = new WebIFC.IfcAPI();
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2466
|
+
async useJSONData(useJSON = true) {
|
|
2467
|
+
var _a;
|
|
2468
|
+
this.state.useJSON = useJSON;
|
|
2469
|
+
if (useJSON) {
|
|
2470
|
+
await ((_a = this.worker) === null || _a === void 0 ? void 0 : _a.workerState.updateStateUseJson());
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
async addModelJSONData(modelID, data) {
|
|
2475
|
+
var _a;
|
|
2476
|
+
const model = this.state.models[modelID];
|
|
2477
|
+
if (!model)
|
|
2478
|
+
throw new Error('The specified model for the JSON data does not exist');
|
|
2479
|
+
if (this.state.worker.active) {
|
|
2480
|
+
await ((_a = this.worker) === null || _a === void 0 ? void 0 : _a.workerState.updateModelStateJsonData(modelID, data));
|
|
2481
|
+
} else {
|
|
2482
|
+
model.jsonData = data;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
async loadJsonDataFromWorker(modelID, path) {
|
|
2487
|
+
var _a;
|
|
2488
|
+
if (this.state.worker.active) {
|
|
2489
|
+
await ((_a = this.worker) === null || _a === void 0 ? void 0 : _a.workerState.loadJsonDataFromWorker(modelID, path));
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
close(modelID, scene) {
|
|
2494
|
+
try {
|
|
2495
|
+
this.state.api.CloseModel(modelID);
|
|
2496
|
+
const mesh = this.state.models[modelID].mesh;
|
|
2497
|
+
const {geometry, material} = mesh;
|
|
2498
|
+
if (scene)
|
|
2499
|
+
scene.remove(mesh);
|
|
2500
|
+
geometry === null || geometry === void 0 ? void 0 : geometry.dispose();
|
|
2501
|
+
Array.isArray(material) ? material.forEach(m => m.dispose()) : material === null || material === void 0 ? void 0 : material.dispose();
|
|
2502
|
+
delete this.state.models[modelID];
|
|
2503
|
+
} catch (e) {
|
|
2504
|
+
console.warn(`Close IFCModel ${modelID} failed`);
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
getExpressId(geometry, faceIndex) {
|
|
2509
|
+
return this.properties.getExpressId(geometry, faceIndex);
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
getAllItemsOfType(modelID, type, verbose) {
|
|
2513
|
+
return this.properties.getAllItemsOfType(modelID, type, verbose);
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
getItemProperties(modelID, id, recursive = false) {
|
|
2517
|
+
return this.properties.getItemProperties(modelID, id, recursive);
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
getPropertySets(modelID, id, recursive = false) {
|
|
2521
|
+
return this.properties.getPropertySets(modelID, id, recursive);
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
getTypeProperties(modelID, id, recursive = false) {
|
|
2525
|
+
return this.properties.getTypeProperties(modelID, id, recursive);
|
|
2526
|
+
}
|
|
2527
|
+
|
|
2528
|
+
getMaterialsProperties(modelID, id, recursive = false) {
|
|
2529
|
+
return this.properties.getMaterialsProperties(modelID, id, recursive);
|
|
2530
|
+
}
|
|
2531
|
+
|
|
2532
|
+
getIfcType(modelID, id) {
|
|
2533
|
+
const typeID = this.state.models[modelID].types[id];
|
|
2534
|
+
return this.state.api.GetNameFromTypeCode(typeID);
|
|
2535
|
+
}
|
|
2536
|
+
|
|
2537
|
+
getSpatialStructure(modelID, includeProperties) {
|
|
2538
|
+
return this.properties.getSpatialStructure(modelID, includeProperties);
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
getSubset(modelID, material, customId) {
|
|
2542
|
+
return this.subsets.getSubset(modelID, material, customId);
|
|
2543
|
+
}
|
|
2544
|
+
|
|
2545
|
+
removeSubset(modelID, material, customID) {
|
|
2546
|
+
this.subsets.removeSubset(modelID, material, customID);
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
createSubset(config) {
|
|
2550
|
+
return this.subsets.createSubset(config);
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
removeFromSubset(modelID, ids, customID, material) {
|
|
2554
|
+
return this.subsets.removeFromSubset(modelID, ids, customID, material);
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
clearSubset(modelID, customID, material) {
|
|
2558
|
+
return this.subsets.clearSubset(modelID, customID, material);
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
async isA(entity, entity_class) {
|
|
2562
|
+
return this.utils.isA(entity, entity_class);
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
async getSequenceData(modelID) {
|
|
2566
|
+
await this.sequenceData.load(modelID);
|
|
2567
|
+
return this.sequenceData;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
async byType(modelID, entityClass) {
|
|
2571
|
+
return this.utils.byType(modelID, entityClass);
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
async byId(modelID, id) {
|
|
2575
|
+
return this.utils.byId(modelID, id);
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
async idsByType(modelID, entityClass) {
|
|
2579
|
+
return this.utils.idsByType(modelID, entityClass);
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
async dispose() {
|
|
2583
|
+
IFCModel.dispose();
|
|
2584
|
+
await this.cleaner.dispose();
|
|
2585
|
+
this.subsets.dispose();
|
|
2586
|
+
if (this.worker && this.state.worker.active)
|
|
2587
|
+
await this.worker.terminate();
|
|
2588
|
+
this.state = null;
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
async disposeMemory() {
|
|
2592
|
+
var _a;
|
|
2593
|
+
if (this.state.worker.active) {
|
|
2594
|
+
await ((_a = this.worker) === null || _a === void 0 ? void 0 : _a.Close());
|
|
2595
|
+
} else {
|
|
2596
|
+
this.state.api.Close();
|
|
2597
|
+
this.state.api = null;
|
|
2598
|
+
this.state.api = new WebIFC.IfcAPI();
|
|
2599
|
+
}
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
getAndClearErrors(modelID) {
|
|
2603
|
+
return this.parser.getAndClearErrors(modelID);
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
async initializeWorkers() {
|
|
2607
|
+
this.worker = new IFCWorkerHandler(this.state, this.BVH);
|
|
2608
|
+
this.state.api = this.worker.webIfc;
|
|
2609
|
+
this.properties = this.worker.properties;
|
|
2610
|
+
await this.worker.parser.setupOptionalCategories(this.parser.optionalCategories);
|
|
2611
|
+
this.parser = this.worker.parser;
|
|
2612
|
+
await this.worker.workerState.updateStateUseJson();
|
|
2613
|
+
await this.worker.workerState.updateStateWebIfcSettings();
|
|
2614
|
+
}
|
|
2615
|
+
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
class IFCLoader extends Loader {
|
|
2619
|
+
|
|
2620
|
+
constructor(manager) {
|
|
2621
|
+
super(manager);
|
|
2622
|
+
this.ifcManager = new IFCManager();
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
load(url, onLoad, onProgress, onError) {
|
|
2626
|
+
const scope = this;
|
|
2627
|
+
const loader = new FileLoader(scope.manager);
|
|
2628
|
+
this.onProgress = onProgress;
|
|
2629
|
+
loader.setPath(scope.path);
|
|
2630
|
+
loader.setResponseType('arraybuffer');
|
|
2631
|
+
loader.setRequestHeader(scope.requestHeader);
|
|
2632
|
+
loader.setWithCredentials(scope.withCredentials);
|
|
2633
|
+
loader.load(url, async function (buffer) {
|
|
2634
|
+
try {
|
|
2635
|
+
if (typeof buffer == 'string') {
|
|
2636
|
+
throw new Error('IFC files must be given as a buffer!');
|
|
2637
|
+
}
|
|
2638
|
+
onLoad(await scope.parse(buffer));
|
|
2639
|
+
} catch (e) {
|
|
2640
|
+
if (onError) {
|
|
2641
|
+
onError(e);
|
|
2642
|
+
} else {
|
|
2643
|
+
console.error(e);
|
|
2644
|
+
}
|
|
2645
|
+
scope.manager.itemError(url);
|
|
2646
|
+
}
|
|
2647
|
+
}, onProgress, onError);
|
|
2648
|
+
}
|
|
2649
|
+
|
|
2650
|
+
parse(buffer) {
|
|
2651
|
+
return this.ifcManager.parse(buffer);
|
|
2652
|
+
}
|
|
2653
|
+
|
|
2654
|
+
}
|
|
2655
|
+
|
|
2656
|
+
export { IFCLoader };
|
|
2657
|
+
//# sourceMappingURL=IFCLoader.js.map
|