@ifc-lite/wasm 1.19.1 → 2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ifc-lite/wasm
2
2
 
3
- Pre-built WebAssembly bindings for the IFClite Rust core. ~650 KB binary (~260 KB gzipped) covering STEP parsing, geometry tessellation, georeferencing, and zero-copy GPU upload.
3
+ Pre-built WebAssembly bindings for the IFClite Rust core, covering STEP parsing and geometry tessellation (including the Manifold CSG kernel).
4
4
 
5
5
  > **You probably don't need to use this package directly.** It's the WASM binary plus generated JS/TypeScript bindings that `@ifc-lite/parser`, `@ifc-lite/geometry`, and `@ifc-lite/renderer` consume internally. Reach for it when you want raw access to the Rust core without the higher-level wrappers.
6
6
 
@@ -12,7 +12,9 @@ npm install @ifc-lite/wasm
12
12
 
13
13
  ## Direct WASM use
14
14
 
15
- `IfcAPI` methods take the raw IFC text (a `string`), not a `Uint8Array`. Decode the buffer first.
15
+ The text-based parse methods (`parse`, `parseStreaming`) take the raw IFC text
16
+ (a `string`) — decode the buffer first. The geometry methods (`buildPrePassOnce`,
17
+ `processGeometryBatch`, see below) instead take the raw `Uint8Array` bytes.
16
18
 
17
19
  ```typescript
18
20
  import init, { IfcAPI } from '@ifc-lite/wasm';
@@ -27,94 +29,57 @@ const content = new TextDecoder().decode(buffer);
27
29
  const result = await api.parse(content);
28
30
  console.log(`Entities: ${result.entityCount}`);
29
31
 
30
- // Tessellated meshes — each entry has expressId, positions, indices, normals, color
31
- const meshes = api.parseMeshes(content);
32
- console.log(`${meshes.length} meshes`);
33
- for (let i = 0; i < meshes.length; i++) {
34
- const mesh = meshes.get(i);
35
- console.log(mesh.ifcType, mesh.expressId, mesh.vertexCount, 'vertices');
36
- }
37
-
38
- meshes.free(); // free the Rust-side mesh buffer
39
32
  api.free(); // free the API instance
40
33
  ```
41
34
 
42
- ## Streaming mesh batches
35
+ ## Meshes (pre-pass + job batches)
43
36
 
44
- For progressive rendering, stream meshes in batches and yield to the browser between them:
37
+ Geometry runs as a single pre-pass (one scan that produces a flat job list
38
+ plus unit scale, RTC offset, void/style indices) followed by
39
+ `processGeometryBatch` calls over slices of that job list. Pass the IFC
40
+ **bytes** (`Uint8Array`) to these methods:
45
41
 
46
42
  ```typescript
47
43
  import init, { IfcAPI } from '@ifc-lite/wasm';
48
44
 
49
45
  await init();
50
46
  const api = new IfcAPI();
47
+ const bytes = new Uint8Array(await fetch('model.ifc').then(r => r.arrayBuffer()));
48
+
49
+ const pre = api.buildPrePassOnce(bytes);
50
+ // Large-coordinate models: pre.needsShift / pre.rtcOffset give the RTC origin.
51
+ for (let start = 0; start < pre.totalJobs; start += 100) {
52
+ const end = Math.min(start + 100, pre.totalJobs);
53
+ const jobs = pre.jobs.slice(start * 3, end * 3);
54
+ const collection = api.processGeometryBatch(
55
+ bytes, jobs, pre.unitScale,
56
+ pre.rtcOffset?.[0] ?? 0, pre.rtcOffset?.[1] ?? 0, pre.rtcOffset?.[2] ?? 0,
57
+ pre.needsShift,
58
+ pre.voidKeys, pre.voidCounts, pre.voidValues,
59
+ pre.styleIds, pre.styleColors,
60
+ );
61
+ for (let i = 0; i < collection.length; i++) {
62
+ const mesh = collection.get(i);
63
+ scene.add(toThreeMesh(mesh)); // mesh.expressId, .ifcType, .positions, .normals, .indices, .color
64
+ mesh.free();
65
+ }
66
+ collection.free();
67
+ }
51
68
 
52
- await api.parseMeshesAsync(content, {
53
- batchSize: 100,
54
- onRtcOffset: ({ x, y, z, hasRtc }) => {
55
- if (hasRtc) viewer.setWorldOffset(x, y, z);
56
- },
57
- onBatch: (meshes, progress) => {
58
- for (const mesh of meshes) scene.add(toThreeMesh(mesh));
59
- console.log(`${progress.percent}%`);
60
- },
61
- onComplete: ({ totalMeshes }) => console.log(`Done — ${totalMeshes} meshes`),
62
- });
63
- ```
64
-
65
- ## Zero-copy GPU upload
66
-
67
- `parseToGpuGeometry` returns interleaved (position + normal) vertex data with pointers into WASM linear memory, ready for direct `GPUBuffer` upload:
68
-
69
- ```typescript
70
- import init, { IfcAPI } from '@ifc-lite/wasm';
71
-
72
- await init();
73
- const api = new IfcAPI();
74
- const gpuGeom = api.parseToGpuGeometry(content);
75
- const memory = api.getMemory();
76
-
77
- // Direct views into WASM memory — no intermediate copy
78
- const vertexView = new Float32Array(memory.buffer, gpuGeom.vertexDataPtr, gpuGeom.vertexDataLen);
79
- const indexView = new Uint32Array(memory.buffer, gpuGeom.indicesPtr, gpuGeom.indicesLen);
80
-
81
- device.queue.writeBuffer(gpuVertexBuffer, 0, vertexView);
82
- device.queue.writeBuffer(gpuIndexBuffer, 0, indexView);
83
-
84
- // IMPORTANT: views are only valid until the next WASM allocation. Free immediately after upload.
85
- gpuGeom.free();
69
+ api.clearPrePassCache();
70
+ api.free(); // release the API instance when done
86
71
  ```
