@ifc-lite/wasm 7.0.0 → 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/README.md CHANGED
@@ -157,6 +157,22 @@ for source identity, coordinate frames, budgets and host acceptance requirements
157
157
 
158
158
  `IfcAPI.preparePdfVectorPage` validates bounded ordered PDF vector graphics states
159
159
  and preserves source operator identity, calibrated transforms and paint state.
160
- Unsupported content remains an explicit blocker. It emits no IFC entities and
161
- makes no flattened-geometry fidelity claim; see the
162
- [preparation contract](../../docs/api/wasm.md#pdf-vector-graphics-state-preparation).
160
+ Content the planner cannot convert (text, images, clips, transparency,
161
+ patterns, unqualified dashed strokes, curved/hairline strokes, unknown operators) is returned
162
+ as a fidelity report with counts, page extents and visibility, and an
163
+ `exact`/`rasterOnly` verdict; `IfcAPI.planPdfFillAnnotation` plans a partial
164
+ page only when the request quotes that report's digest as the user's
165
+ acceptance. It emits no IFC entities and makes no flattened-geometry fidelity
166
+ claim; see the
167
+ [preparation contract](../../docs/api/wasm.md#pdf-vector-graphics-state-preparation-and-fidelity-report).
168
+ Qualified positive dash patterns on open and closed straight subpaths preserve
169
+ phase, odd-array repetition, subpath reset, joins across vertices and run caps.
170
+ The closing edge participates in the pattern. PDF 1.0–1.7 retain caps where the
171
+ first and last on-dash pieces meet at the closure seam; PDF 2.0 joins them.
172
+ PDF.js's effective format version is bound into the page DTO; an unknown version
173
+ reports `dashVersion`, and a PDF 1.x dash covering the complete closed perimeter
174
+ reports `dashTopology`. Explicit close-path and close-and-stroke operators share
175
+ the versioned behavior.
176
+ Combined fill and dashed-stroke paints can still refuse atomically when
177
+ multiple run boundaries produce crossings outside the current fill-region
178
+ qualifier.
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": "7.0.0",
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
@@ -399,11 +399,15 @@ export class IfcAPI {
399
399
  * per-mesh local). The caller passes exactly the meshes it wants emitted.
400
400
  *
401
401
  * Fails CLOSED: if the declared vertex/index counts run past the flattened
402
- * `positions` / `indices`, there are fewer `index_counts` than meshes, or `normals`
403
- * is empty or too short to cover every vertex, this throws an `Error` whose message
404
- * starts with `MALFORMED_MESH_INPUT` — instead of silently emitting a GLB with those
405
- * meshes dropped. (The viewer always passes fully-backed, normal-covered arrays, so
406
- * this only fires on a caller bug.)
402
+ * `positions` / `indices`, there are fewer `index_counts` than meshes, `normals`
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.)
407
411
  */
408
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;
409
413
  /**
@@ -452,25 +456,18 @@ export class IfcAPI {
452
456
  exportJson(content: Uint8Array, pretty: boolean, include_properties: boolean, include_quantities: boolean): Uint8Array;
453
457
  /**
454
458
  * Export **JSON-LD** (`@graph` of `ifc:` nodes). Empty `context` ⇒ buildingSMART
455
- * IFC4 OWL default. `included` is an express-id isolation filter mirroring the
456
- * OBJ/glTF/STEP exporters (empty ⇒ all entities).
457
- */
458
- exportJsonld(content: Uint8Array, context: string, include_properties: boolean, include_quantities: boolean, pretty: boolean, included: Uint32Array): Uint8Array;
459
- /**
460
- * Package an already-produced **GLB** + georeference into a **KMZ** (`Uint8Array`)
461
- * for Google Earth: a ZIP of `doc.kml` (a `<Model>` placed at `latitude`/`longitude`/
462
- * `altitude`) + `model.glb`. `x_axis_abscissa`/`x_axis_ordinate` are the
463
- * `IfcMapConversion` grid-north components; pass both as `undefined` for heading 0.
459
+ * IFC4 OWL default.
464
460
  *
465
- * `altitude_mode` selects the KML vertical placement: `"clampToGround"`
466
- * (the default when omitted) rests the model on the terrain, ignoring
467
- * `altitude`; `"absolute"` places the origin at `altitude` metres MSL.
468
- * Google Earth's terrain already encodes the site elevation, so clamping
469
- * keeps a wrong/zero/double-counted OrthogonalHeight from floating the
470
- * model into the sky (#1427); absolute is offered for models whose
471
- * 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.
472
469
  */
473
- 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;
474
471
  /**
475
472
  * Build a Google-Earth-ready **KMZ** (`Uint8Array`) straight from the viewer's
476
473
  * already-produced meshes — the working path (#1427). The model is embedded as
@@ -482,6 +479,15 @@ export class IfcAPI {
482
479
  * `altitude_mode` (`"clampToGround"` default ⇒ rest on terrain, ignoring
483
480
  * `altitude`; `"absolute"` ⇒ place at `altitude` metres MSL) selects the
484
481
  * KML vertical placement (#1427).
482
+ *
483
+ * Fails CLOSED: when no triangle survives (an empty visible set, or meshes
484
+ * whose only triangles are degenerate and collapse in the vertex dedup)
485
+ * this throws an `Error` whose message starts with `NO_RENDER_GEOMETRY`;
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.
485
491
  */
486
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;
487
493
  /**
@@ -521,15 +527,23 @@ export class IfcAPI {
521
527
  * is genuinely needed.
522
528
  *
523
529
  * `schema` is the FILE_SCHEMA label to write (empty ⇒ preserve the source schema).
524
- * `included` is an express-id allowlist (empty ⇒ whole model); when set, the forward
525
- * `#`-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.
526
540
  * `mutations_json` carries `MutablePropertyView` edits (attribute updates +
527
541
  * property-set synthesis); empty ⇒ none. See `export_step_json` for the shape.
528
542
  * A non-empty but malformed `mutations_json` throws rather than silently
529
543
  * exporting the model with none of the caller's edits applied — mirrors
530
544
  * `exportGlb`'s and `exportMerged`'s fail-closed contract on this same API.
531
545
  */
532
- 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;
533
547
  /**
534
548
  * Export **OpenUSD** (`.usda` ASCII): a real Z-up USD stage — spatial hierarchy of
535
549
  * `Xform` prims, `UsdGeomMesh` geometry, `UsdPreviewSurface` materials, IFC
@@ -565,7 +579,9 @@ export class IfcAPI {
565
579
  * CANONICAL styles flatten. Returns the exact `styles` event payload the
566
580
  * serial path emits. Runs on any worker with `setEntityIndex` installed.
567
581
  * Span arguments are `[id, start, len]` triples; `plane_angle_to_radians`
568
- * 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.
569
585
  */
570
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;
571
587
  /**
@@ -667,13 +683,23 @@ export class IfcAPI {
667
683
  */
668
684
  planPageAppearance(content: Uint8Array, request_json: string, rgba: Uint8Array): Uint8Array;
669
685
  /**
670
- * Plan a complete opaque polygonal PDF fill page as canonical IfcAnnotation
671
- * geometry. Painted strokes, curves and unsupported states refuse atomically.
686
+ * Plan an opaque polygonal PDF fill page as canonical IfcAnnotation
687
+ * geometry with a provenance property set. An exact page plans directly; a
688
+ * page with visible omissions needs the accepted fidelity report digest.
672
689
  */
673
690
  planPdfFillAnnotation(source: Uint8Array, request_json: string): Uint8Array;
674
691
  /**
675
- * Prepare bounded ordered PDF vector graphics states. No IFC entities or
676
- * flattened geometry are produced; unsupported content prevents qualification.
692
+ * Registered RGB point-cloud observations (#4381). `request_json.source`
693
+ * is `{kind:'points', …}`; `positions` (3n f64, source-frame metres) and
694
+ * `colors` (3n RGB8) are the payload, `normals` (3n f32, oriented) and
695
+ * `stations` (n indices into `source.viewpoints`) are empty when absent.
696
+ * `rgba` carries only the target's existing rasters. Same output as
697
+ * `planMeshTransfer`; `transfer.source` records the orientation used.
698
+ */
699
+ planPointTransfer(content: Uint8Array, request_json: string, rgba: Uint8Array, positions: Float64Array, colors: Uint8Array, normals: Float32Array, stations: Uint32Array): Uint8Array;
700
+ /**
701
+ * Prepare bounded ordered PDF vector graphics states and the page fidelity
702
+ * report (convertible paths, omissions with extent, exact/raster-only).
677
703
  */
678
704
  preparePdfVectorPage(request_json: string): Uint8Array;
679
705
  /**
@@ -843,6 +869,12 @@ export class IfcAPI {
843
869
  * Idempotent in the sense that repeated calls REPLACE the cache —
844
870
  * supports the parser-worker pattern of reusing one IfcAPI across
845
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.
846
878
  */
847
879
  setEntityIndex(ids: Uint32Array, starts: Uint32Array, lengths: Uint32Array): void;
848
880
  /**
@@ -1009,7 +1041,9 @@ export class MeshCollection {
1009
1041
  */
1010
1042
  get(index: number): MeshDataJs | undefined;
1011
1043
  /**
1012
- * 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).
1013
1047
  */
1014
1048
  hasRtcOffset(): boolean;
1015
1049
  /**
@@ -1921,7 +1955,12 @@ export function intersection2d(a: Contours2D, b: Contours2D): Contours2D;
1921
1955
  *
1922
1956
  * `positions` is flat XYZ; `indices` is flat triangle indices. `axis` is
1923
1957
  * 0/1/2 = x/y/z (the cut axis, WebGL Y-up). Returns `undefined` when the mesh
1924
- * 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.
1925
1964
  *
1926
1965
  * ```javascript
1927
1966
  * const outline = meshOutline2d(positions, indices, 1, false); // axis 1 = y
@@ -1972,10 +2011,17 @@ export function resolve2d(a: Contours2D): Contours2D;
1972
2011
  * meaningless volumes with a plausible `sumErrorRel`, so the closure proof
1973
2012
  * above is the caller's responsibility and not a formality.
1974
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
+ *
1975
2020
  * ```javascript
1976
2021
  * const split = splitMeshByZones(positions, indices, new Float64Array([
1977
2022
  * 0, 0, 0, 10, 10, 10, 0,
1978
2023
  * ]));
2024
+ * if (!split) return; // the mesh encloses no volume
1979
2025
  * for (let i = 0; i < split.pieceCount; i++) {
1980
2026
  * const piece = split.piece(i);
1981
2027
  * // piece.zoneIndex, piece.positions, piece.indices, piece.volume
@@ -1984,7 +2030,7 @@ export function resolve2d(a: Contours2D): Contours2D;
1984
2030
  * split.free();
1985
2031
  * ```
1986
2032
  */
1987
- 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;
1988
2034
 
1989
2035
  /**
1990
2036
  * `a ∪ b`.
@@ -2088,7 +2134,6 @@ export interface InitOutput {
2088
2134
  readonly ifcapi_exportIfcx: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
2089
2135
  readonly ifcapi_exportJson: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
2090
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;
2091
- 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;
2092
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;
2093
2138
  readonly ifcapi_exportMerged: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
2094
2139
  readonly ifcapi_exportObj: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
@@ -2111,6 +2156,7 @@ export interface InitOutput {
2111
2156
  readonly ifcapi_planMeshTransfer: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
2112
2157
  readonly ifcapi_planPageAppearance: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number) => void;
2113
2158
  readonly ifcapi_planPdfFillAnnotation: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
2159
+ readonly ifcapi_planPointTransfer: (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) => void;
2114
2160
  readonly ifcapi_preparePdfVectorPage: (a: number, b: number, c: number, d: number) => void;
2115
2161
  readonly ifcapi_processGeometryBatch: (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, b1: number) => number;
2116
2162
  readonly ifcapi_processGeometryBatchFromSource: (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) => number;
@@ -2126,7 +2172,7 @@ export interface InitOutput {
2126
2172
  readonly ifcapi_scanEntityIndexShardFromSource: (a: number, b: number, c: number) => number;
2127
2173
  readonly ifcapi_scanGeometryEntitiesFast: (a: number, b: number, c: number) => number;
2128
2174
  readonly ifcapi_setComputeGeometryHashes: (a: number, b: number, c: number) => void;
2129
- 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;
2130
2176
  readonly ifcapi_setInstantiatedTypeIds: (a: number, b: number, c: number) => void;
2131
2177
  readonly ifcapi_setMappedInstancePlan: (a: number, b: number, c: number) => void;
2132
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;
@@ -2139,7 +2185,7 @@ export interface InitOutput {
2139
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;
2140
2186
  readonly ifcapi_version: (a: number, b: number) => void;
2141
2187
  readonly intersection2d: (a: number, b: number) => number;
2142
- 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;
2143
2189
  readonly meshcollection_buildingRotation: (a: number, b: number) => void;
2144
2190
  readonly meshcollection_diagnostics: (a: number) => number;
2145
2191
  readonly meshcollection_geometryAabbValues: (a: number) => number;
package/pkg/ifc-lite.js CHANGED
@@ -1058,11 +1058,15 @@ export class IfcAPI {
1058
1058
  * per-mesh local). The caller passes exactly the meshes it wants emitted.
1059
1059
  *
1060
1060
  * Fails CLOSED: if the declared vertex/index counts run past the flattened
1061
- * `positions` / `indices`, there are fewer `index_counts` than meshes, or `normals`
1062
- * is empty or too short to cover every vertex, this throws an `Error` whose message
1063
- * starts with `MALFORMED_MESH_INPUT` — instead of silently emitting a GLB with those
1064
- * meshes dropped. (The viewer always passes fully-backed, normal-covered arrays, so
1065
- * this only fires on a caller bug.)
1061
+ * `positions` / `indices`, there are fewer `index_counts` than meshes, `normals`
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.)
1066
1070
  * @param {Float32Array} positions
1067
1071
  * @param {Float32Array} normals
1068
1072
  * @param {Uint32Array} indices
@@ -1222,14 +1226,22 @@ export class IfcAPI {
1222
1226
  }
1223
1227
  /**
1224
1228
  * Export **JSON-LD** (`@graph` of `ifc:` nodes). Empty `context` ⇒ buildingSMART
1225
- * IFC4 OWL default. `included` is an express-id isolation filter mirroring the
1226
- * 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.
1227
1239
  * @param {Uint8Array} content
1228
1240
  * @param {string} context
1229
1241
  * @param {boolean} include_properties
1230
1242
  * @param {boolean} include_quantities
1231
1243
  * @param {boolean} pretty
1232
- * @param {Uint32Array} included
1244
+ * @param {Uint32Array | null} [included]
1233
1245
  * @returns {Uint8Array}
1234
1246
  */
1235
1247
  exportJsonld(content, context, include_properties, include_quantities, pretty, included) {
@@ -1239,51 +1251,9 @@ export class IfcAPI {
1239
1251
  const len0 = WASM_VECTOR_LEN;
1240
1252
  const ptr1 = passStringToWasm0(context, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1241
1253
  const len1 = WASM_VECTOR_LEN;
1242
- const ptr2 = passArray32ToWasm0(included, wasm.__wbindgen_export);
1243
- const len2 = WASM_VECTOR_LEN;
1244
- wasm.ifcapi_exportJsonld(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, include_properties, include_quantities, pretty, ptr2, len2);
1245
- var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1246
- var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1247
- var v4 = getArrayU8FromWasm0(r0, r1).slice();
1248
- wasm.__wbindgen_export4(r0, r1 * 1, 1);
1249
- return v4;
1250
- } finally {
1251
- wasm.__wbindgen_add_to_stack_pointer(16);
1252
- }
1253
- }
1254
- /**
1255
- * Package an already-produced **GLB** + georeference into a **KMZ** (`Uint8Array`)
1256
- * for Google Earth: a ZIP of `doc.kml` (a `<Model>` placed at `latitude`/`longitude`/
1257
- * `altitude`) + `model.glb`. `x_axis_abscissa`/`x_axis_ordinate` are the
1258
- * `IfcMapConversion` grid-north components; pass both as `undefined` for heading 0.
1259
- *
1260
- * `altitude_mode` selects the KML vertical placement: `"clampToGround"`
1261
- * (the default when omitted) rests the model on the terrain, ignoring
1262
- * `altitude`; `"absolute"` places the origin at `altitude` metres MSL.
1263
- * Google Earth's terrain already encodes the site elevation, so clamping
1264
- * keeps a wrong/zero/double-counted OrthogonalHeight from floating the
1265
- * model into the sky (#1427); absolute is offered for models whose
1266
- * OrthogonalHeight is a true MSL elevation the user wants honoured.
1267
- * @param {Uint8Array} glb
1268
- * @param {number} latitude
1269
- * @param {number} longitude
1270
- * @param {number} altitude
1271
- * @param {number | null | undefined} x_axis_abscissa
1272
- * @param {number | null | undefined} x_axis_ordinate
1273
- * @param {string} name
1274
- * @param {string | null} [altitude_mode]
1275
- * @returns {Uint8Array}
1276
- */
1277
- exportKmz(glb, latitude, longitude, altitude, x_axis_abscissa, x_axis_ordinate, name, altitude_mode) {
1278
- try {
1279
- const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1280
- const ptr0 = passArray8ToWasm0(glb, wasm.__wbindgen_export);
1281
- const len0 = WASM_VECTOR_LEN;
1282
- const ptr1 = passStringToWasm0(name, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1283
- const len1 = WASM_VECTOR_LEN;
1284
- 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);
1285
1255
  var len2 = WASM_VECTOR_LEN;
1286
- 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);
1287
1257
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1288
1258
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1289
1259
  var v4 = getArrayU8FromWasm0(r0, r1).slice();
@@ -1304,6 +1274,15 @@ export class IfcAPI {
1304
1274
  * `altitude_mode` (`"clampToGround"` default ⇒ rest on terrain, ignoring
1305
1275
  * `altitude`; `"absolute"` ⇒ place at `altitude` metres MSL) selects the
1306
1276
  * KML vertical placement (#1427).
1277
+ *
1278
+ * Fails CLOSED: when no triangle survives (an empty visible set, or meshes
1279
+ * whose only triangles are degenerate and collapse in the vertex dedup)
1280
+ * this throws an `Error` whose message starts with `NO_RENDER_GEOMETRY`;
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.
1307
1286
  * @param {Float32Array} positions
1308
1287
  * @param {Float32Array} normals
1309
1288
  * @param {Uint32Array} indices
@@ -1344,6 +1323,11 @@ export class IfcAPI {
1344
1323
  wasm.ifcapi_exportKmzFromMeshes(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6, 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, ptr7, len7, ptr8, len8);
1345
1324
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1346
1325
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1326
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1327
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
1328
+ if (r3) {
1329
+ throw takeObject(r2);
1330
+ }
1347
1331
  var v10 = getArrayU8FromWasm0(r0, r1).slice();
1348
1332
  wasm.__wbindgen_export4(r0, r1 * 1, 1);
1349
1333
  return v10;
@@ -1433,8 +1417,16 @@ export class IfcAPI {
1433
1417
  * is genuinely needed.
1434
1418
  *
1435
1419
  * `schema` is the FILE_SCHEMA label to write (empty ⇒ preserve the source schema).
1436
- * `included` is an express-id allowlist (empty ⇒ whole model); when set, the forward
1437
- * `#`-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.
1438
1430
  * `mutations_json` carries `MutablePropertyView` edits (attribute updates +
1439
1431
  * property-set synthesis); empty ⇒ none. See `export_step_json` for the shape.
1440
1432
  * A non-empty but malformed `mutations_json` throws rather than silently
@@ -1442,7 +1434,7 @@ export class IfcAPI {
1442
1434
  * `exportGlb`'s and `exportMerged`'s fail-closed contract on this same API.
1443
1435
  * @param {Uint8Array} content
1444
1436
  * @param {string} schema
1445
- * @param {Uint32Array} included
1437
+ * @param {Uint32Array | null | undefined} included
1446
1438
  * @param {string} mutations_json
1447
1439
  * @returns {Uint8Array}
1448
1440
  */
@@ -1453,8 +1445,8 @@ export class IfcAPI {
1453
1445
  const len0 = WASM_VECTOR_LEN;
1454
1446
  const ptr1 = passStringToWasm0(schema, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1455
1447
  const len1 = WASM_VECTOR_LEN;
1456
- const ptr2 = passArray32ToWasm0(included, wasm.__wbindgen_export);
1457
- const len2 = WASM_VECTOR_LEN;
1448
+ var ptr2 = isLikeNone(included) ? 0 : passArray32ToWasm0(included, wasm.__wbindgen_export);
1449
+ var len2 = WASM_VECTOR_LEN;
1458
1450
  const ptr3 = passStringToWasm0(mutations_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1459
1451
  const len3 = WASM_VECTOR_LEN;
1460
1452
  wasm.ifcapi_exportStep(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3);
@@ -1526,7 +1518,9 @@ export class IfcAPI {
1526
1518
  * CANONICAL styles flatten. Returns the exact `styles` event payload the
1527
1519
  * serial path emits. Runs on any worker with `setEntityIndex` installed.
1528
1520
  * Span arguments are `[id, start, len]` triples; `plane_angle_to_radians`
1529
- * 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.
1530
1524
  * @param {Uint8Array} data
1531
1525
  * @param {Uint32Array} orphan_ids
1532
1526
  * @param {Float32Array} orphan_colors
@@ -1898,8 +1892,9 @@ export class IfcAPI {
1898
1892
  }
1899
1893
  }
1900
1894
  /**
1901
- * Plan a complete opaque polygonal PDF fill page as canonical IfcAnnotation
1902
- * geometry. Painted strokes, curves and unsupported states refuse atomically.
1895
+ * Plan an opaque polygonal PDF fill page as canonical IfcAnnotation
1896
+ * geometry with a provenance property set. An exact page plans directly; a
1897
+ * page with visible omissions needs the accepted fidelity report digest.
1903
1898
  * @param {Uint8Array} source
1904
1899
  * @param {string} request_json
1905
1900
  * @returns {Uint8Array}
@@ -1927,8 +1922,56 @@ export class IfcAPI {
1927
1922
  }
1928
1923
  }
1929
1924
  /**
1930
- * Prepare bounded ordered PDF vector graphics states. No IFC entities or
1931
- * flattened geometry are produced; unsupported content prevents qualification.
1925
+ * Registered RGB point-cloud observations (#4381). `request_json.source`
1926
+ * is `{kind:'points', …}`; `positions` (3n f64, source-frame metres) and
1927
+ * `colors` (3n RGB8) are the payload, `normals` (3n f32, oriented) and
1928
+ * `stations` (n indices into `source.viewpoints`) are empty when absent.
1929
+ * `rgba` carries only the target's existing rasters. Same output as
1930
+ * `planMeshTransfer`; `transfer.source` records the orientation used.
1931
+ * @param {Uint8Array} content
1932
+ * @param {string} request_json
1933
+ * @param {Uint8Array} rgba
1934
+ * @param {Float64Array} positions
1935
+ * @param {Uint8Array} colors
1936
+ * @param {Float32Array} normals
1937
+ * @param {Uint32Array} stations
1938
+ * @returns {Uint8Array}
1939
+ */
1940
+ planPointTransfer(content, request_json, rgba, positions, colors, normals, stations) {
1941
+ try {
1942
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1943
+ const ptr0 = passArray8ToWasm0(content, wasm.__wbindgen_export);
1944
+ const len0 = WASM_VECTOR_LEN;
1945
+ const ptr1 = passStringToWasm0(request_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
1946
+ const len1 = WASM_VECTOR_LEN;
1947
+ const ptr2 = passArray8ToWasm0(rgba, wasm.__wbindgen_export);
1948
+ const len2 = WASM_VECTOR_LEN;
1949
+ const ptr3 = passArrayF64ToWasm0(positions, wasm.__wbindgen_export);
1950
+ const len3 = WASM_VECTOR_LEN;
1951
+ const ptr4 = passArray8ToWasm0(colors, wasm.__wbindgen_export);
1952
+ const len4 = WASM_VECTOR_LEN;
1953
+ const ptr5 = passArrayF32ToWasm0(normals, wasm.__wbindgen_export);
1954
+ const len5 = WASM_VECTOR_LEN;
1955
+ const ptr6 = passArray32ToWasm0(stations, wasm.__wbindgen_export);
1956
+ const len6 = WASM_VECTOR_LEN;
1957
+ wasm.ifcapi_planPointTransfer(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, ptr5, len5, ptr6, len6);
1958
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1959
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1960
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1961
+ var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true);
1962
+ if (r3) {
1963
+ throw takeObject(r2);
1964
+ }
1965
+ var v8 = getArrayU8FromWasm0(r0, r1).slice();
1966
+ wasm.__wbindgen_export4(r0, r1 * 1, 1);
1967
+ return v8;
1968
+ } finally {
1969
+ wasm.__wbindgen_add_to_stack_pointer(16);
1970
+ }
1971
+ }
1972
+ /**
1973
+ * Prepare bounded ordered PDF vector graphics states and the page fidelity
1974
+ * report (convertible paths, omissions with extent, exact/raster-only).
1932
1975
  * @param {string} request_json
1933
1976
  * @returns {Uint8Array}
1934
1977
  */
@@ -2421,18 +2464,34 @@ export class IfcAPI {
2421
2464
  * Idempotent in the sense that repeated calls REPLACE the cache —
2422
2465
  * supports the parser-worker pattern of reusing one IfcAPI across
2423
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.
2424
2473
  * @param {Uint32Array} ids
2425
2474
  * @param {Uint32Array} starts
2426
2475
  * @param {Uint32Array} lengths
2427
2476
  */
2428
2477
  setEntityIndex(ids, starts, lengths) {
2429
- const ptr0 = passArray32ToWasm0(ids, wasm.__wbindgen_export);
2430
- const len0 = WASM_VECTOR_LEN;
2431
- const ptr1 = passArray32ToWasm0(starts, wasm.__wbindgen_export);
2432
- const len1 = WASM_VECTOR_LEN;
2433
- const ptr2 = passArray32ToWasm0(lengths, wasm.__wbindgen_export);
2434
- const len2 = WASM_VECTOR_LEN;
2435
- 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
+ }
2436
2495
  }
2437
2496
  /**
2438
2497
  * Install the pre-computed set of type ids that an `IfcRelDefinesByType`
@@ -2877,7 +2936,9 @@ export class MeshCollection {
2877
2936
  return ret === 0 ? undefined : MeshDataJs.__wrap(ret);
2878
2937
  }
2879
2938
  /**
2880
- * 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).
2881
2942
  * @returns {boolean}
2882
2943
  */
2883
2944
  hasRtcOffset() {
@@ -5271,7 +5332,12 @@ export function intersection2d(a, b) {
5271
5332
  *
5272
5333
  * `positions` is flat XYZ; `indices` is flat triangle indices. `axis` is
5273
5334
  * 0/1/2 = x/y/z (the cut axis, WebGL Y-up). Returns `undefined` when the mesh
5274
- * 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.
5275
5341
  *
5276
5342
  * ```javascript
5277
5343
  * const outline = meshOutline2d(positions, indices, 1, false); // axis 1 = y
@@ -5289,12 +5355,23 @@ export function intersection2d(a, b) {
5289
5355
  * @returns {MeshOutlineJs | undefined}
5290
5356
  */
5291
5357
  export function meshOutline2d(positions, indices, axis, flipped) {
5292
- const ptr0 = passArrayF32ToWasm0(positions, wasm.__wbindgen_export);
5293
- const len0 = WASM_VECTOR_LEN;
5294
- const ptr1 = passArray32ToWasm0(indices, wasm.__wbindgen_export);
5295
- const len1 = WASM_VECTOR_LEN;
5296
- const ret = wasm.meshOutline2d(ptr0, len0, ptr1, len1, axis, flipped);
5297
- 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
+ }
5298
5375
  }
5299
5376
 
5300
5377
  /**
@@ -5340,10 +5417,17 @@ export function resolve2d(a) {
5340
5417
  * meaningless volumes with a plausible `sumErrorRel`, so the closure proof
5341
5418
  * above is the caller's responsibility and not a formality.
5342
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
+ *
5343
5426
  * ```javascript
5344
5427
  * const split = splitMeshByZones(positions, indices, new Float64Array([
5345
5428
  * 0, 0, 0, 10, 10, 10, 0,
5346
5429
  * ]));
5430
+ * if (!split) return; // the mesh encloses no volume
5347
5431
  * for (let i = 0; i < split.pieceCount; i++) {
5348
5432
  * const piece = split.piece(i);
5349
5433
  * // piece.zoneIndex, piece.positions, piece.indices, piece.volume
@@ -5356,7 +5440,7 @@ export function resolve2d(a) {
5356
5440
  * @param {Float64Array} zones
5357
5441
  * @param {Float64Array | null} [footprints]
5358
5442
  * @param {Uint32Array | null} [footprint_counts]
5359
- * @returns {ZoneSplitJs}
5443
+ * @returns {ZoneSplitJs | undefined}
5360
5444
  */
5361
5445
  export function splitMeshByZones(positions, indices, zones, footprints, footprint_counts) {
5362
5446
  const ptr0 = passArrayF64ToWasm0(positions, wasm.__wbindgen_export);
@@ -5370,7 +5454,7 @@ export function splitMeshByZones(positions, indices, zones, footprints, footprin
5370
5454
  var ptr4 = isLikeNone(footprint_counts) ? 0 : passArray32ToWasm0(footprint_counts, wasm.__wbindgen_export);
5371
5455
  var len4 = WASM_VECTOR_LEN;
5372
5456
  const ret = wasm.splitMeshByZones(ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4);
5373
- return ZoneSplitJs.__wrap(ret);
5457
+ return ret === 0 ? undefined : ZoneSplitJs.__wrap(ret);
5374
5458
  }
5375
5459
 
5376
5460
  /**
Binary file