@ifc-lite/wasm 2.8.0 → 2.9.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.8.0",
8
+ "version": "2.9.0",
9
9
  "license": "MPL-2.0",
10
10
  "repository": {
11
11
  "type": "git",
package/pkg/ifc-lite.d.ts CHANGED
@@ -91,7 +91,7 @@ export class IfcAPI {
91
91
  * Process geometry for a subset of pre-scanned entities.
92
92
  * Takes raw bytes and pre-pass data from buildPrePassOnce.
93
93
  */
94
- 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): MeshCollection;
94
+ 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;
95
95
  /**
96
96
  * Streaming pre-pass: emits geometry jobs in chunks via a JS callback
97
97
  * instead of waiting for the full file scan to complete.
@@ -117,7 +117,7 @@ export class IfcAPI {
117
117
  * `{ type: "jobs", jobs: Uint32Array }` // [id, start, end] triples
118
118
  * `{ type: "complete", totalJobs }`
119
119
  */
120
- buildPrePassStreaming(data: Uint8Array, on_event: Function, chunk_size: number): any;
120
+ buildPrePassStreaming(data: Uint8Array, on_event: Function, chunk_size: number, disabled_type_names: string[] | null | undefined, skip_type_geometry: boolean): any;
121
121
  /**
122
122
  * Parse the file and return structured per-axis data (tag + endpoints) in
123
123
  * the renderer's Y-up world space (RTC-subtracted, metres). Use this when
@@ -306,9 +306,19 @@ export class MeshCollection {
306
306
  */
307
307
  hasRtcOffset(): boolean;
308
308
  /**
309
- * Get mesh at index
309
+ * Get mesh at index (clones — non-destructive). Prefer `takeMesh` on the
310
+ * hot streaming path; this stays for callers that read meshes more than once.
310
311
  */
311
312
  get(index: number): MeshDataJs | undefined;
313
+ /**
314
+ * #1097 perf: MOVE the mesh at `index` out of the collection (the Vec
315
+ * buffers are `std::mem::take`-n, leaving an empty stub). The streaming
316
+ * worker reads each mesh exactly once, so moving avoids the full vertex-
317
+ * data clone `get` pays — one fewer copy of positions/normals/indices/uvs/
318
+ * texture per mesh (the JS getters still do the single Rust→JS copy). Calling
319
+ * it twice for the same index yields the second call an empty mesh.
320
+ */
321
+ takeMesh(index: number): MeshDataJs | undefined;
312
322
  /**
313
323
  * Get RTC offset X (for converting local coords back to world coords)
314
324
  * Add this to local X coordinates to get world X coordinates
@@ -413,6 +423,12 @@ export class MeshDataJs {
413
423
  * Get color as [r, g, b, a] array
414
424
  */
415
425
  readonly color: Float32Array;
426
+ /**
427
+ * Per-element local-frame origin (Float64Array[3], WebGL Y-up, metres):
428
+ * world position of vertex i = `origin + positions[3i..3i+3]`. Returns
429
+ * [0,0,0] when positions are absolute (legacy / local frame off).
430
+ */
431
+ readonly origin: Float64Array;
416
432
  /**
417
433
  * Get indices as Uint32Array (copy to JS)
418
434
  */
@@ -538,10 +554,53 @@ export class SpacePlateHandle {
538
554
  * surviving room.
539
555
  */
540
556
  mergeFaces(edge: number): any;
557
+ /**
558
+ * The face outline offset to a wall boundary, as flat `[x0, y0, …]`: each
559
+ * edge is moved by its own wall's half-thickness — inward when `inset`
560
+ * (the net / inner face), outward otherwise (the gross / outer face).
561
+ * Shared room↔room edges are pinned when pushing outward. Falls back to the
562
+ * centreline outline when no offset applies — so it's always a sane ring.
563
+ * (For a `center` boundary just use `faceOutline`.)
564
+ */
565
+ netOutline(face: number, inset: boolean): Float64Array;
566
+ /**
567
+ * Remove a wall edge, choosing the right semantics from its two faces:
568
+ * two real rooms → union them; a bridge / spur / outer-only wall → delete
569
+ * it and auto-clean the orphaned inner lines and nodes it leaves; a real
570
+ * enclosing wall (room ↔ exterior) → rejected (`BordersExterior`). This is
571
+ * the "remove this wall and tidy up" affordance for the orphan cruft the
572
+ * non-destructive wall arrangement leaves behind. Returns the rooms it
573
+ * changed (empty if the edge bounded no room).
574
+ */
575
+ removeEdge(edge: number): any;
541
576
  /**
542
577
  * Flat outline `[x0, y0, x1, y1, …]` of a face (no repeated closing vertex).
543
578
  */
544
579
  faceOutline(face: number): Float64Array;
580
+ /**
581
+ * Face-based gap-room boundary as flat `[x0, y0, …]`: each edge pushed
582
+ * OUTWARD (into the wall) by `factor × the source wall's half-thickness`.
583
+ * `0` → net (the gap / inner faces); `1` → centre axis (½ thickness, the
584
+ * editable node line on the wall mid); `2` → gross outer face.
585
+ */
586
+ gapBoundary(face: number, factor: number): Float64Array;
587
+ /**
588
+ * Dissolve a degree-2 vertex, welding its two edges into one straight
589
+ * edge between the neighbours — the inverse of `splitEdge`, and the
590
+ * "delete this corner / node" affordance. Returns the rooms it changed.
591
+ * Rejects a wall junction (degree ≥ 3) or a weld that would duplicate an
592
+ * edge.
593
+ */
594
+ dissolveVertex(v: number): any;
595
+ /**
596
+ * FACE-BASED build: rooms are the gaps between wall footprint rectangles.
597
+ * `rectCoords` is flat `[x0, y0, x1, y1, x2, y2, x3, y3, …]` — 8 f64 per wall
598
+ * (its 4 plan-rectangle corners, CCW). A bounded arrangement face is a room
599
+ * only if its centroid is outside every rectangle (a gap, not a wall
600
+ * interior). The room outline IS the net (inner-face) area; `gapBoundary`
601
+ * gives the centre axis (½ thickness) and the gross outer face.
602
+ */
603
+ static fromWallRects(rect_coords: Float64Array, snap_tolerance: number, min_area: number): SpacePlateHandle;
545
604
  /**
546
605
  * The room on the far side of a half-edge (its twin's face), or
547
606
  * `undefined`. O(1) — the "who's across this wall" query.
@@ -566,9 +625,27 @@ export class SpacePlateHandle {
566
625
  *
567
626
  * `segCoords`: `[ax, ay, bx, by, …]` (length a multiple of 4).
568
627
  * `segSources`: one `i32` per segment, `-1` for none.
628
+ * `segHalfThickness`: one `f64` per segment — half the wall's thickness in
629
+ * metres, carried onto the derived edges for `netOutline`. Pass an empty
630
+ * array (or all zeros) when thickness is unknown (centreline only).
569
631
  * `snapTolerance` / `minArea`: pass `<= 0` to take the defaults.
570
632
  */
571
- constructor(seg_coords: Float64Array, seg_sources: Int32Array, snap_tolerance: number, min_area: number);
633
+ constructor(seg_coords: Float64Array, seg_sources: Int32Array, seg_half_thickness: Float64Array, snap_tolerance: number, min_area: number);
634
+ /**
635
+ * Sweep the whole plate clean: remove dangling spur walls, isolated nodes,
636
+ * and redundant collinear nodes — the "clean up orphans" / eraser action.
637
+ * Area-neutral and idempotent. Returns how many topology elements were
638
+ * pruned (0 = the plate was already clean); the caller re-renders via
639
+ * `snapshot` like any other edit.
640
+ */
641
+ prune(): number;
642
+ /**
643
+ * Author a new room from a flat ring `[x0, y0, x1, y1, …]` (no repeated
644
+ * closing vertex). `source` `-1` marks a user-drawn room. Winding is
645
+ * normalised to CCW; returns the new room patch. The room is its own
646
+ * connected component — it does not merge into existing topology.
647
+ */
648
+ addFace(coords: Float64Array, source: number): any;
572
649
  /**
573
650
  * Face ids of every live room.
574
651
  */
@@ -835,7 +912,7 @@ export interface InitOutput {
835
912
  readonly gridaxisjs_start: (a: number) => number;
836
913
  readonly gridaxisjs_tag: (a: number, b: number) => void;
837
914
  readonly ifcapi_buildPrePassOnce: (a: number, b: number, c: number) => number;
838
- readonly ifcapi_buildPrePassStreaming: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
915
+ readonly ifcapi_buildPrePassStreaming: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
839
916
  readonly ifcapi_clearPrePassCache: (a: number) => void;
840
917
  readonly ifcapi_extractProfiles: (a: number, b: number, c: number, d: number) => number;
841
918
  readonly ifcapi_getMemory: (a: number) => number;
@@ -845,7 +922,7 @@ export interface InitOutput {
845
922
  readonly ifcapi_parseGridAxes: (a: number, b: number, c: number) => number;
846
923
  readonly ifcapi_parseGridLines: (a: number, b: number, c: number) => number;
847
924
  readonly ifcapi_parseSymbolicRepresentations: (a: number, b: number, c: number) => number;
848
- 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) => number;
925
+ 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;
849
926
  readonly ifcapi_scanEntitiesFast: (a: number, b: number, c: number) => number;
850
927
  readonly ifcapi_scanEntitiesFastBytes: (a: number, b: number, c: number) => number;
851
928
  readonly ifcapi_scanGeometryEntitiesFast: (a: number, b: number, c: number) => number;
@@ -865,6 +942,7 @@ export interface InitOutput {
865
942
  readonly meshcollection_rtcOffsetX: (a: number) => number;
866
943
  readonly meshcollection_rtcOffsetY: (a: number) => number;
867
944
  readonly meshcollection_rtcOffsetZ: (a: number) => number;
945
+ readonly meshcollection_takeMesh: (a: number, b: number) => number;
868
946
  readonly meshcollection_totalTriangles: (a: number) => number;
869
947
  readonly meshcollection_totalVertices: (a: number) => number;
870
948
  readonly meshdatajs_color: (a: number, b: number) => void;
@@ -874,6 +952,7 @@ export interface InitOutput {
874
952
  readonly meshdatajs_ifcType: (a: number, b: number) => void;
875
953
  readonly meshdatajs_indices: (a: number) => number;
876
954
  readonly meshdatajs_normals: (a: number) => number;
955
+ readonly meshdatajs_origin: (a: number) => number;
877
956
  readonly meshdatajs_positions: (a: number) => number;
878
957
  readonly meshdatajs_shadingColor: (a: number, b: number) => void;
879
958
  readonly meshdatajs_textureHeight: (a: number) => number;
@@ -890,7 +969,6 @@ export interface InitOutput {
890
969
  readonly meshoutlinejs_contourCount: (a: number) => number;
891
970
  readonly profilecollection_get: (a: number, b: number) => number;
892
971
  readonly profilecollection_length: (a: number) => number;
893
- readonly profileentryjs_expressId: (a: number) => number;
894
972
  readonly profileentryjs_extrusionDepth: (a: number) => number;
895
973
  readonly profileentryjs_extrusionDir: (a: number) => number;
896
974
  readonly profileentryjs_holeCounts: (a: number) => number;
@@ -899,15 +977,22 @@ export interface InitOutput {
899
977
  readonly profileentryjs_modelIndex: (a: number) => number;
900
978
  readonly profileentryjs_outerPoints: (a: number) => number;
901
979
  readonly profileentryjs_transform: (a: number) => number;
980
+ readonly spaceplatehandle_addFace: (a: number, b: number, c: number, d: number, e: number) => void;
902
981
  readonly spaceplatehandle_boundingElements: (a: number, b: number, c: number) => void;
982
+ readonly spaceplatehandle_dissolveVertex: (a: number, b: number, c: number) => void;
903
983
  readonly spaceplatehandle_dragVertex: (a: number, b: number, c: number, d: number, e: number) => void;
904
984
  readonly spaceplatehandle_duplicate: (a: number) => number;
905
985
  readonly spaceplatehandle_faceArea: (a: number, b: number) => number;
906
986
  readonly spaceplatehandle_faceOutline: (a: number, b: number, c: number) => void;
907
987
  readonly spaceplatehandle_findVertexNear: (a: number, b: number, c: number, d: number) => number;
988
+ readonly spaceplatehandle_fromWallRects: (a: number, b: number, c: number, d: number, e: number) => void;
989
+ readonly spaceplatehandle_gapBoundary: (a: number, b: number, c: number, d: number) => void;
908
990
  readonly spaceplatehandle_mergeFaces: (a: number, b: number, c: number) => void;
909
991
  readonly spaceplatehandle_neighborAcross: (a: number, b: number) => number;
910
- readonly spaceplatehandle_new: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void;
992
+ readonly spaceplatehandle_netOutline: (a: number, b: number, c: number, d: number) => void;
993
+ readonly spaceplatehandle_new: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number) => void;
994
+ readonly spaceplatehandle_prune: (a: number) => number;
995
+ readonly spaceplatehandle_removeEdge: (a: number, b: number, c: number) => void;
911
996
  readonly spaceplatehandle_roomCount: (a: number) => number;
912
997
  readonly spaceplatehandle_roomIds: (a: number, b: number) => void;
913
998
  readonly spaceplatehandle_setFaceHeight: (a: number, b: number, c: number, d: number, e: number) => void;
@@ -966,6 +1051,7 @@ export interface InitOutput {
966
1051
  readonly init: () => void;
967
1052
  readonly symbolicpolyline_pointCount: (a: number) => number;
968
1053
  readonly get_memory: () => number;
1054
+ readonly profileentryjs_expressId: (a: number) => number;
969
1055
  readonly symbolicfillarea_expressId: (a: number) => number;
970
1056
  readonly symbolicpolyline_worldY: (a: number) => number;
971
1057
  readonly symbolictext_colorB: (a: number) => number;
package/pkg/ifc-lite.js CHANGED
@@ -146,6 +146,16 @@ function passArrayF64ToWasm0(arg, malloc) {
146
146
  return ptr;
147
147
  }
148
148
 
149
+ function passArrayJsValueToWasm0(array, malloc) {
150
+ const ptr = malloc(array.length * 4, 4) >>> 0;
151
+ const mem = getDataViewMemory0();
152
+ for (let i = 0; i < array.length; i++) {
153
+ mem.setUint32(ptr + 4 * i, addHeapObject(array[i]), true);
154
+ }
155
+ WASM_VECTOR_LEN = array.length;
156
+ return ptr;
157
+ }
158
+
149
159
  function passStringToWasm0(arg, malloc, realloc) {
150
160
  if (realloc === undefined) {
151
161
  const buf = cachedTextEncoder.encode(arg);
@@ -641,9 +651,13 @@ export class IfcAPI {
641
651
  * @param {Uint32Array} void_values
642
652
  * @param {Uint32Array} style_ids
643
653
  * @param {Uint8Array} style_colors
654
+ * @param {number | null} [plane_angle_to_radians]
655
+ * @param {Uint32Array | null} [material_element_ids]
656
+ * @param {Uint32Array | null} [material_color_counts]
657
+ * @param {Uint8Array | null} [material_colors_rgba]
644
658
  * @returns {MeshCollection}
645
659
  */
646
- processGeometryBatch(data, jobs_flat, unit_scale, rtc_x, rtc_y, rtc_z, needs_shift, void_keys, void_counts, void_values, style_ids, style_colors) {
660
+ processGeometryBatch(data, jobs_flat, unit_scale, rtc_x, rtc_y, rtc_z, needs_shift, void_keys, void_counts, void_values, style_ids, style_colors, plane_angle_to_radians, material_element_ids, material_color_counts, material_colors_rgba) {
647
661
  const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
648
662
  const len0 = WASM_VECTOR_LEN;
649
663
  const ptr1 = passArray32ToWasm0(jobs_flat, wasm.__wbindgen_export);
@@ -658,7 +672,13 @@ export class IfcAPI {
658
672
  const len5 = WASM_VECTOR_LEN;
659
673
  const ptr6 = passArray8ToWasm0(style_colors, wasm.__wbindgen_export);
660
674
  const len6 = WASM_VECTOR_LEN;
661
- 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);
675
+ var ptr7 = isLikeNone(material_element_ids) ? 0 : passArray32ToWasm0(material_element_ids, wasm.__wbindgen_export);
676
+ var len7 = WASM_VECTOR_LEN;
677
+ var ptr8 = isLikeNone(material_color_counts) ? 0 : passArray32ToWasm0(material_color_counts, wasm.__wbindgen_export);
678
+ var len8 = WASM_VECTOR_LEN;
679
+ var ptr9 = isLikeNone(material_colors_rgba) ? 0 : passArray8ToWasm0(material_colors_rgba, wasm.__wbindgen_export);
680
+ var len9 = WASM_VECTOR_LEN;
681
+ 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);
662
682
  return MeshCollection.__wrap(ret);
663
683
  }
664
684
  /**
@@ -688,14 +708,18 @@ export class IfcAPI {
688
708
  * @param {Uint8Array} data
689
709
  * @param {Function} on_event
690
710
  * @param {number} chunk_size
711
+ * @param {string[] | null | undefined} disabled_type_names
712
+ * @param {boolean} skip_type_geometry
691
713
  * @returns {any}
692
714
  */
693
- buildPrePassStreaming(data, on_event, chunk_size) {
715
+ buildPrePassStreaming(data, on_event, chunk_size, disabled_type_names, skip_type_geometry) {
694
716
  try {
695
717
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
696
718
  const ptr0 = passArray8ToWasm0(data, wasm.__wbindgen_export);
697
719
  const len0 = WASM_VECTOR_LEN;
698
- wasm.ifcapi_buildPrePassStreaming(retptr, this.__wbg_ptr, ptr0, len0, addBorrowedObject(on_event), chunk_size);
720
+ var ptr1 = isLikeNone(disabled_type_names) ? 0 : passArrayJsValueToWasm0(disabled_type_names, wasm.__wbindgen_export);
721
+ var len1 = WASM_VECTOR_LEN;
722
+ wasm.ifcapi_buildPrePassStreaming(retptr, this.__wbg_ptr, ptr0, len0, addBorrowedObject(on_event), chunk_size, ptr1, len1, skip_type_geometry);
699
723
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
700
724
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
701
725
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -1124,7 +1148,8 @@ export class MeshCollection {
1124
1148
  return takeObject(ret);
1125
1149
  }
1126
1150
  /**
1127
- * Get mesh at index
1151
+ * Get mesh at index (clones — non-destructive). Prefer `takeMesh` on the
1152
+ * hot streaming path; this stays for callers that read meshes more than once.
1128
1153
  * @param {number} index
1129
1154
  * @returns {MeshDataJs | undefined}
1130
1155
  */
@@ -1140,6 +1165,20 @@ export class MeshCollection {
1140
1165
  const ret = wasm.meshcollection_length(this.__wbg_ptr);
1141
1166
  return ret >>> 0;
1142
1167
  }
1168
+ /**
1169
+ * #1097 perf: MOVE the mesh at `index` out of the collection (the Vec
1170
+ * buffers are `std::mem::take`-n, leaving an empty stub). The streaming
1171
+ * worker reads each mesh exactly once, so moving avoids the full vertex-
1172
+ * data clone `get` pays — one fewer copy of positions/normals/indices/uvs/
1173
+ * texture per mesh (the JS getters still do the single Rust→JS copy). Calling
1174
+ * it twice for the same index yields the second call an empty mesh.
1175
+ * @param {number} index
1176
+ * @returns {MeshDataJs | undefined}
1177
+ */
1178
+ takeMesh(index) {
1179
+ const ret = wasm.meshcollection_takeMesh(this.__wbg_ptr, index);
1180
+ return ret === 0 ? undefined : MeshDataJs.__wrap(ret);
1181
+ }
1143
1182
  }
1144
1183
  if (Symbol.dispose) MeshCollection.prototype[Symbol.dispose] = MeshCollection.prototype.free;
1145
1184
 
@@ -1292,6 +1331,16 @@ export class MeshDataJs {
1292
1331
  wasm.__wbindgen_add_to_stack_pointer(16);
1293
1332
  }
1294
1333
  }
1334
+ /**
1335
+ * Per-element local-frame origin (Float64Array[3], WebGL Y-up, metres):
1336
+ * world position of vertex i = `origin + positions[3i..3i+3]`. Returns
1337
+ * [0,0,0] when positions are absolute (legacy / local frame off).
1338
+ * @returns {Float64Array}
1339
+ */
1340
+ get origin() {
1341
+ const ret = wasm.meshdatajs_origin(this.__wbg_ptr);
1342
+ return takeObject(ret);
1343
+ }
1295
1344
  /**
1296
1345
  * Get indices as Uint32Array (copy to JS)
1297
1346
  * @returns {Uint32Array}
@@ -1473,7 +1522,7 @@ export class ProfileEntryJs {
1473
1522
  * @returns {number}
1474
1523
  */
1475
1524
  get expressId() {
1476
- const ret = wasm.profileentryjs_expressId(this.__wbg_ptr);
1525
+ const ret = wasm.meshdatajs_textureWidth(this.__wbg_ptr);
1477
1526
  return ret >>> 0;
1478
1527
  }
1479
1528
  /**
@@ -1679,6 +1728,56 @@ export class SpacePlateHandle {
1679
1728
  wasm.__wbindgen_add_to_stack_pointer(16);
1680
1729
  }
1681
1730
  }
1731
+ /**
1732
+ * The face outline offset to a wall boundary, as flat `[x0, y0, …]`: each
1733
+ * edge is moved by its own wall's half-thickness — inward when `inset`
1734
+ * (the net / inner face), outward otherwise (the gross / outer face).
1735
+ * Shared room↔room edges are pinned when pushing outward. Falls back to the
1736
+ * centreline outline when no offset applies — so it's always a sane ring.
1737
+ * (For a `center` boundary just use `faceOutline`.)
1738
+ * @param {number} face
1739
+ * @param {boolean} inset
1740
+ * @returns {Float64Array}
1741
+ */
1742
+ netOutline(face, inset) {
1743
+ try {
1744
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1745
+ wasm.spaceplatehandle_netOutline(retptr, this.__wbg_ptr, face, inset);
1746
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1747
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1748
+ var v1 = getArrayF64FromWasm0(r0, r1).slice();
1749
+ wasm.__wbindgen_export4(r0, r1 * 8, 8);
1750
+ return v1;
1751
+ } finally {
1752
+ wasm.__wbindgen_add_to_stack_pointer(16);
1753
+ }
1754
+ }
1755
+ /**
1756
+ * Remove a wall edge, choosing the right semantics from its two faces:
1757
+ * two real rooms → union them; a bridge / spur / outer-only wall → delete
1758
+ * it and auto-clean the orphaned inner lines and nodes it leaves; a real
1759
+ * enclosing wall (room ↔ exterior) → rejected (`BordersExterior`). This is
1760
+ * the "remove this wall and tidy up" affordance for the orphan cruft the
1761
+ * non-destructive wall arrangement leaves behind. Returns the rooms it
1762
+ * changed (empty if the edge bounded no room).
1763
+ * @param {number} edge
1764
+ * @returns {any}
1765
+ */
1766
+ removeEdge(edge) {
1767
+ try {
1768
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1769
+ wasm.spaceplatehandle_removeEdge(retptr, this.__wbg_ptr, edge);
1770
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1771
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1772
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1773
+ if (r2) {
1774
+ throw takeObject(r1);
1775
+ }
1776
+ return takeObject(r0);
1777
+ } finally {
1778
+ wasm.__wbindgen_add_to_stack_pointer(16);
1779
+ }
1780
+ }
1682
1781
  /**
1683
1782
  * Flat outline `[x0, y0, x1, y1, …]` of a face (no repeated closing vertex).
1684
1783
  * @param {number} face
@@ -1697,6 +1796,81 @@ export class SpacePlateHandle {
1697
1796
  wasm.__wbindgen_add_to_stack_pointer(16);
1698
1797
  }
1699
1798
  }
1799
+ /**
1800
+ * Face-based gap-room boundary as flat `[x0, y0, …]`: each edge pushed
1801
+ * OUTWARD (into the wall) by `factor × the source wall's half-thickness`.
1802
+ * `0` → net (the gap / inner faces); `1` → centre axis (½ thickness, the
1803
+ * editable node line on the wall mid); `2` → gross outer face.
1804
+ * @param {number} face
1805
+ * @param {number} factor
1806
+ * @returns {Float64Array}
1807
+ */
1808
+ gapBoundary(face, factor) {
1809
+ try {
1810
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1811
+ wasm.spaceplatehandle_gapBoundary(retptr, this.__wbg_ptr, face, factor);
1812
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1813
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1814
+ var v1 = getArrayF64FromWasm0(r0, r1).slice();
1815
+ wasm.__wbindgen_export4(r0, r1 * 8, 8);
1816
+ return v1;
1817
+ } finally {
1818
+ wasm.__wbindgen_add_to_stack_pointer(16);
1819
+ }
1820
+ }
1821
+ /**
1822
+ * Dissolve a degree-2 vertex, welding its two edges into one straight
1823
+ * edge between the neighbours — the inverse of `splitEdge`, and the
1824
+ * "delete this corner / node" affordance. Returns the rooms it changed.
1825
+ * Rejects a wall junction (degree ≥ 3) or a weld that would duplicate an
1826
+ * edge.
1827
+ * @param {number} v
1828
+ * @returns {any}
1829
+ */
1830
+ dissolveVertex(v) {
1831
+ try {
1832
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1833
+ wasm.spaceplatehandle_dissolveVertex(retptr, this.__wbg_ptr, v);
1834
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1835
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1836
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1837
+ if (r2) {
1838
+ throw takeObject(r1);
1839
+ }
1840
+ return takeObject(r0);
1841
+ } finally {
1842
+ wasm.__wbindgen_add_to_stack_pointer(16);
1843
+ }
1844
+ }
1845
+ /**
1846
+ * FACE-BASED build: rooms are the gaps between wall footprint rectangles.
1847
+ * `rectCoords` is flat `[x0, y0, x1, y1, x2, y2, x3, y3, …]` — 8 f64 per wall
1848
+ * (its 4 plan-rectangle corners, CCW). A bounded arrangement face is a room
1849
+ * only if its centroid is outside every rectangle (a gap, not a wall
1850
+ * interior). The room outline IS the net (inner-face) area; `gapBoundary`
1851
+ * gives the centre axis (½ thickness) and the gross outer face.
1852
+ * @param {Float64Array} rect_coords
1853
+ * @param {number} snap_tolerance
1854
+ * @param {number} min_area
1855
+ * @returns {SpacePlateHandle}
1856
+ */
1857
+ static fromWallRects(rect_coords, snap_tolerance, min_area) {
1858
+ try {
1859
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1860
+ const ptr0 = passArrayF64ToWasm0(rect_coords, wasm.__wbindgen_export);
1861
+ const len0 = WASM_VECTOR_LEN;
1862
+ wasm.spaceplatehandle_fromWallRects(retptr, ptr0, len0, snap_tolerance, min_area);
1863
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1864
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1865
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1866
+ if (r2) {
1867
+ throw takeObject(r1);
1868
+ }
1869
+ return SpacePlateHandle.__wrap(r0);
1870
+ } finally {
1871
+ wasm.__wbindgen_add_to_stack_pointer(16);
1872
+ }
1873
+ }
1700
1874
  /**
1701
1875
  * The room on the far side of a half-edge (its twin's face), or
1702
1876
  * `undefined`. O(1) — the "who's across this wall" query.
@@ -1755,20 +1929,26 @@ export class SpacePlateHandle {
1755
1929
  *
1756
1930
  * `segCoords`: `[ax, ay, bx, by, …]` (length a multiple of 4).
1757
1931
  * `segSources`: one `i32` per segment, `-1` for none.
1932
+ * `segHalfThickness`: one `f64` per segment — half the wall's thickness in
1933
+ * metres, carried onto the derived edges for `netOutline`. Pass an empty
1934
+ * array (or all zeros) when thickness is unknown (centreline only).
1758
1935
  * `snapTolerance` / `minArea`: pass `<= 0` to take the defaults.
1759
1936
  * @param {Float64Array} seg_coords
1760
1937
  * @param {Int32Array} seg_sources
1938
+ * @param {Float64Array} seg_half_thickness
1761
1939
  * @param {number} snap_tolerance
1762
1940
  * @param {number} min_area
1763
1941
  */
1764
- constructor(seg_coords, seg_sources, snap_tolerance, min_area) {
1942
+ constructor(seg_coords, seg_sources, seg_half_thickness, snap_tolerance, min_area) {
1765
1943
  try {
1766
1944
  const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1767
1945
  const ptr0 = passArrayF64ToWasm0(seg_coords, wasm.__wbindgen_export);
1768
1946
  const len0 = WASM_VECTOR_LEN;
1769
1947
  const ptr1 = passArray32ToWasm0(seg_sources, wasm.__wbindgen_export);
1770
1948
  const len1 = WASM_VECTOR_LEN;
1771
- wasm.spaceplatehandle_new(retptr, ptr0, len0, ptr1, len1, snap_tolerance, min_area);
1949
+ const ptr2 = passArrayF64ToWasm0(seg_half_thickness, wasm.__wbindgen_export);
1950
+ const len2 = WASM_VECTOR_LEN;
1951
+ wasm.spaceplatehandle_new(retptr, ptr0, len0, ptr1, len1, ptr2, len2, snap_tolerance, min_area);
1772
1952
  var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1773
1953
  var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1774
1954
  var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
@@ -1782,6 +1962,44 @@ export class SpacePlateHandle {
1782
1962
  wasm.__wbindgen_add_to_stack_pointer(16);
1783
1963
  }
1784
1964
  }
1965
+ /**
1966
+ * Sweep the whole plate clean: remove dangling spur walls, isolated nodes,
1967
+ * and redundant collinear nodes — the "clean up orphans" / eraser action.
1968
+ * Area-neutral and idempotent. Returns how many topology elements were
1969
+ * pruned (0 = the plate was already clean); the caller re-renders via
1970
+ * `snapshot` like any other edit.
1971
+ * @returns {number}
1972
+ */
1973
+ prune() {
1974
+ const ret = wasm.spaceplatehandle_prune(this.__wbg_ptr);
1975
+ return ret >>> 0;
1976
+ }
1977
+ /**
1978
+ * Author a new room from a flat ring `[x0, y0, x1, y1, …]` (no repeated
1979
+ * closing vertex). `source` `-1` marks a user-drawn room. Winding is
1980
+ * normalised to CCW; returns the new room patch. The room is its own
1981
+ * connected component — it does not merge into existing topology.
1982
+ * @param {Float64Array} coords
1983
+ * @param {number} source
1984
+ * @returns {any}
1985
+ */
1986
+ addFace(coords, source) {
1987
+ try {
1988
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
1989
+ const ptr0 = passArrayF64ToWasm0(coords, wasm.__wbindgen_export);
1990
+ const len0 = WASM_VECTOR_LEN;
1991
+ wasm.spaceplatehandle_addFace(retptr, this.__wbg_ptr, ptr0, len0, source);
1992
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
1993
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
1994
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
1995
+ if (r2) {
1996
+ throw takeObject(r1);
1997
+ }
1998
+ return takeObject(r0);
1999
+ } finally {
2000
+ wasm.__wbindgen_add_to_stack_pointer(16);
2001
+ }
2002
+ }
1785
2003
  /**
1786
2004
  * Face ids of every live room.
1787
2005
  * @returns {Uint32Array}
@@ -1996,7 +2214,7 @@ export class SymbolicFillArea {
1996
2214
  * @returns {number}
1997
2215
  */
1998
2216
  get expressId() {
1999
- const ret = wasm.profileentryjs_expressId(this.__wbg_ptr);
2217
+ const ret = wasm.meshdatajs_textureWidth(this.__wbg_ptr);
2000
2218
  return ret >>> 0;
2001
2219
  }
2002
2220
  /**
@@ -2404,7 +2622,7 @@ export class SymbolicText {
2404
2622
  * @returns {number}
2405
2623
  */
2406
2624
  get expressId() {
2407
- const ret = wasm.profileentryjs_expressId(this.__wbg_ptr);
2625
+ const ret = wasm.meshdatajs_textureWidth(this.__wbg_ptr);
2408
2626
  return ret >>> 0;
2409
2627
  }
2410
2628
  /**
@@ -2694,6 +2912,14 @@ function __wbg_get_imports() {
2694
2912
  const ret = wasm.memory;
2695
2913
  return addHeapObject(ret);
2696
2914
  };
2915
+ imports.wbg.__wbg___wbindgen_string_get_a2a31e16edf96e42 = function(arg0, arg1) {
2916
+ const obj = getObject(arg1);
2917
+ const ret = typeof(obj) === 'string' ? obj : undefined;
2918
+ var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
2919
+ var len1 = WASM_VECTOR_LEN;
2920
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
2921
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
2922
+ };
2697
2923
  imports.wbg.__wbg___wbindgen_throw_dd24417ed36fc46e = function(arg0, arg1) {
2698
2924
  throw new Error(getStringFromWasm0(arg0, arg1));
2699
2925
  };
@@ -2727,6 +2953,10 @@ function __wbg_get_imports() {
2727
2953
  const ret = new Error();
2728
2954
  return addHeapObject(ret);
2729
2955
  };
2956
+ imports.wbg.__wbg_new_df1173567d5ff028 = function(arg0, arg1) {
2957
+ const ret = new Error(getStringFromWasm0(arg0, arg1));
2958
+ return addHeapObject(ret);
2959
+ };
2730
2960
  imports.wbg.__wbg_new_from_slice_41e2764a343e3cb1 = function(arg0, arg1) {
2731
2961
  const ret = new Float32Array(getArrayF32FromWasm0(arg0, arg1));
2732
2962
  return addHeapObject(ret);
@@ -2735,6 +2965,10 @@ function __wbg_get_imports() {
2735
2965
  const ret = new BigUint64Array(getArrayU64FromWasm0(arg0, arg1));
2736
2966
  return addHeapObject(ret);
2737
2967
  };
2968
+ imports.wbg.__wbg_new_from_slice_9a48ef80d2a51f94 = function(arg0, arg1) {
2969
+ const ret = new Float64Array(getArrayF64FromWasm0(arg0, arg1));
2970
+ return addHeapObject(ret);
2971
+ };
2738
2972
  imports.wbg.__wbg_new_from_slice_db0691b69e9d3891 = function(arg0, arg1) {
2739
2973
  const ret = new Uint32Array(getArrayU32FromWasm0(arg0, arg1));
2740
2974
  return addHeapObject(ret);
@@ -2751,10 +2985,6 @@ function __wbg_get_imports() {
2751
2985
  const ret = new Float64Array(arg0 >>> 0);
2752
2986
  return addHeapObject(ret);
2753
2987
  };
2754
- imports.wbg.__wbg_new_with_length_aa5eaf41d35235e5 = function(arg0) {
2755
- const ret = new Uint8Array(arg0 >>> 0);
2756
- return addHeapObject(ret);
2757
- };
2758
2988
  imports.wbg.__wbg_set_3f1d0b984ed272ed = function(arg0, arg1, arg2) {
2759
2989
  getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
2760
2990
  };
@@ -2768,12 +2998,12 @@ function __wbg_get_imports() {
2768
2998
  imports.wbg.__wbg_set_index_021489b2916af13e = function(arg0, arg1, arg2) {
2769
2999
  getObject(arg0)[arg1 >>> 0] = arg2;
2770
3000
  };
2771
- imports.wbg.__wbg_set_index_04c4b93e64d08a52 = function(arg0, arg1, arg2) {
2772
- getObject(arg0)[arg1 >>> 0] = arg2;
2773
- };
2774
3001
  imports.wbg.__wbg_set_index_42abe35f117e614e = function(arg0, arg1, arg2) {
2775
3002
  getObject(arg0)[arg1 >>> 0] = arg2 >>> 0;
2776
3003
  };
3004
+ imports.wbg.__wbg_set_name_df69b75cb0b4de8a = function(arg0, arg1, arg2) {
3005
+ getObject(arg0).name = getStringFromWasm0(arg1, arg2);
3006
+ };
2777
3007
  imports.wbg.__wbg_stack_0ed75d68575b0f3c = function(arg0, arg1) {
2778
3008
  const ret = getObject(arg1).stack;
2779
3009
  const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
Binary file