87
72
 
88
- For deduplicated geometry (one mesh per shape, per-instance transforms), use `parseToGpuInstancedGeometry(content)` and iterate `GpuInstancedGeometryCollection`.
89
-
90
- ## Georeferencing
91
-
92
- ```typescript
93
- import init, { IfcAPI } from '@ifc-lite/wasm';
94
-
95
- await init();
96
- const api = new IfcAPI();
97
- const georef = api.getGeoReference(content);
98
-
99
- if (georef) {
100
- console.log(`CRS: ${georef.crsName}`);
101
- const [e, n, h] = georef.localToMap(10, 20, 5);
102
- console.log(`Local (10,20,5) → Map (${e}, ${n}, ${h})`);
103
- georef.free();
104
- }
105
- ```
73
+ > Most consumers should use [`@ifc-lite/geometry`](../geometry/README.md)'s
74
+ > `GeometryProcessor` instead — it wraps this pre-pass/job-batch flow with a
75
+ > Web-Worker pool, RTC coordinate handling, and progressive streaming.
106
76
 
107
77
  ## Exports
108
78
 
109
79
  | Class | Purpose |
110
80
  |---|---|
111
- | `IfcAPI` | Top-level parser entry point — `parse`, `parseMeshes`, `parseMeshesAsync`, `parseToGpuGeometry`, `parseZeroCopy`, `getGeoReference`, `extractProfiles`, `parseSymbolicRepresentations`, |
81
+ | `IfcAPI` | Top-level entry point — `parse`, `parseStreaming`, `buildPrePassOnce` / `buildPrePassFast` / `buildPrePassStreaming`, `processGeometryBatch`, `scanEntitiesFast` / `scanEntitiesFastBytes` / `scanGeometryEntitiesFast`, `extractProfiles`, `parseSymbolicRepresentations` |
112
82
  | `MeshCollection`, `MeshDataJs` | Tessellated geometry output |
113
- | `MeshCollectionWithRtc`, `RtcOffsetJs` | Mesh collection with relative-to-centre offset for large-coordinate models |
114
- | `InstancedMeshCollection`, `InstancedGeometry`, `InstanceData` | Instanced geometry path (deduplicated meshes + per-instance transforms) |
115
- | `ZeroCopyMesh`, `GpuGeometry`, `GpuMeshMetadata` | Zero-copy GPU upload handles |
116
- | `GpuInstancedGeometry`, `GpuInstancedGeometryCollection`, `GpuInstancedGeometryRef` | Zero-copy instanced path |
117
- | `GeoReferenceJs` | Georeferencing transform |
118
83
  | `ProfileCollection`, `ProfileEntryJs` | Cross-section profile data (extruded-area solids) |
119
84
  | `SymbolicRepresentationCollection`, `SymbolicCircle`, `SymbolicPolyline` | 2D symbolic representations (for plan / annotation views) |
120
85
 
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "IFC-Lite Contributors"
6
6
  ],
7
7
  "description": "WebAssembly bindings for IFC-Lite",
8
- "version": "1.19.1",
8
+ "version": "2.0.0",
9
9
  "license": "MPL-2.0",
10
10
  "repository": {
11
11
  "type": "git",