babylon-ifc-loader 1.0.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/API.md +619 -0
- package/LICENSE +190 -0
- package/dist-npm/ifcInit.d.ts +60 -0
- package/dist-npm/ifcInit.d.ts.map +1 -0
- package/dist-npm/ifcInit.js +301 -0
- package/dist-npm/ifcInit.js.map +1 -0
- package/dist-npm/ifcModel.d.ts +51 -0
- package/dist-npm/ifcModel.d.ts.map +1 -0
- package/dist-npm/ifcModel.js +347 -0
- package/dist-npm/ifcModel.js.map +1 -0
- package/dist-npm/index.d.ts +5 -0
- package/dist-npm/index.d.ts.map +1 -0
- package/dist-npm/index.js +8 -0
- package/dist-npm/index.js.map +1 -0
- package/dist-npm/web-ifc.wasm +0 -0
- package/package.json +70 -0
- package/readme.md +304 -0
package/API.md
ADDED
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
This document provides detailed API reference for the IFC Viewer library. The codebase follows a strict layered architecture with clear separation between the IFC data layer (web-ifc) and the rendering layer (Babylon.js).
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [IFC Data Layer (ifcInit.ts)](#ifc-data-layer-ifcinitts)
|
|
8
|
+
- [initializeWebIFC](#initializewebifc)
|
|
9
|
+
- [loadIfcModel](#loadifcmodel)
|
|
10
|
+
- [closeIfcModel](#closeifcmodel)
|
|
11
|
+
- [getProjectInfo](#getprojectinfo)
|
|
12
|
+
- [Types](#types-ifcinit)
|
|
13
|
+
- [Rendering Layer (ifcModel.ts)](#rendering-layer-ifcmodelts)
|
|
14
|
+
- [buildIfcModel](#buildifcmodel)
|
|
15
|
+
- [disposeIfcModel](#disposeifcmodel)
|
|
16
|
+
- [getModelBounds](#getmodelbounds)
|
|
17
|
+
- [centerModelAtOrigin](#centermodelatorigin)
|
|
18
|
+
- [Types](#types-ifcmodel)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## IFC Data Layer (ifcInit.ts)
|
|
23
|
+
|
|
24
|
+
All web-ifc interaction. **Zero Babylon.js dependencies.**
|
|
25
|
+
|
|
26
|
+
### initializeWebIFC
|
|
27
|
+
|
|
28
|
+
Initialize the web-ifc API. This should be called once at application startup.
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
async function initializeWebIFC(wasmPath?: string, logLevel?: WebIFC.LogLevel): Promise<WebIFC.IfcAPI>;
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### Parameters
|
|
35
|
+
|
|
36
|
+
| Parameter | Type | Required | Default | Description |
|
|
37
|
+
| ---------- | ----------------- | -------- | ----------------- | ----------------------------------------------------------------------- |
|
|
38
|
+
| `wasmPath` | `string` | No | - | Custom path to the web-ifc.wasm file. Use `"./"` for production builds. |
|
|
39
|
+
| `logLevel` | `WebIFC.LogLevel` | No | `LOG_LEVEL_ERROR` | Logging level for web-ifc. |
|
|
40
|
+
|
|
41
|
+
#### Returns
|
|
42
|
+
|
|
43
|
+
`Promise<WebIFC.IfcAPI>` - Initialized web-ifc API instance.
|
|
44
|
+
|
|
45
|
+
#### Example
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { initializeWebIFC } from "./ifcInit";
|
|
49
|
+
|
|
50
|
+
// Initialize with default settings
|
|
51
|
+
const ifcAPI = await initializeWebIFC();
|
|
52
|
+
|
|
53
|
+
// Initialize with custom WASM path (for production)
|
|
54
|
+
const ifcAPI = await initializeWebIFC("./");
|
|
55
|
+
|
|
56
|
+
// Initialize with custom log level
|
|
57
|
+
import * as WebIFC from "web-ifc";
|
|
58
|
+
const ifcAPI = await initializeWebIFC("./", WebIFC.LogLevel.LOG_LEVEL_WARNING);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Console Output
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
✓ Web-IFC initialized in Xms
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### loadIfcModel
|
|
70
|
+
|
|
71
|
+
Load an IFC file and extract raw geometry data. Returns a `RawIfcModel` with no Babylon.js dependencies.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
async function loadIfcModel(
|
|
75
|
+
ifcAPI: WebIFC.IfcAPI,
|
|
76
|
+
source: string | File,
|
|
77
|
+
options?: IfcInitOptions,
|
|
78
|
+
): Promise<RawIfcModel>;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### Parameters
|
|
82
|
+
|
|
83
|
+
| Parameter | Type | Required | Default | Description |
|
|
84
|
+
| --------- | ---------------- | -------- | ------- | ------------------------------------------------------- |
|
|
85
|
+
| `ifcAPI` | `WebIFC.IfcAPI` | Yes | - | Initialized web-ifc API instance. |
|
|
86
|
+
| `source` | `string \| File` | Yes | - | URL path to IFC file or File object from drag-and-drop. |
|
|
87
|
+
| `options` | `IfcInitOptions` | No | `{}` | Configuration options for loading. |
|
|
88
|
+
|
|
89
|
+
#### IfcInitOptions
|
|
90
|
+
|
|
91
|
+
| Property | Type | Default | Description |
|
|
92
|
+
| -------------------- | --------- | ------- | ------------------------------------------------------------------ |
|
|
93
|
+
| `coordinateToOrigin` | `boolean` | `true` | Move model coordinates to origin (web-ifc `COORDINATE_TO_ORIGIN`). |
|
|
94
|
+
| `verbose` | `boolean` | `true` | Enable console logging during loading. |
|
|
95
|
+
|
|
96
|
+
#### Returns
|
|
97
|
+
|
|
98
|
+
`Promise<RawIfcModel>` - Raw IFC model data with geometry parts, storey map, and statistics.
|
|
99
|
+
|
|
100
|
+
#### Example
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { loadIfcModel } from "./ifcInit";
|
|
104
|
+
|
|
105
|
+
// Load from URL
|
|
106
|
+
const model = await loadIfcModel(ifcAPI, "/path/to/model.ifc");
|
|
107
|
+
|
|
108
|
+
// Load from File object (drag-and-drop)
|
|
109
|
+
const model = await loadIfcModel(ifcAPI, fileObject);
|
|
110
|
+
|
|
111
|
+
// Load with options
|
|
112
|
+
const model = await loadIfcModel(ifcAPI, "/model.ifc", {
|
|
113
|
+
coordinateToOrigin: true,
|
|
114
|
+
verbose: true,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Access model data
|
|
118
|
+
console.log(model.modelID); // IFC model identifier
|
|
119
|
+
console.log(model.parts.length); // Number of geometry parts
|
|
120
|
+
console.log(model.rawStats); // Statistics
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### Console Output (verbose mode)
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
📥 Fetching IFC from URL: /test.ifc
|
|
127
|
+
📥 Received 2.45 MB
|
|
128
|
+
📥 Opening IFC model (2.45 MB)...
|
|
129
|
+
📥 OpenModel returned modelID: 0
|
|
130
|
+
|
|
131
|
+
📦 Collected 1234 geometry parts
|
|
132
|
+
|
|
133
|
+
📊 Raw Model Statistics:
|
|
134
|
+
Parts extracted: 1234
|
|
135
|
+
Vertices: 156,789
|
|
136
|
+
Triangles: 52,263
|
|
137
|
+
Storey relationships: 5
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### closeIfcModel
|
|
143
|
+
|
|
144
|
+
Close an IFC model and free WASM memory. Call this when disposing of a model.
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
function closeIfcModel(ifcAPI: WebIFC.IfcAPI, modelID: number): void;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Parameters
|
|
151
|
+
|
|
152
|
+
| Parameter | Type | Required | Description |
|
|
153
|
+
| --------- | --------------- | -------- | -------------------------------------- |
|
|
154
|
+
| `ifcAPI` | `WebIFC.IfcAPI` | Yes | Initialized web-ifc API instance. |
|
|
155
|
+
| `modelID` | `number` | Yes | Model ID returned from `loadIfcModel`. |
|
|
156
|
+
|
|
157
|
+
#### Example
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { closeIfcModel } from "./ifcInit";
|
|
161
|
+
|
|
162
|
+
// Close model and free memory
|
|
163
|
+
closeIfcModel(ifcAPI, model.modelID);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Console Output
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
✓ Model 0 closed and memory freed
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### getProjectInfo
|
|
175
|
+
|
|
176
|
+
Extract high-level IFC project metadata (project name, application, author, organization).
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
function getProjectInfo(ifcAPI: WebIFC.IfcAPI, modelID: number): ProjectInfoResult;
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Parameters
|
|
183
|
+
|
|
184
|
+
| Parameter | Type | Required | Description |
|
|
185
|
+
| --------- | --------------- | -------- | -------------------------------------- |
|
|
186
|
+
| `ifcAPI` | `WebIFC.IfcAPI` | Yes | Initialized web-ifc API instance. |
|
|
187
|
+
| `modelID` | `number` | Yes | Model ID returned from `loadIfcModel`. |
|
|
188
|
+
|
|
189
|
+
#### Returns
|
|
190
|
+
|
|
191
|
+
`ProjectInfoResult` - Project metadata object.
|
|
192
|
+
|
|
193
|
+
#### Example
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { getProjectInfo } from "./ifcInit";
|
|
197
|
+
|
|
198
|
+
const projectInfo = getProjectInfo(ifcAPI, model.modelID);
|
|
199
|
+
|
|
200
|
+
console.log(projectInfo.projectName); // "My Building Project"
|
|
201
|
+
console.log(projectInfo.projectDescription); // "A sample building"
|
|
202
|
+
console.log(projectInfo.application); // "Revit 2024"
|
|
203
|
+
console.log(projectInfo.author); // "John Doe"
|
|
204
|
+
console.log(projectInfo.organization); // "ACME Corp"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
### Types (ifcInit)
|
|
210
|
+
|
|
211
|
+
#### RawIfcModel
|
|
212
|
+
|
|
213
|
+
Complete raw model returned by `loadIfcModel`.
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
interface RawIfcModel {
|
|
217
|
+
modelID: number; // IFC model identifier
|
|
218
|
+
parts: RawGeometryPart[]; // Array of geometry parts
|
|
219
|
+
storeyMap: Map<number, number>; // Element ID to storey ID mapping
|
|
220
|
+
rawStats: {
|
|
221
|
+
partCount: number; // Number of geometry parts
|
|
222
|
+
vertexCount: number; // Total vertices
|
|
223
|
+
triangleCount: number; // Total triangles
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### RawGeometryPart
|
|
229
|
+
|
|
230
|
+
Single piece of placed geometry from web-ifc.
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
interface RawGeometryPart {
|
|
234
|
+
expressID: number; // IFC element express ID
|
|
235
|
+
geometryExpressID: number; // Geometry express ID
|
|
236
|
+
positions: Float32Array; // Vertex positions (x, y, z)
|
|
237
|
+
normals: Float32Array; // Vertex normals (nx, ny, nz)
|
|
238
|
+
indices: Uint32Array; // Triangle indices
|
|
239
|
+
flatTransform: number[]; // 4x4 transformation matrix (16 values)
|
|
240
|
+
color: {
|
|
241
|
+
// RGBA color (normalized 0-1)
|
|
242
|
+
x: number; // R
|
|
243
|
+
y: number; // G
|
|
244
|
+
z: number; // B
|
|
245
|
+
w: number; // A
|
|
246
|
+
} | null;
|
|
247
|
+
colorId: number; // Unique color identifier
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### IfcInitOptions
|
|
252
|
+
|
|
253
|
+
Configuration for IFC loader.
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
interface IfcInitOptions {
|
|
257
|
+
coordinateToOrigin?: boolean; // Move to origin (default: true)
|
|
258
|
+
verbose?: boolean; // Console logging (default: true)
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### ProjectInfoResult
|
|
263
|
+
|
|
264
|
+
Project metadata extracted from IFC file.
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
interface ProjectInfoResult {
|
|
268
|
+
projectName: string | null; // IFC project name
|
|
269
|
+
projectDescription: string | null; // Project description
|
|
270
|
+
application: string | null; // Creating application
|
|
271
|
+
author: string | null; // Author name
|
|
272
|
+
organization: string | null; // Organization name
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Rendering Layer (ifcModel.ts)
|
|
279
|
+
|
|
280
|
+
All Babylon.js scene construction. **Zero web-ifc dependencies.**
|
|
281
|
+
|
|
282
|
+
### buildIfcModel
|
|
283
|
+
|
|
284
|
+
Build a Babylon.js scene from raw IFC model data.
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
function buildIfcModel(model: RawIfcModel, scene: Scene, options?: SceneBuildOptions): SceneBuildResult;
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
#### Parameters
|
|
291
|
+
|
|
292
|
+
| Parameter | Type | Required | Description |
|
|
293
|
+
| --------- | ------------------- | -------- | ----------------------------------------- |
|
|
294
|
+
| `model` | `RawIfcModel` | Yes | Raw model data from `loadIfcModel`. |
|
|
295
|
+
| `scene` | `Scene` | Yes | Babylon.js scene instance. |
|
|
296
|
+
| `options` | `SceneBuildOptions` | No | Configuration options for scene building. |
|
|
297
|
+
|
|
298
|
+
#### SceneBuildOptions
|
|
299
|
+
|
|
300
|
+
| Property | Type | Default | Description |
|
|
301
|
+
| ------------------ | --------- | ------- | ------------------------------------------------ |
|
|
302
|
+
| `mergeMeshes` | `boolean` | `true` | Merge meshes with same material for performance. |
|
|
303
|
+
| `autoCenter` | `boolean` | `true` | Center model at origin. |
|
|
304
|
+
| `doubleSided` | `boolean` | `true` | Disable backface culling (render both sides). |
|
|
305
|
+
| `generateNormals` | `boolean` | `false` | Generate normals if missing. |
|
|
306
|
+
| `verbose` | `boolean` | `true` | Enable console logging during building. |
|
|
307
|
+
| `freezeAfterBuild` | `boolean` | `true` | Freeze meshes and materials for performance. |
|
|
308
|
+
|
|
309
|
+
#### Returns
|
|
310
|
+
|
|
311
|
+
`SceneBuildResult` - Object containing meshes, root node, and statistics.
|
|
312
|
+
|
|
313
|
+
#### Example
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
import { buildIfcModel } from "./ifcModel";
|
|
317
|
+
|
|
318
|
+
const { meshes, rootNode, stats } = buildIfcModel(model, scene, {
|
|
319
|
+
mergeMeshes: true,
|
|
320
|
+
autoCenter: true,
|
|
321
|
+
doubleSided: true,
|
|
322
|
+
generateNormals: false,
|
|
323
|
+
verbose: true,
|
|
324
|
+
freezeAfterBuild: true,
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
console.log(`Created ${meshes.length} meshes`);
|
|
328
|
+
console.log(`Build time: ${stats.buildTimeMs}ms`);
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### Console Output (verbose mode)
|
|
332
|
+
|
|
333
|
+
```
|
|
334
|
+
🏗️ Building Babylon.js scene from 1234 raw parts...
|
|
335
|
+
Created 1234 initial meshes
|
|
336
|
+
Grouped into 567 unique (expressID + material) combinations
|
|
337
|
+
|
|
338
|
+
📍 Model auto-centered at origin (offset: 10.50, 0.00, -5.25)
|
|
339
|
+
|
|
340
|
+
✅ Scene building complete:
|
|
341
|
+
Original parts: 1234
|
|
342
|
+
Merged groups: 100
|
|
343
|
+
Skipped groups: 5
|
|
344
|
+
Final meshes: 1129
|
|
345
|
+
Materials created: 15
|
|
346
|
+
Build time: 234.56ms
|
|
347
|
+
IFC meshes and materials frozen for optimal performance
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
---
|
|
351
|
+
|
|
352
|
+
### disposeIfcModel
|
|
353
|
+
|
|
354
|
+
Dispose all IFC meshes, materials, and the root node. Call this before loading a new model.
|
|
355
|
+
|
|
356
|
+
```typescript
|
|
357
|
+
function disposeIfcModel(scene: Scene): void;
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
#### Parameters
|
|
361
|
+
|
|
362
|
+
| Parameter | Type | Required | Description |
|
|
363
|
+
| --------- | ------- | -------- | -------------------------- |
|
|
364
|
+
| `scene` | `Scene` | Yes | Babylon.js scene instance. |
|
|
365
|
+
|
|
366
|
+
#### Example
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
import { disposeIfcModel } from "./ifcModel";
|
|
370
|
+
|
|
371
|
+
// Clean up before loading new model
|
|
372
|
+
disposeIfcModel(scene);
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### Console Output
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
✓ ifc-root node and all child meshes disposed
|
|
379
|
+
✓ 15 IFC materials disposed
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### getModelBounds
|
|
385
|
+
|
|
386
|
+
Calculate bounding box for a set of meshes. Useful for camera positioning.
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
function getModelBounds(meshes: AbstractMesh[]): BoundsInfo | null;
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
#### Parameters
|
|
393
|
+
|
|
394
|
+
| Parameter | Type | Required | Description |
|
|
395
|
+
| --------- | ---------------- | -------- | ---------------------------------------- |
|
|
396
|
+
| `meshes` | `AbstractMesh[]` | Yes | Array of meshes to calculate bounds for. |
|
|
397
|
+
|
|
398
|
+
#### Returns
|
|
399
|
+
|
|
400
|
+
`BoundsInfo | null` - Bounding box information, or `null` if no valid meshes.
|
|
401
|
+
|
|
402
|
+
#### Example
|
|
403
|
+
|
|
404
|
+
```typescript
|
|
405
|
+
import { getModelBounds } from "./ifcModel";
|
|
406
|
+
|
|
407
|
+
const bounds = getModelBounds(meshes);
|
|
408
|
+
|
|
409
|
+
if (bounds) {
|
|
410
|
+
console.log(`Center: ${bounds.center}`);
|
|
411
|
+
console.log(`Size: ${bounds.size}`);
|
|
412
|
+
console.log(`Diagonal: ${bounds.diagonal}`);
|
|
413
|
+
|
|
414
|
+
// Position camera
|
|
415
|
+
camera.target = bounds.center;
|
|
416
|
+
camera.radius = bounds.diagonal * 1.5;
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
### centerModelAtOrigin
|
|
423
|
+
|
|
424
|
+
Manually center a model at the origin. Useful when `autoCenter` option is disabled.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
function centerModelAtOrigin(meshes: AbstractMesh[], rootNode?: TransformNode): Vector3;
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
#### Parameters
|
|
431
|
+
|
|
432
|
+
| Parameter | Type | Required | Description |
|
|
433
|
+
| ---------- | ---------------- | -------- | ----------------------------- |
|
|
434
|
+
| `meshes` | `AbstractMesh[]` | Yes | Array of meshes to center. |
|
|
435
|
+
| `rootNode` | `TransformNode` | No | Root node to apply offset to. |
|
|
436
|
+
|
|
437
|
+
#### Returns
|
|
438
|
+
|
|
439
|
+
`Vector3` - The offset vector that was applied.
|
|
440
|
+
|
|
441
|
+
#### Example
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
import { centerModelAtOrigin } from "./ifcModel";
|
|
445
|
+
|
|
446
|
+
const offset = centerModelAtOrigin(meshes, rootNode);
|
|
447
|
+
console.log(`Model centered with offset: ${offset}`);
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
---
|
|
451
|
+
|
|
452
|
+
### Types (ifcModel)
|
|
453
|
+
|
|
454
|
+
#### SceneBuildOptions
|
|
455
|
+
|
|
456
|
+
Configuration for scene building.
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
interface SceneBuildOptions {
|
|
460
|
+
mergeMeshes?: boolean; // Merge meshes with same material (default: true)
|
|
461
|
+
autoCenter?: boolean; // Center model at origin (default: true)
|
|
462
|
+
doubleSided?: boolean; // Disable backface culling (default: true)
|
|
463
|
+
generateNormals?: boolean; // Generate normals if missing (default: false)
|
|
464
|
+
verbose?: boolean; // Console logging (default: true)
|
|
465
|
+
freezeAfterBuild?: boolean; // Freeze for performance (default: true)
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
#### SceneBuildResult
|
|
470
|
+
|
|
471
|
+
Result of building a scene.
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
interface SceneBuildResult {
|
|
475
|
+
meshes: AbstractMesh[]; // Created meshes
|
|
476
|
+
rootNode: TransformNode; // Root transform node
|
|
477
|
+
stats: BuildStats; // Build statistics
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
#### BuildStats
|
|
482
|
+
|
|
483
|
+
Statistics from scene building.
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
interface BuildStats {
|
|
487
|
+
originalPartCount: number; // Original geometry parts
|
|
488
|
+
finalMeshCount: number; // Final mesh count after merging
|
|
489
|
+
mergedGroupCount: number; // Successfully merged groups
|
|
490
|
+
skippedGroupCount: number; // Groups that couldn't be merged
|
|
491
|
+
materialCount: number; // Materials created
|
|
492
|
+
buildTimeMs: number; // Build time in milliseconds
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
#### BoundsInfo
|
|
497
|
+
|
|
498
|
+
Bounds information for camera framing.
|
|
499
|
+
|
|
500
|
+
```typescript
|
|
501
|
+
interface BoundsInfo {
|
|
502
|
+
min: Vector3; // Minimum corner
|
|
503
|
+
max: Vector3; // Maximum corner
|
|
504
|
+
center: Vector3; // Center point
|
|
505
|
+
size: Vector3; // Size (width, height, depth)
|
|
506
|
+
diagonal: number; // Diagonal length
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## Complete Usage Example
|
|
513
|
+
|
|
514
|
+
```typescript
|
|
515
|
+
import { initializeWebIFC, loadIfcModel, closeIfcModel, getProjectInfo } from "./ifcInit";
|
|
516
|
+
import { buildIfcModel, disposeIfcModel, getModelBounds } from "./ifcModel";
|
|
517
|
+
import { Engine, Scene, ArcRotateCamera, HemisphericLight, Vector3 } from "@babylonjs/core";
|
|
518
|
+
|
|
519
|
+
// Step 1: Initialize web-ifc
|
|
520
|
+
const ifcAPI = await initializeWebIFC("./");
|
|
521
|
+
|
|
522
|
+
// Step 2: Create Babylon.js scene
|
|
523
|
+
const canvas = document.getElementById("canvas") as HTMLCanvasElement;
|
|
524
|
+
const engine = new Engine(canvas, true);
|
|
525
|
+
const scene = new Scene(engine);
|
|
526
|
+
|
|
527
|
+
// Step 3: Setup camera and lighting
|
|
528
|
+
const camera = new ArcRotateCamera("camera", -Math.PI / 2, Math.PI / 2.5, 10, Vector3.Zero(), scene);
|
|
529
|
+
camera.attachControl(canvas, true);
|
|
530
|
+
const light = new HemisphericLight("light", new Vector3(0, 1, 0), scene);
|
|
531
|
+
|
|
532
|
+
// Step 4: Load IFC model
|
|
533
|
+
const model = await loadIfcModel(ifcAPI, "/model.ifc", {
|
|
534
|
+
coordinateToOrigin: true,
|
|
535
|
+
verbose: true,
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
// Step 5: Get project info
|
|
539
|
+
const projectInfo = getProjectInfo(ifcAPI, model.modelID);
|
|
540
|
+
console.log(`Project: ${projectInfo.projectName}`);
|
|
541
|
+
|
|
542
|
+
// Step 6: Build Babylon.js scene
|
|
543
|
+
const { meshes, rootNode, stats } = buildIfcModel(model, scene, {
|
|
544
|
+
autoCenter: true,
|
|
545
|
+
mergeMeshes: true,
|
|
546
|
+
doubleSided: true,
|
|
547
|
+
verbose: true,
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
// Step 7: Position camera
|
|
551
|
+
const bounds = getModelBounds(meshes);
|
|
552
|
+
if (bounds) {
|
|
553
|
+
camera.target = bounds.center;
|
|
554
|
+
camera.radius = bounds.diagonal * 1.5;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Step 8: Render loop
|
|
558
|
+
engine.runRenderLoop(() => scene.render());
|
|
559
|
+
|
|
560
|
+
// Cleanup when loading new model
|
|
561
|
+
function cleanup() {
|
|
562
|
+
disposeIfcModel(scene);
|
|
563
|
+
closeIfcModel(ifcAPI, model.modelID);
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
## Mesh Metadata
|
|
570
|
+
|
|
571
|
+
All meshes created by `buildIfcModel` have metadata attached:
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
mesh.metadata = {
|
|
575
|
+
expressID: number, // IFC element express ID
|
|
576
|
+
modelID: number, // IFC model ID
|
|
577
|
+
};
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
Use this for element picking and querying:
|
|
581
|
+
|
|
582
|
+
```typescript
|
|
583
|
+
scene.onPointerDown = (evt, pickResult) => {
|
|
584
|
+
if (pickResult.hit && pickResult.pickedMesh?.metadata) {
|
|
585
|
+
const { expressID, modelID } = pickResult.pickedMesh.metadata;
|
|
586
|
+
const element = ifcAPI.GetLine(modelID, expressID, true);
|
|
587
|
+
const typeName = ifcAPI.GetNameFromTypeCode(element.type);
|
|
588
|
+
console.log(`Picked: ${typeName} (ID: ${expressID})`);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
## Performance Notes
|
|
596
|
+
|
|
597
|
+
1. **Mesh Merging**: Enabled by default, significantly reduces draw calls
|
|
598
|
+
2. **Freezing**: Meshes and materials are frozen after build for optimal performance
|
|
599
|
+
3. **Memory**: Always call `closeIfcModel` when done with a model to free WASM memory
|
|
600
|
+
4. **Z-Fighting**: Materials have incremental `zOffset` to mitigate visual artifacts
|
|
601
|
+
5. **Coordinate System**: Z-axis flip is applied via root node scaling for IFC-to-Babylon conversion
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## Error Handling
|
|
606
|
+
|
|
607
|
+
```typescript
|
|
608
|
+
try {
|
|
609
|
+
const model = await loadIfcModel(ifcAPI, "/model.ifc");
|
|
610
|
+
} catch (error) {
|
|
611
|
+
console.error("Failed to load IFC:", error);
|
|
612
|
+
// Handle error (show user message, etc.)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
// Check if model is open before closing
|
|
616
|
+
if (ifcAPI.IsModelOpen(modelID)) {
|
|
617
|
+
closeIfcModel(ifcAPI, modelID);
|
|
618
|
+
}
|
|
619
|
+
```
|