brepjs 18.130.0 → 18.132.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
@@ -19,7 +19,7 @@ const require_curveFns = require("./curveFns-jmKL1KZp.cjs");
19
19
  const require_meshFns = require("./meshFns-CB7HsxzB.cjs");
20
20
  const require_arrayAccess = require("./arrayAccess-e4H9cBfh.cjs");
21
21
  const require_surfaceBuilders = require("./surfaceBuilders-DUTDN2Ay.cjs");
22
- const require_healingFns = require("./healingFns-DTr6cgTb.cjs");
22
+ const require_healingFns = require("./healingFns-BqmIvfPm.cjs");
23
23
  const require_threadFns = require("./threadFns-BQIE5dO9.cjs");
24
24
  const require_blueprintSketcher = require("./blueprintSketcher-B5UqD0FO.cjs");
25
25
  const require_helpers = require("./helpers-DLZUxawd.cjs");
@@ -32,10 +32,10 @@ const require_blueprintFns = require("./blueprintFns-oatmkSjh.cjs");
32
32
  const require_importFns = require("./importFns-ncp_0vEl.cjs");
33
33
  const require_loftFns = require("./loftFns-u-yPHpJ9.cjs");
34
34
  const require_textBlueprints = require("./textBlueprints-BMvBJ79v.cjs");
35
+ const require_refResolveFns = require("./refResolveFns-c7RWIsZy.cjs");
36
+ const require_adjacencyFns = require("./adjacencyFns-BhdfZany.cjs");
35
37
  const require_cameraFns = require("./cameraFns-i1otOZ0V.cjs");
36
38
  const require_textMetrics = require("./textMetrics-Byfb_37y.cjs");
37
- const require_adjacencyFns = require("./adjacencyFns-BhdfZany.cjs");
38
- const require_refResolveFns = require("./refResolveFns-c7RWIsZy.cjs");
39
39
  const require_workerPool = require("./workerPool-D30NsiIW.cjs");
40
40
  //#region src/kernel/types.ts
41
41
  /** Check if the kernel supports hidden-line-removal projection. */
@@ -1794,6 +1794,64 @@ function extrude$1(profile, vector) {
1794
1794
  freeParams: depsOf(profile, ve)
1795
1795
  };
1796
1796
  }
