okgeometry-api 1.26.1 → 1.27.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.
Files changed (99) hide show
  1. package/dist/Arc.js +1 -1
  2. package/dist/Arc.js.map +1 -1
  3. package/dist/Brep.js +1 -1
  4. package/dist/Brep.js.map +1 -1
  5. package/dist/Circle.js +1 -1
  6. package/dist/Circle.js.map +1 -1
  7. package/dist/Line.js +1 -1
  8. package/dist/Line.js.map +1 -1
  9. package/dist/Mesh.d.ts +41 -0
  10. package/dist/Mesh.d.ts.map +1 -1
  11. package/dist/Mesh.js +235 -21
  12. package/dist/Mesh.js.map +1 -1
  13. package/dist/MeshSurface.js +1 -1
  14. package/dist/MeshSurface.js.map +1 -1
  15. package/dist/NurbsCurve.js +1 -1
  16. package/dist/NurbsCurve.js.map +1 -1
  17. package/dist/NurbsSurface.js +1 -1
  18. package/dist/NurbsSurface.js.map +1 -1
  19. package/dist/PolyCurve.js +1 -1
  20. package/dist/PolyCurve.js.map +1 -1
  21. package/dist/Polyline.js +1 -1
  22. package/dist/Polyline.js.map +1 -1
  23. package/dist/Ray.js +1 -1
  24. package/dist/Ray.js.map +1 -1
  25. package/dist/SculptSession.js +1 -1
  26. package/dist/SculptSession.js.map +1 -1
  27. package/dist/engine-threaded.d.ts +2 -0
  28. package/dist/engine-threaded.d.ts.map +1 -0
  29. package/dist/engine-threaded.js +33 -0
  30. package/dist/engine-threaded.js.map +1 -0
  31. package/dist/engine.d.ts +21 -0
  32. package/dist/engine.d.ts.map +1 -1
  33. package/dist/engine.js +42 -0
  34. package/dist/engine.js.map +1 -1
  35. package/dist/index.d.ts +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist/mesh-boolean.pool.d.ts +23 -1
  40. package/dist/mesh-boolean.pool.d.ts.map +1 -1
  41. package/dist/mesh-boolean.pool.js +97 -12
  42. package/dist/mesh-boolean.pool.js.map +1 -1
  43. package/dist/mesh-boolean.protocol.d.ts +21 -1
  44. package/dist/mesh-boolean.protocol.d.ts.map +1 -1
  45. package/dist/mesh-boolean.protocol.js.map +1 -1
  46. package/dist/mesh-boolean.worker.d.ts.map +1 -1
  47. package/dist/mesh-boolean.worker.js +94 -1
  48. package/dist/mesh-boolean.worker.js.map +1 -1
  49. package/dist/wasm-active.d.ts +20 -0
  50. package/dist/wasm-active.d.ts.map +1 -0
  51. package/dist/wasm-active.js +26 -0
  52. package/dist/wasm-active.js.map +1 -0
  53. package/dist/wasm-base64-threaded.d.ts +2 -0
  54. package/dist/wasm-base64-threaded.d.ts.map +1 -0
  55. package/dist/wasm-base64-threaded.js +3 -0
  56. package/dist/wasm-base64-threaded.js.map +1 -0
  57. package/dist/wasm-base64.d.ts +1 -1
  58. package/dist/wasm-base64.d.ts.map +1 -1
  59. package/dist/wasm-base64.js +1 -1
  60. package/dist/wasm-base64.js.map +1 -1
  61. package/dist/wasm-bindings-threaded.d.ts +2664 -0
  62. package/dist/wasm-bindings-threaded.d.ts.map +1 -0
  63. package/dist/wasm-bindings-threaded.js +5008 -0
  64. package/dist/wasm-bindings-threaded.js.map +1 -0
  65. package/dist/wasm-bindings.d.ts +130 -0
  66. package/dist/wasm-bindings.d.ts.map +1 -1
  67. package/dist/wasm-bindings.js +208 -0
  68. package/dist/wasm-bindings.js.map +1 -1
  69. package/dist/workerHelpers-threaded.d.ts +2 -0
  70. package/dist/workerHelpers-threaded.d.ts.map +1 -0
  71. package/dist/workerHelpers-threaded.js +100 -0
  72. package/dist/workerHelpers-threaded.js.map +1 -0
  73. package/package.json +8 -3
  74. package/src/Arc.ts +117 -117
  75. package/src/Brep.ts +1 -1
  76. package/src/Circle.ts +166 -166
  77. package/src/Line.ts +171 -171
  78. package/src/Mesh.ts +300 -45
  79. package/src/MeshSurface.ts +1 -1
  80. package/src/NurbsCurve.ts +655 -655
  81. package/src/NurbsSurface.ts +721 -721
  82. package/src/PolyCurve.ts +203 -203
  83. package/src/Polyline.ts +316 -316
  84. package/src/Ray.ts +90 -90
  85. package/src/SculptSession.ts +377 -377
  86. package/src/engine-threaded.ts +39 -0
  87. package/src/engine.ts +46 -0
  88. package/src/index.ts +1 -1
  89. package/src/mesh-boolean.pool.ts +208 -86
  90. package/src/mesh-boolean.protocol.ts +44 -1
  91. package/src/mesh-boolean.worker.ts +170 -56
  92. package/src/wasm-active.ts +31 -0
  93. package/src/wasm-base64-threaded.ts +2 -0
  94. package/src/wasm-base64.ts +1 -1
  95. package/src/wasm-bindings-threaded.d.ts +1989 -0
  96. package/src/wasm-bindings-threaded.js +5235 -0
  97. package/src/wasm-bindings.d.ts +104 -0
  98. package/src/wasm-bindings.js +225 -0
  99. package/src/workerHelpers-threaded.js +107 -0
