brepjs 18.131.0 → 18.133.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 +117 -37
- package/dist/brepjs.js +119 -39
- package/dist/csg/builders.d.ts +4 -5
- package/dist/csg/evaluators/chamfer.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 +8 -1
- package/package.json +1 -1
package/dist/brepjs.cjs
CHANGED
|
@@ -1809,8 +1809,8 @@ function hashEdgeRef(h0, ref) {
|
|
|
1809
1809
|
* serializable node data (the cache key stays purely structural); it
|
|
1810
1810
|
* resolves against the materialized target at evaluation, so an upstream
|
|
1811
1811
|
* parameter edit re-targets the same edge by its face roles. */
|
|
1812
|
-
function
|
|
1813
|
-
|
|
1812
|
+
function copyEdgeRef(ref) {
|
|
1813
|
+
return {
|
|
1814
1814
|
origin: ref.origin,
|
|
1815
1815
|
faceRoles: [ref.faceRoles[0], ref.faceRoles[1]],
|
|
1816
1816
|
hint: {
|
|
@@ -1819,6 +1819,9 @@ function fillet$1(target, ref, radius) {
|
|
|
1819
1819
|
midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
|
|
1820
1820
|
}
|
|
1821
1821
|
};
|
|
1822
|
+
}
|
|
1823
|
+
function fillet$1(target, ref, radius) {
|
|
1824
|
+
const copied = copyEdgeRef(ref);
|
|
1822
1825
|
const re = asScalarExpr(radius);
|
|
1823
1826
|
let h = mix(startHash("Fillet"), target);
|
|
1824
1827
|
h = hashEdgeRef(h, copied);
|
|
@@ -1832,6 +1835,23 @@ function fillet$1(target, ref, radius) {
|
|
|
1832
1835
|
freeParams: depsOf(target, re)
|
|
1833
1836
|
};
|
|
1834
1837
|
}
|
|
1838
|
+
/** Chamfer the edge named by a lineage ref on the evaluated target. Same
|
|
1839
|
+
* contract as `fillet`: the ref is deep-copied, serializable node data. */
|
|
1840
|
+
function chamfer$1(target, ref, distance) {
|
|
1841
|
+
const copied = copyEdgeRef(ref);
|
|
1842
|
+
const de = asScalarExpr(distance);
|
|
1843
|
+
let h = mix(startHash("Chamfer"), target);
|
|
1844
|
+
h = hashEdgeRef(h, copied);
|
|
1845
|
+
h = mix(h, de);
|
|
1846
|
+
return {
|
|
1847
|
+
kind: "Chamfer",
|
|
1848
|
+
target,
|
|
1849
|
+
ref: copied,
|
|
1850
|
+
distance: de,
|
|
1851
|
+
structuralHash: h,
|
|
1852
|
+
freeParams: depsOf(target, de)
|
|
1853
|
+
};
|
|
1854
|
+
}
|
|
1835
1855
|
/** Attach a color (hex string or RGB/RGBA tuple, canonicalized to RGBA) to
|
|
1836
1856
|
* the evaluated result of `target`. Metadata rides beside the geometry: the
|
|
1837
1857
|
* evaluator re-tags the shared target materialization with an independent
|
|
@@ -1984,7 +2004,8 @@ function outputKindOf(node) {
|
|
|
1984
2004
|
case "Revolve":
|
|
1985
2005
|
case "Loft":
|
|
1986
2006
|
case "Sweep":
|
|
1987
|
-
case "Fillet":
|
|
2007
|
+
case "Fillet":
|
|
2008
|
+
case "Chamfer": return "Solid";
|
|
1988
2009
|
case "Profile": return "Face";
|
|
1989
2010
|
case "Path": return "Wire";
|
|
1990
2011
|
case "Compound": return "Compound";
|
|
@@ -2634,7 +2655,7 @@ function evalExtrude(node, ctx) {
|
|
|
2634
2655
|
function evalRevolve(node, ctx) {
|
|
2635
2656
|
const a = evalScalar(node.angle, ctx.env, "Revolve.angle");
|
|
2636
2657
|
if (!a.ok) return a;
|
|
2637
|
-
if (a.value <= 0) return require_errors.err(require_errors.validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
|
|
2658
|
+
if (!Number.isFinite(a.value) || a.value <= 0) return require_errors.err(require_errors.validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
|
|
2638
2659
|
const deg = Math.min(a.value, 360);
|
|
2639
2660
|
const axis = node.axis ? evalVec3(node.axis, ctx.env, "Revolve.axis") : require_errors.ok([
|
|
2640
2661
|
0,
|
|
@@ -2995,7 +3016,7 @@ function evalColor(node, ctx) {
|
|
|
2995
3016
|
function evalFillet(node, ctx) {
|
|
2996
3017
|
const radius = evalScalar(node.radius, ctx.env, "Fillet.radius");
|
|
2997
3018
|
if (!radius.ok) return radius;
|
|
2998
|
-
if (radius.value <= 0) return require_errors.err(require_errors.validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
|
|
3019
|
+
if (!Number.isFinite(radius.value) || radius.value <= 0) return require_errors.err(require_errors.validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
|
|
2999
3020
|
const t = ctx.evalNode(node.target);
|
|
3000
3021
|
if (!t.ok) return t;
|
|
3001
3022
|
if (!require_shapeTypes.isSolid(t.value)) return require_errors.err(require_errors.validationError("CSG_FILLET_TARGET", "Fillet.target did not produce a Solid"));
|
|
@@ -3007,6 +3028,22 @@ function evalFillet(node, ctx) {
|
|
|
3007
3028
|
return require_healingFns.fillet(solid.value, [resolved.entity], radius.value);
|
|
3008
3029
|
}
|
|
3009
3030
|
//#endregion
|
|
3031
|
+
//#region src/csg/evaluators/chamfer.ts
|
|
3032
|
+
function evalChamfer(node, ctx) {
|
|
3033
|
+
const distance = evalScalar(node.distance, ctx.env, "Chamfer.distance");
|
|
3034
|
+
if (!distance.ok) return distance;
|
|
3035
|
+
if (!Number.isFinite(distance.value) || distance.value <= 0) return require_errors.err(require_errors.validationError("CSG_CHAMFER_DISTANCE", `Chamfer.distance must be positive, got ${distance.value}`));
|
|
3036
|
+
const t = ctx.evalNode(node.target);
|
|
3037
|
+
if (!t.ok) return t;
|
|
3038
|
+
if (!require_shapeTypes.isSolid(t.value)) return require_errors.err(require_errors.validationError("CSG_CHAMFER_TARGET", "Chamfer.target did not produce a Solid"));
|
|
3039
|
+
const solid = require_validityTypes.validSolid(t.value);
|
|
3040
|
+
if (!solid.ok) return require_errors.err(require_errors.validationError("CSG_CHAMFER_TARGET", solid.error));
|
|
3041
|
+
const resolved = require_refResolveFns.resolveRefIn(node.ref, t.value);
|
|
3042
|
+
if (!resolved.ok) return require_errors.err(require_errors.validationError("CSG_CHAMFER_REF", `Chamfer.ref did not resolve: ${resolved.reason}`));
|
|
3043
|
+
if (!require_shapeTypes.isEdge(resolved.entity)) return require_errors.err(require_errors.validationError("CSG_CHAMFER_REF", "Chamfer.ref resolved to a non-edge"));
|
|
3044
|
+
return require_healingFns.chamfer(solid.value, [resolved.entity], distance.value);
|
|
3045
|
+
}
|
|
3046
|
+
//#endregion
|
|
3010
3047
|
//#region src/csg/evaluate.ts
|
|
3011
3048
|
function dispatch(node, ctx) {
|
|
3012
3049
|
switch (node.kind) {
|
|
@@ -3031,6 +3068,19 @@ function dispatch(node, ctx) {
|
|
|
3031
3068
|
case "Mirror": return evalMirror(node, ctx);
|
|
3032
3069
|
case "Compound": return evalCompound(node, ctx);
|
|
3033
3070
|
case "Instance": return evalInstance(node, ctx);
|
|
3071
|
+
case "Extrude":
|
|
3072
|
+
case "Revolve":
|
|
3073
|
+
case "Loft":
|
|
3074
|
+
case "Path":
|
|
3075
|
+
case "Sweep":
|
|
3076
|
+
case "Profile":
|
|
3077
|
+
case "Color":
|
|
3078
|
+
case "Fillet":
|
|
3079
|
+
case "Chamfer": return dispatchFeature(node, ctx);
|
|
3080
|
+
}
|
|
3081
|
+
}
|
|
3082
|
+
function dispatchFeature(node, ctx) {
|
|
3083
|
+
switch (node.kind) {
|
|
3034
3084
|
case "Extrude": return evalExtrude(node, ctx);
|
|
3035
3085
|
case "Revolve": return evalRevolve(node, ctx);
|
|
3036
3086
|
case "Loft": return evalLoft(node, ctx);
|
|
@@ -3039,6 +3089,7 @@ function dispatch(node, ctx) {
|
|
|
3039
3089
|
case "Profile": return evalProfile(node, ctx);
|
|
3040
3090
|
case "Color": return evalColor(node, ctx);
|
|
3041
3091
|
case "Fillet": return evalFillet(node, ctx);
|
|
3092
|
+
case "Chamfer": return evalChamfer(node, ctx);
|
|
3042
3093
|
}
|
|
3043
3094
|
}
|
|
3044
3095
|
function hashExprValue(h, v) {
|
|
@@ -3448,7 +3499,7 @@ function withEvaluator(options, fn) {
|
|
|
3448
3499
|
var MIN_CSG_VERSION = 1;
|
|
3449
3500
|
function toJSON(node) {
|
|
3450
3501
|
return {
|
|
3451
|
-
csgVersion:
|
|
3502
|
+
csgVersion: 6,
|
|
3452
3503
|
root: nodeToJson(node)
|
|
3453
3504
|
};
|
|
3454
3505
|
}
|
|
@@ -3604,6 +3655,17 @@ function segmentToJson(s) {
|
|
|
3604
3655
|
};
|
|
3605
3656
|
}
|
|
3606
3657
|
}
|
|
3658
|
+
function edgeRefToJson(ref) {
|
|
3659
|
+
return {
|
|
3660
|
+
origin: ref.origin,
|
|
3661
|
+
faceRoles: [...ref.faceRoles],
|
|
3662
|
+
hint: {
|
|
3663
|
+
entityType: "edge",
|
|
3664
|
+
length: ref.hint.length,
|
|
3665
|
+
midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
|
|
3666
|
+
}
|
|
3667
|
+
};
|
|
3668
|
+
}
|
|
3607
3669
|
function contourToJson(c) {
|
|
3608
3670
|
return {
|
|
3609
3671
|
start: exprToJson(c.start),
|
|
@@ -3681,17 +3743,15 @@ function nodeToJson(n) {
|
|
|
3681
3743
|
if (n.kind === "Fillet") return {
|
|
3682
3744
|
kind: "Fillet",
|
|
3683
3745
|
target: nodeToJson(n.target),
|
|
3684
|
-
ref:
|
|
3685
|
-
origin: n.ref.origin,
|
|
3686
|
-
faceRoles: [...n.ref.faceRoles],
|
|
3687
|
-
hint: {
|
|
3688
|
-
entityType: "edge",
|
|
3689
|
-
length: n.ref.hint.length,
|
|
3690
|
-
midpoint: n.ref.hint.midpoint ? [...n.ref.hint.midpoint] : void 0
|
|
3691
|
-
}
|
|
3692
|
-
},
|
|
3746
|
+
ref: edgeRefToJson(n.ref),
|
|
3693
3747
|
radius: exprToJson(n.radius)
|
|
3694
3748
|
};
|
|
3749
|
+
if (n.kind === "Chamfer") return {
|
|
3750
|
+
kind: "Chamfer",
|
|
3751
|
+
target: nodeToJson(n.target),
|
|
3752
|
+
ref: edgeRefToJson(n.ref),
|
|
3753
|
+
distance: exprToJson(n.distance)
|
|
3754
|
+
};
|
|
3695
3755
|
if (n.kind === "Compound") return {
|
|
3696
3756
|
kind: "Compound",
|
|
3697
3757
|
children: n.children.map(nodeToJson)
|
|
@@ -3735,7 +3795,7 @@ function readVec2(v, where) {
|
|
|
3735
3795
|
function fromJSON(envelope) {
|
|
3736
3796
|
if (!isObj(envelope)) return bad("input is not an object");
|
|
3737
3797
|
const v = envelope["csgVersion"];
|
|
3738
|
-
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v >
|
|
3798
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 6) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..6)`);
|
|
3739
3799
|
const root = envelope["root"];
|
|
3740
3800
|
return readNode(root);
|
|
3741
3801
|
}
|
|
@@ -3851,6 +3911,7 @@ function readNode(j) {
|
|
|
3851
3911
|
case "Profile": return readProfile(j);
|
|
3852
3912
|
case "Color": return readColor(j);
|
|
3853
3913
|
case "Fillet": return readFillet(j);
|
|
3914
|
+
case "Chamfer": return readChamfer(j);
|
|
3854
3915
|
default: return bad(`unknown node kind: ${String(kind)}`);
|
|
3855
3916
|
}
|
|
3856
3917
|
}
|
|
@@ -4100,28 +4161,23 @@ function readContour(j, where) {
|
|
|
4100
4161
|
}
|
|
4101
4162
|
return require_errors.ok(contour(start.value, segments));
|
|
4102
4163
|
}
|
|
4103
|
-
function
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
if (!isString(origin)) return bad("Fillet.ref.origin: not a string");
|
|
4112
|
-
const roles = ref["faceRoles"];
|
|
4113
|
-
if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad("Fillet.ref.faceRoles: expected two role strings");
|
|
4114
|
-
const hintRaw = ref["hint"];
|
|
4115
|
-
if (!isObj(hintRaw)) return bad("Fillet.ref.hint: not an object");
|
|
4164
|
+
function readEdgeRef(j, where) {
|
|
4165
|
+
if (!isObj(j)) return bad(`${where}: not an object`);
|
|
4166
|
+
const origin = j["origin"];
|
|
4167
|
+
if (!isString(origin)) return bad(`${where}.origin: not a string`);
|
|
4168
|
+
const roles = j["faceRoles"];
|
|
4169
|
+
if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad(`${where}.faceRoles: expected two role strings`);
|
|
4170
|
+
const hintRaw = j["hint"];
|
|
4171
|
+
if (!isObj(hintRaw)) return bad(`${where}.hint: not an object`);
|
|
4116
4172
|
const length = hintRaw["length"];
|
|
4117
|
-
if (length !== void 0 && !isNumber$1(length)) return bad(
|
|
4173
|
+
if (length !== void 0 && !isNumber$1(length)) return bad(`${where}.hint.length`);
|
|
4118
4174
|
let midpoint;
|
|
4119
4175
|
if (hintRaw["midpoint"] !== void 0) {
|
|
4120
|
-
const m = readVec3(hintRaw["midpoint"],
|
|
4176
|
+
const m = readVec3(hintRaw["midpoint"], `${where}.hint.midpoint`);
|
|
4121
4177
|
if (!m.ok) return m;
|
|
4122
4178
|
midpoint = m.value;
|
|
4123
4179
|
}
|
|
4124
|
-
return require_errors.ok(
|
|
4180
|
+
return require_errors.ok({
|
|
4125
4181
|
origin,
|
|
4126
4182
|
faceRoles: [roles[0], roles[1]],
|
|
4127
4183
|
hint: {
|
|
@@ -4129,7 +4185,25 @@ function readFillet(j) {
|
|
|
4129
4185
|
length,
|
|
4130
4186
|
midpoint
|
|
4131
4187
|
}
|
|
4132
|
-
}
|
|
4188
|
+
});
|
|
4189
|
+
}
|
|
4190
|
+
function readFillet(j) {
|
|
4191
|
+
const target = readNode(j["target"]);
|
|
4192
|
+
if (!target.ok) return target;
|
|
4193
|
+
const radius = readExpr(j["radius"]);
|
|
4194
|
+
if (!radius.ok) return radius;
|
|
4195
|
+
const ref = readEdgeRef(j["ref"], "Fillet.ref");
|
|
4196
|
+
if (!ref.ok) return ref;
|
|
4197
|
+
return require_errors.ok(fillet$1(target.value, ref.value, radius.value));
|
|
4198
|
+
}
|
|
4199
|
+
function readChamfer(j) {
|
|
4200
|
+
const target = readNode(j["target"]);
|
|
4201
|
+
if (!target.ok) return target;
|
|
4202
|
+
const distance = readExpr(j["distance"]);
|
|
4203
|
+
if (!distance.ok) return distance;
|
|
4204
|
+
const ref = readEdgeRef(j["ref"], "Chamfer.ref");
|
|
4205
|
+
if (!ref.ok) return ref;
|
|
4206
|
+
return require_errors.ok(chamfer$1(target.value, ref.value, distance.value));
|
|
4133
4207
|
}
|
|
4134
4208
|
function readColor(j) {
|
|
4135
4209
|
const target = readNode(j["target"]);
|
|
@@ -4290,7 +4364,8 @@ function optimizeNode(n) {
|
|
|
4290
4364
|
case "Profile":
|
|
4291
4365
|
case "Path":
|
|
4292
4366
|
case "Color":
|
|
4293
|
-
case "Fillet":
|
|
4367
|
+
case "Fillet":
|
|
4368
|
+
case "Chamfer": return optimizeFeature(n);
|
|
4294
4369
|
}
|
|
4295
4370
|
}
|
|
4296
4371
|
function optimizeFeature(n) {
|
|
@@ -4306,6 +4381,7 @@ function optimizeFeature(n) {
|
|
|
4306
4381
|
case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
|
|
4307
4382
|
case "Color": return color(optimizeNode(n.target), [...n.color]);
|
|
4308
4383
|
case "Fillet": return fillet$1(optimizeNode(n.target), n.ref, foldExpr(n.radius));
|
|
4384
|
+
case "Chamfer": return chamfer$1(optimizeNode(n.target), n.ref, foldExpr(n.distance));
|
|
4309
4385
|
}
|
|
4310
4386
|
}
|
|
4311
4387
|
function optimizeTransform(n) {
|
|
@@ -4416,7 +4492,8 @@ function rebuildChildren(n, pred, repl) {
|
|
|
4416
4492
|
case "Loft":
|
|
4417
4493
|
case "Sweep":
|
|
4418
4494
|
case "Color":
|
|
4419
|
-
case "Fillet":
|
|
4495
|
+
case "Fillet":
|
|
4496
|
+
case "Chamfer": return rebuildFeature(n, pred, repl);
|
|
4420
4497
|
}
|
|
4421
4498
|
}
|
|
4422
4499
|
function rebuildFeature(n, pred, repl) {
|
|
@@ -4430,6 +4507,7 @@ function rebuildFeature(n, pred, repl) {
|
|
|
4430
4507
|
case "Sweep": return sweep$2(walk(n.profile, pred, repl), walk(n.spine, pred, repl), { frenet: n.frenet });
|
|
4431
4508
|
case "Color": return color(walk(n.target, pred, repl), [...n.color]);
|
|
4432
4509
|
case "Fillet": return fillet$1(walk(n.target, pred, repl), n.ref, n.radius);
|
|
4510
|
+
case "Chamfer": return chamfer$1(walk(n.target, pred, repl), n.ref, n.distance);
|
|
4433
4511
|
}
|
|
4434
4512
|
}
|
|
4435
4513
|
function forEachNode(root, fn) {
|
|
@@ -4460,7 +4538,8 @@ function childrenOf(n) {
|
|
|
4460
4538
|
case "Scale":
|
|
4461
4539
|
case "Mirror":
|
|
4462
4540
|
case "Color":
|
|
4463
|
-
case "Fillet":
|
|
4541
|
+
case "Fillet":
|
|
4542
|
+
case "Chamfer": return [n.target];
|
|
4464
4543
|
case "Compound": return n.children;
|
|
4465
4544
|
case "Instance": return [n.source];
|
|
4466
4545
|
case "Extrude":
|
|
@@ -8471,7 +8550,7 @@ var patterns_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
|
8471
8550
|
//#endregion
|
|
8472
8551
|
//#region src/ns/csg.ts
|
|
8473
8552
|
var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
8474
|
-
CSG_VERSION: () =>
|
|
8553
|
+
CSG_VERSION: () => 6,
|
|
8475
8554
|
Evaluator: () => Evaluator,
|
|
8476
8555
|
add: () => add$1,
|
|
8477
8556
|
arbitraryClosedProfile: () => arbitraryClosedProfile,
|
|
@@ -8486,6 +8565,7 @@ var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
|
8486
8565
|
box: () => box$2,
|
|
8487
8566
|
buildVec: () => buildVec,
|
|
8488
8567
|
cShapeProfile: () => cShapeProfile,
|
|
8568
|
+
chamfer: () => chamfer$1,
|
|
8489
8569
|
circle: () => circle$1,
|
|
8490
8570
|
circleHollowProfile: () => circleHollowProfile,
|
|
8491
8571
|
circularProfile: () => circularProfile,
|
package/dist/brepjs.js
CHANGED
|
@@ -17,7 +17,7 @@ import { a as curveIsPeriodic, c as curvePointAt, d as flipOrientation, f as get
|
|
|
17
17
|
import { a as meshEdges$1, c as meshMultiLOD, d as createMeshCache, i as mesh$1, l as buildMeshCacheKey, n as exportSTEP, o as meshLODs, r as exportSTL, s as meshLODsProgressive, t as exportIGES, u as clearMeshCache } from "./meshFns-CpfeEN1b.js";
|
|
18
18
|
import { n as getAtOrThrow, r as lastOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
|
|
19
19
|
import { _ as makeThreePointArc, d as makeCircle, h as makeLine, l as makeBSplineInterpolation, n as fill, p as makeEllipseArc, r as makeFace, s as assembleWire, u as makeBezierCurve } from "./surfaceBuilders-B7WlmoVr.js";
|
|
20
|
-
import { A as toBufferGeometryData, C as chamfer$
|
|
20
|
+
import { A as toBufferGeometryData, C as chamfer$2, D as shell$1, E as offset$1, M as toLODGeometryData, N as toLODGeometryLevels, O as thicken$1, P as toLineGeometryData, S as chamferDistAngle, T as fillet$2, _ as checkBoolean, a as healFace, b as getNurbsCurveData, c as isValid$1, d as chamferWithEvolution, f as cutWithEvolution, g as shellWithEvolution, h as intersectWithEvolution, i as heal$1, j as toGroupedBufferGeometryData, k as variableFillet, l as solidFromShell, m as fuseWithEvolution, n as fixSelfIntersection, o as healSolid, p as filletWithEvolution, r as fixShape, s as healWire, t as autoHeal, u as positionOnCurve, v as cutAllBisect, w as draft$1, x as getNurbsSurfaceData, y as fuseAllBisect } from "./healingFns-BrrTpxjI.js";
|
|
21
21
|
import { A as setJointValue, B as walkAssembly, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as countNodes, G as quatFromAxisAngle, H as circularPattern, I as createAssemblyNode, J as quatRotate, K as quatFromTo, L as findNode, M as sphericalJoint, N as addChild, O as prismaticJoint, P as collectShapes, R as removeChild, S as addJoint, T as jointTransform, U as gridPattern, V as exportAssemblySTEP, W as linearPattern, Y as createAssembly, _ as exportURDF, a as deserializeHistory, b as inverseKinematics, c as modifyStep, d as replayFrom, f as replayHistory, g as undoLast, h as stepsFrom, i as createRegistry, j as setJointValues, k as revoluteJoint, l as registerOperation, m as stepCount, n as addStep, o as findStep, p as serializeHistory, q as quatMultiply, r as createHistory, s as getShape, t as thread, u as registerShape, v as importURDF, w as forwardKinematics, x as jointTrajectory, y as jointsFromDH, z as updateNode } from "./threadFns-B6-3UeCZ.js";
|
|
22
22
|
import { n as BaseSketcher2d, r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-yZiAeqft.js";
|
|
23
23
|
import { a as createTypedFinder, i as wireFinder, n as edgeFinder, r as faceFinder, t as getSingleFace } from "./helpers-BiqV-wPK.js";
|
|
@@ -1819,8 +1819,8 @@ function hashEdgeRef(h0, ref) {
|
|
|
1819
1819
|
* serializable node data (the cache key stays purely structural); it
|
|
1820
1820
|
* resolves against the materialized target at evaluation, so an upstream
|
|
1821
1821
|
* parameter edit re-targets the same edge by its face roles. */
|
|
1822
|
-
function
|
|
1823
|
-
|
|
1822
|
+
function copyEdgeRef(ref) {
|
|
1823
|
+
return {
|
|
1824
1824
|
origin: ref.origin,
|
|
1825
1825
|
faceRoles: [ref.faceRoles[0], ref.faceRoles[1]],
|
|
1826
1826
|
hint: {
|
|
@@ -1829,6 +1829,9 @@ function fillet$1(target, ref, radius) {
|
|
|
1829
1829
|
midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
|
|
1830
1830
|
}
|
|
1831
1831
|
};
|
|
1832
|
+
}
|
|
1833
|
+
function fillet$1(target, ref, radius) {
|
|
1834
|
+
const copied = copyEdgeRef(ref);
|
|
1832
1835
|
const re = asScalarExpr(radius);
|
|
1833
1836
|
let h = mix(startHash("Fillet"), target);
|
|
1834
1837
|
h = hashEdgeRef(h, copied);
|
|
@@ -1842,6 +1845,23 @@ function fillet$1(target, ref, radius) {
|
|
|
1842
1845
|
freeParams: depsOf(target, re)
|
|
1843
1846
|
};
|
|
1844
1847
|
}
|
|
1848
|
+
/** Chamfer the edge named by a lineage ref on the evaluated target. Same
|
|
1849
|
+
* contract as `fillet`: the ref is deep-copied, serializable node data. */
|
|
1850
|
+
function chamfer$1(target, ref, distance) {
|
|
1851
|
+
const copied = copyEdgeRef(ref);
|
|
1852
|
+
const de = asScalarExpr(distance);
|
|
1853
|
+
let h = mix(startHash("Chamfer"), target);
|
|
1854
|
+
h = hashEdgeRef(h, copied);
|
|
1855
|
+
h = mix(h, de);
|
|
1856
|
+
return {
|
|
1857
|
+
kind: "Chamfer",
|
|
1858
|
+
target,
|
|
1859
|
+
ref: copied,
|
|
1860
|
+
distance: de,
|
|
1861
|
+
structuralHash: h,
|
|
1862
|
+
freeParams: depsOf(target, de)
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1845
1865
|
/** Attach a color (hex string or RGB/RGBA tuple, canonicalized to RGBA) to
|
|
1846
1866
|
* the evaluated result of `target`. Metadata rides beside the geometry: the
|
|
1847
1867
|
* evaluator re-tags the shared target materialization with an independent
|
|
@@ -1994,7 +2014,8 @@ function outputKindOf(node) {
|
|
|
1994
2014
|
case "Revolve":
|
|
1995
2015
|
case "Loft":
|
|
1996
2016
|
case "Sweep":
|
|
1997
|
-
case "Fillet":
|
|
2017
|
+
case "Fillet":
|
|
2018
|
+
case "Chamfer": return "Solid";
|
|
1998
2019
|
case "Profile": return "Face";
|
|
1999
2020
|
case "Path": return "Wire";
|
|
2000
2021
|
case "Compound": return "Compound";
|
|
@@ -2644,7 +2665,7 @@ function evalExtrude(node, ctx) {
|
|
|
2644
2665
|
function evalRevolve(node, ctx) {
|
|
2645
2666
|
const a = evalScalar(node.angle, ctx.env, "Revolve.angle");
|
|
2646
2667
|
if (!a.ok) return a;
|
|
2647
|
-
if (a.value <= 0) return err(validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
|
|
2668
|
+
if (!Number.isFinite(a.value) || a.value <= 0) return err(validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
|
|
2648
2669
|
const deg = Math.min(a.value, 360);
|
|
2649
2670
|
const axis = node.axis ? evalVec3(node.axis, ctx.env, "Revolve.axis") : ok([
|
|
2650
2671
|
0,
|
|
@@ -3005,7 +3026,7 @@ function evalColor(node, ctx) {
|
|
|
3005
3026
|
function evalFillet(node, ctx) {
|
|
3006
3027
|
const radius = evalScalar(node.radius, ctx.env, "Fillet.radius");
|
|
3007
3028
|
if (!radius.ok) return radius;
|
|
3008
|
-
if (radius.value <= 0) return err(validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
|
|
3029
|
+
if (!Number.isFinite(radius.value) || radius.value <= 0) return err(validationError("CSG_FILLET_RADIUS", `Fillet.radius must be positive, got ${radius.value}`));
|
|
3009
3030
|
const t = ctx.evalNode(node.target);
|
|
3010
3031
|
if (!t.ok) return t;
|
|
3011
3032
|
if (!isSolid(t.value)) return err(validationError("CSG_FILLET_TARGET", "Fillet.target did not produce a Solid"));
|
|
@@ -3017,6 +3038,22 @@ function evalFillet(node, ctx) {
|
|
|
3017
3038
|
return fillet$2(solid.value, [resolved.entity], radius.value);
|
|
3018
3039
|
}
|
|
3019
3040
|
//#endregion
|
|
3041
|
+
//#region src/csg/evaluators/chamfer.ts
|
|
3042
|
+
function evalChamfer(node, ctx) {
|
|
3043
|
+
const distance = evalScalar(node.distance, ctx.env, "Chamfer.distance");
|
|
3044
|
+
if (!distance.ok) return distance;
|
|
3045
|
+
if (!Number.isFinite(distance.value) || distance.value <= 0) return err(validationError("CSG_CHAMFER_DISTANCE", `Chamfer.distance must be positive, got ${distance.value}`));
|
|
3046
|
+
const t = ctx.evalNode(node.target);
|
|
3047
|
+
if (!t.ok) return t;
|
|
3048
|
+
if (!isSolid(t.value)) return err(validationError("CSG_CHAMFER_TARGET", "Chamfer.target did not produce a Solid"));
|
|
3049
|
+
const solid = validSolid(t.value);
|
|
3050
|
+
if (!solid.ok) return err(validationError("CSG_CHAMFER_TARGET", solid.error));
|
|
3051
|
+
const resolved = resolveRefIn(node.ref, t.value);
|
|
3052
|
+
if (!resolved.ok) return err(validationError("CSG_CHAMFER_REF", `Chamfer.ref did not resolve: ${resolved.reason}`));
|
|
3053
|
+
if (!isEdge(resolved.entity)) return err(validationError("CSG_CHAMFER_REF", "Chamfer.ref resolved to a non-edge"));
|
|
3054
|
+
return chamfer$2(solid.value, [resolved.entity], distance.value);
|
|
3055
|
+
}
|
|
3056
|
+
//#endregion
|
|
3020
3057
|
//#region src/csg/evaluate.ts
|
|
3021
3058
|
function dispatch(node, ctx) {
|
|
3022
3059
|
switch (node.kind) {
|
|
@@ -3041,6 +3078,19 @@ function dispatch(node, ctx) {
|
|
|
3041
3078
|
case "Mirror": return evalMirror(node, ctx);
|
|
3042
3079
|
case "Compound": return evalCompound(node, ctx);
|
|
3043
3080
|
case "Instance": return evalInstance(node, ctx);
|
|
3081
|
+
case "Extrude":
|
|
3082
|
+
case "Revolve":
|
|
3083
|
+
case "Loft":
|
|
3084
|
+
case "Path":
|
|
3085
|
+
case "Sweep":
|
|
3086
|
+
case "Profile":
|
|
3087
|
+
case "Color":
|
|
3088
|
+
case "Fillet":
|
|
3089
|
+
case "Chamfer": return dispatchFeature(node, ctx);
|
|
3090
|
+
}
|
|
3091
|
+
}
|
|
3092
|
+
function dispatchFeature(node, ctx) {
|
|
3093
|
+
switch (node.kind) {
|
|
3044
3094
|
case "Extrude": return evalExtrude(node, ctx);
|
|
3045
3095
|
case "Revolve": return evalRevolve(node, ctx);
|
|
3046
3096
|
case "Loft": return evalLoft(node, ctx);
|
|
@@ -3049,6 +3099,7 @@ function dispatch(node, ctx) {
|
|
|
3049
3099
|
case "Profile": return evalProfile(node, ctx);
|
|
3050
3100
|
case "Color": return evalColor(node, ctx);
|
|
3051
3101
|
case "Fillet": return evalFillet(node, ctx);
|
|
3102
|
+
case "Chamfer": return evalChamfer(node, ctx);
|
|
3052
3103
|
}
|
|
3053
3104
|
}
|
|
3054
3105
|
function hashExprValue(h, v) {
|
|
@@ -3458,7 +3509,7 @@ function withEvaluator(options, fn) {
|
|
|
3458
3509
|
var MIN_CSG_VERSION = 1;
|
|
3459
3510
|
function toJSON(node) {
|
|
3460
3511
|
return {
|
|
3461
|
-
csgVersion:
|
|
3512
|
+
csgVersion: 6,
|
|
3462
3513
|
root: nodeToJson(node)
|
|
3463
3514
|
};
|
|
3464
3515
|
}
|
|
@@ -3614,6 +3665,17 @@ function segmentToJson(s) {
|
|
|
3614
3665
|
};
|
|
3615
3666
|
}
|
|
3616
3667
|
}
|
|
3668
|
+
function edgeRefToJson(ref) {
|
|
3669
|
+
return {
|
|
3670
|
+
origin: ref.origin,
|
|
3671
|
+
faceRoles: [...ref.faceRoles],
|
|
3672
|
+
hint: {
|
|
3673
|
+
entityType: "edge",
|
|
3674
|
+
length: ref.hint.length,
|
|
3675
|
+
midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
|
|
3676
|
+
}
|
|
3677
|
+
};
|
|
3678
|
+
}
|
|
3617
3679
|
function contourToJson(c) {
|
|
3618
3680
|
return {
|
|
3619
3681
|
start: exprToJson(c.start),
|
|
@@ -3691,17 +3753,15 @@ function nodeToJson(n) {
|
|
|
3691
3753
|
if (n.kind === "Fillet") return {
|
|
3692
3754
|
kind: "Fillet",
|
|
3693
3755
|
target: nodeToJson(n.target),
|
|
3694
|
-
ref:
|
|
3695
|
-
origin: n.ref.origin,
|
|
3696
|
-
faceRoles: [...n.ref.faceRoles],
|
|
3697
|
-
hint: {
|
|
3698
|
-
entityType: "edge",
|
|
3699
|
-
length: n.ref.hint.length,
|
|
3700
|
-
midpoint: n.ref.hint.midpoint ? [...n.ref.hint.midpoint] : void 0
|
|
3701
|
-
}
|
|
3702
|
-
},
|
|
3756
|
+
ref: edgeRefToJson(n.ref),
|
|
3703
3757
|
radius: exprToJson(n.radius)
|
|
3704
3758
|
};
|
|
3759
|
+
if (n.kind === "Chamfer") return {
|
|
3760
|
+
kind: "Chamfer",
|
|
3761
|
+
target: nodeToJson(n.target),
|
|
3762
|
+
ref: edgeRefToJson(n.ref),
|
|
3763
|
+
distance: exprToJson(n.distance)
|
|
3764
|
+
};
|
|
3705
3765
|
if (n.kind === "Compound") return {
|
|
3706
3766
|
kind: "Compound",
|
|
3707
3767
|
children: n.children.map(nodeToJson)
|
|
@@ -3745,7 +3805,7 @@ function readVec2(v, where) {
|
|
|
3745
3805
|
function fromJSON(envelope) {
|
|
3746
3806
|
if (!isObj(envelope)) return bad("input is not an object");
|
|
3747
3807
|
const v = envelope["csgVersion"];
|
|
3748
|
-
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v >
|
|
3808
|
+
if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 6) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..6)`);
|
|
3749
3809
|
const root = envelope["root"];
|
|
3750
3810
|
return readNode(root);
|
|
3751
3811
|
}
|
|
@@ -3861,6 +3921,7 @@ function readNode(j) {
|
|
|
3861
3921
|
case "Profile": return readProfile(j);
|
|
3862
3922
|
case "Color": return readColor(j);
|
|
3863
3923
|
case "Fillet": return readFillet(j);
|
|
3924
|
+
case "Chamfer": return readChamfer(j);
|
|
3864
3925
|
default: return bad(`unknown node kind: ${String(kind)}`);
|
|
3865
3926
|
}
|
|
3866
3927
|
}
|
|
@@ -4110,28 +4171,23 @@ function readContour(j, where) {
|
|
|
4110
4171
|
}
|
|
4111
4172
|
return ok(contour(start.value, segments));
|
|
4112
4173
|
}
|
|
4113
|
-
function
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
if (!isString(origin)) return bad("Fillet.ref.origin: not a string");
|
|
4122
|
-
const roles = ref["faceRoles"];
|
|
4123
|
-
if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad("Fillet.ref.faceRoles: expected two role strings");
|
|
4124
|
-
const hintRaw = ref["hint"];
|
|
4125
|
-
if (!isObj(hintRaw)) return bad("Fillet.ref.hint: not an object");
|
|
4174
|
+
function readEdgeRef(j, where) {
|
|
4175
|
+
if (!isObj(j)) return bad(`${where}: not an object`);
|
|
4176
|
+
const origin = j["origin"];
|
|
4177
|
+
if (!isString(origin)) return bad(`${where}.origin: not a string`);
|
|
4178
|
+
const roles = j["faceRoles"];
|
|
4179
|
+
if (!Array.isArray(roles) || roles.length !== 2 || !roles.every(isString)) return bad(`${where}.faceRoles: expected two role strings`);
|
|
4180
|
+
const hintRaw = j["hint"];
|
|
4181
|
+
if (!isObj(hintRaw)) return bad(`${where}.hint: not an object`);
|
|
4126
4182
|
const length = hintRaw["length"];
|
|
4127
|
-
if (length !== void 0 && !isNumber$1(length)) return bad(
|
|
4183
|
+
if (length !== void 0 && !isNumber$1(length)) return bad(`${where}.hint.length`);
|
|
4128
4184
|
let midpoint;
|
|
4129
4185
|
if (hintRaw["midpoint"] !== void 0) {
|
|
4130
|
-
const m = readVec3(hintRaw["midpoint"],
|
|
4186
|
+
const m = readVec3(hintRaw["midpoint"], `${where}.hint.midpoint`);
|
|
4131
4187
|
if (!m.ok) return m;
|
|
4132
4188
|
midpoint = m.value;
|
|
4133
4189
|
}
|
|
4134
|
-
return ok(
|
|
4190
|
+
return ok({
|
|
4135
4191
|
origin,
|
|
4136
4192
|
faceRoles: [roles[0], roles[1]],
|
|
4137
4193
|
hint: {
|
|
@@ -4139,7 +4195,25 @@ function readFillet(j) {
|
|
|
4139
4195
|
length,
|
|
4140
4196
|
midpoint
|
|
4141
4197
|
}
|
|
4142
|
-
}
|
|
4198
|
+
});
|
|
4199
|
+
}
|
|
4200
|
+
function readFillet(j) {
|
|
4201
|
+
const target = readNode(j["target"]);
|
|
4202
|
+
if (!target.ok) return target;
|
|
4203
|
+
const radius = readExpr(j["radius"]);
|
|
4204
|
+
if (!radius.ok) return radius;
|
|
4205
|
+
const ref = readEdgeRef(j["ref"], "Fillet.ref");
|
|
4206
|
+
if (!ref.ok) return ref;
|
|
4207
|
+
return ok(fillet$1(target.value, ref.value, radius.value));
|
|
4208
|
+
}
|
|
4209
|
+
function readChamfer(j) {
|
|
4210
|
+
const target = readNode(j["target"]);
|
|
4211
|
+
if (!target.ok) return target;
|
|
4212
|
+
const distance = readExpr(j["distance"]);
|
|
4213
|
+
if (!distance.ok) return distance;
|
|
4214
|
+
const ref = readEdgeRef(j["ref"], "Chamfer.ref");
|
|
4215
|
+
if (!ref.ok) return ref;
|
|
4216
|
+
return ok(chamfer$1(target.value, ref.value, distance.value));
|
|
4143
4217
|
}
|
|
4144
4218
|
function readColor(j) {
|
|
4145
4219
|
const target = readNode(j["target"]);
|
|
@@ -4300,7 +4374,8 @@ function optimizeNode(n) {
|
|
|
4300
4374
|
case "Profile":
|
|
4301
4375
|
case "Path":
|
|
4302
4376
|
case "Color":
|
|
4303
|
-
case "Fillet":
|
|
4377
|
+
case "Fillet":
|
|
4378
|
+
case "Chamfer": return optimizeFeature(n);
|
|
4304
4379
|
}
|
|
4305
4380
|
}
|
|
4306
4381
|
function optimizeFeature(n) {
|
|
@@ -4316,6 +4391,7 @@ function optimizeFeature(n) {
|
|
|
4316
4391
|
case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
|
|
4317
4392
|
case "Color": return color(optimizeNode(n.target), [...n.color]);
|
|
4318
4393
|
case "Fillet": return fillet$1(optimizeNode(n.target), n.ref, foldExpr(n.radius));
|
|
4394
|
+
case "Chamfer": return chamfer$1(optimizeNode(n.target), n.ref, foldExpr(n.distance));
|
|
4319
4395
|
}
|
|
4320
4396
|
}
|
|
4321
4397
|
function optimizeTransform(n) {
|
|
@@ -4426,7 +4502,8 @@ function rebuildChildren(n, pred, repl) {
|
|
|
4426
4502
|
case "Loft":
|
|
4427
4503
|
case "Sweep":
|
|
4428
4504
|
case "Color":
|
|
4429
|
-
case "Fillet":
|
|
4505
|
+
case "Fillet":
|
|
4506
|
+
case "Chamfer": return rebuildFeature(n, pred, repl);
|
|
4430
4507
|
}
|
|
4431
4508
|
}
|
|
4432
4509
|
function rebuildFeature(n, pred, repl) {
|
|
@@ -4440,6 +4517,7 @@ function rebuildFeature(n, pred, repl) {
|
|
|
4440
4517
|
case "Sweep": return sweep$2(walk(n.profile, pred, repl), walk(n.spine, pred, repl), { frenet: n.frenet });
|
|
4441
4518
|
case "Color": return color(walk(n.target, pred, repl), [...n.color]);
|
|
4442
4519
|
case "Fillet": return fillet$1(walk(n.target, pred, repl), n.ref, n.radius);
|
|
4520
|
+
case "Chamfer": return chamfer$1(walk(n.target, pred, repl), n.ref, n.distance);
|
|
4443
4521
|
}
|
|
4444
4522
|
}
|
|
4445
4523
|
function forEachNode(root, fn) {
|
|
@@ -4470,7 +4548,8 @@ function childrenOf(n) {
|
|
|
4470
4548
|
case "Scale":
|
|
4471
4549
|
case "Mirror":
|
|
4472
4550
|
case "Color":
|
|
4473
|
-
case "Fillet":
|
|
4551
|
+
case "Fillet":
|
|
4552
|
+
case "Chamfer": return [n.target];
|
|
4474
4553
|
case "Compound": return n.children;
|
|
4475
4554
|
case "Instance": return [n.source];
|
|
4476
4555
|
case "Extrude":
|
|
@@ -7075,7 +7154,7 @@ function chamfer(shape, edgesOrDistance, maybeDistance) {
|
|
|
7075
7154
|
const selectedEdges = edges ?? getEdges(s);
|
|
7076
7155
|
return chamferDistAngle(s, [...selectedEdges], normalized.distance, normalized.angle);
|
|
7077
7156
|
}
|
|
7078
|
-
return chamfer$
|
|
7157
|
+
return chamfer$2(s, edges, normalized.distance);
|
|
7079
7158
|
}
|
|
7080
7159
|
/** Create a hollow shell by removing faces and offsetting remaining walls. */
|
|
7081
7160
|
function shell(shape, faces, thickness, options) {
|
|
@@ -8480,7 +8559,7 @@ var patterns_exports = /* @__PURE__ */ __exportAll({
|
|
|
8480
8559
|
//#endregion
|
|
8481
8560
|
//#region src/ns/csg.ts
|
|
8482
8561
|
var csg_exports = /* @__PURE__ */ __exportAll({
|
|
8483
|
-
CSG_VERSION: () =>
|
|
8562
|
+
CSG_VERSION: () => 6,
|
|
8484
8563
|
Evaluator: () => Evaluator,
|
|
8485
8564
|
add: () => add$1,
|
|
8486
8565
|
arbitraryClosedProfile: () => arbitraryClosedProfile,
|
|
@@ -8495,6 +8574,7 @@ var csg_exports = /* @__PURE__ */ __exportAll({
|
|
|
8495
8574
|
box: () => box$2,
|
|
8496
8575
|
buildVec: () => buildVec,
|
|
8497
8576
|
cShapeProfile: () => cShapeProfile,
|
|
8577
|
+
chamfer: () => chamfer$1,
|
|
8498
8578
|
circle: () => circle$1,
|
|
8499
8579
|
circleHollowProfile: () => circleHollowProfile,
|
|
8500
8580
|
circularProfile: () => circularProfile,
|
package/dist/csg/builders.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Contour, Segment2D } from './segments.js';
|
|
|
3
3
|
import { Matrix4x4 } from '../core/types.js';
|
|
4
4
|
import { ColorInput } from '../topology/metadata/colorFns.js';
|
|
5
5
|
import { EdgeRef } from '../topology/shapeRef/shapeRefTypes.js';
|
|
6
|
-
import { BoxNode, SphereNode, CylinderNode, ConeNode, TorusNode, PolygonNode, CircleNode, LineNode, VertexLitNode, EmptyNode, FuseNode, CutNode, IntersectNode, FuseAllNode, CutAllNode, TranslateNode, RotateNode, ScaleNode, MirrorNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, CompoundNode, InstanceNode, IRNode, SolidNode, FaceNode, EdgeNode, VertexNode } from './types.js';
|
|
6
|
+
import { BoxNode, SphereNode, CylinderNode, ConeNode, TorusNode, PolygonNode, CircleNode, LineNode, VertexLitNode, EmptyNode, FuseNode, CutNode, IntersectNode, FuseAllNode, CutAllNode, TranslateNode, RotateNode, ScaleNode, MirrorNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, ChamferNode, CompoundNode, InstanceNode, IRNode, SolidNode, FaceNode, EdgeNode, VertexNode } from './types.js';
|
|
7
7
|
export declare function box(x: ScalarInput, y: ScalarInput, z: ScalarInput): BoxNode;
|
|
8
8
|
export declare function sphere(radius: ScalarInput): SphereNode;
|
|
9
9
|
export declare function cylinder(radius: ScalarInput, height: ScalarInput): CylinderNode;
|
|
@@ -37,11 +37,10 @@ export interface MirrorOptions {
|
|
|
37
37
|
}
|
|
38
38
|
export declare function mirror(target: IRNode, options?: MirrorOptions): MirrorNode;
|
|
39
39
|
export declare function extrude(profile: FaceNode, vector: Vec3Input): ExtrudeNode;
|
|
40
|
-
/** Fillet the edge named by a lineage ref on the evaluated target. The ref is
|
|
41
|
-
* serializable node data (the cache key stays purely structural); it
|
|
42
|
-
* resolves against the materialized target at evaluation, so an upstream
|
|
43
|
-
* parameter edit re-targets the same edge by its face roles. */
|
|
44
40
|
export declare function fillet(target: IRNode, ref: EdgeRef, radius: ScalarInput): FilletNode;
|
|
41
|
+
/** Chamfer the edge named by a lineage ref on the evaluated target. Same
|
|
42
|
+
* contract as `fillet`: the ref is deep-copied, serializable node data. */
|
|
43
|
+
export declare function chamfer(target: IRNode, ref: EdgeRef, distance: ScalarInput): ChamferNode;
|
|
45
44
|
/** Attach a color (hex string or RGB/RGBA tuple, canonicalized to RGBA) to
|
|
46
45
|
* the evaluated result of `target`. Metadata rides beside the geometry: the
|
|
47
46
|
* evaluator re-tags the shared target materialization with an independent
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Result } from '../../core/result.js';
|
|
2
|
+
import { AnyShape, Dimension } from '../../core/shapeTypes.js';
|
|
3
|
+
import { ChamferNode } from '../types.js';
|
|
4
|
+
import { EvalContext } from './context.js';
|
|
5
|
+
export declare function evalChamfer(node: ChamferNode, 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, sweep, profile, path, color, fillet, compound, instance, type RevolveOptions, type LoftOptions, type SweepNodeOptions, 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, profile, path, color, fillet, chamfer, 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, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, InstanceNode, SolidNode, FaceNode, EdgeNode, VertexNode, AnyNode, } from './types.js';
|
|
10
|
+
export type { IRNode, NodeKind, OutputKind, PrimitiveNode, BooleanNode, TransformIRNode, ExtrudeNode, RevolveNode, LoftNode, SweepNode, ProfileNode, PathNode, ColorNode, FilletNode, ChamferNode, InstanceNode, SolidNode, FaceNode, EdgeNode, VertexNode, AnyNode, } from './types.js';
|
|
11
11
|
export { outputKindOf } from './types.js';
|
|
12
12
|
export { lineTo, arcTo, bezierTo, ellipseArcTo, contour, type Contour, type Segment2D, type SegmentOptions, type EllipseArcOptions, } from './segments.js';
|
|
13
13
|
export { rectangularProfile, circularProfile, iBeamProfile, asymmetricIProfile, lShapeProfile, tShapeProfile, uShapeProfile, zShapeProfile, cShapeProfile, ellipseProfile, trapeziumProfile, rectangleHollowProfile, circleHollowProfile, arbitraryClosedProfile, arbitraryProfileWithVoids, type IBeamParams, type AsymmetricIParams, type LShapeParams, type TShapeParams, type UShapeParams, type ZShapeParams, type CShapeParams, type TrapeziumParams, type RectangleHollowParams, type CircleHollowParams, } from './profiles.js';
|
package/dist/csg/serialize.d.ts
CHANGED
package/dist/csg/types.d.ts
CHANGED
|
@@ -134,6 +134,13 @@ export interface FilletNode extends IRNodeBase {
|
|
|
134
134
|
readonly ref: EdgeRef;
|
|
135
135
|
readonly radius: Expr;
|
|
136
136
|
}
|
|
137
|
+
export interface ChamferNode extends IRNodeBase {
|
|
138
|
+
readonly kind: 'Chamfer';
|
|
139
|
+
readonly target: IRNode;
|
|
140
|
+
/** Serializable lineage ref naming the edge by its two adjacent face roles. */
|
|
141
|
+
readonly ref: EdgeRef;
|
|
142
|
+
readonly distance: Expr;
|
|
143
|
+
}
|
|
137
144
|
export interface ColorNode extends IRNodeBase {
|
|
138
145
|
readonly kind: 'Color';
|
|
139
146
|
readonly target: IRNode;
|
|
@@ -186,7 +193,7 @@ export interface InstanceNode extends IRNodeBase {
|
|
|
186
193
|
export type PrimitiveNode = BoxNode | SphereNode | CylinderNode | ConeNode | TorusNode | PolygonNode | CircleNode | LineNode | VertexLitNode | EmptyNode;
|
|
187
194
|
export type BooleanNode = FuseNode | CutNode | IntersectNode | FuseAllNode | CutAllNode;
|
|
188
195
|
export type TransformIRNode = TranslateNode | RotateNode | ScaleNode | MirrorNode;
|
|
189
|
-
export type IRNode = PrimitiveNode | BooleanNode | TransformIRNode | ExtrudeNode | RevolveNode | LoftNode | SweepNode | ProfileNode | PathNode | ColorNode | FilletNode | CompoundNode | InstanceNode;
|
|
196
|
+
export type IRNode = PrimitiveNode | BooleanNode | TransformIRNode | ExtrudeNode | RevolveNode | LoftNode | SweepNode | ProfileNode | PathNode | ColorNode | FilletNode | ChamferNode | CompoundNode | InstanceNode;
|
|
190
197
|
export type NodeKind = IRNode['kind'];
|
|
191
198
|
export type AnyNode = IRNode;
|
|
192
199
|
/** Nodes that produce a 3D solid. */
|