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.
- package/dist/Arc.js +1 -1
- package/dist/Arc.js.map +1 -1
- package/dist/Brep.js +1 -1
- package/dist/Brep.js.map +1 -1
- package/dist/Circle.js +1 -1
- package/dist/Circle.js.map +1 -1
- package/dist/Line.js +1 -1
- package/dist/Line.js.map +1 -1
- package/dist/Mesh.d.ts +41 -0
- package/dist/Mesh.d.ts.map +1 -1
- package/dist/Mesh.js +235 -21
- package/dist/Mesh.js.map +1 -1
- package/dist/MeshSurface.js +1 -1
- package/dist/MeshSurface.js.map +1 -1
- package/dist/NurbsCurve.js +1 -1
- package/dist/NurbsCurve.js.map +1 -1
- package/dist/NurbsSurface.js +1 -1
- package/dist/NurbsSurface.js.map +1 -1
- package/dist/PolyCurve.js +1 -1
- package/dist/PolyCurve.js.map +1 -1
- package/dist/Polyline.js +1 -1
- package/dist/Polyline.js.map +1 -1
- package/dist/Ray.js +1 -1
- package/dist/Ray.js.map +1 -1
- package/dist/SculptSession.js +1 -1
- package/dist/SculptSession.js.map +1 -1
- package/dist/engine-threaded.d.ts +2 -0
- package/dist/engine-threaded.d.ts.map +1 -0
- package/dist/engine-threaded.js +33 -0
- package/dist/engine-threaded.js.map +1 -0
- package/dist/engine.d.ts +21 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +42 -0
- package/dist/engine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mesh-boolean.pool.d.ts +23 -1
- package/dist/mesh-boolean.pool.d.ts.map +1 -1
- package/dist/mesh-boolean.pool.js +97 -12
- package/dist/mesh-boolean.pool.js.map +1 -1
- package/dist/mesh-boolean.protocol.d.ts +21 -1
- package/dist/mesh-boolean.protocol.d.ts.map +1 -1
- package/dist/mesh-boolean.protocol.js.map +1 -1
- package/dist/mesh-boolean.worker.d.ts.map +1 -1
- package/dist/mesh-boolean.worker.js +94 -1
- package/dist/mesh-boolean.worker.js.map +1 -1
- package/dist/wasm-active.d.ts +20 -0
- package/dist/wasm-active.d.ts.map +1 -0
- package/dist/wasm-active.js +26 -0
- package/dist/wasm-active.js.map +1 -0
- package/dist/wasm-base64-threaded.d.ts +2 -0
- package/dist/wasm-base64-threaded.d.ts.map +1 -0
- package/dist/wasm-base64-threaded.js +3 -0
- package/dist/wasm-base64-threaded.js.map +1 -0
- package/dist/wasm-base64.d.ts +1 -1
- package/dist/wasm-base64.d.ts.map +1 -1
- package/dist/wasm-base64.js +1 -1
- package/dist/wasm-base64.js.map +1 -1
- package/dist/wasm-bindings-threaded.d.ts +2664 -0
- package/dist/wasm-bindings-threaded.d.ts.map +1 -0
- package/dist/wasm-bindings-threaded.js +5008 -0
- package/dist/wasm-bindings-threaded.js.map +1 -0
- package/dist/wasm-bindings.d.ts +130 -0
- package/dist/wasm-bindings.d.ts.map +1 -1
- package/dist/wasm-bindings.js +208 -0
- package/dist/wasm-bindings.js.map +1 -1
- package/dist/workerHelpers-threaded.d.ts +2 -0
- package/dist/workerHelpers-threaded.d.ts.map +1 -0
- package/dist/workerHelpers-threaded.js +100 -0
- package/dist/workerHelpers-threaded.js.map +1 -0
- package/package.json +8 -3
- package/src/Arc.ts +117 -117
- package/src/Brep.ts +1 -1
- package/src/Circle.ts +166 -166
- package/src/Line.ts +171 -171
- package/src/Mesh.ts +300 -45
- package/src/MeshSurface.ts +1 -1
- package/src/NurbsCurve.ts +655 -655
- package/src/NurbsSurface.ts +721 -721
- package/src/PolyCurve.ts +203 -203
- package/src/Polyline.ts +316 -316
- package/src/Ray.ts +90 -90
- package/src/SculptSession.ts +377 -377
- package/src/engine-threaded.ts +39 -0
- package/src/engine.ts +46 -0
- package/src/index.ts +1 -1
- package/src/mesh-boolean.pool.ts +208 -86
- package/src/mesh-boolean.protocol.ts +44 -1
- package/src/mesh-boolean.worker.ts +170 -56
- package/src/wasm-active.ts +31 -0
- package/src/wasm-base64-threaded.ts +2 -0
- package/src/wasm-base64.ts +1 -1
- package/src/wasm-bindings-threaded.d.ts +1989 -0
- package/src/wasm-bindings-threaded.js +5235 -0
- package/src/wasm-bindings.d.ts +104 -0
- package/src/wasm-bindings.js +225 -0
- package/src/workerHelpers-threaded.js +107 -0
package/src/Mesh.ts
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";
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
configureDefaultMeshBooleanWorkerPool,
|
|
18
18
|
disposeMeshBooleanWorkerPools,
|
|
19
19
|
runMeshBooleanInWorkerPool,
|
|
20
|
+
runMeshHeavyInWorkerPool,
|
|
20
21
|
} from "./mesh-boolean.pool.js";
|
|
21
22
|
import { MeshBooleanExecutionError } from "./mesh-boolean.protocol.js";
|
|
22
23
|
import type {
|
|
@@ -24,8 +25,7 @@ import type {
|
|
|
24
25
|
MeshBooleanLimits,
|
|
25
26
|
MeshBooleanOptions,
|
|
26
27
|
} from "./mesh-boolean.protocol.js";
|
|
27
|
-
import
|
|
28
|
-
import { mesh_topology_metrics, mesh_topology_metrics_raw } from "./wasm-bindings.js";
|
|
28
|
+
import { wasm } from "./wasm-active.js";
|
|
29
29
|
|
|
30
30
|
export { MeshBooleanExecutionError };
|
|
31
31
|
export type {
|
|
@@ -362,6 +362,83 @@ export class Mesh {
|
|
|
362
362
|
this._trustedBooleanInput = trustedBooleanInput;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
// ---- WASM-side residency (KERNEL-PERF-ARC lever 2) -----------------------
|
|
366
|
+
//
|
|
367
|
+
// Repeated queries on the same mesh (hover face groups, raycasts, render
|
|
368
|
+
// buffers, diagnostics) skip the per-call JS→WASM buffer copy by storing
|
|
369
|
+
// the buffer WASM-side once; raycasts additionally reuse a cached BVH.
|
|
370
|
+
// Residency is self-tuning: the FIRST hot call uses the classic buffer
|
|
371
|
+
// path (one-shot meshes never pay the store), the second call onward
|
|
372
|
+
// stores. `dispose()` releases eagerly; a FinalizationRegistry frees
|
|
373
|
+
// leaked ids on GC as a safety net. Buffers are immutable, so stored
|
|
374
|
+
// copies never need invalidation.
|
|
375
|
+
|
|
376
|
+
private _storeId: number | null = null;
|
|
377
|
+
private _hotCallCount = 0;
|
|
378
|
+
|
|
379
|
+
private static residencyFinalizer: FinalizationRegistry<number> | null =
|
|
380
|
+
typeof FinalizationRegistry !== "undefined"
|
|
381
|
+
? new FinalizationRegistry<number>((id) => {
|
|
382
|
+
try {
|
|
383
|
+
if (isInitialized()) wasm.mesh_store_free(id);
|
|
384
|
+
} catch {
|
|
385
|
+
// engine torn down — nothing to free
|
|
386
|
+
}
|
|
387
|
+
})
|
|
388
|
+
: null;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* WASM-side stored-mesh id, or 0 when this call should use the buffer
|
|
392
|
+
* path (first hot call, store failure, or disposed-and-cold mesh).
|
|
393
|
+
*/
|
|
394
|
+
private storedId(): number {
|
|
395
|
+
if (this._storeId !== null) return this._storeId;
|
|
396
|
+
if (this._hotCallCount < 1) {
|
|
397
|
+
this._hotCallCount++;
|
|
398
|
+
return 0;
|
|
399
|
+
}
|
|
400
|
+
let id = 0;
|
|
401
|
+
try {
|
|
402
|
+
id = wasm.mesh_store(this._vertexCount, this._buffer);
|
|
403
|
+
} catch {
|
|
404
|
+
id = 0;
|
|
405
|
+
}
|
|
406
|
+
this._storeId = id;
|
|
407
|
+
if (id > 0) Mesh.residencyFinalizer?.register(this, id, this);
|
|
408
|
+
return id;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Release this mesh's WASM-side stored copy (idempotent). The mesh stays
|
|
413
|
+
* fully usable — the next repeated hot call re-stores it. Call from
|
|
414
|
+
* long-lived hosts (okdraw engine-bridge release paths) to return WASM
|
|
415
|
+
* memory promptly instead of waiting for GC.
|
|
416
|
+
*/
|
|
417
|
+
dispose(): void {
|
|
418
|
+
if (this._storeId !== null && this._storeId > 0) {
|
|
419
|
+
try {
|
|
420
|
+
wasm.mesh_store_free(this._storeId);
|
|
421
|
+
} catch {
|
|
422
|
+
// engine torn down — nothing to free
|
|
423
|
+
}
|
|
424
|
+
Mesh.residencyFinalizer?.unregister(this);
|
|
425
|
+
}
|
|
426
|
+
this._storeId = null;
|
|
427
|
+
this._hotCallCount = 0;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/** Number of meshes currently resident WASM-side (diagnostics/tests). */
|
|
431
|
+
static residentMeshCount(): number {
|
|
432
|
+
ensureInit();
|
|
433
|
+
return wasm.mesh_store_count();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** Approximate bytes of WASM-side resident mesh buffers (diagnostics). */
|
|
437
|
+
static residentMeshBytes(): number {
|
|
438
|
+
ensureInit();
|
|
439
|
+
return wasm.mesh_store_bytes();
|
|
440
|
+
}
|
|
441
|
+
|
|
365
442
|
/**
|
|
366
443
|
* Configure default size for the shared boolean worker pool.
|
|
367
444
|
*/
|
|
@@ -2198,7 +2275,10 @@ export class Mesh {
|
|
|
2198
2275
|
if (this._edgeVertexPairs) return this._edgeVertexPairs;
|
|
2199
2276
|
|
|
2200
2277
|
ensureInit();
|
|
2201
|
-
const
|
|
2278
|
+
const sidEdges = this.storedId();
|
|
2279
|
+
const packed = sidEdges > 0
|
|
2280
|
+
? wasm.mesh_get_edge_vertex_pairs_h(sidEdges)
|
|
2281
|
+
: wasm.mesh_get_edge_vertex_pairs(this._vertexCount, this._buffer);
|
|
2202
2282
|
const edgeCount = Math.max(0, Math.floor(packed[0] ?? 0));
|
|
2203
2283
|
const pairs: Array<[number, number]> = [];
|
|
2204
2284
|
let off = 1;
|
|
@@ -3111,6 +3191,141 @@ export class Mesh {
|
|
|
3111
3191
|
}
|
|
3112
3192
|
}
|
|
3113
3193
|
|
|
3194
|
+
// ── Heavy async ops on the worker pool (KERNEL-PERF-ARC lever 4) ──
|
|
3195
|
+
//
|
|
3196
|
+
// Multi-second operations run off the main thread with the same
|
|
3197
|
+
// fallback contract as the pairwise async booleans: any worker-side
|
|
3198
|
+
// failure falls back to the synchronous main-thread path.
|
|
3199
|
+
|
|
3200
|
+
/** Async `Mesh.unionAll` on the worker pool. */
|
|
3201
|
+
static async unionAllAsync(
|
|
3202
|
+
meshes: Mesh[],
|
|
3203
|
+
options?: MeshBooleanAsyncOptions,
|
|
3204
|
+
): Promise<Mesh> {
|
|
3205
|
+
try {
|
|
3206
|
+
const { buffer } = await runMeshHeavyInWorkerPool(
|
|
3207
|
+
"unionAll",
|
|
3208
|
+
meshes.map((m) => m._buffer),
|
|
3209
|
+
{ ...options, trusted: meshes.map((m) => m._trustedBooleanInput) },
|
|
3210
|
+
);
|
|
3211
|
+
return Mesh.fromTrustedBuffer(buffer);
|
|
3212
|
+
} catch (error) {
|
|
3213
|
+
if (!shouldFallbackFromWorkerFailure(error)) throw error;
|
|
3214
|
+
console.warn("Mesh.unionAllAsync worker failed; falling back to main thread.", error);
|
|
3215
|
+
return Mesh.unionAll(meshes, {
|
|
3216
|
+
allowUnsafe: options?.allowUnsafe ?? true,
|
|
3217
|
+
limits: options?.limits,
|
|
3218
|
+
});
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
/** Async `mesh.subtractAll` on the worker pool. */
|
|
3223
|
+
async subtractAllAsync(
|
|
3224
|
+
cutters: Mesh[],
|
|
3225
|
+
options?: MeshBooleanAsyncOptions,
|
|
3226
|
+
): Promise<Mesh> {
|
|
3227
|
+
try {
|
|
3228
|
+
const { buffer } = await runMeshHeavyInWorkerPool(
|
|
3229
|
+
"differenceAll",
|
|
3230
|
+
[this._buffer, ...cutters.map((m) => m._buffer)],
|
|
3231
|
+
{
|
|
3232
|
+
...options,
|
|
3233
|
+
trusted: [this._trustedBooleanInput, ...cutters.map((m) => m._trustedBooleanInput)],
|
|
3234
|
+
},
|
|
3235
|
+
);
|
|
3236
|
+
return Mesh.fromTrustedBuffer(buffer);
|
|
3237
|
+
} catch (error) {
|
|
3238
|
+
if (!shouldFallbackFromWorkerFailure(error)) throw error;
|
|
3239
|
+
console.warn("Mesh.subtractAllAsync worker failed; falling back to main thread.", error);
|
|
3240
|
+
return this.subtractAll(cutters, {
|
|
3241
|
+
allowUnsafe: options?.allowUnsafe ?? true,
|
|
3242
|
+
limits: options?.limits,
|
|
3243
|
+
});
|
|
3244
|
+
}
|
|
3245
|
+
}
|
|
3246
|
+
|
|
3247
|
+
/** Async `mesh.makeWatertight` on the worker pool. NOTE: the async
|
|
3248
|
+
* variant reports the result mesh, method and effective resolution;
|
|
3249
|
+
* before/after diagnostics can be recomputed by the caller if needed. */
|
|
3250
|
+
async makeWatertightAsync(
|
|
3251
|
+
options: { resolution?: number; iso?: number } & MeshBooleanAsyncOptions = {},
|
|
3252
|
+
): Promise<{ mesh: Mesh; method: "repair" | "remesh"; effectiveResolution: number }> {
|
|
3253
|
+
try {
|
|
3254
|
+
const { buffer, meta } = await runMeshHeavyInWorkerPool(
|
|
3255
|
+
"makeWatertight",
|
|
3256
|
+
[this._buffer],
|
|
3257
|
+
{
|
|
3258
|
+
...options,
|
|
3259
|
+
trusted: [this._trustedBooleanInput],
|
|
3260
|
+
params: { resolution: options.resolution, iso: options.iso },
|
|
3261
|
+
},
|
|
3262
|
+
);
|
|
3263
|
+
return {
|
|
3264
|
+
mesh: Mesh.fromTrustedBuffer(buffer),
|
|
3265
|
+
method: (meta?.method as "repair" | "remesh") ?? "repair",
|
|
3266
|
+
effectiveResolution: Number(meta?.effectiveResolution ?? 0),
|
|
3267
|
+
};
|
|
3268
|
+
} catch (error) {
|
|
3269
|
+
if (!shouldFallbackFromWorkerFailure(error)) throw error;
|
|
3270
|
+
console.warn("Mesh.makeWatertightAsync worker failed; falling back to main thread.", error);
|
|
3271
|
+
const r = this.makeWatertight({ resolution: options.resolution, iso: options.iso });
|
|
3272
|
+
return { mesh: r.mesh, method: r.method, effectiveResolution: r.effectiveResolution };
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
/** Async `mesh.voxelRemesh` on the worker pool. */
|
|
3277
|
+
async voxelRemeshAsync(
|
|
3278
|
+
resolution = 0,
|
|
3279
|
+
iso = 0.5,
|
|
3280
|
+
options?: MeshBooleanAsyncOptions,
|
|
3281
|
+
): Promise<Mesh> {
|
|
3282
|
+
try {
|
|
3283
|
+
const { buffer } = await runMeshHeavyInWorkerPool("voxelRemesh", [this._buffer], {
|
|
3284
|
+
...options,
|
|
3285
|
+
trusted: [this._trustedBooleanInput],
|
|
3286
|
+
params: { resolution, iso },
|
|
3287
|
+
});
|
|
3288
|
+
return Mesh.fromTrustedBuffer(buffer);
|
|
3289
|
+
} catch (error) {
|
|
3290
|
+
if (!shouldFallbackFromWorkerFailure(error)) throw error;
|
|
3291
|
+
console.warn("Mesh.voxelRemeshAsync worker failed; falling back to main thread.", error);
|
|
3292
|
+
return this.voxelRemesh(resolution, iso);
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
/** Async `mesh.chamferEdges` on the worker pool. */
|
|
3297
|
+
async chamferEdgesAsync(
|
|
3298
|
+
edges: Array<{ a: Point | Vec3; b: Point | Vec3 }>,
|
|
3299
|
+
distance: number,
|
|
3300
|
+
options?: MeshBooleanAsyncOptions,
|
|
3301
|
+
): Promise<Mesh> {
|
|
3302
|
+
const flat = new Float64Array(edges.length * 6);
|
|
3303
|
+
edges.forEach((edge, i) => {
|
|
3304
|
+
flat[i * 6] = edge.a.x;
|
|
3305
|
+
flat[i * 6 + 1] = edge.a.y;
|
|
3306
|
+
flat[i * 6 + 2] = edge.a.z;
|
|
3307
|
+
flat[i * 6 + 3] = edge.b.x;
|
|
3308
|
+
flat[i * 6 + 4] = edge.b.y;
|
|
3309
|
+
flat[i * 6 + 5] = edge.b.z;
|
|
3310
|
+
});
|
|
3311
|
+
try {
|
|
3312
|
+
const { buffer } = await runMeshHeavyInWorkerPool(
|
|
3313
|
+
"chamferEdges",
|
|
3314
|
+
[this._buffer, flat],
|
|
3315
|
+
{
|
|
3316
|
+
...options,
|
|
3317
|
+
trusted: [this._trustedBooleanInput],
|
|
3318
|
+
params: { distance },
|
|
3319
|
+
},
|
|
3320
|
+
);
|
|
3321
|
+
return Mesh.fromTrustedBuffer(buffer);
|
|
3322
|
+
} catch (error) {
|
|
3323
|
+
if (!shouldFallbackFromWorkerFailure(error)) throw error;
|
|
3324
|
+
console.warn("Mesh.chamferEdgesAsync worker failed; falling back to main thread.", error);
|
|
3325
|
+
return this.chamferEdges(edges, distance);
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3114
3329
|
// ── Intersection queries ───────────────────────────────────────
|
|
3115
3330
|
|
|
3116
3331
|
/**
|
|
@@ -3459,7 +3674,10 @@ export class Mesh {
|
|
|
3459
3674
|
getCoplanarFaceIndices(faceIndex: number): number[] {
|
|
3460
3675
|
ensureInit();
|
|
3461
3676
|
if (!Number.isFinite(faceIndex) || faceIndex < 0) return [];
|
|
3462
|
-
const
|
|
3677
|
+
const sidCfi = this.storedId();
|
|
3678
|
+
const r = sidCfi > 0
|
|
3679
|
+
? wasm.mesh_get_coplanar_face_indices_h(sidCfi, Math.floor(faceIndex))
|
|
3680
|
+
: wasm.mesh_get_coplanar_face_indices(this._vertexCount, this._buffer, Math.floor(faceIndex));
|
|
3463
3681
|
const count = Math.max(0, Math.floor(r[0] ?? 0));
|
|
3464
3682
|
const out: number[] = [];
|
|
3465
3683
|
for (let i = 0; i < count; i++) {
|
|
@@ -3483,12 +3701,15 @@ export class Mesh {
|
|
|
3483
3701
|
if (!Number.isFinite(faceIndex) || faceIndex < 0) {
|
|
3484
3702
|
return { faceIndices: [], isPlanar: true };
|
|
3485
3703
|
}
|
|
3486
|
-
const
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3704
|
+
const sidSfg = this.storedId();
|
|
3705
|
+
const r = sidSfg > 0
|
|
3706
|
+
? wasm.mesh_get_smooth_face_group_h(sidSfg, Math.floor(faceIndex), maxAngleDeg)
|
|
3707
|
+
: wasm.mesh_get_smooth_face_group(
|
|
3708
|
+
this._vertexCount,
|
|
3709
|
+
this._buffer,
|
|
3710
|
+
Math.floor(faceIndex),
|
|
3711
|
+
maxAngleDeg,
|
|
3712
|
+
);
|
|
3492
3713
|
const count = Math.max(0, Math.floor(r[0] ?? 0));
|
|
3493
3714
|
const isPlanar = (r[1] ?? 1) !== 0;
|
|
3494
3715
|
const faceIndices: number[] = [];
|
|
@@ -3515,11 +3736,14 @@ export class Mesh {
|
|
|
3515
3736
|
featureEdges: Float32Array;
|
|
3516
3737
|
} {
|
|
3517
3738
|
ensureInit();
|
|
3518
|
-
const
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3739
|
+
const sidRb = this.storedId();
|
|
3740
|
+
const r: Float32Array = sidRb > 0
|
|
3741
|
+
? wasm.mesh_build_render_buffers_h(sidRb, creaseAngleDeg)
|
|
3742
|
+
: wasm.mesh_build_render_buffers(
|
|
3743
|
+
this._vertexCount,
|
|
3744
|
+
this._buffer,
|
|
3745
|
+
creaseAngleDeg,
|
|
3746
|
+
);
|
|
3523
3747
|
const vertexCount = Math.max(0, Math.floor(r[0] ?? 0));
|
|
3524
3748
|
const posStart = 1;
|
|
3525
3749
|
const norStart = posStart + vertexCount * 3;
|
|
@@ -3582,11 +3806,14 @@ export class Mesh {
|
|
|
3582
3806
|
getCoplanarFaceGroupCentroid(faceIndex: number): Point | null {
|
|
3583
3807
|
ensureInit();
|
|
3584
3808
|
if (!Number.isFinite(faceIndex) || faceIndex < 0) return null;
|
|
3585
|
-
const
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3809
|
+
const sidCent = this.storedId();
|
|
3810
|
+
const r = sidCent > 0
|
|
3811
|
+
? wasm.mesh_get_coplanar_face_group_centroid_h(sidCent, Math.floor(faceIndex))
|
|
3812
|
+
: wasm.mesh_get_coplanar_face_group_centroid(
|
|
3813
|
+
this._vertexCount,
|
|
3814
|
+
this._buffer,
|
|
3815
|
+
Math.floor(faceIndex),
|
|
3816
|
+
);
|
|
3590
3817
|
if (!r || r.length < 3) return null;
|
|
3591
3818
|
return new Point(r[0], r[1], r[2]);
|
|
3592
3819
|
}
|
|
@@ -3600,11 +3827,14 @@ export class Mesh {
|
|
|
3600
3827
|
getFaceBoundaryLoops(faceIndex: number): Point[][] {
|
|
3601
3828
|
ensureInit();
|
|
3602
3829
|
if (!Number.isFinite(faceIndex) || faceIndex < 0) return [];
|
|
3603
|
-
const
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3830
|
+
const sidLoops = this.storedId();
|
|
3831
|
+
const r = sidLoops > 0
|
|
3832
|
+
? wasm.mesh_get_face_boundary_loops_h(sidLoops, Math.floor(faceIndex))
|
|
3833
|
+
: wasm.mesh_get_face_boundary_loops(
|
|
3834
|
+
this._vertexCount,
|
|
3835
|
+
this._buffer,
|
|
3836
|
+
Math.floor(faceIndex),
|
|
3837
|
+
);
|
|
3608
3838
|
if (!r || r.length < 1) return [];
|
|
3609
3839
|
const loopCount = Math.floor(r[0]);
|
|
3610
3840
|
const loops: Point[][] = [];
|
|
@@ -3658,13 +3888,21 @@ export class Mesh {
|
|
|
3658
3888
|
maxDistance = Number.POSITIVE_INFINITY,
|
|
3659
3889
|
): { point: Point; normal: Vec3; faceIndex: number; distance: number } | null {
|
|
3660
3890
|
ensureInit();
|
|
3661
|
-
const
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3891
|
+
const sidRay = this.storedId();
|
|
3892
|
+
const r = sidRay > 0
|
|
3893
|
+
? wasm.mesh_raycast_h(
|
|
3894
|
+
sidRay,
|
|
3895
|
+
origin.x, origin.y, origin.z,
|
|
3896
|
+
direction.x, direction.y, direction.z,
|
|
3897
|
+
maxDistance,
|
|
3898
|
+
)
|
|
3899
|
+
: wasm.mesh_raycast(
|
|
3900
|
+
this._vertexCount,
|
|
3901
|
+
this._buffer,
|
|
3902
|
+
origin.x, origin.y, origin.z,
|
|
3903
|
+
direction.x, direction.y, direction.z,
|
|
3904
|
+
maxDistance,
|
|
3905
|
+
);
|
|
3668
3906
|
if (!r || r.length < 8) return null;
|
|
3669
3907
|
return {
|
|
3670
3908
|
point: new Point(r[0], r[1], r[2]),
|
|
@@ -3683,13 +3921,21 @@ export class Mesh {
|
|
|
3683
3921
|
maxDistance = Number.POSITIVE_INFINITY,
|
|
3684
3922
|
): Array<{ point: Point; normal: Vec3; faceIndex: number; distance: number }> {
|
|
3685
3923
|
ensureInit();
|
|
3686
|
-
const
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3924
|
+
const sidRayAll = this.storedId();
|
|
3925
|
+
const buf = sidRayAll > 0
|
|
3926
|
+
? wasm.mesh_raycast_all_h(
|
|
3927
|
+
sidRayAll,
|
|
3928
|
+
origin.x, origin.y, origin.z,
|
|
3929
|
+
direction.x, direction.y, direction.z,
|
|
3930
|
+
maxDistance,
|
|
3931
|
+
)
|
|
3932
|
+
: wasm.mesh_raycast_all(
|
|
3933
|
+
this._vertexCount,
|
|
3934
|
+
this._buffer,
|
|
3935
|
+
origin.x, origin.y, origin.z,
|
|
3936
|
+
direction.x, direction.y, direction.z,
|
|
3937
|
+
maxDistance,
|
|
3938
|
+
);
|
|
3693
3939
|
const count = Math.max(0, Math.floor(buf[0] ?? 0));
|
|
3694
3940
|
const hits: Array<{ point: Point; normal: Vec3; faceIndex: number; distance: number }> = [];
|
|
3695
3941
|
let off = 1;
|
|
@@ -3774,8 +4020,8 @@ export class Mesh {
|
|
|
3774
4020
|
|
|
3775
4021
|
ensureInit();
|
|
3776
4022
|
const metrics = this._trustedBooleanInput
|
|
3777
|
-
? mesh_topology_metrics_raw(this._vertexCount, this._buffer)
|
|
3778
|
-
: mesh_topology_metrics(this._vertexCount, this._buffer);
|
|
4023
|
+
? wasm.mesh_topology_metrics_raw(this._vertexCount, this._buffer)
|
|
4024
|
+
: wasm.mesh_topology_metrics(this._vertexCount, this._buffer);
|
|
3779
4025
|
const boundaryEdges = Math.floor(metrics[0] ?? 0);
|
|
3780
4026
|
const nonManifoldEdges = Math.floor(metrics[1] ?? 0);
|
|
3781
4027
|
this._topologyMetricsCache = { boundaryEdges, nonManifoldEdges };
|
|
@@ -3795,7 +4041,10 @@ export class Mesh {
|
|
|
3795
4041
|
*/
|
|
3796
4042
|
diagnostics(): MeshDiagnostics {
|
|
3797
4043
|
ensureInit();
|
|
3798
|
-
const
|
|
4044
|
+
const sidDiag = this.storedId();
|
|
4045
|
+
const r = sidDiag > 0
|
|
4046
|
+
? wasm.mesh_repair_diagnostics_h(sidDiag)
|
|
4047
|
+
: wasm.mesh_repair_diagnostics(this._vertexCount, this._buffer);
|
|
3799
4048
|
return parseMeshDiagnostics(r, 0);
|
|
3800
4049
|
}
|
|
3801
4050
|
|
|
@@ -3806,7 +4055,10 @@ export class Mesh {
|
|
|
3806
4055
|
*/
|
|
3807
4056
|
boundaryEdgeSegments(): Float64Array {
|
|
3808
4057
|
ensureInit();
|
|
3809
|
-
|
|
4058
|
+
const sidBes = this.storedId();
|
|
4059
|
+
return sidBes > 0
|
|
4060
|
+
? wasm.mesh_boundary_edge_segments_h(sidBes)
|
|
4061
|
+
: wasm.mesh_boundary_edge_segments(this._vertexCount, this._buffer);
|
|
3810
4062
|
}
|
|
3811
4063
|
|
|
3812
4064
|
/**
|
|
@@ -3857,7 +4109,10 @@ export class Mesh {
|
|
|
3857
4109
|
*/
|
|
3858
4110
|
featureEdgeChains(): Array<{ closed: boolean; points: Float64Array }> {
|
|
3859
4111
|
ensureInit();
|
|
3860
|
-
const
|
|
4112
|
+
const sidFec = this.storedId();
|
|
4113
|
+
const r = sidFec > 0
|
|
4114
|
+
? wasm.mesh_feature_edge_chains_h(sidFec)
|
|
4115
|
+
: wasm.mesh_feature_edge_chains(this._vertexCount, this._buffer);
|
|
3861
4116
|
if (!r.length) {
|
|
3862
4117
|
throw new Error(
|
|
3863
4118
|
`Mesh.featureEdgeChains() failed: ${wasm.geometry_last_error() || "unknown error"}`,
|
package/src/MeshSurface.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { Mesh, MeshPlanarFace } from "./Mesh.js";
|
|
|
4
4
|
import { Point } from "./Point.js";
|
|
5
5
|
import type { Surface } from "./Surface.js";
|
|
6
6
|
import { Vec3 } from "./Vec3.js";
|
|
7
|
-
import
|
|
7
|
+
import { wasm } from "./wasm-active.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Logical planar surface extracted from a coplanar connected face group on a mesh.
|