brepjs 18.66.1 → 18.67.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/2d.cjs +6 -6
- package/dist/2d.js +6 -6
- package/dist/{blueprint-DUu2ps2h.js → blueprint-Z5mhI2QD.js} +5 -5
- package/dist/{blueprint-D0HcOCoD.cjs → blueprint-a7QLhV4U.cjs} +5 -5
- package/dist/{blueprintFns-BoMZHBGl.js → blueprintFns-BNhsXv6q.js} +2 -2
- package/dist/{blueprintFns-pq0yw94E.cjs → blueprintFns-DULa6FpG.cjs} +2 -2
- package/dist/{blueprintSketcher-DelJzBzJ.js → blueprintSketcher-0DeTMXwj.js} +3 -3
- package/dist/{blueprintSketcher-CWSesXXR.cjs → blueprintSketcher-4zOPSOnK.cjs} +3 -3
- package/dist/{boolean2D-DYjuIlFY.js → boolean2D-BNWuFXK_.js} +4 -4
- package/dist/{boolean2D-C6xLLzU_.cjs → boolean2D-xDBZQH_n.cjs} +4 -4
- package/dist/{booleanFns-CLzeqmgT.js → booleanFns-CaKngiuu.js} +4 -4
- package/dist/{booleanFns-D57G9tJA.cjs → booleanFns-aeG4pQmM.cjs} +4 -4
- package/dist/brepjs.cjs +312 -46
- package/dist/brepjs.js +304 -47
- package/dist/{cameraFns-DSAYGgrz.cjs → cameraFns-Bk8frXwa.cjs} +2 -2
- package/dist/{cameraFns-D_UnhA2O.js → cameraFns-k787od3u.js} +2 -2
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/{cornerFinder-CszkHDW1.js → cornerFinder-B8GvvW0U.js} +1 -1
- package/dist/{cornerFinder-Dvu2q_-E.cjs → cornerFinder-tTS3ny7e.cjs} +1 -1
- package/dist/{curveFns-BJLQixZw.cjs → curveFns-CYP8UOgX.cjs} +1 -1
- package/dist/{curveFns-CLNHpU2N.js → curveFns-DvNBwUdJ.js} +1 -1
- package/dist/{drawFns-BuE0lne3.cjs → drawFns-Chpdmj4G.cjs} +12 -12
- package/dist/{drawFns-Cw29tkrx.js → drawFns-DmAPsfmx.js} +12 -12
- package/dist/{extrudeFns-19bOK66L.js → extrudeFns-CMr1tf7I.js} +1 -1
- package/dist/{extrudeFns-BDgqrytA.cjs → extrudeFns-IvYW5-8y.cjs} +1 -1
- package/dist/{faceFns-BmaS4kkW.cjs → faceFns-Byt7Vd3F.cjs} +2 -2
- package/dist/{faceFns-CWU_70z7.js → faceFns-CZp3Y8vi.js} +2 -2
- package/dist/{helpers-CA8uFXQW.js → helpers-BX-0e71G.js} +6 -6
- package/dist/{helpers-qkB-gFkC.cjs → helpers-wFts3ttt.cjs} +6 -6
- package/dist/{historyFns-CDVZ3KM8.cjs → historyFns-BzPsKySX.cjs} +4 -4
- package/dist/{historyFns-CnUZzNHQ.js → historyFns-CZ9oNL7j.js} +4 -4
- package/dist/{importFns-BBnjqm6T.js → importFns-1SHLSNtG.js} +2 -2
- package/dist/{importFns-B7pbqJhZ.cjs → importFns-CwILDYiQ.cjs} +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/io.cjs +2 -2
- package/dist/io.js +2 -2
- package/dist/{measureFns-HhPPUiRO.cjs → measureFns-CrSEblGG.cjs} +3 -3
- package/dist/{measureFns-Bye5UsOe.js → measureFns-CvvenWkS.js} +3 -3
- package/dist/measurement.cjs +1 -1
- package/dist/measurement.js +1 -1
- package/dist/{meshFns-Cog1SKSV.js → meshFns-0RHalM3t.js} +3 -3
- package/dist/{meshFns-B5jxU_H4.cjs → meshFns-DwHAYqRN.cjs} +3 -3
- package/dist/operations.cjs +2 -2
- package/dist/operations.js +2 -2
- package/dist/{primitiveFns-B_Vhus6h.cjs → primitiveFns-CKCALTVe.cjs} +7 -7
- package/dist/{primitiveFns-DTg4kOPD.js → primitiveFns-ecKWNC5k.js} +7 -7
- package/dist/projection.cjs +1 -1
- package/dist/projection.js +1 -1
- package/dist/query.cjs +2 -2
- package/dist/query.js +2 -2
- package/dist/{shapeFns-ClKe2vri.cjs → shapeFns-B5JrP5aD.cjs} +2 -2
- package/dist/{shapeFns-CMQD_3Rz.js → shapeFns-D63FuB8f.js} +2 -2
- package/dist/shapeRef.cjs +1 -1
- package/dist/shapeRef.js +1 -1
- package/dist/{shapeRefFns-DqmUj3wF.js → shapeRefFns-DjGKujf0.js} +4 -4
- package/dist/{shapeRefFns-DUt-hIWq.cjs → shapeRefFns-H_O8zyAx.cjs} +4 -4
- package/dist/{shapeTypes-CQscfe8k.js → shapeTypes-RYLpXWzG.js} +10 -4
- package/dist/{shapeTypes-CPClTSJn.cjs → shapeTypes-kAKwccy_.cjs} +10 -4
- package/dist/sketching.cjs +3 -3
- package/dist/sketching.js +3 -3
- package/dist/{solidBuilders-U04-5yA1.js → solidBuilders-0SgkQ386.js} +2 -2
- package/dist/{solidBuilders-CtxTfDlu.cjs → solidBuilders-B2IX6Pm8.cjs} +2 -2
- package/dist/{surfaceBuilders-88vLyzZe.cjs → surfaceBuilders-BkvJS8pw.cjs} +2 -2
- package/dist/{surfaceBuilders-GesSUnRk.js → surfaceBuilders-jx81G_YJ.js} +2 -2
- package/dist/text.cjs +2 -2
- package/dist/text.js +2 -2
- package/dist/{textBlueprints-DP_2uuR2.js → textBlueprints-BXGrW7Ak.js} +7 -7
- package/dist/{textBlueprints-BRqklfRI.cjs → textBlueprints-Q2gxuZd1.cjs} +7 -7
- package/dist/{textMetrics-F2qR-eqQ.cjs → textMetrics-CnCjqf59.cjs} +1 -1
- package/dist/{textMetrics-BAOyWVzI.js → textMetrics-V7TXOETY.js} +1 -1
- package/dist/topology.cjs +7 -7
- package/dist/topology.js +7 -7
- package/dist/{topologyQueryFns-BuZ2h4o9.js → topologyQueryFns-BtWPlP5v.js} +1 -1
- package/dist/{topologyQueryFns-jK9Vpzqr.cjs → topologyQueryFns-Ck5trXrW.cjs} +1 -1
- package/dist/voxel/engine.d.ts +43 -0
- package/dist/voxel/fieldFns.d.ts +120 -0
- package/dist/voxel/index.d.ts +2 -0
- package/package.json +1 -1
package/dist/brepjs.cjs
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_textBlueprints = require("./textBlueprints-
|
|
3
|
-
const require_shapeTypes = require("./shapeTypes-
|
|
2
|
+
const require_textBlueprints = require("./textBlueprints-Q2gxuZd1.cjs");
|
|
3
|
+
const require_shapeTypes = require("./shapeTypes-kAKwccy_.cjs");
|
|
4
4
|
const require_occtWasmAdapter = require("./occtWasmAdapter-BPu07Zxg.cjs");
|
|
5
5
|
const require_vec3 = require("./vec3-CFwOI0ZI.cjs");
|
|
6
6
|
const require_errors = require("./errors-CXJtc4I7.cjs");
|
|
7
|
-
const require_topologyQueryFns = require("./topologyQueryFns-
|
|
7
|
+
const require_topologyQueryFns = require("./topologyQueryFns-Ck5trXrW.cjs");
|
|
8
8
|
const require_constants = require("./constants-BOVyEYGH.cjs");
|
|
9
9
|
const require_types = require("./types-KjA8tY4Y.cjs");
|
|
10
10
|
const require_vecOps = require("./vecOps-CCnJt-yH.cjs");
|
|
11
11
|
const require_planeOps = require("./planeOps-BA4HfgQu.cjs");
|
|
12
|
-
const require_faceFns = require("./faceFns-
|
|
13
|
-
const require_shapeFns = require("./shapeFns-
|
|
14
|
-
const require_curveFns = require("./curveFns-
|
|
15
|
-
const require_meshFns = require("./meshFns-
|
|
12
|
+
const require_faceFns = require("./faceFns-Byt7Vd3F.cjs");
|
|
13
|
+
const require_shapeFns = require("./shapeFns-B5JrP5aD.cjs");
|
|
14
|
+
const require_curveFns = require("./curveFns-CYP8UOgX.cjs");
|
|
15
|
+
const require_meshFns = require("./meshFns-DwHAYqRN.cjs");
|
|
16
16
|
const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
|
|
17
|
-
const require_surfaceBuilders = require("./surfaceBuilders-
|
|
18
|
-
const require_booleanFns = require("./booleanFns-
|
|
19
|
-
const require_primitiveFns = require("./primitiveFns-
|
|
20
|
-
const require_historyFns = require("./historyFns-
|
|
21
|
-
const require_blueprintSketcher = require("./blueprintSketcher-
|
|
22
|
-
const require_helpers = require("./helpers-
|
|
23
|
-
const require_drawFns = require("./drawFns-
|
|
24
|
-
const require_solidBuilders = require("./solidBuilders-
|
|
25
|
-
const require_measureFns = require("./measureFns-
|
|
26
|
-
const require_cornerFinder = require("./cornerFinder-
|
|
27
|
-
const require_boolean2D = require("./boolean2D-
|
|
28
|
-
const require_blueprintFns = require("./blueprintFns-
|
|
29
|
-
const require_importFns = require("./importFns-
|
|
30
|
-
const require_extrudeFns = require("./extrudeFns-
|
|
31
|
-
const require_cameraFns = require("./cameraFns-
|
|
32
|
-
const require_textMetrics = require("./textMetrics-
|
|
33
|
-
const require_shapeRefFns = require("./shapeRefFns-
|
|
17
|
+
const require_surfaceBuilders = require("./surfaceBuilders-BkvJS8pw.cjs");
|
|
18
|
+
const require_booleanFns = require("./booleanFns-aeG4pQmM.cjs");
|
|
19
|
+
const require_primitiveFns = require("./primitiveFns-CKCALTVe.cjs");
|
|
20
|
+
const require_historyFns = require("./historyFns-BzPsKySX.cjs");
|
|
21
|
+
const require_blueprintSketcher = require("./blueprintSketcher-4zOPSOnK.cjs");
|
|
22
|
+
const require_helpers = require("./helpers-wFts3ttt.cjs");
|
|
23
|
+
const require_drawFns = require("./drawFns-Chpdmj4G.cjs");
|
|
24
|
+
const require_solidBuilders = require("./solidBuilders-B2IX6Pm8.cjs");
|
|
25
|
+
const require_measureFns = require("./measureFns-CrSEblGG.cjs");
|
|
26
|
+
const require_cornerFinder = require("./cornerFinder-tTS3ny7e.cjs");
|
|
27
|
+
const require_boolean2D = require("./boolean2D-xDBZQH_n.cjs");
|
|
28
|
+
const require_blueprintFns = require("./blueprintFns-DULa6FpG.cjs");
|
|
29
|
+
const require_importFns = require("./importFns-CwILDYiQ.cjs");
|
|
30
|
+
const require_extrudeFns = require("./extrudeFns-IvYW5-8y.cjs");
|
|
31
|
+
const require_cameraFns = require("./cameraFns-Bk8frXwa.cjs");
|
|
32
|
+
const require_textMetrics = require("./textMetrics-CnCjqf59.cjs");
|
|
33
|
+
const require_shapeRefFns = require("./shapeRefFns-H_O8zyAx.cjs");
|
|
34
34
|
const require_workerHandler = require("./workerHandler-CdlOTwJg.cjs");
|
|
35
35
|
//#region src/topology/shapeBooleans.ts
|
|
36
36
|
var BOPAlgo_GlueShift = 1;
|
|
@@ -218,8 +218,8 @@ function pointsInside(mesh, queries, id) {
|
|
|
218
218
|
}
|
|
219
219
|
//#endregion
|
|
220
220
|
//#region src/voxel/repairFns.ts
|
|
221
|
-
var DEFAULT_RESOLUTION$
|
|
222
|
-
var DEFAULT_PADDING$
|
|
221
|
+
var DEFAULT_RESOLUTION$3 = 48;
|
|
222
|
+
var DEFAULT_PADDING$3 = 2;
|
|
223
223
|
/**
|
|
224
224
|
* Repair a (possibly non-watertight) triangle-soup mesh into a closed surface:
|
|
225
225
|
* voxelize an FWN-signed SDF, then Surface-Nets contour it back to triangles.
|
|
@@ -232,16 +232,16 @@ function repairMesh(mesh, opts, id) {
|
|
|
232
232
|
const invalid = validateMesh(mesh);
|
|
233
233
|
if (invalid) return require_errors.err(invalid);
|
|
234
234
|
if (mesh.vertices.length === 0 || mesh.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "repairMesh requires a non-empty triangle mesh."));
|
|
235
|
-
const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$
|
|
236
|
-
const padding = opts?.padding ?? DEFAULT_PADDING$
|
|
235
|
+
const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$3;
|
|
236
|
+
const padding = opts?.padding ?? DEFAULT_PADDING$3;
|
|
237
237
|
if (!Number.isInteger(resolution) || resolution < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_RESOLUTION", "resolution must be an integer >= 1."));
|
|
238
238
|
if (!Number.isInteger(padding) || padding < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_PADDING", "padding must be an integer >= 1."));
|
|
239
239
|
const engine = resolveEngine(id);
|
|
240
240
|
if (require_errors.isErr(engine)) return engine;
|
|
241
241
|
try {
|
|
242
242
|
try {
|
|
243
|
-
var _usingCtx$
|
|
244
|
-
const repaired = _usingCtx$
|
|
243
|
+
var _usingCtx$7 = require_shapeTypes._usingCtx();
|
|
244
|
+
const repaired = _usingCtx$7.u(engine.value.repair_mesh(mesh.vertices, mesh.triangles, resolution, padding));
|
|
245
245
|
const vertexCount = repaired.positions.length / 3;
|
|
246
246
|
return require_errors.ok({
|
|
247
247
|
vertices: repaired.positions,
|
|
@@ -255,9 +255,9 @@ function repairMesh(mesh, opts, id) {
|
|
|
255
255
|
}]
|
|
256
256
|
});
|
|
257
257
|
} catch (_) {
|
|
258
|
-
_usingCtx$
|
|
258
|
+
_usingCtx$7.e = _;
|
|
259
259
|
} finally {
|
|
260
|
-
_usingCtx$
|
|
260
|
+
_usingCtx$7.d();
|
|
261
261
|
}
|
|
262
262
|
} catch (cause) {
|
|
263
263
|
return require_errors.err(require_errors.computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
|
|
@@ -286,16 +286,16 @@ function shapeToMeshInput(shape, deflection = DEFAULT_DEFLECTION) {
|
|
|
286
286
|
}
|
|
287
287
|
//#endregion
|
|
288
288
|
//#region src/voxel/meshOpsFns.ts
|
|
289
|
-
var DEFAULT_RESOLUTION$
|
|
290
|
-
var DEFAULT_PADDING$
|
|
291
|
-
var BOOLEAN_OP_CODES = {
|
|
289
|
+
var DEFAULT_RESOLUTION$2 = 48;
|
|
290
|
+
var DEFAULT_PADDING$2 = 2;
|
|
291
|
+
var BOOLEAN_OP_CODES$1 = {
|
|
292
292
|
union: 0,
|
|
293
293
|
intersection: 1,
|
|
294
294
|
difference: 2
|
|
295
295
|
};
|
|
296
|
-
function resolveGridParams(opts) {
|
|
297
|
-
const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$
|
|
298
|
-
const padding = opts?.padding ?? DEFAULT_PADDING$
|
|
296
|
+
function resolveGridParams$1(opts) {
|
|
297
|
+
const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$2;
|
|
298
|
+
const padding = opts?.padding ?? DEFAULT_PADDING$2;
|
|
299
299
|
if (!Number.isInteger(resolution) || resolution < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_RESOLUTION", "resolution must be an integer >= 1."));
|
|
300
300
|
if (!Number.isInteger(padding) || padding < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_PADDING", "padding must be an integer >= 1."));
|
|
301
301
|
return require_errors.ok({
|
|
@@ -330,18 +330,18 @@ function offsetMesh(mesh, distance, opts, id) {
|
|
|
330
330
|
if (invalid) return require_errors.err(invalid);
|
|
331
331
|
if (mesh.vertices.length === 0 || mesh.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "offsetMesh requires a non-empty triangle mesh."));
|
|
332
332
|
if (!Number.isFinite(distance)) return require_errors.err(require_errors.validationError("VOXEL_INVALID_DISTANCE", "distance must be a finite number."));
|
|
333
|
-
const params = resolveGridParams(opts);
|
|
333
|
+
const params = resolveGridParams$1(opts);
|
|
334
334
|
if (require_errors.isErr(params)) return params;
|
|
335
335
|
const engine = resolveEngine(id);
|
|
336
336
|
if (require_errors.isErr(engine)) return engine;
|
|
337
337
|
try {
|
|
338
338
|
try {
|
|
339
|
-
var _usingCtx$
|
|
340
|
-
return meshFromResult(_usingCtx$
|
|
339
|
+
var _usingCtx$6 = require_shapeTypes._usingCtx();
|
|
340
|
+
return meshFromResult(_usingCtx$6.u(engine.value.offset_mesh(mesh.vertices, mesh.triangles, distance, params.value.resolution, params.value.padding)));
|
|
341
341
|
} catch (_) {
|
|
342
|
-
_usingCtx$
|
|
342
|
+
_usingCtx$6.e = _;
|
|
343
343
|
} finally {
|
|
344
|
-
_usingCtx$
|
|
344
|
+
_usingCtx$6.d();
|
|
345
345
|
}
|
|
346
346
|
} catch (cause) {
|
|
347
347
|
return require_errors.err(require_errors.computationError("VOXEL_OFFSET_FAILED", cause instanceof Error ? cause.message : "voxel offset failed (grid too large?).", cause));
|
|
@@ -359,7 +359,7 @@ function shellMesh(mesh, thickness, opts, id) {
|
|
|
359
359
|
if (invalid) return require_errors.err(invalid);
|
|
360
360
|
if (mesh.vertices.length === 0 || mesh.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "shellMesh requires a non-empty triangle mesh."));
|
|
361
361
|
if (!Number.isFinite(thickness) || thickness <= 0) return require_errors.err(require_errors.validationError("VOXEL_INVALID_THICKNESS", "thickness must be a finite number > 0."));
|
|
362
|
-
const params = resolveGridParams(opts);
|
|
362
|
+
const params = resolveGridParams$1(opts);
|
|
363
363
|
if (require_errors.isErr(params)) return params;
|
|
364
364
|
const engine = resolveEngine(id);
|
|
365
365
|
if (require_errors.isErr(engine)) return engine;
|
|
@@ -390,8 +390,8 @@ function voxelBoolean(a, b, op, opts, id) {
|
|
|
390
390
|
if (invalidB) return require_errors.err(invalidB);
|
|
391
391
|
if (a.vertices.length === 0 || a.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "voxelBoolean requires a non-empty mesh for operand A."));
|
|
392
392
|
if (b.vertices.length === 0 || b.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "voxelBoolean requires a non-empty mesh for operand B."));
|
|
393
|
-
const opCode = BOOLEAN_OP_CODES[op];
|
|
394
|
-
const params = resolveGridParams(opts);
|
|
393
|
+
const opCode = BOOLEAN_OP_CODES$1[op];
|
|
394
|
+
const params = resolveGridParams$1(opts);
|
|
395
395
|
if (require_errors.isErr(params)) return params;
|
|
396
396
|
const engine = resolveEngine(id);
|
|
397
397
|
if (require_errors.isErr(engine)) return engine;
|
|
@@ -441,6 +441,263 @@ function voxelBooleanShapes(a, b, op, opts, id) {
|
|
|
441
441
|
return voxelBoolean(meshA.value, meshB.value, op, opts, id);
|
|
442
442
|
}
|
|
443
443
|
//#endregion
|
|
444
|
+
//#region src/voxel/fieldFns.ts
|
|
445
|
+
var DEFAULT_RESOLUTION$1 = 48;
|
|
446
|
+
var DEFAULT_PADDING$1 = 2;
|
|
447
|
+
var BOOLEAN_OP_CODES = {
|
|
448
|
+
union: 0,
|
|
449
|
+
intersection: 1,
|
|
450
|
+
difference: 2
|
|
451
|
+
};
|
|
452
|
+
function resolveGridParams(opts) {
|
|
453
|
+
const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$1;
|
|
454
|
+
const padding = opts?.padding ?? DEFAULT_PADDING$1;
|
|
455
|
+
if (!Number.isInteger(resolution) || resolution < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_RESOLUTION", "resolution must be an integer >= 1."));
|
|
456
|
+
if (!Number.isInteger(padding) || padding < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_PADDING", "padding must be an integer >= 1."));
|
|
457
|
+
return require_errors.ok({
|
|
458
|
+
resolution,
|
|
459
|
+
padding
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Copy the buffers out of a WASM {@link VoxelRepairResult} into a plain
|
|
464
|
+
* {@link KernelMeshResult}, freeing the WASM result via `using` (the getters
|
|
465
|
+
* copy, so the mesh survives the free). An empty contour surfaces as an error.
|
|
466
|
+
*/
|
|
467
|
+
function meshFromField(field) {
|
|
468
|
+
try {
|
|
469
|
+
var _usingCtx$5 = require_shapeTypes._usingCtx();
|
|
470
|
+
const rawResult = field.contour();
|
|
471
|
+
const { positions, normals, indices } = _usingCtx$5.u({
|
|
472
|
+
value: rawResult,
|
|
473
|
+
[Symbol.dispose]() {
|
|
474
|
+
rawResult.free();
|
|
475
|
+
}
|
|
476
|
+
}).value;
|
|
477
|
+
if (positions.length === 0 || indices.length === 0) return require_errors.err(require_errors.computationError("VOXEL_DEGENERATE_RESULT", "the voxel field contoured to an empty mesh (over-shrunk offset or disjoint operands?)."));
|
|
478
|
+
const vertexCount = positions.length / 3;
|
|
479
|
+
return require_errors.ok({
|
|
480
|
+
vertices: positions,
|
|
481
|
+
normals,
|
|
482
|
+
triangles: indices,
|
|
483
|
+
uvs: new Float32Array(vertexCount * 2),
|
|
484
|
+
faceGroups: [{
|
|
485
|
+
start: 0,
|
|
486
|
+
count: indices.length / 3,
|
|
487
|
+
faceHash: 0
|
|
488
|
+
}]
|
|
489
|
+
});
|
|
490
|
+
} catch (_) {
|
|
491
|
+
_usingCtx$5.e = _;
|
|
492
|
+
} finally {
|
|
493
|
+
_usingCtx$5.d();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
function fieldDeletable(raw) {
|
|
497
|
+
return {
|
|
498
|
+
raw,
|
|
499
|
+
delete() {
|
|
500
|
+
raw.free();
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function makeHandle(raw) {
|
|
505
|
+
const inner = require_shapeTypes.createKernelHandle(fieldDeletable(raw));
|
|
506
|
+
const handle = {
|
|
507
|
+
get value() {
|
|
508
|
+
return inner.value.raw;
|
|
509
|
+
},
|
|
510
|
+
get disposed() {
|
|
511
|
+
return inner.disposed;
|
|
512
|
+
},
|
|
513
|
+
[Symbol.dispose]() {
|
|
514
|
+
inner[Symbol.dispose]();
|
|
515
|
+
},
|
|
516
|
+
boolean(other, op) {
|
|
517
|
+
this.value.boolean(other.value, BOOLEAN_OP_CODES[op]);
|
|
518
|
+
return handle;
|
|
519
|
+
},
|
|
520
|
+
offset(distance) {
|
|
521
|
+
this.value.offset(distance);
|
|
522
|
+
return handle;
|
|
523
|
+
},
|
|
524
|
+
shell(thickness) {
|
|
525
|
+
this.value.shell(thickness);
|
|
526
|
+
return handle;
|
|
527
|
+
},
|
|
528
|
+
reinit() {
|
|
529
|
+
this.value.reinit();
|
|
530
|
+
return handle;
|
|
531
|
+
},
|
|
532
|
+
contour() {
|
|
533
|
+
const mesh = meshFromField(this.value);
|
|
534
|
+
if (require_errors.isErr(mesh)) throw new Error(mesh.error.message);
|
|
535
|
+
return mesh.value;
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
return handle;
|
|
539
|
+
}
|
|
540
|
+
/** Live-handle guard (the `VoxelFieldHandle` analogue of disposal's `isLive`). */
|
|
541
|
+
function isLive$1(handle) {
|
|
542
|
+
return !handle.disposed;
|
|
543
|
+
}
|
|
544
|
+
function disposedErr() {
|
|
545
|
+
return require_errors.err(require_errors.validationError("VOXEL_FIELD_DISPOSED", "the voxel field handle has been disposed."));
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Voxelize a mesh into a persistent dense {@link VoxelFieldHandle}: one grid you
|
|
549
|
+
* can boolean / offset / shell / reinit in place, then contour once. The handle
|
|
550
|
+
* is disposable — free the WASM grid with `using` (or `[Symbol.dispose]()`).
|
|
551
|
+
*
|
|
552
|
+
* `resolution` sizes the longest bbox axis; `padding` is the air-margin ring.
|
|
553
|
+
* Errors on an empty/invalid mesh, or if the grid would exceed the dense budget
|
|
554
|
+
* (the persistent path is dense-only) or the voxel cap.
|
|
555
|
+
*/
|
|
556
|
+
function voxelField(mesh, opts, id) {
|
|
557
|
+
const invalid = validateMesh(mesh);
|
|
558
|
+
if (invalid) return require_errors.err(invalid);
|
|
559
|
+
if (mesh.vertices.length === 0 || mesh.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "voxelField requires a non-empty triangle mesh."));
|
|
560
|
+
const params = resolveGridParams(opts);
|
|
561
|
+
if (require_errors.isErr(params)) return params;
|
|
562
|
+
const engine = resolveEngine(id);
|
|
563
|
+
if (require_errors.isErr(engine)) return engine;
|
|
564
|
+
try {
|
|
565
|
+
return require_errors.ok(makeHandle(new engine.value.VoxelField(mesh.vertices, mesh.triangles, params.value.resolution, params.value.padding)));
|
|
566
|
+
} catch (cause) {
|
|
567
|
+
return require_errors.err(require_errors.computationError("VOXEL_FIELD_VOXELIZE_FAILED", cause instanceof Error ? cause.message : "voxel field voxelization failed (grid too large or non-dense?).", cause));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Boolean two meshes into ONE co-registered, chainable {@link VoxelFieldHandle}:
|
|
572
|
+
* voxelize both onto a single shared grid sized to their union bbox, combine by
|
|
573
|
+
* `op`, and keep the field. This is THE correct way to "boolean then chain
|
|
574
|
+
* offset/shell" two independently-described meshes — unlike {@link fieldBoolean},
|
|
575
|
+
* which requires the operands to already share grid geometry. The result is
|
|
576
|
+
* dirty (the blend drifts the gradient), so a subsequent offset/shell
|
|
577
|
+
* auto-reinitializes. The handle is disposable — free it with `using`.
|
|
578
|
+
*
|
|
579
|
+
* `op` is `'difference'` = A − B. Errors on an empty/invalid mesh, or if the
|
|
580
|
+
* shared grid would exceed the dense budget (the persistent path is dense-only).
|
|
581
|
+
*/
|
|
582
|
+
function voxelBooleanField(a, b, op, opts, id) {
|
|
583
|
+
const invalidA = validateMesh(a);
|
|
584
|
+
if (invalidA) return require_errors.err(invalidA);
|
|
585
|
+
const invalidB = validateMesh(b);
|
|
586
|
+
if (invalidB) return require_errors.err(invalidB);
|
|
587
|
+
if (a.vertices.length === 0 || a.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "voxelBooleanField requires a non-empty mesh for operand A."));
|
|
588
|
+
if (b.vertices.length === 0 || b.triangles.length === 0) return require_errors.err(require_errors.validationError("VOXEL_EMPTY_MESH", "voxelBooleanField requires a non-empty mesh for operand B."));
|
|
589
|
+
const params = resolveGridParams(opts);
|
|
590
|
+
if (require_errors.isErr(params)) return params;
|
|
591
|
+
const engine = resolveEngine(id);
|
|
592
|
+
if (require_errors.isErr(engine)) return engine;
|
|
593
|
+
try {
|
|
594
|
+
return require_errors.ok(makeHandle(engine.value.VoxelField.boolean_of(a.vertices, a.triangles, b.vertices, b.triangles, BOOLEAN_OP_CODES[op], params.value.resolution, params.value.padding)));
|
|
595
|
+
} catch (cause) {
|
|
596
|
+
return require_errors.err(require_errors.computationError("VOXEL_FIELD_BOOLEAN_FAILED", cause instanceof Error ? cause.message : "voxel field boolean failed (grid too large or non-dense?).", cause));
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* CSG-combine two fields IN PLACE, returning the SAME `handle` for chaining. The
|
|
601
|
+
* min/max blend keeps the zero set exact but drifts the gradient near the join,
|
|
602
|
+
* so a subsequent {@link fieldOffset}/{@link fieldShell} auto-reinitializes.
|
|
603
|
+
*
|
|
604
|
+
* PRECONDITION: both operands must be CO-REGISTERED — same origin, spacing, AND
|
|
605
|
+
* dims. Two fields built by {@link voxelField} from DIFFERENT meshes generally do
|
|
606
|
+
* NOT share geometry (each sizes its grid to its own bbox), and the WASM guard
|
|
607
|
+
* rejects that mismatch as an `err(...)` rather than silently blending mismatched
|
|
608
|
+
* coordinate frames. For the easy co-registered path, build the field directly
|
|
609
|
+
* from both meshes with {@link voxelBooleanField}.
|
|
610
|
+
*/
|
|
611
|
+
function fieldBoolean(handle, other, op) {
|
|
612
|
+
if (!isLive$1(handle) || !isLive$1(other)) return disposedErr();
|
|
613
|
+
try {
|
|
614
|
+
handle.value.boolean(other.value, BOOLEAN_OP_CODES[op]);
|
|
615
|
+
return require_errors.ok(handle);
|
|
616
|
+
} catch (cause) {
|
|
617
|
+
return require_errors.err(require_errors.computationError("VOXEL_FIELD_BOOLEAN_FAILED", cause instanceof Error ? cause.message : "voxel field boolean failed (dim mismatch?).", cause));
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Offset the field's surface IN PLACE (>0 outward, <0 inward), returning the
|
|
622
|
+
* SAME `handle`. Auto-reinitializes first if the field is dirty (post-boolean),
|
|
623
|
+
* so the iso-shift always rides a true SDF.
|
|
624
|
+
*/
|
|
625
|
+
function fieldOffset(handle, distance) {
|
|
626
|
+
if (!isLive$1(handle)) return disposedErr();
|
|
627
|
+
if (!Number.isFinite(distance)) return require_errors.err(require_errors.validationError("VOXEL_INVALID_DISTANCE", "distance must be a finite number."));
|
|
628
|
+
try {
|
|
629
|
+
handle.value.offset(distance);
|
|
630
|
+
return require_errors.ok(handle);
|
|
631
|
+
} catch (cause) {
|
|
632
|
+
return require_errors.err(require_errors.computationError("VOXEL_FIELD_OFFSET_FAILED", cause instanceof Error ? cause.message : "voxel field offset failed.", cause));
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Hollow the field into an inward shell of `thickness` IN PLACE, returning the
|
|
637
|
+
* SAME `handle`. Auto-reinitializes first if dirty; the result is dirty again
|
|
638
|
+
* (the shell re-introduces a kink).
|
|
639
|
+
*/
|
|
640
|
+
function fieldShell(handle, thickness) {
|
|
641
|
+
if (!isLive$1(handle)) return disposedErr();
|
|
642
|
+
if (!Number.isFinite(thickness) || thickness <= 0) return require_errors.err(require_errors.validationError("VOXEL_INVALID_THICKNESS", "thickness must be a finite number > 0."));
|
|
643
|
+
try {
|
|
644
|
+
handle.value.shell(thickness);
|
|
645
|
+
return require_errors.ok(handle);
|
|
646
|
+
} catch (cause) {
|
|
647
|
+
return require_errors.err(require_errors.computationError("VOXEL_FIELD_SHELL_FAILED", cause instanceof Error ? cause.message : "voxel field shell failed.", cause));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Explicitly reinitialize φ to a true SDF (|∇φ|=1) while preserving the zero
|
|
652
|
+
* set, returning the SAME `handle`. Idempotent on a clean field. Offset/shell
|
|
653
|
+
* already auto-reinitialize, so this is for advanced control only.
|
|
654
|
+
*/
|
|
655
|
+
function fieldReinit(handle) {
|
|
656
|
+
if (!isLive$1(handle)) return disposedErr();
|
|
657
|
+
try {
|
|
658
|
+
handle.value.reinit();
|
|
659
|
+
return require_errors.ok(handle);
|
|
660
|
+
} catch (cause) {
|
|
661
|
+
return require_errors.err(require_errors.computationError("VOXEL_FIELD_REINIT_FAILED", cause instanceof Error ? cause.message : "voxel field reinit failed.", cause));
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Surface-Nets contour the current field to a {@link KernelMeshResult}. The
|
|
666
|
+
* field stays alive and chainable afterwards (contour borrows it). An empty
|
|
667
|
+
* contour surfaces as `VOXEL_DEGENERATE_RESULT`.
|
|
668
|
+
*/
|
|
669
|
+
function fieldContour(handle) {
|
|
670
|
+
if (!isLive$1(handle)) return disposedErr();
|
|
671
|
+
try {
|
|
672
|
+
return meshFromField(handle.value);
|
|
673
|
+
} catch (cause) {
|
|
674
|
+
return require_errors.err(require_errors.computationError("VOXEL_FIELD_CONTOUR_FAILED", cause instanceof Error ? cause.message : "voxel field contour failed.", cause));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Voxelize a B-rep shape into a persistent {@link VoxelFieldHandle}: tessellate
|
|
679
|
+
* it, then run {@link voxelField}. Threads a meshing failure back as an
|
|
680
|
+
* `err(...)`. The handle is disposable — free it with `using`.
|
|
681
|
+
*/
|
|
682
|
+
function voxelFieldFromShape(shape, opts, id) {
|
|
683
|
+
const meshInput = shapeToMeshInput(shape);
|
|
684
|
+
if (require_errors.isErr(meshInput)) return meshInput;
|
|
685
|
+
return voxelField(meshInput.value, opts, id);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Boolean two B-rep shapes into one co-registered, chainable
|
|
689
|
+
* {@link VoxelFieldHandle}: tessellate both, then run {@link voxelBooleanField}.
|
|
690
|
+
* `op` is `'difference'` = A − B. Threads either meshing failure back as an
|
|
691
|
+
* `err(...)`. The handle is disposable — free it with `using`.
|
|
692
|
+
*/
|
|
693
|
+
function voxelBooleanFieldShapes(a, b, op, opts, id) {
|
|
694
|
+
const meshA = shapeToMeshInput(a);
|
|
695
|
+
if (require_errors.isErr(meshA)) return meshA;
|
|
696
|
+
const meshB = shapeToMeshInput(b);
|
|
697
|
+
if (require_errors.isErr(meshB)) return meshB;
|
|
698
|
+
return voxelBooleanField(meshA.value, meshB.value, op, opts, id);
|
|
699
|
+
}
|
|
700
|
+
//#endregion
|
|
444
701
|
//#region src/lattice/latticeFns.ts
|
|
445
702
|
var LATTICE_TAGS = {
|
|
446
703
|
gyroid: 0,
|
|
@@ -5776,6 +6033,11 @@ exports.faceFinder = require_helpers.faceFinder;
|
|
|
5776
6033
|
exports.faceGeomType = require_faceFns.faceGeomType;
|
|
5777
6034
|
exports.faceOrientation = require_faceFns.faceOrientation;
|
|
5778
6035
|
exports.facesOfEdge = require_primitiveFns.facesOfEdge;
|
|
6036
|
+
exports.fieldBoolean = fieldBoolean;
|
|
6037
|
+
exports.fieldContour = fieldContour;
|
|
6038
|
+
exports.fieldOffset = fieldOffset;
|
|
6039
|
+
exports.fieldReinit = fieldReinit;
|
|
6040
|
+
exports.fieldShell = fieldShell;
|
|
5779
6041
|
exports.fill = require_surfaceBuilders.fill;
|
|
5780
6042
|
exports.filledFace = require_primitiveFns.filledFace;
|
|
5781
6043
|
exports.fillet = fillet;
|
|
@@ -6164,7 +6426,11 @@ exports.vertexFinder = vertexFinder;
|
|
|
6164
6426
|
exports.vertexPosition = require_topologyQueryFns.vertexPosition;
|
|
6165
6427
|
exports.verticesOfEdge = require_primitiveFns.verticesOfEdge;
|
|
6166
6428
|
exports.voxelBoolean = voxelBoolean;
|
|
6429
|
+
exports.voxelBooleanField = voxelBooleanField;
|
|
6430
|
+
exports.voxelBooleanFieldShapes = voxelBooleanFieldShapes;
|
|
6167
6431
|
exports.voxelBooleanShapes = voxelBooleanShapes;
|
|
6432
|
+
exports.voxelField = voxelField;
|
|
6433
|
+
exports.voxelFieldFromShape = voxelFieldFromShape;
|
|
6168
6434
|
exports.walkAssembly = require_historyFns.walkAssembly;
|
|
6169
6435
|
exports.windingNumbers = windingNumbers;
|
|
6170
6436
|
exports.wire = require_primitiveFns.wire;
|