package/dist/Mesh.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ensureInit } from "./engine.js";
1
+ import { ensureInit, isInitialized } from "./engine.js";
2
2
  import { Point } from "./Point.js";
3
3
  import { Vec3 } from "./Vec3.js";
4
4
  import { Plane } from "./Plane.js";
@@ -11,10 +11,9 @@ import { MeshSurface } from "./MeshSurface.js";
11
11
  import { NurbsCurve } from "./NurbsCurve.js";
12
12
  import { PolyCurve } from "./PolyCurve.js";
13
13
  import { pointsToCoords, parsePolylineBuffer as parsePolylineBuf } from "./BufferCodec.js";
14
- import { configureDefaultMeshBooleanWorkerPool, disposeMeshBooleanWorkerPools, runMeshBooleanInWorkerPool, } from "./mesh-boolean.pool.js";
14
+ import { configureDefaultMeshBooleanWorkerPool, disposeMeshBooleanWorkerPools, runMeshBooleanInWorkerPool, runMeshHeavyInWorkerPool, } from "./mesh-boolean.pool.js";
15
15
  import { MeshBooleanExecutionError } from "./mesh-boolean.protocol.js";
16
- import * as wasm from "./wasm-bindings.js";
17
- import { mesh_topology_metrics, mesh_topology_metrics_raw } from "./wasm-bindings.js";
16
+ import { wasm } from "./wasm-active.js";
18
17
  export { MeshBooleanExecutionError };
