brepjs 18.126.0 → 18.127.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 +113 -40
- package/dist/brepjs.js +113 -40
- package/dist/csg/builders.d.ts +8 -1
- package/dist/csg/evaluators/sweep.d.ts +5 -0
- package/dist/csg/index.d.ts +2 -2
- package/dist/csg/serialize.d.ts +1 -1
- package/dist/csg/types.d.ts +10 -1
- package/package.json +1 -1
package/dist/brepjs.cjs
CHANGED
|
@@ -254,8 +254,8 @@ function repairMesh(mesh, opts, id) {
|
|
|
254
254
|
if (require_errors.isErr(engine)) return engine;
|
|
255
255
|
try {
|
|
256
256
|
try {
|
|
257
|
-
var _usingCtx$
|
|
258
|
-
const repaired = _usingCtx$
|
|
257
|
+
var _usingCtx$11 = require_shapeTypes._usingCtx();
|
|
258
|
+
const repaired = _usingCtx$11.u(engine.value.repair_mesh(mesh.vertices, mesh.triangles, resolution, padding));
|
|
259
259
|
const vertexCount = repaired.positions.length / 3;
|
|
260
260
|
return require_errors.ok({
|
|
261
261
|
vertices: repaired.positions,
|
|
@@ -269,9 +269,9 @@ function repairMesh(mesh, opts, id) {
|
|
|
269
269
|
}]
|
|
270
270
|
});
|
|
271
271
|
} catch (_) {
|
|
272
|
-
_usingCtx$
|
|
272
|
+
_usingCtx$11.e = _;
|
|
273
273
|
} finally {
|
|
274
|
-
_usingCtx$
|
|
274
|
+
_usingCtx$11.d();
|
|
275
275
|
}
|
|
276
276
|
} catch (cause) {
|
|
277
277
|
return require_errors.err(require_errors.computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
|
|
@@ -350,12 +350,12 @@ function offsetMesh(mesh, distance, opts, id) {
|
|
|
350
350
|
if (require_errors.isErr(engine)) return engine;
|
|
351
351
|
try {
|
|
352
352
|
try {
|
|
353
|
-
var _usingCtx$
|
|
354
|
-
return meshFromResult(_usingCtx$
|
|
353
|
+
var _usingCtx$10 = require_shapeTypes._usingCtx();
|
|
354
|
+
return meshFromResult(_usingCtx$10.u(engine.value.offset_mesh(mesh.vertices, mesh.triangles, distance, params.value.resolution, params.value.padding)));
|
|
355
355
|
} catch (_) {
|
|
356
|
-
_usingCtx$
|
|
356
|
+
_usingCtx$10.e = _;
|
|
357
357
|
} finally {
|
|
358
|
-
_usingCtx$
|
|
358
|
+
_usingCtx$10.d();
|
|
359
359
|
}
|
|
360
360
|
} catch (cause) {
|
|
361
361
|
return require_errors.err(require_errors.computationError("VOXEL_OFFSET_FAILED", cause instanceof Error ? cause.message : "voxel offset failed (grid too large?).", cause));
|
|
@@ -480,9 +480,9 @@ function resolveGridParams$1(opts) {
|
|
|
480
480
|
*/
|
|
481
481
|
function meshFromField(field) {
|
|
482
482
|
try {
|
|
483
|
-
var _usingCtx$
|
|
483
|
+
var _usingCtx$9 = require_shapeTypes._usingCtx();
|
|
484
484
|
const rawResult = field.contour();
|
|
485
|
-
const { positions, normals, indices } = _usingCtx$
|
|
485
|
+
const { positions, normals, indices } = _usingCtx$9.u({
|
|
486
486
|
value: rawResult,
|
|
487
487
|
[Symbol.dispose]() {
|
|
488
488
|
rawResult.free();
|
|
@@ -502,9 +502,9 @@ function meshFromField(field) {
|
|
|
502
502
|
}]
|
|
503
503
|
});
|
|
504
504
|
} catch (_) {
|
|
505
|
-
_usingCtx$
|
|
505
|
+
_usingCtx$9.e = _;
|
|
506
506
|
} finally {
|
|
507
|
-
_usingCtx$
|
|
507
|
+
_usingCtx$9.d();
|
|
508
508
|
}
|
|
509
509
|
}
|
|
510
510
|
function fieldDeletable(raw) {
|
|
@@ -1072,13 +1072,13 @@ function latticeInfill(mesh, opts, id) {
|
|
|
1072
1072
|
const { tag, period, thickness, resolution, padding } = resolved.value;
|
|
1073
1073
|
try {
|
|
1074
1074
|
try {
|
|
1075
|
-
var _usingCtx$
|
|
1076
|
-
const repaired = _usingCtx$
|
|
1075
|
+
var _usingCtx$8 = require_shapeTypes._usingCtx();
|
|
1076
|
+
const repaired = _usingCtx$8.u(engine.value.lattice_infill(mesh.vertices, mesh.triangles, resolution, padding, tag, period, thickness));
|
|
1077
1077
|
return require_errors.ok(toMesh(repaired));
|
|
1078
1078
|
} catch (_) {
|
|
1079
|
-
_usingCtx$
|
|
1079
|
+
_usingCtx$8.e = _;
|
|
1080
1080
|
} finally {
|
|
1081
|
-
_usingCtx$
|
|
1081
|
+
_usingCtx$8.d();
|
|
1082
1082
|
}
|
|
1083
1083
|
} catch (cause) {
|
|
1084
1084
|
return require_errors.err(require_errors.computationError("LATTICE_INFILL_FAILED", cause instanceof Error ? cause.message : "lattice infill failed (grid too large?).", cause));
|
|
@@ -3901,7 +3901,7 @@ function drill(shape, options) {
|
|
|
3901
3901
|
*/
|
|
3902
3902
|
function pocket(shape, options) {
|
|
3903
3903
|
try {
|
|
3904
|
-
var _usingCtx$
|
|
3904
|
+
var _usingCtx$7 = require_shapeTypes._usingCtx();
|
|
3905
3905
|
const s = resolve(shape);
|
|
3906
3906
|
const { profile, depth } = options;
|
|
3907
3907
|
if (depth <= 0) return require_errors.err(require_errors.validationError("POCKET_INVALID_DEPTH", "Pocket depth must be positive"));
|
|
@@ -3910,7 +3910,7 @@ function pocket(shape, options) {
|
|
|
3910
3910
|
const targetFace = targetResult.value;
|
|
3911
3911
|
const normal = require_faceFns.normalAt(targetFace);
|
|
3912
3912
|
const center = require_faceFns.faceCenter(targetFace);
|
|
3913
|
-
const scope = _usingCtx$
|
|
3913
|
+
const scope = _usingCtx$7.u(new require_shapeTypes.DisposalScope());
|
|
3914
3914
|
const { wire: w, owned } = toWire(profile);
|
|
3915
3915
|
if (owned) scope.register(w);
|
|
3916
3916
|
const faceResult = require_surfaceBuilders.makeFace(w);
|
|
@@ -3923,9 +3923,9 @@ function pocket(shape, options) {
|
|
|
3923
3923
|
scope.register(toolResult.value);
|
|
3924
3924
|
return require_solidBuilders.cut(s, toolResult.value, { unsafe: true });
|
|
3925
3925
|
} catch (_) {
|
|
3926
|
-
_usingCtx$
|
|
3926
|
+
_usingCtx$7.e = _;
|
|
3927
3927
|
} finally {
|
|
3928
|
-
_usingCtx$
|
|
3928
|
+
_usingCtx$7.d();
|
|
3929
3929
|
}
|
|
3930
3930
|
}
|
|
3931
3931
|
/**
|
|
@@ -4515,12 +4515,12 @@ function makeInternalGearProfileWire(params) {
|
|
|
4515
4515
|
}
|
|
4516
4516
|
function makeProfileWire(params, isInternal) {
|
|
4517
4517
|
try {
|
|
4518
|
-
var _usingCtx$
|
|
4518
|
+
var _usingCtx$6 = require_shapeTypes._usingCtx();
|
|
4519
4519
|
const { teeth, moduleSize, pressureAngle, shift, clearance, flankThinning, samples = adaptiveSampleCount(moduleSize) } = params;
|
|
4520
4520
|
if (teeth < 4) return require_errors.err(require_errors.validationError("GEAR_TEETH_TOO_FEW", `gear needs ≥ 4 teeth, got ${teeth}`));
|
|
4521
4521
|
if (moduleSize <= 0) return require_errors.err(require_errors.validationError("GEAR_MODULE_NONPOSITIVE", `module must be > 0, got ${moduleSize}`));
|
|
4522
4522
|
const tm = gearGeometry(teeth, moduleSize, pressureAngle, shift, clearance, flankThinning, isInternal);
|
|
4523
|
-
const scope = _usingCtx$
|
|
4523
|
+
const scope = _usingCtx$6.u(new require_shapeTypes.DisposalScope());
|
|
4524
4524
|
const allEdges = [];
|
|
4525
4525
|
for (let i = 0; i < teeth; i++) {
|
|
4526
4526
|
const periodEdges = buildToothPeriodEdges(tm, i, teeth, samples, scope);
|
|
@@ -4531,9 +4531,9 @@ function makeProfileWire(params, isInternal) {
|
|
|
4531
4531
|
if (require_errors.isErr(wireResult)) return wireResult;
|
|
4532
4532
|
return require_errors.ok(wireResult.value);
|
|
4533
4533
|
} catch (_) {
|
|
4534
|
-
_usingCtx$
|
|
4534
|
+
_usingCtx$6.e = _;
|
|
4535
4535
|
} finally {
|
|
4536
|
-
_usingCtx$
|
|
4536
|
+
_usingCtx$6.d();
|
|
4537
4537
|
}
|
|
4538
4538
|
}
|
|
4539
4539
|
//#endregion
|
|
@@ -4714,8 +4714,8 @@ function resolvePlanetaryParams(params) {
|
|
|
4714
4714
|
}
|
|
4715
4715
|
function makeOuterCircleWire(radius) {
|
|
4716
4716
|
try {
|
|
4717
|
-
var _usingCtx$
|
|
4718
|
-
const circleEdge = _usingCtx$
|
|
4717
|
+
var _usingCtx$5 = require_shapeTypes._usingCtx();
|
|
4718
|
+
const circleEdge = _usingCtx$5.u(new require_shapeTypes.DisposalScope()).register(require_surfaceBuilders.makeCircle(radius, [
|
|
4719
4719
|
0,
|
|
4720
4720
|
0,
|
|
4721
4721
|
0
|
|
@@ -4728,9 +4728,9 @@ function makeOuterCircleWire(radius) {
|
|
|
4728
4728
|
if (require_errors.isErr(wireResult)) return wireResult;
|
|
4729
4729
|
return require_errors.ok(wireResult.value);
|
|
4730
4730
|
} catch (_) {
|
|
4731
|
-
_usingCtx$
|
|
4731
|
+
_usingCtx$5.e = _;
|
|
4732
4732
|
} finally {
|
|
4733
|
-
_usingCtx$
|
|
4733
|
+
_usingCtx$5.d();
|
|
4734
4734
|
}
|
|
4735
4735
|
}
|
|
4736
4736
|
function finalizeExternalSolid(wire, thickness, bore, geom, diagnostics) {
|
|
@@ -5702,6 +5702,22 @@ function extrude$1(profile, vector) {
|
|
|
5702
5702
|
freeParams: depsOf(profile, ve)
|
|
5703
5703
|
};
|
|
5704
5704
|
}
|
|
5705
|
+
/** Sweep a face-producing profile along a Wire/Edge-producing spine.
|
|
5706
|
+
* `frenet` is canonicalized (default false) so the default and explicit
|
|
5707
|
+
* forms share one content address. */
|
|
5708
|
+
function sweep$2(profile, spine, options) {
|
|
5709
|
+
const frenet = options?.frenet ?? false;
|
|
5710
|
+
let h = mix(mix(startHash("Sweep"), profile), spine);
|
|
5711
|
+
h = fnvMixBool(h, frenet);
|
|
5712
|
+
return {
|
|
5713
|
+
kind: "Sweep",
|
|
5714
|
+
profile,
|
|
5715
|
+
spine,
|
|
5716
|
+
frenet,
|
|
5717
|
+
structuralHash: h,
|
|
5718
|
+
freeParams: depsOf(profile, spine)
|
|
5719
|
+
};
|
|
5720
|
+
}
|
|
5705
5721
|
/** Open (or incidentally closed) planar path in the XY plane at z = 0,
|
|
5706
5722
|
* producing a Wire. Segments come from `lineTo`/`arcTo`/`bezierTo`/
|
|
5707
5723
|
* `ellipseArcTo`. */
|
|
@@ -5802,7 +5818,8 @@ function outputKindOf(node) {
|
|
|
5802
5818
|
case "Mirror": return outputKindOf(node.target);
|
|
5803
5819
|
case "Extrude":
|
|
5804
5820
|
case "Revolve":
|
|
5805
|
-
case "Loft":
|
|
5821
|
+
case "Loft":
|
|
5822
|
+
case "Sweep": return "Solid";
|
|
5806
5823
|
case "Path": return "Wire";
|
|
5807
5824
|
case "Compound": return "Compound";
|
|
5808
5825
|
case "Instance": return node.fuse ? "Solid" : "Compound";
|
|
@@ -6131,9 +6148,9 @@ function evalRevolve(node, ctx) {
|
|
|
6131
6148
|
//#region src/csg/evaluators/loft.ts
|
|
6132
6149
|
function evalLoft(node, ctx) {
|
|
6133
6150
|
try {
|
|
6134
|
-
var _usingCtx$
|
|
6151
|
+
var _usingCtx$4 = require_shapeTypes._usingCtx();
|
|
6135
6152
|
if (node.sections.length < 2) return require_errors.err(require_errors.validationError("CSG_LOFT_SECTIONS", `Loft requires at least 2 sections, got ${node.sections.length}`));
|
|
6136
|
-
const scope = _usingCtx$
|
|
6153
|
+
const scope = _usingCtx$4.u(new require_shapeTypes.DisposalScope());
|
|
6137
6154
|
const wires = [];
|
|
6138
6155
|
for (const [i, section] of node.sections.entries()) {
|
|
6139
6156
|
const face = resolveProfileFace(ctx, section, `Loft.sections[${i}]`);
|
|
@@ -6144,9 +6161,9 @@ function evalLoft(node, ctx) {
|
|
|
6144
6161
|
}
|
|
6145
6162
|
return require_loftFns.loft(wires, { ruled: node.ruled });
|
|
6146
6163
|
} catch (_) {
|
|
6147
|
-
_usingCtx$
|
|
6164
|
+
_usingCtx$4.e = _;
|
|
6148
6165
|
} finally {
|
|
6149
|
-
_usingCtx$
|
|
6166
|
+
_usingCtx$4.d();
|
|
6150
6167
|
}
|
|
6151
6168
|
}
|
|
6152
6169
|
//#endregion
|
|
@@ -6257,14 +6274,14 @@ function ellipseEdge(from, seg, ctx) {
|
|
|
6257
6274
|
if (!arc.ok) return arc;
|
|
6258
6275
|
let edge = arc.value;
|
|
6259
6276
|
if (Math.abs(psi) > EPS) try {
|
|
6260
|
-
var _usingCtx$
|
|
6261
|
-
const rotated = rotateEdgeAbout(_usingCtx$
|
|
6277
|
+
var _usingCtx$3 = require_shapeTypes._usingCtx();
|
|
6278
|
+
const rotated = rotateEdgeAbout(_usingCtx$3.u(edge), psi * 180 / Math.PI, center);
|
|
6262
6279
|
if (!rotated.ok) return rotated;
|
|
6263
6280
|
edge = rotated.value;
|
|
6264
6281
|
} catch (_) {
|
|
6265
|
-
_usingCtx$
|
|
6282
|
+
_usingCtx$3.e = _;
|
|
6266
6283
|
} finally {
|
|
6267
|
-
_usingCtx$
|
|
6284
|
+
_usingCtx$3.d();
|
|
6268
6285
|
}
|
|
6269
6286
|
if (seg.clockwise) try {
|
|
6270
6287
|
var _usingCtx3 = require_shapeTypes._usingCtx();
|
|
@@ -6368,6 +6385,39 @@ function evalPath(node, ctx) {
|
|
|
6368
6385
|
}
|
|
6369
6386
|
}
|
|
6370
6387
|
//#endregion
|
|
6388
|
+
//#region src/csg/evaluators/sweep.ts
|
|
6389
|
+
function evalSweep(node, ctx) {
|
|
6390
|
+
try {
|
|
6391
|
+
var _usingCtx$2 = require_shapeTypes._usingCtx();
|
|
6392
|
+
const face = resolveProfileFace(ctx, node.profile, "Sweep.profile");
|
|
6393
|
+
if (!face.ok) return face;
|
|
6394
|
+
const spineShape = ctx.evalNode(node.spine);
|
|
6395
|
+
if (!spineShape.ok) return spineShape;
|
|
6396
|
+
const scope = _usingCtx$2.u(new require_shapeTypes.DisposalScope());
|
|
6397
|
+
let spine;
|
|
6398
|
+
if (require_shapeTypes.isWire(spineShape.value)) spine = spineShape.value;
|
|
6399
|
+
else if (require_shapeTypes.isEdge(spineShape.value)) {
|
|
6400
|
+
const wrapped = require_surfaceBuilders.assembleWire([spineShape.value]);
|
|
6401
|
+
if (!wrapped.ok) return wrapped;
|
|
6402
|
+
scope.register(wrapped.value);
|
|
6403
|
+
spine = wrapped.value;
|
|
6404
|
+
} else return require_errors.err(require_errors.typeCastError("CSG_SWEEP_SPINE", "Sweep.spine: node did not produce a Wire or Edge"));
|
|
6405
|
+
const profileWire = require_faceFns.outerWire(face.value);
|
|
6406
|
+
scope.register(profileWire);
|
|
6407
|
+
const r = require_loftFns.sweep(profileWire, spine, { frenet: node.frenet });
|
|
6408
|
+
if (!r.ok) return r;
|
|
6409
|
+
if (Array.isArray(r.value)) {
|
|
6410
|
+
for (const s of r.value) s[Symbol.dispose]();
|
|
6411
|
+
return require_errors.err(require_errors.typeCastError("CSG_SWEEP_SPINE", "Sweep: unexpected shell-mode result"));
|
|
6412
|
+
}
|
|
6413
|
+
return require_errors.ok(r.value);
|
|
6414
|
+
} catch (_) {
|
|
6415
|
+
_usingCtx$2.e = _;
|
|
6416
|
+
} finally {
|
|
6417
|
+
_usingCtx$2.d();
|
|
6418
|
+
}
|
|
6419
|
+
}
|
|
6420
|
+
//#endregion
|
|
6371
6421
|
//#region src/csg/evaluate.ts
|
|
6372
6422
|
function dispatch(node, ctx) {
|
|
6373
6423
|
switch (node.kind) {
|
|
@@ -6396,6 +6446,7 @@ function dispatch(node, ctx) {
|
|
|
6396
6446
|
case "Revolve": return evalRevolve(node, ctx);
|
|
6397
6447
|
case "Loft": return evalLoft(node, ctx);
|
|
6398
6448
|
case "Path": return evalPath(node, ctx);
|
|
6449
|
+
case "Sweep": return evalSweep(node, ctx);
|
|
6399
6450
|
}
|
|
6400
6451
|
}
|
|
6401
6452
|
function hashExprValue(h, v) {
|
|
@@ -6802,9 +6853,10 @@ function withEvaluator(options, fn) {
|
|
|
6802
6853
|
_usingCtx$1.d();
|
|
6803
6854
|
}
|
|
6804
6855
|
}
|
|
6856
|
+
var MIN_CSG_VERSION = 1;
|
|
6805
6857
|
function toJSON(node) {
|
|
6806
6858
|
return {
|
|
6807
|
-
csgVersion:
|
|
6859
|
+
csgVersion: 2,
|
|
6808
6860
|
root: nodeToJson(node)
|
|
6809
6861
|
};
|
|
6810
6862
|
}
|
|
@@ -7012,6 +7064,12 @@ function nodeToJson(n) {
|
|
|
7012
7064
|
start: exprToJson(n.start),
|
|
7013
7065
|
segments: n.segments.map(segmentToJson)
|
|
7014
7066
|
};
|
|
7067
|
+
if (n.kind === "Sweep") return {
|
|
7068
|
+
kind: "Sweep",
|
|
7069
|
+
profile: nodeToJson(n.profile),
|
|
7070
|
+
spine: nodeToJson(n.spine),
|
|
7071
|
+
frenet: n.frenet
|
|
7072
|
+
};
|
|
7015
7073
|
if (n.kind === "Compound") return {
|
|
7016
7074
|
kind: "Compound",
|
|
7017
7075
|
children: n.children.map(nodeToJson)
|
|
@@ -7055,7 +7113,7 @@ function readVec2(v, where) {
|
|
|
7055
7113
|
function fromJSON(envelope) {
|
|
7056
7114
|
if (!isObj(envelope)) return bad("input is not an object");
|
|
7057
7115
|
const v = envelope["csgVersion"];
|
|
7058
|
-
if (v !==
|
|
7116
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 2) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..2)`);
|
|
7059
7117
|
const root = envelope["root"];
|
|
7060
7118
|
return readNode(root);
|
|
7061
7119
|
}
|
|
@@ -7167,6 +7225,7 @@ function readNode(j) {
|
|
|
7167
7225
|
case "Revolve": return readRevolve(j);
|
|
7168
7226
|
case "Loft": return readLoft(j);
|
|
7169
7227
|
case "Path": return readPath(j);
|
|
7228
|
+
case "Sweep": return readSweep(j);
|
|
7170
7229
|
default: return bad(`unknown node kind: ${String(kind)}`);
|
|
7171
7230
|
}
|
|
7172
7231
|
}
|
|
@@ -7402,6 +7461,15 @@ function readSegment(j) {
|
|
|
7402
7461
|
default: return bad(`unknown segment kind: ${String(kind)}`);
|
|
7403
7462
|
}
|
|
7404
7463
|
}
|
|
7464
|
+
function readSweep(j) {
|
|
7465
|
+
const profile = readNode(j["profile"]);
|
|
7466
|
+
if (!profile.ok) return profile;
|
|
7467
|
+
const spine = readNode(j["spine"]);
|
|
7468
|
+
if (!spine.ok) return spine;
|
|
7469
|
+
const frenet = readFlag(j, "frenet");
|
|
7470
|
+
if (!frenet.ok) return frenet;
|
|
7471
|
+
return require_errors.ok(sweep$2(profile.value, spine.value, { frenet: frenet.value }));
|
|
7472
|
+
}
|
|
7405
7473
|
function readPath(j) {
|
|
7406
7474
|
const start = readExpr(j["start"]);
|
|
7407
7475
|
if (!start.ok) return start;
|
|
@@ -7529,6 +7597,7 @@ function optimizeNode(n) {
|
|
|
7529
7597
|
case "Extrude":
|
|
7530
7598
|
case "Revolve":
|
|
7531
7599
|
case "Loft":
|
|
7600
|
+
case "Sweep":
|
|
7532
7601
|
case "Path": return optimizeFeature(n);
|
|
7533
7602
|
}
|
|
7534
7603
|
}
|
|
@@ -7540,6 +7609,7 @@ function optimizeFeature(n) {
|
|
|
7540
7609
|
at: n.at ? foldExpr(n.at) : void 0
|
|
7541
7610
|
});
|
|
7542
7611
|
case "Loft": return loft$1(n.sections.map(optimizeNode), { ruled: n.ruled });
|
|
7612
|
+
case "Sweep": return sweep$2(optimizeNode(n.profile), optimizeNode(n.spine), { frenet: n.frenet });
|
|
7543
7613
|
case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
|
|
7544
7614
|
}
|
|
7545
7615
|
}
|
|
@@ -7638,6 +7708,7 @@ function rebuildChildren(n, pred, repl) {
|
|
|
7638
7708
|
at: n.at
|
|
7639
7709
|
});
|
|
7640
7710
|
case "Loft": return loft$1(n.sections.map((s) => walk(s, pred, repl)), { ruled: n.ruled });
|
|
7711
|
+
case "Sweep": return sweep$2(walk(n.profile, pred, repl), walk(n.spine, pred, repl), { frenet: n.frenet });
|
|
7641
7712
|
}
|
|
7642
7713
|
}
|
|
7643
7714
|
function forEachNode(root, fn) {
|
|
@@ -7671,6 +7742,7 @@ function childrenOf(n) {
|
|
|
7671
7742
|
case "Extrude":
|
|
7672
7743
|
case "Revolve": return [n.profile];
|
|
7673
7744
|
case "Loft": return n.sections;
|
|
7745
|
+
case "Sweep": return [n.profile, n.spine];
|
|
7674
7746
|
}
|
|
7675
7747
|
}
|
|
7676
7748
|
function nodeCount(root) {
|
|
@@ -7683,7 +7755,7 @@ function nodeCount(root) {
|
|
|
7683
7755
|
//#endregion
|
|
7684
7756
|
//#region src/ns/csg.ts
|
|
7685
7757
|
var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
7686
|
-
CSG_VERSION: () =>
|
|
7758
|
+
CSG_VERSION: () => 2,
|
|
7687
7759
|
Evaluator: () => Evaluator,
|
|
7688
7760
|
add: () => add,
|
|
7689
7761
|
arcTo: () => arcTo,
|
|
@@ -7730,6 +7802,7 @@ var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
|
7730
7802
|
rotate: () => rotate$1,
|
|
7731
7803
|
scale: () => scale$1,
|
|
7732
7804
|
sphere: () => sphere$2,
|
|
7805
|
+
sweep: () => sweep$2,
|
|
7733
7806
|
toJSON: () => toJSON,
|
|
7734
7807
|
torus: () => torus$2,
|
|
7735
7808
|
translate: () => translate$1,
|
package/dist/brepjs.js
CHANGED
|
@@ -264,8 +264,8 @@ function repairMesh(mesh, opts, id) {
|
|
|
264
264
|
if (isErr(engine)) return engine;
|
|
265
265
|
try {
|
|
266
266
|
try {
|
|
267
|
-
var _usingCtx$
|
|
268
|
-
const repaired = _usingCtx$
|
|
267
|
+
var _usingCtx$11 = _usingCtx();
|
|
268
|
+
const repaired = _usingCtx$11.u(engine.value.repair_mesh(mesh.vertices, mesh.triangles, resolution, padding));
|
|
269
269
|
const vertexCount = repaired.positions.length / 3;
|
|
270
270
|
return ok({
|
|
271
271
|
vertices: repaired.positions,
|
|
@@ -279,9 +279,9 @@ function repairMesh(mesh, opts, id) {
|
|
|
279
279
|
}]
|
|
280
280
|
});
|
|
281
281
|
} catch (_) {
|
|
282
|
-
_usingCtx$
|
|
282
|
+
_usingCtx$11.e = _;
|
|
283
283
|
} finally {
|
|
284
|
-
_usingCtx$
|
|
284
|
+
_usingCtx$11.d();
|
|
285
285
|
}
|
|
286
286
|
} catch (cause) {
|
|
287
287
|
return err(computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
|
|
@@ -360,12 +360,12 @@ function offsetMesh(mesh, distance, opts, id) {
|
|
|
360
360
|
if (isErr(engine)) return engine;
|
|
361
361
|
try {
|
|
362
362
|
try {
|
|
363
|
-
var _usingCtx$
|
|
364
|
-
return meshFromResult(_usingCtx$
|
|
363
|
+
var _usingCtx$10 = _usingCtx();
|
|
364
|
+
return meshFromResult(_usingCtx$10.u(engine.value.offset_mesh(mesh.vertices, mesh.triangles, distance, params.value.resolution, params.value.padding)));
|
|
365
365
|
} catch (_) {
|
|
366
|
-
_usingCtx$
|
|
366
|
+
_usingCtx$10.e = _;
|
|
367
367
|
} finally {
|
|
368
|
-
_usingCtx$
|
|
368
|
+
_usingCtx$10.d();
|
|
369
369
|
}
|
|
370
370
|
} catch (cause) {
|
|
371
371
|
return err(computationError("VOXEL_OFFSET_FAILED", cause instanceof Error ? cause.message : "voxel offset failed (grid too large?).", cause));
|
|
@@ -490,9 +490,9 @@ function resolveGridParams$1(opts) {
|
|
|
490
490
|
*/
|
|
491
491
|
function meshFromField(field) {
|
|
492
492
|
try {
|
|
493
|
-
var _usingCtx$
|
|
493
|
+
var _usingCtx$9 = _usingCtx();
|
|
494
494
|
const rawResult = field.contour();
|
|
495
|
-
const { positions, normals, indices } = _usingCtx$
|
|
495
|
+
const { positions, normals, indices } = _usingCtx$9.u({
|
|
496
496
|
value: rawResult,
|
|
497
497
|
[Symbol.dispose]() {
|
|
498
498
|
rawResult.free();
|
|
@@ -512,9 +512,9 @@ function meshFromField(field) {
|
|
|
512
512
|
}]
|
|
513
513
|
});
|
|
514
514
|
} catch (_) {
|
|
515
|
-
_usingCtx$
|
|
515
|
+
_usingCtx$9.e = _;
|
|
516
516
|
} finally {
|
|
517
|
-
_usingCtx$
|
|
517
|
+
_usingCtx$9.d();
|
|
518
518
|
}
|
|
519
519
|
}
|
|
520
520
|
function fieldDeletable(raw) {
|
|
@@ -1082,13 +1082,13 @@ function latticeInfill(mesh, opts, id) {
|
|
|
1082
1082
|
const { tag, period, thickness, resolution, padding } = resolved.value;
|
|
1083
1083
|
try {
|
|
1084
1084
|
try {
|
|
1085
|
-
var _usingCtx$
|
|
1086
|
-
const repaired = _usingCtx$
|
|
1085
|
+
var _usingCtx$8 = _usingCtx();
|
|
1086
|
+
const repaired = _usingCtx$8.u(engine.value.lattice_infill(mesh.vertices, mesh.triangles, resolution, padding, tag, period, thickness));
|
|
1087
1087
|
return ok(toMesh(repaired));
|
|
1088
1088
|
} catch (_) {
|
|
1089
|
-
_usingCtx$
|
|
1089
|
+
_usingCtx$8.e = _;
|
|
1090
1090
|
} finally {
|
|
1091
|
-
_usingCtx$
|
|
1091
|
+
_usingCtx$8.d();
|
|
1092
1092
|
}
|
|
1093
1093
|
} catch (cause) {
|
|
1094
1094
|
return err(computationError("LATTICE_INFILL_FAILED", cause instanceof Error ? cause.message : "lattice infill failed (grid too large?).", cause));
|
|
@@ -3910,7 +3910,7 @@ function drill(shape, options) {
|
|
|
3910
3910
|
*/
|
|
3911
3911
|
function pocket(shape, options) {
|
|
3912
3912
|
try {
|
|
3913
|
-
var _usingCtx$
|
|
3913
|
+
var _usingCtx$7 = _usingCtx();
|
|
3914
3914
|
const s = resolve(shape);
|
|
3915
3915
|
const { profile, depth } = options;
|
|
3916
3916
|
if (depth <= 0) return err(validationError("POCKET_INVALID_DEPTH", "Pocket depth must be positive"));
|
|
@@ -3919,7 +3919,7 @@ function pocket(shape, options) {
|
|
|
3919
3919
|
const targetFace = targetResult.value;
|
|
3920
3920
|
const normal = normalAt(targetFace);
|
|
3921
3921
|
const center = faceCenter(targetFace);
|
|
3922
|
-
const scope = _usingCtx$
|
|
3922
|
+
const scope = _usingCtx$7.u(new DisposalScope());
|
|
3923
3923
|
const { wire: w, owned } = toWire(profile);
|
|
3924
3924
|
if (owned) scope.register(w);
|
|
3925
3925
|
const faceResult = makeFace(w);
|
|
@@ -3932,9 +3932,9 @@ function pocket(shape, options) {
|
|
|
3932
3932
|
scope.register(toolResult.value);
|
|
3933
3933
|
return cut$2(s, toolResult.value, { unsafe: true });
|
|
3934
3934
|
} catch (_) {
|
|
3935
|
-
_usingCtx$
|
|
3935
|
+
_usingCtx$7.e = _;
|
|
3936
3936
|
} finally {
|
|
3937
|
-
_usingCtx$
|
|
3937
|
+
_usingCtx$7.d();
|
|
3938
3938
|
}
|
|
3939
3939
|
}
|
|
3940
3940
|
/**
|
|
@@ -4524,12 +4524,12 @@ function makeInternalGearProfileWire(params) {
|
|
|
4524
4524
|
}
|
|
4525
4525
|
function makeProfileWire(params, isInternal) {
|
|
4526
4526
|
try {
|
|
4527
|
-
var _usingCtx$
|
|
4527
|
+
var _usingCtx$6 = _usingCtx();
|
|
4528
4528
|
const { teeth, moduleSize, pressureAngle, shift, clearance, flankThinning, samples = adaptiveSampleCount(moduleSize) } = params;
|
|
4529
4529
|
if (teeth < 4) return err(validationError("GEAR_TEETH_TOO_FEW", `gear needs ≥ 4 teeth, got ${teeth}`));
|
|
4530
4530
|
if (moduleSize <= 0) return err(validationError("GEAR_MODULE_NONPOSITIVE", `module must be > 0, got ${moduleSize}`));
|
|
4531
4531
|
const tm = gearGeometry(teeth, moduleSize, pressureAngle, shift, clearance, flankThinning, isInternal);
|
|
4532
|
-
const scope = _usingCtx$
|
|
4532
|
+
const scope = _usingCtx$6.u(new DisposalScope());
|
|
4533
4533
|
const allEdges = [];
|
|
4534
4534
|
for (let i = 0; i < teeth; i++) {
|
|
4535
4535
|
const periodEdges = buildToothPeriodEdges(tm, i, teeth, samples, scope);
|
|
@@ -4540,9 +4540,9 @@ function makeProfileWire(params, isInternal) {
|
|
|
4540
4540
|
if (isErr(wireResult)) return wireResult;
|
|
4541
4541
|
return ok(wireResult.value);
|
|
4542
4542
|
} catch (_) {
|
|
4543
|
-
_usingCtx$
|
|
4543
|
+
_usingCtx$6.e = _;
|
|
4544
4544
|
} finally {
|
|
4545
|
-
_usingCtx$
|
|
4545
|
+
_usingCtx$6.d();
|
|
4546
4546
|
}
|
|
4547
4547
|
}
|
|
4548
4548
|
//#endregion
|
|
@@ -4723,8 +4723,8 @@ function resolvePlanetaryParams(params) {
|
|
|
4723
4723
|
}
|
|
4724
4724
|
function makeOuterCircleWire(radius) {
|
|
4725
4725
|
try {
|
|
4726
|
-
var _usingCtx$
|
|
4727
|
-
const circleEdge = _usingCtx$
|
|
4726
|
+
var _usingCtx$5 = _usingCtx();
|
|
4727
|
+
const circleEdge = _usingCtx$5.u(new DisposalScope()).register(makeCircle(radius, [
|
|
4728
4728
|
0,
|
|
4729
4729
|
0,
|
|
4730
4730
|
0
|
|
@@ -4737,9 +4737,9 @@ function makeOuterCircleWire(radius) {
|
|
|
4737
4737
|
if (isErr(wireResult)) return wireResult;
|
|
4738
4738
|
return ok(wireResult.value);
|
|
4739
4739
|
} catch (_) {
|
|
4740
|
-
_usingCtx$
|
|
4740
|
+
_usingCtx$5.e = _;
|
|
4741
4741
|
} finally {
|
|
4742
|
-
_usingCtx$
|
|
4742
|
+
_usingCtx$5.d();
|
|
4743
4743
|
}
|
|
4744
4744
|
}
|
|
4745
4745
|
function finalizeExternalSolid(wire, thickness, bore, geom, diagnostics) {
|
|
@@ -5711,6 +5711,22 @@ function extrude$1(profile, vector) {
|
|
|
5711
5711
|
freeParams: depsOf(profile, ve)
|
|
5712
5712
|
};
|
|
5713
5713
|
}
|
|
5714
|
+
/** Sweep a face-producing profile along a Wire/Edge-producing spine.
|
|
5715
|
+
* `frenet` is canonicalized (default false) so the default and explicit
|
|
5716
|
+
* forms share one content address. */
|
|
5717
|
+
function sweep$2(profile, spine, options) {
|
|
5718
|
+
const frenet = options?.frenet ?? false;
|
|
5719
|
+
let h = mix(mix(startHash("Sweep"), profile), spine);
|
|
5720
|
+
h = fnvMixBool(h, frenet);
|
|
5721
|
+
return {
|
|
5722
|
+
kind: "Sweep",
|
|
5723
|
+
profile,
|
|
5724
|
+
spine,
|
|
5725
|
+
frenet,
|
|
5726
|
+
structuralHash: h,
|
|
5727
|
+
freeParams: depsOf(profile, spine)
|
|
5728
|
+
};
|
|
5729
|
+
}
|
|
5714
5730
|
/** Open (or incidentally closed) planar path in the XY plane at z = 0,
|
|
5715
5731
|
* producing a Wire. Segments come from `lineTo`/`arcTo`/`bezierTo`/
|
|
5716
5732
|
* `ellipseArcTo`. */
|
|
@@ -5811,7 +5827,8 @@ function outputKindOf(node) {
|
|
|
5811
5827
|
case "Mirror": return outputKindOf(node.target);
|
|
5812
5828
|
case "Extrude":
|
|
5813
5829
|
case "Revolve":
|
|
5814
|
-
case "Loft":
|
|
5830
|
+
case "Loft":
|
|
5831
|
+
case "Sweep": return "Solid";
|
|
5815
5832
|
case "Path": return "Wire";
|
|
5816
5833
|
case "Compound": return "Compound";
|
|
5817
5834
|
case "Instance": return node.fuse ? "Solid" : "Compound";
|
|
@@ -6140,9 +6157,9 @@ function evalRevolve(node, ctx) {
|
|
|
6140
6157
|
//#region src/csg/evaluators/loft.ts
|
|
6141
6158
|
function evalLoft(node, ctx) {
|
|
6142
6159
|
try {
|
|
6143
|
-
var _usingCtx$
|
|
6160
|
+
var _usingCtx$4 = _usingCtx();
|
|
6144
6161
|
if (node.sections.length < 2) return err(validationError("CSG_LOFT_SECTIONS", `Loft requires at least 2 sections, got ${node.sections.length}`));
|
|
6145
|
-
const scope = _usingCtx$
|
|
6162
|
+
const scope = _usingCtx$4.u(new DisposalScope());
|
|
6146
6163
|
const wires = [];
|
|
6147
6164
|
for (const [i, section] of node.sections.entries()) {
|
|
6148
6165
|
const face = resolveProfileFace(ctx, section, `Loft.sections[${i}]`);
|
|
@@ -6153,9 +6170,9 @@ function evalLoft(node, ctx) {
|
|
|
6153
6170
|
}
|
|
6154
6171
|
return loft$2(wires, { ruled: node.ruled });
|
|
6155
6172
|
} catch (_) {
|
|
6156
|
-
_usingCtx$
|
|
6173
|
+
_usingCtx$4.e = _;
|
|
6157
6174
|
} finally {
|
|
6158
|
-
_usingCtx$
|
|
6175
|
+
_usingCtx$4.d();
|
|
6159
6176
|
}
|
|
6160
6177
|
}
|
|
6161
6178
|
//#endregion
|
|
@@ -6266,14 +6283,14 @@ function ellipseEdge(from, seg, ctx) {
|
|
|
6266
6283
|
if (!arc.ok) return arc;
|
|
6267
6284
|
let edge = arc.value;
|
|
6268
6285
|
if (Math.abs(psi) > EPS) try {
|
|
6269
|
-
var _usingCtx$
|
|
6270
|
-
const rotated = rotateEdgeAbout(_usingCtx$
|
|
6286
|
+
var _usingCtx$3 = _usingCtx();
|
|
6287
|
+
const rotated = rotateEdgeAbout(_usingCtx$3.u(edge), psi * 180 / Math.PI, center);
|
|
6271
6288
|
if (!rotated.ok) return rotated;
|
|
6272
6289
|
edge = rotated.value;
|
|
6273
6290
|
} catch (_) {
|
|
6274
|
-
_usingCtx$
|
|
6291
|
+
_usingCtx$3.e = _;
|
|
6275
6292
|
} finally {
|
|
6276
|
-
_usingCtx$
|
|
6293
|
+
_usingCtx$3.d();
|
|
6277
6294
|
}
|
|
6278
6295
|
if (seg.clockwise) try {
|
|
6279
6296
|
var _usingCtx3 = _usingCtx();
|
|
@@ -6377,6 +6394,39 @@ function evalPath(node, ctx) {
|
|
|
6377
6394
|
}
|
|
6378
6395
|
}
|
|
6379
6396
|
//#endregion
|
|
6397
|
+
//#region src/csg/evaluators/sweep.ts
|
|
6398
|
+
function evalSweep(node, ctx) {
|
|
6399
|
+
try {
|
|
6400
|
+
var _usingCtx$2 = _usingCtx();
|
|
6401
|
+
const face = resolveProfileFace(ctx, node.profile, "Sweep.profile");
|
|
6402
|
+
if (!face.ok) return face;
|
|
6403
|
+
const spineShape = ctx.evalNode(node.spine);
|
|
6404
|
+
if (!spineShape.ok) return spineShape;
|
|
6405
|
+
const scope = _usingCtx$2.u(new DisposalScope());
|
|
6406
|
+
let spine;
|
|
6407
|
+
if (isWire(spineShape.value)) spine = spineShape.value;
|
|
6408
|
+
else if (isEdge(spineShape.value)) {
|
|
6409
|
+
const wrapped = assembleWire([spineShape.value]);
|
|
6410
|
+
if (!wrapped.ok) return wrapped;
|
|
6411
|
+
scope.register(wrapped.value);
|
|
6412
|
+
spine = wrapped.value;
|
|
6413
|
+
} else return err(typeCastError("CSG_SWEEP_SPINE", "Sweep.spine: node did not produce a Wire or Edge"));
|
|
6414
|
+
const profileWire = outerWire(face.value);
|
|
6415
|
+
scope.register(profileWire);
|
|
6416
|
+
const r = sweep$1(profileWire, spine, { frenet: node.frenet });
|
|
6417
|
+
if (!r.ok) return r;
|
|
6418
|
+
if (Array.isArray(r.value)) {
|
|
6419
|
+
for (const s of r.value) s[Symbol.dispose]();
|
|
6420
|
+
return err(typeCastError("CSG_SWEEP_SPINE", "Sweep: unexpected shell-mode result"));
|
|
6421
|
+
}
|
|
6422
|
+
return ok(r.value);
|
|
6423
|
+
} catch (_) {
|
|
6424
|
+
_usingCtx$2.e = _;
|
|
6425
|
+
} finally {
|
|
6426
|
+
_usingCtx$2.d();
|
|
6427
|
+
}
|
|
6428
|
+
}
|
|
6429
|
+
//#endregion
|
|
6380
6430
|
//#region src/csg/evaluate.ts
|
|
6381
6431
|
function dispatch(node, ctx) {
|
|
6382
6432
|
switch (node.kind) {
|
|
@@ -6405,6 +6455,7 @@ function dispatch(node, ctx) {
|
|
|
6405
6455
|
case "Revolve": return evalRevolve(node, ctx);
|
|
6406
6456
|
case "Loft": return evalLoft(node, ctx);
|
|
6407
6457
|
case "Path": return evalPath(node, ctx);
|
|
6458
|
+
case "Sweep": return evalSweep(node, ctx);
|
|
6408
6459
|
}
|
|
6409
6460
|
}
|
|
6410
6461
|
function hashExprValue(h, v) {
|
|
@@ -6811,9 +6862,10 @@ function withEvaluator(options, fn) {
|
|
|
6811
6862
|
_usingCtx$1.d();
|
|
6812
6863
|
}
|
|
6813
6864
|
}
|
|
6865
|
+
var MIN_CSG_VERSION = 1;
|
|
6814
6866
|
function toJSON(node) {
|
|
6815
6867
|
return {
|
|
6816
|
-
csgVersion:
|
|
6868
|
+
csgVersion: 2,
|
|
6817
6869
|
root: nodeToJson(node)
|
|
6818
6870
|
};
|
|
6819
6871
|
}
|
|
@@ -7021,6 +7073,12 @@ function nodeToJson(n) {
|
|
|
7021
7073
|
start: exprToJson(n.start),
|
|
7022
7074
|
segments: n.segments.map(segmentToJson)
|
|
7023
7075
|
};
|
|
7076
|
+
if (n.kind === "Sweep") return {
|
|
7077
|
+
kind: "Sweep",
|
|
7078
|
+
profile: nodeToJson(n.profile),
|
|
7079
|
+
spine: nodeToJson(n.spine),
|
|
7080
|
+
frenet: n.frenet
|
|
7081
|
+
};
|
|
7024
7082
|
if (n.kind === "Compound") return {
|
|
7025
7083
|
kind: "Compound",
|
|
7026
7084
|
children: n.children.map(nodeToJson)
|
|
@@ -7064,7 +7122,7 @@ function readVec2(v, where) {
|
|
|
7064
7122
|
function fromJSON(envelope) {
|
|
7065
7123
|
if (!isObj(envelope)) return bad("input is not an object");
|
|
7066
7124
|
const v = envelope["csgVersion"];
|
|
7067
|
-
if (v !==
|
|
7125
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 2) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..2)`);
|
|
7068
7126
|
const root = envelope["root"];
|
|
7069
7127
|
return readNode(root);
|
|
7070
7128
|
}
|
|
@@ -7176,6 +7234,7 @@ function readNode(j) {
|
|
|
7176
7234
|
case "Revolve": return readRevolve(j);
|
|
7177
7235
|
case "Loft": return readLoft(j);
|
|
7178
7236
|
case "Path": return readPath(j);
|
|
7237
|
+
case "Sweep": return readSweep(j);
|
|
7179
7238
|
default: return bad(`unknown node kind: ${String(kind)}`);
|
|
7180
7239
|
}
|
|
7181
7240
|
}
|
|
@@ -7411,6 +7470,15 @@ function readSegment(j) {
|
|
|
7411
7470
|
default: return bad(`unknown segment kind: ${String(kind)}`);
|
|
7412
7471
|
}
|
|
7413
7472
|
}
|
|
7473
|
+
function readSweep(j) {
|
|
7474
|
+
const profile = readNode(j["profile"]);
|
|
7475
|
+
if (!profile.ok) return profile;
|
|
7476
|
+
const spine = readNode(j["spine"]);
|
|
7477
|
+
if (!spine.ok) return spine;
|
|
7478
|
+
const frenet = readFlag(j, "frenet");
|
|
7479
|
+
if (!frenet.ok) return frenet;
|
|
7480
|
+
return ok(sweep$2(profile.value, spine.value, { frenet: frenet.value }));
|
|
7481
|
+
}
|
|
7414
7482
|
function readPath(j) {
|
|
7415
7483
|
const start = readExpr(j["start"]);
|
|
7416
7484
|
if (!start.ok) return start;
|
|
@@ -7538,6 +7606,7 @@ function optimizeNode(n) {
|
|
|
7538
7606
|
case "Extrude":
|
|
7539
7607
|
case "Revolve":
|
|
7540
7608
|
case "Loft":
|
|
7609
|
+
case "Sweep":
|
|
7541
7610
|
case "Path": return optimizeFeature(n);
|
|
7542
7611
|
}
|
|
7543
7612
|
}
|
|
@@ -7549,6 +7618,7 @@ function optimizeFeature(n) {
|
|
|
7549
7618
|
at: n.at ? foldExpr(n.at) : void 0
|
|
7550
7619
|
});
|
|
7551
7620
|
case "Loft": return loft$1(n.sections.map(optimizeNode), { ruled: n.ruled });
|
|
7621
|
+
case "Sweep": return sweep$2(optimizeNode(n.profile), optimizeNode(n.spine), { frenet: n.frenet });
|
|
7552
7622
|
case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
|
|
7553
7623
|
}
|
|
7554
7624
|
}
|
|
@@ -7647,6 +7717,7 @@ function rebuildChildren(n, pred, repl) {
|
|
|
7647
7717
|
at: n.at
|
|
7648
7718
|
});
|
|
7649
7719
|
case "Loft": return loft$1(n.sections.map((s) => walk(s, pred, repl)), { ruled: n.ruled });
|
|
7720
|
+
case "Sweep": return sweep$2(walk(n.profile, pred, repl), walk(n.spine, pred, repl), { frenet: n.frenet });
|
|
7650
7721
|
}
|
|
7651
7722
|
}
|
|
7652
7723
|
function forEachNode(root, fn) {
|
|
@@ -7680,6 +7751,7 @@ function childrenOf(n) {
|
|
|
7680
7751
|
case "Extrude":
|
|
7681
7752
|
case "Revolve": return [n.profile];
|
|
7682
7753
|
case "Loft": return n.sections;
|
|
7754
|
+
case "Sweep": return [n.profile, n.spine];
|
|
7683
7755
|
}
|
|
7684
7756
|
}
|
|
7685
7757
|
function nodeCount(root) {
|
|
@@ -7692,7 +7764,7 @@ function nodeCount(root) {
|
|
|
7692
7764
|
//#endregion
|
|
7693
7765
|
//#region src/ns/csg.ts
|
|
7694
7766
|
var csg_exports = /* @__PURE__ */ __exportAll({
|
|
7695
|
-
CSG_VERSION: () =>
|
|
7767
|
+
CSG_VERSION: () => 2,
|
|
7696
7768
|
Evaluator: () => Evaluator,
|
|
7697
7769
|
add: () => add,
|
|
7698
7770
|
arcTo: () => arcTo,
|
|
@@ -7739,6 +7811,7 @@ var csg_exports = /* @__PURE__ */ __exportAll({
|
|
|
7739
7811
|
rotate: () => rotate$1,
|
|
7740
7812
|
scale: () => scale$1,
|
|
7741
7813
|
sphere: () => sphere$2,
|
|
7814
|
+
sweep: () => sweep$2,
|
|
7742
7815
|
toJSON: () => toJSON,
|
|
7743
7816
|
torus: () => torus$2,
|
|
7744
7817
|
translate: () => translate$1,
|
package/dist/csg/builders.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ScalarInput, Vec2Input, Vec3Input } from './expressions.js';
|
|
2
2
|
import { Segment2D } from './segments.js';
|
|
3
3
|
import { Matrix4x4 } from '../core/types.js';
|
|
4
|
-
import { BoxNode, SphereNode, CylinderNode, ConeNode, TorusNode, PolygonNode, CircleNode, LineNode, VertexLitNode, EmptyNode, FuseNode, CutNode, IntersectNode, FuseAllNode, CutAllNode, TranslateNode, RotateNode, ScaleNode, MirrorNode, ExtrudeNode, RevolveNode, LoftNode, PathNode, CompoundNode, InstanceNode, IRNode, SolidNode, FaceNode, EdgeNode, VertexNode } from './types.js';
|
|
4
|
+
import { BoxNode, SphereNode, CylinderNode, ConeNode, TorusNode, PolygonNode, CircleNode, LineNode, VertexLitNode, EmptyNode, FuseNode, CutNode, IntersectNode, FuseAllNode, CutAllNode, TranslateNode, RotateNode, ScaleNode, MirrorNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, PathNode, CompoundNode, InstanceNode, IRNode, SolidNode, FaceNode, EdgeNode, VertexNode } from './types.js';
|
|
5
5
|
export declare function box(x: ScalarInput, y: ScalarInput, z: ScalarInput): BoxNode;
|
|
6
6
|
export declare function sphere(radius: ScalarInput): SphereNode;
|
|
7
7
|
export declare function cylinder(radius: ScalarInput, height: ScalarInput): CylinderNode;
|
|
@@ -35,6 +35,13 @@ export interface MirrorOptions {
|
|
|
35
35
|
}
|
|
36
36
|
export declare function mirror(target: IRNode, options?: MirrorOptions): MirrorNode;
|
|
37
37
|
export declare function extrude(profile: FaceNode, vector: Vec3Input): ExtrudeNode;
|
|
38
|
+
export interface SweepNodeOptions {
|
|
39
|
+
readonly frenet?: boolean | undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Sweep a face-producing profile along a Wire/Edge-producing spine.
|
|
42
|
+
* `frenet` is canonicalized (default false) so the default and explicit
|
|
43
|
+
* forms share one content address. */
|
|
44
|
+
export declare function sweep(profile: FaceNode, spine: IRNode, options?: SweepNodeOptions): SweepNode;
|
|
38
45
|
/** Open (or incidentally closed) planar path in the XY plane at z = 0,
|
|
39
46
|
* producing a Wire. Segments come from `lineTo`/`arcTo`/`bezierTo`/
|
|
40
47
|
* `ellipseArcTo`. */
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Result } from '../../core/result.js';
|
|
2
|
+
import { AnyShape, Dimension } from '../../core/shapeTypes.js';
|
|
3
|
+
import { SweepNode } from '../types.js';
|
|
4
|
+
import { EvalContext } from './context.js';
|
|
5
|
+
export declare function evalSweep(node: SweepNode, ctx: EvalContext): Result<AnyShape<Dimension>>;
|
package/dist/csg/index.d.ts
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* parameterize via named expression bindings; evaluate against the active
|
|
6
6
|
* kernel with subtree-level cache reuse for incremental parametric edits.
|
|
7
7
|
*/
|
|
8
|
-
export { box, sphere, cylinder, cone, torus, polygon, circle, line, vertex, emptySolid, emptyFace, emptyWire, fuse, cut, intersect, fuseAll, cutAll, translate, rotate, scale, mirror, extrude, revolve, loft, path, compound, instance, type RevolveOptions, type LoftOptions, type RotateOptions, type ScaleOptions, type MirrorOptions, } from './builders.js';
|
|
8
|
+
export { box, sphere, cylinder, cone, torus, polygon, circle, line, vertex, emptySolid, emptyFace, emptyWire, fuse, cut, intersect, fuseAll, cutAll, translate, rotate, scale, mirror, extrude, revolve, loft, sweep, path, compound, instance, type RevolveOptions, type LoftOptions, type SweepNodeOptions, type RotateOptions, type ScaleOptions, type MirrorOptions, } from './builders.js';
|
|
9
9
|
export { numLit, vec3Lit, vec2Lit, param, binOp, unaryOp, component, buildVec, add, mul, asScalarExpr, asVec3Expr, asVec2Expr, type Expr, type ExprValue, type Env, type ScalarInput, type Vec3Input, type Vec2Input, type BinaryOp, type UnaryOp, } from './expressions.js';
|
|
10
|
-
export type { IRNode, NodeKind, OutputKind, PrimitiveNode, BooleanNode, TransformIRNode, ExtrudeNode, RevolveNode, LoftNode, PathNode, InstanceNode, SolidNode, FaceNode, EdgeNode, VertexNode, AnyNode, } from './types.js';
|
|
10
|
+
export type { IRNode, NodeKind, OutputKind, PrimitiveNode, BooleanNode, TransformIRNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, PathNode, InstanceNode, SolidNode, FaceNode, EdgeNode, VertexNode, AnyNode, } from './types.js';
|
|
11
11
|
export { outputKindOf } from './types.js';
|
|
12
12
|
export { lineTo, arcTo, bezierTo, ellipseArcTo, type Segment2D, type SegmentOptions, type EllipseArcOptions, } from './segments.js';
|
|
13
13
|
export { Evaluator, withEvaluator, type EvaluatorOptions, type StepInfo, type CacheStats, } from './evaluate.js';
|
package/dist/csg/serialize.d.ts
CHANGED
package/dist/csg/types.d.ts
CHANGED
|
@@ -124,6 +124,15 @@ export interface RevolveNode extends IRNodeBase {
|
|
|
124
124
|
readonly axis?: Expr | undefined;
|
|
125
125
|
readonly at?: Expr | undefined;
|
|
126
126
|
}
|
|
127
|
+
export interface SweepNode extends IRNodeBase {
|
|
128
|
+
readonly kind: 'Sweep';
|
|
129
|
+
/** Must produce OutputKind 'Face'. */
|
|
130
|
+
readonly profile: IRNode;
|
|
131
|
+
/** Must produce OutputKind 'Wire' or 'Edge' (Line, Circle, Path). */
|
|
132
|
+
readonly spine: IRNode;
|
|
133
|
+
/** Canonicalized by the builder (default false). */
|
|
134
|
+
readonly frenet: boolean;
|
|
135
|
+
}
|
|
127
136
|
export interface PathNode extends IRNodeBase {
|
|
128
137
|
readonly kind: 'Path';
|
|
129
138
|
/** Vec2 start point; the path lies in the XY plane (z = 0) and is lifted
|
|
@@ -154,7 +163,7 @@ export interface InstanceNode extends IRNodeBase {
|
|
|
154
163
|
export type PrimitiveNode = BoxNode | SphereNode | CylinderNode | ConeNode | TorusNode | PolygonNode | CircleNode | LineNode | VertexLitNode | EmptyNode;
|
|
155
164
|
export type BooleanNode = FuseNode | CutNode | IntersectNode | FuseAllNode | CutAllNode;
|
|
156
165
|
export type TransformIRNode = TranslateNode | RotateNode | ScaleNode | MirrorNode;
|
|
157
|
-
export type IRNode = PrimitiveNode | BooleanNode | TransformIRNode | ExtrudeNode | RevolveNode | LoftNode | PathNode | CompoundNode | InstanceNode;
|
|
166
|
+
export type IRNode = PrimitiveNode | BooleanNode | TransformIRNode | ExtrudeNode | RevolveNode | LoftNode | SweepNode | PathNode | CompoundNode | InstanceNode;
|
|
158
167
|
export type NodeKind = IRNode['kind'];
|
|
159
168
|
export type AnyNode = IRNode;
|
|
160
169
|
/** Nodes that produce a 3D solid. */
|