jscad-electronics 0.0.237 → 0.0.239

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/vanilla.js CHANGED
@@ -24,7 +24,7 @@ function h(type, props, ...restChildren) {
24
24
  };
25
25
  }
26
26
 
27
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/external.js
27
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/external.js
28
28
  var external_exports = {};
29
29
  __export(external_exports, {
30
30
  BRAND: () => BRAND,
@@ -136,7 +136,7 @@ __export(external_exports, {
136
136
  void: () => voidType
137
137
  });
138
138
 
139
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/helpers/util.js
139
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/helpers/util.js
140
140
  var util;
141
141
  (function(util2) {
142
142
  util2.assertEqual = (_) => {
@@ -270,7 +270,7 @@ var getParsedType = (data) => {
270
270
  }
271
271
  };
272
272
 
273
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/ZodError.js
273
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/ZodError.js
274
274
  var ZodIssueCode = util.arrayToEnum([
275
275
  "invalid_type",
276
276
  "invalid_literal",
@@ -388,7 +388,7 @@ ZodError.create = (issues) => {
388
388
  return error;
389
389
  };
390
390
 
391
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/locales/en.js
391
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/locales/en.js
392
392
  var errorMap = (issue, _ctx) => {
393
393
  let message;
394
394
  switch (issue.code) {
@@ -491,7 +491,7 @@ var errorMap = (issue, _ctx) => {
491
491
  };
492
492
  var en_default = errorMap;
493
493
 
494
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/errors.js
494
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/errors.js
495
495
  var overrideErrorMap = en_default;
496
496
  function setErrorMap(map) {
497
497
  overrideErrorMap = map;
@@ -500,7 +500,7 @@ function getErrorMap() {
500
500
  return overrideErrorMap;
501
501
  }
502
502
 
503
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/helpers/parseUtil.js
503
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/helpers/parseUtil.js
504
504
  var makeIssue = (params) => {
505
505
  const { data, path, errorMaps, issueData } = params;
506
506
  const fullPath = [...path, ...issueData.path || []];
@@ -610,14 +610,14 @@ var isDirty = (x) => x.status === "dirty";
610
610
  var isValid = (x) => x.status === "valid";
611
611
  var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
612
612
 
613
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/helpers/errorUtil.js
613
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/helpers/errorUtil.js
614
614
  var errorUtil;
615
615
  (function(errorUtil2) {
616
616
  errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
617
617
  errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
618
618
  })(errorUtil || (errorUtil = {}));
619
619
 
620
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/zod/v3/types.js
620
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/zod/v3/types.js
621
621
  var ParseInputLazyPath = class {
622
622
  constructor(parent, value, path, key) {
623
623
  this._cachedPath = [];
@@ -4065,7 +4065,7 @@ var coerce = {
4065
4065
  };
4066
4066
  var NEVER = INVALID;
4067
4067
 
4068
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/node_modules/@tscircuit/mm/dist/index.js
4068
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/node_modules/@tscircuit/mm/dist/index.js
4069
4069
  var unitToMm = {
4070
4070
  in: 25.4,
4071
4071
  inch: 25.4,
@@ -4092,7 +4092,7 @@ var mm = (n) => {
4092
4092
  throw new Error(`Unsupported unit: ${unit}`);
4093
4093
  };
4094
4094
 
4095
- // .model-contracts/generations/e80fbad5260b66fd00b4ab7513941eadd9b0b17b-v2/index.js
4095
+ // .model-contracts/generations/ad649bc7a403a3e6e9b12ce32ac0b3d0fa61c6bf-v2/index.js
4096
4096
  function normalizeNemaMotorModelString(value) {
4097
4097
  if (!/^nema(?:8|17|23|34)(?:_|$)/i.test(value)) return value;
4098
4098
  return value.replace(/(^|_)jst([0-9]+)_(ph|sh)(?=_|$)/gi, "$1jst$3$2").replace(/(^|_)jst[_-](ph|sh)[_-]([0-9]+)(?=_|$)/gi, "$1jst$2$3").replace(/(^|_)none(?=_|$)/gi, "$1nowires").replace(/(^|_)stubs(?=_|$)/gi, "$1wirestubs");
@@ -4647,6 +4647,76 @@ var jstMotorWireConnectionSchema = external_exports.string().refine((value) => {
4647
4647
  const connector = getJstMotorConnector(value);
4648
4648
  return connector !== void 0 && connector.pinCount >= 2 && connector.pinCount <= connector.maxPinCount;
4649
4649
  }, "Expected jst-ph-N (2\u201316 pins) or jst-sh-N (2\u201315 pins)");
4650
+ function isInsideNemaFace(x, y, p) {
4651
+ const h2 = p.width / 2;
4652
+ x = Math.abs(x);
4653
+ y = Math.abs(y);
4654
+ if (x > h2 || y > h2) return false;
4655
+ const chamfer = p.chamfer;
4656
+ if (!p.stepped) return x + y <= 2 * h2 - chamfer;
4657
+ const c = chamfer / Math.SQRT2;
4658
+ if (c === 0) return true;
4659
+ const recess = p.recessRadius;
4660
+ const fillet = p.filletRadius;
4661
+ const k = h2 - c + recess;
4662
+ if (x > h2 - c && y > h2 - c)
4663
+ return x <= k && y <= k && Math.hypot(x - k, y - k) >= recess;
4664
+ if (y > h2 - fillet && x > h2 - c - fillet)
4665
+ return Math.hypot(x - (h2 - c - fillet), y - (h2 - fillet)) <= fillet;
4666
+ if (x > h2 - fillet && y > h2 - c - fillet)
4667
+ return Math.hypot(x - (h2 - fillet), y - (h2 - c - fillet)) <= fillet;
4668
+ return true;
4669
+ }
4670
+ var segmentDistance = (x, y, ax, ay, bx, by) => {
4671
+ const dx = bx - ax;
4672
+ const dy = by - ay;
4673
+ const t = Math.max(
4674
+ 0,
4675
+ Math.min(1, ((x - ax) * dx + (y - ay) * dy) / (dx * dx + dy * dy || 1))
4676
+ );
4677
+ return Math.hypot(x - ax - t * dx, y - ay - t * dy);
4678
+ };
4679
+ var arcDistance = (x, y, cx, cy, r, start, end) => {
4680
+ const angle = (Math.atan2(y - cy, x - cx) + 2 * Math.PI) % (2 * Math.PI);
4681
+ if (angle >= start && angle <= end)
4682
+ return Math.abs(Math.hypot(x - cx, y - cy) - r);
4683
+ return Math.min(
4684
+ Math.hypot(x - cx - r * Math.cos(start), y - cy - r * Math.sin(start)),
4685
+ Math.hypot(x - cx - r * Math.cos(end), y - cy - r * Math.sin(end))
4686
+ );
4687
+ };
4688
+ var boundaryDistance = (x, y, p) => {
4689
+ const h2 = p.width / 2;
4690
+ x = Math.abs(x);
4691
+ y = Math.abs(y);
4692
+ const chamfer = p.chamfer;
4693
+ if (!p.stepped || chamfer === 0)
4694
+ return Math.min(
4695
+ Math.abs(h2 - x),
4696
+ Math.abs(h2 - y),
4697
+ Math.abs(2 * h2 - chamfer - x - y) / Math.SQRT2
4698
+ );
4699
+ const c = chamfer / Math.SQRT2;
4700
+ const recess = p.recessRadius;
4701
+ const fillet = p.filletRadius;
4702
+ const a = h2 - c - fillet;
4703
+ const k = h2 - c + recess;
4704
+ return Math.min(
4705
+ segmentDistance(x, y, -a, h2, a, h2),
4706
+ segmentDistance(x, y, h2, -a, h2, a),
4707
+ segmentDistance(x, y, h2 - c, h2 - fillet, h2 - c, k),
4708
+ segmentDistance(x, y, k, h2 - c, h2 - fillet, h2 - c),
4709
+ arcDistance(x, y, a, h2 - fillet, fillet, 0, Math.PI / 2),
4710
+ arcDistance(x, y, k, k, recess, Math.PI, 3 * Math.PI / 2),
4711
+ arcDistance(x, y, h2 - fillet, a, fillet, 0, Math.PI / 2)
4712
+ );
4713
+ };
4714
+ function fitsNemaCircle(x, y, radius, p) {
4715
+ return isInsideNemaFace(x, y, p) && boundaryDistance(x, y, p) > radius;
4716
+ }
4717
+ function clearsNemaCircle(x, y, radius, p) {
4718
+ return !isInsideNemaFace(x, y, p) && boundaryDistance(x, y, p) > radius;
4719
+ }
4650
4720
  var hexSocketBoltDimensions = {
4651
4721
  M2: {
4652
4722
  diameter: 2,
@@ -4797,7 +4867,15 @@ var nemaMotorDimensions = {
4797
4867
  bodyCornerChamfer: 6
4798
4868
  },
4799
4869
  23: {
4800
- backFaceScrewSize: "M4",
4870
+ // Representative side-tab rear pattern from STEPPERONLINE's ST-M10 adapter.
4871
+ // The adapter's R5/R2.5 profile is a visual reference, not a frame guarantee:
4872
+ // https://www.omc-stepperonline.com/image/catalog/dimensions/ST-M10_Dimension.svg
4873
+ backFaceHoleSpacing: 50,
4874
+ backFaceHoleSpacingY: 32,
4875
+ rearCornerChamfer: 9 * Math.SQRT2,
4876
+ rearCornerRecessRadius: 5,
4877
+ rearCornerFilletRadius: 2.5,
4878
+ backFaceScrewSize: "M3",
4801
4879
  backFaceHoleDepth: 4.5,
4802
4880
  bodyWidth: 56.4,
4803
4881
  bodyLength: 51,
@@ -4817,7 +4895,10 @@ var nemaMotorDimensions = {
4817
4895
  frontCapLength: 5,
4818
4896
  rearCapLength: 5,
4819
4897
  faceCornerChamfer: 2,
4820
- bodyCornerChamfer: 15
4898
+ bodyCornerChamfer: 9 * Math.SQRT2,
4899
+ bodyCornerRecessRadius: 5,
4900
+ bodyCornerFilletRadius: 2.5,
4901
+ chamferedBodyCornerChamfer: 15
4821
4902
  },
4822
4903
  34: {
4823
4904
  // Illustrative rear details; independent of the mounting flange.
@@ -4853,6 +4934,9 @@ var shape3 = {
4853
4934
  backFaceHoles: external_exports.boolean().optional(),
4854
4935
  backFaceScrews: external_exports.boolean().optional(),
4855
4936
  backFaceHoleSpacing: positiveModelLengthSchema.optional(),
4937
+ /** Axis overrides; the legacy scalar still sets a square pattern when supplied. */
4938
+ backFaceHoleSpacingX: positiveModelLengthSchema.optional(),
4939
+ backFaceHoleSpacingY: positiveModelLengthSchema.optional(),
4856
4940
  backFaceHoleDiameter: positiveModelLengthSchema.optional(),
4857
4941
  backFaceHoleDepth: positiveModelLengthSchema.optional(),
4858
4942
  backFaceScrewSize: metricBoltSizeSchema.optional(),
@@ -4889,8 +4973,14 @@ var shape3 = {
4889
4973
  rearCapLength: positiveModelLengthSchema.optional(),
4890
4974
  faceCornerChamfer: nonnegativeModelLengthSchema.optional(),
4891
4975
  bodyCornerChamfer: nonnegativeModelLengthSchema.optional(),
4976
+ bodyCornerRecessRadius: nonnegativeModelLengthSchema.optional(),
4977
+ bodyCornerFilletRadius: nonnegativeModelLengthSchema.optional(),
4892
4978
  /** Rear outline is independent of the front mounting flange. */
4893
4979
  rearCornerChamfer: nonnegativeModelLengthSchema.optional(),
4980
+ rearCornerRecessRadius: nonnegativeModelLengthSchema.optional(),
4981
+ rearCornerFilletRadius: nonnegativeModelLengthSchema.optional(),
4982
+ rearChamfered: external_exports.boolean().optional(),
4983
+ rearStepped: external_exports.boolean().optional(),
4894
4984
  chamfered: external_exports.boolean().optional(),
4895
4985
  stepped: external_exports.boolean().optional()
4896
4986
  };
@@ -4915,7 +5005,11 @@ var resolve = (p, ctx) => {
4915
5005
  );
4916
5006
  const corner = select(
4917
5007
  ["chamfered", "stepped"],
4918
- p.nemaSize === 34 ? "stepped" : "chamfered"
5008
+ p.nemaSize === 23 || p.nemaSize === 34 ? "stepped" : "chamfered"
5009
+ );
5010
+ const rearCorner = select(
5011
+ ["rearChamfered", "rearStepped"],
5012
+ p.chamfered === true ? "rearChamfered" : p.nemaSize === 23 || corner === "stepped" ? "rearStepped" : "rearChamfered"
4919
5013
  );
4920
5014
  const wireSpecified = p.noWires !== void 0 || p.wireStubs !== void 0 || p.wireConnection !== void 0;
4921
5015
  const wireSelections = Number(p.noWires === true) + Number(p.wireStubs === true) + Number(p.wireConnection !== void 0);
@@ -4925,8 +5019,13 @@ var resolve = (p, ctx) => {
4925
5019
  message: "Select exactly one of noWires, wireStubs or a JST wireConnection"
4926
5020
  });
4927
5021
  const d = nemaMotorDimensions[p.nemaSize];
5022
+ const bodyCornerChamfer = p.bodyCornerChamfer ?? (corner === "chamfered" && "chamferedBodyCornerChamfer" in d ? d.chamferedBodyCornerChamfer : d.bodyCornerChamfer);
5023
+ const defaultBodyRadius = Math.min(4, bodyCornerChamfer / Math.SQRT2 / 4);
4928
5024
  const backFaceScrewSize = p.backFaceScrewSize ?? d.backFaceScrewSize;
4929
5025
  const screw = hexSocketBoltDimensions[backFaceScrewSize];
5026
+ const backFaceHoleSpacing = p.backFaceHoleSpacing ?? ("backFaceHoleSpacing" in d ? d.backFaceHoleSpacing : p.mountingHoleSpacing ?? d.mountingHoleSpacing);
5027
+ const rearCornerChamfer = p.rearCornerChamfer ?? (p.nemaSize === 23 && rearCorner === "rearChamfered" ? p.faceCornerChamfer ?? d.faceCornerChamfer : "rearCornerChamfer" in d ? d.rearCornerChamfer : back === "backFacePlain" && (p.mountingHoleThrough ?? d.mountingHoleThrough) ? p.bodyCornerChamfer ?? d.bodyCornerChamfer : p.faceCornerChamfer ?? d.faceCornerChamfer);
5028
+ const defaultRearRadius = Math.min(4, rearCornerChamfer / Math.SQRT2 / 4);
4930
5029
  return {
4931
5030
  nemaSize: p.nemaSize,
4932
5031
  noWires: p.noWires === true,
@@ -4939,7 +5038,9 @@ var resolve = (p, ctx) => {
4939
5038
  backFacePlain: back === "backFacePlain",
4940
5039
  backFaceHoles: back === "backFaceHoles",
4941
5040
  backFaceScrews: back === "backFaceScrews",
4942
- backFaceHoleSpacing: p.backFaceHoleSpacing ?? ("backFaceHoleSpacing" in d ? d.backFaceHoleSpacing : p.mountingHoleSpacing ?? d.mountingHoleSpacing),
5041
+ backFaceHoleSpacing,
5042
+ backFaceHoleSpacingX: p.backFaceHoleSpacingX ?? backFaceHoleSpacing,
5043
+ backFaceHoleSpacingY: p.backFaceHoleSpacingY ?? p.backFaceHoleSpacing ?? ("backFaceHoleSpacingY" in d ? d.backFaceHoleSpacingY : backFaceHoleSpacing),
4943
5044
  backFaceHoleDiameter: p.backFaceHoleDiameter ?? screw.diameter,
4944
5045
  backFaceHoleDepth: p.backFaceHoleDepth ?? d.backFaceHoleDepth,
4945
5046
  backFaceScrewSize,
@@ -4961,24 +5062,43 @@ var resolve = (p, ctx) => {
4961
5062
  frontCapLength: p.frontCapLength ?? d.frontCapLength,
4962
5063
  rearCapLength: p.rearCapLength ?? d.rearCapLength,
4963
5064
  faceCornerChamfer: p.faceCornerChamfer ?? d.faceCornerChamfer,
4964
- bodyCornerChamfer: p.bodyCornerChamfer ?? d.bodyCornerChamfer,
5065
+ bodyCornerChamfer,
5066
+ bodyCornerRecessRadius: p.bodyCornerRecessRadius ?? ("bodyCornerRecessRadius" in d ? d.bodyCornerRecessRadius : defaultBodyRadius),
5067
+ bodyCornerFilletRadius: p.bodyCornerFilletRadius ?? ("bodyCornerFilletRadius" in d ? d.bodyCornerFilletRadius : defaultBodyRadius),
4965
5068
  chamfered: corner === "chamfered",
4966
5069
  stepped: corner === "stepped",
4967
- ..."rearCornerChamfer" in d || p.rearCornerChamfer !== void 0 ? {
4968
- rearCornerChamfer: p.rearCornerChamfer ?? ("rearCornerChamfer" in d ? d.rearCornerChamfer : p.faceCornerChamfer ?? d.faceCornerChamfer)
4969
- } : {}
5070
+ rearCornerChamfer,
5071
+ rearStepped: rearCorner === "rearStepped",
5072
+ rearChamfered: rearCorner === "rearChamfered",
5073
+ rearCornerRecessRadius: p.rearCornerRecessRadius ?? ("rearCornerRecessRadius" in d ? d.rearCornerRecessRadius : defaultRearRadius),
5074
+ rearCornerFilletRadius: p.rearCornerFilletRadius ?? ("rearCornerFilletRadius" in d ? d.rearCornerFilletRadius : defaultRearRadius)
4970
5075
  };
4971
5076
  };
4972
5077
  var validate3 = (p, ctx) => {
4973
5078
  const issue = (message) => ctx.addIssue({ code: "custom", message });
5079
+ if (p.stepped && p.bodyCornerRecessRadius + p.bodyCornerFilletRadius > p.bodyCornerChamfer / Math.SQRT2)
5080
+ issue("Body recess and fillet radii must fit within the corner shoulder");
4974
5081
  const rearChamfer = p.rearCornerChamfer ?? (p.backFacePlain && p.mountingHoleThrough ? p.bodyCornerChamfer : p.faceCornerChamfer);
4975
- const rearEdge = p.stepped ? rearChamfer / Math.SQRT2 : rearChamfer;
5082
+ const rearEdge = p.rearStepped ? rearChamfer / Math.SQRT2 : rearChamfer;
5083
+ if (p.rearStepped && p.rearCornerRecessRadius + p.rearCornerFilletRadius > rearEdge)
5084
+ issue("Rear recess and fillet radii must fit within the corner shoulder");
4976
5085
  if (!p.backFacePlain) {
4977
5086
  const screw = hexSocketBoltDimensions[p.backFaceScrewSize];
4978
5087
  const radius = (p.backFaceScrews ? Math.max(p.backFaceHoleDiameter, screw.headDiameter) : p.backFaceHoleDiameter) / 2;
4979
- if (p.backFaceHoleSpacing <= 2 * radius)
5088
+ if (p.backFaceHoleSpacingX <= 2 * radius || p.backFaceHoleSpacingY <= 2 * radius)
4980
5089
  issue("Rear holes and screw heads must not overlap each other");
4981
- if (p.backFaceHoleSpacing + 2 * radius >= p.bodyWidth || (p.stepped ? p.backFaceHoleSpacing + 2 * radius >= p.bodyWidth - 2 * rearEdge : p.bodyWidth - rearChamfer - p.backFaceHoleSpacing <= radius * Math.SQRT2))
5090
+ if (!fitsNemaCircle(
5091
+ p.backFaceHoleSpacingX / 2,
5092
+ p.backFaceHoleSpacingY / 2,
5093
+ radius,
5094
+ {
5095
+ width: p.bodyWidth,
5096
+ chamfer: p.rearCornerChamfer,
5097
+ stepped: p.rearStepped,
5098
+ recessRadius: p.rearCornerRecessRadius,
5099
+ filletRadius: p.rearCornerFilletRadius
5100
+ }
5101
+ ))
4982
5102
  issue("Rear holes and screw heads must fit entirely inside the rear face");
4983
5103
  if (p.backFaceHoleDepth >= p.rearCapLength)
4984
5104
  issue("Rear hole depth must be less than the rear cap length");
@@ -5009,7 +5129,13 @@ var validate3 = (p, ctx) => {
5009
5129
  issue("Mounting holes must clear the pilot");
5010
5130
  if (!p.mountingHoleThrough && p.mountingHoleDepth >= p.frontCapLength)
5011
5131
  issue("Blind mounting hole depth must be less than the front cap length");
5012
- if (p.mountingHoleThrough && (p.stepped ? p.bodyWidth / 2 - p.bodyCornerChamfer / Math.SQRT2 + Math.min(4, p.bodyCornerChamfer / Math.SQRT2 / 4) >= p.mountingHoleSpacing / 2 - r : p.bodyWidth - p.bodyCornerChamfer - p.mountingHoleSpacing >= -r * Math.SQRT2))
5132
+ if (p.mountingHoleThrough && !clearsNemaCircle(p.mountingHoleSpacing / 2, p.mountingHoleSpacing / 2, r, {
5133
+ width: p.bodyWidth,
5134
+ chamfer: p.bodyCornerChamfer,
5135
+ stepped: p.stepped,
5136
+ recessRadius: p.bodyCornerRecessRadius,
5137
+ filletRadius: p.bodyCornerFilletRadius
5138
+ }))
5013
5139
  issue("Body must clear through front mounting holes");
5014
5140
  if (p.shaftLength <= p.pilotLength)
5015
5141
  issue("Shaft tip must extend beyond the pilot");
@@ -5028,6 +5154,8 @@ var lengths2 = {
5028
5154
  bodylength: "bodyLength",
5029
5155
  bodywidth: "bodyWidth",
5030
5156
  backholespacing: "backFaceHoleSpacing",
5157
+ backholespacingx: "backFaceHoleSpacingX",
5158
+ backholespacingy: "backFaceHoleSpacingY",
5031
5159
  backholediameter: "backFaceHoleDiameter",
5032
5160
  backholedepth: "backFaceHoleDepth",
5033
5161
  shaftlength: "shaftLength",
@@ -5043,7 +5171,11 @@ var lengths2 = {
5043
5171
  rearcap: "rearCapLength",
5044
5172
  facechamfer: "faceCornerChamfer",
5045
5173
  bodychamfer: "bodyCornerChamfer",
5046
- rearchamfer: "rearCornerChamfer"
5174
+ bodyrecess: "bodyCornerRecessRadius",
5175
+ bodyfillet: "bodyCornerFilletRadius",
5176
+ rearchamfer: "rearCornerChamfer",
5177
+ rearrecess: "rearCornerRecessRadius",
5178
+ rearfillet: "rearCornerFilletRadius"
5047
5179
  };
5048
5180
  var flags = {
5049
5181
  backfaceplain: "backFacePlain",
@@ -5055,6 +5187,8 @@ var flags = {
5055
5187
  dshaft: "dShaft",
5056
5188
  chamfered: "chamfered",
5057
5189
  stepped: "stepped",
5190
+ rearstepped: "rearStepped",
5191
+ rearchamfered: "rearChamfered",
5058
5192
  nowires: "noWires",
5059
5193
  wirestubs: "wireStubs"
5060
5194
  };
@@ -12044,24 +12178,24 @@ function getNemaMotorReferencePoints(input) {
12044
12178
  p.bodyWidth / 2 / Math.max(Math.abs(x), Math.abs(y)),
12045
12179
  (p.bodyWidth - p.faceCornerChamfer) / (Math.abs(x) + Math.abs(y))
12046
12180
  );
12047
- if (p.nemaSize === 34 && p.stepped) {
12048
- const h2 = p.bodyWidth / 2, c = p.bodyCornerChamfer / Math.SQRT2, r = Math.min(4, c / 4);
12049
- const contains = (distance2) => {
12050
- const a = Math.abs(distance2 * x), b = Math.abs(distance2 * y);
12051
- if (a > h2 || b > h2) return false;
12052
- if (c === 0) return true;
12053
- if (a > h2 - c && b > h2 - c)
12054
- return a <= h2 - c + r && b <= h2 - c + r && Math.hypot(a - (h2 - c + r), b - (h2 - c + r)) >= r;
12055
- if (b > h2 - r && a > h2 - c - r)
12056
- return Math.hypot(a - (h2 - c - r), b - (h2 - r)) <= r;
12057
- if (a > h2 - r && b > h2 - c - r)
12058
- return Math.hypot(a - (h2 - r), b - (h2 - c - r)) <= r;
12059
- return true;
12181
+ if (p.nemaSize !== 34 || p.stepped) {
12182
+ const profile5 = p.nemaSize === 34 ? {
12183
+ width: p.bodyWidth,
12184
+ chamfer: p.bodyCornerChamfer,
12185
+ stepped: p.stepped,
12186
+ recessRadius: p.bodyCornerRecessRadius,
12187
+ filletRadius: p.bodyCornerFilletRadius
12188
+ } : {
12189
+ width: p.bodyWidth,
12190
+ chamfer: p.rearCornerChamfer,
12191
+ stepped: p.rearStepped,
12192
+ recessRadius: p.rearCornerRecessRadius,
12193
+ filletRadius: p.rearCornerFilletRadius
12060
12194
  };
12061
12195
  let low = 0, high = p.bodyWidth;
12062
12196
  for (let i = 0; i < 50; i++) {
12063
12197
  const mid = (low + high) / 2;
12064
- if (contains(mid)) low = mid;
12198
+ if (isInsideNemaFace(mid * x, mid * y, profile5)) low = mid;
12065
12199
  else high = mid;
12066
12200
  }
12067
12201
  radius = low;
@@ -12249,6 +12383,746 @@ var componentMaterials = {
12249
12383
  steel: { metalness: 1, roughness: 0.25 }
12250
12384
  };
12251
12385
 
12386
+ // node_modules/@tscircuit/jscad/lib/cleanup-subtraction.ts
12387
+ import insertTjunctions from "@jscad/modeling/src/operations/modifiers/insertTjunctions.js";
12388
+ function cleanupSubtraction(kernel, geometry) {
12389
+ const { geom3 } = kernel.geometries;
12390
+ if (!geometry.polygons.length) return geometry;
12391
+ const source = structuredClone(geometry);
12392
+ const polygons = geom3.toPolygons(source);
12393
+ const extent = Math.max(...kernel.measurements.measureDimensions(source));
12394
+ if (!Number.isFinite(extent) || extent <= 0)
12395
+ throw new Error("Subtraction requires finite nonempty geometry");
12396
+ const epsilon = Math.max(extent * 1e-10, 1e-12);
12397
+ source.polygons = polygons.map((polygon4) => ({
12398
+ ...polygon4,
12399
+ vertices: polygon4.vertices.map((point) => {
12400
+ if (!point.every(Number.isFinite))
12401
+ throw new Error("Subtraction requires finite coordinates");
12402
+ return point.map((value) => Math.round(value / epsilon) * epsilon);
12403
+ })
12404
+ }));
12405
+ const triangles = insertTjunctions(source.polygons).flatMap((polygon4) => {
12406
+ if (polygon4.vertices.length === 3) return [polygon4];
12407
+ const center = [0, 0, 0];
12408
+ for (const point of polygon4.vertices)
12409
+ for (let axis = 0; axis < 3; axis++)
12410
+ center[axis] += point[axis] / polygon4.vertices.length;
12411
+ return polygon4.vertices.map((point, index) => {
12412
+ const triangle = kernel.geometries.poly3.create([
12413
+ center,
12414
+ point,
12415
+ polygon4.vertices[(index + 1) % polygon4.vertices.length]
12416
+ ]);
12417
+ if (polygon4.color) triangle.color = polygon4.color;
12418
+ return triangle;
12419
+ });
12420
+ });
12421
+ const cleaned = geom3.create(triangles);
12422
+ return {
12423
+ ...geometry,
12424
+ polygons: cleaned.polygons,
12425
+ transforms: cleaned.transforms
12426
+ };
12427
+ }
12428
+
12429
+ // node_modules/@tscircuit/jscad/lib/with-references.ts
12430
+ import modeling from "@jscad/modeling";
12431
+ var metadata = /* @__PURE__ */ Symbol.for("@tscircuit/jscad/references/v1");
12432
+ var cache = /* @__PURE__ */ new WeakMap();
12433
+ var snapshot = (value) => structuredClone(value);
12434
+ var assertName = (name) => {
12435
+ if (typeof name !== "string" || !name.trim())
12436
+ throw new Error("Reference name must be nonempty");
12437
+ };
12438
+ function withReferences(kernel = modeling) {
12439
+ if (cache.has(kernel)) return cache.get(kernel);
12440
+ const k = kernel;
12441
+ const { mat4 } = k.maths;
12442
+ const identity = () => Array.from(mat4.create());
12443
+ const multiply = (a, b) => Array.from(mat4.multiply(mat4.create(), a, b));
12444
+ const isGeometry = (g) => g && (k.geometries.geom2.isA(g) || k.geometries.path2.isA(g) || k.geometries.geom3.isA(g));
12445
+ const inputs = (args) => args.flat(Infinity).filter(isGeometry);
12446
+ const read = (g) => g?.[metadata] ?? /* @__PURE__ */ Object.create(null);
12447
+ const merge = (geometries9) => {
12448
+ const refs = /* @__PURE__ */ Object.create(null);
12449
+ for (const g of geometries9)
12450
+ for (const [name, ref] of Object.entries(read(g))) {
12451
+ if (Object.hasOwn(refs, name) && refs[name] !== ref)
12452
+ throw new Error(`Duplicate reference: ${name}`);
12453
+ refs[name] = ref;
12454
+ }
12455
+ return refs;
12456
+ };
12457
+ const attach = (g, refs) => {
12458
+ if (!Object.keys(refs).length) return g;
12459
+ if (Array.isArray(g)) return g.map((item) => attach(item, refs));
12460
+ return isGeometry(g) ? Object.assign({}, g, { [metadata]: refs }) : g;
12461
+ };
12462
+ const moved = (refs, matrix) => Object.fromEntries(
12463
+ Object.entries(refs).map(([name, ref]) => [
12464
+ name,
12465
+ { geometry: ref.geometry, matrix: multiply(matrix, ref.matrix) }
12466
+ ])
12467
+ );
12468
+ const add = (refs, name, ref) => {
12469
+ assertName(name);
12470
+ if (Object.hasOwn(refs, name))
12471
+ throw new Error(`Duplicate reference: ${name}`);
12472
+ refs[name] = ref;
12473
+ };
12474
+ const planar = (g) => {
12475
+ if (!k.geometries.geom2.isA(g) && !k.geometries.path2.isA(g))
12476
+ throw new Error("References require native planar geometry");
12477
+ };
12478
+ const references2 = {
12479
+ name(name, geometry) {
12480
+ planar(geometry);
12481
+ const refs = merge([geometry]);
12482
+ add(refs, name, { geometry: snapshot(geometry), matrix: identity() });
12483
+ return attach(geometry, refs);
12484
+ },
12485
+ nameOutlines(geometry, names) {
12486
+ if (!k.geometries.geom2.isA(geometry))
12487
+ throw new Error("nameOutlines requires a native Geom2");
12488
+ const refs = merge([geometry]);
12489
+ const outlines = k.geometries.geom2.toOutlines(
12490
+ snapshot(geometry)
12491
+ );
12492
+ const area = (points) => points.reduce((sum, p, i) => {
12493
+ const q = points[(i + 1) % points.length];
12494
+ return sum + p[0] * q[1] - p[1] * q[0];
12495
+ }, 0);
12496
+ for (const [role, name] of Object.entries(names)) {
12497
+ if (name === void 0) continue;
12498
+ if (role !== "outer" && role !== "hole")
12499
+ throw new Error(`Unknown outline role: ${role}`);
12500
+ const matches = outlines.filter(
12501
+ (points) => role === "outer" ? area(points) > 0 : area(points) < 0
12502
+ );
12503
+ if (matches.length !== 1)
12504
+ throw new Error(
12505
+ `Expected exactly one ${role} outline, found ${matches.length}`
12506
+ );
12507
+ add(refs, name, {
12508
+ geometry: k.geometries.path2.fromPoints({ closed: true }, matches[0]),
12509
+ matrix: identity()
12510
+ });
12511
+ }
12512
+ return attach(geometry, refs);
12513
+ },
12514
+ reference(name, geometry) {
12515
+ return attach(
12516
+ k.geometries.geom3.create(),
12517
+ read(references2.name(name, geometry))
12518
+ );
12519
+ },
12520
+ get(geometry, name) {
12521
+ const ref = read(geometry)[name];
12522
+ if (!Object.hasOwn(read(geometry), name))
12523
+ throw new Error(`Unknown reference: ${name}`);
12524
+ return snapshot(ref);
12525
+ },
12526
+ list(geometry) {
12527
+ return Object.keys(read(geometry));
12528
+ },
12529
+ collect(geometries9) {
12530
+ return snapshot(merge(inputs([geometries9])));
12531
+ }
12532
+ };
12533
+ const wrapped = { ...k, references: references2 };
12534
+ for (const namespace of [
12535
+ "booleans",
12536
+ "hulls",
12537
+ "expansions",
12538
+ "modifiers",
12539
+ "extrusions",
12540
+ "colors"
12541
+ ]) {
12542
+ wrapped[namespace] = { ...k[namespace] };
12543
+ for (const [name, fn] of Object.entries(k[namespace]))
12544
+ if (typeof fn === "function") {
12545
+ wrapped[namespace][name] = (...args) => {
12546
+ const refs = merge(inputs(args));
12547
+ let result = fn(...args);
12548
+ if (namespace === "booleans" && name === "subtract" && k.geometries.geom3.isA(result)) {
12549
+ result = cleanupSubtraction(kernel, result);
12550
+ }
12551
+ return attach(result, refs);
12552
+ };
12553
+ }
12554
+ }
12555
+ const transformResult = (fn, args, offset, boundsBased = false) => {
12556
+ const gs = inputs(args.slice(offset));
12557
+ if (!gs.some((g) => Object.keys(read(g)).length)) return fn(...args);
12558
+ const maps = gs.map((g) => read(g));
12559
+ const before = boundsBased ? gs.map((g) => k.measurements.measureBoundingBox(snapshot(g))[0]) : [];
12560
+ const matrix = boundsBased ? null : fn(...args.slice(0, offset), k.geometries.geom3.create()).transforms;
12561
+ const result = fn(...args);
12562
+ const results = Array.isArray(result) ? result : [result];
12563
+ const output = results.map((g, i) => {
12564
+ let m = matrix;
12565
+ if (boundsBased) {
12566
+ const after = k.measurements.measureBoundingBox(snapshot(g))[0];
12567
+ m = mat4.fromTranslation(
12568
+ mat4.create(),
12569
+ after.map((n, axis) => n - before[i][axis])
12570
+ );
12571
+ }
12572
+ return attach(g, moved(maps[i], Array.from(m)));
12573
+ });
12574
+ return Array.isArray(result) ? output : output[0];
12575
+ };
12576
+ wrapped.transforms = { ...k.transforms };
12577
+ for (const [name, fn] of Object.entries(k.transforms)) {
12578
+ const boundsBased = /^(center|align)/.test(name);
12579
+ const offset = /^center[XYZ]$|^mirror[XYZ]$/.test(name) ? 0 : 1;
12580
+ wrapped.transforms[name] = (...args) => transformResult(fn, args, offset, boundsBased);
12581
+ }
12582
+ wrapped.geometries = { ...k.geometries };
12583
+ for (const ns of ["geom2", "geom3", "path2"]) {
12584
+ wrapped.geometries[ns] = {
12585
+ ...k.geometries[ns],
12586
+ transform: (matrix, g) => attach(k.geometries[ns].transform(matrix, g), moved(read(g), matrix))
12587
+ };
12588
+ }
12589
+ wrapped.extrusions.extrudeLinear = (options, ...objects) => {
12590
+ const gs = inputs(objects);
12591
+ const { topOutlineName, bottomOutlineName } = options ?? {};
12592
+ if (topOutlineName === void 0 && bottomOutlineName === void 0) {
12593
+ const refs2 = gs.map(read);
12594
+ const result = k.extrusions.extrudeLinear(options, ...objects);
12595
+ return Array.isArray(result) ? result.map((g, i) => attach(g, refs2[i])) : attach(result, refs2[0] ?? {});
12596
+ }
12597
+ if (gs.length !== 1)
12598
+ throw new Error("Named extrusion outlines require exactly one profile");
12599
+ const profile5 = gs[0];
12600
+ planar(profile5);
12601
+ if (k.geometries.path2.isA(profile5) && !profile5.isClosed)
12602
+ throw new Error("Named extrusion outlines require a closed path");
12603
+ const { height: height10 = 1, twistAngle = 0, twistSteps = 1 } = options;
12604
+ if (!Number.isFinite(height10) || !Number.isFinite(twistAngle) || !Number.isInteger(twistSteps) || twistSteps < 1)
12605
+ throw new Error(
12606
+ "Invalid named extrusion height, twistAngle or twistSteps"
12607
+ );
12608
+ const refs = merge(gs);
12609
+ const source = snapshot(profile5);
12610
+ const top = multiply(
12611
+ Array.from(mat4.fromTranslation(mat4.create(), [0, 0, height10])),
12612
+ Array.from(mat4.fromZRotation(mat4.create(), twistAngle))
12613
+ );
12614
+ for (const [prefix, matrix] of [
12615
+ [bottomOutlineName, identity()],
12616
+ [topOutlineName, top]
12617
+ ]) {
12618
+ if (prefix === void 0) continue;
12619
+ add(refs, prefix, { geometry: source, matrix });
12620
+ for (const [name, ref] of Object.entries(read(profile5)))
12621
+ add(refs, `${prefix}.${name}`, {
12622
+ geometry: ref.geometry,
12623
+ matrix: multiply(matrix, ref.matrix)
12624
+ });
12625
+ }
12626
+ return attach(k.extrusions.extrudeLinear(options, ...objects), refs);
12627
+ };
12628
+ cache.set(kernel, wrapped);
12629
+ cache.set(wrapped, wrapped);
12630
+ return wrapped;
12631
+ }
12632
+
12633
+ // node_modules/@tscircuit/jscad/lib/geom3-to-indexed-mesh.ts
12634
+ import jscad from "@jscad/modeling";
12635
+ var edgeKey = (a, b) => a < b ? `${a},${b}` : `${b},${a}`;
12636
+ function geom3ToIndexedMesh(input) {
12637
+ const generalize8 = jscad.modifiers.generalize;
12638
+ input = structuredClone(input);
12639
+ const inputExtent = Math.max(...jscad.measurements.measureDimensions(input));
12640
+ if (!Number.isFinite(inputExtent) || inputExtent <= 0)
12641
+ throw new Error("Expected finite nonempty geometry");
12642
+ const weldTolerance = Math.max(inputExtent * 1e-10, 1e-12);
12643
+ const cells = /* @__PURE__ */ new Map();
12644
+ const weld = (v) => {
12645
+ if (v.length !== 3 || v.some((value) => !Number.isFinite(value)))
12646
+ throw new Error("Expected finite mesh coordinates");
12647
+ const cell = v.map((value) => Math.floor(value / weldTolerance));
12648
+ for (let x = -1; x <= 1; x++)
12649
+ for (let y = -1; y <= 1; y++)
12650
+ for (let z = -1; z <= 1; z++) {
12651
+ const entries2 = cells.get(
12652
+ `${cell[0] + x},${cell[1] + y},${cell[2] + z}`
12653
+ );
12654
+ const existing = entries2?.find(
12655
+ (point3) => Math.hypot(...v.map((value, axis) => value - point3[axis])) <= weldTolerance
12656
+ );
12657
+ if (existing) return existing;
12658
+ }
12659
+ const point2 = [v[0], v[1], v[2]], key = cell.join(","), entries = cells.get(key);
12660
+ if (entries) entries.push(point2);
12661
+ else cells.set(key, [point2]);
12662
+ return point2;
12663
+ };
12664
+ const welded = jscad.geometries.geom3.fromPoints(
12665
+ jscad.geometries.geom3.toPolygons(input).map((poly) => poly.vertices.map(weld))
12666
+ );
12667
+ const geom = generalize8({ snap: true, triangulate: true }, welded);
12668
+ const extent = Math.max(...jscad.measurements.measureDimensions(geom));
12669
+ if (!Number.isFinite(extent) || extent <= 0)
12670
+ throw new Error("Expected finite nonempty geometry");
12671
+ const epsilon = Math.max(extent * 1e-10, 1e-12);
12672
+ const snapTolerance = Math.max(
12673
+ 2 * jscad.measurements.measureEpsilon(geom),
12674
+ epsilon
12675
+ );
12676
+ const positions = [], indices = [];
12677
+ const lookup = /* @__PURE__ */ new Map();
12678
+ const point = (index) => [
12679
+ positions[index * 3],
12680
+ positions[index * 3 + 1],
12681
+ positions[index * 3 + 2]
12682
+ ];
12683
+ const vertex = (v) => {
12684
+ if (v.length !== 3 || v.some((value) => !Number.isFinite(value)))
12685
+ throw new Error("Expected finite mesh coordinates");
12686
+ const key = v.map((x) => Math.round(x / epsilon)).join(",");
12687
+ let index = lookup.get(key);
12688
+ if (index === void 0) {
12689
+ index = positions.length / 3;
12690
+ positions.push(...v);
12691
+ lookup.set(key, index);
12692
+ }
12693
+ return index;
12694
+ };
12695
+ const area = ([a, b, c]) => {
12696
+ const pa = point(a), pb = point(b), pc = point(c);
12697
+ const u = pb.map((x, i) => x - pa[i]), v = pc.map((x, i) => x - pa[i]);
12698
+ return Math.hypot(
12699
+ u[1] * v[2] - u[2] * v[1],
12700
+ u[2] * v[0] - u[0] * v[2],
12701
+ u[0] * v[1] - u[1] * v[0]
12702
+ );
12703
+ };
12704
+ const triangles = [];
12705
+ const edges = /* @__PURE__ */ new Map();
12706
+ for (const poly of jscad.geometries.geom3.toPolygons(geom)) {
12707
+ for (let i = 1; i < poly.vertices.length - 1; i++) {
12708
+ const triangle = [
12709
+ vertex(poly.vertices[0]),
12710
+ vertex(poly.vertices[i]),
12711
+ vertex(poly.vertices[i + 1])
12712
+ ];
12713
+ if (area(triangle) <= epsilon * epsilon) continue;
12714
+ triangles.push(triangle);
12715
+ triangle.forEach((a, i2) => {
12716
+ const b = triangle[(i2 + 1) % 3], key = edgeKey(a, b), entry = edges.get(key);
12717
+ if (entry) entry.count++;
12718
+ else edges.set(key, { a, b, count: 1 });
12719
+ });
12720
+ }
12721
+ }
12722
+ const unmatched = [...edges.values()].filter(({ count }) => count === 1);
12723
+ const candidates = [...new Set(unmatched.flatMap(({ a, b }) => [a, b]))];
12724
+ const sorted = [0, 1, 2].map(
12725
+ (axis) => [...candidates].sort(
12726
+ (a, b) => positions[a * 3 + axis] - positions[b * 3 + axis]
12727
+ )
12728
+ );
12729
+ const subdivisions = /* @__PURE__ */ new Map();
12730
+ for (const { a, b } of unmatched) {
12731
+ const pa = point(a), pb = point(b), direction = pb.map((x, i) => x - pa[i]), length32 = Math.hypot(...direction);
12732
+ if (length32 <= epsilon) continue;
12733
+ const axis = direction.reduce(
12734
+ (best, x, i) => Math.abs(x) > Math.abs(direction[best]) ? i : best,
12735
+ 0
12736
+ );
12737
+ const unit = direction.map((x) => x / length32), low = Math.min(pa[axis], pb[axis]), high = Math.max(pa[axis], pb[axis]);
12738
+ const byAxis = sorted[axis];
12739
+ let left = 0, right = byAxis.length;
12740
+ while (left < right) {
12741
+ const mid = left + right >>> 1;
12742
+ if (positions[byAxis[mid] * 3 + axis] < low) left = mid + 1;
12743
+ else right = mid;
12744
+ }
12745
+ const splits = [];
12746
+ for (let i = left; i < byAxis.length; i++) {
12747
+ const index = byAxis[i], p = point(index);
12748
+ if (p[axis] > high) break;
12749
+ if (index === a || index === b) continue;
12750
+ const delta = p.map((x, j) => x - pa[j]), along = delta.reduce((sum, x, j) => sum + x * unit[j], 0);
12751
+ if (along <= epsilon || along >= length32 - epsilon) continue;
12752
+ const distance2 = Math.hypot(...delta.map((x, j) => x - along * unit[j]));
12753
+ if (distance2 <= snapTolerance) splits.push({ index, t: along / length32 });
12754
+ }
12755
+ if (splits.length)
12756
+ subdivisions.set(
12757
+ edgeKey(a, b),
12758
+ splits.sort((x, y) => x.t - y.t).map(({ index }) => index)
12759
+ );
12760
+ }
12761
+ for (const triangle of triangles) {
12762
+ const boundary = triangle.flatMap((a, i) => {
12763
+ const b = triangle[(i + 1) % 3], splits = subdivisions.get(edgeKey(a, b));
12764
+ if (!splits) return [a];
12765
+ const edge = edges.get(edgeKey(a, b));
12766
+ return [a, ...edge.a === a ? splits : [...splits].reverse()];
12767
+ });
12768
+ if (boundary.length === 3) {
12769
+ indices.push(...triangle);
12770
+ continue;
12771
+ }
12772
+ const origin = point(boundary[0]);
12773
+ const center = origin.map(
12774
+ (value, axis) => value + boundary.reduce(
12775
+ (sum, index) => sum + (point(index)[axis] - value) / boundary.length,
12776
+ 0
12777
+ )
12778
+ );
12779
+ const middle = vertex(center);
12780
+ for (let i = 0; i < boundary.length; i++) {
12781
+ const part = [
12782
+ middle,
12783
+ boundary[i],
12784
+ boundary[(i + 1) % boundary.length]
12785
+ ];
12786
+ if (area(part) <= epsilon * epsilon)
12787
+ throw new Error("Unable to preserve a degenerate mesh boundary");
12788
+ indices.push(...part);
12789
+ }
12790
+ }
12791
+ const compactPositions = [], compactIndices = [], remap = /* @__PURE__ */ new Map();
12792
+ for (const original of indices) {
12793
+ let index = remap.get(original);
12794
+ if (index === void 0) {
12795
+ index = compactPositions.length / 3;
12796
+ compactPositions.push(...point(original));
12797
+ remap.set(original, index);
12798
+ }
12799
+ compactIndices.push(index);
12800
+ }
12801
+ if (!compactIndices.length)
12802
+ throw new Error("Expected finite nonempty geometry");
12803
+ return { positions: compactPositions, indices: compactIndices };
12804
+ }
12805
+
12806
+ // node_modules/@tscircuit/jscad/lib/index.ts
12807
+ var jscad2 = withReferences();
12808
+ var {
12809
+ booleans,
12810
+ colors,
12811
+ curves,
12812
+ expansions,
12813
+ extrusions,
12814
+ geometries,
12815
+ hulls,
12816
+ maths,
12817
+ measurements,
12818
+ modifiers,
12819
+ primitives,
12820
+ text,
12821
+ transforms,
12822
+ utils,
12823
+ references
12824
+ } = jscad2;
12825
+
12826
+ // lib/vanilla/render.ts
12827
+ var isVNode = (n) => n && typeof n === "object" && "type" in n;
12828
+ var degToRad = (v) => {
12829
+ if (typeof v === "number") return v;
12830
+ if (typeof v === "string") {
12831
+ const m = /^(-?\d+(?:\.\d+)?)\s*deg$/i.exec(v);
12832
+ if (m) return parseFloat(m[1]) * Math.PI / 180;
12833
+ const n = Number(v);
12834
+ if (!Number.isNaN(n)) return n;
12835
+ }
12836
+ return 0;
12837
+ };
12838
+ var toVec3 = (v) => {
12839
+ if (Array.isArray(v))
12840
+ return [Number(v[0]) || 0, Number(v[1]) || 0, Number(v[2]) || 0];
12841
+ if (typeof v === "object" && v)
12842
+ return [Number(v.x) || 0, Number(v.y) || 0, Number(v.z) || 0];
12843
+ return [0, 0, 0];
12844
+ };
12845
+ var assertFiniteFeatureTransform = (values) => {
12846
+ if (!values.every(Number.isFinite))
12847
+ throw new Error("JSCAD reference feature transforms must be finite");
12848
+ };
12849
+ var transformFeatureContext = (context, local) => {
12850
+ if (!context.referenceFeatures) return context;
12851
+ const { mat4 } = context.jscad.maths;
12852
+ const matrix = mat4.multiply(mat4.create(), context.matrix, local);
12853
+ assertFiniteFeatureTransform(matrix);
12854
+ return { ...context, matrix };
12855
+ };
12856
+ var validateFeatureName = (name) => {
12857
+ if (name !== void 0 && (typeof name !== "string" || !name.trim()))
12858
+ throw new Error("Named JSCAD features require a nonblank name");
12859
+ };
12860
+ var recordFeature = (context, name, geometry) => {
12861
+ if (!context.referenceFeatures || name === void 0) return;
12862
+ if (Object.hasOwn(context.referenceFeatures, name))
12863
+ throw new Error(`Duplicate JSCAD feature name "${name}"`);
12864
+ const { geometries: geometries9 } = context.jscad;
12865
+ if (!geometries9.geom2.isA(geometry) && !geometries9.path2.isA(geometry) && !geometries9.geom3.isA(geometry))
12866
+ throw new Error(`Named JSCAD feature "${name}" requires native geometry`);
12867
+ assertFiniteFeatureTransform(context.matrix);
12868
+ context.referenceFeatures[name] = {
12869
+ geometry,
12870
+ matrix: [...context.matrix]
12871
+ };
12872
+ };
12873
+ function renderNode(node, colorCtx, renderCtx) {
12874
+ const {
12875
+ jscad: { primitives: primitives9, booleans: booleans5, hulls: hulls2, geometries: geometries9, extrusions: extrusions9, transforms: transforms3 }
12876
+ } = renderCtx;
12877
+ if (node == null || node === false) return [];
12878
+ if (Array.isArray(node))
12879
+ return node.flatMap((n) => renderNode(n, colorCtx, renderCtx));
12880
+ if (!isVNode(node)) return [];
12881
+ const { type, props, children } = node;
12882
+ if (props?.material) {
12883
+ const { material, ...rest } = props;
12884
+ return renderNode({ ...node, props: rest }, colorCtx, renderCtx).map(
12885
+ (entry) => ({
12886
+ ...entry,
12887
+ material: { ...material },
12888
+ geom: { ...entry.geom, material: { ...material } }
12889
+ })
12890
+ );
12891
+ }
12892
+ if (type === Fragment) {
12893
+ return (children ?? []).flatMap((c) => renderNode(c, colorCtx, renderCtx));
12894
+ }
12895
+ if (type === Colorize) {
12896
+ const newColor = props?.color;
12897
+ return (children ?? []).flatMap(
12898
+ (c) => renderNode(c, newColor ?? colorCtx, renderCtx)
12899
+ );
12900
+ }
12901
+ if (type === Translate) {
12902
+ const offset = props?.offset ?? props?.center ?? { x: props?.x, y: props?.y, z: props?.z };
12903
+ if (renderCtx.referenceFeatures)
12904
+ assertFiniteFeatureTransform(
12905
+ (Array.isArray(offset) ? offset.slice(0, 3) : [offset?.x, offset?.y, offset?.z]).map((value) => Number(value ?? 0))
12906
+ );
12907
+ const off = toVec3(offset);
12908
+ const { mat4 } = renderCtx.jscad.maths;
12909
+ const childContext = transformFeatureContext(
12910
+ renderCtx,
12911
+ mat4.fromTranslation(mat4.create(), off)
12912
+ );
12913
+ const geoms = (children ?? []).flatMap(
12914
+ (c) => renderNode(c, colorCtx, childContext)
12915
+ );
12916
+ return geoms.map(({ geom, color, material }) => ({
12917
+ material,
12918
+ geom: transforms3.translate(off, geom),
12919
+ color: color ?? colorCtx
12920
+ }));
12921
+ }
12922
+ if (type === Rotate) {
12923
+ const angles = props?.angles ?? props?.rotation;
12924
+ if (renderCtx.referenceFeatures)
12925
+ assertFiniteFeatureTransform(
12926
+ (Array.isArray(angles) ? angles.slice(0, 3) : [props?.x, props?.y, props?.z]).map(
12927
+ (value) => Number(
12928
+ typeof value === "string" ? value.replace(/\s*deg$/i, "") : value ?? 0
12929
+ )
12930
+ )
12931
+ );
12932
+ const rot = Array.isArray(angles) ? [degToRad(angles[0]), degToRad(angles[1]), degToRad(angles[2])] : [
12933
+ degToRad(props?.x ?? 0),
12934
+ degToRad(props?.y ?? 0),
12935
+ degToRad(props?.z ?? 0)
12936
+ ];
12937
+ const { mat4 } = renderCtx.jscad.maths;
12938
+ const childContext = transformFeatureContext(
12939
+ renderCtx,
12940
+ mat4.fromTaitBryanRotation(mat4.create(), rot[2], rot[1], rot[0])
12941
+ );
12942
+ const geoms = (children ?? []).flatMap(
12943
+ (c) => renderNode(c, colorCtx, childContext)
12944
+ );
12945
+ return geoms.map(({ geom, color, material }) => ({
12946
+ material,
12947
+ geom: transforms3.rotateZ(
12948
+ rot[2],
12949
+ transforms3.rotateY(rot[1], transforms3.rotateX(rot[0], geom))
12950
+ ),
12951
+ color
12952
+ }));
12953
+ }
12954
+ if (type === Union || type === Subtract || type === Hull) {
12955
+ const entries = (children ?? []).flatMap(
12956
+ (c) => renderNode(c, colorCtx, renderCtx)
12957
+ );
12958
+ const geoms = entries.map((g) => g.geom);
12959
+ if (geoms.length === 0) return [];
12960
+ let geom;
12961
+ if (type === Union) geom = booleans5.union(geoms);
12962
+ else if (type === Subtract)
12963
+ geom = booleans5.subtract(geoms[0], geoms.slice(1));
12964
+ else geom = hulls2.hull(geoms);
12965
+ return [
12966
+ {
12967
+ geom,
12968
+ color: colorCtx,
12969
+ material: type === Subtract ? entries[0]?.material : void 0
12970
+ }
12971
+ ];
12972
+ }
12973
+ if (type === Custom) {
12974
+ const { name, reference, geometry } = props;
12975
+ validateFeatureName(name);
12976
+ if (reference && name === void 0)
12977
+ throw new Error("Named JSCAD features require a nonblank name");
12978
+ recordFeature(renderCtx, name, geometry);
12979
+ if (reference) return [];
12980
+ return [{ geom: props.geometry, color: colorCtx }];
12981
+ }
12982
+ if (type === Polygon) {
12983
+ const points = props?.points ?? [];
12984
+ const origin = points[0] ?? [0, 0];
12985
+ const area = points.reduce((sum, point, index) => {
12986
+ const next = points[(index + 1) % points.length];
12987
+ return sum + (point[0] - origin[0]) * (next[1] - origin[1]) - (next[0] - origin[0]) * (point[1] - origin[1]);
12988
+ }, 0);
12989
+ const oriented = area < 0 ? [...points].reverse() : points;
12990
+ const g2 = geometries9.geom2.fromPoints(oriented);
12991
+ return [{ geom: g2, color: colorCtx ?? props?.color }];
12992
+ }
12993
+ if (type === ExtrudeLinear) {
12994
+ const { topOutlineName, bottomOutlineName, twistAngle, twistSteps } = props;
12995
+ const namedOutline = topOutlineName !== void 0 || bottomOutlineName !== void 0;
12996
+ const height10 = props?.height ?? props?.h ?? 1;
12997
+ validateFeatureName(topOutlineName);
12998
+ validateFeatureName(bottomOutlineName);
12999
+ if (namedOutline) {
13000
+ if (!Number.isFinite(height10) || !Number.isFinite(twistAngle ?? 0))
13001
+ throw new Error(
13002
+ "Named extrusion outlines require finite height and twistAngle"
13003
+ );
13004
+ if (twistSteps !== void 0 && (!Number.isInteger(twistSteps) || twistSteps < 1))
13005
+ throw new Error(
13006
+ "Named extrusion outlines require positive integer twistSteps"
13007
+ );
13008
+ }
13009
+ const entries = (children ?? []).flatMap(
13010
+ (c) => renderNode(c, colorCtx, renderCtx)
13011
+ );
13012
+ const geoms2 = entries.map((g) => g.geom);
13013
+ if (geoms2.length === 0) return [];
13014
+ if (namedOutline && geoms2.length !== 1)
13015
+ throw new Error("Named extrusion outlines require exactly one profile");
13016
+ const base2 = geoms2.length > 1 ? booleans5.union(geoms2) : geoms2[0];
13017
+ if (namedOutline && !geometries9.geom2.isA(base2) && !(geometries9.path2.isA(base2) && base2.isClosed))
13018
+ throw new Error(
13019
+ "Named extrusion outlines require a geom2 or closed path2 profile"
13020
+ );
13021
+ if (namedOutline && renderCtx.referenceFeatures) {
13022
+ const { mat4 } = renderCtx.jscad.maths;
13023
+ const topContext = transformFeatureContext(
13024
+ renderCtx,
13025
+ mat4.multiply(
13026
+ mat4.create(),
13027
+ mat4.fromTranslation(mat4.create(), [0, 0, height10]),
13028
+ mat4.fromZRotation(mat4.create(), twistAngle ?? 0)
13029
+ )
13030
+ );
13031
+ recordFeature(topContext, topOutlineName, base2);
13032
+ recordFeature(renderCtx, bottomOutlineName, base2);
13033
+ }
13034
+ const g3 = extrusions9.extrudeLinear(
13035
+ {
13036
+ height: height10,
13037
+ ...twistAngle !== void 0 ? { twistAngle } : {},
13038
+ ...twistSteps !== void 0 ? { twistSteps } : {}
13039
+ },
13040
+ base2
13041
+ );
13042
+ return [
13043
+ {
13044
+ geom: g3,
13045
+ color: colorCtx ?? props?.color,
13046
+ material: entries.length === 1 ? entries[0]?.material : void 0
13047
+ }
13048
+ ];
13049
+ }
13050
+ if (type === Cuboid || type === Cube || type === Cylinder || type === Sphere || type === RoundedCuboid || type === RoundedCylinder) {
13051
+ let g;
13052
+ if (type === Cuboid) {
13053
+ const size = props?.size ?? [1, 1, 1];
13054
+ const offset = props?.offset;
13055
+ const center = props?.center ?? (offset ? [offset[0], offset[1], offset[2]] : [0, 0, 0]);
13056
+ g = primitives9.cuboid({ size, center });
13057
+ } else if (type === Cube) {
13058
+ const size = props?.size ?? 1;
13059
+ const offset = props?.offset;
13060
+ const center = props?.center ?? (offset ? [offset[0], offset[1], offset[2]] : [0, 0, 0]);
13061
+ g = primitives9.cube({ size, center });
13062
+ } else if (type === Cylinder) {
13063
+ const height10 = props?.height ?? 1;
13064
+ const radius = props?.radius ?? 1;
13065
+ const center = props?.center ?? [0, 0, 0];
13066
+ g = primitives9.cylinder({ height: height10, radius, center });
13067
+ } else if (type === Sphere) {
13068
+ const radius = props?.radius ?? 1;
13069
+ const center = props?.center ?? [0, 0, 0];
13070
+ g = primitives9.sphere({ radius, center });
13071
+ } else if (type === RoundedCylinder) {
13072
+ const height10 = props?.height ?? 1;
13073
+ const radius = props?.radius ?? 1;
13074
+ const roundRadius = props?.roundRadius ?? 0.1;
13075
+ const center = props?.center ?? [0, 0, 0];
13076
+ g = primitives9.roundedCylinder({ height: height10, radius, roundRadius, center });
13077
+ } else {
13078
+ const size = props?.size ?? [1, 1, 1];
13079
+ const roundRadius = props?.roundRadius ?? 0.1;
13080
+ const center = props?.center ?? [0, 0, 0];
13081
+ g = primitives9.roundedCuboid({ size, roundRadius, center });
13082
+ }
13083
+ return [{ geom: g, color: colorCtx ?? props?.color }];
13084
+ }
13085
+ if (typeof type === "function") {
13086
+ const out = type(props ?? {});
13087
+ return renderNode(out, colorCtx, renderCtx);
13088
+ }
13089
+ return (children ?? []).flatMap((c) => renderNode(c, colorCtx, renderCtx));
13090
+ }
13091
+ function render(root, jscad22) {
13092
+ jscad22 = withReferences(
13093
+ jscad22
13094
+ );
13095
+ const geometries9 = renderNode(root, void 0, { jscad: jscad22 });
13096
+ return {
13097
+ geometries: geometries9.map(
13098
+ (entry) => entry.material ? { ...entry, geom: { ...entry.geom, material: entry.material } } : entry
13099
+ )
13100
+ };
13101
+ }
13102
+ function renderToJscadModel(root, jscad22) {
13103
+ jscad22 = withReferences(
13104
+ jscad22
13105
+ );
13106
+ const referenceFeatures = /* @__PURE__ */ Object.create(null);
13107
+ const geometries9 = renderNode(root, void 0, {
13108
+ jscad: jscad22,
13109
+ referenceFeatures,
13110
+ matrix: jscad22.maths.mat4.create()
13111
+ });
13112
+ return {
13113
+ geometries: geometries9.map(({ geom, color }) => {
13114
+ if (color === void 0) return geom;
13115
+ const { colors: colors2 } = jscad22;
13116
+ const rgb = typeof color === "string" ? color.startsWith("#") ? colors2.hexToRgb(
13117
+ /^#[\da-f]{3,4}$/i.test(color) ? `#${[...color.slice(1)].map((c) => c + c).join("")}` : color
13118
+ ) : colors2.colorNameToRgb(color) : color;
13119
+ if (!rgb) throw new Error(`Unknown JSCAD color "${color}"`);
13120
+ return colors2.colorize(rgb, geom);
13121
+ }),
13122
+ referenceFeatures
13123
+ };
13124
+ }
13125
+
12252
13126
  // lib/vanilla/primitives.ts
12253
13127
  var Cuboid = /* @__PURE__ */ Symbol("Cuboid");
12254
13128
  var Cube = /* @__PURE__ */ Symbol("Cube");
@@ -12439,11 +13313,11 @@ var ModelRendererRegistry = class {
12439
13313
  };
12440
13314
 
12441
13315
  // lib/models/anglebar/geometry.ts
12442
- import jscad from "@jscad/modeling";
12443
- var { primitives, extrusions, geometries, modifiers, measurements } = jscad;
12444
- var generalize = modifiers.generalize;
12445
- var { rectangle, roundedRectangle, polygon } = primitives;
12446
- var profile = (shape49, height10) => extrusions.extrudeLinear({ height: height10 }, shape49);
13316
+ import jscad3 from "@jscad/modeling";
13317
+ var { primitives: primitives2, extrusions: extrusions2, geometries: geometries2, modifiers: modifiers2, measurements: measurements2 } = jscad3;
13318
+ var generalize = modifiers2.generalize;
13319
+ var { rectangle, roundedRectangle, polygon } = primitives2;
13320
+ var profile = (shape49, height10) => extrusions2.extrudeLinear({ height: height10 }, shape49);
12447
13321
  function filletProfile(points, radii, width10, height10) {
12448
13322
  const outline = [];
12449
13323
  for (let i = 0; i < points.length; i++) {
@@ -12502,7 +13376,7 @@ function createAngleBarMesh(input) {
12502
13376
  { snap: true, triangulate: true },
12503
13377
  createAngleBarGeom(input)
12504
13378
  );
12505
- const epsilon = Math.max(...measurements.measureDimensions(geom)) * 1e-10;
13379
+ const epsilon = Math.max(...measurements2.measureDimensions(geom)) * 1e-10;
12506
13380
  const positions = [];
12507
13381
  const indices = [];
12508
13382
  const lookup = /* @__PURE__ */ new Map();
@@ -12516,7 +13390,7 @@ function createAngleBarMesh(input) {
12516
13390
  }
12517
13391
  return index;
12518
13392
  };
12519
- for (const poly of geometries.geom3.toPolygons(geom)) {
13393
+ for (const poly of geometries2.geom3.toPolygons(geom)) {
12520
13394
  for (let i = 1; i < poly.vertices.length - 1; i++) {
12521
13395
  const a = poly.vertices[0], b = poly.vertices[i], c = poly.vertices[i + 1];
12522
13396
  const u = b.map((x, j) => x - a[j]), v = c.map((x, j) => x - a[j]);
@@ -12549,7 +13423,7 @@ function register55(registry2) {
12549
13423
  }
12550
13424
 
12551
13425
  // lib/mechanical/indexedMeshToGeom3.ts
12552
- import jscad2 from "@jscad/modeling";
13426
+ import jscad4 from "@jscad/modeling";
12553
13427
  function indexedMeshToGeom3(mesh) {
12554
13428
  const polygons = [];
12555
13429
  for (let i = 0; i < mesh.indices.length; i += 3)
@@ -12560,7 +13434,7 @@ function indexedMeshToGeom3(mesh) {
12560
13434
  mesh.positions[index * 3 + 2]
12561
13435
  ])
12562
13436
  );
12563
- return jscad2.geometries.geom3.fromPoints(polygons);
13437
+ return jscad4.geometries.geom3.fromPoints(polygons);
12564
13438
  }
12565
13439
 
12566
13440
  // lib/models/ballbearing/mesh.ts
@@ -12689,11 +13563,11 @@ function createBallBearingMesh(input = {}, options = {}) {
12689
13563
  [ri + 0.15 * (ro - ri), 0.5 * t],
12690
13564
  [ro - 0.15 * (ro - ri), 0.5 * t]
12691
13565
  ];
12692
- const profile6 = sign === -1 ? shape49 : shape49.map(([r, z]) => [r, d.width - z]).reverse();
13566
+ const profile5 = sign === -1 ? shape49 : shape49.map(([r, z]) => [r, d.width - z]).reverse();
12693
13567
  parts.push({
12694
13568
  name: `${face2} ${sign < 0 ? "lower" : "upper"}`,
12695
13569
  color: face2 === "sealed" ? "#252a30" : "#b5bbc3",
12696
- mesh: revolve(profile6, segments)
13570
+ mesh: revolve(profile5, segments)
12697
13571
  });
12698
13572
  }
12699
13573
  return { ...combine(parts), parts };
@@ -12710,21 +13584,21 @@ function checkPrecision(lengths25) {
12710
13584
  "Bearing dimensions exceed the renderer's numerical resolution"
12711
13585
  );
12712
13586
  }
12713
- function revolve(profile6, segments) {
13587
+ function revolve(profile5, segments) {
12714
13588
  const positions = [];
12715
13589
  const indices = [];
12716
- for (const [radius, z] of profile6)
13590
+ for (const [radius, z] of profile5)
12717
13591
  for (let i = 0; i < segments; i++) {
12718
13592
  const angle = i * Math.PI * 2 / segments;
12719
13593
  const r = typeof radius === "number" ? radius : radius(angle);
12720
13594
  positions.push(r * Math.cos(angle), r * Math.sin(angle), z);
12721
13595
  }
12722
- for (let j = 0; j < profile6.length; j++)
13596
+ for (let j = 0; j < profile5.length; j++)
12723
13597
  for (let i = 0; i < segments; i++) {
12724
13598
  const a = j * segments + i;
12725
13599
  const b = j * segments + (i + 1) % segments;
12726
- const c = (j + 1) % profile6.length * segments + (i + 1) % segments;
12727
- const e = (j + 1) % profile6.length * segments + i;
13600
+ const c = (j + 1) % profile5.length * segments + (i + 1) % segments;
13601
+ const e = (j + 1) % profile5.length * segments + i;
12728
13602
  indices.push(a, b, c, a, c, e);
12729
13603
  }
12730
13604
  return { positions, indices };
@@ -12735,7 +13609,7 @@ function annularSector(inner, outer, z0, z1, start, end, segments) {
12735
13609
  Math.ceil((end - start) / (2 * Math.PI) * segments)
12736
13610
  );
12737
13611
  const count = steps + 1;
12738
- const profile6 = [
13612
+ const profile5 = [
12739
13613
  [outer, z0],
12740
13614
  [outer, z1],
12741
13615
  [inner, z1],
@@ -12743,7 +13617,7 @@ function annularSector(inner, outer, z0, z1, start, end, segments) {
12743
13617
  ];
12744
13618
  const positions = [];
12745
13619
  const indices = [];
12746
- for (const [r, z] of profile6)
13620
+ for (const [r, z] of profile5)
12747
13621
  for (let i = 0; i <= steps; i++) {
12748
13622
  const angle = start + (end - start) * i / steps;
12749
13623
  positions.push(r * Math.cos(angle), r * Math.sin(angle), z);
@@ -12934,7 +13808,7 @@ function createBallTransferUnitMesh(input = {}) {
12934
13808
  );
12935
13809
  const segments = 96;
12936
13810
  const latitude = 48;
12937
- const profile6 = [
13811
+ const profile5 = [
12938
13812
  [d.bodyRadius, 0],
12939
13813
  [d.bodyRadius, d.flangeBottomZ],
12940
13814
  [d.flangeRadius, d.flangeBottomZ],
@@ -12947,12 +13821,12 @@ function createBallTransferUnitMesh(input = {}) {
12947
13821
  for (let j = 1; j < latitude; j++) {
12948
13822
  const angle = j * Math.PI / latitude;
12949
13823
  if ((angle - openingAngle) * d.socketRadius > resolution7)
12950
- profile6.push([
13824
+ profile5.push([
12951
13825
  d.socketRadius * Math.sin(angle),
12952
13826
  d.ballCenterZ + d.socketRadius * Math.cos(angle)
12953
13827
  ]);
12954
13828
  }
12955
- profile6.push([0, d.socketBottomZ], [0, 0]);
13829
+ profile5.push([0, d.socketBottomZ], [0, 0]);
12956
13830
  const holes = d.mountingHoles.map(
12957
13831
  ({ x, y, diameter }) => circularProfile(x, y, diameter / 2, segments)
12958
13832
  );
@@ -12960,7 +13834,7 @@ function createBallTransferUnitMesh(input = {}) {
12960
13834
  const housing = joinProfileMeshes([
12961
13835
  // Cap faces are triangulated with all openings, rather than covered by
12962
13836
  // annular triangles and repaired afterward with Boolean subtraction.
12963
- revolve2(profile6, segments, /* @__PURE__ */ new Set([1, 3])),
13837
+ revolve2(profile5, segments, /* @__PURE__ */ new Set([1, 3])),
12964
13838
  cap(
12965
13839
  flangeOutline,
12966
13840
  [circularProfile(0, 0, d.bodyRadius, segments), ...holes],
@@ -12997,10 +13871,10 @@ function createBallTransferUnitMesh(input = {}) {
12997
13871
  ];
12998
13872
  return { positions, indices, parts };
12999
13873
  }
13000
- function revolve2(profile6, segments, omittedEdges = /* @__PURE__ */ new Set()) {
13874
+ function revolve2(profile5, segments, omittedEdges = /* @__PURE__ */ new Set()) {
13001
13875
  const positions = [];
13002
13876
  const indices = [];
13003
- const rings = profile6.map(([radius, z]) => {
13877
+ const rings = profile5.map(([radius, z]) => {
13004
13878
  const start = positions.length / 3;
13005
13879
  const count = radius === 0 ? 1 : segments;
13006
13880
  for (let i = 0; i < count; i++) {
@@ -13282,11 +14156,11 @@ function register59(registry2) {
13282
14156
  }
13283
14157
 
13284
14158
  // lib/models/channelbar/geometry.ts
13285
- import jscad3 from "@jscad/modeling";
13286
- var { primitives: primitives2, extrusions: extrusions2, geometries: geometries2, modifiers: modifiers2, measurements: measurements2 } = jscad3;
13287
- var generalize2 = modifiers2.generalize;
13288
- var { rectangle: rectangle2, roundedRectangle: roundedRectangle2, polygon: polygon2 } = primitives2;
13289
- var profile2 = (shape49, height10) => extrusions2.extrudeLinear({ height: height10 }, shape49);
14159
+ import jscad5 from "@jscad/modeling";
14160
+ var { primitives: primitives3, extrusions: extrusions3, geometries: geometries3, modifiers: modifiers3, measurements: measurements3 } = jscad5;
14161
+ var generalize2 = modifiers3.generalize;
14162
+ var { rectangle: rectangle2, roundedRectangle: roundedRectangle2, polygon: polygon2 } = primitives3;
14163
+ var profile2 = (shape49, height10) => extrusions3.extrudeLinear({ height: height10 }, shape49);
13290
14164
  function filletProfile2(points, radii, width10, height10) {
13291
14165
  const outline = [];
13292
14166
  for (let i = 0; i < points.length; i++) {
@@ -13356,7 +14230,7 @@ function createChannelBarMesh(input) {
13356
14230
  { snap: true, triangulate: true },
13357
14231
  createChannelBarGeom(input)
13358
14232
  );
13359
- const epsilon = Math.max(...measurements2.measureDimensions(geom)) * 1e-10;
14233
+ const epsilon = Math.max(...measurements3.measureDimensions(geom)) * 1e-10;
13360
14234
  const positions = [];
13361
14235
  const indices = [];
13362
14236
  const lookup = /* @__PURE__ */ new Map();
@@ -13370,7 +14244,7 @@ function createChannelBarMesh(input) {
13370
14244
  }
13371
14245
  return index;
13372
14246
  };
13373
- for (const poly of geometries2.geom3.toPolygons(geom)) {
14247
+ for (const poly of geometries3.geom3.toPolygons(geom)) {
13374
14248
  for (let i = 1; i < poly.vertices.length - 1; i++) {
13375
14249
  const a = poly.vertices[0], b = poly.vertices[i], c = poly.vertices[i + 1];
13376
14250
  const u = b.map((x, j) => x - a[j]), v = c.map((x, j) => x - a[j]);
@@ -13403,10 +14277,10 @@ function register60(registry2) {
13403
14277
  }
13404
14278
 
13405
14279
  // lib/models/clampingshaftcollar/mesh.ts
13406
- import jscad5 from "@jscad/modeling";
14280
+ import jscad7 from "@jscad/modeling";
13407
14281
 
13408
14282
  // lib/mechanical/shaft-mount-geometry.ts
13409
- import jscad4 from "@jscad/modeling";
14283
+ import jscad6 from "@jscad/modeling";
13410
14284
  var bodySegments = 64;
13411
14285
  var threadSegments = 24;
13412
14286
  var samplesPerTurn = 12;
@@ -13449,22 +14323,22 @@ function createAnnularSleeve({
13449
14323
  [chamfer, boreARadius, true],
13450
14324
  [0, boreARadius + chamfer, true]
13451
14325
  ];
13452
- const profile6 = raw.filter(
14326
+ const profile5 = raw.filter(
13453
14327
  ([z, r], i) => i === 0 || z !== raw[i - 1][0] || r !== raw[i - 1][1]
13454
14328
  );
13455
14329
  const positions = [];
13456
14330
  const indices = [];
13457
- for (const [z, r, isBore] of profile6)
14331
+ for (const [z, r, isBore] of profile5)
13458
14332
  for (let i = 0; i < bodySegments; i++) {
13459
14333
  const angle = (i + (isBore ? 0.5 : 0)) * Math.PI * 2 / bodySegments;
13460
14334
  const radius = isBore ? r / cosine : r;
13461
14335
  positions.push(radius * Math.cos(angle), radius * Math.sin(angle), z);
13462
14336
  }
13463
- for (let row = 0; row < profile6.length; row++)
14337
+ for (let row = 0; row < profile5.length; row++)
13464
14338
  for (let i = 0; i < bodySegments; i++) {
13465
14339
  const next = (i + 1) % bodySegments;
13466
14340
  const a = row * bodySegments + i, b = row * bodySegments + next;
13467
- const c = (row + 1) % profile6.length * bodySegments + next, d = (row + 1) % profile6.length * bodySegments + i;
14341
+ const c = (row + 1) % profile5.length * bodySegments + next, d = (row + 1) % profile5.length * bodySegments + i;
13468
14342
  indices.push(a, b, c, a, c, d);
13469
14343
  }
13470
14344
  return indexedMeshToGeom3({ positions, indices });
@@ -13522,10 +14396,10 @@ function createMountingHoleCutter(hole) {
13522
14396
  function subtractShaftMountParts(body, ...cutters) {
13523
14397
  const factor = 100;
13524
14398
  const scaled = [body, ...cutters].map(
13525
- (geometry) => jscad4.transforms.scale([factor, factor, factor], geometry)
14399
+ (geometry) => jscad6.transforms.scale([factor, factor, factor], geometry)
13526
14400
  );
13527
- const result = jscad4.booleans.subtract(scaled[0], ...scaled.slice(1));
13528
- return jscad4.transforms.scale([1 / factor, 1 / factor, 1 / factor], result);
14401
+ const result = jscad6.booleans.subtract(scaled[0], ...scaled.slice(1));
14402
+ return jscad6.transforms.scale([1 / factor, 1 / factor, 1 / factor], result);
13529
14403
  }
13530
14404
  function finishShaftMountMesh(geometry) {
13531
14405
  const positions = [];
@@ -13551,7 +14425,7 @@ function finishShaftMountMesh(geometry) {
13551
14425
  vertices.set(key, [...vertices.get(key) ?? [], index]);
13552
14426
  return index;
13553
14427
  };
13554
- const polygons = jscad4.geometries.geom3.toPolygons(geometry).map(
14428
+ const polygons = jscad6.geometries.geom3.toPolygons(geometry).map(
13555
14429
  (polygon4) => polygon4.vertices.map(weld).filter((id, i, ids) => id !== ids[(i + ids.length - 1) % ids.length])
13556
14430
  ).map((ids) => [...new Set(ids)]).filter((ids) => ids.length >= 3).filter((ids) => {
13557
14431
  let longest = 0;
@@ -13574,11 +14448,11 @@ function finishShaftMountMesh(geometry) {
13574
14448
  return Math.hypot(...delta.map((v, axis) => v - t * direction[axis])) >= tolerance;
13575
14449
  });
13576
14450
  });
13577
- const edgeKey = (a, b) => `${Math.min(a, b)},${Math.max(a, b)}`;
14451
+ const edgeKey2 = (a, b) => `${Math.min(a, b)},${Math.max(a, b)}`;
13578
14452
  const edges = /* @__PURE__ */ new Map();
13579
14453
  for (const polygon4 of polygons)
13580
14454
  for (let i = 0; i < polygon4.length; i++) {
13581
- const a = polygon4[i], b = polygon4[(i + 1) % polygon4.length], key = edgeKey(a, b);
14455
+ const a = polygon4[i], b = polygon4[(i + 1) % polygon4.length], key = edgeKey2(a, b);
13582
14456
  const edge = edges.get(key) ?? { a, b, count: 0 };
13583
14457
  edge.count++;
13584
14458
  edges.set(key, edge);
@@ -13663,7 +14537,7 @@ function createClampingShaftCollarMesh(input) {
13663
14537
  });
13664
14538
  const s = dimensions5.split;
13665
14539
  const epsilon = 1e-4;
13666
- const slit = jscad5.primitives.cuboid({
14540
+ const slit = jscad7.primitives.cuboid({
13667
14541
  size: [
13668
14542
  s.xMax - s.xMin + epsilon,
13669
14543
  s.yMax - s.yMin,
@@ -14238,7 +15112,7 @@ function createFlangedBushingMesh(input) {
14238
15112
  const ri = d.innerDiameter / 2;
14239
15113
  const ro = d.outerDiameter / 2;
14240
15114
  const rf = d.flangeDiameter / 2;
14241
- const profile6 = [
15115
+ const profile5 = [
14242
15116
  [rf, 0],
14243
15117
  [rf, d.shoulderZ],
14244
15118
  [ro, d.shoulderZ],
@@ -14249,14 +15123,14 @@ function createFlangedBushingMesh(input) {
14249
15123
  const segments = 96;
14250
15124
  const positions = [];
14251
15125
  const indices = [];
14252
- for (const [radius, z] of profile6)
15126
+ for (const [radius, z] of profile5)
14253
15127
  for (let i = 0; i < segments; i++) {
14254
15128
  const angle = i * Math.PI * 2 / segments;
14255
15129
  positions.push(radius * Math.cos(angle), radius * Math.sin(angle), z);
14256
15130
  }
14257
- for (let ring = 0; ring < profile6.length; ring++) {
15131
+ for (let ring = 0; ring < profile5.length; ring++) {
14258
15132
  const a = ring * segments;
14259
- const b = (ring + 1) % profile6.length * segments;
15133
+ const b = (ring + 1) % profile5.length * segments;
14260
15134
  for (let i = 0; i < segments; i++) {
14261
15135
  const next = (i + 1) % segments;
14262
15136
  indices.push(a + i, a + next, b + next, a + i, b + next, b + i);
@@ -14401,15 +15275,15 @@ function register67(registry2) {
14401
15275
  }
14402
15276
 
14403
15277
  // lib/models/flatcableclip/geometry.ts
14404
- import jscad6 from "@jscad/modeling";
15278
+ import jscad8 from "@jscad/modeling";
14405
15279
  var {
14406
- primitives: primitives3,
14407
- extrusions: extrusions3,
14408
- transforms,
14409
- booleans,
14410
- geometries: geometries3,
14411
- measurements: measurements3
14412
- } = jscad6;
15280
+ primitives: primitives4,
15281
+ extrusions: extrusions4,
15282
+ transforms: transforms2,
15283
+ booleans: booleans2,
15284
+ geometries: geometries4,
15285
+ measurements: measurements4
15286
+ } = jscad8;
14413
15287
  function createFlatCableClipSolid(input) {
14414
15288
  const p = flatCableClipModelPropsSchema.parse(input);
14415
15289
  const legOuter = p.innerWidth / 2 + p.thickness, half = legOuter + p.footLength;
@@ -14427,25 +15301,25 @@ function createFlatCableClipSolid(input) {
14427
15301
  [-legOuter, p.thickness],
14428
15302
  [-half, p.thickness]
14429
15303
  ];
14430
- const bridge = transforms.translate(
15304
+ const bridge = transforms2.translate(
14431
15305
  [0, p.depth / 2, 0],
14432
- transforms.rotateX(
15306
+ transforms2.rotateX(
14433
15307
  Math.PI / 2,
14434
- extrusions3.extrudeLinear(
15308
+ extrusions4.extrudeLinear(
14435
15309
  { height: p.depth },
14436
- primitives3.polygon({ points })
15310
+ primitives4.polygon({ points })
14437
15311
  )
14438
15312
  )
14439
15313
  );
14440
15314
  const bores = [-1, 1].map(
14441
- (sign) => primitives3.cylinder({
15315
+ (sign) => primitives4.cylinder({
14442
15316
  radius: p.holeDiameter / 2,
14443
15317
  height: p.thickness + 2,
14444
15318
  center: [sign * p.holePitch / 2, 0, p.thickness / 2],
14445
15319
  segments: 96
14446
15320
  })
14447
15321
  );
14448
- return booleans.subtract(bridge, ...bores);
15322
+ return booleans2.subtract(bridge, ...bores);
14449
15323
  }
14450
15324
  function createFlatCableClipMesh(input) {
14451
15325
  const p = flatCableClipModelPropsSchema.parse(input);
@@ -14456,8 +15330,8 @@ function createFlatCableClipMesh(input) {
14456
15330
  [0, p.thickness, p.innerHeight, p.innerHeight + p.thickness]
14457
15331
  ];
14458
15332
  const geom = createFlatCableClipSolid(p);
14459
- const tolerance = Math.max(...measurements3.measureDimensions(geom)) * 1e-5;
14460
- const polygons = geometries3.geom3.toPolygons(geom).map(
15333
+ const tolerance = Math.max(...measurements4.measureDimensions(geom)) * 1e-5;
15334
+ const polygons = geometries4.geom3.toPolygons(geom).map(
14461
15335
  (poly) => poly.vertices.map(
14462
15336
  (point) => point.map((value, axis) => {
14463
15337
  const nearest = planes[axis].reduce(
@@ -14467,7 +15341,7 @@ function createFlatCableClipMesh(input) {
14467
15341
  })
14468
15342
  )
14469
15343
  );
14470
- return finishShaftMountMesh(geometries3.geom3.fromPoints(polygons));
15344
+ return finishShaftMountMesh(geometries4.geom3.fromPoints(polygons));
14471
15345
  }
14472
15346
  function createFlatCableClipGeom(input) {
14473
15347
  return indexedMeshToGeom3(createFlatCableClipMesh(input));
@@ -16370,7 +17244,7 @@ function register79(registry2) {
16370
17244
  }
16371
17245
 
16372
17246
  // lib/utils/nemaMotorAssemblyGeometry.ts
16373
- import jscad7 from "@jscad/modeling";
17247
+ import jscad9 from "@jscad/modeling";
16374
17248
  function nema34AssemblyCenters(p) {
16375
17249
  const edge = p.bodyWidth / 2;
16376
17250
  return [-1, 1].flatMap(
@@ -16380,16 +17254,16 @@ function nema34AssemblyCenters(p) {
16380
17254
  );
16381
17255
  }
16382
17256
  function cutNema34FrontRecesses(geometry, p) {
16383
- return jscad7.booleans.subtract(
17257
+ return jscad9.booleans.subtract(
16384
17258
  geometry,
16385
17259
  ...nema34AssemblyCenters(p).flatMap(([x, y]) => [
16386
- jscad7.primitives.cylinder({
17260
+ jscad9.primitives.cylinder({
16387
17261
  radius: 1.6,
16388
17262
  height: p.frontCapLength + 0.2,
16389
17263
  center: [x, y, -p.frontCapLength / 2],
16390
17264
  segments: 32
16391
17265
  }),
16392
- jscad7.primitives.cylinder({
17266
+ jscad9.primitives.cylinder({
16393
17267
  radius: 5,
16394
17268
  height: Math.min(4, p.frontCapLength / 2) + 0.1,
16395
17269
  center: [
@@ -16403,8 +17277,8 @@ function cutNema34FrontRecesses(geometry, p) {
16403
17277
  );
16404
17278
  }
16405
17279
  function createNema34FrontScrews(p) {
16406
- const head = jscad7.booleans.subtract(
16407
- jscad7.primitives.ellipsoid({
17280
+ const head = jscad9.booleans.subtract(
17281
+ jscad9.primitives.ellipsoid({
16408
17282
  radius: [3.2, 3.2, 1.5],
16409
17283
  center: [0, 0, -1.8],
16410
17284
  segments: 32
@@ -16413,22 +17287,22 @@ function createNema34FrontScrews(p) {
16413
17287
  [3.7, 0.8, 1.1],
16414
17288
  [0.8, 3.7, 1.1]
16415
17289
  ].map(
16416
- (size) => jscad7.primitives.cuboid({
17290
+ (size) => jscad9.primitives.cuboid({
16417
17291
  size,
16418
17292
  center: [0, 0, -0.8]
16419
17293
  })
16420
17294
  )
16421
17295
  );
16422
17296
  return nema34AssemblyCenters(p).map(
16423
- ([x, y]) => jscad7.transforms.translate([x, y, 0], head)
17297
+ ([x, y]) => jscad9.transforms.translate([x, y, 0], head)
16424
17298
  );
16425
17299
  }
16426
17300
 
16427
17301
  // lib/NemaMotor.tsx
16428
- import jscad9 from "@jscad/modeling";
17302
+ import jscad11 from "@jscad/modeling";
16429
17303
 
16430
17304
  // lib/utils/nemaMotorWireGeometry.ts
16431
- import jscad8 from "@jscad/modeling";
17305
+ import jscad10 from "@jscad/modeling";
16432
17306
 
16433
17307
  // lib/utils/nemaMotorParameters.ts
16434
17308
  var resolveNemaMotorProps = nemaMotorModelPropsSchema.parse.bind(nemaMotorModelPropsSchema);
@@ -16439,12 +17313,12 @@ function createNemaMotorWireGeometry(input) {
16439
17313
  if (p.noWires) return [];
16440
17314
  const { position } = getNemaMotorReferencePoints(p).wireside;
16441
17315
  const angle = p.wireSideAngle * Math.PI / 180;
16442
- const place = (geometry) => jscad8.transforms.translate(
17316
+ const place = (geometry) => jscad10.transforms.translate(
16443
17317
  [position.x, position.y, position.z],
16444
- jscad8.transforms.rotateZ(angle, geometry)
17318
+ jscad10.transforms.rotateZ(angle, geometry)
16445
17319
  );
16446
17320
  if (p.wireStubs) {
16447
- const colors = [
17321
+ const colors2 = [
16448
17322
  "#d53f3f",
16449
17323
  "#2463af",
16450
17324
  "#3b934b",
@@ -16455,17 +17329,17 @@ function createNemaMotorWireGeometry(input) {
16455
17329
  "#803e91"
16456
17330
  ];
16457
17331
  const wires = Array.from({ length: p.wireCount }, (_, i) => ({
16458
- color: colors[i],
17332
+ color: colors2[i],
16459
17333
  geometry: place(
16460
- jscad8.transforms.translate(
17334
+ jscad10.transforms.translate(
16461
17335
  [
16462
17336
  (p.wireLength - 0.15) / 2,
16463
17337
  (i - (p.wireCount - 1) / 2) * p.wireDiameter * 1.5,
16464
17338
  0
16465
17339
  ],
16466
- jscad8.transforms.rotateY(
17340
+ jscad10.transforms.rotateY(
16467
17341
  Math.PI / 2,
16468
- jscad8.primitives.cylinder({
17342
+ jscad10.primitives.cylinder({
16469
17343
  height: p.wireLength + 0.15,
16470
17344
  radius: p.wireDiameter / 2,
16471
17345
  segments: 24
@@ -16478,7 +17352,7 @@ function createNemaMotorWireGeometry(input) {
16478
17352
  wires.unshift({
16479
17353
  color: "#252830",
16480
17354
  geometry: place(
16481
- jscad8.primitives.roundedCuboid({
17355
+ jscad10.primitives.roundedCuboid({
16482
17356
  size: [3, p.wireCount * p.wireDiameter * 1.5 + 3, 6],
16483
17357
  center: [0.8, 0, 0],
16484
17358
  roundRadius: 1,
@@ -16493,12 +17367,12 @@ function createNemaMotorWireGeometry(input) {
16493
17367
  const wall = pitch === 2 ? 0.6 : 0.3;
16494
17368
  const contactLength = pitch === 2 ? 3.4 : 2.4;
16495
17369
  const contactSize = pitch === 2 ? 0.5 : 0.3;
16496
- const shell = jscad8.booleans.subtract(
16497
- jscad8.primitives.cuboid({
17370
+ const shell = jscad10.booleans.subtract(
17371
+ jscad10.primitives.cuboid({
16498
17372
  size: [matingDepth + 0.1, bodyWidth, bodyHeight],
16499
17373
  center: [(matingDepth - 0.1) / 2, 0, 0]
16500
17374
  }),
16501
- jscad8.primitives.cuboid({
17375
+ jscad10.primitives.cuboid({
16502
17376
  size: [matingDepth - 0.5, bodyWidth - 2 * wall, bodyHeight - 2 * wall],
16503
17377
  center: [matingDepth / 2 + 0.55, 0, 0]
16504
17378
  })
@@ -16508,7 +17382,7 @@ function createNemaMotorWireGeometry(input) {
16508
17382
  ...Array.from({ length: pinCount }, (_, i) => ({
16509
17383
  color: "#b8bec6",
16510
17384
  geometry: place(
16511
- jscad8.primitives.cuboid({
17385
+ jscad10.primitives.cuboid({
16512
17386
  size: [contactLength, contactSize, contactSize],
16513
17387
  center: [contactLength / 2, (i - (pinCount - 1) / 2) * pitch, 0]
16514
17388
  })
@@ -16556,19 +17430,25 @@ var roundedFace = (width10, radius) => {
16556
17430
  })
16557
17431
  );
16558
17432
  };
16559
- var steppedFace = (width10, chamfer) => {
17433
+ var steppedFace = (width10, chamfer, recessRadius, filletRadius) => {
16560
17434
  if (chamfer === 0) return face(width10, 0);
16561
17435
  const h2 = width10 / 2, c = chamfer / Math.SQRT2, r = Math.min(4, c / 4);
16562
17436
  const corner = [];
16563
- const arc = (x, y, from, to) => {
17437
+ const arc = (x, y, radius, from, to) => {
17438
+ if (radius === 0) {
17439
+ corner.push([x, y]);
17440
+ return;
17441
+ }
16564
17442
  for (let i = 0; i <= 12; i++) {
16565
17443
  const a = (from + (to - from) * i / 12) * Math.PI / 180;
16566
- corner.push([x + r * Math.cos(a), y + r * Math.sin(a)]);
17444
+ corner.push([x + radius * Math.cos(a), y + radius * Math.sin(a)]);
16567
17445
  }
16568
17446
  };
16569
- arc(h2 - c - r, h2 - r, 90, 0);
16570
- arc(h2 - c + r, h2 - c + r, 180, 270);
16571
- arc(h2 - r, h2 - c - r, 90, 0);
17447
+ const convex = filletRadius ?? r;
17448
+ const concave = recessRadius ?? r;
17449
+ arc(h2 - c - convex, h2 - convex, convex, 90, 0);
17450
+ arc(h2 - c + concave, h2 - c + concave, concave, 180, 270);
17451
+ arc(h2 - convex, h2 - c - convex, convex, 90, 0);
16572
17452
  return [0, 1, 2, 3].flatMap(
16573
17453
  (i) => corner.map(([x, y]) => {
16574
17454
  const a = -i * Math.PI / 2;
@@ -16589,12 +17469,18 @@ function createNemaMotorSections(input) {
16589
17469
  p.bodyWidth,
16590
17470
  p.faceCornerChamfer
16591
17471
  );
16592
- const profile6 = p.stepped ? steppedFace : face;
16593
- const core = profile6(p.bodyWidth, p.bodyCornerChamfer);
16594
- const rear = profile6(
17472
+ const core = p.stepped ? steppedFace(
16595
17473
  p.bodyWidth,
16596
- p.rearCornerChamfer ?? (p.backFacePlain && p.mountingHoleThrough ? p.bodyCornerChamfer : p.faceCornerChamfer)
16597
- );
17474
+ p.bodyCornerChamfer,
17475
+ p.bodyCornerRecessRadius,
17476
+ p.bodyCornerFilletRadius
17477
+ ) : face(p.bodyWidth, p.bodyCornerChamfer);
17478
+ const rear = p.rearStepped ? steppedFace(
17479
+ p.bodyWidth,
17480
+ p.rearCornerChamfer,
17481
+ p.rearCornerRecessRadius,
17482
+ p.rearCornerFilletRadius
17483
+ ) : face(p.bodyWidth, p.rearCornerChamfer);
16598
17484
  const h2 = p.mountingHoleSpacing / 2;
16599
17485
  const centers = [
16600
17486
  [-h2, -h2],
@@ -16612,9 +17498,10 @@ function createNemaMotorSections(input) {
16612
17498
  if (p.backFacePlain) {
16613
17499
  add("rearCap", rear, -p.bodyLength, -p.bodyLength + p.rearCapLength);
16614
17500
  } else {
16615
- const halfPitch = p.backFaceHoleSpacing / 2;
16616
- const rearHoles = [-halfPitch, halfPitch].flatMap(
16617
- (x) => [-halfPitch, halfPitch].map(
17501
+ const halfPitchX = p.backFaceHoleSpacingX / 2;
17502
+ const halfPitchY = p.backFaceHoleSpacingY / 2;
17503
+ const rearHoles = [-halfPitchX, halfPitchX].flatMap(
17504
+ (x) => [-halfPitchY, halfPitchY].map(
16618
17505
  (y) => circle(p.backFaceHoleDiameter / 2, x, y)
16619
17506
  )
16620
17507
  );
@@ -16639,12 +17526,12 @@ function createNemaMotorSections(input) {
16639
17526
  else {
16640
17527
  const cut = r - p.shaftFlatDepth;
16641
17528
  const angle = Math.acos(cut / r);
16642
- const profile7 = Array.from({ length: 97 }, (_, i) => {
17529
+ const profile5 = Array.from({ length: 97 }, (_, i) => {
16643
17530
  const a = angle + (2 * Math.PI - 2 * angle) * i / 96;
16644
17531
  return [r * Math.cos(a), r * Math.sin(a)];
16645
17532
  });
16646
17533
  const rotation = p.shaftFlatAngle * Math.PI / 180;
16647
- const d = profile7.map(([x, y]) => [
17534
+ const d = profile5.map(([x, y]) => [
16648
17535
  x * Math.cos(rotation) - y * Math.sin(rotation),
16649
17536
  x * Math.sin(rotation) + y * Math.cos(rotation)
16650
17537
  ]);
@@ -16655,7 +17542,7 @@ function createNemaMotorSections(input) {
16655
17542
  }
16656
17543
 
16657
17544
  // lib/NemaMotor.tsx
16658
- var generalize3 = jscad9.modifiers.generalize;
17545
+ var generalize3 = jscad11.modifiers.generalize;
16659
17546
  function NemaMotor({
16660
17547
  bodyColor = "#242830",
16661
17548
  capColor = "#aeb5bd",
@@ -16664,7 +17551,7 @@ function NemaMotor({
16664
17551
  ...props
16665
17552
  }) {
16666
17553
  const p = resolveNemaMotorProps(props);
16667
- const screw = p.backFaceScrews ? jscad9.transforms.rotateX(
17554
+ const screw = p.backFaceScrews ? jscad11.transforms.rotateX(
16668
17555
  Math.PI,
16669
17556
  createHexSocketBoltGeom({
16670
17557
  metricSize: p.backFaceScrewSize,
@@ -16672,19 +17559,20 @@ function NemaMotor({
16672
17559
  showThreads: false
16673
17560
  })
16674
17561
  ) : void 0;
16675
- const halfPitch = p.backFaceHoleSpacing / 2;
17562
+ const halfPitchX = p.backFaceHoleSpacingX / 2;
17563
+ const halfPitchY = p.backFaceHoleSpacingY / 2;
16676
17564
  return /* @__PURE__ */ jsxs(Fragment2, { children: [
16677
17565
  createNemaMotorSections(p).map((section, index) => {
16678
- const outline = jscad9.geometries.geom2.fromPoints(section.outline);
16679
- const profile6 = section.holes.length ? jscad9.booleans.subtract(
17566
+ const outline = jscad11.geometries.geom2.fromPoints(section.outline);
17567
+ const profile5 = section.holes.length ? jscad11.booleans.subtract(
16680
17568
  outline,
16681
- ...section.holes.map((h2) => jscad9.geometries.geom2.fromPoints(h2))
17569
+ ...section.holes.map((h2) => jscad11.geometries.geom2.fromPoints(h2))
16682
17570
  ) : outline;
16683
- let geometry = jscad9.transforms.translate(
17571
+ let geometry = jscad11.transforms.translate(
16684
17572
  [0, 0, section.zMin],
16685
- jscad9.extrusions.extrudeLinear(
17573
+ jscad11.extrusions.extrudeLinear(
16686
17574
  { height: section.zMax - section.zMin },
16687
- profile6
17575
+ profile5
16688
17576
  )
16689
17577
  );
16690
17578
  if (p.nemaSize === 34 && section.name === "frontCap")
@@ -16717,8 +17605,8 @@ function NemaMotor({
16717
17605
  },
16718
17606
  `front-screw-${index}`
16719
17607
  )),
16720
- screw && [-halfPitch, halfPitch].flatMap(
16721
- (x) => [-halfPitch, halfPitch].map((y) => /* @__PURE__ */ jsx(
17608
+ screw && [-halfPitchX, halfPitchX].flatMap(
17609
+ (x) => [-halfPitchY, halfPitchY].map((y) => /* @__PURE__ */ jsx(
16722
17610
  Colorize,
16723
17611
  {
16724
17612
  material: componentMaterials.steel,
@@ -16726,7 +17614,7 @@ function NemaMotor({
16726
17614
  children: /* @__PURE__ */ jsx(
16727
17615
  Custom,
16728
17616
  {
16729
- geometry: jscad9.transforms.translate(
17617
+ geometry: jscad11.transforms.translate(
16730
17618
  [x, y, -p.bodyLength],
16731
17619
  generalize3({ simplify: true }, screw)
16732
17620
  )
@@ -17216,19 +18104,19 @@ function register83(registry2) {
17216
18104
  }
17217
18105
 
17218
18106
  // lib/models/perforatedsheet/geometry.ts
17219
- import jscad10 from "@jscad/modeling";
18107
+ import jscad12 from "@jscad/modeling";
17220
18108
  var {
17221
- booleans: booleans2,
17222
- primitives: primitives4,
17223
- extrusions: extrusions4,
17224
- geometries: geometries4,
17225
- modifiers: modifiers3,
17226
- measurements: measurements4
17227
- } = jscad10;
17228
- var generalize4 = modifiers3.generalize;
17229
- var { subtract } = booleans2;
17230
- var { rectangle: rectangle3, roundedRectangle: roundedRectangle3, circle: circle2 } = primitives4;
17231
- var profile3 = (shape49, height10) => extrusions4.extrudeLinear({ height: height10 }, shape49);
18109
+ booleans: booleans3,
18110
+ primitives: primitives5,
18111
+ extrusions: extrusions5,
18112
+ geometries: geometries5,
18113
+ modifiers: modifiers4,
18114
+ measurements: measurements5
18115
+ } = jscad12;
18116
+ var generalize4 = modifiers4.generalize;
18117
+ var { subtract } = booleans3;
18118
+ var { rectangle: rectangle3, roundedRectangle: roundedRectangle3, circle: circle2 } = primitives5;
18119
+ var profile3 = (shape49, height10) => extrusions5.extrudeLinear({ height: height10 }, shape49);
17232
18120
  function perforated(p) {
17233
18121
  const holes = [];
17234
18122
  const rows = Math.floor((p.width - 2 * p.edgeY) / p.pitchY + 1 + 1e-10);
@@ -17259,7 +18147,7 @@ function createPerforatedSheetMesh(input) {
17259
18147
  { snap: true, triangulate: true },
17260
18148
  createPerforatedSheetGeom(input)
17261
18149
  );
17262
- const epsilon = Math.max(...measurements4.measureDimensions(geom)) * 1e-10;
18150
+ const epsilon = Math.max(...measurements5.measureDimensions(geom)) * 1e-10;
17263
18151
  const positions = [];
17264
18152
  const indices = [];
17265
18153
  const lookup = /* @__PURE__ */ new Map();
@@ -17273,7 +18161,7 @@ function createPerforatedSheetMesh(input) {
17273
18161
  }
17274
18162
  return index;
17275
18163
  };
17276
- for (const poly of geometries4.geom3.toPolygons(geom)) {
18164
+ for (const poly of geometries5.geom3.toPolygons(geom)) {
17277
18165
  for (let i = 1; i < poly.vertices.length - 1; i++) {
17278
18166
  const a = poly.vertices[0], b = poly.vertices[i], c = poly.vertices[i + 1];
17279
18167
  const u = b.map((x, j) => x - a[j]), v = c.map((x, j) => x - a[j]);
@@ -17315,7 +18203,7 @@ function createPlainBushingMesh(input) {
17315
18203
  const ri = d.innerDiameter / 2;
17316
18204
  const ro = d.outerDiameter / 2;
17317
18205
  const c = props.edgeChamfer;
17318
- const profile6 = c > 0 ? [
18206
+ const profile5 = c > 0 ? [
17319
18207
  [d.endOuterDiameter / 2, 0],
17320
18208
  [ro, c],
17321
18209
  [ro, d.length - c],
@@ -17333,14 +18221,14 @@ function createPlainBushingMesh(input) {
17333
18221
  const segments = 96;
17334
18222
  const positions = [];
17335
18223
  const indices = [];
17336
- for (const [radius, z] of profile6)
18224
+ for (const [radius, z] of profile5)
17337
18225
  for (let i = 0; i < segments; i++) {
17338
18226
  const angle = i * Math.PI * 2 / segments;
17339
18227
  positions.push(radius * Math.cos(angle), radius * Math.sin(angle), z);
17340
18228
  }
17341
- for (let ring = 0; ring < profile6.length; ring++) {
18229
+ for (let ring = 0; ring < profile5.length; ring++) {
17342
18230
  const a = ring * segments;
17343
- const b = (ring + 1) % profile6.length * segments;
18231
+ const b = (ring + 1) % profile5.length * segments;
17344
18232
  for (let i = 0; i < segments; i++) {
17345
18233
  const next = (i + 1) % segments;
17346
18234
  indices.push(a + i, a + next, b + next, a + i, b + next, b + i);
@@ -17372,13 +18260,13 @@ function register85(registry2) {
17372
18260
  }
17373
18261
 
17374
18262
  // lib/models/pushfitplug/geometry.ts
17375
- import jscad11 from "@jscad/modeling";
17376
- var { primitives: primitives5, extrusions: extrusions5, geometries: geometries5, modifiers: modifiers4, measurements: measurements5 } = jscad11;
17377
- var generalize5 = modifiers4.generalize;
17378
- var { rectangle: rectangle4, roundedRectangle: roundedRectangle4, polygon: polygon3 } = primitives5;
18263
+ import jscad13 from "@jscad/modeling";
18264
+ var { primitives: primitives6, extrusions: extrusions6, geometries: geometries6, modifiers: modifiers5, measurements: measurements6 } = jscad13;
18265
+ var generalize5 = modifiers5.generalize;
18266
+ var { rectangle: rectangle4, roundedRectangle: roundedRectangle4, polygon: polygon3 } = primitives6;
17379
18267
  function createPushFitPlugGeom(input) {
17380
18268
  const p = pushFitPlugModelPropsSchema.parse(input);
17381
- return extrusions5.extrudeRotate(
18269
+ return extrusions6.extrudeRotate(
17382
18270
  { segments: 64 },
17383
18271
  polygon3({
17384
18272
  points: [
@@ -17397,7 +18285,7 @@ function createPushFitPlugMesh(input) {
17397
18285
  { snap: true, triangulate: true },
17398
18286
  createPushFitPlugGeom(input)
17399
18287
  );
17400
- const epsilon = Math.max(...measurements5.measureDimensions(geom)) * 1e-10;
18288
+ const epsilon = Math.max(...measurements6.measureDimensions(geom)) * 1e-10;
17401
18289
  const positions = [];
17402
18290
  const indices = [];
17403
18291
  const lookup = /* @__PURE__ */ new Map();
@@ -17411,7 +18299,7 @@ function createPushFitPlugMesh(input) {
17411
18299
  }
17412
18300
  return index;
17413
18301
  };
17414
- for (const poly of geometries5.geom3.toPolygons(geom)) {
18302
+ for (const poly of geometries6.geom3.toPolygons(geom)) {
17415
18303
  for (let i = 1; i < poly.vertices.length - 1; i++) {
17416
18304
  const a = poly.vertices[0], b = poly.vertices[i], c = poly.vertices[i + 1];
17417
18305
  const u = b.map((x, j) => x - a[j]), v = c.map((x, j) => x - a[j]);
@@ -17444,11 +18332,11 @@ function register86(registry2) {
17444
18332
  }
17445
18333
 
17446
18334
  // lib/models/rectangularbar/geometry.ts
17447
- import jscad12 from "@jscad/modeling";
17448
- var { primitives: primitives6, extrusions: extrusions6, geometries: geometries6, modifiers: modifiers5, measurements: measurements6 } = jscad12;
17449
- var generalize6 = modifiers5.generalize;
17450
- var { rectangle: rectangle5, roundedRectangle: roundedRectangle5 } = primitives6;
17451
- var profile4 = (shape49, height10) => extrusions6.extrudeLinear({ height: height10 }, shape49);
18335
+ import jscad14 from "@jscad/modeling";
18336
+ var { primitives: primitives7, extrusions: extrusions7, geometries: geometries7, modifiers: modifiers6, measurements: measurements7 } = jscad14;
18337
+ var generalize6 = modifiers6.generalize;
18338
+ var { rectangle: rectangle5, roundedRectangle: roundedRectangle5 } = primitives7;
18339
+ var profile4 = (shape49, height10) => extrusions7.extrudeLinear({ height: height10 }, shape49);
17452
18340
  var roundedRect = (width10, height10, radius) => radius ? roundedRectangle5({
17453
18341
  size: [width10, height10],
17454
18342
  roundRadius: radius,
@@ -17463,7 +18351,7 @@ function createRectangularBarMesh(input) {
17463
18351
  { snap: true, triangulate: true },
17464
18352
  createRectangularBarGeom(input)
17465
18353
  );
17466
- const epsilon = Math.max(...measurements6.measureDimensions(geom)) * 1e-10;
18354
+ const epsilon = Math.max(...measurements7.measureDimensions(geom)) * 1e-10;
17467
18355
  const positions = [];
17468
18356
  const indices = [];
17469
18357
  const lookup = /* @__PURE__ */ new Map();
@@ -17477,7 +18365,7 @@ function createRectangularBarMesh(input) {
17477
18365
  }
17478
18366
  return index;
17479
18367
  };
17480
- for (const poly of geometries6.geom3.toPolygons(geom)) {
18368
+ for (const poly of geometries7.geom3.toPolygons(geom)) {
17481
18369
  for (let i = 1; i < poly.vertices.length - 1; i++) {
17482
18370
  const a = poly.vertices[0], b = poly.vertices[i], c = poly.vertices[i + 1];
17483
18371
  const u = b.map((x, j) => x - a[j]), v = c.map((x, j) => x - a[j]);
@@ -17621,72 +18509,27 @@ function register88(registry2) {
17621
18509
  registry2.register(model88);
17622
18510
  }
17623
18511
 
17624
- // lib/models/rectangulartube/geometry.ts
17625
- import jscad13 from "@jscad/modeling";
17626
- var {
17627
- booleans: booleans3,
17628
- primitives: primitives7,
17629
- extrusions: extrusions7,
17630
- geometries: geometries7,
17631
- modifiers: modifiers6,
17632
- measurements: measurements7
17633
- } = jscad13;
17634
- var generalize7 = modifiers6.generalize;
17635
- var { subtract: subtract2 } = booleans3;
17636
- var { rectangle: rectangle6, roundedRectangle: roundedRectangle6 } = primitives7;
17637
- var profile5 = (shape49, height10) => extrusions7.extrudeLinear({ height: height10 }, shape49);
17638
- var roundedRect2 = (width10, height10, radius) => radius ? roundedRectangle6({
18512
+ // lib/models/rectangulartube/profiles.ts
18513
+ import jscad15 from "@jscad/modeling";
18514
+ var roundedRectangle6 = (width10, height10, radius) => radius ? jscad15.primitives.roundedRectangle({
17639
18515
  size: [width10, height10],
17640
18516
  roundRadius: radius,
17641
18517
  segments: 64
17642
- }) : rectangle6({ size: [width10, height10] });
17643
- function createRectangularTubeGeom(input) {
18518
+ }) : jscad15.primitives.rectangle({ size: [width10, height10] });
18519
+ function getRectangularTubeProfiles(input) {
17644
18520
  const p = rectangularTubeModelPropsSchema.parse(input);
17645
- return profile5(
17646
- subtract2(
17647
- roundedRect2(p.width, p.height, p.outerRadius),
17648
- roundedRect2(
18521
+ const points = (geometry) => jscad15.geometries.geom2.toPoints(geometry);
18522
+ return {
18523
+ length: p.length,
18524
+ outerPoints: points(roundedRectangle6(p.width, p.height, p.outerRadius)),
18525
+ innerPoints: points(
18526
+ roundedRectangle6(
17649
18527
  p.width - 2 * p.wallThickness,
17650
18528
  p.height - 2 * p.wallThickness,
17651
18529
  p.innerRadius
17652
18530
  )
17653
- ),
17654
- p.length
17655
- );
17656
- }
17657
- function createRectangularTubeMesh(input) {
17658
- const geom = generalize7(
17659
- { snap: true, triangulate: true },
17660
- createRectangularTubeGeom(input)
17661
- );
17662
- const epsilon = Math.max(...measurements7.measureDimensions(geom)) * 1e-10;
17663
- const positions = [];
17664
- const indices = [];
17665
- const lookup = /* @__PURE__ */ new Map();
17666
- const vertex = (v) => {
17667
- const key = v.map((x) => Math.round(x / epsilon)).join(",");
17668
- let index = lookup.get(key);
17669
- if (index === void 0) {
17670
- index = positions.length / 3;
17671
- positions.push(...v);
17672
- lookup.set(key, index);
17673
- }
17674
- return index;
18531
+ )
17675
18532
  };
17676
- for (const poly of geometries7.geom3.toPolygons(geom)) {
17677
- for (let i = 1; i < poly.vertices.length - 1; i++) {
17678
- const a = poly.vertices[0], b = poly.vertices[i], c = poly.vertices[i + 1];
17679
- const u = b.map((x, j) => x - a[j]), v = c.map((x, j) => x - a[j]);
17680
- const area = Math.hypot(
17681
- u[1] * v[2] - u[2] * v[1],
17682
- u[2] * v[0] - u[0] * v[2],
17683
- u[0] * v[1] - u[1] * v[0]
17684
- );
17685
- if (area > epsilon * epsilon)
17686
- indices.push(vertex(a), vertex(b), vertex(c));
17687
- }
17688
- }
17689
- return { positions, indices };
17690
18533
  }
17691
18534
 
17692
18535
  // lib/models/rectangulartube/RectangularTube.tsx
@@ -17694,7 +18537,27 @@ function RectangularTube({
17694
18537
  color = "#929da9",
17695
18538
  ...props
17696
18539
  }) {
17697
- return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsx(Custom, { geometry: createRectangularTubeGeom(props) }) });
18540
+ const { length: length32, outerPoints, innerPoints } = getRectangularTubeProfiles(props);
18541
+ return /* @__PURE__ */ jsx(Colorize, { color, children: /* @__PURE__ */ jsxs(Subtract, { children: [
18542
+ /* @__PURE__ */ jsx(
18543
+ ExtrudeLinear,
18544
+ {
18545
+ height: length32,
18546
+ topOutlineName: "outer_top",
18547
+ bottomOutlineName: "outer_bottom",
18548
+ children: /* @__PURE__ */ jsx(Polygon, { points: outerPoints })
18549
+ }
18550
+ ),
18551
+ /* @__PURE__ */ jsx(
18552
+ ExtrudeLinear,
18553
+ {
18554
+ height: length32,
18555
+ topOutlineName: "inner_top",
18556
+ bottomOutlineName: "inner_bottom",
18557
+ children: /* @__PURE__ */ jsx(Polygon, { points: innerPoints })
18558
+ }
18559
+ )
18560
+ ] }) });
17698
18561
  }
17699
18562
 
17700
18563
  // lib/models/rectangulartube/register.tsx
@@ -17939,7 +18802,7 @@ function holeOutline(hole) {
17939
18802
  function createSheetMetalMesh(input) {
17940
18803
  const props = sheetMetalModelPropsSchema.parse(input);
17941
18804
  const { width: width10, baseLength, flangeHeight, thickness } = props;
17942
- const profile6 = props.channel ? "channel" : props.angle ? "angle" : "plate";
18805
+ const profile5 = props.channel ? "channel" : props.angle ? "angle" : "plate";
17943
18806
  const radius = props.insideBendRadius + thickness / 2;
17944
18807
  const positions = [];
17945
18808
  const indices = [];
@@ -17952,10 +18815,10 @@ function createSheetMetalMesh(input) {
17952
18815
  addTriangle([vertices[0], vertices[1], vertices[2]], reverse);
17953
18816
  addTriangle([vertices[0], vertices[2], vertices[3]], reverse);
17954
18817
  };
17955
- const panels = profile6 === "plate" ? ["base"] : profile6 === "angle" ? ["base", "right"] : ["base", "left", "right"];
18818
+ const panels = profile5 === "plate" ? ["base"] : profile5 === "angle" ? ["base", "right"] : ["base", "left", "right"];
17956
18819
  for (const hole of props.holes) {
17957
18820
  if (!panels.includes(hole.panel))
17958
- throw new Error(`No ${hole.panel} panel on ${profile6}`);
18821
+ throw new Error(`No ${hole.panel} panel on ${profile5}`);
17959
18822
  }
17960
18823
  for (const panel of panels) {
17961
18824
  const length32 = panel === "base" ? baseLength : flangeHeight;
@@ -18006,7 +18869,7 @@ function createSheetMetalMesh(input) {
18006
18869
  for (const [loopIndex, loop] of loops.entries())
18007
18870
  for (let i = 0; i < loop.length; i++) {
18008
18871
  const a = loop[i], b = loop[(i + 1) % loop.length];
18009
- if (loopIndex === 0 && a.u === b.u && (panel === "base" && (a.u > 0 && profile6 !== "plate" || a.u < 0 && profile6 === "channel") || panel !== "base" && a.u < 0))
18872
+ if (loopIndex === 0 && a.u === b.u && (panel === "base" && (a.u > 0 && profile5 !== "plate" || a.u < 0 && profile5 === "channel") || panel !== "base" && a.u < 0))
18010
18873
  continue;
18011
18874
  addQuad(
18012
18875
  [
@@ -18019,7 +18882,7 @@ function createSheetMetalMesh(input) {
18019
18882
  );
18020
18883
  }
18021
18884
  }
18022
- const sides = profile6 === "plate" ? [] : profile6 === "angle" ? [1] : [-1, 1];
18885
+ const sides = profile5 === "plate" ? [] : profile5 === "angle" ? [1] : [-1, 1];
18023
18886
  for (const side of sides) {
18024
18887
  const project = (angle, crossSection) => {
18025
18888
  const r = radius - crossSection.offset;
@@ -18618,7 +19481,7 @@ function register100(registry2) {
18618
19481
  }
18619
19482
 
18620
19483
  // lib/models/tslotcoverstrip/geometry.ts
18621
- import jscad16 from "@jscad/modeling";
19484
+ import jscad18 from "@jscad/modeling";
18622
19485
  var {
18623
19486
  primitives: primitives8,
18624
19487
  extrusions: extrusions8,
@@ -18626,8 +19489,8 @@ var {
18626
19489
  geometries: geometries8,
18627
19490
  modifiers: modifiers7,
18628
19491
  measurements: measurements8
18629
- } = jscad16;
18630
- var generalize8 = modifiers7.generalize;
19492
+ } = jscad18;
19493
+ var generalize7 = modifiers7.generalize;
18631
19494
  function createTSlotCoverStripGeom(input) {
18632
19495
  const p = tSlotCoverStripModelPropsSchema.parse(input);
18633
19496
  const w = p.width / 2;
@@ -18654,7 +19517,7 @@ function createTSlotCoverStripGeom(input) {
18654
19517
  return extrusions8.extrudeLinear({ height: p.length }, outline);
18655
19518
  }
18656
19519
  function createTSlotCoverStripMesh(input) {
18657
- const geom = generalize8(
19520
+ const geom = generalize7(
18658
19521
  { snap: false, triangulate: true },
18659
19522
  createTSlotCoverStripGeom(input)
18660
19523
  );
@@ -18908,10 +19771,10 @@ function register104(registry2) {
18908
19771
  }
18909
19772
 
18910
19773
  // lib/models/ufl/geometry.ts
18911
- import jscad17 from "@jscad/modeling";
19774
+ import jscad19 from "@jscad/modeling";
18912
19775
  function createUflGeometries(input = {}) {
18913
19776
  const d = getUflDimensions(input);
18914
- const { booleans: booleans5, primitives: primitives9 } = jscad17;
19777
+ const { booleans: booleans5, primitives: primitives9 } = jscad19;
18915
19778
  const silver = "#bcbfc3";
18916
19779
  const dielectric = "#eee9d5";
18917
19780
  const gold = "#d9b45b";
@@ -19068,17 +19931,17 @@ var createWormGearMesh = (input) => {
19068
19931
  fractions.push(fraction);
19069
19932
  }
19070
19933
  }
19071
- const profile6 = [];
19934
+ const profile5 = [];
19072
19935
  for (let start = 0; start < props.starts; start++) {
19073
19936
  for (const fraction of fractions) {
19074
19937
  const distance2 = Math.min(fraction, 1 - fraction) * axialPitch;
19075
- profile6.push({
19938
+ profile5.push({
19076
19939
  angle: (start + fraction) * Math.PI * 2 / props.starts,
19077
19940
  radius: distance2 <= tipHalfWidth ? outsideRadius : distance2 >= rootHalfWidth ? rootRadius : pitchRadius + (toothThickness / 2 - distance2) / pressureTangent
19078
19941
  });
19079
19942
  }
19080
19943
  }
19081
- const count = profile6.length;
19944
+ const count = profile5.length;
19082
19945
  const positions = [];
19083
19946
  const indices = [];
19084
19947
  const phase = props.phase % 360 * Math.PI / 180;
@@ -19086,7 +19949,7 @@ var createWormGearMesh = (input) => {
19086
19949
  const ring = (z) => {
19087
19950
  const first = positions.length / 3;
19088
19951
  const rotation = phase + direction * (z / lead) * Math.PI * 2;
19089
- for (const sample of profile6) {
19952
+ for (const sample of profile5) {
19090
19953
  const angle = sample.angle + rotation;
19091
19954
  positions.push(
19092
19955
  sample.radius * Math.cos(angle),
@@ -27589,185 +28452,6 @@ var Footprinter3d = ({ footprint }) => {
27589
28452
  return null;
27590
28453
  };
27591
28454
 
27592
- // lib/vanilla/render.ts
27593
- var isVNode = (n) => n && typeof n === "object" && "type" in n;
27594
- var degToRad = (v) => {
27595
- if (typeof v === "number") return v;
27596
- if (typeof v === "string") {
27597
- const m = /^(-?\d+(?:\.\d+)?)\s*deg$/i.exec(v);
27598
- if (m) return parseFloat(m[1]) * Math.PI / 180;
27599
- const n = Number(v);
27600
- if (!Number.isNaN(n)) return n;
27601
- }
27602
- return 0;
27603
- };
27604
- var toVec3 = (v) => {
27605
- if (Array.isArray(v))
27606
- return [Number(v[0]) || 0, Number(v[1]) || 0, Number(v[2]) || 0];
27607
- if (typeof v === "object" && v)
27608
- return [Number(v.x) || 0, Number(v.y) || 0, Number(v.z) || 0];
27609
- return [0, 0, 0];
27610
- };
27611
- function renderNode(node, colorCtx, renderCtx) {
27612
- const {
27613
- jscad: { primitives: primitives9, booleans: booleans5, hulls, geometries: geometries9, extrusions: extrusions9, transforms: transforms2 }
27614
- } = renderCtx;
27615
- if (node == null || node === false) return [];
27616
- if (Array.isArray(node))
27617
- return node.flatMap((n) => renderNode(n, colorCtx, renderCtx));
27618
- if (!isVNode(node)) return [];
27619
- const { type, props, children } = node;
27620
- if (props?.material) {
27621
- const { material, ...rest } = props;
27622
- return renderNode({ ...node, props: rest }, colorCtx, renderCtx).map(
27623
- (entry) => ({
27624
- ...entry,
27625
- material: { ...material },
27626
- geom: { ...entry.geom, material: { ...material } }
27627
- })
27628
- );
27629
- }
27630
- if (type === Fragment) {
27631
- return (children ?? []).flatMap((c) => renderNode(c, colorCtx, renderCtx));
27632
- }
27633
- if (type === Colorize) {
27634
- const newColor = props?.color;
27635
- return (children ?? []).flatMap(
27636
- (c) => renderNode(c, newColor ?? colorCtx, renderCtx)
27637
- );
27638
- }
27639
- if (type === Translate) {
27640
- const off = toVec3(
27641
- props?.offset ?? props?.center ?? { x: props?.x, y: props?.y, z: props?.z }
27642
- );
27643
- const geoms = (children ?? []).flatMap(
27644
- (c) => renderNode(c, colorCtx, renderCtx)
27645
- );
27646
- return geoms.map(({ geom, color, material }) => ({
27647
- material,
27648
- geom: transforms2.translate(off, geom),
27649
- color: color ?? colorCtx
27650
- }));
27651
- }
27652
- if (type === Rotate) {
27653
- const angles = props?.angles ?? props?.rotation;
27654
- const rot = Array.isArray(angles) ? [degToRad(angles[0]), degToRad(angles[1]), degToRad(angles[2])] : [
27655
- degToRad(props?.x ?? 0),
27656
- degToRad(props?.y ?? 0),
27657
- degToRad(props?.z ?? 0)
27658
- ];
27659
- const geoms = (children ?? []).flatMap(
27660
- (c) => renderNode(c, colorCtx, renderCtx)
27661
- );
27662
- return geoms.map(({ geom, color, material }) => ({
27663
- material,
27664
- geom: transforms2.rotateZ(
27665
- rot[2],
27666
- transforms2.rotateY(rot[1], transforms2.rotateX(rot[0], geom))
27667
- ),
27668
- color
27669
- }));
27670
- }
27671
- if (type === Union || type === Subtract || type === Hull) {
27672
- const entries = (children ?? []).flatMap(
27673
- (c) => renderNode(c, colorCtx, renderCtx)
27674
- );
27675
- const geoms = entries.map((g) => g.geom);
27676
- if (geoms.length === 0) return [];
27677
- let geom;
27678
- if (type === Union) geom = booleans5.union(geoms);
27679
- else if (type === Subtract)
27680
- geom = booleans5.subtract(geoms[0], geoms.slice(1));
27681
- else geom = hulls.hull(geoms);
27682
- return [
27683
- {
27684
- geom,
27685
- color: colorCtx,
27686
- material: type === Subtract ? entries[0]?.material : void 0
27687
- }
27688
- ];
27689
- }
27690
- if (type === Custom) {
27691
- return [{ geom: props.geometry, color: colorCtx }];
27692
- }
27693
- if (type === Polygon) {
27694
- const points = props?.points ?? [];
27695
- const g2 = geometries9.geom2.fromPoints(points);
27696
- return [{ geom: g2, color: colorCtx ?? props?.color }];
27697
- }
27698
- if (type === ExtrudeLinear) {
27699
- const entries = (children ?? []).flatMap(
27700
- (c) => renderNode(c, colorCtx, renderCtx)
27701
- );
27702
- const geoms2 = entries.map((g) => g.geom);
27703
- if (geoms2.length === 0) return [];
27704
- const base2 = geoms2.length > 1 ? booleans5.union(geoms2) : geoms2[0];
27705
- const height10 = props?.height ?? props?.h ?? 1;
27706
- let g3 = extrusions9.extrudeLinear({ height: height10 }, base2);
27707
- if (g3.polygons) {
27708
- for (const poly of g3.polygons) {
27709
- if (!poly.plane || !poly.vertices || poly.vertices.length < 3) continue;
27710
- poly.vertices.reverse();
27711
- }
27712
- }
27713
- return [
27714
- {
27715
- geom: g3,
27716
- color: colorCtx ?? props?.color,
27717
- material: entries.length === 1 ? entries[0]?.material : void 0
27718
- }
27719
- ];
27720
- }
27721
- if (type === Cuboid || type === Cube || type === Cylinder || type === Sphere || type === RoundedCuboid || type === RoundedCylinder) {
27722
- let g;
27723
- if (type === Cuboid) {
27724
- const size = props?.size ?? [1, 1, 1];
27725
- const offset = props?.offset;
27726
- const center = props?.center ?? (offset ? [offset[0], offset[1], offset[2]] : [0, 0, 0]);
27727
- g = primitives9.cuboid({ size, center });
27728
- } else if (type === Cube) {
27729
- const size = props?.size ?? 1;
27730
- const offset = props?.offset;
27731
- const center = props?.center ?? (offset ? [offset[0], offset[1], offset[2]] : [0, 0, 0]);
27732
- g = primitives9.cube({ size, center });
27733
- } else if (type === Cylinder) {
27734
- const height10 = props?.height ?? 1;
27735
- const radius = props?.radius ?? 1;
27736
- const center = props?.center ?? [0, 0, 0];
27737
- g = primitives9.cylinder({ height: height10, radius, center });
27738
- } else if (type === Sphere) {
27739
- const radius = props?.radius ?? 1;
27740
- const center = props?.center ?? [0, 0, 0];
27741
- g = primitives9.sphere({ radius, center });
27742
- } else if (type === RoundedCylinder) {
27743
- const height10 = props?.height ?? 1;
27744
- const radius = props?.radius ?? 1;
27745
- const roundRadius = props?.roundRadius ?? 0.1;
27746
- const center = props?.center ?? [0, 0, 0];
27747
- g = primitives9.roundedCylinder({ height: height10, radius, roundRadius, center });
27748
- } else {
27749
- const size = props?.size ?? [1, 1, 1];
27750
- const roundRadius = props?.roundRadius ?? 0.1;
27751
- const center = props?.center ?? [0, 0, 0];
27752
- g = primitives9.roundedCuboid({ size, roundRadius, center });
27753
- }
27754
- return [{ geom: g, color: colorCtx ?? props?.color }];
27755
- }
27756
- if (typeof type === "function") {
27757
- const out = type(props ?? {});
27758
- return renderNode(out, colorCtx, renderCtx);
27759
- }
27760
- return (children ?? []).flatMap((c) => renderNode(c, colorCtx, renderCtx));
27761
- }
27762
- function render(root, jscad18) {
27763
- const geometries9 = renderNode(root, void 0, { jscad: jscad18 });
27764
- return {
27765
- geometries: geometries9.map(
27766
- (entry) => entry.material ? { ...entry, geom: { ...entry.geom, material: entry.material } } : entry
27767
- )
27768
- };
27769
- }
27770
-
27771
28455
  // lib/vanilla/convertCSGToThreeGeom.ts
27772
28456
  import {
27773
28457
  BufferAttribute,
@@ -27778,16 +28462,16 @@ function convertCSGToThreeGeom(csg) {
27778
28462
  if (csg.polygons) {
27779
28463
  const vertices = [];
27780
28464
  const indices = [];
27781
- const colors = [];
28465
+ const colors2 = [];
27782
28466
  let idx = 0;
27783
28467
  for (const polygon4 of csg.polygons) {
27784
28468
  for (const vertex of polygon4.vertices) {
27785
28469
  vertex.index = idx;
27786
28470
  vertices.push(vertex[0], vertex[1], vertex[2]);
27787
28471
  if (csg.color && csg.color.length >= 3) {
27788
- colors.push(csg.color[0], csg.color[1], csg.color[2]);
28472
+ colors2.push(csg.color[0], csg.color[1], csg.color[2]);
27789
28473
  } else {
27790
- colors.push(1, 1, 1);
28474
+ colors2.push(1, 1, 1);
27791
28475
  }
27792
28476
  idx++;
27793
28477
  }
@@ -27804,29 +28488,29 @@ function convertCSGToThreeGeom(csg) {
27804
28488
  new BufferAttribute(new Float32Array(vertices), 3)
27805
28489
  );
27806
28490
  geo.setIndex(indices);
27807
- if (colors.length > 0) {
28491
+ if (colors2.length > 0) {
27808
28492
  geo.setAttribute(
27809
28493
  "color",
27810
- new BufferAttribute(new Float32Array(colors), 3)
28494
+ new BufferAttribute(new Float32Array(colors2), 3)
27811
28495
  );
27812
28496
  }
27813
28497
  if (csg.transforms) {
27814
- const transforms2 = new Matrix4();
27815
- transforms2.fromArray(csg.transforms);
27816
- geo.applyMatrix4(transforms2);
28498
+ const transforms3 = new Matrix4();
28499
+ transforms3.fromArray(csg.transforms);
28500
+ geo.applyMatrix4(transforms3);
27817
28501
  }
27818
28502
  geo.computeVertexNormals();
27819
28503
  return geo;
27820
28504
  }
27821
28505
  if (csg.sides) {
27822
28506
  const vertices = [];
27823
- const colors = [];
28507
+ const colors2 = [];
27824
28508
  for (const side of csg.sides) {
27825
28509
  vertices.push(side[0][0], side[0][1], 0);
27826
28510
  if (csg.color && csg.color.length >= 3) {
27827
- colors.push(csg.color[0], csg.color[1], csg.color[2]);
28511
+ colors2.push(csg.color[0], csg.color[1], csg.color[2]);
27828
28512
  } else {
27829
- colors.push(1, 1, 1);
28513
+ colors2.push(1, 1, 1);
27830
28514
  }
27831
28515
  }
27832
28516
  const geo = new BufferGeometry();
@@ -27834,16 +28518,16 @@ function convertCSGToThreeGeom(csg) {
27834
28518
  "position",
27835
28519
  new BufferAttribute(new Float32Array(vertices), 3)
27836
28520
  );
27837
- if (colors.length > 0) {
28521
+ if (colors2.length > 0) {
27838
28522
  geo.setAttribute(
27839
28523
  "color",
27840
- new BufferAttribute(new Float32Array(colors), 3)
28524
+ new BufferAttribute(new Float32Array(colors2), 3)
27841
28525
  );
27842
28526
  }
27843
28527
  if (csg.transforms) {
27844
- const transforms2 = new Matrix4();
27845
- transforms2.fromArray(csg.transforms);
27846
- geo.applyMatrix4(transforms2);
28528
+ const transforms3 = new Matrix4();
28529
+ transforms3.fromArray(csg.transforms);
28530
+ geo.applyMatrix4(transforms3);
27847
28531
  }
27848
28532
  return geo;
27849
28533
  }
@@ -27851,25 +28535,104 @@ function convertCSGToThreeGeom(csg) {
27851
28535
  return new BufferGeometry();
27852
28536
  }
27853
28537
 
28538
+ // lib/named-edges.ts
28539
+ import jscad20 from "@jscad/modeling";
28540
+ function listJscadNamedEdges(model108) {
28541
+ return listJscadReferenceFeatures(model108).filter((name) => {
28542
+ const { geometry } = model108.referenceFeatures[name];
28543
+ return jscad20.geometries.geom2.isA(geometry) || jscad20.geometries.path2.isA(geometry);
28544
+ });
28545
+ }
28546
+ function listJscadReferenceFeatures(model108) {
28547
+ return Object.keys(model108.referenceFeatures);
28548
+ }
28549
+ function readJscadReferenceFeature(model108, name) {
28550
+ if (!Object.hasOwn(model108.referenceFeatures, name))
28551
+ throw new Error(`JSCAD model does not define named feature "${name}"`);
28552
+ return model108.referenceFeatures[name];
28553
+ }
28554
+ function readJscadNamedEdge(model108, name) {
28555
+ const { geometry: feature, matrix } = readJscadReferenceFeature(model108, name);
28556
+ if (matrix.length !== 16 || !matrix.every(Number.isFinite))
28557
+ throw new Error(
28558
+ `Named JSCAD feature "${name}" requires a finite 4x4 matrix`
28559
+ );
28560
+ let points;
28561
+ let closed;
28562
+ if (jscad20.geometries.path2.isA(feature)) {
28563
+ const path = jscad20.geometries.path2.clone(feature);
28564
+ points = jscad20.geometries.path2.toPoints(path);
28565
+ closed = path.isClosed;
28566
+ } else if (jscad20.geometries.geom2.isA(feature)) {
28567
+ const outlines = jscad20.geometries.geom2.toOutlines(
28568
+ jscad20.geometries.geom2.clone(feature)
28569
+ );
28570
+ if (outlines.length !== 1)
28571
+ throw new Error(
28572
+ `Named JSCAD edge "${name}" must identify one contour; name its boundaries separately`
28573
+ );
28574
+ points = outlines[0];
28575
+ closed = true;
28576
+ } else {
28577
+ throw new Error(
28578
+ `Named JSCAD edge "${name}" is not a geom2 or path2 feature`
28579
+ );
28580
+ }
28581
+ if (points.length < 2)
28582
+ throw new Error(`Named JSCAD edge "${name}" has no measurable path`);
28583
+ return {
28584
+ points: points.map(([x, y]) => {
28585
+ const point = jscad20.maths.vec3.transform(
28586
+ jscad20.maths.vec3.create(),
28587
+ [x, y, 0],
28588
+ matrix
28589
+ );
28590
+ return { x: point[0], y: point[1], z: point[2] };
28591
+ }),
28592
+ closed
28593
+ };
28594
+ }
28595
+
28596
+ // lib/models/rectangulartube/model.tsx
28597
+ import jscad21 from "@jscad/modeling";
28598
+ function createRectangularTubeModel(input) {
28599
+ const model108 = renderToJscadModel(
28600
+ /* @__PURE__ */ jsx(RectangularTube, { ...input }),
28601
+ jscad21
28602
+ );
28603
+ if (model108.geometries.length !== 1 || !jscad21.geometries.geom3.isA(model108.geometries[0]))
28604
+ throw new Error("RectangularTube must render exactly one native solid");
28605
+ return model108;
28606
+ }
28607
+
28608
+ // lib/models/rectangulartube/geometry.ts
28609
+ function createRectangularTubeGeom(input) {
28610
+ const model108 = createRectangularTubeModel(input);
28611
+ return model108.geometries[0];
28612
+ }
28613
+ function createRectangularTubeMesh(input) {
28614
+ return geom3ToIndexedMesh(createRectangularTubeGeom(input));
28615
+ }
28616
+
27854
28617
  // lib/vanilla/index.ts
27855
- function getJscadModelForFootprint(footprint, jscad18) {
28618
+ function getJscadModelForFootprint(footprint, jscad22) {
27856
28619
  const vnode = h(Footprinter3d, { footprint });
27857
- return render(vnode, jscad18);
28620
+ return render(vnode, jscad22);
27858
28621
  }
27859
- function getJscadModelForFootprintWithPads(footprint, jscad18) {
28622
+ function getJscadModelForFootprintWithPads(footprint, jscad22) {
27860
28623
  const vnode = h(
27861
28624
  Fragment,
27862
28625
  {},
27863
28626
  h(Footprinter3d, { footprint }),
27864
28627
  h(ExtrudedPads, { footprint })
27865
28628
  );
27866
- return render(vnode, jscad18);
28629
+ return render(vnode, jscad22);
27867
28630
  }
27868
- function createJSCADRenderer(jscad18) {
28631
+ function createJSCADRenderer(jscad22) {
27869
28632
  function createJSCADRoot(container) {
27870
28633
  return {
27871
28634
  render(element) {
27872
- const { geometries: geometries9 } = render(element, jscad18);
28635
+ const { geometries: geometries9 } = render(element, jscad22);
27873
28636
  container.splice(0, container.length, ...geometries9);
27874
28637
  }
27875
28638
  };
@@ -28004,6 +28767,7 @@ export {
28004
28767
  createRectangularGasketMesh,
28005
28768
  createRectangularTubeGeom,
28006
28769
  createRectangularTubeMesh,
28770
+ createRectangularTubeModel,
28007
28771
  createRigidCouplerGeom,
28008
28772
  createRigidCouplerMesh,
28009
28773
  createSetScrewGeom,
@@ -28039,8 +28803,14 @@ export {
28039
28803
  createWormGearMesh,
28040
28804
  createZeeBarGeom,
28041
28805
  createZeeBarMesh,
28806
+ geom3ToIndexedMesh,
28042
28807
  getJscadModelForFootprint,
28043
28808
  getJscadModelForFootprintWithPads,
28044
- h
28809
+ h,
28810
+ listJscadNamedEdges,
28811
+ listJscadReferenceFeatures,
28812
+ readJscadNamedEdge,
28813
+ readJscadReferenceFeature,
28814
+ renderToJscadModel
28045
28815
  };
28046
28816
  //# sourceMappingURL=vanilla.js.map