brepjs 18.39.0 → 18.40.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/brepjs.cjs CHANGED
@@ -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$1 = 48;
222
- var DEFAULT_PADDING$1 = 2;
221
+ var DEFAULT_RESOLUTION$2 = 48;
222
+ var DEFAULT_PADDING$2 = 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$1;
236
- const padding = opts?.padding ?? DEFAULT_PADDING$1;
235
+ const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$2;
236
+ const padding = opts?.padding ?? DEFAULT_PADDING$2;
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$5 = require_shapeTypes._usingCtx();
244
- const repaired = _usingCtx$5.u(engine.value.repair_mesh(mesh.vertices, mesh.triangles, resolution, padding));
243
+ var _usingCtx$6 = require_shapeTypes._usingCtx();
244
+ const repaired = _usingCtx$6.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,
@@ -254,15 +254,192 @@ function repairMesh(mesh, opts, id) {
254
254
  faceHash: 0
255
255
  }]
256
256
  });
257
+ } catch (_) {
258
+ _usingCtx$6.e = _;
259
+ } finally {
260
+ _usingCtx$6.d();
261
+ }
262
+ } catch (cause) {
263
+ return require_errors.err(require_errors.computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
264
+ }
265
+ }
266
+ //#endregion
267
+ //#region src/voxel/shapeMesh.ts
268
+ var DEFAULT_DEFLECTION = .001;
269
+ /**
270
+ * Mesh a B-rep shape into the flat triangle-soup {@link VoxelMeshInput} the voxel
271
+ * ops consume. Tessellates via the topology mesh API at `deflection` linear
272
+ * tolerance and forwards its `{ vertices, triangles }` (already Float32Array /
273
+ * Uint32Array). Meshing failures surface as an `err(...)` rather than a throw.
274
+ */
275
+ function shapeToMeshInput(shape, deflection = DEFAULT_DEFLECTION) {
276
+ try {
277
+ const tessellated = require_meshFns.mesh(shape, { tolerance: deflection });
278
+ if (tessellated.vertices.length === 0 || tessellated.triangles.length === 0) return require_errors.err(require_errors.computationError("VOXEL_SHAPE_MESH_EMPTY", "shape tessellated to an empty triangle mesh."));
279
+ return require_errors.ok({
280
+ vertices: tessellated.vertices,
281
+ triangles: tessellated.triangles
282
+ });
283
+ } catch (cause) {
284
+ return require_errors.err(require_errors.computationError("VOXEL_SHAPE_MESH_FAILED", cause instanceof Error ? cause.message : "failed to mesh shape for voxel op.", cause));
285
+ }
286
+ }
287
+ //#endregion
288
+ //#region src/voxel/meshOpsFns.ts
289
+ var DEFAULT_RESOLUTION$1 = 48;
290
+ var DEFAULT_PADDING$1 = 2;
291
+ var BOOLEAN_OP_CODES = {
292
+ union: 0,
293
+ intersection: 1,
294
+ difference: 2
295
+ };
296
+ function resolveGridParams(opts) {
297
+ const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$1;
298
+ const padding = opts?.padding ?? DEFAULT_PADDING$1;
299
+ if (!Number.isInteger(resolution) || resolution < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_RESOLUTION", "resolution must be an integer >= 1."));
300
+ if (!Number.isInteger(padding) || padding < 1) return require_errors.err(require_errors.validationError("VOXEL_INVALID_PADDING", "padding must be an integer >= 1."));
301
+ return require_errors.ok({
302
+ resolution,
303
+ padding
304
+ });
305
+ }
306
+ function meshFromResult(result) {
307
+ if (result.positions.length === 0 || result.indices.length === 0) return require_errors.err(require_errors.computationError("VOXEL_DEGENERATE_RESULT", "the voxel operation produced an empty mesh (over-shrunk offset or disjoint operands?)."));
308
+ const vertexCount = result.positions.length / 3;
309
+ return require_errors.ok({
310
+ vertices: result.positions,
311
+ normals: result.normals,
312
+ triangles: result.indices,
313
+ uvs: new Float32Array(vertexCount * 2),
314
+ faceGroups: [{
315
+ start: 0,
316
+ count: result.indices.length / 3,
317
+ faceHash: 0
318
+ }]
319
+ });
320
+ }
321
+ /**
322
+ * Offset a mesh by `distance` via a true-SDF iso-level shift: voxelize an
323
+ * FWN-signed SDF, subtract `distance`, then Surface-Nets contour it back.
324
+ *
325
+ * `distance > 0` grows the surface outward, `< 0` shrinks it inward. Returns a
326
+ * {@link KernelMeshResult} in world coordinates (a single face group, no UVs).
327
+ */
328
+ function offsetMesh(mesh, distance, opts, id) {
329
+ const invalid = validateMesh(mesh);
330
+ if (invalid) return require_errors.err(invalid);
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
+ 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);
334
+ if (require_errors.isErr(params)) return params;
335
+ const engine = resolveEngine(id);
336
+ if (require_errors.isErr(engine)) return engine;
337
+ try {
338
+ try {
339
+ var _usingCtx$5 = require_shapeTypes._usingCtx();
340
+ return meshFromResult(_usingCtx$5.u(engine.value.offset_mesh(mesh.vertices, mesh.triangles, distance, params.value.resolution, params.value.padding)));
257
341
  } catch (_) {
258
342
  _usingCtx$5.e = _;
259
343
  } finally {
260
344
  _usingCtx$5.d();
261
345
  }
262
346
  } catch (cause) {
263
- return require_errors.err(require_errors.computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
347
+ return require_errors.err(require_errors.computationError("VOXEL_OFFSET_FAILED", cause instanceof Error ? cause.message : "voxel offset failed (grid too large?).", cause));
264
348
  }
265
349
  }
350
+ /**
351
+ * Hollow a solid mesh into a shell of the given inward `thickness`: voxelize an
352
+ * FWN-signed SDF, take `max(solid, -(solid + thickness))`, then contour it.
353
+ *
354
+ * `thickness` must be finite and > 0 (inward-only). Returns a
355
+ * {@link KernelMeshResult} in world coordinates (a single face group, no UVs).
356
+ */
357
+ function shellMesh(mesh, thickness, opts, id) {
358
+ const invalid = validateMesh(mesh);
359
+ if (invalid) return require_errors.err(invalid);
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
+ 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);
363
+ if (require_errors.isErr(params)) return params;
364
+ const engine = resolveEngine(id);
365
+ if (require_errors.isErr(engine)) return engine;
366
+ try {
367
+ try {
368
+ var _usingCtx3 = require_shapeTypes._usingCtx();
369
+ return meshFromResult(_usingCtx3.u(engine.value.shell_mesh(mesh.vertices, mesh.triangles, thickness, params.value.resolution, params.value.padding)));
370
+ } catch (_) {
371
+ _usingCtx3.e = _;
372
+ } finally {
373
+ _usingCtx3.d();
374
+ }
375
+ } catch (cause) {
376
+ return require_errors.err(require_errors.computationError("VOXEL_SHELL_FAILED", cause instanceof Error ? cause.message : "voxel shell failed (grid too large?).", cause));
377
+ }
378
+ }
379
+ /**
380
+ * Voxel-based CSG of two meshes: voxelize both onto a shared grid, combine their
381
+ * SDFs (union/intersection/difference), then Surface-Nets contour the result.
382
+ *
383
+ * `op` is `'difference'` = A − B. Robust on non-watertight input (FWN sign).
384
+ * Returns a {@link KernelMeshResult} in world coordinates (single group, no UVs).
385
+ */
386
+ function voxelBoolean(a, b, op, opts, id) {
387
+ const invalidA = validateMesh(a);
388
+ if (invalidA) return require_errors.err(invalidA);
389
+ const invalidB = validateMesh(b);
390
+ if (invalidB) return require_errors.err(invalidB);
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
+ 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);
395
+ if (require_errors.isErr(params)) return params;
396
+ const engine = resolveEngine(id);
397
+ if (require_errors.isErr(engine)) return engine;
398
+ try {
399
+ try {
400
+ var _usingCtx4 = require_shapeTypes._usingCtx();
401
+ return meshFromResult(_usingCtx4.u(engine.value.voxel_boolean(a.vertices, a.triangles, b.vertices, b.triangles, opCode, params.value.resolution, params.value.padding)));
402
+ } catch (_) {
403
+ _usingCtx4.e = _;
404
+ } finally {
405
+ _usingCtx4.d();
406
+ }
407
+ } catch (cause) {
408
+ return require_errors.err(require_errors.computationError("VOXEL_BOOLEAN_FAILED", cause instanceof Error ? cause.message : "voxel boolean failed (grid too large?).", cause));
409
+ }
410
+ }
411
+ /**
412
+ * Offset a B-rep shape by `distance`: tessellate it, then run {@link offsetMesh}
413
+ * on the resulting triangle soup. `distance > 0` grows outward, `< 0` shrinks
414
+ * inward. Threads a meshing failure straight back as an `err(...)`.
415
+ */
416
+ function offsetShape(shape, distance, opts, id) {
417
+ const meshInput = shapeToMeshInput(shape);
418
+ if (require_errors.isErr(meshInput)) return meshInput;
419
+ return offsetMesh(meshInput.value, distance, opts, id);
420
+ }
421
+ /**
422
+ * Hollow a B-rep shape into a shell of inward `thickness`: tessellate it, then
423
+ * run {@link shellMesh}. `thickness` must be finite and > 0. Threads a meshing
424
+ * failure straight back as an `err(...)`.
425
+ */
426
+ function shellShape(shape, thickness, opts, id) {
427
+ const meshInput = shapeToMeshInput(shape);
428
+ if (require_errors.isErr(meshInput)) return meshInput;
429
+ return shellMesh(meshInput.value, thickness, opts, id);
430
+ }
431
+ /**
432
+ * Voxel CSG of two B-rep shapes: tessellate both, then run {@link voxelBoolean}.
433
+ * `op` is `'difference'` = A − B. Threads either meshing failure back as an
434
+ * `err(...)`.
435
+ */
436
+ function voxelBooleanShapes(a, b, op, opts, id) {
437
+ const meshA = shapeToMeshInput(a);
438
+ if (require_errors.isErr(meshA)) return meshA;
439
+ const meshB = shapeToMeshInput(b);
440
+ if (require_errors.isErr(meshB)) return meshB;
441
+ return voxelBoolean(meshA.value, meshB.value, op, opts, id);
442
+ }
266
443
  //#endregion