19
18
  function shouldFallbackFromWorkerFailure(error) {
20
19
  if (!error || typeof error !== "object")
@@ -68,10 +67,74 @@ export class Mesh {
68
67
  this._topologyMetricsCache = null;
69
68
  this._isClosedVolumeCache = null;
70
69
  this._rawBoundsCache = undefined;
70
+ // ---- WASM-side residency (KERNEL-PERF-ARC lever 2) -----------------------
71
+ //
72
+ // Repeated queries on the same mesh (hover face groups, raycasts, render
73
+ // buffers, diagnostics) skip the per-call JS→WASM buffer copy by storing
74
+ // the buffer WASM-side once; raycasts additionally reuse a cached BVH.
75
+ // Residency is self-tuning: the FIRST hot call uses the classic buffer
76
+ // path (one-shot meshes never pay the store), the second call onward
77
+ // stores. `dispose()` releases eagerly; a FinalizationRegistry frees
78
+ // leaked ids on GC as a safety net. Buffers are immutable, so stored
79
+ // copies never need invalidation.
80
+ this._storeId = null;
81
+ this._hotCallCount = 0;
71
82
  this._buffer = buffer;
72
83
  this._vertexCount = buffer.length > 0 ? buffer[0] : 0;
73
84
  this._trustedBooleanInput = trustedBooleanInput;
74
85
  }
86
+ /**
87
+ * WASM-side stored-mesh id, or 0 when this call should use the buffer
88
+ * path (first hot call, store failure, or disposed-and-cold mesh).
89
+ */
90
+ storedId() {
91
+ if (this._storeId !== null)
92
+ return this._storeId;
93
+ if (this._hotCallCount < 1) {
94
+ this._hotCallCount++;
95
+ return 0;
96
+ }
97
+ let id = 0;
98
+ try {
99
+ id = wasm.mesh_store(this._vertexCount, this._buffer);
100
+ }
101
+ catch {
102
+ id = 0;
103
+ }
104
+ this._storeId = id;
105
+ if (id > 0)
106
+ Mesh.residencyFinalizer?.register(this, id, this);
107
+ return id;
108
+ }
109
+ /**
110
+ * Release this mesh's WASM-side stored copy (idempotent). The mesh stays
111
+ * fully usable — the next repeated hot call re-stores it. Call from
112
+ * long-lived hosts (okdraw engine-bridge release paths) to return WASM
113
+ * memory promptly instead of waiting for GC.
114
+ */
115
+ dispose() {
116
+ if (this._storeId !== null && this._storeId > 0) {
117
+ try {
118
+ wasm.mesh_store_free(this._storeId);
119
+ }
120
+ catch {
121
+ // engine torn down — nothing to free
122
+ }
123
+ Mesh.residencyFinalizer?.unregister(this);
124
+ }
125
+ this._storeId = null;
126
+ this._hotCallCount = 0;
127
+ }
128
+ /** Number of meshes currently resident WASM-side (diagnostics/tests). */
129
+ static residentMeshCount() {
130
+ ensureInit();
131
+ return wasm.mesh_store_count();
132
+ }
133
+ /** Approximate bytes of WASM-side resident mesh buffers (diagnostics). */
134
+ static residentMeshBytes() {
135
+ ensureInit();
136
+ return wasm.mesh_store_bytes();
137
+ }
75
138
  /**
76
139
  * Configure default size for the shared boolean worker pool.
77
140
  */
@@ -1559,7 +1622,10 @@ export class Mesh {
1559
1622
  if (this._edgeVertexPairs)
1560
1623
  return this._edgeVertexPairs;
1561
1624
  ensureInit();
1562
- const packed = wasm.mesh_get_edge_vertex_pairs(this._vertexCount, this._buffer);
1625
+ const sidEdges = this.storedId();
1626
+ const packed = sidEdges > 0
1627
+ ? wasm.mesh_get_edge_vertex_pairs_h(sidEdges)
1628
+ : wasm.mesh_get_edge_vertex_pairs(this._vertexCount, this._buffer);
1563
1629
  const edgeCount = Math.max(0, Math.floor(packed[0] ?? 0));
1564
1630
  const pairs = [];
1565
1631
  let off = 1;
@@ -2211,6 +2277,113 @@ export class Mesh {
2211
2277
  });
2212
2278
  }
2213
2279
  }
