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/readme.md ADDED
@@ -0,0 +1,304 @@
1
+ # Babylon.js IFC Loader
2
+
3
+ IFC Loader built with Babylon.js and web-ifc. Features automatic loading of sample IFC files, drag-and-drop support, intelligent mesh merging, element picking with metadata display, and automatic camera framing.
4
+
5
+ While providing the minimal viewer experience, this repo is dedicated to developing and testing the IFC Babylon.js Loader. The viewer is provided for testing and demonstration purposes only. Full-featured Babylon.js IFC Babylon.js Viewer will be available in a separate repo later.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ # Install dependencies
11
+ npm install
12
+
13
+ # Start development server
14
+ npm run dev
15
+
16
+ # Build for production
17
+ npm run build
18
+
19
+ # Preview production build
20
+ npm run preview
21
+
22
+ # Run tests
23
+ npm test
24
+
25
+ # Run tests with coverage
26
+ npm run test:coverage
27
+ ```
28
+
29
+ ### Dev Server URL
30
+
31
+ After running `npm run dev`, open:
32
+
33
+ | URL | Entry Point | Description |
34
+ | ---------------------- | ----------- | ------------------------------------------------ |
35
+ | http://localhost:5173/ | `main.ts` | Uses low-level two-step API (ifcInit + ifcModel) |
36
+
37
+ ## Features
38
+
39
+ - **Automatic Loading:** Sample IFC file loads on startup
40
+ - **Drag & Drop:** Drop `.ifc` files onto the canvas to load them
41
+ - **Element Picking:** Click on elements to view metadata and highlight them
42
+ - **Intelligent Merging:** Automatically merges meshes with same material while preserving metadata
43
+ - **Camera Framing:** Automatically positions camera to view the entire model
44
+ - **Inspector:** Built-in Babylon.js Inspector for debugging
45
+ - **Keyboard Shortcuts:** Ctrl+I (or Cmd+I on Mac) toggles the inspector, works across all keyboard layouts
46
+ - **Memory Management:** Proper cleanup when loading new files
47
+
48
+ ## Architecture
49
+
50
+ The codebase follows a strict layered architecture with clear separation of concerns:
51
+
52
+ ### IFC Data Layer (`src/ifcInit.ts`)
53
+
54
+ All web-ifc interaction. **Zero Babylon.js dependencies.**
55
+
56
+ - `initializeWebIFC(wasmPath?, logLevel?)` — initialize web-ifc API
57
+ - `loadIfcModel(ifcAPI, source, options?)` — load and extract raw geometry data
58
+ - `closeIfcModel(ifcAPI, modelID)` — free IFC model memory
59
+ - `getProjectInfo(ifcAPI, modelID)` — extract project metadata
60
+
61
+ ### Rendering Layer (`src/ifcModel.ts`)
62
+
63
+ All Babylon.js scene construction. **Zero web-ifc dependencies.**
64
+
65
+ - `buildIfcModel(model, scene, options?)` — create meshes, materials, merge, center
66
+ - `disposeIfcModel(scene)` — dispose all IFC meshes and materials
67
+ - `getModelBounds(meshes)` — calculate bounding box
68
+ - `centerModelAtOrigin(meshes, rootNode?)` — center model at origin
69
+
70
+ ### Application Layer
71
+
72
+ - `src/main.ts` — uses low-level two-step API (ifcInit + ifcModel)
73
+
74
+ ## Usage
75
+
76
+ ### Two-Step Loading API
77
+
78
+ For more control, use the two-step API directly:
79
+
80
+ ```typescript
81
+ // Step 1: Initialize web-ifc
82
+ const ifcAPI = await initializeWebIFC("./");
83
+
84
+ // Step 2: Load raw IFC data (web-ifc only)
85
+ const model = await loadIfcModel(ifcAPI, "/test.ifc", {
86
+ coordinateToOrigin: true,
87
+ verbose: true,
88
+ });
89
+
90
+ // Step 3: Extract metadata (optional)
91
+ const projectInfo = getProjectInfo(ifcAPI, model.modelID);
92
+
93
+ // Step 4: Build Babylon.js scene (Babylon only)
94
+ const { meshes, rootNode, stats } = buildIfcModel(model, scene, {
95
+ autoCenter: true,
96
+ mergeMeshes: true,
97
+ doubleSided: true,
98
+ verbose: true,
99
+ });
100
+ ```
101
+
102
+ ### Load from URL or File
103
+
104
+ ```typescript
105
+ // From URL
106
+ const model = await loadIfcModel(ifcAPI, "/path/to/file.ifc");
107
+
108
+ // From File object (drag-and-drop)
109
+ const model = await loadIfcModel(ifcAPI, fileObject);
110
+ ```
111
+
112
+ ### Cleanup before loading a new model
113
+
114
+ ```typescript
115
+ // Dispose Babylon.js scene (meshes, materials, root node)
116
+ disposeIfcModel(scene);
117
+
118
+ // Close IFC model and free WASM memory
119
+ closeIfcModel(ifcAPI, modelID);
120
+ ```
121
+
122
+ ## API Reference
123
+
124
+ See [API.md](./API.md) for complete API documentation with all types, parameters, and examples.
125
+
126
+ ## NPM Package
127
+
128
+ The package is published as `babylon-ifc-loader` and exports:
129
+
130
+ ```typescript
131
+ // Low-level IFC Data Layer (web-ifc only)
132
+ import { initializeWebIFC, loadIfcModel, closeIfcModel, getProjectInfo } from "babylon-ifc-loader";
133
+
134
+ // Rendering Layer (Babylon.js only)
135
+ import { buildIfcModel, disposeIfcModel, getModelBounds, centerModelAtOrigin } from "babylon-ifc-loader";
136
+ ```
137
+
138
+ ### Testing NPM Package Locally
139
+
140
+ To test the npm package locally before publishing:
141
+
142
+ ```bash
143
+ # 1. Build the npm package
144
+ npm run build:npm
145
+
146
+ # 2. Run Vite dev server with the test-npm entry point
147
+ npx vite . --open test-npm/index.html
148
+ ```
149
+
150
+ The `test-npm/` folder contains a test page that imports from `babylon-ifc-loader`. Since the package's `main` entry points to `dist-npm/index.js`, Vite resolves the import from the built output.
151
+
152
+ **Testing from another project:**
153
+
154
+ To test the package in a different project:
155
+
156
+ ```bash
157
+ # In ifc-babylon root
158
+ npm link
159
+
160
+ # In the other project
161
+ npm link babylon-ifc-loader
162
+ ```
163
+
164
+ ## Testing
165
+
166
+ The project uses [Vitest](https://vitest.dev/) for unit testing with the following setup:
167
+
168
+ - **Test Runner:** Vitest v4 with `jsdom` environment
169
+ - **Coverage:** `@vitest/coverage-v8` for code coverage reports
170
+ - **Location:** Test files are in `src/__tests__/`
171
+
172
+ ### Test Files
173
+
174
+ | File | Description |
175
+ | -------------------------- | ------------------------------------- |
176
+ | `initializeWebIFC.test.ts` | Tests for web-ifc initialization |
177
+ | `loadIfcModel.test.ts` | Tests for IFC model loading |
178
+ | `closeIfcModel.test.ts` | Tests for model cleanup |
179
+ | `getProjectInfo.test.ts` | Tests for project metadata extraction |
180
+ | `buildIfcModel.test.ts` | Tests for Babylon.js scene building |
181
+ | `zOffset.test.ts` | Tests for z-offset material handling |
182
+
183
+ ### Running Tests
184
+
185
+ ```bash
186
+ # Run tests in watch mode
187
+ npm test
188
+
189
+ # Run tests once
190
+ npm test -- --run
191
+
192
+ # Run tests with coverage report
193
+ npm run test:coverage
194
+ ```
195
+
196
+ ### Writing Tests
197
+
198
+ Tests follow the standard Vitest pattern with mocked dependencies:
199
+
200
+ ```typescript
201
+ import { describe, it, expect, beforeEach, vi } from "vitest";
202
+
203
+ describe("myFunction", () => {
204
+ beforeEach(() => {
205
+ vi.clearAllMocks();
206
+ });
207
+
208
+ it("should do something", async () => {
209
+ const result = await myFunction();
210
+ expect(result).toBe(expected);
211
+ });
212
+ });
213
+ ```
214
+
215
+ ## Project Structure
216
+
217
+ ```
218
+ src/
219
+ ├── main.ts — app entry (two-step API: ifcInit + ifcModel)
220
+ ├── ifcInit.ts — IFC data layer (web-ifc only)
221
+ ├── ifcModel.ts — rendering layer (Babylon.js only)
222
+ ├── style.css — basic styling
223
+ └── __tests__/ — unit tests
224
+
225
+ public/
226
+ ├── test.ifc — sample IFC file loaded at startup
227
+ ├── example.ifc — additional sample
228
+ └── bplogo.svg — asset
229
+
230
+ Root
231
+ ├── index.html — HTML entry
232
+ ├── vite.config.ts — copies web-ifc.wasm to dist/, sets WASM handling
233
+ ├── tsconfig.json — TypeScript config
234
+ └── package.json — scripts and deps
235
+ ```
236
+
237
+ ## Picking and Highlighting
238
+
239
+ - Left-click a mesh to log full element data via `ifcAPI.GetLine(modelID, expressID, true)` and type name via `GetNameFromTypeCode`
240
+ - Highlight uses `renderOverlay` with teal color and alpha=0.3
241
+ - Upper text banner shows type, name, and ExpressID; clicking empty space clears it
242
+
243
+ ## Materials, Merging, and Performance
244
+
245
+ - Materials are `StandardMaterial` per unique RGBA color, configurable `backFaceCulling`, incremental `zOffset` to mitigate z-fighting
246
+ - Meshes are merged per (expressID + color) when safe; safety check prevents merging across different storeys using spatial relations
247
+ - Metadata (`expressID`, `modelID`) preserved on merged meshes
248
+ - Stats for counts, triangles, materials, and build time are computed
249
+
250
+ ### Custom Merging Strategy
251
+
252
+ When `mergeMeshes = false`, each geometry part remains as a separate mesh with full metadata. This lets you implement your own merging strategy based on:
253
+
254
+ - Mesh metadata (`expressID`, `modelID`) for element identification
255
+ - IFC queries via `ifcAPI.GetLine()` for property-based grouping
256
+ - Spatial relationships for storey/zone-based organization
257
+ - Material or color-based batching
258
+
259
+ Example:
260
+
261
+ ```typescript
262
+ const { meshes } = buildIfcModel(model, scene, { mergeMeshes: false });
263
+
264
+ // Custom grouping by IFC type
265
+ for (const mesh of meshes) {
266
+ const element = ifcAPI.GetLine(modelID, mesh.metadata.expressID, true);
267
+ const typeName = ifcAPI.GetNameFromTypeCode(element.type);
268
+ // Group or merge meshes by typeName, storey, etc.
269
+ }
270
+ ```
271
+
272
+ ## Coordinate System and Geometry
273
+
274
+ - web-ifc streams interleaved vertex data `[x,y,z,nx,ny,nz]`
275
+ - Optional normal generation when required
276
+ - Per-part transforms baked from placed geometry matrices
277
+ - Z-axis flip applied via root node scaling for IFC-to-Babylon coordinate conversion
278
+
279
+ ## Build and Deploy Notes
280
+
281
+ - The Vite config copies `node_modules/web-ifc/web-ifc.wasm` to `dist/`
282
+ - In production, `initializeWebIFC("./")` ensures the WASM is loaded from the dist root
283
+ - `optimizeDeps.exclude = ["web-ifc"]` prevents esbuild issues during dev
284
+
285
+ ## Dependencies
286
+
287
+ | Package | Version | Description |
288
+ | ----------------------- | ------- | ----------------------------------- |
289
+ | @babylonjs/core | ^8.52.0 | Core Babylon.js engine |
290
+ | @babylonjs/inspector | ^8.52.0 | Built-in debugging inspector |
291
+ | web-ifc | ^0.0.75 | IFC parsing and geometry extraction |
292
+ | vite | ^7.3.1 | Build tool and dev server |
293
+ | vite-plugin-static-copy | ^3.2.0 | Copy WASM files to dist |
294
+
295
+ ## Limitations and Future Improvements
296
+
297
+ - No spatial tree or filters yet
298
+ - No property panel UI
299
+ - No outline/edge rendering highlight option
300
+ - No UI controls for scene manipulation
301
+
302
+ ## License
303
+
304
+ Apache-2.0 - See [LICENSE](./LICENSE) for details.