1797
+ function hashEdgeRef(h0, ref) {
1798
+ let h = fnvMixString(h0, ref.origin);
1799
+ h = fnvMixString(h, ref.faceRoles[0]);
1800
+ h = fnvMixString(h, ref.faceRoles[1]);
1801
+ const hint = ref.hint;
1802
+ h = fnvMixBool(h, hint.length !== void 0);
1803
+ if (hint.length !== void 0) h = fnvMixNumber(h, hint.length);
1804
+ h = fnvMixBool(h, hint.midpoint !== void 0);
1805
+ if (hint.midpoint) for (const c of hint.midpoint) h = fnvMixNumber(h, c);
1806
+ return h;
1807
+ }
1808
+ /** Fillet the edge named by a lineage ref on the evaluated target. The ref is
1809
+ * serializable node data (the cache key stays purely structural); it
1810
+ * resolves against the materialized target at evaluation, so an upstream
1811
+ * parameter edit re-targets the same edge by its face roles. */
1812
+ function copyEdgeRef(ref) {
1813
+ return {
1814
+ origin: ref.origin,
1815
+ faceRoles: [ref.faceRoles[0], ref.faceRoles[1]],
1816
+ hint: {
1817
+ entityType: "edge",
1818
+ length: ref.hint.length,
1819
+ midpoint: ref.hint.midpoint ? [...ref.hint.midpoint] : void 0
1820
+ }
1821
+ };
1822
+ }
1823
+ function fillet$1(target, ref, radius) {
1824
+ const copied = copyEdgeRef(ref);
1825
+ const re = asScalarExpr(radius);
1826
+ let h = mix(startHash("Fillet"), target);
1827
+ h = hashEdgeRef(h, copied);
1828
+ h = mix(h, re);
1829
+ return {
1830
+ kind: "Fillet",
1831
+ target,
1832
+ ref: copied,
1833
+ radius: re,
1834
+ structuralHash: h,
1835
+ freeParams: depsOf(target, re)
1836
+ };
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
+ }
1797
1855
  /** Attach a color (hex string or RGB/RGBA tuple, canonicalized to RGBA) to
1798
1856
  * the evaluated result of `target`. Metadata rides beside the geometry: the
1799
1857
  * evaluator re-tags the shared target materialization with an independent
@@ -1945,7 +2003,9 @@ function outputKindOf(node) {
1945
2003
  case "Extrude":
1946
2004
  case "Revolve":
1947
2005
  case "Loft":
1948
- case "Sweep": return "Solid";
2006
+ case "Sweep":
2007
+ case "Fillet":
2008
+ case "Chamfer": return "Solid";
1949
2009
  case "Profile": return "Face";
1950
2010
  case "Path": return "Wire";
1951
2011
  case "Compound": return "Compound";
@@ -2595,7 +2655,7 @@ function evalExtrude(node, ctx) {
2595
2655
  function evalRevolve(node, ctx) {
2596
2656
  const a = evalScalar(node.angle, ctx.env, "Revolve.angle");
2597
2657
  if (!a.ok) return a;
2598
- 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}`));
2599
2659
  const deg = Math.min(a.value, 360);
2600
2660
  const axis = node.axis ? evalVec3(node.axis, ctx.env, "Revolve.axis") : require_errors.ok([
2601
2661
  0,
@@ -2952,6 +3012,38 @@ function evalColor(node, ctx) {
2952
3012
  return require_errors.ok(require_solidBuilders.colorShape(moved, [...node.color]));
2953
3013
  }
2954
3014
  //#endregion
3015
+ //#region src/csg/evaluators/fillet.ts
3016
+ function evalFillet(node, ctx) {
3017
+ const radius = evalScalar(node.radius, ctx.env, "Fillet.radius");
3018
+ if (!radius.ok) return radius;
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}`));
3020
+ const t = ctx.evalNode(node.target);
3021
+ if (!t.ok) return t;
3022
+ if (!require_shapeTypes.isSolid(t.value)) return require_errors.err(require_errors.validationError("CSG_FILLET_TARGET", "Fillet.target did not produce a Solid"));
3023
+ const solid = require_validityTypes.validSolid(t.value);
3024
+ if (!solid.ok) return require_errors.err(require_errors.validationError("CSG_FILLET_TARGET", solid.error));
3025
+ const resolved = require_refResolveFns.resolveRefIn(node.ref, t.value);
3026
+ if (!resolved.ok) return require_errors.err(require_errors.validationError("CSG_FILLET_REF", `Fillet.ref did not resolve: ${resolved.reason}`));
3027
+ if (!require_shapeTypes.isEdge(resolved.entity)) return require_errors.err(require_errors.validationError("CSG_FILLET_REF", "Fillet.ref resolved to a non-edge"));
3028
+ return require_healingFns.fillet(solid.value, [resolved.entity], radius.value);
3029
+ }
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
2955
3047
  //#region src/csg/evaluate.ts
2956
3048
  function dispatch(node, ctx) {
2957
3049
  switch (node.kind) {
@@ -2976,6 +3068,19 @@ function dispatch(node, ctx) {
2976
3068
  case "Mirror": return evalMirror(node, ctx);
2977
3069
  case "Compound": return evalCompound(node, ctx);
2978
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) {
2979
3084
  case "Extrude": return evalExtrude(node, ctx);
2980
3085
  case "Revolve": return evalRevolve(node, ctx);
2981
3086
  case "Loft": return evalLoft(node, ctx);
@@ -2983,6 +3088,8 @@ function dispatch(node, ctx) {
2983
3088
  case "Sweep": return evalSweep(node, ctx);
2984
3089
  case "Profile": return evalProfile(node, ctx);
2985
3090
  case "Color": return evalColor(node, ctx);
3091
+ case "Fillet": return evalFillet(node, ctx);
3092
+ case "Chamfer": return evalChamfer(node, ctx);
2986
3093
  }
2987
3094
  }
2988
3095
  function hashExprValue(h, v) {
@@ -3392,7 +3499,7 @@ function withEvaluator(options, fn) {
3392
3499
  var MIN_CSG_VERSION = 1;
3393
3500
  function toJSON(node) {
3394
3501
  return {
3395
- csgVersion: 4,
3502
+ csgVersion: 6,
3396
3503
  root: nodeToJson(node)
3397
3504
  };
3398
3505
  }
@@ -3548,6 +3655,17 @@ function segmentToJson(s) {
3548
3655
  };
3549
3656
  }
3550
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
+ }
3551
3669
  function contourToJson(c) {
3552
3670
  return {
3553
3671
  start: exprToJson(c.start),
@@ -3622,6 +3740,18 @@ function nodeToJson(n) {
3622
3740
  target: nodeToJson(n.target),
3623
3741
  color: [...n.color]
3624
3742
  };
3743
+ if (n.kind === "Fillet") return {
3744
+ kind: "Fillet",
3745
+ target: nodeToJson(n.target),
3746
+ ref: edgeRefToJson(n.ref),
3747
+ radius: exprToJson(n.radius)
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
+ };
3625
3755
  if (n.kind === "Compound") return {
3626
3756
  kind: "Compound",
3627
3757
  children: n.children.map(nodeToJson)
@@ -3665,7 +3795,7 @@ function readVec2(v, where) {
3665
3795
  function fromJSON(envelope) {
3666
3796
  if (!isObj(envelope)) return bad("input is not an object");
3667
3797
  const v = envelope["csgVersion"];
3668
- if (typeof v !== "number" || !Number.isInteger(v) || v < MIN_CSG_VERSION || v > 4) return bad(`unsupported csgVersion ${String(v)} (expected ${MIN_CSG_VERSION}..4)`);
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)`);
3669
3799
  const root = envelope["root"];
3670
3800
  return readNode(root);
3671
3801
  }
@@ -3780,6 +3910,8 @@ function readNode(j) {
3780
3910
  case "Sweep": return readSweep(j);
3781
3911
  case "Profile": return readProfile(j);
3782
3912
  case "Color": return readColor(j);
3913
+ case "Fillet": return readFillet(j);
3914
+ case "Chamfer": return readChamfer(j);
3783
3915
  default: return bad(`unknown node kind: ${String(kind)}`);
3784
3916
  }
3785
3917
  }
@@ -4029,6 +4161,50 @@ function readContour(j, where) {
4029
4161
  }
4030
4162
  return require_errors.ok(contour(start.value, segments));
4031
4163
  }
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`);
4172
+ const length = hintRaw["length"];
4173
+ if (length !== void 0 && !isNumber$1(length)) return bad(`${where}.hint.length`);
4174
+ let midpoint;
4175
+ if (hintRaw["midpoint"] !== void 0) {
4176
+ const m = readVec3(hintRaw["midpoint"], `${where}.hint.midpoint`);
4177
+ if (!m.ok) return m;
4178
+ midpoint = m.value;
4179
+ }
4180
+ return require_errors.ok({
4181
+ origin,
4182
+ faceRoles: [roles[0], roles[1]],
4183
+ hint: {
4184
+ entityType: "edge",
4185
+ length,
4186
+ midpoint
4187
+ }
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));
4207
+ }
4032
4208
  function readColor(j) {
4033
4209
  const target = readNode(j["target"]);
4034
4210
  if (!target.ok) return target;
@@ -4176,15 +4352,9 @@ function optimizeNode(n) {
4176
4352
  case "FuseAll": return optimizeFuseAll(n.shapes, n.tolerance);
4177
4353
  case "CutAll": return optimizeCutAll(n.base, n.tools, n.tolerance);
4178
4354
  case "Translate": return optimizeTranslate(n.target, n.vector);
4179
- case "Rotate": return rotate$1(optimizeNode(n.target), foldExpr(n.angle), {
4180
- axis: n.axis ? foldExpr(n.axis) : void 0,
4181
- at: n.at ? foldExpr(n.at) : void 0
4182
- });
4183
- case "Scale": return scale$2(optimizeNode(n.target), foldExpr(n.factor), { center: n.center ? foldExpr(n.center) : void 0 });
4184
- case "Mirror": return mirror$1(optimizeNode(n.target), {
4185
- normal: n.normal ? foldExpr(n.normal) : void 0,
4186
- at: n.at ? foldExpr(n.at) : void 0
4187
- });
4355
+ case "Rotate":
4356
+ case "Scale":
4357
+ case "Mirror": return optimizeTransform(n);
4188
4358
  case "Compound": return compound$1(n.children.map(optimizeNode).filter((c) => c.kind !== "Empty"));
4189
4359
  case "Instance": return instance$1(optimizeNode(n.source), n.placements, n.fuse);
4190
4360
  case "Extrude":
@@ -4193,7 +4363,9 @@ function optimizeNode(n) {
4193
4363
  case "Sweep":
4194
4364
  case "Profile":
4195
4365
  case "Path":
4196
- case "Color": return optimizeFeature(n);
4366
+ case "Color":
4367
+ case "Fillet":
4368
+ case "Chamfer": return optimizeFeature(n);
4197
4369
  }
4198
4370
  }
4199
4371
  function optimizeFeature(n) {
@@ -4208,6 +4380,21 @@ function optimizeFeature(n) {
4208
4380
  case "Profile": return profile(foldContour(n.outline, foldExpr), n.holes.map((hole) => foldContour(hole, foldExpr)));
4209
4381
  case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
4210
4382
  case "Color": return color(optimizeNode(n.target), [...n.color]);
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));
4385
+ }
4386
+ }
4387
+ function optimizeTransform(n) {
4388
+ switch (n.kind) {
4389
+ case "Rotate": return rotate$1(optimizeNode(n.target), foldExpr(n.angle), {
4390
+ axis: n.axis ? foldExpr(n.axis) : void 0,
4391
+ at: n.at ? foldExpr(n.at) : void 0
4392
+ });
4393
+ case "Scale": return scale$2(optimizeNode(n.target), foldExpr(n.factor), { center: n.center ? foldExpr(n.center) : void 0 });
4394
+ case "Mirror": return mirror$1(optimizeNode(n.target), {
4395
+ normal: n.normal ? foldExpr(n.normal) : void 0,
4396
+ at: n.at ? foldExpr(n.at) : void 0
4397
+ });
4211
4398
  }
4212
4399
  }
4213
4400
  function optimizeFuse(a, b, tol) {
@@ -4300,6 +4487,17 @@ function rebuildChildren(n, pred, repl) {
4300
4487
  });
4301
4488
  case "Compound": return compound$1(n.children.map((c) => walk(c, pred, repl)));
4302
4489
  case "Instance": return instance$1(walk(n.source, pred, repl), n.placements, n.fuse);
4490
+ case "Extrude":
4491
+ case "Revolve":
4492
+ case "Loft":
4493
+ case "Sweep":
4494
+ case "Color":
4495
+ case "Fillet":
4496
+ case "Chamfer": return rebuildFeature(n, pred, repl);
4497
+ }
4498
+ }
4499
+ function rebuildFeature(n, pred, repl) {
4500
+ switch (n.kind) {
4303
4501
  case "Extrude": return extrude$1(walk(n.profile, pred, repl), n.vector);
4304
4502
  case "Revolve": return revolve$1(walk(n.profile, pred, repl), n.angle, {
4305
4503
  axis: n.axis,
@@ -4308,6 +4506,8 @@ function rebuildChildren(n, pred, repl) {
4308
4506
  case "Loft": return loft$1(n.sections.map((s) => walk(s, pred, repl)), { ruled: n.ruled });
4309
4507
  case "Sweep": return sweep$2(walk(n.profile, pred, repl), walk(n.spine, pred, repl), { frenet: n.frenet });
4310
4508
  case "Color": return color(walk(n.target, pred, repl), [...n.color]);
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);
4311
4511
  }
4312
4512
  }
4313
4513
  function forEachNode(root, fn) {
@@ -4337,7 +4537,9 @@ function childrenOf(n) {
4337
4537
  case "Rotate":
4338
4538
  case "Scale":
4339
4539
  case "Mirror":
4340
- case "Color": return [n.target];
4540
+ case "Color":
4541
+ case "Fillet":
4542
+ case "Chamfer": return [n.target];
4341
4543
  case "Compound": return n.children;
4342
4544
  case "Instance": return [n.source];
4343
4545
  case "Extrude":
@@ -8348,7 +8550,7 @@ var patterns_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
8348
8550
  //#endregion
8349
8551
  //#region src/ns/csg.ts
8350
8552
  var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
8351
- CSG_VERSION: () => 4,
8553
+ CSG_VERSION: () => 6,
8352
8554
  Evaluator: () => Evaluator,
8353
8555
  add: () => add$1,
8354
8556
  arbitraryClosedProfile: () => arbitraryClosedProfile,
@@ -8363,6 +8565,7 @@ var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
8363
8565
  box: () => box$2,
8364
8566
  buildVec: () => buildVec,
8365
8567
  cShapeProfile: () => cShapeProfile,
8568
+ chamfer: () => chamfer$1,
8366
8569
  circle: () => circle$1,
8367
8570
  circleHollowProfile: () => circleHollowProfile,
8368
8571
  circularProfile: () => circularProfile,
@@ -8380,6 +8583,7 @@ var csg_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
8380
8583
  emptySolid: () => emptySolid,
8381
8584
  emptyWire: () => emptyWire,
8382
8585
  extrude: () => extrude$1,
8586
+ fillet: () => fillet$1,
8383
8587
  foldExpr: () => foldExpr,
8384
8588
  forEachNode: () => forEachNode,
8385
8589
  fromJSON: () => fromJSON,