@ifc-lite/wasm 8.0.1 → 9.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": "8.0.1",
8
+ "version": "9.0.0",
9
9
  "license": "MPL-2.0",
10
10
  "repository": {
11
11
  "type": "git",
package/pkg/ifc-lite.d.ts CHANGED
@@ -400,12 +400,14 @@ export class IfcAPI {
400
400
  *
401
401
  * Fails CLOSED: if the declared vertex/index counts run past the flattened
402
402
  * `positions` / `indices`, there are fewer `index_counts` than meshes, `normals`
403
- * is empty or too short to cover every vertex, or an index names a vertex its own
404
- * mesh does not have (glTF 2.0 3.7.2.1), this throws an `Error` whose message
405
- * starts with `MALFORMED_MESH_INPUT` — instead of silently emitting a GLB with
406
- * those meshes dropped, or one carrying the out-of-range index straight into the
407
- * BIN chunk. (The viewer always passes fully-backed, normal-covered, in-range
408
- * arrays, so this only fires on a caller bug.)
403
+ * is empty or too short to cover every vertex, a mesh's index block is not a
404
+ * whole number of triangles, or an index names a vertex its own mesh does not
405
+ * have (glTF 2.0 3.7.2.1), this throws an `Error` whose message starts with
406
+ * `MALFORMED_MESH_INPUT` — instead of silently emitting a GLB with those meshes
407
+ * dropped, a TRIANGLES primitive whose count is not a multiple of 3, or the
408
+ * out-of-range index copied into the BIN chunk. (The viewer always passes
409
+ * fully-backed, normal-covered, whole-triangle, in-range arrays, so this only
410
+ * fires on a caller bug.)
409
411
  */
410
412
  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, emissive?: boolean | null): Uint8Array;
411
413
  /**
@@ -454,25 +456,18 @@ export class IfcAPI {
454
456
  exportJson(content: Uint8Array, pretty: boolean, include_properties: boolean, include_quantities: boolean): Uint8Array;
455
457
  /**
456
458
  * Export **JSON-LD** (`@graph` of `ifc:` nodes). Empty `context` ⇒ buildingSMART
457
- * IFC4 OWL default. `included` is an express-id isolation filter mirroring the
458
- * OBJ/glTF/STEP exporters (empty ⇒ all entities).
459
- */
460
- exportJsonld(content: Uint8Array, context: string, include_properties: boolean, include_quantities: boolean, pretty: boolean, included: Uint32Array): Uint8Array;
461
- /**
462
- * Package an already-produced **GLB** + georeference into a **KMZ** (`Uint8Array`)
463
- * for Google Earth: a ZIP of `doc.kml` (a `<Model>` placed at `latitude`/`longitude`/
464
- * `altitude`) + `model.glb`. `x_axis_abscissa`/`x_axis_ordinate` are the
465
- * `IfcMapConversion` grid-north components; pass both as `undefined` for heading 0.
459
+ * IFC4 OWL default.
466
460
  *
467
- * `altitude_mode` selects the KML vertical placement: `"clampToGround"`
468
- * (the default when omitted) rests the model on the terrain, ignoring
469
- * `altitude`; `"absolute"` places the origin at `altitude` metres MSL.
470
- * Google Earth's terrain already encodes the site elevation, so clamping
471
- * keeps a wrong/zero/double-counted OrthogonalHeight from floating the
472
- * model into the sky (#1427); absolute is offered for models whose
473
- * OrthogonalHeight is a true MSL elevation the user wants honoured.
461
+ * `included` is an express-id isolation filter mirroring `exportObj` /
462
+ * `exportGlb`, and carries the same null-vs-empty distinction across the wasm
463
+ * boundary: omit it (`undefined`) for "no isolation filter" (every entity is
464
+ * emitted); pass an empty `Uint32Array` for "isolation is ACTIVE and currently
465
+ * matches nothing", which emits an empty `@graph`. Collapsing the two — as a
466
+ * bare `Uint32Array` parameter would force a caller to do — silently exported
467
+ * the whole model when a filter matched nothing (#4659, the JSON-LD twin of
468
+ * #4483/#4484). A non-empty `Uint32Array` is the ordinary allowlist.
474
469
  */
475
- exportKmz(glb: Uint8Array, latitude: number, longitude: number, altitude: number, x_axis_abscissa: number | null | undefined, x_axis_ordinate: number | null | undefined, name: string, altitude_mode?: string | null): Uint8Array;
470
+ exportJsonld(content: Uint8Array, context: string, include_properties: boolean, include_quantities: boolean, pretty: boolean, included?: Uint32Array | null): Uint8Array;
476
471
  /**
477
472
  * Build a Google-Earth-ready **KMZ** (`Uint8Array`) straight from the viewer's
478
473
  * already-produced meshes — the working path (#1427). The model is embedded as
@@ -488,10 +483,11 @@ export class IfcAPI {
488
483
  * Fails CLOSED: when no triangle survives (an empty visible set, or meshes
489
484
  * whose only triangles are degenerate and collapse in the vertex dedup)
490
485
  * this throws an `Error` whose message starts with `NO_RENDER_GEOMETRY`;
491
- * a declared vertex/index count running past its buffer throws
492
- * `MALFORMED_MESH_INPUT`, as `exportGlbFromMeshes` does. Both used to ship
493
- * as a small "successful" archive: the first around a COLLADA document
494
- * the 1.4.1 schema rejects, the second with every later mesh missing.
486
+ * a declared vertex/index count running past its buffer, an index block
487
+ * that is not whole triangles, or an index outside its mesh throws
488
+ * `MALFORMED_MESH_INPUT`, exactly as `exportGlbFromMeshes` does. These used
489
+ * to ship as a "successful" archive: an empty one around a COLLADA
490
+ * document the 1.4.1 schema rejects, or one with meshes or faces missing.
495
491
  */
496
492
  exportKmzFromMeshes(positions: Float32Array, normals: Float32Array, indices: Uint32Array, vertex_counts: Uint32Array, index_counts: Uint32Array, colors: Float32Array, origins: Float64Array, latitude: number, longitude: number, altitude: number, x_axis_abscissa: number | null | undefined, x_axis_ordinate: number | null | undefined, name: string, altitude_mode?: string | null): Uint8Array;
497
493
  /**
@@ -531,15 +527,23 @@ export class IfcAPI {
531
527
  * is genuinely needed.
532
528
  *
533
529
  * `schema` is the FILE_SCHEMA label to write (empty ⇒ preserve the source schema).
534
- * `included` is an express-id allowlist (empty ⇒ whole model); when set, the forward
535
- * `#`-reference closure is added so the subset never dangles a reference.
530
+ *
531
+ * `included` is an express-id allowlist carrying the same null-vs-empty
532
+ * distinction as `exportObj` / `exportGlb`: omit it (`undefined`) for "no
533
+ * isolation filter" (whole model); pass an empty `Uint32Array` for "isolation
534
+ * is ACTIVE and currently matches nothing", which writes a header-only file
535
+ * with an empty `DATA;` section. Collapsing the two — as a bare `Uint32Array`
536
+ * parameter would force a caller to do — silently exported the whole model
537
+ * when a filter matched nothing (#4659, the STEP twin of #4483/#4484). When
538
+ * set, the forward `#`-reference closure is added so the subset never dangles
539
+ * a reference.
536
540
  * `mutations_json` carries `MutablePropertyView` edits (attribute updates +
537
541
  * property-set synthesis); empty ⇒ none. See `export_step_json` for the shape.
538
542
  * A non-empty but malformed `mutations_json` throws rather than silently
539
543
  * exporting the model with none of the caller's edits applied — mirrors
540
544
  * `exportGlb`'s and `exportMerged`'s fail-closed contract on this same API.
541
545
  */
542
- exportStep(content: Uint8Array, schema: string, included: Uint32Array, mutations_json: string): Uint8Array;
546
+ exportStep(content: Uint8Array, schema: string, included: Uint32Array | null | undefined, mutations_json: string): Uint8Array;
543
547
  /**
544
548
  * Export **OpenUSD** (`.usda` ASCII): a real Z-up USD stage — spatial hierarchy of
545
549
  * `Xform` prims, `UsdGeomMesh` geometry, `UsdPreviewSurface` materials, IFC
@@ -575,7 +579,9 @@ export class IfcAPI {
575
579
  * CANONICAL styles flatten. Returns the exact `styles` event payload the
576
580
  * serial path emits. Runs on any worker with `setEntityIndex` installed.
577
581
  * Span arguments are `[id, start, len]` triples; `plane_angle_to_radians`
578
- * comes from the meta event.
582
+ * comes from the meta event. `orphanColors` / `geomColors` carry exactly
583
+ * four floats per id in `orphanIds` / `geomIds`; any other length throws
584
+ * before either column is read.
579
585
  */
580
586
  finalizePrepassStyles(data: Uint8Array, orphan_ids: Uint32Array, orphan_colors: Float32Array, geom_ids: Uint32Array, geom_colors: Float32Array, colour_map_spans: Uint32Array, material_def_spans: Uint32Array, rel_material_spans: Uint32Array, void_spans: Uint32Array, fills_spans: Uint32Array, aggregate_spans: Uint32Array, plane_angle_to_radians: number): any;
581
587
  /**
@@ -863,6 +869,12 @@ export class IfcAPI {
863
869
  * Idempotent in the sense that repeated calls REPLACE the cache —
864
870
  * supports the parser-worker pattern of reusing one IfcAPI across
865
871
  * multiple loads with different files.
872
+ *
873
+ * Throws when the three columns disagree in length. Every call is a
874
+ * content swap, a rejected one included: the previous file's index,
875
+ * content-scoped caches and pipeline diagnostics are dropped before the
876
+ * error is raised, and a rejected or empty index leaves no index, so the
877
+ * next batch scans the bytes it is given.
866
878
  */
867
879
  setEntityIndex(ids: Uint32Array, starts: Uint32Array, lengths: Uint32Array): void;
868
880
  /**
@@ -1029,7 +1041,9 @@ export class MeshCollection {
1029
1041
  */
1030
1042
  get(index: number): MeshDataJs | undefined;
1031
1043
  /**
1032
- * Check if RTC offset is significant (>10km)
1044
+ * Check if an RTC offset was applied to these meshes (any non-zero
1045
+ * component). It can be inside 10 km: the placement-bounds fallback
1046
+ * re-bases on the bbox centre when a corner is past 10 km (#4643).
1033
1047
  */
1034
1048
  hasRtcOffset(): boolean;
1035
1049
  /**
@@ -1941,7 +1955,12 @@ export function intersection2d(a: Contours2D, b: Contours2D): Contours2D;
1941
1955
  *
1942
1956
  * `positions` is flat XYZ; `indices` is flat triangle indices. `axis` is
1943
1957
  * 0/1/2 = x/y/z (the cut axis, WebGL Y-up). Returns `undefined` when the mesh
1944
- * has no triangles or projects to nothing.
1958
+ * has no triangles or projects to nothing: the element has no footprint.
1959
+ *
1960
+ * THROWS when the outline was not computed: an `axis` outside 0..=2, or a
1961
+ * mesh with more valid projected triangles than the overlay budget (50 000).
1962
+ * The viewer's outline provider catches the throw and draws its TypeScript
1963
+ * silhouette for that mesh.
1945
1964
  *
1946
1965
  * ```javascript
1947
1966
  * const outline = meshOutline2d(positions, indices, 1, false); // axis 1 = y
@@ -1992,10 +2011,17 @@ export function resolve2d(a: Contours2D): Contours2D;
1992
2011
  * meaningless volumes with a plausible `sumErrorRel`, so the closure proof
1993
2012
  * above is the caller's responsibility and not a formality.
1994
2013
  *
2014
+ * Returns `undefined` when the mesh encloses no volume (no triangles survive
2015
+ * the filter above, or the shell is degenerate): there is nothing to split,
2016
+ * and a result for it would report `pieceCount` 1, `sumErrorRel` 0 and
2017
+ * `remainderFailed` false, a perfect split of nothing. A caller that gates
2018
+ * on those numbers must treat `undefined` as "no split", not as "no error".
2019
+ *
1995
2020
  * ```javascript
1996
2021
  * const split = splitMeshByZones(positions, indices, new Float64Array([
1997
2022
  * 0, 0, 0, 10, 10, 10, 0,
1998
2023
  * ]));
2024
+ * if (!split) return; // the mesh encloses no volume
1999
2025
  * for (let i = 0; i < split.pieceCount; i++) {
2000
2026
  * const piece = split.piece(i);
2001
2027
  * // piece.zoneIndex, piece.positions, piece.indices, piece.volume
@@ -2004,7 +2030,7 @@ export function resolve2d(a: Contours2D): Contours2D;
2004
2030
  * split.free();
2005
2031
  * ```
2006
2032
  */
2007
- export function splitMeshByZones(positions: Float64Array, indices: Uint32Array, zones: Float64Array, footprints?: Float64Array | null, footprint_counts?: Uint32Array | null): ZoneSplitJs;
2033
+ export function splitMeshByZones(positions: Float64Array, indices: Uint32Array, zones: Float64Array, footprints?: Float64Array | null, footprint_counts?: Uint32Array | null): ZoneSplitJs | undefined;
2008
2034
 
2009
2035
  /**
2010
2036
  * `a ∪ b`.
@@ -2108,7 +2134,6 @@ export interface InitOutput {
2108
2134
  readonly ifcapi_exportIfcx: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
2109
2135
  readonly ifcapi_exportJson: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
2110
2136
  readonly ifcapi_exportJsonld: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => void;
2111
- readonly ifcapi_exportKmz: (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) => void;
2112
2137
  readonly ifcapi_exportKmzFromMeshes: (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, u: number, v: number, w: number, x: number, y: number, z: number, a1: number) => void;
2113
2138
  readonly ifcapi_exportMerged: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
2114
2139
  readonly ifcapi_exportObj: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
@@ -2147,7 +2172,7 @@ export interface InitOutput {
2147
2172
  readonly ifcapi_scanEntityIndexShardFromSource: (a: number, b: number, c: number) => number;
2148
2173
  readonly ifcapi_scanGeometryEntitiesFast: (a: number, b: number, c: number) => number;
2149
2174
  readonly ifcapi_setComputeGeometryHashes: (a: number, b: number, c: number) => void;
2150
- readonly ifcapi_setEntityIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
2175
+ readonly ifcapi_setEntityIndex: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
2151
2176
  readonly ifcapi_setInstantiatedTypeIds: (a: number, b: number, c: number) => void;
2152
2177
  readonly ifcapi_setMappedInstancePlan: (a: number, b: number, c: number) => void;
2153
2178
  readonly ifcapi_setMaterialLayerIndex: (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) => void;
@@ -2160,7 +2185,7 @@ export interface InitOutput {
2160
2185
  readonly ifcapi_simplifyMeshes: (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, u: number, v: number, w: number, x: number, y: number, z: number, a1: number) => void;
2161
2186
  readonly ifcapi_version: (a: number, b: number) => void;
2162
2187
  readonly intersection2d: (a: number, b: number) => number;
2163
- readonly meshOutline2d: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
2188
+ readonly meshOutline2d: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
2164
2189
  readonly meshcollection_buildingRotation: (a: number, b: number) => void;
2165
2190
  readonly meshcollection_diagnostics: (a: number) => number;
2166
2191
  readonly meshcollection_geometryAabbValues: (a: number) => number;
package/pkg/ifc-lite.js CHANGED
@@ -1059,12 +1059,14 @@ export class IfcAPI {
1059
1059
  *
1060
1060
  * Fails CLOSED: if the declared vertex/index counts run past the flattened
1061
1061
  * `positions` / `indices`, there are fewer `index_counts` than meshes, `normals`
1062
- * is empty or too short to cover every vertex, or an index names a vertex its own
1063
- * mesh does not have (glTF 2.0 3.7.2.1), this throws an `Error` whose message
1064
- * starts with `MALFORMED_MESH_INPUT` — instead of silently emitting a GLB with
1065
- * those meshes dropped, or one carrying the out-of-range index straight into the
1066
- * BIN chunk. (The viewer always passes fully-backed, normal-covered, in-range
1067
- * arrays, so this only fires on a caller bug.)
1062
+ * is empty or too short to cover every vertex, a mesh's index block is not a
1063
+ * whole number of triangles, or an index names a vertex its own mesh does not
1064
+ * have (glTF 2.0 3.7.2.1), this throws an `Error` whose message starts with
1065
+ * `MALFORMED_MESH_INPUT` — instead of silently emitting a GLB with those meshes
1066
+ * dropped, a TRIANGLES primitive whose count is not a multiple of 3, or the
1067
+ * out-of-range index copied into the BIN chunk. (The viewer always passes
1068
+ * fully-backed, normal-covered, whole-triangle, in-range arrays, so this only
1069
+ * fires on a caller bug.)
1068
1070
  * @param {Float32Array} positions
1069
1071
  * @param {Float32Array} normals
1070
1072
  * @param {Uint32Array} indices
@@ -1224,14 +1226,22 @@ export class IfcAPI {
1224
1226
  }
1225
1227
  /**
1226
1228
  * Export **JSON-LD** (`@graph` of `ifc:` nodes). Empty `context` ⇒ buildingSMART
1227
- * IFC4 OWL default. `included` is an express-id isolation filter mirroring the
1228
- * OBJ/glTF/STEP exporters (empty ⇒ all entities).
1229
+ * IFC4 OWL default.
1230
+ *
1231
+ * `included` is an express-id isolation filter mirroring `exportObj` /
1232
+ * `exportGlb`, and carries the same null-vs-empty distinction across the wasm
1233
+ * boundary: omit it (`undefined`) for "no isolation filter" (every entity is
1234
+ * emitted); pass an empty `Uint32Array` for "isolation is ACTIVE and currently
1235
+ * matches nothing", which emits an empty `@graph`. Collapsing the two — as a
1236
+ * bare `Uint32Array` parameter would force a caller to do — silently exported
1237
+ * the whole model when a filter matched nothing (#4659, the JSON-LD twin of
1238
+ * #4483/#4484). A non-empty `Uint32Array` is the ordinary allowlist.
1229
1239
  * @param {Uint8Array} content
1230
1240
  * @param {string} context
1231
1241
  * @param {boolean} include_properties
1232
1242
  * @param {boolean} include_quantities
1233
1243
  * @param {boolean} pretty
1234
- * @param {Uint32Array} included
1244
+ * @param {Uint32Array | null} [included]
1235
1245
  * @returns {Uint8Array}
1236
1246
  */
1237
1247
  exportJsonld(content, context, include_properties, include_quantities, pretty, included) {
@@ -1241,51 +1251,9 @@ export class IfcAPI {
1241
1251
  const len0 = WASM_VECTOR_LEN;
1242
1252
  const ptr1 = passStringToWasm0(context, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1243
1253
  const len1 = WASM_VECTOR_LEN;
1244
- const ptr2 = passArray32ToWasm0(included, wasm.__wbindgen_export);
1245
- const len2 = WASM_VECTOR_LEN;
1246
- wasm.ifcapi_exportJsonld(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, include_properties, include_quantities, pretty, ptr2, len2);
1247
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1248
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1249
- var v4 = getArrayU8FromWasm0(r0, r1).slice();
1250
- wasm.__wbindgen_export4(r0, r1 * 1, 1);
1251
- return v4;
1252
- } finally {
1253
- wasm.__wbindgen_add_to_stack_pointer(16);
1254
- }
1255
- }
1256
- /**
1257
- * Package an already-produced **GLB** + georeference into a **KMZ** (`Uint8Array`)
1258
- * for Google Earth: a ZIP of `doc.kml` (a `<Model>` placed at `latitude`/`longitude`/
1259
- * `altitude`) + `model.glb`. `x_axis_abscissa`/`x_axis_ordinate` are the
1260
- * `IfcMapConversion` grid-north components; pass both as `undefined` for heading 0.
1261
- *
1262
- * `altitude_mode` selects the KML vertical placement: `"clampToGround"`
1263
- * (the default when omitted) rests the model on the terrain, ignoring
1264
- * `altitude`; `"absolute"` places the origin at `altitude` metres MSL.
1265
- * Google Earth's terrain already encodes the site elevation, so clamping
1266
- * keeps a wrong/zero/double-counted OrthogonalHeight from floating the
1267
- * model into the sky (#1427); absolute is offered for models whose
1268
- * OrthogonalHeight is a true MSL elevation the user wants honoured.
1269
- * @param {Uint8Array} glb
1270
- * @param {number} latitude
1271
- * @param {number} longitude
1272
- * @param {number} altitude
1273
- * @param {number | null | undefined} x_axis_abscissa
1274
- * @param {number | null | undefined} x_axis_ordinate
1275
- * @param {string} name
1276
- * @param {string | null} [altitude_mode]
1277
- * @returns {Uint8Array}
1278
- */
1279
- exportKmz(glb, latitude, longitude, altitude, x_axis_abscissa, x_axis_ordinate, name, altitude_mode) {
1280
- try {
1281
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1282
- const ptr0 = passArray8ToWasm0(glb, wasm.__wbindgen_export);
1283
- const len0 = WASM_VECTOR_LEN;
1284
- const ptr1 = passStringToWasm0(name, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1285
- const len1 = WASM_VECTOR_LEN;
1286
- var ptr2 = isLikeNone(altitude_mode) ? 0 : passStringToWasm0(altitude_mode, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1254
+ var ptr2 = isLikeNone(included) ? 0 : passArray32ToWasm0(included, wasm.__wbindgen_export);
1287
1255
  var len2 = WASM_VECTOR_LEN;
1288
- wasm.ifcapi_exportKmz(retptr, this.__wbg_ptr, ptr0, len0, latitude, longitude, altitude, !isLikeNone(x_axis_abscissa), isLikeNone(x_axis_abscissa) ? 0 : x_axis_abscissa, !isLikeNone(x_axis_ordinate), isLikeNone(x_axis_ordinate) ? 0 : x_axis_ordinate, ptr1, len1, ptr2, len2);
1256
+ wasm.ifcapi_exportJsonld(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, include_properties, include_quantities, pretty, ptr2, len2);
1289
1257
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1290
1258
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1291
1259
  var v4 = getArrayU8FromWasm0(r0, r1).slice();
@@ -1310,10 +1278,11 @@ export class IfcAPI {
1310
1278
  * Fails CLOSED: when no triangle survives (an empty visible set, or meshes
1311
1279
  * whose only triangles are degenerate and collapse in the vertex dedup)
1312
1280
  * this throws an `Error` whose message starts with `NO_RENDER_GEOMETRY`;
1313
- * a declared vertex/index count running past its buffer throws
1314
- * `MALFORMED_MESH_INPUT`, as `exportGlbFromMeshes` does. Both used to ship
1315
- * as a small "successful" archive: the first around a COLLADA document
1316
- * the 1.4.1 schema rejects, the second with every later mesh missing.
1281
+ * a declared vertex/index count running past its buffer, an index block
1282
+ * that is not whole triangles, or an index outside its mesh throws
1283
+ * `MALFORMED_MESH_INPUT`, exactly as `exportGlbFromMeshes` does. These used
1284
+ * to ship as a "successful" archive: an empty one around a COLLADA
1285
+ * document the 1.4.1 schema rejects, or one with meshes or faces missing.
1317
1286
  * @param {Float32Array} positions
1318
1287
  * @param {Float32Array} normals
1319
1288
  * @param {Uint32Array} indices
@@ -1448,8 +1417,16 @@ export class IfcAPI {
1448
1417
  * is genuinely needed.
1449
1418
  *
1450
1419
  * `schema` is the FILE_SCHEMA label to write (empty ⇒ preserve the source schema).
1451
- * `included` is an express-id allowlist (empty ⇒ whole model); when set, the forward
1452
- * `#`-reference closure is added so the subset never dangles a reference.
1420
+ *
1421
+ * `included` is an express-id allowlist carrying the same null-vs-empty
1422
+ * distinction as `exportObj` / `exportGlb`: omit it (`undefined`) for "no
1423
+ * isolation filter" (whole model); pass an empty `Uint32Array` for "isolation
1424
+ * is ACTIVE and currently matches nothing", which writes a header-only file
1425
+ * with an empty `DATA;` section. Collapsing the two — as a bare `Uint32Array`
1426
+ * parameter would force a caller to do — silently exported the whole model
1427
+ * when a filter matched nothing (#4659, the STEP twin of #4483/#4484). When
1428
+ * set, the forward `#`-reference closure is added so the subset never dangles
1429
+ * a reference.
1453
1430
  * `mutations_json` carries `MutablePropertyView` edits (attribute updates +
1454
1431
  * property-set synthesis); empty ⇒ none. See `export_step_json` for the shape.
1455
1432
  * A non-empty but malformed `mutations_json` throws rather than silently
@@ -1457,7 +1434,7 @@ export class IfcAPI {
1457
1434
  * `exportGlb`'s and `exportMerged`'s fail-closed contract on this same API.
1458
1435
  * @param {Uint8Array} content
1459
1436
  * @param {string} schema
1460
- * @param {Uint32Array} included
1437
+ * @param {Uint32Array | null | undefined} included
1461
1438
  * @param {string} mutations_json
1462
1439
  * @returns {Uint8Array}
1463
1440
  */
@@ -1468,8 +1445,8 @@ export class IfcAPI {
1468
1445
  const len0 = WASM_VECTOR_LEN;
1469
1446
  const ptr1 = passStringToWasm0(schema, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1470
1447
  const len1 = WASM_VECTOR_LEN;
1471
- const ptr2 = passArray32ToWasm0(included, wasm.__wbindgen_export);
1472
- const len2 = WASM_VECTOR_LEN;
1448
+ var ptr2 = isLikeNone(included) ? 0 : passArray32ToWasm0(included, wasm.__wbindgen_export);
1449
+ var len2 = WASM_VECTOR_LEN;
1473
1450
  const ptr3 = passStringToWasm0(mutations_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1474
1451
  const len3 = WASM_VECTOR_LEN;
1475
1452
  wasm.ifcapi_exportStep(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
@@ -1541,7 +1518,9 @@ export class IfcAPI {
1541
1518
  * CANONICAL styles flatten. Returns the exact `styles` event payload the
1542
1519
  * serial path emits. Runs on any worker with `setEntityIndex` installed.
1543
1520
  * Span arguments are `[id, start, len]` triples; `plane_angle_to_radians`
1544
- * comes from the meta event.
1521
+ * comes from the meta event. `orphanColors` / `geomColors` carry exactly
1522
+ * four floats per id in `orphanIds` / `geomIds`; any other length throws
1523
+ * before either column is read.
1545
1524
  * @param {Uint8Array} data
1546
1525
  * @param {Uint32Array} orphan_ids
1547
1526
  * @param {Float32Array} orphan_colors
@@ -2485,18 +2464,34 @@ export class IfcAPI {
2485
2464
  * Idempotent in the sense that repeated calls REPLACE the cache —
2486
2465
  * supports the parser-worker pattern of reusing one IfcAPI across
2487
2466
  * multiple loads with different files.
2467
+ *
2468
+ * Throws when the three columns disagree in length. Every call is a
2469
+ * content swap, a rejected one included: the previous file's index,
2470
+ * content-scoped caches and pipeline diagnostics are dropped before the
2471
+ * error is raised, and a rejected or empty index leaves no index, so the
2472
+ * next batch scans the bytes it is given.
2488
2473
  * @param {Uint32Array} ids
2489
2474
  * @param {Uint32Array} starts
2490
2475
  * @param {Uint32Array} lengths
2491
2476
  */
2492
2477
  setEntityIndex(ids, starts, lengths) {
2493
- const ptr0 = passArray32ToWasm0(ids, wasm.__wbindgen_export);
2494
- const len0 = WASM_VECTOR_LEN;
2495
- const ptr1 = passArray32ToWasm0(starts, wasm.__wbindgen_export);
2496
- const len1 = WASM_VECTOR_LEN;
2497
- const ptr2 = passArray32ToWasm0(lengths, wasm.__wbindgen_export);
2498
- const len2 = WASM_VECTOR_LEN;
2499
- wasm.ifcapi_setEntityIndex(this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
2478
+ try {
2479
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
2480
+ const ptr0 = passArray32ToWasm0(ids, wasm.__wbindgen_export);
2481
+ const len0 = WASM_VECTOR_LEN;
2482
+ const ptr1 = passArray32ToWasm0(starts, wasm.__wbindgen_export);
2483
+ const len1 = WASM_VECTOR_LEN;
2484
+ const ptr2 = passArray32ToWasm0(lengths, wasm.__wbindgen_export);
2485
+ const len2 = WASM_VECTOR_LEN;
2486
+ wasm.ifcapi_setEntityIndex(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2);
2487
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
2488
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
2489
+ if (r1) {
2490
+ throw takeObject(r0);
2491
+ }
2492
+ } finally {
2493
+ wasm.__wbindgen_add_to_stack_pointer(16);
2494
+ }
2500
2495
  }
2501
2496
  /**
2502
2497
  * Install the pre-computed set of type ids that an `IfcRelDefinesByType`
@@ -2941,7 +2936,9 @@ export class MeshCollection {
2941
2936
  return ret === 0 ? undefined : MeshDataJs.__wrap(ret);
2942
2937
  }
2943
2938
  /**
2944
- * Check if RTC offset is significant (>10km)
2939
+ * Check if an RTC offset was applied to these meshes (any non-zero
2940
+ * component). It can be inside 10 km: the placement-bounds fallback
2941
+ * re-bases on the bbox centre when a corner is past 10 km (#4643).
2945
2942
  * @returns {boolean}
2946
2943
  */
2947
2944
  hasRtcOffset() {
@@ -5335,7 +5332,12 @@ export function intersection2d(a, b) {
5335
5332
  *
5336
5333
  * `positions` is flat XYZ; `indices` is flat triangle indices. `axis` is
5337
5334
  * 0/1/2 = x/y/z (the cut axis, WebGL Y-up). Returns `undefined` when the mesh
5338
- * has no triangles or projects to nothing.
5335
+ * has no triangles or projects to nothing: the element has no footprint.
5336
+ *
5337
+ * THROWS when the outline was not computed: an `axis` outside 0..=2, or a
5338
+ * mesh with more valid projected triangles than the overlay budget (50 000).
5339
+ * The viewer's outline provider catches the throw and draws its TypeScript
5340
+ * silhouette for that mesh.
5339
5341
  *
5340
5342
  * ```javascript
5341
5343
  * const outline = meshOutline2d(positions, indices, 1, false); // axis 1 = y
@@ -5353,12 +5355,23 @@ export function intersection2d(a, b) {
5353
5355
  * @returns {MeshOutlineJs | undefined}
5354
5356
  */
5355
5357
  export function meshOutline2d(positions, indices, axis, flipped) {
5356
- const ptr0 = passArrayF32ToWasm0(positions, wasm.__wbindgen_export);
5357
- const len0 = WASM_VECTOR_LEN;
5358
- const ptr1 = passArray32ToWasm0(indices, wasm.__wbindgen_export);
5359
- const len1 = WASM_VECTOR_LEN;
5360
- const ret = wasm.meshOutline2d(ptr0, len0, ptr1, len1, axis, flipped);
5361
- return ret === 0 ? undefined : MeshOutlineJs.__wrap(ret);
5358
+ try {
5359
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
5360
+ const ptr0 = passArrayF32ToWasm0(positions, wasm.__wbindgen_export);
5361
+ const len0 = WASM_VECTOR_LEN;
5362
+ const ptr1 = passArray32ToWasm0(indices, wasm.__wbindgen_export);
5363
+ const len1 = WASM_VECTOR_LEN;
5364
+ wasm.meshOutline2d(retptr, ptr0, len0, ptr1, len1, axis, flipped);
5365
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
5366
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
5367
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
5368
+ if (r2) {
5369
+ throw takeObject(r1);
5370
+ }
5371
+ return r0 === 0 ? undefined : MeshOutlineJs.__wrap(r0);
5372
+ } finally {
5373
+ wasm.__wbindgen_add_to_stack_pointer(16);
5374
+ }
5362
5375
  }
5363
5376
 
5364
5377
  /**
@@ -5404,10 +5417,17 @@ export function resolve2d(a) {
5404
5417
  * meaningless volumes with a plausible `sumErrorRel`, so the closure proof
5405
5418
  * above is the caller's responsibility and not a formality.
5406
5419
  *
5420
+ * Returns `undefined` when the mesh encloses no volume (no triangles survive
5421
+ * the filter above, or the shell is degenerate): there is nothing to split,
5422
+ * and a result for it would report `pieceCount` 1, `sumErrorRel` 0 and
5423
+ * `remainderFailed` false, a perfect split of nothing. A caller that gates
5424
+ * on those numbers must treat `undefined` as "no split", not as "no error".
5425
+ *
5407
5426
  * ```javascript
5408
5427
  * const split = splitMeshByZones(positions, indices, new Float64Array([
5409
5428
  * 0, 0, 0, 10, 10, 10, 0,
5410
5429
  * ]));
5430
+ * if (!split) return; // the mesh encloses no volume
5411
5431
  * for (let i = 0; i < split.pieceCount; i++) {
5412
5432
  * const piece = split.piece(i);
5413
5433
  * // piece.zoneIndex, piece.positions, piece.indices, piece.volume
@@ -5420,7 +5440,7 @@ export function resolve2d(a) {
5420
5440
  * @param {Float64Array} zones
5421
5441
  * @param {Float64Array | null} [footprints]
5422
5442
  * @param {Uint32Array | null} [footprint_counts]
5423
- * @returns {ZoneSplitJs}
5443
+ * @returns {ZoneSplitJs | undefined}
5424
5444
  */
5425
5445
  export function splitMeshByZones(positions, indices, zones, footprints, footprint_counts) {
5426
5446
  const ptr0 = passArrayF64ToWasm0(positions, wasm.__wbindgen_export);
@@ -5434,7 +5454,7 @@ export function splitMeshByZones(positions, indices, zones, footprints, footprin
5434
5454
  var ptr4 = isLikeNone(footprint_counts) ? 0 : passArray32ToWasm0(footprint_counts, wasm.__wbindgen_export);
5435
5455
  var len4 = WASM_VECTOR_LEN;
5436
5456
  const ret = wasm.splitMeshByZones(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4);
5437
- return ZoneSplitJs.__wrap(ret);
5457
+ return ret === 0 ? undefined : ZoneSplitJs.__wrap(ret);
5438
5458
  }
5439
5459
 
5440
5460
  /**
Binary file