2280
+ // ── Heavy async ops on the worker pool (KERNEL-PERF-ARC lever 4) ──
2281
+ //
2282
+ // Multi-second operations run off the main thread with the same
2283
+ // fallback contract as the pairwise async booleans: any worker-side
2284
+ // failure falls back to the synchronous main-thread path.
2285
+ /** Async `Mesh.unionAll` on the worker pool. */
2286
+ static async unionAllAsync(meshes, options) {
2287
+ try {
2288
+ const { buffer } = await runMeshHeavyInWorkerPool("unionAll", meshes.map((m) => m._buffer), { ...options, trusted: meshes.map((m) => m._trustedBooleanInput) });
2289
+ return Mesh.fromTrustedBuffer(buffer);
2290
+ }
2291
+ catch (error) {
2292
+ if (!shouldFallbackFromWorkerFailure(error))
2293
+ throw error;
2294
+ console.warn("Mesh.unionAllAsync worker failed; falling back to main thread.", error);
2295
+ return Mesh.unionAll(meshes, {
2296
+ allowUnsafe: options?.allowUnsafe ?? true,
2297
+ limits: options?.limits,
2298
+ });
2299
+ }
2300
+ }
2301
+ /** Async `mesh.subtractAll` on the worker pool. */
2302
+ async subtractAllAsync(cutters, options) {
2303
+ try {
2304
+ const { buffer } = await runMeshHeavyInWorkerPool("differenceAll", [this._buffer, ...cutters.map((m) => m._buffer)], {
2305
+ ...options,
2306
+ trusted: [this._trustedBooleanInput, ...cutters.map((m) => m._trustedBooleanInput)],
2307
+ });
2308
+ return Mesh.fromTrustedBuffer(buffer);
2309
+ }
2310
+ catch (error) {
2311
+ if (!shouldFallbackFromWorkerFailure(error))
2312
+ throw error;
2313
+ console.warn("Mesh.subtractAllAsync worker failed; falling back to main thread.", error);
2314
+ return this.subtractAll(cutters, {
2315
+ allowUnsafe: options?.allowUnsafe ?? true,
2316
+ limits: options?.limits,
2317
+ });
2318
+ }
2319
+ }
2320
+ /** Async `mesh.makeWatertight` on the worker pool. NOTE: the async
2321
+ * variant reports the result mesh, method and effective resolution;
2322
+ * before/after diagnostics can be recomputed by the caller if needed. */
2323
+ async makeWatertightAsync(options = {}) {
2324
+ try {
2325
+ const { buffer, meta } = await runMeshHeavyInWorkerPool("makeWatertight", [this._buffer], {
2326
+ ...options,
2327
+ trusted: [this._trustedBooleanInput],
2328
+ params: { resolution: options.resolution, iso: options.iso },
2329
+ });
2330
+ return {
2331
+ mesh: Mesh.fromTrustedBuffer(buffer),
2332
+ method: meta?.method ?? "repair",
2333
+ effectiveResolution: Number(meta?.effectiveResolution ?? 0),
2334
+ };
2335
+ }
2336
+ catch (error) {
2337
+ if (!shouldFallbackFromWorkerFailure(error))
2338
+ throw error;
2339
+ console.warn("Mesh.makeWatertightAsync worker failed; falling back to main thread.", error);
2340
+ const r = this.makeWatertight({ resolution: options.resolution, iso: options.iso });
2341
+ return { mesh: r.mesh, method: r.method, effectiveResolution: r.effectiveResolution };
2342
+ }
2343
+ }
2344
+ /** Async `mesh.voxelRemesh` on the worker pool. */
2345
+ async voxelRemeshAsync(resolution = 0, iso = 0.5, options) {
2346
+ try {
2347
+ const { buffer } = await runMeshHeavyInWorkerPool("voxelRemesh", [this._buffer], {
2348
+ ...options,
2349
+ trusted: [this._trustedBooleanInput],
2350
+ params: { resolution, iso },
2351
+ });
2352
+ return Mesh.fromTrustedBuffer(buffer);
2353
+ }
2354
+ catch (error) {
2355
+ if (!shouldFallbackFromWorkerFailure(error))
2356
+ throw error;
2357
+ console.warn("Mesh.voxelRemeshAsync worker failed; falling back to main thread.", error);
2358
+ return this.voxelRemesh(resolution, iso);
2359
+ }
2360
+ }
2361
+ /** Async `mesh.chamferEdges` on the worker pool. */
2362
+ async chamferEdgesAsync(edges, distance, options) {
2363
+ const flat = new Float64Array(edges.length * 6);
2364
+ edges.forEach((edge, i) => {
2365
+ flat[i * 6] = edge.a.x;
2366
+ flat[i * 6 + 1] = edge.a.y;
2367
+ flat[i * 6 + 2] = edge.a.z;
2368
+ flat[i * 6 + 3] = edge.b.x;
2369
+ flat[i * 6 + 4] = edge.b.y;
2370
+ flat[i * 6 + 5] = edge.b.z;
2371
+ });
2372
+ try {
2373
+ const { buffer } = await runMeshHeavyInWorkerPool("chamferEdges", [this._buffer, flat], {
2374
+ ...options,
2375
+ trusted: [this._trustedBooleanInput],
2376
+ params: { distance },
2377
+ });
2378
+ return Mesh.fromTrustedBuffer(buffer);
2379
+ }
2380
+ catch (error) {
2381
+ if (!shouldFallbackFromWorkerFailure(error))
2382
+ throw error;
2383
+ console.warn("Mesh.chamferEdgesAsync worker failed; falling back to main thread.", error);
2384
+ return this.chamferEdges(edges, distance);
2385
+ }
2386
+ }
2214
2387
  // ── Intersection queries ───────────────────────────────────────
