@ifc-lite/wasm 2.13.4 → 3.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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "IFC-Lite Contributors"
6
6
  ],
7
7
  "description": "WebAssembly bindings for IFC-Lite",
8
- "version": "2.13.4",
8
+ "version": "3.0.0",
9
9
  "license": "MPL-2.0",
10
10
  "repository": {
11
11
  "type": "git",
package/pkg/ifc-lite.d.ts CHANGED
@@ -93,8 +93,14 @@ export class IfcAPI {
93
93
  * `true` ⇒ lit (the default), `false` ⇒ flat `KHR_materials_unlit` (the
94
94
  * historical look — #1321). Optional at the boundary so older 5-arg callers
95
95
  * keep lit-by-default behaviour.
96
+ *
97
+ * Fails CLOSED: when the visible mesh set is empty this throws an `Error`
98
+ * whose message starts with `NO_RENDER_GEOMETRY`, instead of returning a
99
+ * structurally valid but empty GLB. #1438 put that guard only in the TS
100
+ * CLI/MCP wrappers; making the boundary itself refuse means SDK/viewer/
101
+ * direct callers inherit it too (the TS guards stay as defense-in-depth).
96
102
  */
97
- exportGlb(content: string, include_metadata: boolean, hidden: Uint32Array, isolated: Uint32Array, hidden_types_csv: string, lit?: boolean | null): Uint8Array;
103
+ exportGlb(content: Uint8Array, include_metadata: boolean, hidden: Uint32Array, isolated: Uint32Array, hidden_types_csv: string, lit?: boolean | null): Uint8Array;
98
104
  /**
99
105
  * Package an already-produced **GLB** + georeference into a **KMZ** (`Uint8Array`)
100
106
  * for Google Earth: a ZIP of `doc.kml` (a `<Model>` placed at `latitude`/`longitude`/
@@ -111,7 +117,11 @@ export class IfcAPI {
111
117
  */
112
118
  exportGlbFromMeshes(positions: Float32Array, normals: Float32Array, indices: Uint32Array, vertex_counts: Uint32Array, index_counts: Uint32Array, colors: Float32Array, origins: Float64Array, express_ids: Uint32Array, include_metadata: boolean, lit?: boolean | null): Uint8Array;
113
119
  /**
114
- * Export the render geometry in `content` as a Wavefront **OBJ** string.
120
+ * Export the render geometry in `content` as Wavefront **OBJ** UTF-8 bytes.
121
+ *
122
+ * Returned as UTF-8 bytes (`Uint8Array`) so output is not capped by the
123
+ * V8 max-string ceiling (~512 MB); decode with `TextDecoder` when a string
124
+ * is genuinely needed.
115
125
  *
116
126
  * `hidden` / `isolated` are express-id filters mirroring the viewer's visibility
117
127
  * state (empty `isolated` ⇒ all visible). Instanced type-library shapes are skipped.
@@ -120,12 +130,7 @@ export class IfcAPI {
120
130
  * const obj = api.exportObj(ifcContent, true, new Uint32Array(), new Uint32Array());
121
131
  * ```
122
132
  */
123
- exportObj(content: string, include_normals: boolean, hidden: Uint32Array, isolated: Uint32Array): string;
124
- /**
125
- * Run the pre-pass ONCE and return serialized results for worker distribution.
126
- * Takes raw bytes (&[u8]) to avoid TextDecoder overhead.
127
- */
128
- buildPrePassOnce(data: Uint8Array): any;
133
+ exportObj(content: Uint8Array, include_normals: boolean, hidden: Uint32Array, isolated: Uint32Array): Uint8Array;
129
134
  /**
130
135
  * Process geometry for a subset of pre-scanned entities → flat
131
136
  * MeshCollection. Takes raw bytes + pre-pass data from buildPrePassOnce.
@@ -134,32 +139,6 @@ export class IfcAPI {
134
139
  * there). Output is byte-for-byte what the pre-refactor method produced.
135
140
  */
136
141
  processGeometryBatch(data: Uint8Array, jobs_flat: Uint32Array, unit_scale: number, rtc_x: number, rtc_y: number, rtc_z: number, needs_shift: boolean, void_keys: Uint32Array, void_counts: Uint32Array, void_values: Uint32Array, style_ids: Uint32Array, style_colors: Uint8Array, plane_angle_to_radians?: number | null, material_element_ids?: Uint32Array | null, material_color_counts?: Uint32Array | null, material_colors_rgba?: Uint8Array | null): MeshCollection;
137
- /**
138
- * Streaming pre-pass: emits geometry jobs in chunks via a JS callback
139
- * instead of waiting for the full file scan to complete.
140
- *
141
- * Single linear walk over the file:
142
- * 1. Builds the entity index incrementally from the same scan that
143
- * collects geometry jobs (a separate index scan would double
144
- * wall-clock).
145
- * 2. As soon as `IFCPROJECT` has been seen, the unit scale and the
146
- * first ~50 geometry jobs have been collected, resolves
147
- * `unitScale` + `rtcOffset` and emits a `meta` callback so the
148
- * JS host can spin up geometry process workers.
149
- * 3. Emits `jobs` callbacks every `chunk_size` jobs (or fewer if
150
- * the meta phase already buffered some).
151
- * 4. Emits `complete` with the total job count at end of scan.
152
- *
153
- * On a 986 MB / 14 M-entity file this drops time-to-first-geometry
154
- * from ~17 s (full pre-pass + worker spawn + first batch) to ~3 s
155
- * (first 100 K bytes scanned + meta + first chunk).
156
- *
157
- * The callback receives a single `JsValue` argument shaped as one of:
158
- * `{ type: "meta", unitScale, rtcOffset: [x,y,z], needsShift, buildingRotation? }`
159
- * `{ type: "jobs", jobs: Uint32Array }` // [id, start, end] triples
160
- * `{ type: "complete", totalJobs }`
161
- */
162
- buildPrePassStreaming(data: Uint8Array, on_event: Function, chunk_size: number, disabled_type_names: string[] | null | undefined, skip_type_geometry: boolean): any;
163
142
  /**
164
143
  * Like [`IfcAPI::process_geometry_batch`] but collates the batch's meshes
165
144
  * into a GPU-instancing shard (IFNS wire format) instead of a flat
@@ -190,6 +169,37 @@ export class IfcAPI {
190
169
  * opaque bulk. See the instanced-only follow-ups.
191
170
  */
192
171
  processGeometryBatchPartitioned(data: Uint8Array, jobs_flat: Uint32Array, unit_scale: number, rtc_x: number, rtc_y: number, rtc_z: number, needs_shift: boolean, void_keys: Uint32Array, void_counts: Uint32Array, void_values: Uint32Array, style_ids: Uint32Array, style_colors: Uint8Array, plane_angle_to_radians?: number | null, material_element_ids?: Uint32Array | null, material_color_counts?: Uint32Array | null, material_colors_rgba?: Uint8Array | null): PartitionedBatch;
172
+ /**
173
+ * Run the pre-pass ONCE and return serialized results for worker distribution.
174
+ * Takes raw bytes (&[u8]) to avoid TextDecoder overhead.
175
+ */
176
+ buildPrePassOnce(data: Uint8Array): any;
177
+ /**
178
+ * Streaming pre-pass: emits geometry jobs in chunks via a JS callback
179
+ * instead of waiting for the full file scan to complete.
180
+ *
181
+ * Single linear walk over the file:
182
+ * 1. Builds the entity index incrementally from the same scan that
183
+ * collects geometry jobs (a separate index scan would double
184
+ * wall-clock).
185
+ * 2. As soon as `IFCPROJECT` has been seen, the unit scale and the
186
+ * first ~50 geometry jobs have been collected, resolves
187
+ * `unitScale` + `rtcOffset` and emits a `meta` callback so the
188
+ * JS host can spin up geometry process workers.
189
+ * 3. Emits `jobs` callbacks every `chunk_size` jobs (or fewer if
190
+ * the meta phase already buffered some).
191
+ * 4. Emits `complete` with the total job count at end of scan.
192
+ *
193
+ * On a 986 MB / 14 M-entity file this drops time-to-first-geometry
194
+ * from ~17 s (full pre-pass + worker spawn + first batch) to ~3 s
195
+ * (first 100 K bytes scanned + meta + first chunk).
196
+ *
197
+ * The callback receives a single `JsValue` argument shaped as one of:
198
+ * `{ type: "meta", unitScale, rtcOffset: [x,y,z], needsShift, buildingRotation? }`
199
+ * `{ type: "jobs", jobs: Uint32Array }` // [id, start, end] triples
200
+ * `{ type: "complete", totalJobs }`
201
+ */
202
+ buildPrePassStreaming(data: Uint8Array, on_event: Function, chunk_size: number, disabled_type_names: string[] | null | undefined, skip_type_geometry: boolean): any;
193
203
  /**
194
204
  * Parse the file and return structured per-axis data (tag + endpoints) in
195
205
  * the renderer's Y-up world space (RTC-subtracted, metres). Use this when
@@ -211,24 +221,28 @@ export class IfcAPI {
211
221
  * `"spatial"`}. `delimiter` defaults to `,` when empty; `include_properties` adds
212
222
  * flattened `Pset_Prop` columns to the entities view.
213
223
  */
214
- exportCsv(content: string, mode: string, delimiter: string, include_properties: boolean): string;
224
+ exportCsv(content: Uint8Array, mode: string, delimiter: string, include_properties: boolean): Uint8Array;
215
225
  /**
216
226
  * Export **IFC5 / IFCX** (the USD-style node graph). `only_known_properties` keeps
217
227
  * only properties with an official IFC5 schema.
218
228
  */
219
- exportIfcx(content: string, only_known_properties: boolean, pretty: boolean): string;
229
+ exportIfcx(content: Uint8Array, only_known_properties: boolean, pretty: boolean): Uint8Array;
220
230
  /**
221
231
  * Export structured **JSON** (array of entity objects with typed property values).
222
232
  */
223
- exportJson(content: string, pretty: boolean, include_properties: boolean, include_quantities: boolean): string;
233
+ exportJson(content: Uint8Array, pretty: boolean, include_properties: boolean, include_quantities: boolean): Uint8Array;
224
234
  /**
225
235
  * Export **JSON-LD** (`@graph` of `ifc:` nodes). Empty `context` ⇒ buildingSMART
226
236
  * IFC4 OWL default. `included` is an express-id isolation filter mirroring the
227
237
  * OBJ/glTF/STEP exporters (empty ⇒ all entities).
228
238
  */
229
- exportJsonld(content: string, context: string, include_properties: boolean, include_quantities: boolean, pretty: boolean, included: Uint32Array): string;
239
+ exportJsonld(content: Uint8Array, context: string, include_properties: boolean, include_quantities: boolean, pretty: boolean, included: Uint32Array): Uint8Array;
230
240
  /**
231
- * Re-serialize the model in `content` to a STEP/IFC string.
241
+ * Re-serialize the model in `content` to STEP/IFC UTF-8 bytes.
242
+ *
243
+ * Returned as UTF-8 bytes (`Uint8Array`) so output is not capped by the
244
+ * V8 max-string ceiling (~512 MB); decode with `TextDecoder` when a string
245
+ * is genuinely needed.
232
246
  *
233
247
  * `schema` is the FILE_SCHEMA label to write (empty ⇒ preserve the source schema).
234
248
  * `included` is an express-id allowlist (empty ⇒ whole model); when set, the forward
@@ -236,15 +250,20 @@ export class IfcAPI {
236
250
  * `mutations_json` carries `MutablePropertyView` edits (attribute updates +
237
251
  * property-set synthesis); empty ⇒ none. See `export_step_json` for the shape.
238
252
  */
239
- exportStep(content: string, schema: string, included: Uint32Array, mutations_json: string): string;
253
+ exportStep(content: Uint8Array, schema: string, included: Uint32Array, mutations_json: string): Uint8Array;
240
254
  /**
241
- * Merge several IFC models into one STEP/IFC string. `concatenated` is every model's
255
+ * Merge several IFC models into one STEP/IFC UTF-8 byte buffer (`Uint8Array`).
256
+ * `concatenated` is every model's
242
257
  * bytes laid end-to-end; `lengths[i]` is the byte length of model `i`. The first model
243
258
  * keeps its ids; later models are id-offset and their project unified to the first.
244
259
  */
245
- exportMerged(concatenated: Uint8Array, lengths: Uint32Array, schema: string): string;
260
+ exportMerged(concatenated: Uint8Array, lengths: Uint32Array, schema: string): Uint8Array;
246
261
  /**
247
- * Export the `IfcSpace` volumes in `content` as a Honeybee **HBJSON** string.
262
+ * Export the `IfcSpace` volumes in `content` as Honeybee **HBJSON** UTF-8 bytes.
263
+ *
264
+ * Returned as UTF-8 bytes (`Uint8Array`) so output is not capped by the
265
+ * V8 max-string ceiling (~512 MB); decode with `TextDecoder` when a string
266
+ * is genuinely needed.
248
267
  *
249
268
  * Rooms are built analytically from extruded-area profiles (watertight by construction);
250
269
  * faces are typed Floor / RoofCeiling / Wall with outward normals. The result loads via
@@ -255,7 +274,7 @@ export class IfcAPI {
255
274
  * const hbjson = api.exportHbjson(ifcContent, "my_model");
256
275
  * ```
257
276
  */
258
- exportHbjson(content: string, name: string): string;
277
+ exportHbjson(content: Uint8Array, name: string): Uint8Array;
259
278
  /**
260
279
  * Parse the file and return every `IfcAlignment` directrix as a flat
261
280
  * `Float32Array` of 3D line-list vertices `[x0,y0,z0, x1,y1,z1, …]` in
@@ -290,6 +309,15 @@ export class IfcAPI {
290
309
  * ```
291
310
  */
292
311
  extractProfiles(content: string, model_index: number): ProfileCollection;
312
+ /**
313
+ * Structured pipeline diagnostics accumulated across every
314
+ * `processGeometryBatch*` call since the last load reset
315
+ * (`clearPrePassCache` / `setEntityIndex`), as a JS object with a
316
+ * `schemaVersion` field — or `undefined` when no batch has run yet.
317
+ * Includes per-batch summed geometry wall time, mesh/triangle counts,
318
+ * the degenerate-backstop drop count, and the CSG failure aggregates.
319
+ */
320
+ getPipelineDiagnostics(): any;
293
321
  /**
294
322
  * Get WASM memory for zero-copy access
295
323
  */
@@ -331,6 +359,17 @@ export class IfcAPI {
331
359
  * Default is `false`. Pass `true` before calling `processGeometryBatch`.
332
360
  */
333
361
  setMergeLayers(enabled: boolean): void;
362
+ /**
363
+ * Toggle the tier-independent small-cut skip (#1286). When `true`,
364
+ * `processGeometryBatch` drops `IfcBooleanResult` differences whose cutter is
365
+ * tiny relative to its host (steel copes/notches) while keeping the
366
+ * tessellation tier — so curves stay full-density. The viewer enables this for
367
+ * the on-screen load; exports/drawings leave it off so their geometry keeps
368
+ * every cut. Default off ⇒ byte-identical to before.
369
+ *
370
+ * Set BEFORE processing — meshes already emitted are not regenerated.
371
+ */
372
+ setSkipSmallCuts(on: boolean): void;
334
373
  /**
335
374
  * Clear the cached entity index (call between loads when reusing
336
375
  * the same `IfcAPI` instance — e.g. the parser worker keeps one
@@ -346,12 +385,13 @@ export class IfcAPI {
346
385
  * Enable or disable the PARAMETRIC rectangular-opening fast path (the
347
386
  * placement-frame, ground-truth-exact analytic cut) for `processGeometryBatch`.
348
387
  *
349
- * DEFAULT OFF. This is the wasm-side toggle that lets native and wasm flip the
350
- * flag in LOCKSTEP the byte-identical native==wasm contract requires both
351
- * targets take the same path, and wasm has no env to read `IFC_LITE_RECT_PARAM`.
388
+ * DEFAULT ON (corpus-validated; native defaults ON too, and wasm has no env to
389
+ * read `IFC_LITE_RECT_PARAM`, so both targets default in LOCKSTEP -- the
390
+ * byte-identical native==wasm contract requires both take the same path). This
391
+ * toggle is the wasm-side escape hatch mirroring `IFC_LITE_RECT_PARAM=0`.
352
392
  * The path subtracts rectangular openings as exact parametric boxes in the host's
353
393
  * own placement frame (rotated walls included), deferring any non-clean case to
354
- * the exact kernel. Pass `true` before `processGeometryBatch`.
394
+ * the exact kernel. Pass `false` before `processGeometryBatch` to opt out.
355
395
  */
356
396
  setRectParamFastPath(enabled: boolean): void;
357
397
  /**
@@ -404,6 +444,14 @@ export class IfcAPI {
404
444
  * Much faster than scanning all entities (3x speedup for large files)
405
445
  */
406
446
  scanGeometryEntitiesFast(content: string): any;
447
+ /**
448
+ * Run geometry extraction on `content` and return its typed CSG / opening
449
+ * diagnostics (the `GeometryDiagnostics` contract) as a JS object, or
450
+ * `undefined` when nothing diagnostic-worthy happened (no openings, no
451
+ * failures). Takes the raw IFC bytes (`Uint8Array`) so there is no input-size
452
+ * cap. The produced meshes are dropped; only the diagnostics are returned.
453
+ */
454
+ diagnoseGeometry(content: Uint8Array): any;
407
455
  /**
408
456
  * Parse IFC file and extract symbolic representations (Plan,
409
457
  * Annotation, FootPrint, Axis). These are 2D curves used for
@@ -453,6 +501,13 @@ export class MeshCollection {
453
501
  * it twice for the same index yields the second call an empty mesh.
454
502
  */
455
503
  takeMesh(index: number): MeshDataJs | undefined;
504
+ /**
505
+ * The batch's typed CSG / opening diagnostics as a JS object (the
506
+ * `GeometryDiagnostics` contract), or `undefined` if none were recorded. The
507
+ * worker merges these across batches. One serialized value keeps the rich
508
+ * nested shape as a single FFI crossing instead of dozens of getters.
509
+ */
510
+ readonly diagnostics: any;
456
511
  /**
457
512
  * Get RTC offset X (for converting local coords back to world coords)
458
513
  * Add this to local X coordinates to get world X coordinates
@@ -514,6 +569,12 @@ export class MeshDataJs {
514
569
  * True when this mesh carries a surface texture (#961).
515
570
  */
516
571
  readonly hasTexture: boolean;
572
+ /**
573
+ * Local (pre-placement, object-space) AABB (issue #1474), WebGL Y-up,
574
+ * `[minX,minY,minZ,maxX,maxY,maxZ]`. `undefined` when not captured
575
+ * (wasm-bindgen maps `Option::None` to `undefined`, not `null`).
576
+ */
577
+ readonly localBounds: Float32Array | undefined;
517
578
  /**
518
579
  * Decoded RGBA8 texture bytes (`width*height*4`). Empty when untextured.
519
580
  */
@@ -535,6 +596,12 @@ export class MeshDataJs {
535
596
  * type geometry (hidden in Model mode, shown in Types mode).
536
597
  */
537
598
  readonly geometryClass: number;
599
+ /**
600
+ * The resolved `IfcLocalPlacement` chain for this mesh (issue #1474),
601
+ * row-major 4×4, WebGL Y-up. `undefined` when not captured (see
602
+ * `local_bounds` above).
603
+ */
604
+ readonly localToWorld: Float64Array | undefined;
538
605
  readonly textureHeight: number;
539
606
  /**
540
607
  * Get triangle count
@@ -1070,6 +1137,7 @@ export interface InitOutput {
1070
1137
  readonly ifcapi_buildPrePassOnce: (a: number, b: number, c: number) => number;
1071
1138
  readonly ifcapi_buildPrePassStreaming: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
1072
1139
  readonly ifcapi_clearPrePassCache: (a: number) => void;
1140
+ readonly ifcapi_diagnoseGeometry: (a: number, b: number, c: number) => number;
1073
1141
  readonly ifcapi_exportCsv: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
1074
1142
  readonly ifcapi_exportGlb: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number) => void;
1075
1143
  readonly ifcapi_exportGlbFromMeshes: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number, l: number, m: number, n: number, o: number, p: number, q: number, r: number, s: number, t: number) => void;
@@ -1083,6 +1151,7 @@ export interface InitOutput {
1083
1151
  readonly ifcapi_exportStep: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void;
1084
1152
  readonly ifcapi_extractProfiles: (a: number, b: number, c: number, d: number) => number;
1085
1153
  readonly ifcapi_getMemory: (a: number) => number;
1154
+ readonly ifcapi_getPipelineDiagnostics: (a: number) => number;
1086
1155
  readonly ifcapi_is_ready: (a: number) => number;
1087
1156
  readonly ifcapi_new: () => number;
1088
1157
  readonly ifcapi_parseAlignmentLines: (a: number, b: number, c: number) => number;
@@ -1099,10 +1168,12 @@ export interface InitOutput {
1099
1168
  readonly ifcapi_setEntityIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
1100
1169
  readonly ifcapi_setMergeLayers: (a: number, b: number) => void;
1101
1170
  readonly ifcapi_setRectParamFastPath: (a: number, b: number) => void;
1171
+ readonly ifcapi_setSkipSmallCuts: (a: number, b: number) => void;
1102
1172
  readonly ifcapi_setTessellationQuality: (a: number, b: number, c: number, d: number) => void;
1103
1173
  readonly ifcapi_version: (a: number, b: number) => void;
1104
1174
  readonly meshOutline2d: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
1105
1175
  readonly meshcollection_buildingRotation: (a: number, b: number) => void;
1176
+ readonly meshcollection_diagnostics: (a: number) => number;
1106
1177
  readonly meshcollection_geometryHashCount: (a: number) => number;
1107
1178
  readonly meshcollection_geometryHashIds: (a: number) => number;
1108
1179
  readonly meshcollection_geometryHashValues: (a: number) => number;
@@ -1121,6 +1192,8 @@ export interface InitOutput {
1121
1192
  readonly meshdatajs_hasTexture: (a: number) => number;
1122
1193
  readonly meshdatajs_ifcType: (a: number, b: number) => void;
1123
1194
  readonly meshdatajs_indices: (a: number) => number;
1195
+ readonly meshdatajs_localBounds: (a: number, b: number) => void;
1196
+ readonly meshdatajs_localToWorld: (a: number, b: number) => void;
1124
1197
  readonly meshdatajs_normals: (a: number) => number;
1125
1198
  readonly meshdatajs_origin: (a: number) => number;
1126
1199
  readonly meshdatajs_positions: (a: number) => number;
@@ -1142,6 +1215,7 @@ export interface InitOutput {
1142
1215
  readonly partitionedbatch_takeShard: (a: number, b: number) => void;
1143
1216
  readonly profilecollection_get: (a: number, b: number) => number;
1144
1217
  readonly profilecollection_length: (a: number) => number;
1218
+ readonly profileentryjs_expressId: (a: number) => number;
1145
1219
  readonly profileentryjs_extrusionDepth: (a: number) => number;
1146
1220
  readonly profileentryjs_extrusionDir: (a: number) => number;
1147
1221
  readonly profileentryjs_holeCounts: (a: number) => number;
@@ -1224,7 +1298,6 @@ export interface InitOutput {
1224
1298
  readonly init: () => void;
1225
1299
  readonly symbolicpolyline_pointCount: (a: number) => number;
1226
1300
  readonly get_memory: () => number;
1227
- readonly profileentryjs_expressId: (a: number) => number;
1228
1301
  readonly symbolicfillarea_expressId: (a: number) => number;
1229
1302
  readonly symbolicpolyline_worldY: (a: number) => number;
1230
1303
  readonly symbolictext_colorB: (a: number) => number;
package/pkg/ifc-lite.js CHANGED
@@ -639,7 +639,13 @@ export class IfcAPI {
639
639
  * `true` ⇒ lit (the default), `false` ⇒ flat `KHR_materials_unlit` (the
640
640
  * historical look — #1321). Optional at the boundary so older 5-arg callers
641
641
  * keep lit-by-default behaviour.
642
- * @param {string} content
642
+ *
643
+ * Fails CLOSED: when the visible mesh set is empty this throws an `Error`
644
+ * whose message starts with `NO_RENDER_GEOMETRY`, instead of returning a
645
+ * structurally valid but empty GLB. #1438 put that guard only in the TS
646
+ * CLI/MCP wrappers; making the boundary itself refuse means SDK/viewer/
647
+ * direct callers inherit it too (the TS guards stay as defense-in-depth).
648
+ * @param {Uint8Array} content
643
649
  * @param {boolean} include_metadata
644
650
  * @param {Uint32Array} hidden
645
651
  * @param {Uint32Array} isolated
@@ -650,7 +656,7 @@ export class IfcAPI {
650
656
  exportGlb(content, include_metadata, hidden, isolated, hidden_types_csv, lit) {
651
657
  try {
652
658
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
653
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
659
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
654
660
  const len0 = WASM_VECTOR_LEN;
655
661
  const ptr1 = passArray32ToWasm0(hidden, wasm.__wbindgen_export);
656
662
  const len1 = WASM_VECTOR_LEN;
@@ -661,6 +667,11 @@ export class IfcAPI {
661
667
  wasm.ifcapi_exportGlb(retptr, this.__wbg_ptr, ptr0, len0, include_metadata, ptr1, len1, ptr2, len2, ptr3, len3, isLikeNone(lit) ? 0xFFFFFF : lit ? 1 : 0);
662
668
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
663
669
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
670
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
671
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
672
+ if (r3) {
673
+ throw takeObject(r2);
674
+ }
664
675
  var v5 = getArrayU8FromWasm0(r0, r1).slice();
665
676
  wasm.__wbindgen_export4(r0, r1 * 1, 1);
666
677
  return v5;
@@ -747,7 +758,11 @@ export class IfcAPI {
747
758
  }
748
759
  }
749
760
  /**
750
- * Export the render geometry in `content` as a Wavefront **OBJ** string.
761
+ * Export the render geometry in `content` as Wavefront **OBJ** UTF-8 bytes.
762
+ *
763
+ * Returned as UTF-8 bytes (`Uint8Array`) so output is not capped by the
764
+ * V8 max-string ceiling (~512 MB); decode with `TextDecoder` when a string
765
+ * is genuinely needed.
751
766
  *
752
767
  * `hidden` / `isolated` are express-id filters mirroring the viewer's visibility
753
768
  * state (empty `isolated` ⇒ all visible). Instanced type-library shapes are skipped.
@@ -755,18 +770,16 @@ export class IfcAPI {
755
770
  * ```javascript
756
771
  * const obj = api.exportObj(ifcContent, true, new Uint32Array(), new Uint32Array());
757
772
  * ```
758
- * @param {string} content
773
+ * @param {Uint8Array} content
759
774
  * @param {boolean} include_normals
760
775
  * @param {Uint32Array} hidden
761
776
  * @param {Uint32Array} isolated
762
- * @returns {string}
777
+ * @returns {Uint8Array}
763
778
  */
764
779
  exportObj(content, include_normals, hidden, isolated) {
765
- let deferred4_0;
766
- let deferred4_1;
767
780
  try {
768
781
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
769
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
782
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
770
783
  const len0 = WASM_VECTOR_LEN;
771
784
  const ptr1 = passArray32ToWasm0(hidden, wasm.__wbindgen_export);
772
785
  const len1 = WASM_VECTOR_LEN;
@@ -775,26 +788,13 @@ export class IfcAPI {
775
788
  wasm.ifcapi_exportObj(retptr, this.__wbg_ptr, ptr0, len0, include_normals, ptr1, len1, ptr2, len2);
776
789
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
777
790
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
778
- deferred4_0 = r0;
779
- deferred4_1 = r1;
780
- return getStringFromWasm0(r0, r1);
791
+ var v4 = getArrayU8FromWasm0(r0, r1).slice();
792
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
793
+ return v4;
781
794
  } finally {
782
795
  wasm.__wbindgen_add_to_stack_pointer(16);
783
- wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
784
796
  }
785
797
  }
786
- /**
787
- * Run the pre-pass ONCE and return serialized results for worker distribution.
788
- * Takes raw bytes (&[u8]) to avoid TextDecoder overhead.
789
- * @param {Uint8Array} data
790
- * @returns {any}
791
- */
792
- buildPrePassOnce(data) {
793
- const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
794
- const len0 = WASM_VECTOR_LEN;
795
- const ret = wasm.ifcapi_buildPrePassOnce(this.__wbg_ptr, ptr0, len0);
796
- return takeObject(ret);
797
- }
798
798
  /**
799
799
  * Process geometry for a subset of pre-scanned entities → flat
800
800
  * MeshCollection. Takes raw bytes + pre-pass data from buildPrePassOnce.
@@ -843,57 +843,6 @@ export class IfcAPI {
843
843
  const ret = wasm.ifcapi_processGeometryBatch(this.__wbg_ptr, ptr0, len0, ptr1, len1, unit_scale, rtc_x, rtc_y, rtc_z, needs_shift, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, !isLikeNone(plane_angle_to_radians), isLikeNone(plane_angle_to_radians) ? 0 : plane_angle_to_radians, ptr7, len7, ptr8, len8, ptr9, len9);
844
844
  return MeshCollection.__wrap(ret);
845
845
  }
846
- /**
847
- * Streaming pre-pass: emits geometry jobs in chunks via a JS callback
848
- * instead of waiting for the full file scan to complete.
849
- *
850
- * Single linear walk over the file:
851
- * 1. Builds the entity index incrementally from the same scan that
852
- * collects geometry jobs (a separate index scan would double
853
- * wall-clock).
854
- * 2. As soon as `IFCPROJECT` has been seen, the unit scale and the
855
- * first ~50 geometry jobs have been collected, resolves
856
- * `unitScale` + `rtcOffset` and emits a `meta` callback so the
857
- * JS host can spin up geometry process workers.
858
- * 3. Emits `jobs` callbacks every `chunk_size` jobs (or fewer if
859
- * the meta phase already buffered some).
860
- * 4. Emits `complete` with the total job count at end of scan.
861
- *
862
- * On a 986 MB / 14 M-entity file this drops time-to-first-geometry
863
- * from ~17 s (full pre-pass + worker spawn + first batch) to ~3 s
864
- * (first 100 K bytes scanned + meta + first chunk).
865
- *
866
- * The callback receives a single `JsValue` argument shaped as one of:
867
- * `{ type: "meta", unitScale, rtcOffset: [x,y,z], needsShift, buildingRotation? }`
868
- * `{ type: "jobs", jobs: Uint32Array }` // [id, start, end] triples
869
- * `{ type: "complete", totalJobs }`
870
- * @param {Uint8Array} data
871
- * @param {Function} on_event
872
- * @param {number} chunk_size
873
- * @param {string[] | null | undefined} disabled_type_names
874
- * @param {boolean} skip_type_geometry
875
- * @returns {any}
876
- */
877
- buildPrePassStreaming(data, on_event, chunk_size, disabled_type_names, skip_type_geometry) {
878
- try {
879
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
880
- const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
881
- const len0 = WASM_VECTOR_LEN;
882
- var ptr1 = isLikeNone(disabled_type_names) ? 0 : passArrayJsValueToWasm0(disabled_type_names, wasm.__wbindgen_export);
883
- var len1 = WASM_VECTOR_LEN;
884
- wasm.ifcapi_buildPrePassStreaming(retptr, this.__wbg_ptr, ptr0, len0, addBorrowedObject(on_event), chunk_size, ptr1, len1, skip_type_geometry);
885
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
886
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
887
- var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
888
- if (r2) {
889
- throw takeObject(r1);
890
- }
891
- return takeObject(r0);
892
- } finally {
893
- wasm.__wbindgen_add_to_stack_pointer(16);
894
- heap[stack_pointer++] = undefined;
895
- }
896
- }
897
846
  /**
898
847
  * Like [`IfcAPI::process_geometry_batch`] but collates the batch's meshes
899
848
  * into a GPU-instancing shard (IFNS wire format) instead of a flat
@@ -1013,6 +962,69 @@ export class IfcAPI {
1013
962
  const ret = wasm.ifcapi_processGeometryBatchPartitioned(this.__wbg_ptr, ptr0, len0, ptr1, len1, unit_scale, rtc_x, rtc_y, rtc_z, needs_shift, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, !isLikeNone(plane_angle_to_radians), isLikeNone(plane_angle_to_radians) ? 0 : plane_angle_to_radians, ptr7, len7, ptr8, len8, ptr9, len9);
1014
963
  return PartitionedBatch.__wrap(ret);
1015
964
  }
965
+ /**
966
+ * Run the pre-pass ONCE and return serialized results for worker distribution.
967
+ * Takes raw bytes (&[u8]) to avoid TextDecoder overhead.
968
+ * @param {Uint8Array} data
969
+ * @returns {any}
970
+ */
971
+ buildPrePassOnce(data) {
972
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
973
+ const len0 = WASM_VECTOR_LEN;
974
+ const ret = wasm.ifcapi_buildPrePassOnce(this.__wbg_ptr, ptr0, len0);
975
+ return takeObject(ret);
976
+ }
977
+ /**
978
+ * Streaming pre-pass: emits geometry jobs in chunks via a JS callback
979
+ * instead of waiting for the full file scan to complete.
980
+ *
981
+ * Single linear walk over the file:
982
+ * 1. Builds the entity index incrementally from the same scan that
983
+ * collects geometry jobs (a separate index scan would double
984
+ * wall-clock).
985
+ * 2. As soon as `IFCPROJECT` has been seen, the unit scale and the
986
+ * first ~50 geometry jobs have been collected, resolves
987
+ * `unitScale` + `rtcOffset` and emits a `meta` callback so the
988
+ * JS host can spin up geometry process workers.
989
+ * 3. Emits `jobs` callbacks every `chunk_size` jobs (or fewer if
990
+ * the meta phase already buffered some).
991
+ * 4. Emits `complete` with the total job count at end of scan.
992
+ *
993
+ * On a 986 MB / 14 M-entity file this drops time-to-first-geometry
994
+ * from ~17 s (full pre-pass + worker spawn + first batch) to ~3 s
995
+ * (first 100 K bytes scanned + meta + first chunk).
996
+ *
997
+ * The callback receives a single `JsValue` argument shaped as one of:
998
+ * `{ type: "meta", unitScale, rtcOffset: [x,y,z], needsShift, buildingRotation? }`
999
+ * `{ type: "jobs", jobs: Uint32Array }` // [id, start, end] triples
1000
+ * `{ type: "complete", totalJobs }`
1001
+ * @param {Uint8Array} data
1002
+ * @param {Function} on_event
1003
+ * @param {number} chunk_size
1004
+ * @param {string[] | null | undefined} disabled_type_names
1005
+ * @param {boolean} skip_type_geometry
1006
+ * @returns {any}
1007
+ */
1008
+ buildPrePassStreaming(data, on_event, chunk_size, disabled_type_names, skip_type_geometry) {
1009
+ try {
1010
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1011
+ const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
1012
+ const len0 = WASM_VECTOR_LEN;
1013
+ var ptr1 = isLikeNone(disabled_type_names) ? 0 : passArrayJsValueToWasm0(disabled_type_names, wasm.__wbindgen_export);
1014
+ var len1 = WASM_VECTOR_LEN;
1015
+ wasm.ifcapi_buildPrePassStreaming(retptr, this.__wbg_ptr, ptr0, len0, addBorrowedObject(on_event), chunk_size, ptr1, len1, skip_type_geometry);
1016
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1017
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1018
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1019
+ if (r2) {
1020
+ throw takeObject(r1);
1021
+ }
1022
+ return takeObject(r0);
1023
+ } finally {
1024
+ wasm.__wbindgen_add_to_stack_pointer(16);
1025
+ heap[stack_pointer++] = undefined;
1026
+ }
1027
+ }
1016
1028
  /**
1017
1029
  * Parse the file and return structured per-axis data (tag + endpoints) in
1018
1030
  * the renderer's Y-up world space (RTC-subtracted, metres). Use this when
@@ -1047,18 +1059,16 @@ export class IfcAPI {
1047
1059
  * Export tabular **CSV**. `mode` ∈ {`"entities"`, `"properties"`, `"quantities"`,
1048
1060
  * `"spatial"`}. `delimiter` defaults to `,` when empty; `include_properties` adds
1049
1061
  * flattened `Pset_Prop` columns to the entities view.
1050
- * @param {string} content
1062
+ * @param {Uint8Array} content
1051
1063
  * @param {string} mode
1052
1064
  * @param {string} delimiter
1053
1065
  * @param {boolean} include_properties
1054
- * @returns {string}
1066
+ * @returns {Uint8Array}
1055
1067
  */
1056
1068
  exportCsv(content, mode, delimiter, include_properties) {
1057
- let deferred4_0;
1058
- let deferred4_1;
1059
1069
  try {
1060
1070
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1061
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1071
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1062
1072
  const len0 = WASM_VECTOR_LEN;
1063
1073
  const ptr1 = passStringToWasm0(mode, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1064
1074
  const len1 = WASM_VECTOR_LEN;
@@ -1067,84 +1077,75 @@ export class IfcAPI {
1067
1077
  wasm.ifcapi_exportCsv(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, include_properties);
1068
1078
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1069
1079
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1070
- deferred4_0 = r0;
1071
- deferred4_1 = r1;
1072
- return getStringFromWasm0(r0, r1);
1080
+ var v4 = getArrayU8FromWasm0(r0, r1).slice();
1081
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1082
+ return v4;
1073
1083
  } finally {
1074
1084
  wasm.__wbindgen_add_to_stack_pointer(16);
1075
- wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
1076
1085
  }
1077
1086
  }
1078
1087
  /**
1079
1088
  * Export **IFC5 / IFCX** (the USD-style node graph). `only_known_properties` keeps
1080
1089
  * only properties with an official IFC5 schema.
1081
- * @param {string} content
1090
+ * @param {Uint8Array} content
1082
1091
  * @param {boolean} only_known_properties
1083
1092
  * @param {boolean} pretty
1084
- * @returns {string}
1093
+ * @returns {Uint8Array}
1085
1094
  */
1086
1095
  exportIfcx(content, only_known_properties, pretty) {
1087
- let deferred2_0;
1088
- let deferred2_1;
1089
1096
  try {
1090
1097
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1091
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1098
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1092
1099
  const len0 = WASM_VECTOR_LEN;
1093
1100
  wasm.ifcapi_exportIfcx(retptr, this.__wbg_ptr, ptr0, len0, only_known_properties, pretty);
1094
1101
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1095
1102
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1096
- deferred2_0 = r0;
1097
- deferred2_1 = r1;
1098
- return getStringFromWasm0(r0, r1);
1103
+ var v2 = getArrayU8FromWasm0(r0, r1).slice();
1104
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1105
+ return v2;
1099
1106
  } finally {
1100
1107
  wasm.__wbindgen_add_to_stack_pointer(16);
1101
- wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
1102
1108
  }
1103
1109
  }
1104
1110
  /**
1105
1111
  * Export structured **JSON** (array of entity objects with typed property values).
1106
- * @param {string} content
1112
+ * @param {Uint8Array} content
1107
1113
  * @param {boolean} pretty
1108
1114
  * @param {boolean} include_properties
1109
1115
  * @param {boolean} include_quantities
1110
- * @returns {string}
1116
+ * @returns {Uint8Array}
1111
1117
  */
1112
1118
  exportJson(content, pretty, include_properties, include_quantities) {
1113
- let deferred2_0;
1114
- let deferred2_1;
1115
1119
  try {
1116
1120
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1117
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1121
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1118
1122
  const len0 = WASM_VECTOR_LEN;
1119
1123
  wasm.ifcapi_exportJson(retptr, this.__wbg_ptr, ptr0, len0, pretty, include_properties, include_quantities);
1120
1124
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1121
1125
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1122
- deferred2_0 = r0;
1123
- deferred2_1 = r1;
1124
- return getStringFromWasm0(r0, r1);
1126
+ var v2 = getArrayU8FromWasm0(r0, r1).slice();
1127
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1128
+ return v2;
1125
1129
  } finally {
1126
1130
  wasm.__wbindgen_add_to_stack_pointer(16);
1127
- wasm.__wbindgen_export4(deferred2_0, deferred2_1, 1);
1128
1131
  }
1129
1132
  }
1130
1133
  /**
1131
1134
  * Export **JSON-LD** (`@graph` of `ifc:` nodes). Empty `context` ⇒ buildingSMART
1132
1135
  * IFC4 OWL default. `included` is an express-id isolation filter mirroring the
1133
1136
  * OBJ/glTF/STEP exporters (empty ⇒ all entities).
1134
- * @param {string} content
1137
+ * @param {Uint8Array} content
1135
1138
  * @param {string} context
1136
1139
  * @param {boolean} include_properties
1137
1140
  * @param {boolean} include_quantities
1138
1141
  * @param {boolean} pretty
1139
1142
  * @param {Uint32Array} included
1140
- * @returns {string}
1143
+ * @returns {Uint8Array}
1141
1144
  */
1142
1145
  exportJsonld(content, context, include_properties, include_quantities, pretty, included) {
1143
- let deferred4_0;
1144
- let deferred4_1;
1145
1146
  try {
1146
1147
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1147
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1148
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1148
1149
  const len0 = WASM_VECTOR_LEN;
1149
1150
  const ptr1 = passStringToWasm0(context, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1150
1151
  const len1 = WASM_VECTOR_LEN;
@@ -1153,34 +1154,35 @@ export class IfcAPI {
1153
1154
  wasm.ifcapi_exportJsonld(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, include_properties, include_quantities, pretty, ptr2, len2);
1154
1155
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1155
1156
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1156
- deferred4_0 = r0;
1157
- deferred4_1 = r1;
1158
- return getStringFromWasm0(r0, r1);
1157
+ var v4 = getArrayU8FromWasm0(r0, r1).slice();
1158
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1159
+ return v4;
1159
1160
  } finally {
1160
1161
  wasm.__wbindgen_add_to_stack_pointer(16);
1161
- wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
1162
1162
  }
1163
1163
  }
1164
1164
  /**
1165
- * Re-serialize the model in `content` to a STEP/IFC string.
1165
+ * Re-serialize the model in `content` to STEP/IFC UTF-8 bytes.
1166
+ *
1167
+ * Returned as UTF-8 bytes (`Uint8Array`) so output is not capped by the
1168
+ * V8 max-string ceiling (~512 MB); decode with `TextDecoder` when a string
1169
+ * is genuinely needed.
1166
1170
  *
1167
1171
  * `schema` is the FILE_SCHEMA label to write (empty ⇒ preserve the source schema).
1168
1172
  * `included` is an express-id allowlist (empty ⇒ whole model); when set, the forward
1169
1173
  * `#`-reference closure is added so the subset never dangles a reference.
1170
1174
  * `mutations_json` carries `MutablePropertyView` edits (attribute updates +
1171
1175
  * property-set synthesis); empty ⇒ none. See `export_step_json` for the shape.
1172
- * @param {string} content
1176
+ * @param {Uint8Array} content
1173
1177
  * @param {string} schema
1174
1178
  * @param {Uint32Array} included
1175
1179
  * @param {string} mutations_json
1176
- * @returns {string}
1180
+ * @returns {Uint8Array}
1177
1181
  */
1178
1182
  exportStep(content, schema, included, mutations_json) {
1179
- let deferred5_0;
1180
- let deferred5_1;
1181
1183
  try {
1182
1184
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1183
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1185
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1184
1186
  const len0 = WASM_VECTOR_LEN;
1185
1187
  const ptr1 = passStringToWasm0(schema, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1186
1188
  const len1 = WASM_VECTOR_LEN;
@@ -1191,26 +1193,24 @@ export class IfcAPI {
1191
1193
  wasm.ifcapi_exportStep(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
1192
1194
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1193
1195
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1194
- deferred5_0 = r0;
1195
- deferred5_1 = r1;
1196
- return getStringFromWasm0(r0, r1);
1196
+ var v5 = getArrayU8FromWasm0(r0, r1).slice();
1197
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1198
+ return v5;
1197
1199
  } finally {
1198
1200
  wasm.__wbindgen_add_to_stack_pointer(16);
1199
- wasm.__wbindgen_export4(deferred5_0, deferred5_1, 1);
1200
1201
  }
1201
1202
  }
1202
1203
  /**
1203
- * Merge several IFC models into one STEP/IFC string. `concatenated` is every model's
1204
+ * Merge several IFC models into one STEP/IFC UTF-8 byte buffer (`Uint8Array`).
1205
+ * `concatenated` is every model's
1204
1206
  * bytes laid end-to-end; `lengths[i]` is the byte length of model `i`. The first model
1205
1207
  * keeps its ids; later models are id-offset and their project unified to the first.
1206
1208
  * @param {Uint8Array} concatenated
1207
1209
  * @param {Uint32Array} lengths
1208
1210
  * @param {string} schema
1209
- * @returns {string}
1211
+ * @returns {Uint8Array}
1210
1212
  */
1211
1213
  exportMerged(concatenated, lengths, schema) {
1212
- let deferred4_0;
1213
- let deferred4_1;
1214
1214
  try {
1215
1215
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1216
1216
  const ptr0 = passArray8ToWasm0(concatenated, wasm.__wbindgen_export);
@@ -1222,16 +1222,19 @@ export class IfcAPI {
1222
1222
  wasm.ifcapi_exportMerged(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
1223
1223
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1224
1224
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1225
- deferred4_0 = r0;
1226
- deferred4_1 = r1;
1227
- return getStringFromWasm0(r0, r1);
1225
+ var v4 = getArrayU8FromWasm0(r0, r1).slice();
1226
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1227
+ return v4;
1228
1228
  } finally {
1229
1229
  wasm.__wbindgen_add_to_stack_pointer(16);
1230
- wasm.__wbindgen_export4(deferred4_0, deferred4_1, 1);
1231
1230
  }
1232
1231
  }
1233
1232
  /**
1234
- * Export the `IfcSpace` volumes in `content` as a Honeybee **HBJSON** string.
1233
+ * Export the `IfcSpace` volumes in `content` as Honeybee **HBJSON** UTF-8 bytes.
1234
+ *
1235
+ * Returned as UTF-8 bytes (`Uint8Array`) so output is not capped by the
1236
+ * V8 max-string ceiling (~512 MB); decode with `TextDecoder` when a string
1237
+ * is genuinely needed.
1235
1238
  *
1236
1239
  * Rooms are built analytically from extruded-area profiles (watertight by construction);
1237
1240
  * faces are typed Floor / RoofCeiling / Wall with outward normals. The result loads via
@@ -1241,28 +1244,25 @@ export class IfcAPI {
1241
1244
  * const api = new IfcAPI();
1242
1245
  * const hbjson = api.exportHbjson(ifcContent, "my_model");
1243
1246
  * ```
1244
- * @param {string} content
1247
+ * @param {Uint8Array} content
1245
1248
  * @param {string} name
1246
- * @returns {string}
1249
+ * @returns {Uint8Array}
1247
1250
  */
1248
1251
  exportHbjson(content, name) {
1249
- let deferred3_0;
1250
- let deferred3_1;
1251
1252
  try {
1252
1253
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1253
- const ptr0 = passStringToWasm0(content, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1254
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1254
1255
  const len0 = WASM_VECTOR_LEN;
1255
1256
  const ptr1 = passStringToWasm0(name, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1256
1257
  const len1 = WASM_VECTOR_LEN;
1257
1258
  wasm.ifcapi_exportHbjson(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1);
1258
1259
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1259
1260
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1260
- deferred3_0 = r0;
1261
- deferred3_1 = r1;
1262
- return getStringFromWasm0(r0, r1);
1261
+ var v3 = getArrayU8FromWasm0(r0, r1).slice();
1262
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1263
+ return v3;
1263
1264
  } finally {
1264
1265
  wasm.__wbindgen_add_to_stack_pointer(16);
1265
- wasm.__wbindgen_export4(deferred3_0, deferred3_1, 1);
1266
1266
  }
1267
1267
  }
1268
1268
  /**
@@ -1314,6 +1314,19 @@ export class IfcAPI {
1314
1314
  const ret = wasm.ifcapi_extractProfiles(this.__wbg_ptr, ptr0, len0, model_index);
1315
1315
  return ProfileCollection.__wrap(ret);
1316
1316
  }
1317
+ /**
1318
+ * Structured pipeline diagnostics accumulated across every
1319
+ * `processGeometryBatch*` call since the last load reset
1320
+ * (`clearPrePassCache` / `setEntityIndex`), as a JS object with a
1321
+ * `schemaVersion` field — or `undefined` when no batch has run yet.
1322
+ * Includes per-batch summed geometry wall time, mesh/triangle counts,
1323
+ * the degenerate-backstop drop count, and the CSG failure aggregates.
1324
+ * @returns {any}
1325
+ */
1326
+ getPipelineDiagnostics() {
1327
+ const ret = wasm.ifcapi_getPipelineDiagnostics(this.__wbg_ptr);
1328
+ return takeObject(ret);
1329
+ }
1317
1330
  /**
1318
1331
  * Get WASM memory for zero-copy access
1319
1332
  * @returns {any}
@@ -1373,6 +1386,20 @@ export class IfcAPI {
1373
1386
  setMergeLayers(enabled) {
1374
1387
  wasm.ifcapi_setMergeLayers(this.__wbg_ptr, enabled);
1375
1388
  }
1389
+ /**
1390
+ * Toggle the tier-independent small-cut skip (#1286). When `true`,
1391
+ * `processGeometryBatch` drops `IfcBooleanResult` differences whose cutter is
1392
+ * tiny relative to its host (steel copes/notches) while keeping the
1393
+ * tessellation tier — so curves stay full-density. The viewer enables this for
1394
+ * the on-screen load; exports/drawings leave it off so their geometry keeps
1395
+ * every cut. Default off ⇒ byte-identical to before.
1396
+ *
1397
+ * Set BEFORE processing — meshes already emitted are not regenerated.
1398
+ * @param {boolean} on
1399
+ */
1400
+ setSkipSmallCuts(on) {
1401
+ wasm.ifcapi_setSkipSmallCuts(this.__wbg_ptr, on);
1402
+ }
1376
1403
  /**
1377
1404
  * Clear the cached entity index (call between loads when reusing
1378
1405
  * the same `IfcAPI` instance — e.g. the parser worker keeps one
@@ -1390,12 +1417,13 @@ export class IfcAPI {
1390
1417
  * Enable or disable the PARAMETRIC rectangular-opening fast path (the
1391
1418
  * placement-frame, ground-truth-exact analytic cut) for `processGeometryBatch`.
1392
1419
  *
1393
- * DEFAULT OFF. This is the wasm-side toggle that lets native and wasm flip the
1394
- * flag in LOCKSTEP the byte-identical native==wasm contract requires both
1395
- * targets take the same path, and wasm has no env to read `IFC_LITE_RECT_PARAM`.
1420
+ * DEFAULT ON (corpus-validated; native defaults ON too, and wasm has no env to
1421
+ * read `IFC_LITE_RECT_PARAM`, so both targets default in LOCKSTEP -- the
1422
+ * byte-identical native==wasm contract requires both take the same path). This
1423
+ * toggle is the wasm-side escape hatch mirroring `IFC_LITE_RECT_PARAM=0`.
1396
1424
  * The path subtracts rectangular openings as exact parametric boxes in the host's
1397
1425
  * own placement frame (rotated walls included), deferring any non-clean case to
1398
- * the exact kernel. Pass `true` before `processGeometryBatch`.
1426
+ * the exact kernel. Pass `false` before `processGeometryBatch` to opt out.
1399
1427
  * @param {boolean} enabled
1400
1428
  */
1401
1429
  setRectParamFastPath(enabled) {
@@ -1523,6 +1551,21 @@ export class IfcAPI {
1523
1551
  const ret = wasm.ifcapi_scanGeometryEntitiesFast(this.__wbg_ptr, ptr0, len0);
1524
1552
  return takeObject(ret);
1525
1553
  }
1554
+ /**
1555
+ * Run geometry extraction on `content` and return its typed CSG / opening
1556
+ * diagnostics (the `GeometryDiagnostics` contract) as a JS object, or
1557
+ * `undefined` when nothing diagnostic-worthy happened (no openings, no
1558
+ * failures). Takes the raw IFC bytes (`Uint8Array`) so there is no input-size
1559
+ * cap. The produced meshes are dropped; only the diagnostics are returned.
1560
+ * @param {Uint8Array} content
1561
+ * @returns {any}
1562
+ */
1563
+ diagnoseGeometry(content) {
1564
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1565
+ const len0 = WASM_VECTOR_LEN;
1566
+ const ret = wasm.ifcapi_diagnoseGeometry(this.__wbg_ptr, ptr0, len0);
1567
+ return takeObject(ret);
1568
+ }
1526
1569
  /**
1527
1570
  * Parse IFC file and extract symbolic representations (Plan,
1528
1571
  * Annotation, FootPrint, Axis). These are 2D curves used for
@@ -1571,6 +1614,17 @@ export class MeshCollection {
1571
1614
  const ptr = this.__destroy_into_raw();
1572
1615
  wasm.__wbg_meshcollection_free(ptr, 0);
1573
1616
  }
1617
+ /**
1618
+ * The batch's typed CSG / opening diagnostics as a JS object (the
1619
+ * `GeometryDiagnostics` contract), or `undefined` if none were recorded. The
1620
+ * worker merges these across batches. One serialized value keeps the rich
1621
+ * nested shape as a single FFI crossing instead of dozens of getters.
1622
+ * @returns {any}
1623
+ */
1624
+ get diagnostics() {
1625
+ const ret = wasm.meshcollection_diagnostics(this.__wbg_ptr);
1626
+ return takeObject(ret);
1627
+ }
1574
1628
  /**
1575
1629
  * Get RTC offset X (for converting local coords back to world coords)
1576
1630
  * Add this to local X coordinates to get world X coordinates
@@ -1737,6 +1791,28 @@ export class MeshDataJs {
1737
1791
  const ret = wasm.meshdatajs_hasTexture(this.__wbg_ptr);
1738
1792
  return ret !== 0;
1739
1793
  }
1794
+ /**
1795
+ * Local (pre-placement, object-space) AABB (issue #1474), WebGL Y-up,
1796
+ * `[minX,minY,minZ,maxX,maxY,maxZ]`. `undefined` when not captured
1797
+ * (wasm-bindgen maps `Option::None` to `undefined`, not `null`).
1798
+ * @returns {Float32Array | undefined}
1799
+ */
1800
+ get localBounds() {
1801
+ try {
1802
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1803
+ wasm.meshdatajs_localBounds(retptr, this.__wbg_ptr);
1804
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1805
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1806
+ let v1;
1807
+ if (r0 !== 0) {
1808
+ v1 = getArrayF32FromWasm0(r0, r1).slice();
1809
+ wasm.__wbindgen_export4(r0, r1 * 4, 4);
1810
+ }
1811
+ return v1;
1812
+ } finally {
1813
+ wasm.__wbindgen_add_to_stack_pointer(16);
1814
+ }
1815
+ }
1740
1816
  /**
1741
1817
  * Decoded RGBA8 texture bytes (`width*height*4`). Empty when untextured.
1742
1818
  * @returns {Uint8Array}
@@ -1792,6 +1868,28 @@ export class MeshDataJs {
1792
1868
  const ret = wasm.meshdatajs_geometryClass(this.__wbg_ptr);
1793
1869
  return ret;
1794
1870
  }
1871
+ /**
1872
+ * The resolved `IfcLocalPlacement` chain for this mesh (issue #1474),
1873
+ * row-major 4×4, WebGL Y-up. `undefined` when not captured (see
1874
+ * `local_bounds` above).
1875
+ * @returns {Float64Array | undefined}
1876
+ */
1877
+ get localToWorld() {
1878
+ try {
1879
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1880
+ wasm.meshdatajs_localToWorld(retptr, this.__wbg_ptr);
1881
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1882
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1883
+ let v1;
1884
+ if (r0 !== 0) {
1885
+ v1 = getArrayF64FromWasm0(r0, r1).slice();
1886
+ wasm.__wbindgen_export4(r0, r1 * 8, 8);
1887
+ }
1888
+ return v1;
1889
+ } finally {
1890
+ wasm.__wbindgen_add_to_stack_pointer(16);
1891
+ }
1892
+ }
1795
1893
  /**
1796
1894
  * @returns {number}
1797
1895
  */
@@ -2103,7 +2201,7 @@ export class ProfileEntryJs {
2103
2201
  * @returns {number}
2104
2202
  */
2105
2203
  get expressId() {
2106
- const ret = wasm.meshdatajs_textureWidth(this.__wbg_ptr);
2204
+ const ret = wasm.profileentryjs_expressId(this.__wbg_ptr);
2107
2205
  return ret >>> 0;
2108
2206
  }
2109
2207
  /**
@@ -2795,7 +2893,7 @@ export class SymbolicFillArea {
2795
2893
  * @returns {number}
2796
2894
  */
2797
2895
  get expressId() {
2798
- const ret = wasm.meshdatajs_textureWidth(this.__wbg_ptr);
2896
+ const ret = wasm.profileentryjs_expressId(this.__wbg_ptr);
2799
2897
  return ret >>> 0;
2800
2898
  }
2801
2899
  /**
@@ -3203,7 +3301,7 @@ export class SymbolicText {
3203
3301
  * @returns {number}
3204
3302
  */
3205
3303
  get expressId() {
3206
- const ret = wasm.meshdatajs_textureWidth(this.__wbg_ptr);
3304
+ const ret = wasm.profileentryjs_expressId(this.__wbg_ptr);
3207
3305
  return ret >>> 0;
3208
3306
  }
3209
3307
  /**
@@ -3566,6 +3664,10 @@ function __wbg_get_imports() {
3566
3664
  const ret = new Float64Array(arg0 >>> 0);
3567
3665
  return addHeapObject(ret);
3568
3666
  };
3667
+ imports.wbg.__wbg_now_69d776cd24f5215b = function() {
3668
+ const ret = Date.now();
3669
+ return ret;
3670
+ };
3569
3671
  imports.wbg.__wbg_set_3f1d0b984ed272ed = function(arg0, arg1, arg2) {
3570
3672
  getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
3571
3673
  };
Binary file