267
444
  //#region src/lattice/latticeFns.ts
268
445
  var LATTICE_TAGS = {
@@ -334,6 +511,16 @@ function latticeInfill(mesh, opts, id) {
334
511
  }
335
512
  }
336
513
  /**
514
+ * Fill a B-rep shape with a TPMS lattice infill: tessellate the shape, then run
515
+ * {@link latticeInfill} on the resulting triangle soup. Threads a meshing
516
+ * failure straight back as an `err(...)`.
517
+ */
518
+ function latticeInfillShape(shape, opts, id) {
519
+ const meshInput = shapeToMeshInput(shape);
520
+ if (require_errors.isErr(meshInput)) return meshInput;
521
+ return latticeInfill(meshInput.value, opts, id);
522
+ }
523
+ /**
337
524
  * Contour the infinite TPMS lattice clipped to an axis-aligned box.
338
525
  *
339
526
  * Returns a {@link KernelMeshResult} in world coordinates (a single face group,
@@ -5725,6 +5912,7 @@ exports.kernelCallRaw = require_topologyQueryFns.kernelCallRaw;
5725
5912
  exports.kernelCallScoped = require_topologyQueryFns.kernelCallScoped;
5726
5913
  exports.kernelError = require_errors.kernelError;
5727
5914
  exports.latticeInfill = latticeInfill;
5915
+ exports.latticeInfillShape = latticeInfillShape;
5728
5916
  exports.line = require_primitiveFns.line;
5729
5917
  exports.linearPattern = require_historyFns.linearPattern;
5730
5918
  exports.loadFont = require_textBlueprints.loadFont;
@@ -5777,6 +5965,8 @@ exports.multiSectionSweep = require_extrudeFns.multiSectionSweep;
5777
5965
  exports.normalAt = require_faceFns.normalAt;
5778
5966
  exports.offset = offset;
5779
5967
  exports.offsetFace = require_primitiveFns.offsetFace;
5968
+ exports.offsetMesh = offsetMesh;
5969
+ exports.offsetShape = offsetShape;
5780
5970
  exports.offsetWire2D = require_curveFns.offsetWire2D;
5781
5971
  exports.ok = require_errors.ok;
5782
5972
  exports.or = require_errors.or;
@@ -5857,9 +6047,12 @@ exports.setShapeOrigin = require_shapeFns.setShapeOrigin;
5857
6047
  exports.setTagMetadata = require_shapeFns.setTagMetadata;
5858
6048
  exports.sewShells = require_primitiveFns.sewShells;
5859
6049
  exports.shape = shape;
6050
+ exports.shapeToMeshInput = shapeToMeshInput;
5860
6051
  exports.shapeType = require_faceFns.shapeType;
5861
6052
  exports.sharedEdges = require_primitiveFns.sharedEdges;
5862
6053
  exports.shell = shell;
6054
+ exports.shellMesh = shellMesh;
6055
+ exports.shellShape = shellShape;
5863
6056
  exports.shellWithEvolution = require_primitiveFns.shellWithEvolution;
5864
6057
  exports.simplify = simplify;
5865
6058
  exports.sketchCircle = require_drawFns.sketchCircle;
@@ -5964,6 +6157,8 @@ exports.vertex = require_primitiveFns.vertex;
5964
6157
  exports.vertexFinder = vertexFinder;
5965
6158
  exports.vertexPosition = require_topologyQueryFns.vertexPosition;
5966
6159
  exports.verticesOfEdge = require_primitiveFns.verticesOfEdge;
6160
+ exports.voxelBoolean = voxelBoolean;
6161
+ exports.voxelBooleanShapes = voxelBooleanShapes;
5967
6162
  exports.walkAssembly = require_historyFns.walkAssembly;
5968
6163
  exports.windingNumbers = windingNumbers;
5969
6164
  exports.wire = require_primitiveFns.wire;
package/dist/brepjs.js CHANGED
@@ -229,8 +229,8 @@ function pointsInside(mesh, queries, id) {
229
229
  }
230
230
  //#endregion
231
231
  //#region src/voxel/repairFns.ts
232
- var DEFAULT_RESOLUTION$1 = 48;
233
- var DEFAULT_PADDING$1 = 2;
232
+ var DEFAULT_RESOLUTION$2 = 48;
233
+ var DEFAULT_PADDING$2 = 2;
234
234
  /**
235
235
  * Repair a (possibly non-watertight) triangle-soup mesh into a closed surface:
236
236
  * voxelize an FWN-signed SDF, then Surface-Nets contour it back to triangles.
@@ -243,16 +243,16 @@ function repairMesh(mesh, opts, id) {
243
243
  const invalid = validateMesh(mesh);
244
244
  if (invalid) return err(invalid);
245
245
  if (mesh.vertices.length === 0 || mesh.triangles.length === 0) return err(validationError("VOXEL_EMPTY_MESH", "repairMesh requires a non-empty triangle mesh."));
246
- const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$1;
247
- const padding = opts?.padding ?? DEFAULT_PADDING$1;
246
+ const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$2;
247
+ const padding = opts?.padding ?? DEFAULT_PADDING$2;
248
248
  if (!Number.isInteger(resolution) || resolution < 1) return err(validationError("VOXEL_INVALID_RESOLUTION", "resolution must be an integer >= 1."));
249
249
  if (!Number.isInteger(padding) || padding < 1) return err(validationError("VOXEL_INVALID_PADDING", "padding must be an integer >= 1."));
250
250
  const engine = resolveEngine(id);
251
251
  if (isErr(engine)) return engine;
252
252
  try {
253
253
  try {
254
- var _usingCtx$5 = _usingCtx();
255
- const repaired = _usingCtx$5.u(engine.value.repair_mesh(mesh.vertices, mesh.triangles, resolution, padding));
254
+ var _usingCtx$6 = _usingCtx();
255
+ const repaired = _usingCtx$6.u(engine.value.repair_mesh(mesh.vertices, mesh.triangles, resolution, padding));
256
256
  const vertexCount = repaired.positions.length / 3;
257
257
  return ok({
258
258
  vertices: repaired.positions,
@@ -265,15 +265,192 @@ function repairMesh(mesh, opts, id) {
265
265
  faceHash: 0
266
266
  }]
267
267
  });
268
+ } catch (_) {
269
+ _usingCtx$6.e = _;
270
+ } finally {
271
+ _usingCtx$6.d();
272
+ }
273
+ } catch (cause) {
274
+ return err(computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
275
+ }
276
+ }
277
+ //#endregion
278
+ //#region src/voxel/shapeMesh.ts
279
+ var DEFAULT_DEFLECTION = .001;
280
+ /**
281
+ * Mesh a B-rep shape into the flat triangle-soup {@link VoxelMeshInput} the voxel
282
+ * ops consume. Tessellates via the topology mesh API at `deflection` linear
283
+ * tolerance and forwards its `{ vertices, triangles }` (already Float32Array /
284
+ * Uint32Array). Meshing failures surface as an `err(...)` rather than a throw.
285
+ */
286
+ function shapeToMeshInput(shape, deflection = DEFAULT_DEFLECTION) {
287
+ try {
288
+ const tessellated = mesh$1(shape, { tolerance: deflection });
289
+ if (tessellated.vertices.length === 0 || tessellated.triangles.length === 0) return err(computationError("VOXEL_SHAPE_MESH_EMPTY", "shape tessellated to an empty triangle mesh."));
290
+ return ok({
291
+ vertices: tessellated.vertices,
292
+ triangles: tessellated.triangles
293
+ });
294
+ } catch (cause) {
295
+ return err(computationError("VOXEL_SHAPE_MESH_FAILED", cause instanceof Error ? cause.message : "failed to mesh shape for voxel op.", cause));
296
+ }
297
+ }
298
+ //#endregion
299
+ //#region src/voxel/meshOpsFns.ts
300
+ var DEFAULT_RESOLUTION$1 = 48;
301
+ var DEFAULT_PADDING$1 = 2;
302
+ var BOOLEAN_OP_CODES = {
303
+ union: 0,
304
+ intersection: 1,
305
+ difference: 2
306
+ };
307
+ function resolveGridParams(opts) {
308
+ const resolution = opts?.resolution ?? DEFAULT_RESOLUTION$1;
309
+ const padding = opts?.padding ?? DEFAULT_PADDING$1;
310
+ if (!Number.isInteger(resolution) || resolution < 1) return err(validationError("VOXEL_INVALID_RESOLUTION", "resolution must be an integer >= 1."));
311
+ if (!Number.isInteger(padding) || padding < 1) return err(validationError("VOXEL_INVALID_PADDING", "padding must be an integer >= 1."));
312
+ return ok({
313
+ resolution,
314
+ padding
315
+ });
316
+ }
317
+ function meshFromResult(result) {
318
+ if (result.positions.length === 0 || result.indices.length === 0) return err(computationError("VOXEL_DEGENERATE_RESULT", "the voxel operation produced an empty mesh (over-shrunk offset or disjoint operands?)."));
319
+ const vertexCount = result.positions.length / 3;
320
+ return ok({
321
+ vertices: result.positions,
322
+ normals: result.normals,
323
+ triangles: result.indices,
324
+ uvs: new Float32Array(vertexCount * 2),
325
+ faceGroups: [{
326
+ start: 0,
327
+ count: result.indices.length / 3,
328
+ faceHash: 0
329
+ }]
330
+ });
331
+ }
332
+ /**
333
+ * Offset a mesh by `distance` via a true-SDF iso-level shift: voxelize an
334
+ * FWN-signed SDF, subtract `distance`, then Surface-Nets contour it back.
335
+ *
336
+ * `distance > 0` grows the surface outward, `< 0` shrinks it inward. Returns a
337
+ * {@link KernelMeshResult} in world coordinates (a single face group, no UVs).
338
+ */
339
+ function offsetMesh(mesh, distance, opts, id) {
340
+ const invalid = validateMesh(mesh);
341
+ if (invalid) return err(invalid);
342
+ if (mesh.vertices.length === 0 || mesh.triangles.length === 0) return err(validationError("VOXEL_EMPTY_MESH", "offsetMesh requires a non-empty triangle mesh."));
343
+ if (!Number.isFinite(distance)) return err(validationError("VOXEL_INVALID_DISTANCE", "distance must be a finite number."));
344
+ const params = resolveGridParams(opts);
345
+ if (isErr(params)) return params;
346
+ const engine = resolveEngine(id);
347
+ if (isErr(engine)) return engine;
348
+ try {
349
+ try {
350
+ var _usingCtx$5 = _usingCtx();
351
+ return meshFromResult(_usingCtx$5.u(engine.value.offset_mesh(mesh.vertices, mesh.triangles, distance, params.value.resolution, params.value.padding)));
268
352
  } catch (_) {
269
353
  _usingCtx$5.e = _;
270
354
  } finally {
271
355
  _usingCtx$5.d();
272
356
  }
273
357
  } catch (cause) {
274
- return err(computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
358
+ return err(computationError("VOXEL_OFFSET_FAILED", cause instanceof Error ? cause.message : "voxel offset failed (grid too large?).", cause));
275
359
  }
276
360
  }
361
+ /**
362
+ * Hollow a solid mesh into a shell of the given inward `thickness`: voxelize an
363
+ * FWN-signed SDF, take `max(solid, -(solid + thickness))`, then contour it.
364
+ *
365
+ * `thickness` must be finite and > 0 (inward-only). Returns a
366
+ * {@link KernelMeshResult} in world coordinates (a single face group, no UVs).
367
+ */
368
+ function shellMesh(mesh, thickness, opts, id) {
369
+ const invalid = validateMesh(mesh);
370
+ if (invalid) return err(invalid);
371
+ if (mesh.vertices.length === 0 || mesh.triangles.length === 0) return err(validationError("VOXEL_EMPTY_MESH", "shellMesh requires a non-empty triangle mesh."));
372
+ if (!Number.isFinite(thickness) || thickness <= 0) return err(validationError("VOXEL_INVALID_THICKNESS", "thickness must be a finite number > 0."));
373
+ const params = resolveGridParams(opts);
374
+ if (isErr(params)) return params;
375
+ const engine = resolveEngine(id);
376
+ if (isErr(engine)) return engine;
377
+ try {
378
+ try {
379
+ var _usingCtx3 = _usingCtx();
380
+ return meshFromResult(_usingCtx3.u(engine.value.shell_mesh(mesh.vertices, mesh.triangles, thickness, params.value.resolution, params.value.padding)));
381
+ } catch (_) {
382
+ _usingCtx3.e = _;
383
+ } finally {
384
+ _usingCtx3.d();
385
+ }
386
+ } catch (cause) {
387
+ return err(computationError("VOXEL_SHELL_FAILED", cause instanceof Error ? cause.message : "voxel shell failed (grid too large?).", cause));
388
+ }
389
+ }
390
+ /**
391
+ * Voxel-based CSG of two meshes: voxelize both onto a shared grid, combine their
392
+ * SDFs (union/intersection/difference), then Surface-Nets contour the result.
393
+ *
394
+ * `op` is `'difference'` = A − B. Robust on non-watertight input (FWN sign).
395
+ * Returns a {@link KernelMeshResult} in world coordinates (single group, no UVs).
396
+ */
397
+ function voxelBoolean(a, b, op, opts, id) {
398
+ const invalidA = validateMesh(a);
399
+ if (invalidA) return err(invalidA);
400
+ const invalidB = validateMesh(b);
401
+ if (invalidB) return err(invalidB);
402
+ if (a.vertices.length === 0 || a.triangles.length === 0) return err(validationError("VOXEL_EMPTY_MESH", "voxelBoolean requires a non-empty mesh for operand A."));
403
+ if (b.vertices.length === 0 || b.triangles.length === 0) return err(validationError("VOXEL_EMPTY_MESH", "voxelBoolean requires a non-empty mesh for operand B."));
404
+ const opCode = BOOLEAN_OP_CODES[op];
405
+ const params = resolveGridParams(opts);
406
+ if (isErr(params)) return params;
407
+ const engine = resolveEngine(id);
408
+ if (isErr(engine)) return engine;
409
+ try {
410
+ try {
411
+ var _usingCtx4 = _usingCtx();
412
+ return meshFromResult(_usingCtx4.u(engine.value.voxel_boolean(a.vertices, a.triangles, b.vertices, b.triangles, opCode, params.value.resolution, params.value.padding)));
413
+ } catch (_) {
414
+ _usingCtx4.e = _;
415
+ } finally {
416
+ _usingCtx4.d();
417
+ }
418
+ } catch (cause) {
419
+ return err(computationError("VOXEL_BOOLEAN_FAILED", cause instanceof Error ? cause.message : "voxel boolean failed (grid too large?).", cause));
420
+ }
421
+ }
422
+ /**
423
+ * Offset a B-rep shape by `distance`: tessellate it, then run {@link offsetMesh}
424
+ * on the resulting triangle soup. `distance > 0` grows outward, `< 0` shrinks
425
+ * inward. Threads a meshing failure straight back as an `err(...)`.
426
+ */
427
+ function offsetShape(shape, distance, opts, id) {
428
+ const meshInput = shapeToMeshInput(shape);
429
+ if (isErr(meshInput)) return meshInput;
430
+ return offsetMesh(meshInput.value, distance, opts, id);
431
+ }
432
+ /**
433
+ * Hollow a B-rep shape into a shell of inward `thickness`: tessellate it, then
434
+ * run {@link shellMesh}. `thickness` must be finite and > 0. Threads a meshing
435
+ * failure straight back as an `err(...)`.
436
+ */
437
+ function shellShape(shape, thickness, opts, id) {
438
+ const meshInput = shapeToMeshInput(shape);
439
+ if (isErr(meshInput)) return meshInput;
440
+ return shellMesh(meshInput.value, thickness, opts, id);
441
+ }
442
+ /**
443
+ * Voxel CSG of two B-rep shapes: tessellate both, then run {@link voxelBoolean}.
444
+ * `op` is `'difference'` = A − B. Threads either meshing failure back as an
445
+ * `err(...)`.
446
+ */
447
+ function voxelBooleanShapes(a, b, op, opts, id) {
448
+ const meshA = shapeToMeshInput(a);
449
+ if (isErr(meshA)) return meshA;
450
+ const meshB = shapeToMeshInput(b);
451
+ if (isErr(meshB)) return meshB;
452
+ return voxelBoolean(meshA.value, meshB.value, op, opts, id);
453
+ }
277
454
  //#endregion
278
455
  //#region src/lattice/latticeFns.ts
279
456
  var LATTICE_TAGS = {
@@ -345,6 +522,16 @@ function latticeInfill(mesh, opts, id) {
345
522
  }
346
523
  }
347
524
  /**
525
+ * Fill a B-rep shape with a TPMS lattice infill: tessellate the shape, then run
526
+ * {@link latticeInfill} on the resulting triangle soup. Threads a meshing
527
+ * failure straight back as an `err(...)`.
528
+ */
529
+ function latticeInfillShape(shape, opts, id) {
530
+ const meshInput = shapeToMeshInput(shape);
531
+ if (isErr(meshInput)) return meshInput;
532
+ return latticeInfill(meshInput.value, opts, id);
533
+ }
534
+ /**
348
535
  * Contour the infinite TPMS lattice clipped to an axis-aligned box.
349
536
  *
350
537
  * Returns a {@link KernelMeshResult} in world coordinates (a single face group,
@@ -5396,4 +5583,4 @@ var csg_exports = /* @__PURE__ */ __exportAll({
5396
5583
  withEvaluator: () => withEvaluator
5397
5584
  });
5398
5585
  //#endregion
5399
- export { BaseSketcher2d, BlueprintSketcher, BrepBugError, BrepErrorCode, BrepWrapperError, BrepkitAdapter, CompoundSketch, DEG2RAD, DisposalScope, FaceSketcher, HASH_CODE_MAX, OK, OcctWasmAdapter, RAD2DEG, Sketch, Sketcher, Sketches, addChild, addHoles, addMate, addStep, adjacentFaces, all, andThen, applyGlue, applyMatrix, approximateCurve, as2D, as3D, asTopo, assignRoles, autoHeal, bezier, blueprintToDXF, booleanPipeline, booleans_exports as booleans, boss, box, bsplineApprox, bug, cameraFromPlane, cameraLookAt, captureHint, cast, castShape, castShape3D, chamfer, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkAllInterferences, checkBoolean, checkInterference, circle, circularPattern, classifyPointOnFace, clearMeshCache, clone, closedWire, collect, collectShapes, colorFaces, colorShape, complexExtrude, composeTransforms, compound, compoundSketchExtrude, compoundSketchFace, compoundSketchLoft, compoundSketchRevolve, computationError, computeStraightSkeleton, cone, construction_exports as construction, convexHull, cornerFinder, countNodes, createAssembly, createAssemblyNode, createBlueprint, createCamera, createCompound, createCompoundBlueprint, createDistanceQuery, createEdge, createFace, createHandle, createHistory, createKernelHandle, createMeshCache, createNamedPlane, createOperationRegistry, createPlane, createRef, createRegistry, createShell, createSolid, createTaskQueue, createVertex, createWire, createWorkerClient, createWorkerHandler, csg_exports as csg, curve2dBoundingBox, curve2dDistanceFrom, curve2dFirstPoint, curve2dIsOnCurve, curve2dLastPoint, curve2dParameter, curve2dSplitAt, curve2dTangentAt, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cut, cut2D, cutAll, cutAllBisect, cutBlueprints, cutWithEvolution, cylinder, defaultScorer, dequeueTask, describe, deserializeDrawing, deserializeHistory, fromBREP as deserializeShape, downcast, draft, draw, drawCircle, drawEllipse, drawFaceOutline, drawParametricFunction, drawPointsInterpolation, drawPolysides, drawProjection, drawRectangle, drawRoundedRectangle, drawSingleCircle, drawSingleEllipse, drawText, drawingChamfer, drawingCut, drawingFillet, drawingFuse, drawingIntersect, drawingToSketchOnPlane, drill, edgeFinder, edgesOfFace, ellipse, ellipseArc, ellipsoid, enqueueTask, err, exportAssemblySTEP, exportDXF, exportGlb, exportGltf, exportIGES, exportOBJ, exportSTEP, exportSTEPConfigured, exportSTL, exportThreeMF, extrude, extrudeAll, face, faceCenter, faceFinder, faceGeomType, faceOrientation, facesOfEdge, fill, filledFace, fillet, filletWithEvolution, findFacesByTag, findNode, findStep, fixSelfIntersection, fixShape, flatMap, flatten, flipFaceOrientation, flipOrientation, fontMetrics, fromBREP$1 as fromBREP, fromKernelDir, fromKernelPnt, fromKernelVec, fromNullable, fuse, fuse2D, fuseAll, fuseAllBisect, fuseBlueprints, fuseWithEvolution, gearGeometry, getActiveVoxelId, getBounds, getBounds2D, getCompSolids, getCurveType, getDisposalStats, getEdges, getFaceColor, getFaceOrigins, getFaceTags, getFaces, getFont, getHashCode, getShape as getHistoryShape, getKernel, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getOrientation2D, getPerformanceStats, getShapeColor, getShapeKind, getShells, getSingleFace, getSolids, getSurfaceType, getTagMetadata, getVertices, getVoxel, getWires, guidedSweep, heal, healFace, healSolid, healWire, helix, hull, importDXF, importGLB, importIGES, importOBJ, importSTEP, importSTL, importSVG, importSVGPathD, importThreeMF, init, initFromManifold, initFromOC, initVoxel, innerWires, interpolateCurve, intersect, intersect2D, intersectBlueprints, intersectWithEvolution, invalidateShapeCache, ioNs_exports as io, ioError, is2D, is3D, isChamferRadius, isClosedWire, isCompSolid, isCompound, isDisposeRequest, isEdge, isEmpty, isEqualShape, isErr, isErrorResponse, isFace, isFilletRadius, isInitRequest, isInside2D, isLive, isManifoldShell, isNumber, isOk, isOperationRequest, isOrientedFace, isPlanarFace, isPlanarWire, isProjectionPlane, isEmpty$1 as isQueueEmpty, isSameShape, isShape1D, isShape3D, isShell, isSolid, isSuccessResponse, isValid, isValidSolid, isVertex, isWire, iterCompSolids, iterEdges, iterFaces, iterShells, iterSolids, iterTopo, iterVertices, iterWires, kernelCall, kernelCallRaw, kernelCallScoped, kernelError, latticeInfill, line, linearPattern, loadFont, loft, loftAll, makeBaseBox, makeExternalGear, makeInternalGear, makePlane, makePlanetaryGear, makeProjectedEdges, manifoldShell, map, mapBoth, mapErr, match, measureArea, measureCurvatureAt, measureCurvatureAtMid, measureDistance, measureDistanceProps, measureLength, measureLinearProps, measureSurfaceProps, measureVolume, measureVolumeProps, measurement_exports as measurement, mesh, meshEdges, meshMultiLOD, minkowski, mirror, mirror2D, mirrorDrawing, mirrorJoin, modifiers_exports as modifiers, modifyStep, moduleInitError, multiSectionSweep, normalAt, offset, offsetFace, offsetWire2D, ok, or, orElse, organiseBlueprints, orientedFace, outerWire, patterns_exports as patterns, pendingCount, pipeline, pivotPlane, planarFace, planarWire, planetPlacements, pocket, pointOnSurface, pointsInside, polygon, polyhedron, polysideInnerRadius, polysidesBlueprint, positionOnCurve, prewarm, primitives_exports as primitives, projectEdges, projectPointOnFace, query_exports as query, queryError, rectangularPattern, registerHandler, registerKernel, registerOperation, registerShape, registerVoxel, rejectAll, removeChild, removeHolesFromFace, repairMesh, replayFrom, replayHistory, resetDisposalStats, resetPerformanceStats, resize, resolve, resolve3D, resolveDirection, resolvePlane, resolveRef, reverseCurve, revolve, roof, rotate, rotate2D, rotateDrawing, roundedRectangleBlueprint, scale, scale2D, scaleDrawing, section, sectionToFace, serializeHistory, setShapeOrigin, setTagMetadata, sewShells, shape, shapeType, sharedEdges, shell, shellWithEvolution, simplify, sketchCircle, sketchEllipse, sketchExtrude, sketchFace, sketchFaceOffset, sketchHelix, sketchLoft, sketchOnFace2D, sketchOnPlane2D, sketchParametricFunction, sketchPolysides, sketchRectangle, sketchRevolve, sketchRoundedRectangle, sketchSweep, sketchText, sketchWires, sketcherStateError, slice, solid, solidFromShell, solveAssembly, sphere, split, stepCount, stepsFrom, stretch2D, subFace, supportExtrude, supportsConstraintSketch, supportsProjection, surfaceFromGrid, surfaceFromImage, sweep, tagFaces, tangentArc, tap, tapErr, textBlueprints, textMetrics, thicken, threePointArc, toBREP, toBufferGeometryData, toGroupedBufferGeometryData, toKernelVec, toLODGeometryData, toLineGeometryData, toSVGPathD, toVec2, toVec3, torus, tpmsLattice, transformCopy, transforms_exports as transforms, translate, translate2D, translateDrawing, translatePlane, tryCatch, tryCatchAsync, twistExtrude, typeCastError, undoLast, unsupportedError, unwrap, unwrapErr, unwrapOr, unwrapOrElse, updateNode, updateRoles, uvBounds, uvCoordinates, validSolid, validatePlanetary, validationError, variableFillet, vecAdd, vecAngle, vecCross, vecDistance, vecDot, vecEquals, vecIsZero, vecLength, vecLengthSq, vecNegate, vecNormalize, vecProjectToPlane, vecRepr, vecRotate, vecScale, vecSub, vertex, vertexFinder, vertexPosition, verticesOfEdge, walkAssembly, windingNumbers, wire, wireFinder, wireLoop, wiresOfFace, withKernel, withKernelDir, withKernelPnt, withKernelVec, withScope, withScopeResult, withScopeResultAsync, zip as zipResults };
5586
+ export { BaseSketcher2d, BlueprintSketcher, BrepBugError, BrepErrorCode, BrepWrapperError, BrepkitAdapter, CompoundSketch, DEG2RAD, DisposalScope, FaceSketcher, HASH_CODE_MAX, OK, OcctWasmAdapter, RAD2DEG, Sketch, Sketcher, Sketches, addChild, addHoles, addMate, addStep, adjacentFaces, all, andThen, applyGlue, applyMatrix, approximateCurve, as2D, as3D, asTopo, assignRoles, autoHeal, bezier, blueprintToDXF, booleanPipeline, booleans_exports as booleans, boss, box, bsplineApprox, bug, cameraFromPlane, cameraLookAt, captureHint, cast, castShape, castShape3D, chamfer, chamferDistAngle as chamferDistAngleShape, chamferWithEvolution, checkAllInterferences, checkBoolean, checkInterference, circle, circularPattern, classifyPointOnFace, clearMeshCache, clone, closedWire, collect, collectShapes, colorFaces, colorShape, complexExtrude, composeTransforms, compound, compoundSketchExtrude, compoundSketchFace, compoundSketchLoft, compoundSketchRevolve, computationError, computeStraightSkeleton, cone, construction_exports as construction, convexHull, cornerFinder, countNodes, createAssembly, createAssemblyNode, createBlueprint, createCamera, createCompound, createCompoundBlueprint, createDistanceQuery, createEdge, createFace, createHandle, createHistory, createKernelHandle, createMeshCache, createNamedPlane, createOperationRegistry, createPlane, createRef, createRegistry, createShell, createSolid, createTaskQueue, createVertex, createWire, createWorkerClient, createWorkerHandler, csg_exports as csg, curve2dBoundingBox, curve2dDistanceFrom, curve2dFirstPoint, curve2dIsOnCurve, curve2dLastPoint, curve2dParameter, curve2dSplitAt, curve2dTangentAt, curveEndPoint, curveIsClosed, curveIsPeriodic, curveLength, curvePeriod, curvePointAt, curveStartPoint, curveTangentAt, cut, cut2D, cutAll, cutAllBisect, cutBlueprints, cutWithEvolution, cylinder, defaultScorer, dequeueTask, describe, deserializeDrawing, deserializeHistory, fromBREP as deserializeShape, downcast, draft, draw, drawCircle, drawEllipse, drawFaceOutline, drawParametricFunction, drawPointsInterpolation, drawPolysides, drawProjection, drawRectangle, drawRoundedRectangle, drawSingleCircle, drawSingleEllipse, drawText, drawingChamfer, drawingCut, drawingFillet, drawingFuse, drawingIntersect, drawingToSketchOnPlane, drill, edgeFinder, edgesOfFace, ellipse, ellipseArc, ellipsoid, enqueueTask, err, exportAssemblySTEP, exportDXF, exportGlb, exportGltf, exportIGES, exportOBJ, exportSTEP, exportSTEPConfigured, exportSTL, exportThreeMF, extrude, extrudeAll, face, faceCenter, faceFinder, faceGeomType, faceOrientation, facesOfEdge, fill, filledFace, fillet, filletWithEvolution, findFacesByTag, findNode, findStep, fixSelfIntersection, fixShape, flatMap, flatten, flipFaceOrientation, flipOrientation, fontMetrics, fromBREP$1 as fromBREP, fromKernelDir, fromKernelPnt, fromKernelVec, fromNullable, fuse, fuse2D, fuseAll, fuseAllBisect, fuseBlueprints, fuseWithEvolution, gearGeometry, getActiveVoxelId, getBounds, getBounds2D, getCompSolids, getCurveType, getDisposalStats, getEdges, getFaceColor, getFaceOrigins, getFaceTags, getFaces, getFont, getHashCode, getShape as getHistoryShape, getKernel, getNurbsCurveData, getNurbsSurfaceData, getOrientation, getOrientation2D, getPerformanceStats, getShapeColor, getShapeKind, getShells, getSingleFace, getSolids, getSurfaceType, getTagMetadata, getVertices, getVoxel, getWires, guidedSweep, heal, healFace, healSolid, healWire, helix, hull, importDXF, importGLB, importIGES, importOBJ, importSTEP, importSTL, importSVG, importSVGPathD, importThreeMF, init, initFromManifold, initFromOC, initVoxel, innerWires, interpolateCurve, intersect, intersect2D, intersectBlueprints, intersectWithEvolution, invalidateShapeCache, ioNs_exports as io, ioError, is2D, is3D, isChamferRadius, isClosedWire, isCompSolid, isCompound, isDisposeRequest, isEdge, isEmpty, isEqualShape, isErr, isErrorResponse, isFace, isFilletRadius, isInitRequest, isInside2D, isLive, isManifoldShell, isNumber, isOk, isOperationRequest, isOrientedFace, isPlanarFace, isPlanarWire, isProjectionPlane, isEmpty$1 as isQueueEmpty, isSameShape, isShape1D, isShape3D, isShell, isSolid, isSuccessResponse, isValid, isValidSolid, isVertex, isWire, iterCompSolids, iterEdges, iterFaces, iterShells, iterSolids, iterTopo, iterVertices, iterWires, kernelCall, kernelCallRaw, kernelCallScoped, kernelError, latticeInfill, latticeInfillShape, line, linearPattern, loadFont, loft, loftAll, makeBaseBox, makeExternalGear, makeInternalGear, makePlane, makePlanetaryGear, makeProjectedEdges, manifoldShell, map, mapBoth, mapErr, match, measureArea, measureCurvatureAt, measureCurvatureAtMid, measureDistance, measureDistanceProps, measureLength, measureLinearProps, measureSurfaceProps, measureVolume, measureVolumeProps, measurement_exports as measurement, mesh, meshEdges, meshMultiLOD, minkowski, mirror, mirror2D, mirrorDrawing, mirrorJoin, modifiers_exports as modifiers, modifyStep, moduleInitError, multiSectionSweep, normalAt, offset, offsetFace, offsetMesh, offsetShape, offsetWire2D, ok, or, orElse, organiseBlueprints, orientedFace, outerWire, patterns_exports as patterns, pendingCount, pipeline, pivotPlane, planarFace, planarWire, planetPlacements, pocket, pointOnSurface, pointsInside, polygon, polyhedron, polysideInnerRadius, polysidesBlueprint, positionOnCurve, prewarm, primitives_exports as primitives, projectEdges, projectPointOnFace, query_exports as query, queryError, rectangularPattern, registerHandler, registerKernel, registerOperation, registerShape, registerVoxel, rejectAll, removeChild, removeHolesFromFace, repairMesh, replayFrom, replayHistory, resetDisposalStats, resetPerformanceStats, resize, resolve, resolve3D, resolveDirection, resolvePlane, resolveRef, reverseCurve, revolve, roof, rotate, rotate2D, rotateDrawing, roundedRectangleBlueprint, scale, scale2D, scaleDrawing, section, sectionToFace, serializeHistory, setShapeOrigin, setTagMetadata, sewShells, shape, shapeToMeshInput, shapeType, sharedEdges, shell, shellMesh, shellShape, shellWithEvolution, simplify, sketchCircle, sketchEllipse, sketchExtrude, sketchFace, sketchFaceOffset, sketchHelix, sketchLoft, sketchOnFace2D, sketchOnPlane2D, sketchParametricFunction, sketchPolysides, sketchRectangle, sketchRevolve, sketchRoundedRectangle, sketchSweep, sketchText, sketchWires, sketcherStateError, slice, solid, solidFromShell, solveAssembly, sphere, split, stepCount, stepsFrom, stretch2D, subFace, supportExtrude, supportsConstraintSketch, supportsProjection, surfaceFromGrid, surfaceFromImage, sweep, tagFaces, tangentArc, tap, tapErr, textBlueprints, textMetrics, thicken, threePointArc, toBREP, toBufferGeometryData, toGroupedBufferGeometryData, toKernelVec, toLODGeometryData, toLineGeometryData, toSVGPathD, toVec2, toVec3, torus, tpmsLattice, transformCopy, transforms_exports as transforms, translate, translate2D, translateDrawing, translatePlane, tryCatch, tryCatchAsync, twistExtrude, typeCastError, undoLast, unsupportedError, unwrap, unwrapErr, unwrapOr, unwrapOrElse, updateNode, updateRoles, uvBounds, uvCoordinates, validSolid, validatePlanetary, validationError, variableFillet, vecAdd, vecAngle, vecCross, vecDistance, vecDot, vecEquals, vecIsZero, vecLength, vecLengthSq, vecNegate, vecNormalize, vecProjectToPlane, vecRepr, vecRotate, vecScale, vecSub, vertex, vertexFinder, vertexPosition, verticesOfEdge, voxelBoolean, voxelBooleanShapes, walkAssembly, windingNumbers, wire, wireFinder, wireLoop, wiresOfFace, withKernel, withKernelDir, withKernelPnt, withKernelVec, withScope, withScopeResult, withScopeResultAsync, zip as zipResults };
package/dist/index.d.ts CHANGED
@@ -34,9 +34,9 @@ export { exportDXF, blueprintToDXF, type DXFEntity, type DXFExportOptions, } fro
34
34
  export { exportThreeMF, type ThreeMFExportOptions, type ThreeMFMaterial, } from './io/threemfExportFns.js';
35
35
  export { importSVGPathD, importSVG, type SVGImportOptions } from './io/svgImportFns.js';
36
36
  export { exportSTEPConfigured, type StepExportOptions, type StepExportPart, } from './io/stepConfigFns.js';
37
- export { initVoxel, registerVoxel, getVoxel, getActiveVoxelId, windingNumbers, pointsInside, repairMesh, } from './voxel/index.js';
38
- export type { VoxelEngine, VoxelMeshInput, VoxelRepairResult, RepairOptions, } from './voxel/index.js';
39
- export { latticeInfill, tpmsLattice } from './lattice/index.js';
37
+ export { initVoxel, registerVoxel, getVoxel, getActiveVoxelId, windingNumbers, pointsInside, repairMesh, offsetMesh, shellMesh, voxelBoolean, offsetShape, shellShape, voxelBooleanShapes, shapeToMeshInput, } from './voxel/index.js';
38
+ export type { VoxelEngine, VoxelMeshInput, VoxelRepairResult, RepairOptions, VoxelOpOptions, } from './voxel/index.js';
39
+ export { latticeInfill, latticeInfillShape, tpmsLattice } from './lattice/index.js';
40
40
  export type { LatticeType, LatticeOptions, LatticeBounds } from './lattice/index.js';
41
41
  export { default as Sketcher } from './sketching/sketcher.js';
42
42
  export { default as FaceSketcher } from './sketching/faceSketcher.js';
@@ -5,5 +5,5 @@
5
5
  * solid (infill) or clipped to a box. Sits on the voxel domain's FWN-signed grid
6
6
  * and Surface-Nets contour, surfaced through the shared voxel engine registry.
7
7
  */
8
- export { latticeInfill, tpmsLattice } from './latticeFns.js';
8
+ export { latticeInfill, latticeInfillShape, tpmsLattice } from './latticeFns.js';
9
9
  export type { LatticeType, LatticeOptions, LatticeBounds } from './latticeFns.js';
@@ -1,5 +1,6 @@
1
1
  import { Result } from '../core/result.js';
2
2
  import { KernelMeshResult } from '../kernel/types.js';
3
+ import { AnyShape, Dimension } from '../core/shapeTypes.js';
3
4
  import { VoxelMeshInput } from '../voxel/signFns.js';
4
5
  /** TPMS lattice families. Maps to the wasm tag (0=Gyroid, 1=SchwarzP, 2=Diamond). */
5
6
  export type LatticeType = 'gyroid' | 'schwarzP' | 'diamond';
@@ -25,6 +26,12 @@ export interface LatticeOptions {
25
26
  * is contoured at the zero level without distance normalization (ADR-0013).
26
27
  */
27
28
  export declare function latticeInfill(mesh: VoxelMeshInput, opts: LatticeOptions, id?: string): Result<KernelMeshResult>;
29
+ /**
30
+ * Fill a B-rep shape with a TPMS lattice infill: tessellate the shape, then run
31
+ * {@link latticeInfill} on the resulting triangle soup. Threads a meshing
32
+ * failure straight back as an `err(...)`.
33
+ */
34
+ export declare function latticeInfillShape(shape: AnyShape<Dimension>, opts: LatticeOptions, id?: string): Result<KernelMeshResult>;
28
35
  /** Axis-aligned bounds for a clipped TPMS lattice. */
29
36
  export interface LatticeBounds {
30
37
  min: [number, number, number];
@@ -17,6 +17,12 @@ export interface VoxelEngine {
17
17
  lattice_infill(verts: Float32Array, tris: Uint32Array, resolution: number, padding: number, lattice_type: number, period: number, thickness: number): VoxelRepairResult;
18
18
  /** Contour the infinite TPMS lattice clipped to an axis-aligned box. */
19
19
  tpms_box(min_x: number, min_y: number, min_z: number, max_x: number, max_y: number, max_z: number, resolution: number, padding: number, lattice_type: number, period: number, thickness: number): VoxelRepairResult;
20
+ /** Offset a mesh by a true-SDF iso-level shift (>0 outward, <0 inward). */
21
+ offset_mesh(verts: Float32Array, tris: Uint32Array, distance: number, resolution: number, padding: number): VoxelRepairResult;
22
+ /** Hollow a solid mesh into an inward shell of the given thickness (>0). */
23
+ shell_mesh(verts: Float32Array, tris: Uint32Array, thickness: number, resolution: number, padding: number): VoxelRepairResult;
24
+ /** Voxel CSG of two meshes (op: 0=union, 1=intersection, 2=difference A−B). */
25
+ voxel_boolean(verts_a: Float32Array, tris_a: Uint32Array, verts_b: Float32Array, tris_b: Uint32Array, op: number, resolution: number, padding: number): VoxelRepairResult;
20
26
  /** Engine artifact version, for loader/artifact compatibility checks. */
21
27
  version(): string;
22
28
  }
@@ -8,6 +8,9 @@
8
8
  export type { VoxelEngine, VoxelRepairResult } from './engine.js';
9
9
  export type { VoxelMeshInput } from './signFns.js';
10
10
  export type { RepairOptions } from './repairFns.js';
11
+ export type { VoxelOpOptions } from './meshOpsFns.js';
11
12
  export { registerVoxel, getVoxel, getActiveVoxelId, initVoxel } from './registry.js';
12
13
  export { windingNumbers, pointsInside } from './signFns.js';
13
14
  export { repairMesh } from './repairFns.js';
15
+ export { offsetMesh, shellMesh, voxelBoolean, offsetShape, shellShape, voxelBooleanShapes, } from './meshOpsFns.js';
16
+ export { shapeToMeshInput } from './shapeMesh.js';
@@ -0,0 +1,52 @@
1
+ import { Result } from '../core/result.js';
2
+ import { KernelMeshResult } from '../kernel/types.js';
3
+ import { AnyShape, Dimension } from '../core/shapeTypes.js';
4
+ import { VoxelMeshInput } from './signFns.js';
5
+ /** Voxel mesh-op tuning. `resolution` sizes the longest bbox axis in voxels;
6
+ * `padding` is the positive air-margin ring (>= 1) Surface Nets needs. */
7
+ export interface VoxelOpOptions {
8
+ resolution?: number;
9
+ padding?: number;
10
+ }
11
+ /**
12
+ * Offset a mesh by `distance` via a true-SDF iso-level shift: voxelize an
13
+ * FWN-signed SDF, subtract `distance`, then Surface-Nets contour it back.
14
+ *
15
+ * `distance > 0` grows the surface outward, `< 0` shrinks it inward. Returns a
16
+ * {@link KernelMeshResult} in world coordinates (a single face group, no UVs).
17
+ */
18
+ export declare function offsetMesh(mesh: VoxelMeshInput, distance: number, opts?: VoxelOpOptions, id?: string): Result<KernelMeshResult>;
19
+ /**
20
+ * Hollow a solid mesh into a shell of the given inward `thickness`: voxelize an
21
+ * FWN-signed SDF, take `max(solid, -(solid + thickness))`, then contour it.
22
+ *
23
+ * `thickness` must be finite and > 0 (inward-only). Returns a
24
+ * {@link KernelMeshResult} in world coordinates (a single face group, no UVs).
25
+ */
26
+ export declare function shellMesh(mesh: VoxelMeshInput, thickness: number, opts?: VoxelOpOptions, id?: string): Result<KernelMeshResult>;
27
+ /**
28
+ * Voxel-based CSG of two meshes: voxelize both onto a shared grid, combine their
29
+ * SDFs (union/intersection/difference), then Surface-Nets contour the result.
30
+ *
31
+ * `op` is `'difference'` = A − B. Robust on non-watertight input (FWN sign).
32
+ * Returns a {@link KernelMeshResult} in world coordinates (single group, no UVs).
33
+ */
34
+ export declare function voxelBoolean(a: VoxelMeshInput, b: VoxelMeshInput, op: 'union' | 'intersection' | 'difference', opts?: VoxelOpOptions, id?: string): Result<KernelMeshResult>;
35
+ /**
36
+ * Offset a B-rep shape by `distance`: tessellate it, then run {@link offsetMesh}
37
+ * on the resulting triangle soup. `distance > 0` grows outward, `< 0` shrinks
38
+ * inward. Threads a meshing failure straight back as an `err(...)`.
39
+ */
40
+ export declare function offsetShape(shape: AnyShape<Dimension>, distance: number, opts?: VoxelOpOptions, id?: string): Result<KernelMeshResult>;
41
+ /**
42
+ * Hollow a B-rep shape into a shell of inward `thickness`: tessellate it, then
43
+ * run {@link shellMesh}. `thickness` must be finite and > 0. Threads a meshing
44
+ * failure straight back as an `err(...)`.
45
+ */
46
+ export declare function shellShape(shape: AnyShape<Dimension>, thickness: number, opts?: VoxelOpOptions, id?: string): Result<KernelMeshResult>;
47
+ /**
48
+ * Voxel CSG of two B-rep shapes: tessellate both, then run {@link voxelBoolean}.
49
+ * `op` is `'difference'` = A − B. Threads either meshing failure back as an
50
+ * `err(...)`.
51
+ */
52
+ export declare function voxelBooleanShapes(a: AnyShape<Dimension>, b: AnyShape<Dimension>, op: 'union' | 'intersection' | 'difference', opts?: VoxelOpOptions, id?: string): Result<KernelMeshResult>;
@@ -0,0 +1,10 @@
1
+ import { AnyShape, Dimension } from '../core/shapeTypes.js';
2
+ import { Result } from '../core/result.js';
3
+ import { VoxelMeshInput } from './signFns.js';
4
+ /**
5
+ * Mesh a B-rep shape into the flat triangle-soup {@link VoxelMeshInput} the voxel
6
+ * ops consume. Tessellates via the topology mesh API at `deflection` linear
7
+ * tolerance and forwards its `{ vertices, triangles }` (already Float32Array /
8
+ * Uint32Array). Meshing failures surface as an `err(...)` rather than a throw.
9
+ */
10
+ export declare function shapeToMeshInput(shape: AnyShape<Dimension>, deflection?: number): Result<VoxelMeshInput>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brepjs",
3
- "version": "18.39.0",
3
+ "version": "18.40.0",
4
4
  "description": "Web CAD library with pluggable geometry kernel",
5
5
  "keywords": [
6
6
  "cad",