2215
2388
  /**
2216
2389
  * Compute intersection curves with a plane.
@@ -2506,7 +2679,10 @@ export class Mesh {
2506
2679
  ensureInit();
2507
2680
  if (!Number.isFinite(faceIndex) || faceIndex < 0)
2508
2681
  return [];
2509
- const r = wasm.mesh_get_coplanar_face_indices(this._vertexCount, this._buffer, Math.floor(faceIndex));
2682
+ const sidCfi = this.storedId();
2683
+ const r = sidCfi > 0
2684
+ ? wasm.mesh_get_coplanar_face_indices_h(sidCfi, Math.floor(faceIndex))
2685
+ : wasm.mesh_get_coplanar_face_indices(this._vertexCount, this._buffer, Math.floor(faceIndex));
2510
2686
  const count = Math.max(0, Math.floor(r[0] ?? 0));
2511
2687
  const out = [];
2512
2688
  for (let i = 0; i < count; i++) {
@@ -2526,7 +2702,10 @@ export class Mesh {
2526
2702
  if (!Number.isFinite(faceIndex) || faceIndex < 0) {
2527
2703
  return { faceIndices: [], isPlanar: true };
2528
2704
  }
2529
- const r = wasm.mesh_get_smooth_face_group(this._vertexCount, this._buffer, Math.floor(faceIndex), maxAngleDeg);
2705
+ const sidSfg = this.storedId();
2706
+ const r = sidSfg > 0
2707
+ ? wasm.mesh_get_smooth_face_group_h(sidSfg, Math.floor(faceIndex), maxAngleDeg)
2708
+ : wasm.mesh_get_smooth_face_group(this._vertexCount, this._buffer, Math.floor(faceIndex), maxAngleDeg);
2530
2709
  const count = Math.max(0, Math.floor(r[0] ?? 0));
2531
2710
  const isPlanar = (r[1] ?? 1) !== 0;
2532
2711
  const faceIndices = [];
@@ -2548,7 +2727,10 @@ export class Mesh {
2548
2727
  */
2549
2728
  buildRenderBuffers(creaseAngleDeg = 30) {
2550
2729
  ensureInit();
2551
- const r = wasm.mesh_build_render_buffers(this._vertexCount, this._buffer, creaseAngleDeg);
2730
+ const sidRb = this.storedId();
2731
+ const r = sidRb > 0
2732
+ ? wasm.mesh_build_render_buffers_h(sidRb, creaseAngleDeg)
2733
+ : wasm.mesh_build_render_buffers(this._vertexCount, this._buffer, creaseAngleDeg);
2552
2734
  const vertexCount = Math.max(0, Math.floor(r[0] ?? 0));
2553
2735
  const posStart = 1;
2554
2736
  const norStart = posStart + vertexCount * 3;
@@ -2593,7 +2775,10 @@ export class Mesh {
2593
2775
  ensureInit();
2594
2776
  if (!Number.isFinite(faceIndex) || faceIndex < 0)
2595
2777
  return null;
2596
- const r = wasm.mesh_get_coplanar_face_group_centroid(this._vertexCount, this._buffer, Math.floor(faceIndex));
2778
+ const sidCent = this.storedId();
2779
+ const r = sidCent > 0
2780
+ ? wasm.mesh_get_coplanar_face_group_centroid_h(sidCent, Math.floor(faceIndex))
2781
+ : wasm.mesh_get_coplanar_face_group_centroid(this._vertexCount, this._buffer, Math.floor(faceIndex));
2597
2782
  if (!r || r.length < 3)
2598
2783
  return null;
2599
2784
  return new Point(r[0], r[1], r[2]);
@@ -2608,7 +2793,10 @@ export class Mesh {
2608
2793
  ensureInit();
2609
2794
  if (!Number.isFinite(faceIndex) || faceIndex < 0)
2610
2795
  return [];
2611
- const r = wasm.mesh_get_face_boundary_loops(this._vertexCount, this._buffer, Math.floor(faceIndex));
2796
+ const sidLoops = this.storedId();
2797
+ const r = sidLoops > 0
2798
+ ? wasm.mesh_get_face_boundary_loops_h(sidLoops, Math.floor(faceIndex))
2799
+ : wasm.mesh_get_face_boundary_loops(this._vertexCount, this._buffer, Math.floor(faceIndex));
2612
2800
  if (!r || r.length < 1)
2613
2801
  return [];
2614
2802
  const loopCount = Math.floor(r[0]);
@@ -2655,7 +2843,10 @@ export class Mesh {
2655
2843
  */
2656
2844
  raycast(origin, direction, maxDistance = Number.POSITIVE_INFINITY) {
2657
2845
  ensureInit();
2658
- const r = wasm.mesh_raycast(this._vertexCount, this._buffer, origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, maxDistance);
2846
+ const sidRay = this.storedId();
2847
+ const r = sidRay > 0
2848
+ ? wasm.mesh_raycast_h(sidRay, origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, maxDistance)
2849
+ : wasm.mesh_raycast(this._vertexCount, this._buffer, origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, maxDistance);
2659
2850
  if (!r || r.length < 8)
2660
2851
  return null;
2661
2852
  return {
@@ -2670,7 +2861,10 @@ export class Mesh {
2670
2861
  */
2671
2862
  raycastAll(origin, direction, maxDistance = Number.POSITIVE_INFINITY) {
2672
2863
  ensureInit();
2673
- const buf = wasm.mesh_raycast_all(this._vertexCount, this._buffer, origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, maxDistance);
2864
+ const sidRayAll = this.storedId();
2865
+ const buf = sidRayAll > 0
2866
+ ? wasm.mesh_raycast_all_h(sidRayAll, origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, maxDistance)
2867
+ : wasm.mesh_raycast_all(this._vertexCount, this._buffer, origin.x, origin.y, origin.z, direction.x, direction.y, direction.z, maxDistance);
2674
2868
  const count = Math.max(0, Math.floor(buf[0] ?? 0));
2675
2869
  const hits = [];
2676
2870
  let off = 1;
@@ -2746,8 +2940,8 @@ export class Mesh {
2746
2940
  }
2747
2941
  ensureInit();
2748
2942
  const metrics = this._trustedBooleanInput
2749
- ? mesh_topology_metrics_raw(this._vertexCount, this._buffer)
2750
- : mesh_topology_metrics(this._vertexCount, this._buffer);
2943
+ ? wasm.mesh_topology_metrics_raw(this._vertexCount, this._buffer)
2944
+ : wasm.mesh_topology_metrics(this._vertexCount, this._buffer);
2751
2945
  const boundaryEdges = Math.floor(metrics[0] ?? 0);
2752
2946
  const nonManifoldEdges = Math.floor(metrics[1] ?? 0);
2753
2947
  this._topologyMetricsCache = { boundaryEdges, nonManifoldEdges };
@@ -2766,7 +2960,10 @@ export class Mesh {
2766
2960
  */
2767
2961
  diagnostics() {
2768
2962
  ensureInit();
2769
- const r = wasm.mesh_repair_diagnostics(this._vertexCount, this._buffer);
2963
+ const sidDiag = this.storedId();
2964
+ const r = sidDiag > 0
2965
+ ? wasm.mesh_repair_diagnostics_h(sidDiag)
2966
+ : wasm.mesh_repair_diagnostics(this._vertexCount, this._buffer);
2770
2967
  return parseMeshDiagnostics(r, 0);
2771
2968
  }
2772
2969
  /**
@@ -2776,7 +2973,10 @@ export class Mesh {
2776
2973
  */
2777
2974
  boundaryEdgeSegments() {
2778
2975
  ensureInit();
2779
- return wasm.mesh_boundary_edge_segments(this._vertexCount, this._buffer);
2976
+ const sidBes = this.storedId();
2977
+ return sidBes > 0
2978
+ ? wasm.mesh_boundary_edge_segments_h(sidBes)
2979
+ : wasm.mesh_boundary_edge_segments(this._vertexCount, this._buffer);
2780
2980
  }
2781
2981
  /**
2782
2982
  * Chamfer feature edges of this closed solid. Each entry in `edges` is one
@@ -2820,7 +3020,10 @@ export class Mesh {
2820
3020
  */
2821
3021
  featureEdgeChains() {
2822
3022
  ensureInit();
2823
- const r = wasm.mesh_feature_edge_chains(this._vertexCount, this._buffer);
3023
+ const sidFec = this.storedId();
3024
+ const r = sidFec > 0
3025
+ ? wasm.mesh_feature_edge_chains_h(sidFec)
3026
+ : wasm.mesh_feature_edge_chains(this._vertexCount, this._buffer);
2824
3027
  if (!r.length) {
2825
3028
  throw new Error(`Mesh.featureEdgeChains() failed: ${wasm.geometry_last_error() || "unknown error"}`);
2826
3029
  }
@@ -3041,11 +3244,22 @@ Mesh.DEFAULT_BOOLEAN_DEBUG_PROBES = [
3041
3244
  "negZ",
3042
3245
  ];
3043
3246
  Mesh.DEFAULT_BOOLEAN_LIMITS = {
3044
- maxInputFacesPerMesh: 120000,
3045
- maxCombinedInputFaces: 180000,
3046
- maxFaceProduct: 500000000,
3247
+ maxInputFacesPerMesh: 120_000,
3248
+ maxCombinedInputFaces: 180_000,
3249
+ maxFaceProduct: 500_000_000,
3047
3250
  };
3048
- Mesh.TOPOLOGY_METRICS_CACHE_FACE_THRESHOLD = 20000;
3251
+ Mesh.TOPOLOGY_METRICS_CACHE_FACE_THRESHOLD = 20_000;
3252
+ Mesh.residencyFinalizer = typeof FinalizationRegistry !== "undefined"
3253
+ ? new FinalizationRegistry((id) => {
3254
+ try {
3255
+ if (isInitialized())
3256
+ wasm.mesh_store_free(id);
3257
+ }
3258
+ catch {
3259
+ // engine torn down — nothing to free
3260
+ }
3261
+ })
3262
+ : null;
3049
3263
  /** Largest supported arc sweep — just under a full circle keeps arcs open. */
3050
3264
  Mesh.MAX_ARC_SWEEP = Math.PI * 2 - 1e-4;
3051
3265
  //# sourceMappingURL=Mesh.js.map