@tscircuit/3d-viewer 0.0.604 → 0.0.606

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.
Files changed (2) hide show
  1. package/dist/index.js +1723 -477
  2. package/package.json +7 -6
package/dist/index.js CHANGED
@@ -215,8 +215,8 @@ var require_invert = __commonJS({
215
215
  var require_equals = __commonJS({
216
216
  "node_modules/@jscad/modeling/src/maths/mat4/equals.js"(exports, module) {
217
217
  "use strict";
218
- var equals = (a, b) => a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
219
- module.exports = equals;
218
+ var equals2 = (a, b) => a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15];
219
+ module.exports = equals2;
220
220
  }
221
221
  });
222
222
 
@@ -225,11 +225,11 @@ var require_constants = __commonJS({
225
225
  "node_modules/@jscad/modeling/src/maths/constants.js"(exports, module) {
226
226
  "use strict";
227
227
  var spatialResolution = 1e5;
228
- var EPS = 1e-5;
228
+ var EPS3 = 1e-5;
229
229
  var NEPS = 1e-13;
230
230
  var TAU = Math.PI * 2;
231
231
  module.exports = {
232
- EPS,
232
+ EPS: EPS3,
233
233
  NEPS,
234
234
  TAU,
235
235
  spatialResolution
@@ -280,13 +280,13 @@ var require_identity = __commonJS({
280
280
  var require_fromRotation = __commonJS({
281
281
  "node_modules/@jscad/modeling/src/maths/mat4/fromRotation.js"(exports, module) {
282
282
  "use strict";
283
- var { EPS } = require_constants();
283
+ var { EPS: EPS3 } = require_constants();
284
284
  var { sin, cos } = require_trigonometry();
285
285
  var identity = require_identity();
286
286
  var fromRotation = (out, rad, axis) => {
287
287
  let [x, y, z42] = axis;
288
288
  const lengthSquared = x * x + y * y + z42 * z42;
289
- if (Math.abs(lengthSquared) < EPS) {
289
+ if (Math.abs(lengthSquared) < EPS3) {
290
290
  return identity(out);
291
291
  }
292
292
  const len = 1 / Math.sqrt(lengthSquared);
@@ -585,8 +585,8 @@ var require_divide = __commonJS({
585
585
  var require_equals2 = __commonJS({
586
586
  "node_modules/@jscad/modeling/src/maths/vec3/equals.js"(exports, module) {
587
587
  "use strict";
588
- var equals = (a, b) => a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
589
- module.exports = equals;
588
+ var equals2 = (a, b) => a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
589
+ module.exports = equals2;
590
590
  }
591
591
  });
592
592
 
@@ -1213,13 +1213,13 @@ var require_multiply2 = __commonJS({
1213
1213
  var require_rotate = __commonJS({
1214
1214
  "node_modules/@jscad/modeling/src/maths/mat4/rotate.js"(exports, module) {
1215
1215
  "use strict";
1216
- var { EPS } = require_constants();
1216
+ var { EPS: EPS3 } = require_constants();
1217
1217
  var { sin, cos } = require_trigonometry();
1218
1218
  var copy = require_copy();
1219
1219
  var rotate2 = (out, matrix, radians, axis) => {
1220
1220
  let [x, y, z42] = axis;
1221
1221
  const lengthSquared = x * x + y * y + z42 * z42;
1222
- if (Math.abs(lengthSquared) < EPS) {
1222
+ if (Math.abs(lengthSquared) < EPS3) {
1223
1223
  return copy(out, matrix);
1224
1224
  }
1225
1225
  const len = 1 / Math.sqrt(lengthSquared);
@@ -1720,8 +1720,8 @@ var require_dot2 = __commonJS({
1720
1720
  var require_equals3 = __commonJS({
1721
1721
  "node_modules/@jscad/modeling/src/maths/vec2/equals.js"(exports, module) {
1722
1722
  "use strict";
1723
- var equals = (a, b) => a[0] === b[0] && a[1] === b[1];
1724
- module.exports = equals;
1723
+ var equals2 = (a, b) => a[0] === b[0] && a[1] === b[1];
1724
+ module.exports = equals2;
1725
1725
  }
1726
1726
  });
1727
1727
 
@@ -2431,12 +2431,12 @@ var require_point_line_distance = __commonJS({
2431
2431
  const cr = [];
2432
2432
  subtract4(ab, b, a);
2433
2433
  subtract4(ap, p, a);
2434
- const area = squaredLength(cross(cr, ap, ab));
2434
+ const area2 = squaredLength(cross(cr, ap, ab));
2435
2435
  const s = squaredLength(ab);
2436
2436
  if (s === 0) {
2437
2437
  throw Error("a and b are the same point");
2438
2438
  }
2439
- return area / s;
2439
+ return area2 / s;
2440
2440
  };
2441
2441
  var pointLineDistance = (point, a, b) => Math.sqrt(distanceSquared(point, a, b));
2442
2442
  module.exports = pointLineDistance;
@@ -3540,8 +3540,8 @@ var require_copy4 = __commonJS({
3540
3540
  var require_equals4 = __commonJS({
3541
3541
  "node_modules/@jscad/modeling/src/maths/vec4/equals.js"(exports, module) {
3542
3542
  "use strict";
3543
- var equals = (a, b) => a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
3544
- module.exports = equals;
3543
+ var equals2 = (a, b) => a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
3544
+ module.exports = equals2;
3545
3545
  }
3546
3546
  });
3547
3547
 
@@ -3708,19 +3708,19 @@ var require_fromPoints3 = __commonJS({
3708
3708
  var require_fromPointsRandom = __commonJS({
3709
3709
  "node_modules/@jscad/modeling/src/maths/plane/fromPointsRandom.js"(exports, module) {
3710
3710
  "use strict";
3711
- var { EPS } = require_constants();
3711
+ var { EPS: EPS3 } = require_constants();
3712
3712
  var vec3 = require_vec3();
3713
3713
  var fromPointsRandom = (out, a, b, c) => {
3714
3714
  let ba = vec3.subtract(vec3.create(), b, a);
3715
3715
  let ca = vec3.subtract(vec3.create(), c, a);
3716
- if (vec3.length(ba) < EPS) {
3716
+ if (vec3.length(ba) < EPS3) {
3717
3717
  ba = vec3.orthogonal(ba, ca);
3718
3718
  }
3719
- if (vec3.length(ca) < EPS) {
3719
+ if (vec3.length(ca) < EPS3) {
3720
3720
  ca = vec3.orthogonal(ca, ba);
3721
3721
  }
3722
3722
  let normal = vec3.cross(vec3.create(), ba, ca);
3723
- if (vec3.length(normal) < EPS) {
3723
+ if (vec3.length(normal) < EPS3) {
3724
3724
  ca = vec3.orthogonal(ca, ba);
3725
3725
  normal = vec3.cross(normal, ba, ca);
3726
3726
  }
@@ -3960,7 +3960,7 @@ var require_measureArea = __commonJS({
3960
3960
  } else if (ay > az) {
3961
3961
  coord = 2;
3962
3962
  }
3963
- let area = 0;
3963
+ let area2 = 0;
3964
3964
  let h2 = 0;
3965
3965
  let i = 1;
3966
3966
  let j = 2;
@@ -3969,19 +3969,19 @@ var require_measureArea = __commonJS({
3969
3969
  for (i = 1; i < n; i++) {
3970
3970
  h2 = i - 1;
3971
3971
  j = (i + 1) % n;
3972
- area += vertices[i][1] * (vertices[j][2] - vertices[h2][2]);
3972
+ area2 += vertices[i][1] * (vertices[j][2] - vertices[h2][2]);
3973
3973
  }
3974
- area += vertices[0][1] * (vertices[1][2] - vertices[n - 1][2]);
3975
- area /= 2 * normal[0];
3974
+ area2 += vertices[0][1] * (vertices[1][2] - vertices[n - 1][2]);
3975
+ area2 /= 2 * normal[0];
3976
3976
  break;
3977
3977
  case 2:
3978
3978
  for (i = 1; i < n; i++) {
3979
3979
  h2 = i - 1;
3980
3980
  j = (i + 1) % n;
3981
- area += vertices[i][2] * (vertices[j][0] - vertices[h2][0]);
3981
+ area2 += vertices[i][2] * (vertices[j][0] - vertices[h2][0]);
3982
3982
  }
3983
- area += vertices[0][2] * (vertices[1][0] - vertices[n - 1][0]);
3984
- area /= 2 * normal[1];
3983
+ area2 += vertices[0][2] * (vertices[1][0] - vertices[n - 1][0]);
3984
+ area2 /= 2 * normal[1];
3985
3985
  break;
3986
3986
  case 3:
3987
3987
  // ignore Z coordinates
@@ -3989,13 +3989,13 @@ var require_measureArea = __commonJS({
3989
3989
  for (i = 1; i < n; i++) {
3990
3990
  h2 = i - 1;
3991
3991
  j = (i + 1) % n;
3992
- area += vertices[i][0] * (vertices[j][1] - vertices[h2][1]);
3992
+ area2 += vertices[i][0] * (vertices[j][1] - vertices[h2][1]);
3993
3993
  }
3994
- area += vertices[0][0] * (vertices[1][1] - vertices[n - 1][1]);
3995
- area /= 2 * normal[2];
3994
+ area2 += vertices[0][0] * (vertices[1][1] - vertices[n - 1][1]);
3995
+ area2 /= 2 * normal[2];
3996
3996
  break;
3997
3997
  }
3998
- return area;
3998
+ return area2;
3999
3999
  };
4000
4000
  module.exports = measureArea;
4001
4001
  }
@@ -4403,7 +4403,7 @@ var require_isA3 = __commonJS({
4403
4403
  var require_isConvex2 = __commonJS({
4404
4404
  "node_modules/@jscad/modeling/src/geometries/geom3/isConvex.js"(exports, module) {
4405
4405
  "use strict";
4406
- var { EPS } = require_constants();
4406
+ var { EPS: EPS3 } = require_constants();
4407
4407
  var vec3 = require_vec3();
4408
4408
  var geom3 = require_isA3();
4409
4409
  var toPolygons = require_toPolygons();
@@ -4434,7 +4434,7 @@ var require_isConvex2 = __commonJS({
4434
4434
  for (let j = 0; j < vertices.length; j++) {
4435
4435
  const v = vertices[j];
4436
4436
  const distance6 = vec3.dot(plane, v) - plane[3];
4437
- if (distance6 > EPS) {
4437
+ if (distance6 > EPS3) {
4438
4438
  return false;
4439
4439
  }
4440
4440
  }
@@ -4626,7 +4626,7 @@ var require_clone8 = __commonJS({
4626
4626
  var require_close = __commonJS({
4627
4627
  "node_modules/@jscad/modeling/src/geometries/path2/close.js"(exports, module) {
4628
4628
  "use strict";
4629
- var { EPS } = require_constants();
4629
+ var { EPS: EPS3 } = require_constants();
4630
4630
  var vec2 = require_vec2();
4631
4631
  var clone = require_clone8();
4632
4632
  var close = (geometry) => {
@@ -4637,7 +4637,7 @@ var require_close = __commonJS({
4637
4637
  const points = cloned.points;
4638
4638
  const p0 = points[0];
4639
4639
  let pn = points[points.length - 1];
4640
- while (vec2.distance(p0, pn) < EPS * EPS) {
4640
+ while (vec2.distance(p0, pn) < EPS3 * EPS3) {
4641
4641
  points.pop();
4642
4642
  if (points.length === 1) break;
4643
4643
  pn = points[points.length - 1];
@@ -4672,7 +4672,7 @@ var require_create8 = __commonJS({
4672
4672
  var require_fromPoints5 = __commonJS({
4673
4673
  "node_modules/@jscad/modeling/src/geometries/path2/fromPoints.js"(exports, module) {
4674
4674
  "use strict";
4675
- var { EPS } = require_constants();
4675
+ var { EPS: EPS3 } = require_constants();
4676
4676
  var vec2 = require_vec2();
4677
4677
  var close = require_close();
4678
4678
  var create = require_create8();
@@ -4684,7 +4684,7 @@ var require_fromPoints5 = __commonJS({
4684
4684
  if (created.points.length > 1) {
4685
4685
  const p0 = created.points[0];
4686
4686
  const pn = created.points[created.points.length - 1];
4687
- if (vec2.distance(p0, pn) < EPS * EPS) {
4687
+ if (vec2.distance(p0, pn) < EPS3 * EPS3) {
4688
4688
  closed = true;
4689
4689
  }
4690
4690
  }
@@ -4825,13 +4825,13 @@ var require_concat = __commonJS({
4825
4825
  "use strict";
4826
4826
  var fromPoints = require_fromPoints5();
4827
4827
  var toPoints = require_toPoints4();
4828
- var { equals } = require_vec2();
4828
+ var { equals: equals2 } = require_vec2();
4829
4829
  var concat = (...paths) => {
4830
4830
  let isClosed = false;
4831
4831
  let newpoints = [];
4832
4832
  paths.forEach((path, i) => {
4833
4833
  const tmp = toPoints(path).slice();
4834
- if (newpoints.length > 0 && tmp.length > 0 && equals(tmp[0], newpoints[newpoints.length - 1])) tmp.shift();
4834
+ if (newpoints.length > 0 && tmp.length > 0 && equals2(tmp[0], newpoints[newpoints.length - 1])) tmp.shift();
4835
4835
  if (tmp.length > 0 && isClosed) {
4836
4836
  throw new Error(`Cannot concatenate to a closed path; check the ${i}th path`);
4837
4837
  }
@@ -4975,7 +4975,7 @@ var require_equals5 = __commonJS({
4975
4975
  "use strict";
4976
4976
  var vec2 = require_vec2();
4977
4977
  var toPoints = require_toPoints4();
4978
- var equals = (a, b) => {
4978
+ var equals2 = (a, b) => {
4979
4979
  if (a.isClosed !== b.isClosed) {
4980
4980
  return false;
4981
4981
  }
@@ -5003,7 +5003,7 @@ var require_equals5 = __commonJS({
5003
5003
  } while (++offset4 < length83);
5004
5004
  return false;
5005
5005
  };
5006
- module.exports = equals;
5006
+ module.exports = equals2;
5007
5007
  }
5008
5008
  });
5009
5009
 
@@ -5927,16 +5927,16 @@ var require_curves = __commonJS({
5927
5927
  var require_area = __commonJS({
5928
5928
  "node_modules/@jscad/modeling/src/maths/utils/area.js"(exports, module) {
5929
5929
  "use strict";
5930
- var area = (points) => {
5931
- let area2 = 0;
5930
+ var area2 = (points) => {
5931
+ let area3 = 0;
5932
5932
  for (let i = 0; i < points.length; i++) {
5933
5933
  const j = (i + 1) % points.length;
5934
- area2 += points[i][0] * points[j][1];
5935
- area2 -= points[j][0] * points[i][1];
5934
+ area3 += points[i][0] * points[j][1];
5935
+ area3 -= points[j][0] * points[i][1];
5936
5936
  }
5937
- return area2 / 2;
5937
+ return area3 / 2;
5938
5938
  };
5939
- module.exports = area;
5939
+ module.exports = area2;
5940
5940
  }
5941
5941
  });
5942
5942
 
@@ -5944,8 +5944,8 @@ var require_area = __commonJS({
5944
5944
  var require_measureArea2 = __commonJS({
5945
5945
  "node_modules/@jscad/modeling/src/geometries/poly2/measureArea.js"(exports, module) {
5946
5946
  "use strict";
5947
- var area = require_area();
5948
- var measureArea = (polygon2) => area(polygon2.vertices);
5947
+ var area2 = require_area();
5948
+ var measureArea = (polygon2) => area2(polygon2.vertices);
5949
5949
  module.exports = measureArea;
5950
5950
  }
5951
5951
  });
@@ -6153,8 +6153,8 @@ var require_distanceToPoint = __commonJS({
6153
6153
  var require_equals6 = __commonJS({
6154
6154
  "node_modules/@jscad/modeling/src/maths/line2/equals.js"(exports, module) {
6155
6155
  "use strict";
6156
- var equals = (line1, line2) => line1[0] === line2[0] && (line1[1] === line2[1] && line1[2] === line2[2]);
6157
- module.exports = equals;
6156
+ var equals2 = (line1, line2) => line1[0] === line2[0] && (line1[1] === line2[1] && line1[2] === line2[2]);
6157
+ module.exports = equals2;
6158
6158
  }
6159
6159
  });
6160
6160
 
@@ -6481,12 +6481,12 @@ var require_equals7 = __commonJS({
6481
6481
  "node_modules/@jscad/modeling/src/maths/line3/equals.js"(exports, module) {
6482
6482
  "use strict";
6483
6483
  var vec3 = require_vec3();
6484
- var equals = (line1, line2) => {
6484
+ var equals2 = (line1, line2) => {
6485
6485
  if (!vec3.equals(line1[1], line2[1])) return false;
6486
6486
  if (!vec3.equals(line1[0], line2[0])) return false;
6487
6487
  return true;
6488
6488
  };
6489
- module.exports = equals;
6489
+ module.exports = equals2;
6490
6490
  }
6491
6491
  });
6492
6492
 
@@ -6511,12 +6511,12 @@ var require_fromPlanes = __commonJS({
6511
6511
  "use strict";
6512
6512
  var vec3 = require_vec3();
6513
6513
  var { solve2Linear } = require_utils();
6514
- var { EPS } = require_constants();
6514
+ var { EPS: EPS3 } = require_constants();
6515
6515
  var fromPointAndDirection = require_fromPointAndDirection();
6516
6516
  var fromPlanes = (out, plane1, plane2) => {
6517
6517
  let direction = vec3.cross(vec3.create(), plane1, plane2);
6518
6518
  let length83 = vec3.length(direction);
6519
- if (length83 < EPS) {
6519
+ if (length83 < EPS3) {
6520
6520
  throw new Error("parallel planes do not intersect");
6521
6521
  }
6522
6522
  length83 = 1 / length83;
@@ -6684,21 +6684,21 @@ var require_measureArea3 = __commonJS({
6684
6684
  var cache = /* @__PURE__ */ new WeakMap();
6685
6685
  var measureAreaOfPath2 = () => 0;
6686
6686
  var measureAreaOfGeom2 = (geometry) => {
6687
- let area = cache.get(geometry);
6688
- if (area) return area;
6687
+ let area2 = cache.get(geometry);
6688
+ if (area2) return area2;
6689
6689
  const sides2 = geom2.toSides(geometry);
6690
- area = sides2.reduce((area2, side) => area2 + (side[0][0] * side[1][1] - side[0][1] * side[1][0]), 0);
6691
- area *= 0.5;
6692
- cache.set(geometry, area);
6693
- return area;
6690
+ area2 = sides2.reduce((area3, side) => area3 + (side[0][0] * side[1][1] - side[0][1] * side[1][0]), 0);
6691
+ area2 *= 0.5;
6692
+ cache.set(geometry, area2);
6693
+ return area2;
6694
6694
  };
6695
6695
  var measureAreaOfGeom3 = (geometry) => {
6696
- let area = cache.get(geometry);
6697
- if (area) return area;
6696
+ let area2 = cache.get(geometry);
6697
+ if (area2) return area2;
6698
6698
  const polygons = geom3.toPolygons(geometry);
6699
- area = polygons.reduce((area2, polygon2) => area2 + poly3.measureArea(polygon2), 0);
6700
- cache.set(geometry, area);
6701
- return area;
6699
+ area2 = polygons.reduce((area3, polygon2) => area3 + poly3.measureArea(polygon2), 0);
6700
+ cache.set(geometry, area2);
6701
+ return area2;
6702
6702
  };
6703
6703
  var measureArea = (...geometries) => {
6704
6704
  geometries = flatten(geometries);
@@ -6729,7 +6729,7 @@ var require_measureAggregateArea = __commonJS({
6729
6729
  return areas;
6730
6730
  }
6731
6731
  const result = 0;
6732
- return areas.reduce((result2, area) => result2 + area, result);
6732
+ return areas.reduce((result2, area2) => result2 + area2, result);
6733
6733
  };
6734
6734
  module.exports = measureAggregateArea;
6735
6735
  }
@@ -6855,13 +6855,13 @@ var require_measureAggregateBoundingBox = __commonJS({
6855
6855
  var require_calculateEpsilonFromBounds = __commonJS({
6856
6856
  "node_modules/@jscad/modeling/src/measurements/calculateEpsilonFromBounds.js"(exports, module) {
6857
6857
  "use strict";
6858
- var { EPS } = require_constants();
6858
+ var { EPS: EPS3 } = require_constants();
6859
6859
  var calculateEpsilonFromBounds = (bounds, dimensions) => {
6860
6860
  let total = 0;
6861
6861
  for (let i = 0; i < dimensions; i++) {
6862
6862
  total += bounds[1][i] - bounds[0][i];
6863
6863
  }
6864
- return EPS * total / dimensions;
6864
+ return EPS3 * total / dimensions;
6865
6865
  };
6866
6866
  module.exports = calculateEpsilonFromBounds;
6867
6867
  }
@@ -7079,7 +7079,7 @@ var require_measureCenterOfMass = __commonJS({
7079
7079
  let centerOfMass = cacheOfCenterOfMass.get(geometry);
7080
7080
  if (centerOfMass !== void 0) return centerOfMass;
7081
7081
  const sides2 = geom2.toSides(geometry);
7082
- let area = 0;
7082
+ let area2 = 0;
7083
7083
  let x = 0;
7084
7084
  let y = 0;
7085
7085
  if (sides2.length > 0) {
@@ -7087,12 +7087,12 @@ var require_measureCenterOfMass = __commonJS({
7087
7087
  const p1 = sides2[i][0];
7088
7088
  const p2 = sides2[i][1];
7089
7089
  const a = p1[0] * p2[1] - p1[1] * p2[0];
7090
- area += a;
7090
+ area2 += a;
7091
7091
  x += (p1[0] + p2[0]) * a;
7092
7092
  y += (p1[1] + p2[1]) * a;
7093
7093
  }
7094
- area /= 2;
7095
- const f = 1 / (area * 6);
7094
+ area2 /= 2;
7095
+ const f = 1 / (area2 * 6);
7096
7096
  x *= f;
7097
7097
  y *= f;
7098
7098
  }
@@ -7230,7 +7230,7 @@ var require_commonChecks = __commonJS({
7230
7230
  var require_arc = __commonJS({
7231
7231
  "node_modules/@jscad/modeling/src/primitives/arc.js"(exports, module) {
7232
7232
  "use strict";
7233
- var { EPS, TAU } = require_constants();
7233
+ var { EPS: EPS3, TAU } = require_constants();
7234
7234
  var vec2 = require_vec2();
7235
7235
  var path2 = require_path2();
7236
7236
  var { isGT, isGTE, isNumberArray } = require_commonChecks();
@@ -7258,7 +7258,7 @@ var require_arc = __commonJS({
7258
7258
  if (startAngle > endAngle) {
7259
7259
  rotation = endAngle + (TAU - startAngle);
7260
7260
  }
7261
- const minangle = Math.acos((radius * radius + radius * radius - EPS * EPS) / (2 * radius * radius));
7261
+ const minangle = Math.acos((radius * radius + radius * radius - EPS3 * EPS3) / (2 * radius * radius));
7262
7262
  const centerv = vec2.clone(center);
7263
7263
  let point;
7264
7264
  const pointArray = [];
@@ -7296,7 +7296,7 @@ var require_arc = __commonJS({
7296
7296
  var require_ellipse = __commonJS({
7297
7297
  "node_modules/@jscad/modeling/src/primitives/ellipse.js"(exports, module) {
7298
7298
  "use strict";
7299
- var { EPS, TAU } = require_constants();
7299
+ var { EPS: EPS3, TAU } = require_constants();
7300
7300
  var vec2 = require_vec2();
7301
7301
  var geom2 = require_geom2();
7302
7302
  var { sin, cos } = require_trigonometry();
@@ -7327,7 +7327,7 @@ var require_ellipse = __commonJS({
7327
7327
  rotation = endAngle + (TAU - startAngle);
7328
7328
  }
7329
7329
  const minradius = Math.min(radius[0], radius[1]);
7330
- const minangle = Math.acos((minradius * minradius + minradius * minradius - EPS * EPS) / (2 * minradius * minradius));
7330
+ const minangle = Math.acos((minradius * minradius + minradius * minradius - EPS3 * EPS3) / (2 * minradius * minradius));
7331
7331
  if (rotation < minangle) throw new Error("startAngle and endAngle do not define a significant rotation");
7332
7332
  segments = Math.floor(segments * (rotation / TAU));
7333
7333
  const centerv = vec2.clone(center);
@@ -7439,7 +7439,7 @@ var require_cube = __commonJS({
7439
7439
  var require_cylinderElliptic = __commonJS({
7440
7440
  "node_modules/@jscad/modeling/src/primitives/cylinderElliptic.js"(exports, module) {
7441
7441
  "use strict";
7442
- var { EPS, TAU } = require_constants();
7442
+ var { EPS: EPS3, TAU } = require_constants();
7443
7443
  var vec3 = require_vec3();
7444
7444
  var geom3 = require_geom3();
7445
7445
  var poly3 = require_poly3();
@@ -7476,7 +7476,7 @@ var require_cylinderElliptic = __commonJS({
7476
7476
  rotation = endAngle + (TAU - startAngle);
7477
7477
  }
7478
7478
  const minradius = Math.min(startRadius[0], startRadius[1], endRadius[0], endRadius[1]);
7479
- const minangle = Math.acos((minradius * minradius + minradius * minradius - EPS * EPS) / (2 * minradius * minradius));
7479
+ const minangle = Math.acos((minradius * minradius + minradius * minradius - EPS3 * EPS3) / (2 * minradius * minradius));
7480
7480
  if (rotation < minangle) throw new Error("startAngle and endAngle do not define a significant rotation");
7481
7481
  const slices = Math.floor(segments * (rotation / TAU));
7482
7482
  const start = vec3.fromValues(0, 0, -(height10 / 2));
@@ -7584,15 +7584,15 @@ var require_ellipsoid = __commonJS({
7584
7584
  segments: 32,
7585
7585
  axes: [[1, 0, 0], [0, -1, 0], [0, 0, 1]]
7586
7586
  };
7587
- const { center, radius, segments, axes } = Object.assign({}, defaults2, options);
7587
+ const { center, radius, segments, axes: axes2 } = Object.assign({}, defaults2, options);
7588
7588
  if (!isNumberArray(center, 3)) throw new Error("center must be an array of X, Y and Z values");
7589
7589
  if (!isNumberArray(radius, 3)) throw new Error("radius must be an array of X, Y and Z values");
7590
7590
  if (!radius.every((n) => n >= 0)) throw new Error("radius values must be positive");
7591
7591
  if (!isGTE(segments, 4)) throw new Error("segments must be four or more");
7592
7592
  if (radius[0] === 0 || radius[1] === 0 || radius[2] === 0) return geom3.create();
7593
- const xvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(), axes[0]), radius[0]);
7594
- const yvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(), axes[1]), radius[1]);
7595
- const zvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(), axes[2]), radius[2]);
7593
+ const xvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(), axes2[0]), radius[0]);
7594
+ const yvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(), axes2[1]), radius[1]);
7595
+ const zvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(), axes2[2]), radius[2]);
7596
7596
  const qsegments = Math.round(segments / 4);
7597
7597
  let prevcylinderpoint;
7598
7598
  const polygons = [];
@@ -7925,7 +7925,7 @@ var require_rectangle = __commonJS({
7925
7925
  var require_roundedCuboid = __commonJS({
7926
7926
  "node_modules/@jscad/modeling/src/primitives/roundedCuboid.js"(exports, module) {
7927
7927
  "use strict";
7928
- var { EPS, TAU } = require_constants();
7928
+ var { EPS: EPS3, TAU } = require_constants();
7929
7929
  var vec2 = require_vec2();
7930
7930
  var vec3 = require_vec3();
7931
7931
  var geom3 = require_geom3();
@@ -7941,7 +7941,7 @@ var require_roundedCuboid = __commonJS({
7941
7941
  let layerradius = radius * cospitch;
7942
7942
  let layeroffset = size4[2] - (radius - radius * sinpitch);
7943
7943
  if (!positive) layeroffset = radius - radius * sinpitch - size4[2];
7944
- layerradius = layerradius > EPS ? layerradius : 0;
7944
+ layerradius = layerradius > EPS3 ? layerradius : 0;
7945
7945
  const corner0 = vec3.add(vec3.create(), center, [size4[0] - radius, size4[1] - radius, layeroffset]);
7946
7946
  const corner1 = vec3.add(vec3.create(), center, [radius - size4[0], size4[1] - radius, layeroffset]);
7947
7947
  const corner2 = vec3.add(vec3.create(), center, [radius - size4[0], radius - size4[1], layeroffset]);
@@ -8036,7 +8036,7 @@ var require_roundedCuboid = __commonJS({
8036
8036
  if (size4[0] === 0 || size4[1] === 0 || size4[2] === 0) return geom3.create();
8037
8037
  if (roundRadius === 0) return cuboid5({ center, size: size4 });
8038
8038
  size4 = size4.map((v) => v / 2);
8039
- if (roundRadius > size4[0] - EPS || roundRadius > size4[1] - EPS || roundRadius > size4[2] - EPS) throw new Error("roundRadius must be smaller than the radius of all dimensions");
8039
+ if (roundRadius > size4[0] - EPS3 || roundRadius > size4[1] - EPS3 || roundRadius > size4[2] - EPS3) throw new Error("roundRadius must be smaller than the radius of all dimensions");
8040
8040
  segments = Math.floor(segments / 4);
8041
8041
  let prevCornersPos = null;
8042
8042
  let prevCornersNeg = null;
@@ -8078,7 +8078,7 @@ var require_roundedCuboid = __commonJS({
8078
8078
  var require_roundedCylinder = __commonJS({
8079
8079
  "node_modules/@jscad/modeling/src/primitives/roundedCylinder.js"(exports, module) {
8080
8080
  "use strict";
8081
- var { EPS, TAU } = require_constants();
8081
+ var { EPS: EPS3, TAU } = require_constants();
8082
8082
  var vec3 = require_vec3();
8083
8083
  var geom3 = require_geom3();
8084
8084
  var poly3 = require_poly3();
@@ -8106,7 +8106,7 @@ var require_roundedCylinder = __commonJS({
8106
8106
  const end = [0, 0, height10 / 2];
8107
8107
  const direction = vec3.subtract(vec3.create(), end, start);
8108
8108
  const length83 = vec3.length(direction);
8109
- if (2 * roundRadius > length83 - EPS) throw new Error("height must be larger than twice roundRadius");
8109
+ if (2 * roundRadius > length83 - EPS3) throw new Error("height must be larger than twice roundRadius");
8110
8110
  let defaultnormal;
8111
8111
  if (Math.abs(direction[0]) > Math.abs(direction[1])) {
8112
8112
  defaultnormal = vec3.fromValues(0, 1, 0);
@@ -8191,7 +8191,7 @@ var require_roundedCylinder = __commonJS({
8191
8191
  var require_roundedRectangle = __commonJS({
8192
8192
  "node_modules/@jscad/modeling/src/primitives/roundedRectangle.js"(exports, module) {
8193
8193
  "use strict";
8194
- var { EPS, TAU } = require_constants();
8194
+ var { EPS: EPS3, TAU } = require_constants();
8195
8195
  var vec2 = require_vec2();
8196
8196
  var geom2 = require_geom2();
8197
8197
  var { isGTE, isNumberArray } = require_commonChecks();
@@ -8212,7 +8212,7 @@ var require_roundedRectangle = __commonJS({
8212
8212
  if (size4[0] === 0 || size4[1] === 0) return geom2.create();
8213
8213
  if (roundRadius === 0) return rectangle({ center, size: size4 });
8214
8214
  size4 = size4.map((v) => v / 2);
8215
- if (roundRadius > size4[0] - EPS || roundRadius > size4[1] - EPS) throw new Error("roundRadius must be smaller than the radius of all dimensions");
8215
+ if (roundRadius > size4[0] - EPS3 || roundRadius > size4[1] - EPS3) throw new Error("roundRadius must be smaller than the radius of all dimensions");
8216
8216
  const cornersegments = Math.floor(segments / 4);
8217
8217
  const corner0 = vec2.add(vec2.create(), center, [size4[0] - roundRadius, size4[1] - roundRadius]);
8218
8218
  const corner1 = vec2.add(vec2.create(), center, [roundRadius - size4[0], size4[1] - roundRadius]);
@@ -8253,10 +8253,10 @@ var require_sphere = __commonJS({
8253
8253
  segments: 32,
8254
8254
  axes: [[1, 0, 0], [0, -1, 0], [0, 0, 1]]
8255
8255
  };
8256
- let { center, radius, segments, axes } = Object.assign({}, defaults2, options);
8256
+ let { center, radius, segments, axes: axes2 } = Object.assign({}, defaults2, options);
8257
8257
  if (!isGTE(radius, 0)) throw new Error("radius must be positive");
8258
8258
  radius = [radius, radius, radius];
8259
- return ellipsoid({ center, radius, segments, axes });
8259
+ return ellipsoid({ center, radius, segments, axes: axes2 });
8260
8260
  };
8261
8261
  module.exports = sphere;
8262
8262
  }
@@ -8458,7 +8458,7 @@ var require_equals8 = __commonJS({
8458
8458
  "node_modules/@jscad/modeling/src/operations/extrusions/slice/equals.js"(exports, module) {
8459
8459
  "use strict";
8460
8460
  var vec3 = require_vec3();
8461
- var equals = (a, b) => {
8461
+ var equals2 = (a, b) => {
8462
8462
  const aedges = a.edges;
8463
8463
  const bedges = b.edges;
8464
8464
  if (aedges.length !== bedges.length) {
@@ -8471,7 +8471,7 @@ var require_equals8 = __commonJS({
8471
8471
  }, true);
8472
8472
  return isEqual;
8473
8473
  };
8474
- module.exports = equals;
8474
+ module.exports = equals2;
8475
8475
  }
8476
8476
  });
8477
8477
 
@@ -8630,7 +8630,7 @@ var require_linkedList = __commonJS({
8630
8630
  this.steiner = false;
8631
8631
  }
8632
8632
  };
8633
- var insertNode = (i, x, y, last) => {
8633
+ var insertNode2 = (i, x, y, last) => {
8634
8634
  const p = new Node2(i, x, y);
8635
8635
  if (!last) {
8636
8636
  p.prev = p;
@@ -8643,13 +8643,13 @@ var require_linkedList = __commonJS({
8643
8643
  }
8644
8644
  return p;
8645
8645
  };
8646
- var removeNode = (p) => {
8646
+ var removeNode2 = (p) => {
8647
8647
  p.next.prev = p.prev;
8648
8648
  p.prev.next = p.next;
8649
8649
  if (p.prevZ) p.prevZ.nextZ = p.nextZ;
8650
8650
  if (p.nextZ) p.nextZ.prevZ = p.prevZ;
8651
8651
  };
8652
- module.exports = { Node: Node2, insertNode, removeNode, sortLinked };
8652
+ module.exports = { Node: Node2, insertNode: insertNode2, removeNode: removeNode2, sortLinked };
8653
8653
  }
8654
8654
  });
8655
8655
 
@@ -8657,9 +8657,9 @@ var require_linkedList = __commonJS({
8657
8657
  var require_triangle = __commonJS({
8658
8658
  "node_modules/@jscad/modeling/src/operations/extrusions/earcut/triangle.js"(exports, module) {
8659
8659
  "use strict";
8660
- var pointInTriangle = (ax, ay, bx, by, cx, cy, px, py) => (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 && (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
8661
- var area = (p, q, r) => (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
8662
- module.exports = { area, pointInTriangle };
8660
+ var pointInTriangle2 = (ax, ay, bx, by, cx, cy, px, py) => (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 && (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
8661
+ var area2 = (p, q, r) => (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
8662
+ module.exports = { area: area2, pointInTriangle: pointInTriangle2 };
8663
8663
  }
8664
8664
  });
8665
8665
 
@@ -8667,34 +8667,34 @@ var require_triangle = __commonJS({
8667
8667
  var require_linkedPolygon = __commonJS({
8668
8668
  "node_modules/@jscad/modeling/src/operations/extrusions/earcut/linkedPolygon.js"(exports, module) {
8669
8669
  "use strict";
8670
- var { Node: Node2, insertNode, removeNode } = require_linkedList();
8671
- var { area } = require_triangle();
8670
+ var { Node: Node2, insertNode: insertNode2, removeNode: removeNode2 } = require_linkedList();
8671
+ var { area: area2 } = require_triangle();
8672
8672
  var linkedPolygon = (data, start, end, dim, clockwise) => {
8673
8673
  let last;
8674
- if (clockwise === signedArea(data, start, end, dim) > 0) {
8674
+ if (clockwise === signedArea2(data, start, end, dim) > 0) {
8675
8675
  for (let i = start; i < end; i += dim) {
8676
- last = insertNode(i, data[i], data[i + 1], last);
8676
+ last = insertNode2(i, data[i], data[i + 1], last);
8677
8677
  }
8678
8678
  } else {
8679
8679
  for (let i = end - dim; i >= start; i -= dim) {
8680
- last = insertNode(i, data[i], data[i + 1], last);
8680
+ last = insertNode2(i, data[i], data[i + 1], last);
8681
8681
  }
8682
8682
  }
8683
- if (last && equals(last, last.next)) {
8684
- removeNode(last);
8683
+ if (last && equals2(last, last.next)) {
8684
+ removeNode2(last);
8685
8685
  last = last.next;
8686
8686
  }
8687
8687
  return last;
8688
8688
  };
8689
- var filterPoints = (start, end) => {
8689
+ var filterPoints2 = (start, end) => {
8690
8690
  if (!start) return start;
8691
8691
  if (!end) end = start;
8692
8692
  let p = start;
8693
8693
  let again;
8694
8694
  do {
8695
8695
  again = false;
8696
- if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
8697
- removeNode(p);
8696
+ if (!p.steiner && (equals2(p, p.next) || area2(p.prev, p, p.next) === 0)) {
8697
+ removeNode2(p);
8698
8698
  p = end = p.prev;
8699
8699
  if (p === p.next) break;
8700
8700
  again = true;
@@ -8704,33 +8704,33 @@ var require_linkedPolygon = __commonJS({
8704
8704
  } while (again || p !== end);
8705
8705
  return end;
8706
8706
  };
8707
- var cureLocalIntersections = (start, triangles, dim) => {
8707
+ var cureLocalIntersections2 = (start, triangles, dim) => {
8708
8708
  let p = start;
8709
8709
  do {
8710
8710
  const a = p.prev;
8711
8711
  const b = p.next.next;
8712
- if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
8712
+ if (!equals2(a, b) && intersects2(a, p, p.next, b) && locallyInside2(a, b) && locallyInside2(b, a)) {
8713
8713
  triangles.push(a.i / dim);
8714
8714
  triangles.push(p.i / dim);
8715
8715
  triangles.push(b.i / dim);
8716
- removeNode(p);
8717
- removeNode(p.next);
8716
+ removeNode2(p);
8717
+ removeNode2(p.next);
8718
8718
  p = start = b;
8719
8719
  }
8720
8720
  p = p.next;
8721
8721
  } while (p !== start);
8722
- return filterPoints(p);
8722
+ return filterPoints2(p);
8723
8723
  };
8724
- var intersectsPolygon = (a, b) => {
8724
+ var intersectsPolygon2 = (a, b) => {
8725
8725
  let p = a;
8726
8726
  do {
8727
- if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b)) return true;
8727
+ if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects2(p, p.next, a, b)) return true;
8728
8728
  p = p.next;
8729
8729
  } while (p !== a);
8730
8730
  return false;
8731
8731
  };
8732
- var locallyInside = (a, b) => area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
8733
- var middleInside = (a, b) => {
8732
+ var locallyInside2 = (a, b) => area2(a.prev, a, a.next) < 0 ? area2(a, b, a.next) >= 0 && area2(a, a.prev, b) >= 0 : area2(a, b, a.prev) < 0 || area2(a, a.next, b) < 0;
8733
+ var middleInside2 = (a, b) => {
8734
8734
  let p = a;
8735
8735
  let inside = false;
8736
8736
  const px = (a.x + b.x) / 2;
@@ -8743,7 +8743,7 @@ var require_linkedPolygon = __commonJS({
8743
8743
  } while (p !== a);
8744
8744
  return inside;
8745
8745
  };
8746
- var splitPolygon = (a, b) => {
8746
+ var splitPolygon2 = (a, b) => {
8747
8747
  const a2 = new Node2(a.i, a.x, a.y);
8748
8748
  const b2 = new Node2(b.i, b.x, b.y);
8749
8749
  const an = a.next;
@@ -8758,24 +8758,24 @@ var require_linkedPolygon = __commonJS({
8758
8758
  b2.prev = bp;
8759
8759
  return b2;
8760
8760
  };
8761
- var isValidDiagonal = (a, b) => a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && // doesn't intersect other edges
8762
- (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible
8763
- (area(a.prev, a, b.prev) || area(a, b.prev, b)) || // does not create opposite-facing sectors
8764
- equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0);
8765
- var intersects = (p1, q1, p2, q2) => {
8766
- const o1 = Math.sign(area(p1, q1, p2));
8767
- const o2 = Math.sign(area(p1, q1, q2));
8768
- const o3 = Math.sign(area(p2, q2, p1));
8769
- const o4 = Math.sign(area(p2, q2, q1));
8761
+ var isValidDiagonal2 = (a, b) => a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon2(a, b) && // doesn't intersect other edges
8762
+ (locallyInside2(a, b) && locallyInside2(b, a) && middleInside2(a, b) && // locally visible
8763
+ (area2(a.prev, a, b.prev) || area2(a, b.prev, b)) || // does not create opposite-facing sectors
8764
+ equals2(a, b) && area2(a.prev, a, a.next) > 0 && area2(b.prev, b, b.next) > 0);
8765
+ var intersects2 = (p1, q1, p2, q2) => {
8766
+ const o1 = Math.sign(area2(p1, q1, p2));
8767
+ const o2 = Math.sign(area2(p1, q1, q2));
8768
+ const o3 = Math.sign(area2(p2, q2, p1));
8769
+ const o4 = Math.sign(area2(p2, q2, q1));
8770
8770
  if (o1 !== o2 && o3 !== o4) return true;
8771
- if (o1 === 0 && onSegment2(p1, p2, q1)) return true;
8772
- if (o2 === 0 && onSegment2(p1, q2, q1)) return true;
8773
- if (o3 === 0 && onSegment2(p2, p1, q2)) return true;
8774
- if (o4 === 0 && onSegment2(p2, q1, q2)) return true;
8771
+ if (o1 === 0 && onSegment3(p1, p2, q1)) return true;
8772
+ if (o2 === 0 && onSegment3(p1, q2, q1)) return true;
8773
+ if (o3 === 0 && onSegment3(p2, p1, q2)) return true;
8774
+ if (o4 === 0 && onSegment3(p2, q1, q2)) return true;
8775
8775
  return false;
8776
8776
  };
8777
- var onSegment2 = (p, q, r) => q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
8778
- var signedArea = (data, start, end, dim) => {
8777
+ var onSegment3 = (p, q, r) => q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
8778
+ var signedArea2 = (data, start, end, dim) => {
8779
8779
  let sum = 0;
8780
8780
  for (let i = start, j = end - dim; i < end; i += dim) {
8781
8781
  sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
@@ -8783,8 +8783,8 @@ var require_linkedPolygon = __commonJS({
8783
8783
  }
8784
8784
  return sum;
8785
8785
  };
8786
- var equals = (p1, p2) => p1.x === p2.x && p1.y === p2.y;
8787
- module.exports = { cureLocalIntersections, filterPoints, isValidDiagonal, linkedPolygon, locallyInside, splitPolygon };
8786
+ var equals2 = (p1, p2) => p1.x === p2.x && p1.y === p2.y;
8787
+ module.exports = { cureLocalIntersections: cureLocalIntersections2, filterPoints: filterPoints2, isValidDiagonal: isValidDiagonal2, linkedPolygon, locallyInside: locallyInside2, splitPolygon: splitPolygon2 };
8788
8788
  }
8789
8789
  });
8790
8790
 
@@ -8792,35 +8792,35 @@ var require_linkedPolygon = __commonJS({
8792
8792
  var require_eliminateHoles = __commonJS({
8793
8793
  "node_modules/@jscad/modeling/src/operations/extrusions/earcut/eliminateHoles.js"(exports, module) {
8794
8794
  "use strict";
8795
- var { filterPoints, linkedPolygon, locallyInside, splitPolygon } = require_linkedPolygon();
8796
- var { area, pointInTriangle } = require_triangle();
8797
- var eliminateHoles = (data, holeIndices, outerNode, dim) => {
8795
+ var { filterPoints: filterPoints2, linkedPolygon, locallyInside: locallyInside2, splitPolygon: splitPolygon2 } = require_linkedPolygon();
8796
+ var { area: area2, pointInTriangle: pointInTriangle2 } = require_triangle();
8797
+ var eliminateHoles2 = (data, holeIndices, outerNode, dim) => {
8798
8798
  const queue = [];
8799
8799
  for (let i = 0, len = holeIndices.length; i < len; i++) {
8800
8800
  const start = holeIndices[i] * dim;
8801
8801
  const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
8802
8802
  const list = linkedPolygon(data, start, end, dim, false);
8803
8803
  if (list === list.next) list.steiner = true;
8804
- queue.push(getLeftmost(list));
8804
+ queue.push(getLeftmost2(list));
8805
8805
  }
8806
8806
  queue.sort((a, b) => a.x - b.x);
8807
8807
  for (let i = 0; i < queue.length; i++) {
8808
- outerNode = eliminateHole(queue[i], outerNode);
8809
- outerNode = filterPoints(outerNode, outerNode.next);
8808
+ outerNode = eliminateHole2(queue[i], outerNode);
8809
+ outerNode = filterPoints2(outerNode, outerNode.next);
8810
8810
  }
8811
8811
  return outerNode;
8812
8812
  };
8813
- var eliminateHole = (hole, outerNode) => {
8814
- const bridge = findHoleBridge(hole, outerNode);
8813
+ var eliminateHole2 = (hole, outerNode) => {
8814
+ const bridge = findHoleBridge2(hole, outerNode);
8815
8815
  if (!bridge) {
8816
8816
  return outerNode;
8817
8817
  }
8818
- const bridgeReverse = splitPolygon(bridge, hole);
8819
- const filteredBridge = filterPoints(bridge, bridge.next);
8820
- filterPoints(bridgeReverse, bridgeReverse.next);
8818
+ const bridgeReverse = splitPolygon2(bridge, hole);
8819
+ const filteredBridge = filterPoints2(bridge, bridge.next);
8820
+ filterPoints2(bridgeReverse, bridgeReverse.next);
8821
8821
  return outerNode === bridge ? filteredBridge : outerNode;
8822
8822
  };
8823
- var findHoleBridge = (hole, outerNode) => {
8823
+ var findHoleBridge2 = (hole, outerNode) => {
8824
8824
  let p = outerNode;
8825
8825
  const hx = hole.x;
8826
8826
  const hy = hole.y;
@@ -8848,9 +8848,9 @@ var require_eliminateHoles = __commonJS({
8848
8848
  let tanMin = Infinity;
8849
8849
  p = m;
8850
8850
  do {
8851
- if (hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
8851
+ if (hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle2(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
8852
8852
  const tan = Math.abs(hy - p.y) / (hx - p.x);
8853
- if (locallyInside(p, hole) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
8853
+ if (locallyInside2(p, hole) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector2(m, p)))) {
8854
8854
  m = p;
8855
8855
  tanMin = tan;
8856
8856
  }
@@ -8859,8 +8859,8 @@ var require_eliminateHoles = __commonJS({
8859
8859
  } while (p !== stop);
8860
8860
  return m;
8861
8861
  };
8862
- var sectorContainsSector = (m, p) => area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
8863
- var getLeftmost = (start) => {
8862
+ var sectorContainsSector2 = (m, p) => area2(m.prev, m, p.prev) < 0 && area2(p.next, m, m.next) < 0;
8863
+ var getLeftmost2 = (start) => {
8864
8864
  let p = start;
8865
8865
  let leftmost = start;
8866
8866
  do {
@@ -8869,7 +8869,7 @@ var require_eliminateHoles = __commonJS({
8869
8869
  } while (p !== start);
8870
8870
  return leftmost;
8871
8871
  };
8872
- module.exports = eliminateHoles;
8872
+ module.exports = eliminateHoles2;
8873
8873
  }
8874
8874
  });
8875
8875
 
@@ -8877,10 +8877,10 @@ var require_eliminateHoles = __commonJS({
8877
8877
  var require_earcut = __commonJS({
8878
8878
  "node_modules/@jscad/modeling/src/operations/extrusions/earcut/index.js"(exports, module) {
8879
8879
  "use strict";
8880
- var eliminateHoles = require_eliminateHoles();
8881
- var { removeNode, sortLinked } = require_linkedList();
8882
- var { cureLocalIntersections, filterPoints, isValidDiagonal, linkedPolygon, splitPolygon } = require_linkedPolygon();
8883
- var { area, pointInTriangle } = require_triangle();
8880
+ var eliminateHoles2 = require_eliminateHoles();
8881
+ var { removeNode: removeNode2, sortLinked } = require_linkedList();
8882
+ var { cureLocalIntersections: cureLocalIntersections2, filterPoints: filterPoints2, isValidDiagonal: isValidDiagonal2, linkedPolygon, splitPolygon: splitPolygon2 } = require_linkedPolygon();
8883
+ var { area: area2, pointInTriangle: pointInTriangle2 } = require_triangle();
8884
8884
  var triangulate = (data, holeIndices, dim = 2) => {
8885
8885
  const hasHoles = holeIndices && holeIndices.length;
8886
8886
  const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
@@ -8888,7 +8888,7 @@ var require_earcut = __commonJS({
8888
8888
  const triangles = [];
8889
8889
  if (!outerNode || outerNode.next === outerNode.prev) return triangles;
8890
8890
  let minX, minY, maxX, maxY, invSize;
8891
- if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
8891
+ if (hasHoles) outerNode = eliminateHoles2(data, holeIndices, outerNode, dim);
8892
8892
  if (data.length > 80 * dim) {
8893
8893
  minX = maxX = data[0];
8894
8894
  minY = maxY = data[1];
@@ -8903,23 +8903,23 @@ var require_earcut = __commonJS({
8903
8903
  invSize = Math.max(maxX - minX, maxY - minY);
8904
8904
  invSize = invSize !== 0 ? 1 / invSize : 0;
8905
8905
  }
8906
- earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
8906
+ earcutLinked2(outerNode, triangles, dim, minX, minY, invSize);
8907
8907
  return triangles;
8908
8908
  };
8909
- var earcutLinked = (ear, triangles, dim, minX, minY, invSize, pass) => {
8909
+ var earcutLinked2 = (ear, triangles, dim, minX, minY, invSize, pass) => {
8910
8910
  if (!ear) return;
8911
- if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
8911
+ if (!pass && invSize) indexCurve2(ear, minX, minY, invSize);
8912
8912
  let stop = ear;
8913
8913
  let prev;
8914
8914
  let next;
8915
8915
  while (ear.prev !== ear.next) {
8916
8916
  prev = ear.prev;
8917
8917
  next = ear.next;
8918
- if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
8918
+ if (invSize ? isEarHashed2(ear, minX, minY, invSize) : isEar2(ear)) {
8919
8919
  triangles.push(prev.i / dim);
8920
8920
  triangles.push(ear.i / dim);
8921
8921
  triangles.push(next.i / dim);
8922
- removeNode(ear);
8922
+ removeNode2(ear);
8923
8923
  ear = next.next;
8924
8924
  stop = next.next;
8925
8925
  continue;
@@ -8927,71 +8927,71 @@ var require_earcut = __commonJS({
8927
8927
  ear = next;
8928
8928
  if (ear === stop) {
8929
8929
  if (!pass) {
8930
- earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
8930
+ earcutLinked2(filterPoints2(ear), triangles, dim, minX, minY, invSize, 1);
8931
8931
  } else if (pass === 1) {
8932
- ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
8933
- earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
8932
+ ear = cureLocalIntersections2(filterPoints2(ear), triangles, dim);
8933
+ earcutLinked2(ear, triangles, dim, minX, minY, invSize, 2);
8934
8934
  } else if (pass === 2) {
8935
- splitEarcut(ear, triangles, dim, minX, minY, invSize);
8935
+ splitEarcut2(ear, triangles, dim, minX, minY, invSize);
8936
8936
  }
8937
8937
  break;
8938
8938
  }
8939
8939
  }
8940
8940
  };
8941
- var isEar = (ear) => {
8941
+ var isEar2 = (ear) => {
8942
8942
  const a = ear.prev;
8943
8943
  const b = ear;
8944
8944
  const c = ear.next;
8945
- if (area(a, b, c) >= 0) return false;
8945
+ if (area2(a, b, c) >= 0) return false;
8946
8946
  let p = ear.next.next;
8947
8947
  while (p !== ear.prev) {
8948
- if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) {
8948
+ if (pointInTriangle2(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area2(p.prev, p, p.next) >= 0) {
8949
8949
  return false;
8950
8950
  }
8951
8951
  p = p.next;
8952
8952
  }
8953
8953
  return true;
8954
8954
  };
8955
- var isEarHashed = (ear, minX, minY, invSize) => {
8955
+ var isEarHashed2 = (ear, minX, minY, invSize) => {
8956
8956
  const a = ear.prev;
8957
8957
  const b = ear;
8958
8958
  const c = ear.next;
8959
- if (area(a, b, c) >= 0) return false;
8959
+ if (area2(a, b, c) >= 0) return false;
8960
8960
  const minTX = a.x < b.x ? a.x < c.x ? a.x : c.x : b.x < c.x ? b.x : c.x;
8961
8961
  const minTY = a.y < b.y ? a.y < c.y ? a.y : c.y : b.y < c.y ? b.y : c.y;
8962
8962
  const maxTX = a.x > b.x ? a.x > c.x ? a.x : c.x : b.x > c.x ? b.x : c.x;
8963
8963
  const maxTY = a.y > b.y ? a.y > c.y ? a.y : c.y : b.y > c.y ? b.y : c.y;
8964
- const minZ = zOrder(minTX, minTY, minX, minY, invSize);
8965
- const maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
8964
+ const minZ = zOrder2(minTX, minTY, minX, minY, invSize);
8965
+ const maxZ = zOrder2(maxTX, maxTY, minX, minY, invSize);
8966
8966
  let p = ear.prevZ;
8967
8967
  let n = ear.nextZ;
8968
8968
  while (p && p.z >= minZ && n && n.z <= maxZ) {
8969
- if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
8969
+ if (p !== ear.prev && p !== ear.next && pointInTriangle2(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area2(p.prev, p, p.next) >= 0) return false;
8970
8970
  p = p.prevZ;
8971
- if (n !== ear.prev && n !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
8971
+ if (n !== ear.prev && n !== ear.next && pointInTriangle2(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area2(n.prev, n, n.next) >= 0) return false;
8972
8972
  n = n.nextZ;
8973
8973
  }
8974
8974
  while (p && p.z >= minZ) {
8975
- if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
8975
+ if (p !== ear.prev && p !== ear.next && pointInTriangle2(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area2(p.prev, p, p.next) >= 0) return false;
8976
8976
  p = p.prevZ;
8977
8977
  }
8978
8978
  while (n && n.z <= maxZ) {
8979
- if (n !== ear.prev && n !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
8979
+ if (n !== ear.prev && n !== ear.next && pointInTriangle2(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area2(n.prev, n, n.next) >= 0) return false;
8980
8980
  n = n.nextZ;
8981
8981
  }
8982
8982
  return true;
8983
8983
  };
8984
- var splitEarcut = (start, triangles, dim, minX, minY, invSize) => {
8984
+ var splitEarcut2 = (start, triangles, dim, minX, minY, invSize) => {
8985
8985
  let a = start;
8986
8986
  do {
8987
8987
  let b = a.next.next;
8988
8988
  while (b !== a.prev) {
8989
- if (a.i !== b.i && isValidDiagonal(a, b)) {
8990
- let c = splitPolygon(a, b);
8991
- a = filterPoints(a, a.next);
8992
- c = filterPoints(c, c.next);
8993
- earcutLinked(a, triangles, dim, minX, minY, invSize);
8994
- earcutLinked(c, triangles, dim, minX, minY, invSize);
8989
+ if (a.i !== b.i && isValidDiagonal2(a, b)) {
8990
+ let c = splitPolygon2(a, b);
8991
+ a = filterPoints2(a, a.next);
8992
+ c = filterPoints2(c, c.next);
8993
+ earcutLinked2(a, triangles, dim, minX, minY, invSize);
8994
+ earcutLinked2(c, triangles, dim, minX, minY, invSize);
8995
8995
  return;
8996
8996
  }
8997
8997
  b = b.next;
@@ -8999,10 +8999,10 @@ var require_earcut = __commonJS({
8999
8999
  a = a.next;
9000
9000
  } while (a !== start);
9001
9001
  };
9002
- var indexCurve = (start, minX, minY, invSize) => {
9002
+ var indexCurve2 = (start, minX, minY, invSize) => {
9003
9003
  let p = start;
9004
9004
  do {
9005
- if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, invSize);
9005
+ if (p.z === null) p.z = zOrder2(p.x, p.y, minX, minY, invSize);
9006
9006
  p.prevZ = p.prev;
9007
9007
  p.nextZ = p.next;
9008
9008
  p = p.next;
@@ -9011,7 +9011,7 @@ var require_earcut = __commonJS({
9011
9011
  p.prevZ = null;
9012
9012
  sortLinked(p, (p2) => p2.z);
9013
9013
  };
9014
- var zOrder = (x, y, minX, minY, invSize) => {
9014
+ var zOrder2 = (x, y, minX, minY, invSize) => {
9015
9015
  x = 32767 * (x - minX) * invSize;
9016
9016
  y = 32767 * (y - minY) * invSize;
9017
9017
  x = (x | x << 8) & 16711935;
@@ -9032,7 +9032,7 @@ var require_earcut = __commonJS({
9032
9032
  var require_assignHoles = __commonJS({
9033
9033
  "node_modules/@jscad/modeling/src/operations/extrusions/earcut/assignHoles.js"(exports, module) {
9034
9034
  "use strict";
9035
- var { area } = require_utils();
9035
+ var { area: area2 } = require_utils();
9036
9036
  var { toOutlines } = require_geom2();
9037
9037
  var { arePointsInside } = require_poly2();
9038
9038
  var assignHoles = (geometry) => {
@@ -9040,7 +9040,7 @@ var require_assignHoles = __commonJS({
9040
9040
  const solids = [];
9041
9041
  const holes = [];
9042
9042
  outlines.forEach((outline, i) => {
9043
- const a = area(outline);
9043
+ const a = area2(outline);
9044
9044
  if (a < 0) {
9045
9045
  holes.push(i);
9046
9046
  } else if (a > 0) {
@@ -9148,7 +9148,7 @@ var require_toPolygons2 = __commonJS({
9148
9148
  "node_modules/@jscad/modeling/src/operations/extrusions/slice/toPolygons.js"(exports, module) {
9149
9149
  "use strict";
9150
9150
  var poly3 = require_poly3();
9151
- var earcut = require_earcut();
9151
+ var earcut2 = require_earcut();
9152
9152
  var PolygonHierarchy = require_polygonHierarchy();
9153
9153
  var toPolygons = (slice) => {
9154
9154
  const hierarchy = new PolygonHierarchy(slice);
@@ -9163,7 +9163,7 @@ var require_toPolygons2 = __commonJS({
9163
9163
  const vertices = [solid, ...holes].flat();
9164
9164
  const data = vertices.flat();
9165
9165
  const getVertex = (i) => hierarchy.to3D(vertices[i]);
9166
- const indices = earcut(data, holesIndex);
9166
+ const indices = earcut2(data, holesIndex);
9167
9167
  for (let i = 0; i < indices.length; i += 3) {
9168
9168
  const tri = indices.slice(i, i + 3).map(getVertex);
9169
9169
  polygons.push(poly3.fromPointsAndPlane(tri, hierarchy.plane));
@@ -9276,7 +9276,7 @@ var require_repair = __commonJS({
9276
9276
  var require_extrudeWalls = __commonJS({
9277
9277
  "node_modules/@jscad/modeling/src/operations/extrusions/extrudeWalls.js"(exports, module) {
9278
9278
  "use strict";
9279
- var { EPS } = require_constants();
9279
+ var { EPS: EPS3 } = require_constants();
9280
9280
  var vec3 = require_vec3();
9281
9281
  var poly3 = require_poly3();
9282
9282
  var slice = require_slice();
@@ -9316,7 +9316,7 @@ var require_extrudeWalls = __commonJS({
9316
9316
  });
9317
9317
  return newEdges;
9318
9318
  };
9319
- var EPSAREA = EPS * EPS / 2 * Math.sin(Math.PI / 3);
9319
+ var EPSAREA = EPS3 * EPS3 / 2 * Math.sin(Math.PI / 3);
9320
9320
  var extrudeWalls = (slice0, slice1) => {
9321
9321
  let edges0 = slice.toEdges(slice0);
9322
9322
  let edges1 = slice.toEdges(slice1);
@@ -10299,7 +10299,7 @@ var require_OrthoNormalBasis = __commonJS({
10299
10299
  var require_reTesselateCoplanarPolygons = __commonJS({
10300
10300
  "node_modules/@jscad/modeling/src/operations/modifiers/reTesselateCoplanarPolygons.js"(exports, module) {
10301
10301
  "use strict";
10302
- var { EPS } = require_constants();
10302
+ var { EPS: EPS3 } = require_constants();
10303
10303
  var line2 = require_line2();
10304
10304
  var vec2 = require_vec2();
10305
10305
  var OrthoNormalBasis = require_OrthoNormalBasis();
@@ -10317,7 +10317,7 @@ var require_reTesselateCoplanarPolygons = __commonJS({
10317
10317
  const topy2polygonindexes = /* @__PURE__ */ new Map();
10318
10318
  const ycoordinatetopolygonindexes = /* @__PURE__ */ new Map();
10319
10319
  const ycoordinatebins = /* @__PURE__ */ new Map();
10320
- const ycoordinateBinningFactor = 10 / EPS;
10320
+ const ycoordinateBinningFactor = 10 / EPS3;
10321
10321
  for (let polygonindex = 0; polygonindex < numpolygons; polygonindex++) {
10322
10322
  const poly3d = sourcepolygons[polygonindex];
10323
10323
  let vertices2d = [];
@@ -10497,7 +10497,7 @@ var require_reTesselateCoplanarPolygons = __commonJS({
10497
10497
  const prevoutpolygon = newoutpolygonrow[newoutpolygonrow.length - 1];
10498
10498
  const d1 = vec2.distance(outpolygon.topleft, prevoutpolygon.topright);
10499
10499
  const d2 = vec2.distance(outpolygon.bottomleft, prevoutpolygon.bottomright);
10500
- if (d1 < EPS && d2 < EPS) {
10500
+ if (d1 < EPS3 && d2 < EPS3) {
10501
10501
  outpolygon.topleft = prevoutpolygon.topleft;
10502
10502
  outpolygon.leftline = prevoutpolygon.leftline;
10503
10503
  outpolygon.bottomleft = prevoutpolygon.bottomleft;
@@ -10514,8 +10514,8 @@ var require_reTesselateCoplanarPolygons = __commonJS({
10514
10514
  for (let ii = 0; ii < prevoutpolygonrow.length; ii++) {
10515
10515
  if (!matchedindexes.has(ii)) {
10516
10516
  const prevpolygon = prevoutpolygonrow[ii];
10517
- if (vec2.distance(prevpolygon.bottomleft, thispolygon.topleft) < EPS) {
10518
- if (vec2.distance(prevpolygon.bottomright, thispolygon.topright) < EPS) {
10517
+ if (vec2.distance(prevpolygon.bottomleft, thispolygon.topleft) < EPS3) {
10518
+ if (vec2.distance(prevpolygon.bottomright, thispolygon.topright) < EPS3) {
10519
10519
  matchedindexes.add(ii);
10520
10520
  const v1 = line2.direction(thispolygon.leftline);
10521
10521
  const v2 = line2.direction(prevpolygon.leftline);
@@ -10523,8 +10523,8 @@ var require_reTesselateCoplanarPolygons = __commonJS({
10523
10523
  const v3 = line2.direction(thispolygon.rightline);
10524
10524
  const v4 = line2.direction(prevpolygon.rightline);
10525
10525
  const d2 = v3[0] - v4[0];
10526
- const leftlinecontinues = Math.abs(d1) < EPS;
10527
- const rightlinecontinues = Math.abs(d2) < EPS;
10526
+ const leftlinecontinues = Math.abs(d1) < EPS3;
10527
+ const rightlinecontinues = Math.abs(d2) < EPS3;
10528
10528
  const leftlineisconvex = leftlinecontinues || d1 >= 0;
10529
10529
  const rightlineisconvex = rightlinecontinues || d2 >= 0;
10530
10530
  if (leftlineisconvex && rightlineisconvex) {
@@ -10543,7 +10543,7 @@ var require_reTesselateCoplanarPolygons = __commonJS({
10543
10543
  if (!prevcontinuedindexes.has(ii)) {
10544
10544
  const prevpolygon = prevoutpolygonrow[ii];
10545
10545
  prevpolygon.outpolygon.rightpoints.push(prevpolygon.bottomright);
10546
- if (vec2.distance(prevpolygon.bottomright, prevpolygon.bottomleft) > EPS) {
10546
+ if (vec2.distance(prevpolygon.bottomright, prevpolygon.bottomleft) > EPS3) {
10547
10547
  prevpolygon.outpolygon.leftpoints.push(prevpolygon.bottomleft);
10548
10548
  }
10549
10549
  prevpolygon.outpolygon.leftpoints.reverse();
@@ -10562,7 +10562,7 @@ var require_reTesselateCoplanarPolygons = __commonJS({
10562
10562
  rightpoints: []
10563
10563
  };
10564
10564
  thispolygon.outpolygon.leftpoints.push(thispolygon.topleft);
10565
- if (vec2.distance(thispolygon.topleft, thispolygon.topright) > EPS) {
10565
+ if (vec2.distance(thispolygon.topleft, thispolygon.topright) > EPS3) {
10566
10566
  thispolygon.outpolygon.rightpoints.push(thispolygon.topright);
10567
10567
  }
10568
10568
  } else {
@@ -10663,7 +10663,7 @@ var require_retessellate = __commonJS({
10663
10663
  var require_mayOverlap = __commonJS({
10664
10664
  "node_modules/@jscad/modeling/src/operations/booleans/mayOverlap.js"(exports, module) {
10665
10665
  "use strict";
10666
- var { EPS } = require_constants();
10666
+ var { EPS: EPS3 } = require_constants();
10667
10667
  var measureBoundingBox = require_measureBoundingBox2();
10668
10668
  var mayOverlap = (geometry1, geometry2) => {
10669
10669
  if (geometry1.polygons.length === 0 || geometry2.polygons.length === 0) {
@@ -10675,12 +10675,12 @@ var require_mayOverlap = __commonJS({
10675
10675
  const bounds2 = measureBoundingBox(geometry2);
10676
10676
  const min2 = bounds2[0];
10677
10677
  const max2 = bounds2[1];
10678
- if (min2[0] - max1[0] > EPS) return false;
10679
- if (min1[0] - max2[0] > EPS) return false;
10680
- if (min2[1] - max1[1] > EPS) return false;
10681
- if (min1[1] - max2[1] > EPS) return false;
10682
- if (min2[2] - max1[2] > EPS) return false;
10683
- if (min1[2] - max2[2] > EPS) return false;
10678
+ if (min2[0] - max1[0] > EPS3) return false;
10679
+ if (min1[0] - max2[0] > EPS3) return false;
10680
+ if (min2[1] - max1[1] > EPS3) return false;
10681
+ if (min1[1] - max2[1] > EPS3) return false;
10682
+ if (min2[2] - max1[2] > EPS3) return false;
10683
+ if (min1[2] - max2[2] > EPS3) return false;
10684
10684
  return true;
10685
10685
  };
10686
10686
  module.exports = mayOverlap;
@@ -10830,12 +10830,12 @@ var require_splitLineSegmentByPlane = __commonJS({
10830
10830
  var require_splitPolygonByPlane = __commonJS({
10831
10831
  "node_modules/@jscad/modeling/src/operations/booleans/trees/splitPolygonByPlane.js"(exports, module) {
10832
10832
  "use strict";
10833
- var { EPS } = require_constants();
10833
+ var { EPS: EPS3 } = require_constants();
10834
10834
  var plane = require_plane();
10835
10835
  var vec3 = require_vec3();
10836
10836
  var poly3 = require_poly3();
10837
10837
  var splitLineSegmentByPlane = require_splitLineSegmentByPlane();
10838
- var EPS_SQUARED = EPS * EPS;
10838
+ var EPS_SQUARED = EPS3 * EPS3;
10839
10839
  var removeConsecutiveDuplicates = (vertices) => {
10840
10840
  const result = [];
10841
10841
  let prevvertex = vertices[vertices.length - 1];
@@ -10863,12 +10863,12 @@ var require_splitPolygonByPlane = __commonJS({
10863
10863
  let hasfront = false;
10864
10864
  let hasback = false;
10865
10865
  const vertexIsBack = [];
10866
- const MINEPS = -EPS;
10866
+ const MINEPS = -EPS3;
10867
10867
  for (let i = 0; i < numvertices; i++) {
10868
10868
  const t = vec3.dot(splane, vertices[i]) - splane[3];
10869
10869
  const isback = t < MINEPS;
10870
10870
  vertexIsBack.push(isback);
10871
- if (t > EPS) hasfront = true;
10871
+ if (t > EPS3) hasfront = true;
10872
10872
  if (t < MINEPS) hasback = true;
10873
10873
  }
10874
10874
  if (!hasfront && !hasback) {
@@ -10933,7 +10933,7 @@ var require_splitPolygonByPlane = __commonJS({
10933
10933
  var require_PolygonTreeNode = __commonJS({
10934
10934
  "node_modules/@jscad/modeling/src/operations/booleans/trees/PolygonTreeNode.js"(exports, module) {
10935
10935
  "use strict";
10936
- var { EPS } = require_constants();
10936
+ var { EPS: EPS3 } = require_constants();
10937
10937
  var vec3 = require_vec3();
10938
10938
  var poly3 = require_poly3();
10939
10939
  var splitPolygonByPlane = require_splitPolygonByPlane();
@@ -11036,7 +11036,7 @@ var require_PolygonTreeNode = __commonJS({
11036
11036
  const polygon2 = this.polygon;
11037
11037
  if (polygon2) {
11038
11038
  const bound = poly3.measureBoundingSphere(polygon2);
11039
- const sphereradius = bound[3] + EPS;
11039
+ const sphereradius = bound[3] + EPS3;
11040
11040
  const spherecenter = bound;
11041
11041
  const d = vec3.dot(splane, spherecenter) - splane[3];
11042
11042
  if (d > sphereradius) {
@@ -11752,11 +11752,11 @@ var require_booleans = __commonJS({
11752
11752
  var require_offsetFromPoints = __commonJS({
11753
11753
  "node_modules/@jscad/modeling/src/operations/expansions/offsetFromPoints.js"(exports, module) {
11754
11754
  "use strict";
11755
- var { EPS, TAU } = require_constants();
11755
+ var { EPS: EPS3, TAU } = require_constants();
11756
11756
  var intersect3 = require_intersect();
11757
11757
  var line2 = require_line2();
11758
11758
  var vec2 = require_vec2();
11759
- var area = require_area();
11759
+ var area2 = require_area();
11760
11760
  var offsetFromPoints = (options, points) => {
11761
11761
  const defaults2 = {
11762
11762
  delta: 1,
@@ -11765,8 +11765,8 @@ var require_offsetFromPoints = __commonJS({
11765
11765
  segments: 16
11766
11766
  };
11767
11767
  let { delta, corners, closed, segments } = Object.assign({}, defaults2, options);
11768
- if (Math.abs(delta) < EPS) return points;
11769
- let rotation = options.closed ? area(points) : 1;
11768
+ if (Math.abs(delta) < EPS3) return points;
11769
+ let rotation = options.closed ? area2(points) : 1;
11770
11770
  if (rotation === 0) rotation = 1;
11771
11771
  const orientation2 = rotation > 0 && delta >= 0 || rotation < 0 && delta < 0;
11772
11772
  delta = Math.abs(delta);
@@ -11923,7 +11923,7 @@ var require_extrudePolygon = __commonJS({
11923
11923
  var vec3 = require_vec3();
11924
11924
  var geom3 = require_geom3();
11925
11925
  var poly3 = require_poly3();
11926
- var extrudePolygon = (offsetvector, polygon1) => {
11926
+ var extrudePolygon2 = (offsetvector, polygon1) => {
11927
11927
  const direction = vec3.dot(poly3.plane(polygon1), offsetvector);
11928
11928
  if (direction > 0) {
11929
11929
  polygon1 = poly3.invert(polygon1);
@@ -11944,7 +11944,7 @@ var require_extrudePolygon = __commonJS({
11944
11944
  newpolygons.push(poly3.invert(polygon2));
11945
11945
  return geom3.create(newpolygons);
11946
11946
  };
11947
- module.exports = extrudePolygon;
11947
+ module.exports = extrudePolygon2;
11948
11948
  }
11949
11949
  });
11950
11950
 
@@ -11952,7 +11952,7 @@ var require_extrudePolygon = __commonJS({
11952
11952
  var require_expandShell = __commonJS({
11953
11953
  "node_modules/@jscad/modeling/src/operations/expansions/expandShell.js"(exports, module) {
11954
11954
  "use strict";
11955
- var { EPS, TAU } = require_constants();
11955
+ var { EPS: EPS3, TAU } = require_constants();
11956
11956
  var mat4 = require_mat4();
11957
11957
  var vec3 = require_vec3();
11958
11958
  var fnNumberSort = require_fnNumberSort();
@@ -11961,7 +11961,7 @@ var require_expandShell = __commonJS({
11961
11961
  var sphere = require_sphere();
11962
11962
  var retessellate = require_retessellate();
11963
11963
  var unionGeom3Sub = require_unionGeom3Sub();
11964
- var extrudePolygon = require_extrudePolygon();
11964
+ var extrudePolygon2 = require_extrudePolygon();
11965
11965
  var mapPlaneToVertex = (map, vertex, plane) => {
11966
11966
  const key = vertex.toString();
11967
11967
  if (!map.has(key)) {
@@ -12005,7 +12005,7 @@ var require_expandShell = __commonJS({
12005
12005
  polygons.forEach((polygon2, index2) => {
12006
12006
  const extrudevector = vec3.scale(vec3.create(), poly3.plane(polygon2), 2 * delta);
12007
12007
  const translatedpolygon = poly3.transform(mat4.fromTranslation(mat4.create(), vec3.scale(vec3.create(), extrudevector, -0.5)), polygon2);
12008
- const extrudedface = extrudePolygon(extrudevector, translatedpolygon);
12008
+ const extrudedface = extrudePolygon2(extrudevector, translatedpolygon);
12009
12009
  result = unionGeom3Sub(result, extrudedface);
12010
12010
  const vertices = polygon2.vertices;
12011
12011
  for (let i = 0; i < vertices.length; i++) {
@@ -12057,7 +12057,7 @@ var require_expandShell = __commonJS({
12057
12057
  const p2 = vec3.add(vec3.create(), endpoint, v1);
12058
12058
  let skip = false;
12059
12059
  if (i >= 0) {
12060
- if (vec3.distance(p1, prevp1) < EPS) {
12060
+ if (vec3.distance(p1, prevp1) < EPS3) {
12061
12061
  skip = true;
12062
12062
  }
12063
12063
  }
@@ -12147,14 +12147,14 @@ var require_expandGeom3 = __commonJS({
12147
12147
  var require_expandPath2 = __commonJS({
12148
12148
  "node_modules/@jscad/modeling/src/operations/expansions/expandPath2.js"(exports, module) {
12149
12149
  "use strict";
12150
- var area = require_area();
12150
+ var area2 = require_area();
12151
12151
  var vec2 = require_vec2();
12152
12152
  var geom2 = require_geom2();
12153
12153
  var path2 = require_path2();
12154
12154
  var offsetFromPoints = require_offsetFromPoints();
12155
12155
  var createGeometryFromClosedOffsets = (paths) => {
12156
12156
  let { external, internal } = paths;
12157
- if (area(external) < 0) {
12157
+ if (area2(external) < 0) {
12158
12158
  external = external.reverse();
12159
12159
  } else {
12160
12160
  internal = internal.reverse();
@@ -12467,7 +12467,7 @@ var require_extrudeRectangularPath2 = __commonJS({
12467
12467
  var require_extrudeRectangularGeom2 = __commonJS({
12468
12468
  "node_modules/@jscad/modeling/src/operations/extrusions/extrudeRectangularGeom2.js"(exports, module) {
12469
12469
  "use strict";
12470
- var { area } = require_utils();
12470
+ var { area: area2 } = require_utils();
12471
12471
  var geom2 = require_geom2();
12472
12472
  var path2 = require_path2();
12473
12473
  var expand2 = require_expand();
@@ -12483,7 +12483,7 @@ var require_extrudeRectangularGeom2 = __commonJS({
12483
12483
  const outlines = geom2.toOutlines(geometry);
12484
12484
  if (outlines.length === 0) throw new Error("the given geometry cannot be empty");
12485
12485
  const newparts = outlines.map((outline) => {
12486
- if (area(outline) < 0) outline.reverse();
12486
+ if (area2(outline) < 0) outline.reverse();
12487
12487
  return expand2(options, path2.fromPoints({ closed: true }, outline));
12488
12488
  });
12489
12489
  const allsides = newparts.reduce((sides2, part) => sides2.concat(geom2.toSides(part)), []);
@@ -12876,8 +12876,8 @@ var require_snapPolygons = __commonJS({
12876
12876
  var vec3 = require_vec3();
12877
12877
  var poly3 = require_poly3();
12878
12878
  var isValidPoly3 = (epsilon, polygon2) => {
12879
- const area = Math.abs(poly3.measureArea(polygon2));
12880
- return Number.isFinite(area) && area > epsilon;
12879
+ const area2 = Math.abs(poly3.measureArea(polygon2));
12880
+ return Number.isFinite(area2) && area2 > epsilon;
12881
12881
  };
12882
12882
  var snapPolygons = (epsilon, polygons) => {
12883
12883
  let newpolygons = polygons.map((polygon2) => {
@@ -13563,12 +13563,12 @@ var require_center = __commonJS({
13563
13563
  axes: [true, true, true],
13564
13564
  relativeTo: [0, 0, 0]
13565
13565
  };
13566
- const { axes, relativeTo } = Object.assign({}, defaults2, options);
13566
+ const { axes: axes2, relativeTo } = Object.assign({}, defaults2, options);
13567
13567
  const bounds = measureBoundingBox(object);
13568
13568
  const offset4 = [0, 0, 0];
13569
- if (axes[0]) offset4[0] = relativeTo[0] - (bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2);
13570
- if (axes[1]) offset4[1] = relativeTo[1] - (bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2);
13571
- if (axes[2]) offset4[2] = relativeTo[2] - (bounds[0][2] + (bounds[1][2] - bounds[0][2]) / 2);
13569
+ if (axes2[0]) offset4[0] = relativeTo[0] - (bounds[0][0] + (bounds[1][0] - bounds[0][0]) / 2);
13570
+ if (axes2[1]) offset4[1] = relativeTo[1] - (bounds[0][1] + (bounds[1][1] - bounds[0][1]) / 2);
13571
+ if (axes2[2]) offset4[2] = relativeTo[2] - (bounds[0][2] + (bounds[1][2] - bounds[0][2]) / 2);
13572
13572
  return translate6(offset4, object);
13573
13573
  };
13574
13574
  var center = (options, ...objects) => {
@@ -13577,11 +13577,11 @@ var require_center = __commonJS({
13577
13577
  relativeTo: [0, 0, 0]
13578
13578
  // TODO: Add additional 'methods' of centering: midpoint, centroid
13579
13579
  };
13580
- const { axes, relativeTo } = Object.assign({}, defaults2, options);
13580
+ const { axes: axes2, relativeTo } = Object.assign({}, defaults2, options);
13581
13581
  objects = flatten(objects);
13582
13582
  if (objects.length === 0) throw new Error("wrong number of arguments");
13583
13583
  if (relativeTo.length !== 3) throw new Error("relativeTo must be an array of length 3");
13584
- options = { axes, relativeTo };
13584
+ options = { axes: axes2, relativeTo };
13585
13585
  const results = objects.map((object) => {
13586
13586
  if (path2.isA(object)) return centerGeometry(options, object);
13587
13587
  if (geom2.isA(object)) return centerGeometry(options, object);
@@ -14431,9 +14431,29 @@ var require_browser = __commonJS({
14431
14431
  }
14432
14432
  });
14433
14433
 
14434
+ // src/utils/resolve-fold-pcbs.ts
14435
+ function resolveFoldPcbs(circuitJson, foldPcbs) {
14436
+ return foldPcbs ?? circuitJson.some(
14437
+ (element) => element.type === "cad_component" && element.is_on_folded_board === true
14438
+ );
14439
+ }
14440
+
14434
14441
  // src/CadViewer.tsx
14435
14442
  import { useCallback as useCallback24, useEffect as useEffect49, useRef as useRef29, useState as useState39 } from "react";
14436
- import * as THREE51 from "three";
14443
+ import * as THREE52 from "three";
14444
+
14445
+ // src/hooks/use-convert-children-to-soup.ts
14446
+ import { Circuit } from "@tscircuit/core";
14447
+ import { useMemo } from "react";
14448
+ var useConvertChildrenToCircuitJson = (children) => {
14449
+ return useMemo(() => {
14450
+ if (!children) return [];
14451
+ const circuit = new Circuit();
14452
+ circuit.add(children);
14453
+ circuit.render();
14454
+ return circuit.getCircuitJson();
14455
+ }, [children]);
14456
+ };
14437
14457
 
14438
14458
  // src/CadViewerJscad.tsx
14439
14459
  import { su as su12 } from "@tscircuit/circuit-json-util";
@@ -14457,7 +14477,7 @@ var getCadPcbContext = (cad, circuitJson) => {
14457
14477
 
14458
14478
  // src/AnyCadComponent.tsx
14459
14479
  import { su as su2 } from "@tscircuit/circuit-json-util";
14460
- import { useCallback as useCallback3, useEffect as useEffect11, useMemo as useMemo8, useState as useState7 } from "react";
14480
+ import { useCallback as useCallback3, useEffect as useEffect11, useMemo as useMemo9, useState as useState7 } from "react";
14461
14481
 
14462
14482
  // src/contexts/LayerVisibilityContext.tsx
14463
14483
  import {
@@ -14465,7 +14485,7 @@ import {
14465
14485
  useContext,
14466
14486
  useState,
14467
14487
  useCallback,
14468
- useMemo
14488
+ useMemo as useMemo2
14469
14489
  } from "react";
14470
14490
  import { jsx } from "react/jsx-runtime";
14471
14491
  var ENCLOSURE_VISIBILITY_CYCLE = [
@@ -14512,7 +14532,7 @@ var LayerVisibilityProvider = ({ children }) => {
14512
14532
  const resetToDefaults = useCallback(() => {
14513
14533
  setVisibility(defaultVisibility);
14514
14534
  }, []);
14515
- const value = useMemo(
14535
+ const value = useMemo2(
14516
14536
  () => ({
14517
14537
  visibility,
14518
14538
  setLayerVisibility,
@@ -14533,11 +14553,11 @@ var useLayerVisibility = () => {
14533
14553
  };
14534
14554
 
14535
14555
  // src/hooks/usePcbThickness.ts
14536
- import { useMemo as useMemo2 } from "react";
14556
+ import { useMemo as useMemo3 } from "react";
14537
14557
  import { su } from "@tscircuit/circuit-json-util";
14538
14558
  var DEFAULT_PCB_THICKNESS = 1.2;
14539
14559
  function usePcbThickness(circuitJson) {
14540
- return useMemo2(() => {
14560
+ return useMemo3(() => {
14541
14561
  if (!circuitJson) return DEFAULT_PCB_THICKNESS;
14542
14562
  try {
14543
14563
  const board = su(circuitJson).pcb_board.list()[0];
@@ -37428,7 +37448,7 @@ function getJscadModelForFootprint(footprint, jscad3) {
37428
37448
 
37429
37449
  // src/three-components/FootprinterModel.tsx
37430
37450
  var jscadModeling = __toESM(require_src(), 1);
37431
- import { useMemo as useMemo4, useEffect as useEffect5 } from "react";
37451
+ import { useMemo as useMemo5, useEffect as useEffect5 } from "react";
37432
37452
  import * as THREE4 from "three";
37433
37453
 
37434
37454
  // src/ContainerWithTooltip.tsx
@@ -37440,7 +37460,7 @@ import {
37440
37460
  useContext as useContext3,
37441
37461
  useState as useState3,
37442
37462
  useCallback as useCallback2,
37443
- useMemo as useMemo3,
37463
+ useMemo as useMemo4,
37444
37464
  useEffect as useEffect3,
37445
37465
  useRef as useRef2
37446
37466
  } from "react";
@@ -37457,8 +37477,8 @@ var useHover = () => {
37457
37477
  var HoverProvider = ({ children }) => {
37458
37478
  const { camera, renderer } = useThree();
37459
37479
  const [hoverables, setHoverables] = useState3([]);
37460
- const raycaster = useMemo3(() => new THREE2.Raycaster(), []);
37461
- const mouse = useMemo3(() => new THREE2.Vector2(), []);
37480
+ const raycaster = useMemo4(() => new THREE2.Raycaster(), []);
37481
+ const mouse = useMemo4(() => new THREE2.Vector2(), []);
37462
37482
  const hoverablesRef = useRef2(hoverables);
37463
37483
  hoverablesRef.current = hoverables;
37464
37484
  const hoveredObjectRef = useRef2(null);
@@ -37510,9 +37530,9 @@ var HoverProvider = ({ children }) => {
37510
37530
  }
37511
37531
  return;
37512
37532
  }
37513
- const intersects = raycaster.intersectObjects(objectsToIntersect, true);
37514
- if (intersects.length > 0) {
37515
- const firstIntersect = intersects[0];
37533
+ const intersects2 = raycaster.intersectObjects(objectsToIntersect, true);
37534
+ if (intersects2.length > 0) {
37535
+ const firstIntersect = intersects2[0];
37516
37536
  const newHovered = findHoverable(firstIntersect.object);
37517
37537
  if (newHovered) {
37518
37538
  const eventPayload = {
@@ -37551,7 +37571,7 @@ var HoverProvider = ({ children }) => {
37551
37571
  domElement.removeEventListener("mousemove", onMouseMove);
37552
37572
  };
37553
37573
  }, [renderer, onMouseMove]);
37554
- const contextValue = useMemo3(
37574
+ const contextValue = useMemo4(
37555
37575
  () => ({
37556
37576
  addHoverable,
37557
37577
  removeHoverable
@@ -37610,7 +37630,7 @@ var FootprinterModel = ({
37610
37630
  isTranslucent = false
37611
37631
  }) => {
37612
37632
  const { rootObject } = useThree();
37613
- const group = useMemo4(() => {
37633
+ const group = useMemo5(() => {
37614
37634
  if (!footprint) return null;
37615
37635
  const { geometries } = getJscadModelForFootprint(footprint, jscadModeling);
37616
37636
  const group2 = new THREE4.Group();
@@ -37720,7 +37740,7 @@ var getDefaultEnvironmentMap = (renderer) => {
37720
37740
  };
37721
37741
 
37722
37742
  // src/three-components/useCadModelTransformGraph.ts
37723
- import { useEffect as useEffect6, useMemo as useMemo5 } from "react";
37743
+ import { useEffect as useEffect6, useMemo as useMemo6 } from "react";
37724
37744
  import * as THREE7 from "three";
37725
37745
 
37726
37746
  // src/utils/cad-model-fit.ts
@@ -37788,10 +37808,10 @@ var useCadModelTransformGraph = ({
37788
37808
  scale: scale2
37789
37809
  }) => {
37790
37810
  const { rootObject } = useThree();
37791
- const boardTransformGroup = useMemo5(() => new THREE7.Group(), []);
37792
- const fitTransformGroup = useMemo5(() => new THREE7.Group(), []);
37793
- const modelTransformGroup = useMemo5(() => new THREE7.Group(), []);
37794
- const loaderTransformGroup = useMemo5(() => new THREE7.Group(), []);
37811
+ const boardTransformGroup = useMemo6(() => new THREE7.Group(), []);
37812
+ const fitTransformGroup = useMemo6(() => new THREE7.Group(), []);
37813
+ const modelTransformGroup = useMemo6(() => new THREE7.Group(), []);
37814
+ const loaderTransformGroup = useMemo6(() => new THREE7.Group(), []);
37795
37815
  useEffect6(() => {
37796
37816
  boardTransformGroup.add(fitTransformGroup);
37797
37817
  return () => {
@@ -38028,7 +38048,7 @@ function GltfModel({
38028
38048
  var import_jscad_planner = __toESM(require_dist(), 1);
38029
38049
  var import_modeling = __toESM(require_src(), 1);
38030
38050
  import * as THREE9 from "three";
38031
- import { useMemo as useMemo6, useEffect as useEffect8 } from "react";
38051
+ import { useMemo as useMemo7, useEffect as useEffect8 } from "react";
38032
38052
  import { jsx as jsx7 } from "react/jsx-runtime";
38033
38053
  var JscadModel = ({
38034
38054
  jscadPlan,
@@ -38045,7 +38065,7 @@ var JscadModel = ({
38045
38065
  scale: scale2,
38046
38066
  isTranslucent = false
38047
38067
  }) => {
38048
- const { threeGeom, material } = useMemo6(() => {
38068
+ const { threeGeom, material } = useMemo7(() => {
38049
38069
  const jscadObject = (0, import_jscad_planner.executeJscadOperations)(import_modeling.default, jscadPlan);
38050
38070
  if (!jscadObject || !jscadObject.polygons && !jscadObject.sides) {
38051
38071
  return { threeGeom: null, material: null };
@@ -38060,7 +38080,7 @@ var JscadModel = ({
38060
38080
  });
38061
38081
  return { threeGeom: threeGeom2, material: material2 };
38062
38082
  }, [jscadPlan, isTranslucent]);
38063
- const mesh = useMemo6(() => {
38083
+ const mesh = useMemo7(() => {
38064
38084
  if (!threeGeom) return null;
38065
38085
  const createdMesh = new THREE9.Mesh(threeGeom, material);
38066
38086
  createdMesh.renderOrder = isTranslucent ? 2 : 1;
@@ -38203,7 +38223,7 @@ function useGlobalObjLoader(url) {
38203
38223
  }
38204
38224
 
38205
38225
  // src/three-components/MixedStlModel.tsx
38206
- import { useMemo as useMemo7 } from "react";
38226
+ import { useMemo as useMemo8 } from "react";
38207
38227
  import * as THREE10 from "three";
38208
38228
  import { jsx as jsx8 } from "react/jsx-runtime";
38209
38229
  function MixedStlModel({
@@ -38222,7 +38242,7 @@ function MixedStlModel({
38222
38242
  isTranslucent = false
38223
38243
  }) {
38224
38244
  const obj = useGlobalObjLoader(url);
38225
- const model = useMemo7(() => {
38245
+ const model = useMemo8(() => {
38226
38246
  if (obj && !(obj instanceof Error)) {
38227
38247
  obj.traverse((child) => {
38228
38248
  if (child instanceof THREE10.Mesh && child.material) {
@@ -38796,7 +38816,7 @@ function getAdjustedCadPosition(cadComponent, layer, pcbThickness) {
38796
38816
  return void 0;
38797
38817
  }
38798
38818
  let boardRelativeZ = cadComponent.position.z;
38799
- if (cadComponent.pcb_component_id && layer === "bottom" && cadComponent.position.z >= 0) {
38819
+ if (!cadComponent.is_on_folded_board && cadComponent.pcb_component_id && layer === "bottom" && cadComponent.position.z >= 0) {
38800
38820
  boardRelativeZ = -(cadComponent.position.z + pcbThickness);
38801
38821
  }
38802
38822
  return [cadComponent.position.x, cadComponent.position.y, boardRelativeZ];
@@ -38954,12 +38974,12 @@ var AnyCadComponent = ({
38954
38974
  setIsHovered(false);
38955
38975
  setHoverPosition(null);
38956
38976
  }, []);
38957
- const componentName = useMemo8(() => {
38977
+ const componentName = useMemo9(() => {
38958
38978
  return su2(circuitJson).source_component.getUsing({
38959
38979
  source_component_id: cad_component.source_component_id
38960
38980
  })?.name;
38961
38981
  }, [circuitJson, cad_component.source_component_id]);
38962
- const { pcbComponent, layer, isThroughHole } = useMemo8(
38982
+ const { pcbComponent, layer, isThroughHole } = useMemo9(
38963
38983
  () => getCadPcbContext(cad_component, circuitJson),
38964
38984
  [cad_component, circuitJson]
38965
38985
  );
@@ -38982,7 +39002,7 @@ var AnyCadComponent = ({
38982
39002
  setFallbackModelIndex(0);
38983
39003
  setLastModelError(null);
38984
39004
  }, [cad_component.cad_component_id, url, gltfUrl, stepUrl]);
38985
- const isEnclosure = useMemo8(
39005
+ const isEnclosure = useMemo9(
38986
39006
  () => isLegacyFdmEnclosure(cad_component, circuitJson),
38987
39007
  [cad_component, circuitJson]
38988
39008
  );
@@ -38991,7 +39011,7 @@ var AnyCadComponent = ({
38991
39011
  const renderedModelType = getRenderedCadModelType(sourceModelType);
38992
39012
  const gltfModelType = cad_component.model_glb_url ? "glb" : "gltf";
38993
39013
  const meshModelType = cad_component.model_wrl_url ? "wrl" : cad_component.model_stl_url ? "stl" : "obj";
38994
- const modelTransform = useMemo8(
39014
+ const modelTransform = useMemo9(
38995
39015
  () => getCadModelTransform(cad_component, {
38996
39016
  layer,
38997
39017
  pcbThickness,
@@ -39001,7 +39021,7 @@ var AnyCadComponent = ({
39001
39021
  );
39002
39022
  const rotationOffset = tuple(...modelTransform.rotation);
39003
39023
  const adjustedPosition = modelTransform.position;
39004
- const fallbackModelComponents = useMemo8(() => {
39024
+ const fallbackModelComponents = useMemo9(() => {
39005
39025
  const components = [];
39006
39026
  if (gltfUrl) {
39007
39027
  components.push(
@@ -39198,13 +39218,13 @@ var AnyCadComponent = ({
39198
39218
  };
39199
39219
 
39200
39220
  // src/CadViewerContainer.tsx
39201
- import { forwardRef as forwardRef2, useEffect as useEffect20, useMemo as useMemo16, useState as useState11 } from "react";
39221
+ import { forwardRef as forwardRef2, useEffect as useEffect20, useMemo as useMemo17, useState as useState11 } from "react";
39202
39222
  import * as THREE23 from "three";
39203
39223
 
39204
39224
  // package.json
39205
39225
  var package_default = {
39206
39226
  name: "@tscircuit/3d-viewer",
39207
- version: "0.0.602",
39227
+ version: "0.0.605",
39208
39228
  repository: {
39209
39229
  type: "git",
39210
39230
  url: "https://github.com/tscircuit/3d-viewer"
@@ -39242,7 +39262,7 @@ var package_default = {
39242
39262
  dependencies: {
39243
39263
  "@jscad/regl-renderer": "^2.6.12",
39244
39264
  "@jscad/stl-serializer": "^2.1.20",
39245
- "circuit-json": "^0.0.497",
39265
+ "circuit-json": "^0.0.500",
39246
39266
  "circuit-to-canvas": "^0.0.131",
39247
39267
  "react-hot-toast": "^2.6.0",
39248
39268
  three: "^0.165.0",
@@ -39257,6 +39277,7 @@ var package_default = {
39257
39277
  "@tscircuit/circuit-json-util": "*"
39258
39278
  },
39259
39279
  devDependencies: {
39280
+ "@tscircuit/flex-utils": "https://jscdn.tscircuit.com/@tscircuit/flex-utils/0.0.5.tgz",
39260
39281
  "@biomejs/biome": "^2.1.4",
39261
39282
  "@chromatic-com/storybook": "^1.9.0",
39262
39283
  "@jscad/modeling": "^2.12.5",
@@ -39266,7 +39287,10 @@ var package_default = {
39266
39287
  "@storybook/blocks": "9.0.0-alpha.17",
39267
39288
  "@storybook/react-vite": "^9.1.5",
39268
39289
  "@tscircuit/alphabet": "^0.0.25",
39290
+ "@tscircuit/circuit-json-util": "^0.0.116",
39269
39291
  "@tscircuit/copper-pour-solver": "^0.0.29",
39292
+ "@tscircuit/core": "^0.0.1964",
39293
+ "@tscircuit/props": "^0.0.666",
39270
39294
  "@tscircuit/solver-utils": "^0.0.4",
39271
39295
  "@types/jsdom": "^21.1.7",
39272
39296
  "@types/react": "19",
@@ -39275,7 +39299,6 @@ var package_default = {
39275
39299
  "@vitejs/plugin-react": "^4.3.4",
39276
39300
  "bun-match-svg": "^0.0.9",
39277
39301
  "bun-types": "1.2.1",
39278
- "circuit-json-to-gltf": "0.0.129",
39279
39302
  debug: "^4.4.0",
39280
39303
  "jscad-electronics": "^0.0.178",
39281
39304
  "jscad-planner": "^0.0.13",
@@ -39289,9 +39312,7 @@ var package_default = {
39289
39312
  typescript: "^5.7.3",
39290
39313
  vite: "^7.1.5",
39291
39314
  "vite-tsconfig-paths": "^4.3.2",
39292
- "@tscircuit/core": "^0.0.1955",
39293
- "@tscircuit/props": "^0.0.664",
39294
- "@tscircuit/circuit-json-util": "^0.0.116"
39315
+ "circuit-json-to-gltf": "0.0.129"
39295
39316
  },
39296
39317
  patchedDependencies: {
39297
39318
  "@tscircuit/fanout-solver@0.0.78": "patches/@tscircuit%2Ffanout-solver@0.0.78.patch"
@@ -39299,7 +39320,7 @@ var package_default = {
39299
39320
  };
39300
39321
 
39301
39322
  // src/contexts/appearance-context.tsx
39302
- import { createContext as createContext4, useContext as useContext4, useEffect as useEffect12, useMemo as useMemo9, useState as useState8 } from "react";
39323
+ import { createContext as createContext4, useContext as useContext4, useEffect as useEffect12, useMemo as useMemo10, useState as useState8 } from "react";
39303
39324
  import { jsx as jsx11 } from "react/jsx-runtime";
39304
39325
  var LIGHTING_STORAGE_KEY = "cadViewerLightingEnabled";
39305
39326
  var readStoredLightingEnabled = () => {
@@ -39323,7 +39344,7 @@ var AppearanceProvider = ({
39323
39344
  lightingEnabled ? "true" : "false"
39324
39345
  );
39325
39346
  }, [lightingEnabled]);
39326
- const value = useMemo9(
39347
+ const value = useMemo10(
39327
39348
  () => ({
39328
39349
  darkBackgroundEnabled,
39329
39350
  setDarkBackgroundEnabled,
@@ -39349,7 +39370,7 @@ import {
39349
39370
  createContext as createContext5,
39350
39371
  useCallback as useCallback4,
39351
39372
  useContext as useContext5,
39352
- useMemo as useMemo10,
39373
+ useMemo as useMemo11,
39353
39374
  useRef as useRef3,
39354
39375
  useState as useState9
39355
39376
  } from "react";
@@ -39404,7 +39425,7 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
39404
39425
  const [cameraRotation, setCameraRotation] = useState9(
39405
39426
  new THREE13.Euler(0, 0, 0)
39406
39427
  );
39407
- const baseDistance = useMemo10(() => {
39428
+ const baseDistance = useMemo11(() => {
39408
39429
  const [x, y, z42] = initialCameraPosition ?? [5, -5, 5];
39409
39430
  const distance6 = Math.hypot(
39410
39431
  x - defaultTarget.x,
@@ -39512,7 +39533,7 @@ var CameraControllerProvider = ({ children, defaultTarget, initialCameraPosition
39512
39533
  },
39513
39534
  []
39514
39535
  );
39515
- const cameraControllerContextValue = useMemo10(
39536
+ const cameraControllerContextValue = useMemo11(
39516
39537
  () => ({
39517
39538
  controlsRef,
39518
39539
  mainCameraRef,
@@ -39747,7 +39768,7 @@ import {
39747
39768
  useCallback as useCallback7,
39748
39769
  forwardRef,
39749
39770
  useImperativeHandle,
39750
- useMemo as useMemo11
39771
+ useMemo as useMemo12
39751
39772
  } from "react";
39752
39773
  import * as THREE16 from "three";
39753
39774
 
@@ -39795,7 +39816,7 @@ var Canvas = forwardRef(
39795
39816
  },
39796
39817
  []
39797
39818
  );
39798
- const scene = useMemo11(() => new THREE16.Scene(), []);
39819
+ const scene = useMemo12(() => new THREE16.Scene(), []);
39799
39820
  if (sceneProps?.up) {
39800
39821
  scene.up.set(sceneProps.up.x, sceneProps.up.y, sceneProps.up.z);
39801
39822
  }
@@ -39851,16 +39872,23 @@ var Canvas = forwardRef(
39851
39872
  onCreatedRef.current?.({ camera, renderer });
39852
39873
  let animationFrameId;
39853
39874
  const clock = new THREE16.Clock();
39875
+ let isVisible = true;
39876
+ const visibilityObserver = new IntersectionObserver(([entry]) => {
39877
+ isVisible = entry?.isIntersecting ?? false;
39878
+ if (isVisible) handleResize();
39879
+ });
39880
+ visibilityObserver.observe(mountRef.current);
39854
39881
  const animate = () => {
39882
+ animationFrameId = requestAnimationFrame(animate);
39883
+ if (!isVisible) return;
39855
39884
  const time = clock.getElapsedTime();
39856
39885
  const delta = clock.getDelta();
39857
39886
  frameListeners.current.forEach((listener) => listener(time, delta));
39858
39887
  renderer.render(scene, camera);
39859
- animationFrameId = requestAnimationFrame(animate);
39860
39888
  };
39861
39889
  animate();
39862
39890
  const handleResize = () => {
39863
- if (mountRef.current) {
39891
+ if (mountRef.current?.clientWidth && mountRef.current.clientHeight) {
39864
39892
  const newAspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
39865
39893
  if (camera instanceof THREE16.PerspectiveCamera) {
39866
39894
  camera.aspect = newAspect;
@@ -39886,6 +39914,7 @@ var Canvas = forwardRef(
39886
39914
  };
39887
39915
  window.removeEventListener("resize", handleResize);
39888
39916
  cancelAnimationFrame(animationFrameId);
39917
+ visibilityObserver.disconnect();
39889
39918
  if (mountRef.current && renderer.domElement) {
39890
39919
  mountRef.current.removeChild(renderer.domElement);
39891
39920
  }
@@ -39901,7 +39930,7 @@ var Canvas = forwardRef(
39901
39930
  );
39902
39931
 
39903
39932
  // src/react-three/Grid.tsx
39904
- import { useEffect as useEffect15, useMemo as useMemo12 } from "react";
39933
+ import { useEffect as useEffect15, useMemo as useMemo13 } from "react";
39905
39934
  import * as THREE17 from "three";
39906
39935
  var vertexShader = `
39907
39936
  varying vec3 worldPosition;
@@ -39947,7 +39976,7 @@ var Grid = ({
39947
39976
  }) => {
39948
39977
  const { scene, camera } = useThree();
39949
39978
  const size4 = 1e3;
39950
- const gridMesh = useMemo12(() => {
39979
+ const gridMesh = useMemo13(() => {
39951
39980
  const geometry = new THREE17.PlaneGeometry(size4, size4);
39952
39981
  geometry.rotateX(-Math.PI / 2);
39953
39982
  const material = new THREE17.ShaderMaterial({
@@ -39993,7 +40022,7 @@ var Grid = ({
39993
40022
  };
39994
40023
 
39995
40024
  // src/react-three/Lights.tsx
39996
- import { useEffect as useEffect16, useMemo as useMemo13 } from "react";
40025
+ import { useEffect as useEffect16, useMemo as useMemo14 } from "react";
39997
40026
  import * as THREE18 from "three";
39998
40027
  var UNDERSIDE_LIGHT_FACTOR = 0.75;
39999
40028
  var Lights = ({
@@ -40003,7 +40032,7 @@ var Lights = ({
40003
40032
  shadowsEnabled = false
40004
40033
  }) => {
40005
40034
  const { scene } = useThree();
40006
- const lightRig = useMemo13(() => {
40035
+ const lightRig = useMemo14(() => {
40007
40036
  const rig = new THREE18.Group();
40008
40037
  rig.name = "cad-viewer-light-rig";
40009
40038
  const centerX = boardCenter?.x ?? 0;
@@ -40118,7 +40147,7 @@ var Lights = ({
40118
40147
  };
40119
40148
 
40120
40149
  // src/react-three/OrbitControls.tsx
40121
- import { useEffect as useEffect17, useMemo as useMemo14 } from "react";
40150
+ import { useEffect as useEffect17, useMemo as useMemo15 } from "react";
40122
40151
  import * as THREE19 from "three";
40123
40152
  import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
40124
40153
  var OrbitControls = ({
@@ -40134,7 +40163,7 @@ var OrbitControls = ({
40134
40163
  onControlsChange
40135
40164
  }) => {
40136
40165
  const { camera, renderer } = useThree();
40137
- const controls = useMemo14(() => {
40166
+ const controls = useMemo15(() => {
40138
40167
  if (!camera || !renderer) return null;
40139
40168
  return new ThreeOrbitControls(camera, renderer.domElement);
40140
40169
  }, [camera, renderer]);
@@ -40383,7 +40412,14 @@ var OrientationCubeCanvas = () => {
40383
40412
  group.add(topText);
40384
40413
  group.add(bottomText);
40385
40414
  let animationFrameId = null;
40415
+ let isVisible = true;
40416
+ const visibilityObserver = new IntersectionObserver(([entry]) => {
40417
+ isVisible = entry?.isIntersecting ?? false;
40418
+ });
40419
+ visibilityObserver.observe(canvas);
40386
40420
  const animate = () => {
40421
+ animationFrameId = requestAnimationFrame(animate);
40422
+ if (!isVisible) return;
40387
40423
  if (mainCameraRef.current) {
40388
40424
  const cameraPosition = computePointInFront(
40389
40425
  mainCameraRef.current.rotation ?? new THREE20.Euler(0, 0, 0),
@@ -40395,10 +40431,10 @@ var OrientationCubeCanvas = () => {
40395
40431
  }
40396
40432
  }
40397
40433
  renderer.render(scene, camera);
40398
- animationFrameId = requestAnimationFrame(animate);
40399
40434
  };
40400
40435
  animate();
40401
40436
  return () => {
40437
+ visibilityObserver.disconnect();
40402
40438
  canvas.remove();
40403
40439
  if (animationFrameId !== null) {
40404
40440
  cancelAnimationFrame(animationFrameId);
@@ -40435,7 +40471,7 @@ var OrientationCubeCanvas = () => {
40435
40471
  };
40436
40472
 
40437
40473
  // src/three-components/reference-object.tsx
40438
- import { useEffect as useEffect19, useMemo as useMemo15 } from "react";
40474
+ import { useEffect as useEffect19, useMemo as useMemo16 } from "react";
40439
40475
 
40440
40476
  // src/reference-objects/create-reference-object.ts
40441
40477
  import * as THREE21 from "three";
@@ -40821,7 +40857,7 @@ var ReferenceObject = ({
40821
40857
  boardCenter
40822
40858
  }) => {
40823
40859
  const { scene } = useThree();
40824
- const object = useMemo15(() => {
40860
+ const object = useMemo16(() => {
40825
40861
  const nextObject = createReferenceObject(type);
40826
40862
  const position = getReferenceObjectPosition(
40827
40863
  type,
@@ -40887,17 +40923,17 @@ var CadViewerContainer = forwardRef2(
40887
40923
  onCameraControllerReady(controller);
40888
40924
  }
40889
40925
  }, [controller, onCameraControllerReady]);
40890
- const comparisonBounds = useMemo16(() => {
40926
+ const comparisonBounds = useMemo17(() => {
40891
40927
  if (!referenceObject) return void 0;
40892
40928
  return getComparisonBounds(referenceObject, boardDimensions, boardCenter);
40893
40929
  }, [referenceObject, boardDimensions, boardCenter]);
40894
- const gridSectionSize = useMemo16(() => {
40930
+ const gridSectionSize = useMemo17(() => {
40895
40931
  if (!boardDimensions) return 10;
40896
40932
  const width10 = boardDimensions.width ?? 0;
40897
40933
  const height10 = boardDimensions.height ?? 0;
40898
40934
  return Math.max(Math.max(width10, height10) * 1.5, 10);
40899
40935
  }, [boardDimensions]);
40900
- const orbitTarget = useMemo16(() => {
40936
+ const orbitTarget = useMemo17(() => {
40901
40937
  if (comparisonBounds) {
40902
40938
  return [
40903
40939
  (comparisonBounds.minX + comparisonBounds.maxX) / 2,
@@ -41030,19 +41066,6 @@ var CadViewerContainer = forwardRef2(
41030
41066
  }
41031
41067
  );
41032
41068
 
41033
- // src/hooks/use-convert-children-to-soup.ts
41034
- import { Circuit } from "@tscircuit/core";
41035
- import { useMemo as useMemo17 } from "react";
41036
- var useConvertChildrenToCircuitJson = (children) => {
41037
- return useMemo17(() => {
41038
- if (!children) return [];
41039
- const circuit = new Circuit();
41040
- circuit.add(children);
41041
- circuit.render();
41042
- return circuit.getCircuitJson();
41043
- }, [children]);
41044
- };
41045
-
41046
41069
  // src/hooks/use-stls-from-geom.ts
41047
41070
  import { useState as useState12, useEffect as useEffect21 } from "react";
41048
41071
  import stlSerializer from "@jscad/stl-serializer";
@@ -41091,14 +41114,14 @@ var import_primitives = __toESM(require_primitives(), 1);
41091
41114
  var import_transforms = __toESM(require_transforms(), 1);
41092
41115
  var import_expansions = __toESM(require_expansions(), 1);
41093
41116
  var arePointsClockwise = (points) => {
41094
- let area = 0;
41117
+ let area2 = 0;
41095
41118
  for (let i = 0; i < points.length; i++) {
41096
41119
  const j = (i + 1) % points.length;
41097
- area += points[i][0] * points[j][1];
41098
- area -= points[j][0] * points[i][1];
41120
+ area2 += points[i][0] * points[j][1];
41121
+ area2 -= points[j][0] * points[i][1];
41099
41122
  }
41100
- const signedArea = area / 2;
41101
- return signedArea <= 0;
41123
+ const signedArea2 = area2 / 2;
41124
+ return signedArea2 <= 0;
41102
41125
  };
41103
41126
  var createBoardGeomWithOutline = (board, depth = 1.2, options = {}) => {
41104
41127
  const { xyOutset = 0 } = options;
@@ -41129,6 +41152,7 @@ var colors = {
41129
41152
  fr4SolderMaskGreen: [0.06, 0.31, 0.19],
41130
41153
  fr4TracesWithMaskGreen: [0.09, 0.38, 0.23],
41131
41154
  fr4TracesWithoutMaskTan: [0.6, 0.43, 0.28],
41155
+ flexAmber: [0.8, 0.61, 0.2],
41132
41156
  fr1Tan: [0.8, 0.4, 0.2],
41133
41157
  fr1TracesWithMaskCopper: [0.9, 0.6, 0.2],
41134
41158
  fr1SolderMaskGreen: [0.02, 0.1, 0.04]
@@ -41139,11 +41163,13 @@ var TRACE_TEXTURE_RESOLUTION = 150;
41139
41163
  var FAUX_BOARD_OPACITY = 0.6;
41140
41164
  var boardMaterialColors = {
41141
41165
  fr1: colors.fr1Tan,
41142
- fr4: colors.fr4Tan
41166
+ fr4: colors.fr4Tan,
41167
+ flex: colors.flexAmber
41143
41168
  };
41144
41169
  var soldermaskColors = {
41145
41170
  fr1: colors.fr1SolderMaskGreen,
41146
- fr4: colors.fr4SolderMaskGreen
41171
+ fr4: colors.fr4SolderMaskGreen,
41172
+ flex: colors.flexAmber
41147
41173
  };
41148
41174
 
41149
41175
  // src/utils/soldermask-color.ts
@@ -44646,6 +44672,7 @@ var createDataTexture = (canvas) => {
44646
44672
  var createBoardReliefTextures = (texture, maskedCopperMask) => {
44647
44673
  const sourceCanvas = texture.image;
44648
44674
  if (!sourceCanvas?.width || !sourceCanvas.height) return null;
44675
+ const { width: canvasWidth, height: canvasHeight } = sourceCanvas;
44649
44676
  const sourceCtx = sourceCanvas.getContext("2d");
44650
44677
  if (!sourceCtx) return null;
44651
44678
  const maskCanvas = maskedCopperMask?.image;
@@ -44653,48 +44680,37 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
44653
44680
  const maskWidth = maskCanvas?.width ?? 0;
44654
44681
  const maskHeight = maskCanvas?.height ?? 0;
44655
44682
  const maskImageData = maskCtx && maskWidth && maskHeight ? maskCtx.getImageData(0, 0, maskWidth, maskHeight) : null;
44656
- const imageData = sourceCtx.getImageData(
44657
- 0,
44658
- 0,
44659
- sourceCanvas.width,
44660
- sourceCanvas.height
44661
- );
44683
+ const imageData = sourceCtx.getImageData(0, 0, canvasWidth, canvasHeight);
44662
44684
  const data = imageData.data;
44663
- const heights = new Float32Array(sourceCanvas.width * sourceCanvas.height);
44685
+ const heights = new Float32Array(canvasWidth * canvasHeight);
44664
44686
  const roughnessCanvas = document.createElement("canvas");
44665
44687
  const metalnessCanvas = document.createElement("canvas");
44666
- roughnessCanvas.width = metalnessCanvas.width = sourceCanvas.width;
44667
- roughnessCanvas.height = metalnessCanvas.height = sourceCanvas.height;
44688
+ roughnessCanvas.width = metalnessCanvas.width = canvasWidth;
44689
+ roughnessCanvas.height = metalnessCanvas.height = canvasHeight;
44668
44690
  const roughnessCtx = roughnessCanvas.getContext("2d");
44669
44691
  const metalnessCtx = metalnessCanvas.getContext("2d");
44670
44692
  if (!roughnessCtx || !metalnessCtx) return null;
44671
44693
  const roughnessImageData = roughnessCtx.createImageData(
44672
- sourceCanvas.width,
44673
- sourceCanvas.height
44694
+ canvasWidth,
44695
+ canvasHeight
44674
44696
  );
44675
44697
  const metalnessImageData = metalnessCtx.createImageData(
44676
- sourceCanvas.width,
44677
- sourceCanvas.height
44698
+ canvasWidth,
44699
+ canvasHeight
44678
44700
  );
44679
44701
  const roughnessData = roughnessImageData.data;
44680
44702
  const metalnessData = metalnessImageData.data;
44681
44703
  for (let i = 0; i < data.length; i += 4) {
44682
44704
  const pixelIndex = i / 4;
44683
- const x = pixelIndex % sourceCanvas.width;
44684
- const y = Math.floor(pixelIndex / sourceCanvas.width);
44705
+ const x = pixelIndex % canvasWidth;
44706
+ const y = Math.floor(pixelIndex / canvasWidth);
44685
44707
  const alpha = data[i + 3] ?? 0;
44686
44708
  if (alpha < 16) {
44687
44709
  heights[pixelIndex] = invertSurfaceHeight(PLAIN_SOLDERMASK_HEIGHT);
44688
44710
  continue;
44689
44711
  }
44690
- const maskX = maskImageData ? Math.min(
44691
- maskWidth - 1,
44692
- Math.floor(x / sourceCanvas.width * maskWidth)
44693
- ) : 0;
44694
- const maskY = maskImageData ? Math.min(
44695
- maskHeight - 1,
44696
- Math.floor(y / sourceCanvas.height * maskHeight)
44697
- ) : 0;
44712
+ const maskX = maskImageData ? Math.min(maskWidth - 1, Math.floor(x / canvasWidth * maskWidth)) : 0;
44713
+ const maskY = maskImageData ? Math.min(maskHeight - 1, Math.floor(y / canvasHeight * maskHeight)) : 0;
44698
44714
  const maskAlpha = maskImageData ? maskImageData.data[(maskY * maskWidth + maskX) * 4 + 3] ?? 0 : 0;
44699
44715
  const profile = getBoardSurfaceProfile(
44700
44716
  data[i] ?? 0,
@@ -44702,13 +44718,13 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
44702
44718
  data[i + 2] ?? 0,
44703
44719
  maskAlpha >= 16
44704
44720
  );
44705
- const salt = sourceCanvas.width + sourceCanvas.height;
44721
+ const salt = canvasWidth + canvasHeight;
44706
44722
  const fineGrain = profile.isExposedCopper ? createCopperDetail(x, y, salt) : profile.isMaskedCopper ? createMaskedTraceDetail(x, y, salt) : 0;
44707
- const height10 = clamp01(
44723
+ const surfaceHeight = clamp01(
44708
44724
  invertSurfaceHeight(profile.height) + fineGrain * profile.microSurfaceWeight
44709
44725
  );
44710
- heights[pixelIndex] = height10;
44711
- const heightChannel = height10 * 255;
44726
+ heights[pixelIndex] = surfaceHeight;
44727
+ const heightChannel = surfaceHeight * 255;
44712
44728
  data[i] = data[i + 1] = data[i + 2] = heightChannel;
44713
44729
  data[i + 3] = 255;
44714
44730
  const roughness = profile.isExposedCopper ? clamp01(
@@ -44726,31 +44742,28 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
44726
44742
  roughnessCtx.putImageData(roughnessImageData, 0, 0);
44727
44743
  metalnessCtx.putImageData(metalnessImageData, 0, 0);
44728
44744
  const bumpCanvas = document.createElement("canvas");
44729
- bumpCanvas.width = sourceCanvas.width;
44730
- bumpCanvas.height = sourceCanvas.height;
44745
+ bumpCanvas.width = canvasWidth;
44746
+ bumpCanvas.height = canvasHeight;
44731
44747
  const bumpCtx = bumpCanvas.getContext("2d");
44732
44748
  if (!bumpCtx) return null;
44733
44749
  bumpCtx.putImageData(imageData, 0, 0);
44734
44750
  const normalCanvas = document.createElement("canvas");
44735
- normalCanvas.width = sourceCanvas.width;
44736
- normalCanvas.height = sourceCanvas.height;
44751
+ normalCanvas.width = canvasWidth;
44752
+ normalCanvas.height = canvasHeight;
44737
44753
  const normalCtx = normalCanvas.getContext("2d");
44738
44754
  if (!normalCtx) return null;
44739
- const normalImageData = normalCtx.createImageData(
44740
- sourceCanvas.width,
44741
- sourceCanvas.height
44742
- );
44755
+ const normalImageData = normalCtx.createImageData(canvasWidth, canvasHeight);
44743
44756
  const normalData = normalImageData.data;
44744
- const getHeight4 = (x, y) => heights[Math.max(0, Math.min(sourceCanvas.height - 1, y)) * sourceCanvas.width + Math.max(0, Math.min(sourceCanvas.width - 1, x))] ?? 0;
44745
- for (let y = 0; y < sourceCanvas.height; y++) {
44746
- for (let x = 0; x < sourceCanvas.width; x++) {
44757
+ const getHeight4 = (x, y) => heights[Math.max(0, Math.min(canvasHeight - 1, y)) * canvasWidth + Math.max(0, Math.min(canvasWidth - 1, x))] ?? 0;
44758
+ for (let y = 0; y < canvasHeight; y++) {
44759
+ for (let x = 0; x < canvasWidth; x++) {
44747
44760
  const dx = (getHeight4(x + 1, y) - getHeight4(x - 1, y)) * 4;
44748
44761
  const dy = (getHeight4(x, y + 1) - getHeight4(x, y - 1)) * 4;
44749
- const normal = new THREE40.Vector3(-dx, -dy, 1).normalize();
44750
- const i = (y * sourceCanvas.width + x) * 4;
44751
- normalData[i] = (normal.x * 0.5 + 0.5) * 255;
44752
- normalData[i + 1] = (normal.y * 0.5 + 0.5) * 255;
44753
- normalData[i + 2] = (normal.z * 0.5 + 0.5) * 255;
44762
+ const inverseLength = 1 / Math.sqrt(dx * dx + dy * dy + 1);
44763
+ const i = (y * canvasWidth + x) * 4;
44764
+ normalData[i] = (-dx * inverseLength * 0.5 + 0.5) * 255;
44765
+ normalData[i + 1] = (-dy * inverseLength * 0.5 + 0.5) * 255;
44766
+ normalData[i + 2] = (inverseLength * 0.5 + 0.5) * 255;
44754
44767
  normalData[i + 3] = 255;
44755
44768
  }
44756
44769
  }
@@ -45400,28 +45413,1149 @@ var CadViewerJscad = forwardRef3(
45400
45413
  }
45401
45414
  );
45402
45415
 
45416
+ // node_modules/earcut/src/earcut.js
45417
+ var steiners = /* @__PURE__ */ new Set();
45418
+ var filteredOut = false;
45419
+ function earcut(data, holeIndices, dim = 2) {
45420
+ const hasHoles = holeIndices && holeIndices.length;
45421
+ const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
45422
+ if (steiners.size) steiners.clear();
45423
+ let outerNode = linkedList(data, 0, outerLen, dim, true);
45424
+ const triangles = [];
45425
+ if (!outerNode || outerNode.next === outerNode.prev) return triangles;
45426
+ let minX = 0, minY = 0, invSize = 0;
45427
+ if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
45428
+ if (data.length > 80 * dim) {
45429
+ minX = data[0];
45430
+ minY = data[1];
45431
+ let maxX = minX;
45432
+ let maxY = minY;
45433
+ for (let i = dim; i < outerLen; i += dim) {
45434
+ const x = data[i];
45435
+ const y = data[i + 1];
45436
+ if (x < minX) minX = x;
45437
+ if (y < minY) minY = y;
45438
+ if (x > maxX) maxX = x;
45439
+ if (y > maxY) maxY = y;
45440
+ }
45441
+ invSize = Math.max(maxX - minX, maxY - minY);
45442
+ invSize = invSize !== 0 ? 32767 / invSize : 0;
45443
+ }
45444
+ earcutLinked(outerNode, triangles, minX, minY, invSize);
45445
+ return triangles;
45446
+ }
45447
+ function linkedList(data, start, end, dim, clockwise) {
45448
+ let last = null;
45449
+ if (clockwise === signedArea(data, start, end, dim) > 0) {
45450
+ for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
45451
+ } else {
45452
+ for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
45453
+ }
45454
+ if (last && equals(last, last.next)) {
45455
+ removeNode(last);
45456
+ last = last.next;
45457
+ }
45458
+ return last;
45459
+ }
45460
+ function filterPoints(start, end = start) {
45461
+ const full = end === start;
45462
+ let p = start, again;
45463
+ do {
45464
+ again = false;
45465
+ if (p !== p.next && (steiners.size === 0 || !steiners.has(p)) && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
45466
+ if (full || p === end) end = p.prev;
45467
+ filteredOut = true;
45468
+ removeNode(p);
45469
+ p = p.prev;
45470
+ again = true;
45471
+ } else if (full || p !== end) {
45472
+ p = p.next;
45473
+ again = !full;
45474
+ }
45475
+ } while (again || p !== end);
45476
+ return end;
45477
+ }
45478
+ function earcutLinked(ear, triangles, minX, minY, invSize) {
45479
+ if (invSize) indexCurve(ear, minX, minY, invSize);
45480
+ let stop = ear, cured = false;
45481
+ while (ear.prev !== ear.next) {
45482
+ const prev = ear.prev;
45483
+ const next = ear.next;
45484
+ if (area(prev, ear, next) < 0 && (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear))) {
45485
+ triangles.push(prev.i, ear.i, next.i);
45486
+ removeNode(ear);
45487
+ ear = next;
45488
+ stop = next;
45489
+ continue;
45490
+ }
45491
+ ear = next;
45492
+ if (ear === stop) {
45493
+ filteredOut = false;
45494
+ ear = filterPoints(ear);
45495
+ if (filteredOut) {
45496
+ stop = ear;
45497
+ continue;
45498
+ }
45499
+ if (!cured) {
45500
+ ear = cureLocalIntersections(ear, triangles);
45501
+ stop = ear;
45502
+ cured = true;
45503
+ continue;
45504
+ }
45505
+ splitEarcut(ear, triangles, minX, minY, invSize);
45506
+ break;
45507
+ }
45508
+ }
45509
+ }
45510
+ function isEar(ear) {
45511
+ const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy);
45512
+ let p = c.next;
45513
+ while (p !== a) {
45514
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
45515
+ p = p.next;
45516
+ }
45517
+ return true;
45518
+ }
45519
+ function isEarHashed(ear, minX, minY, invSize) {
45520
+ const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy), minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize);
45521
+ let p = ear.prevZ;
45522
+ while (p && p.z >= minZ) {
45523
+ if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== c && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
45524
+ p = p.prevZ;
45525
+ }
45526
+ let n = ear.nextZ;
45527
+ while (n && n.z <= maxZ) {
45528
+ if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== c && !(ax === n.x && ay === n.y) && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
45529
+ n = n.nextZ;
45530
+ }
45531
+ return true;
45532
+ }
45533
+ function cureLocalIntersections(start, triangles) {
45534
+ let p = start;
45535
+ let cured = false;
45536
+ do {
45537
+ const a = p.prev, b = p.next.next;
45538
+ if (intersects(a, p, p.next, b, false) && locallyInside(a, b) && locallyInside(b, a)) {
45539
+ triangles.push(a.i, p.i, b.i);
45540
+ removeNode(p);
45541
+ removeNode(p.next);
45542
+ p = start = b;
45543
+ cured = true;
45544
+ }
45545
+ p = p.next;
45546
+ } while (p !== start);
45547
+ return cured ? filterPoints(p) : p;
45548
+ }
45549
+ function splitEarcut(start, triangles, minX, minY, invSize) {
45550
+ let a = start;
45551
+ do {
45552
+ let b = a.next.next;
45553
+ while (b !== a.prev) {
45554
+ if (a.i !== b.i && isValidDiagonal(a, b)) {
45555
+ let c = splitPolygon(a, b);
45556
+ a = filterPoints(a, a.next);
45557
+ c = filterPoints(c, c.next);
45558
+ earcutLinked(a, triangles, minX, minY, invSize);
45559
+ earcutLinked(c, triangles, minX, minY, invSize);
45560
+ return;
45561
+ }
45562
+ b = b.next;
45563
+ }
45564
+ a = a.next;
45565
+ } while (a !== start);
45566
+ }
45567
+ var indexActive = false;
45568
+ function eliminateHoles(data, holeIndices, outerNode, dim) {
45569
+ const queue = [];
45570
+ for (let i = 0, len = holeIndices.length; i < len; i++) {
45571
+ const start = holeIndices[i] * dim;
45572
+ const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
45573
+ const list = (
45574
+ /** @type {Node} */
45575
+ linkedList(data, start, end, dim, false)
45576
+ );
45577
+ if (list === list.next) steiners.add(list);
45578
+ queue.push(getLeftmost(list));
45579
+ }
45580
+ queue.sort(compareXYSlope);
45581
+ buildBlockIndex(data.length / dim, holeIndices.length);
45582
+ indexSegment(outerNode, outerNode);
45583
+ indexActive = true;
45584
+ for (let i = 0; i < queue.length; i++) {
45585
+ outerNode = eliminateHole(queue[i], outerNode);
45586
+ }
45587
+ indexActive = false;
45588
+ return filterPoints(outerNode);
45589
+ }
45590
+ function compareXYSlope(a, b) {
45591
+ return a.x - b.x || a.y - b.y || (a.next.y - a.y) / (a.next.x - a.x) - (b.next.y - b.y) / (b.next.x - b.x);
45592
+ }
45593
+ function eliminateHole(hole, outerNode) {
45594
+ const bridge = findHoleBridge(hole, outerNode);
45595
+ if (!bridge) {
45596
+ return outerNode;
45597
+ }
45598
+ const bridgeReverse = splitPolygon(bridge, hole);
45599
+ const bridge2 = bridgeReverse.next;
45600
+ indexSegment(bridge, bridge2.next);
45601
+ filterPoints(bridgeReverse, bridgeReverse.next);
45602
+ return filterPoints(bridge, bridge.next);
45603
+ }
45604
+ var K = 16;
45605
+ var blockBBox = new Float64Array(0);
45606
+ var numBlocks = 0;
45607
+ var blockHead = [];
45608
+ var blockStop = [];
45609
+ function buildBlockIndex(maxNodes, numHoles) {
45610
+ const maxBlocks = Math.ceil((maxNodes + 2 * numHoles) / K) + numHoles + 2;
45611
+ if (blockBBox.length < maxBlocks * 4) blockBBox = new Float64Array(maxBlocks * 4);
45612
+ numBlocks = 0;
45613
+ }
45614
+ function indexSegment(head, stop) {
45615
+ let p = head;
45616
+ do {
45617
+ const b = numBlocks++;
45618
+ blockHead[b] = p;
45619
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
45620
+ let k = 0;
45621
+ do {
45622
+ const c = p.next;
45623
+ p.z = b;
45624
+ if (p.x < minX) minX = p.x;
45625
+ if (p.x > maxX) maxX = p.x;
45626
+ if (p.y < minY) minY = p.y;
45627
+ if (p.y > maxY) maxY = p.y;
45628
+ if (c.x < minX) minX = c.x;
45629
+ if (c.x > maxX) maxX = c.x;
45630
+ if (c.y < minY) minY = c.y;
45631
+ if (c.y > maxY) maxY = c.y;
45632
+ p = c;
45633
+ } while (++k < K && p !== stop);
45634
+ blockStop[b] = p;
45635
+ const g = b * 4;
45636
+ blockBBox[g] = minX;
45637
+ blockBBox[g + 1] = minY;
45638
+ blockBBox[g + 2] = maxX;
45639
+ blockBBox[g + 3] = maxY;
45640
+ } while (p !== stop);
45641
+ }
45642
+ function growBlock(head, tail) {
45643
+ const g = head.z * 4;
45644
+ if (tail.x < blockBBox[g]) blockBBox[g] = tail.x;
45645
+ if (tail.y < blockBBox[g + 1]) blockBBox[g + 1] = tail.y;
45646
+ if (tail.x > blockBBox[g + 2]) blockBBox[g + 2] = tail.x;
45647
+ if (tail.y > blockBBox[g + 3]) blockBBox[g + 3] = tail.y;
45648
+ }
45649
+ function liveBlockStop(b) {
45650
+ let stop = blockStop[b];
45651
+ while (stop.prev.next !== stop) stop = stop.next;
45652
+ blockStop[b] = stop;
45653
+ return stop;
45654
+ }
45655
+ function liveBlockHead(b) {
45656
+ let head = blockHead[b];
45657
+ while (head.prev.next !== head) head = head.next;
45658
+ blockHead[b] = head;
45659
+ return head;
45660
+ }
45661
+ function findHoleBridge(hole, outerNode) {
45662
+ let p = outerNode;
45663
+ const hx = hole.x;
45664
+ const hy = hole.y;
45665
+ let qx = -Infinity;
45666
+ let m;
45667
+ if (equals(hole, p)) return p;
45668
+ for (let b = 0, g = 0; b < numBlocks; b++, g += 4) {
45669
+ if (hy < blockBBox[g + 1] || hy > blockBBox[g + 3] || blockBBox[g] > hx || blockBBox[g + 2] <= qx) continue;
45670
+ const stop = liveBlockStop(b);
45671
+ p = liveBlockHead(b);
45672
+ do {
45673
+ if (p.prev.next === p) {
45674
+ if (equals(hole, p.next)) return p.next;
45675
+ else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
45676
+ const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
45677
+ if (x <= hx && x > qx) {
45678
+ qx = x;
45679
+ m = p.x < p.next.x ? p : p.next;
45680
+ if (x === hx) return m;
45681
+ }
45682
+ }
45683
+ }
45684
+ p = p.next;
45685
+ } while (p !== stop);
45686
+ }
45687
+ if (!m) return null;
45688
+ const mx = m.x;
45689
+ const my = m.y;
45690
+ const tminY = Math.min(hy, my);
45691
+ const tmaxY = Math.max(hy, my);
45692
+ let tanMin = Infinity;
45693
+ for (let b = 0, g = 0; b < numBlocks; b++, g += 4) {
45694
+ if (blockBBox[g + 2] < mx || blockBBox[g] > hx || blockBBox[g + 3] < tminY || blockBBox[g + 1] > tmaxY) continue;
45695
+ const stop = liveBlockStop(b);
45696
+ p = liveBlockHead(b);
45697
+ do {
45698
+ if (p.prev.next === p && hx >= p.x && p.x >= mx && hx !== p.x && // skip dead nodes
45699
+ pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
45700
+ const tan = Math.abs(hy - p.y) / (hx - p.x);
45701
+ if ((locallyInside(p, hole) || p.y === hy && p.next.y === hy && p.next.x > hx) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
45702
+ m = p;
45703
+ tanMin = tan;
45704
+ }
45705
+ }
45706
+ p = p.next;
45707
+ } while (p !== stop);
45708
+ }
45709
+ return m;
45710
+ }
45711
+ function sectorContainsSector(m, p) {
45712
+ return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
45713
+ }
45714
+ var sortArr = [];
45715
+ var sortBuf = [];
45716
+ var zArr = new Uint32Array(0);
45717
+ var zBuf = new Uint32Array(0);
45718
+ var counts = new Uint32Array(256);
45719
+ function indexCurve(start, minX, minY, invSize) {
45720
+ let p = start;
45721
+ let n = 0;
45722
+ do {
45723
+ p.z = zOrder(p.x, p.y, minX, minY, invSize);
45724
+ sortArr[n++] = p;
45725
+ p = p.next;
45726
+ } while (p !== start);
45727
+ sortNodes(n);
45728
+ let prev = null;
45729
+ for (let i = 0; i < n; i++) {
45730
+ const node = sortArr[i];
45731
+ node.prevZ = prev;
45732
+ if (prev) prev.nextZ = node;
45733
+ prev = node;
45734
+ }
45735
+ prev.nextZ = null;
45736
+ }
45737
+ function sortNodes(n) {
45738
+ if (n <= 32) {
45739
+ for (let i = 1; i < n; i++) {
45740
+ const node = sortArr[i], z42 = node.z;
45741
+ let j = i - 1;
45742
+ while (j >= 0 && sortArr[j].z > z42) {
45743
+ sortArr[j + 1] = sortArr[j];
45744
+ j--;
45745
+ }
45746
+ sortArr[j + 1] = node;
45747
+ }
45748
+ return;
45749
+ }
45750
+ if (zArr.length < n) {
45751
+ zArr = new Uint32Array(n);
45752
+ zBuf = new Uint32Array(n);
45753
+ sortBuf = new Array(n);
45754
+ }
45755
+ for (let i = 0; i < n; i++) zArr[i] = sortArr[i].z;
45756
+ radixPass(n, sortArr, zArr, sortBuf, zBuf, 0);
45757
+ radixPass(n, sortBuf, zBuf, sortArr, zArr, 8);
45758
+ radixPass(n, sortArr, zArr, sortBuf, zBuf, 16);
45759
+ radixPass(n, sortBuf, zBuf, sortArr, zArr, 24);
45760
+ }
45761
+ function radixPass(n, src, srcZ, dst, dstZ, shift4) {
45762
+ counts.fill(0);
45763
+ for (let i = 0; i < n; i++) counts[srcZ[i] >>> shift4 & 255]++;
45764
+ let sum = 0;
45765
+ for (let b = 0; b < 256; b++) {
45766
+ const c = counts[b];
45767
+ counts[b] = sum;
45768
+ sum += c;
45769
+ }
45770
+ for (let i = 0; i < n; i++) {
45771
+ const z42 = srcZ[i];
45772
+ const pos = counts[z42 >>> shift4 & 255]++;
45773
+ dst[pos] = src[i];
45774
+ dstZ[pos] = z42;
45775
+ }
45776
+ }
45777
+ function zOrder(x, y, minX, minY, invSize) {
45778
+ x = (x - minX) * invSize | 0;
45779
+ y = (y - minY) * invSize | 0;
45780
+ x = (x | x << 8) & 16711935;
45781
+ x = (x | x << 4) & 252645135;
45782
+ x = (x | x << 2) & 858993459;
45783
+ x = (x | x << 1) & 1431655765;
45784
+ y = (y | y << 8) & 16711935;
45785
+ y = (y | y << 4) & 252645135;
45786
+ y = (y | y << 2) & 858993459;
45787
+ y = (y | y << 1) & 1431655765;
45788
+ return x | y << 1;
45789
+ }
45790
+ function getLeftmost(start) {
45791
+ let p = start, leftmost = start;
45792
+ do {
45793
+ if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y) leftmost = p;
45794
+ p = p.next;
45795
+ } while (p !== start);
45796
+ return leftmost;
45797
+ }
45798
+ function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
45799
+ return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
45800
+ }
45801
+ function isValidDiagonal(a, b) {
45802
+ const zeroLength = equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0;
45803
+ return a.next.i !== b.i && (zeroLength || locallyInside(a, b) && locallyInside(b, a) && // // locally visible
45804
+ (area(a.prev, a, b.prev) !== 0 || area(a, b.prev, b) !== 0)) && // no opposite-facing sectors
45805
+ !intersectsPolygon(a, b) && (zeroLength || middleInside(a, b));
45806
+ }
45807
+ function area(p, q, r) {
45808
+ return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
45809
+ }
45810
+ function equals(p1, p2) {
45811
+ return p1.x === p2.x && p1.y === p2.y;
45812
+ }
45813
+ function intersects(p1, q1, p2, q2, includeBoundary = true) {
45814
+ const o1 = area(p1, q1, p2);
45815
+ const o2 = area(p1, q1, q2);
45816
+ const o3 = area(p2, q2, p1);
45817
+ const o4 = area(p2, q2, q1);
45818
+ if ((o1 > 0 && o2 < 0 || o1 < 0 && o2 > 0) && (o3 > 0 && o4 < 0 || o3 < 0 && o4 > 0)) return true;
45819
+ if (!includeBoundary) return false;
45820
+ if (o1 === 0 && onSegment2(p1, p2, q1)) return true;
45821
+ if (o2 === 0 && onSegment2(p1, q2, q1)) return true;
45822
+ if (o3 === 0 && onSegment2(p2, p1, q2)) return true;
45823
+ if (o4 === 0 && onSegment2(p2, q1, q2)) return true;
45824
+ return false;
45825
+ }
45826
+ function onSegment2(p, q, r) {
45827
+ return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
45828
+ }
45829
+ function intersectsPolygon(a, b) {
45830
+ const minX = Math.min(a.x, b.x);
45831
+ const maxX = Math.max(a.x, b.x);
45832
+ const minY = Math.min(a.y, b.y);
45833
+ const maxY = Math.max(a.y, b.y);
45834
+ let p = a;
45835
+ do {
45836
+ const n = p.next;
45837
+ if (p.x > maxX && n.x > maxX || p.x < minX && n.x < minX || p.y > maxY && n.y > maxY || p.y < minY && n.y < minY) {
45838
+ p = n;
45839
+ continue;
45840
+ }
45841
+ if (p.i !== a.i && n.i !== a.i && p.i !== b.i && n.i !== b.i && intersects(p, n, a, b)) return true;
45842
+ p = n;
45843
+ } while (p !== a);
45844
+ return false;
45845
+ }
45846
+ function locallyInside(a, b) {
45847
+ return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
45848
+ }
45849
+ function middleInside(a, b) {
45850
+ let p = a;
45851
+ let inside = false;
45852
+ const px = (a.x + b.x) / 2;
45853
+ const py = (a.y + b.y) / 2;
45854
+ do {
45855
+ const n = p.next;
45856
+ if (p.y > py !== n.y > py && px < (n.x - p.x) * (py - p.y) / (n.y - p.y) + p.x)
45857
+ inside = !inside;
45858
+ p = n;
45859
+ } while (p !== a);
45860
+ return inside;
45861
+ }
45862
+ function splitPolygon(a, b) {
45863
+ const a2 = createNode(a.i, a.x, a.y), b2 = createNode(b.i, b.x, b.y), an = a.next, bp = b.prev;
45864
+ a.next = b;
45865
+ b.prev = a;
45866
+ a2.next = an;
45867
+ an.prev = a2;
45868
+ b2.next = a2;
45869
+ a2.prev = b2;
45870
+ bp.next = b2;
45871
+ b2.prev = bp;
45872
+ return b2;
45873
+ }
45874
+ function insertNode(i, x, y, last) {
45875
+ const p = createNode(i, x, y);
45876
+ if (!last) {
45877
+ p.prev = p;
45878
+ p.next = p;
45879
+ } else {
45880
+ p.next = last.next;
45881
+ p.prev = last;
45882
+ last.next.prev = p;
45883
+ last.next = p;
45884
+ }
45885
+ return p;
45886
+ }
45887
+ function removeNode(p) {
45888
+ p.next.prev = p.prev;
45889
+ p.prev.next = p.next;
45890
+ if (p.prevZ) p.prevZ.nextZ = p.nextZ;
45891
+ if (p.nextZ) p.nextZ.prevZ = p.prevZ;
45892
+ if (indexActive) growBlock(p.prev, p.next);
45893
+ }
45894
+ function createNode(i, x, y) {
45895
+ return (
45896
+ /** @type {Node} */
45897
+ /** @type {unknown} */
45898
+ {
45899
+ i,
45900
+ // vertex index in coordinates array
45901
+ x,
45902
+ y,
45903
+ // vertex coordinates
45904
+ prev: null,
45905
+ // previous and next vertex nodes in a polygon ring
45906
+ next: null,
45907
+ z: 0,
45908
+ // z-order curve value; doubles as owning block in the hole-bridge index during eliminateHoles
45909
+ prevZ: null,
45910
+ // previous and next nodes in z-order
45911
+ nextZ: null
45912
+ }
45913
+ );
45914
+ }
45915
+ function signedArea(data, start, end, dim) {
45916
+ let sum = 0;
45917
+ for (let i = start, j = end - dim; i < end; i += dim) {
45918
+ sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
45919
+ j = i;
45920
+ }
45921
+ return sum;
45922
+ }
45923
+
45924
+ // node_modules/@tscircuit/flex-utils/dist/index.js
45925
+ var EPS = 1e-7;
45926
+ function createPcbFold(records, thickness) {
45927
+ if (!Number.isFinite(thickness) || thickness < 0)
45928
+ throw new Error("Board thickness must be finite and nonnegative");
45929
+ const bends = records.map((b) => {
45930
+ const { start, end, bend_angle: degrees, bend_radius: radius } = b;
45931
+ const values = [start?.x, start?.y, end?.x, end?.y, degrees, radius];
45932
+ if (values.some((v) => !Number.isFinite(v)) || radius <= thickness / 2 || !["left", "right"].includes(b.bend_side)) {
45933
+ throw new Error(
45934
+ `Invalid PCB bend ${b.pcb_bend_id}: finite geometry and radius greater than half the board thickness are required`
45935
+ );
45936
+ }
45937
+ const length83 = Math.hypot(end.x - start.x, end.y - start.y);
45938
+ if (length83 < EPS || Math.abs(degrees) > 180)
45939
+ throw new Error(
45940
+ `Unsupported PCB bend ${b.pcb_bend_id}: distinct endpoints and angles within \xB1180 degrees are required`
45941
+ );
45942
+ const sign = b.bend_side === "right" ? 1 : -1;
45943
+ const nx = sign * (end.y - start.y) / length83;
45944
+ const ny = -sign * (end.x - start.x) / length83;
45945
+ const angle = degrees * Math.PI / 180;
45946
+ const width10 = radius * Math.abs(angle);
45947
+ const center = start.x * nx + start.y * ny;
45948
+ return {
45949
+ id: b.pcb_bend_id,
45950
+ nx,
45951
+ ny,
45952
+ start: center - width10 / 2,
45953
+ end: center + width10 / 2,
45954
+ angle,
45955
+ radius,
45956
+ axisMin: Math.min(
45957
+ -ny * start.x + nx * start.y,
45958
+ -ny * end.x + nx * end.y
45959
+ ),
45960
+ axisMax: Math.max(
45961
+ -ny * start.x + nx * start.y,
45962
+ -ny * end.x + nx * end.y
45963
+ )
45964
+ };
45965
+ }).filter((b) => Math.abs(b.angle) > EPS);
45966
+ const first = bends[0];
45967
+ if (first && bends.some(
45968
+ (b) => Math.abs(b.nx - first.nx) > EPS || Math.abs(b.ny - first.ny) > EPS
45969
+ )) {
45970
+ throw new Error(
45971
+ "Folded PCB rendering currently requires parallel bends with the same moving direction"
45972
+ );
45973
+ }
45974
+ bends.sort((a, b) => a.start - b.start);
45975
+ for (let i = 1; i < bends.length; i++) {
45976
+ if (bends[i].start < bends[i - 1].end - EPS)
45977
+ throw new Error("Overlapping PCB bend zones are not supported");
45978
+ }
45979
+ const distalFirst = [...bends].reverse();
45980
+ const transform = ({
45981
+ p,
45982
+ anchor,
45983
+ direction
45984
+ }) => {
45985
+ let result = { ...p };
45986
+ for (const b of distalFirst) {
45987
+ const width10 = b.end - b.start;
45988
+ const s = anchor.x * b.nx + anchor.y * b.ny - b.start;
45989
+ const q = Math.max(0, Math.min(width10, s));
45990
+ const theta = b.angle * q / width10;
45991
+ const cos = Math.cos(theta), sin = Math.sin(theta);
45992
+ const projected = result.x * b.nx + result.y * b.ny - (direction ? 0 : b.start);
45993
+ const tangentX = result.x - (projected + (direction ? 0 : b.start)) * b.nx;
45994
+ const tangentY = result.y - (projected + (direction ? 0 : b.start)) * b.ny;
45995
+ const signedRadius = Math.sign(b.angle) * b.radius;
45996
+ const tx = direction ? 0 : signedRadius * sin - q * cos;
45997
+ const tz = direction ? 0 : signedRadius * (1 - cos) - q * sin;
45998
+ const folded = projected * cos - result.z * sin + tx;
45999
+ result = {
46000
+ x: tangentX + (folded + (direction ? 0 : b.start)) * b.nx,
46001
+ y: tangentY + (folded + (direction ? 0 : b.start)) * b.ny,
46002
+ z: projected * sin + result.z * cos + tz
46003
+ };
46004
+ }
46005
+ return result;
46006
+ };
46007
+ const inverse = ({
46008
+ p,
46009
+ anchor,
46010
+ direction
46011
+ }) => {
46012
+ const origin = direction ? { x: 0, y: 0, z: 0 } : transform({
46013
+ p: { x: 0, y: 0, z: 0 },
46014
+ anchor,
46015
+ direction: false
46016
+ });
46017
+ const d = { x: p.x - origin.x, y: p.y - origin.y, z: p.z - origin.z };
46018
+ const axes2 = [
46019
+ { x: 1, y: 0, z: 0 },
46020
+ { x: 0, y: 1, z: 0 },
46021
+ { x: 0, y: 0, z: 1 }
46022
+ ].map((v) => transform({ p: v, anchor, direction: true }));
46023
+ const dot = (v) => v.x * d.x + v.y * d.y + v.z * d.z;
46024
+ return { x: dot(axes2[0]), y: dot(axes2[1]), z: dot(axes2[2]) };
46025
+ };
46026
+ return {
46027
+ bends,
46028
+ inversePoint: (p, anchor) => inverse({ p, anchor, direction: false }),
46029
+ inverseDirection: (p, anchor) => inverse({ p, anchor, direction: true }),
46030
+ point: (p, anchor = p) => transform({ p, anchor, direction: false }),
46031
+ direction: (p, anchor) => transform({ p, anchor, direction: true }),
46032
+ assertRigid(points, label) {
46033
+ for (const b of bends) {
46034
+ const ds = points.map((p) => p.x * b.nx + p.y * b.ny);
46035
+ if (Math.max(...ds) > b.start + EPS && Math.min(...ds) < b.end - EPS)
46036
+ throw new Error(`${label} intersects PCB bend zone ${b.id}`);
46037
+ }
46038
+ }
46039
+ };
46040
+ }
46041
+ var EPS2 = 1e-7;
46042
+ function boundsOfTriangles(triangles) {
46043
+ const points = triangles.flatMap((t) => t.vertices);
46044
+ if (!points.length)
46045
+ return { min: { x: 0, y: 0, z: 0 }, max: { x: 0, y: 0, z: 0 } };
46046
+ const min2 = { x: Infinity, y: Infinity, z: Infinity };
46047
+ const max2 = { x: -Infinity, y: -Infinity, z: -Infinity };
46048
+ for (const p of points)
46049
+ for (const key of ["x", "y", "z"]) {
46050
+ min2[key] = Math.min(min2[key], p[key]);
46051
+ max2[key] = Math.max(max2[key], p[key]);
46052
+ }
46053
+ return { min: min2, max: max2 };
46054
+ }
46055
+ function foldSurfaceMesh(mesh, fold) {
46056
+ const planes = fold.bends.flatMap((b) => {
46057
+ const steps = Math.ceil(Math.abs(b.angle) / (Math.PI / 36));
46058
+ return Array.from({ length: steps + 1 }, (_, i) => ({
46059
+ b,
46060
+ d: b.start + (b.end - b.start) * i / steps
46061
+ }));
46062
+ });
46063
+ const { min: min2, max: max2 } = mesh.boundingBox;
46064
+ const split = ({
46065
+ polygon: polygon2,
46066
+ nx,
46067
+ ny,
46068
+ d
46069
+ }) => {
46070
+ const distances = polygon2.map(({ p }) => nx * p.x + ny * p.y - d);
46071
+ if (Math.min(...distances) >= -EPS2 || Math.max(...distances) <= EPS2)
46072
+ return [polygon2];
46073
+ const halves = [[], []];
46074
+ for (let side = 0; side < 2; side++) {
46075
+ const sign = side === 0 ? 1 : -1;
46076
+ for (let i = 0; i < polygon2.length; i++) {
46077
+ const a = polygon2[i], next = (i + 1) % polygon2.length, b = polygon2[next];
46078
+ const da = distances[i] * sign, db = distances[next] * sign;
46079
+ if (da >= -EPS2) halves[side].push(a);
46080
+ if (da > EPS2 && db < -EPS2 || da < -EPS2 && db > EPS2) {
46081
+ const t = da / (da - db);
46082
+ halves[side].push({
46083
+ p: {
46084
+ x: a.p.x + (b.p.x - a.p.x) * t,
46085
+ y: a.p.y + (b.p.y - a.p.y) * t,
46086
+ z: a.p.z + (b.p.z - a.p.z) * t
46087
+ },
46088
+ uv: {
46089
+ u: a.uv.u + (b.uv.u - a.uv.u) * t,
46090
+ v: a.uv.v + (b.uv.v - a.uv.v) * t
46091
+ }
46092
+ });
46093
+ }
46094
+ }
46095
+ }
46096
+ return halves.filter((p) => p.length >= 3);
46097
+ };
46098
+ const triangles = [];
46099
+ for (const triangle of mesh.triangles) {
46100
+ const face = triangle.pcbFace ?? (triangle.normal.z > 0.8 ? "top" : triangle.normal.z < -0.8 ? "bottom" : "side");
46101
+ let polygons = [
46102
+ triangle.vertices.map((p, index2) => ({
46103
+ p,
46104
+ uv: triangle.uvs?.[index2] ?? {
46105
+ u: (p.x - min2.x) / (max2.x - min2.x),
46106
+ v: 1 - (p.y - min2.y) / (max2.y - min2.y)
46107
+ }
46108
+ }))
46109
+ ];
46110
+ for (const { b, d } of planes)
46111
+ polygons = polygons.flatMap(
46112
+ (p) => split({ polygon: p, nx: b.nx, ny: b.ny, d })
46113
+ );
46114
+ for (const polygon2 of polygons) {
46115
+ for (const b of fold.bends) {
46116
+ const mid = polygon2.reduce((sum, { p }) => sum + p.x * b.nx + p.y * b.ny, 0) / polygon2.length;
46117
+ if (mid > b.start + EPS2 && mid < b.end - EPS2 && polygon2.some(({ p }) => {
46118
+ const along = -b.ny * p.x + b.nx * p.y;
46119
+ return along < b.axisMin - EPS2 || along > b.axisMax + EPS2;
46120
+ }))
46121
+ throw new Error(
46122
+ `PCB bend ${b.id} must span the full board cross-section through its bend zone`
46123
+ );
46124
+ }
46125
+ for (let i = 1; i + 1 < polygon2.length; i++) {
46126
+ const verts = [polygon2[0], polygon2[i], polygon2[i + 1]];
46127
+ const vertices = verts.map(
46128
+ ({ p }) => fold.point(p)
46129
+ );
46130
+ const [a, b, c] = vertices;
46131
+ const u = { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z }, v = { x: c.x - a.x, y: c.y - a.y, z: c.z - a.z };
46132
+ const n = {
46133
+ x: u.y * v.z - u.z * v.y,
46134
+ y: u.z * v.x - u.x * v.z,
46135
+ z: u.x * v.y - u.y * v.x
46136
+ };
46137
+ const l = Math.hypot(n.x, n.y, n.z);
46138
+ if (l < 1e-12) continue;
46139
+ triangles.push({
46140
+ ...triangle,
46141
+ vertices,
46142
+ normal: { x: n.x / l, y: n.y / l, z: n.z / l },
46143
+ pcbFace: face,
46144
+ uvs: verts.map(({ uv }) => uv)
46145
+ });
46146
+ }
46147
+ }
46148
+ }
46149
+ return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
46150
+ }
46151
+ var axes = [
46152
+ { x: 1, y: 0, z: 0 },
46153
+ { x: 0, y: 1, z: 0 },
46154
+ { x: 0, y: 0, z: 1 }
46155
+ ];
46156
+ function rotateVector(v, degrees) {
46157
+ const [x, y, z42] = [degrees.x, degrees.y, degrees.z].map(
46158
+ (a2) => a2 * Math.PI / 180
46159
+ );
46160
+ const a = {
46161
+ x: Math.cos(z42) * v.x - Math.sin(z42) * v.y,
46162
+ y: Math.sin(z42) * v.x + Math.cos(z42) * v.y,
46163
+ z: v.z
46164
+ };
46165
+ const b = {
46166
+ x: Math.cos(y) * a.x + Math.sin(y) * a.z,
46167
+ y: a.y,
46168
+ z: -Math.sin(y) * a.x + Math.cos(y) * a.z
46169
+ };
46170
+ return {
46171
+ x: b.x,
46172
+ y: Math.cos(x) * b.y - Math.sin(x) * b.z,
46173
+ z: Math.sin(x) * b.y + Math.cos(x) * b.z
46174
+ };
46175
+ }
46176
+ function rotationFromAxes([a, b, c]) {
46177
+ const y = Math.asin(Math.max(-1, Math.min(1, c.x)));
46178
+ const regular = Math.abs(c.x) < 1 - 1e-12;
46179
+ return {
46180
+ x: (regular ? Math.atan2(-c.y, c.z) : Math.atan2(b.z, b.y)) * 180 / Math.PI,
46181
+ y: y * 180 / Math.PI,
46182
+ z: (regular ? Math.atan2(-b.x, a.x) : 0) * 180 / Math.PI
46183
+ };
46184
+ }
46185
+ function transformCadComponent({ cadComponent, foldPcbs }, context) {
46186
+ return transformCadComponentPlacement(
46187
+ { cadComponentPlacement: cadComponent, foldPcbs },
46188
+ context
46189
+ );
46190
+ }
46191
+ function transformCadComponentPlacement({
46192
+ cadComponentPlacement,
46193
+ foldPcbs
46194
+ }, context) {
46195
+ if (cadComponentPlacement.is_on_folded_board === true === foldPcbs)
46196
+ return cadComponentPlacement;
46197
+ const { fold, boardCenter, flatMount } = context;
46198
+ const anchor = {
46199
+ x: flatMount.x - boardCenter.x,
46200
+ y: flatMount.y - boardCenter.y,
46201
+ z: 0
46202
+ };
46203
+ fold.assertRigid([anchor], "CAD mount");
46204
+ const point = {
46205
+ x: cadComponentPlacement.position.x - boardCenter.x,
46206
+ y: cadComponentPlacement.position.y - boardCenter.y,
46207
+ z: cadComponentPlacement.position.z
46208
+ };
46209
+ const direction = foldPcbs ? fold.direction : fold.inverseDirection;
46210
+ const transformed = foldPcbs ? fold.point(point, anchor) : fold.inversePoint(point, anchor);
46211
+ const rotation = cadComponentPlacement.rotation ?? context.defaultRotation ?? { x: 0, y: 0, z: 0 };
46212
+ const basis = axes.map((v) => direction(rotateVector(v, rotation), anchor));
46213
+ return {
46214
+ ...cadComponentPlacement,
46215
+ position: {
46216
+ x: transformed.x + boardCenter.x,
46217
+ y: transformed.y + boardCenter.y,
46218
+ z: transformed.z
46219
+ },
46220
+ rotation: rotationFromAxes(basis),
46221
+ is_on_folded_board: foldPcbs
46222
+ };
46223
+ }
46224
+ function getCadFoldContext(cadComponent, json) {
46225
+ const pcb = json.find(
46226
+ (e) => e.type === "pcb_component" && e.pcb_component_id === cadComponent.pcb_component_id
46227
+ );
46228
+ if (pcb?.type !== "pcb_component") {
46229
+ if (cadComponent.is_on_folded_board)
46230
+ throw new Error(
46231
+ `Folded CAD ${cadComponent.cad_component_id} requires its flat pcb_component reference`
46232
+ );
46233
+ return void 0;
46234
+ }
46235
+ const boards = json.filter((e) => e.type === "pcb_board");
46236
+ const explicit = pcb.positioned_relative_to_pcb_board_id;
46237
+ const matching = explicit ? boards.filter((b) => b.pcb_board_id === explicit) : boards.filter(
46238
+ (b) => b.subcircuit_id && b.subcircuit_id === pcb.subcircuit_id
46239
+ );
46240
+ const board = matching.length === 1 ? matching[0] : !explicit && !matching.length && boards.length === 1 ? boards[0] : void 0;
46241
+ if (!board)
46242
+ throw new Error(
46243
+ `Cannot unambiguously resolve board for CAD ${cadComponent.cad_component_id}`
46244
+ );
46245
+ const bends = json.filter(
46246
+ (e) => e.type === "pcb_bend" && e.pcb_board_id === board.pcb_board_id
46247
+ );
46248
+ return {
46249
+ fold: createPcbFold(bends, board.thickness ?? 1.6),
46250
+ boardCenter: board.center,
46251
+ flatMount: pcb.center,
46252
+ defaultRotation: {
46253
+ x: (cadComponent.layer ?? pcb.layer) === "bottom" ? 180 : 0,
46254
+ y: 0,
46255
+ z: 0
46256
+ }
46257
+ };
46258
+ }
46259
+ function transformCircuitJsonCadComponents(json, options) {
46260
+ const hasBends = json.some((element) => element.type === "pcb_bend");
46261
+ return json.map((element) => {
46262
+ if (element.type !== "cad_component") return element;
46263
+ const cadComponent = element;
46264
+ if (!hasBends && !cadComponent.is_on_folded_board) return element;
46265
+ if (cadComponent.is_on_folded_board === true === options.foldPcbs)
46266
+ return element;
46267
+ const context = getCadFoldContext(cadComponent, json);
46268
+ if (!context || !context.fold.bends.length && !cadComponent.is_on_folded_board)
46269
+ return element;
46270
+ return transformCadComponent(
46271
+ { cadComponent, foldPcbs: options.foldPcbs },
46272
+ context
46273
+ );
46274
+ });
46275
+ }
46276
+ function extrudePolygon({
46277
+ outline,
46278
+ bottom,
46279
+ top
46280
+ }) {
46281
+ if (outline.length < 3 || !Number.isFinite(bottom) || !Number.isFinite(top) || top <= bottom || outline.some((p) => !Number.isFinite(p.x) || !Number.isFinite(p.y)))
46282
+ throw new Error(
46283
+ "A finite polygon and positive extrusion thickness are required"
46284
+ );
46285
+ let area2 = 0;
46286
+ for (const [i, a] of outline.entries()) {
46287
+ const b = outline[(i + 1) % outline.length];
46288
+ area2 += a.x * b.y - b.x * a.y;
46289
+ }
46290
+ if (Math.abs(area2) < 1e-12) throw new Error("Degenerate polygon");
46291
+ const polygon2 = area2 > 0 ? outline : [...outline].reverse();
46292
+ const triangles = [];
46293
+ const add = ({
46294
+ a,
46295
+ b,
46296
+ c,
46297
+ pcbFace
46298
+ }) => {
46299
+ const u = { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z }, v = { x: c.x - a.x, y: c.y - a.y, z: c.z - a.z };
46300
+ const n = {
46301
+ x: u.y * v.z - u.z * v.y,
46302
+ y: u.z * v.x - u.x * v.z,
46303
+ z: u.x * v.y - u.y * v.x
46304
+ };
46305
+ const l = Math.hypot(n.x, n.y, n.z);
46306
+ if (l > 1e-12)
46307
+ triangles.push({
46308
+ vertices: [a, b, c],
46309
+ normal: { x: n.x / l, y: n.y / l, z: n.z / l },
46310
+ pcbFace
46311
+ });
46312
+ };
46313
+ const indices = earcut(polygon2.flatMap((p) => [p.x, p.y]));
46314
+ for (let i = 0; i < indices.length; i += 3) {
46315
+ const [a, b, c] = indices.slice(i, i + 3).map((j) => polygon2[j]);
46316
+ add({
46317
+ a: { ...a, z: top },
46318
+ b: { ...b, z: top },
46319
+ c: { ...c, z: top },
46320
+ pcbFace: "top"
46321
+ });
46322
+ add({
46323
+ a: { ...c, z: bottom },
46324
+ b: { ...b, z: bottom },
46325
+ c: { ...a, z: bottom },
46326
+ pcbFace: "bottom"
46327
+ });
46328
+ }
46329
+ for (let i = 0; i < polygon2.length; i++) {
46330
+ const a = polygon2[i], b = polygon2[(i + 1) % polygon2.length];
46331
+ add({
46332
+ a: { ...a, z: bottom },
46333
+ b: { ...b, z: bottom },
46334
+ c: { ...b, z: top },
46335
+ pcbFace: "side"
46336
+ });
46337
+ add({
46338
+ a: { ...a, z: bottom },
46339
+ b: { ...b, z: top },
46340
+ c: { ...a, z: top },
46341
+ pcbFace: "side"
46342
+ });
46343
+ }
46344
+ return { triangles, boundingBox: boundsOfTriangles(triangles) };
46345
+ }
46346
+ function createStiffenerMesh({
46347
+ stiffener,
46348
+ boardThickness,
46349
+ fold
46350
+ }) {
46351
+ const adhesive = stiffener.adhesive_thickness ?? 0;
46352
+ if (!Number.isFinite(adhesive) || adhesive < 0 || !Number.isFinite(stiffener.thickness) || stiffener.thickness <= 0 || !["top", "bottom"].includes(stiffener.layer))
46353
+ throw new Error(`Invalid PCB stiffener ${stiffener.pcb_stiffener_id}`);
46354
+ const outline = stiffener.shape === "polygon" ? stiffener.outline : (() => {
46355
+ if (!(stiffener.width > 0 && stiffener.height > 0))
46356
+ throw new Error("Invalid stiffener dimensions");
46357
+ const a = (stiffener.rotation ?? 0) * Math.PI / 180;
46358
+ return [
46359
+ [-1, -1],
46360
+ [1, -1],
46361
+ [1, 1],
46362
+ [-1, 1]
46363
+ ].map(([x, y]) => ({
46364
+ x: stiffener.center.x + x * stiffener.width / 2 * Math.cos(a) - y * stiffener.height / 2 * Math.sin(a),
46365
+ y: stiffener.center.y + x * stiffener.width / 2 * Math.sin(a) + y * stiffener.height / 2 * Math.cos(a)
46366
+ }));
46367
+ })();
46368
+ const near = boardThickness / 2 + adhesive, far = near + stiffener.thickness;
46369
+ const mesh = extrudePolygon({
46370
+ outline,
46371
+ bottom: stiffener.layer === "top" ? near : -far,
46372
+ top: stiffener.layer === "top" ? far : -near
46373
+ });
46374
+ if (!fold) return mesh;
46375
+ fold.assertRigid(
46376
+ mesh.triangles.flatMap((t) => t.vertices),
46377
+ stiffener.pcb_stiffener_id
46378
+ );
46379
+ const anchor = {
46380
+ x: outline.reduce((s, p) => s + p.x, 0) / outline.length,
46381
+ y: outline.reduce((s, p) => s + p.y, 0) / outline.length,
46382
+ z: 0
46383
+ };
46384
+ const triangles = mesh.triangles.map((t) => ({
46385
+ ...t,
46386
+ vertices: t.vertices.map((p) => fold.point(p, anchor)),
46387
+ normal: fold.direction(t.normal, anchor)
46388
+ }));
46389
+ return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
46390
+ }
46391
+
46392
+ // src/utils/flex-meshes.ts
46393
+ import * as THREE44 from "three";
46394
+ function meshToSurface(mesh, center) {
46395
+ mesh.updateMatrix();
46396
+ const geometry = mesh.geometry.index ? mesh.geometry.toNonIndexed() : mesh.geometry;
46397
+ const position = geometry.getAttribute("position"), uv = geometry.getAttribute("uv");
46398
+ const triangles = [];
46399
+ for (let i = 0; i < position.count; i += 3) {
46400
+ const vertices = [0, 1, 2].map((j) => {
46401
+ const v = new THREE44.Vector3().fromBufferAttribute(position, i + j).applyMatrix4(mesh.matrix);
46402
+ return { x: v.x - center.x, y: v.y - center.y, z: v.z };
46403
+ });
46404
+ const [a, b, c] = vertices;
46405
+ const n = new THREE44.Vector3(b.x - a.x, b.y - a.y, b.z - a.z).cross(new THREE44.Vector3(c.x - a.x, c.y - a.y, c.z - a.z)).normalize();
46406
+ triangles.push({
46407
+ vertices,
46408
+ normal: { x: n.x, y: n.y, z: n.z },
46409
+ ...uv ? {
46410
+ uvs: [0, 1, 2].map((j) => ({
46411
+ u: uv.getX(i + j),
46412
+ v: uv.getY(i + j)
46413
+ }))
46414
+ } : {}
46415
+ });
46416
+ }
46417
+ if (geometry !== mesh.geometry) geometry.dispose();
46418
+ return { triangles, boundingBox: boundsOfTriangles(triangles) };
46419
+ }
46420
+ function surfaceToGeometry(surface, center) {
46421
+ const positions = [], normals = [], uvs = [];
46422
+ for (const triangle of surface.triangles)
46423
+ triangle.vertices.forEach((p, i) => {
46424
+ positions.push(p.x + center.x, p.y + center.y, p.z);
46425
+ normals.push(triangle.normal.x, triangle.normal.y, triangle.normal.z);
46426
+ uvs.push(triangle.uvs?.[i]?.u ?? 0, triangle.uvs?.[i]?.v ?? 0);
46427
+ });
46428
+ const geometry = new THREE44.BufferGeometry();
46429
+ geometry.setAttribute(
46430
+ "position",
46431
+ new THREE44.Float32BufferAttribute(positions, 3)
46432
+ );
46433
+ geometry.setAttribute("normal", new THREE44.Float32BufferAttribute(normals, 3));
46434
+ geometry.setAttribute("uv", new THREE44.Float32BufferAttribute(uvs, 2));
46435
+ geometry.computeBoundingBox();
46436
+ geometry.computeBoundingSphere();
46437
+ return geometry;
46438
+ }
46439
+ function replaceGeometry(mesh, surface, board) {
46440
+ const output = mesh.clone();
46441
+ output.geometry = surfaceToGeometry(surface, board.center);
46442
+ output.position.set(0, 0, 0);
46443
+ output.rotation.set(0, 0, 0);
46444
+ output.scale.set(1, 1, 1);
46445
+ output.updateMatrix();
46446
+ return output;
46447
+ }
46448
+ function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
46449
+ const boards = json.filter((e) => e.type === "pcb_board");
46450
+ const bends = json.filter((e) => e.type === "pcb_bend"), stiffeners = json.filter((e) => e.type === "pcb_stiffener");
46451
+ if (!bends.length && !stiffeners.length)
46452
+ return { geometryMeshes, textureMeshes };
46453
+ const board = boards[0];
46454
+ if (!board || boards.length !== 1 || json.some((e) => e.type === "pcb_panel") || [...bends, ...stiffeners].some((e) => e.pcb_board_id !== board.pcb_board_id))
46455
+ throw new Error(
46456
+ "Flex rendering requires one board, matching board references, and no panel"
46457
+ );
46458
+ const fold = foldPcbs ? createPcbFold(bends, board.thickness ?? 1.6) : void 0;
46459
+ const body = geometryMeshes.find((m) => m.name === "board-geom");
46460
+ const flatBody = body ? meshToSurface(body, board.center) : void 0;
46461
+ const geometry = fold ? geometryMeshes.map(
46462
+ (mesh) => replaceGeometry(
46463
+ mesh,
46464
+ foldSurfaceMesh(meshToSurface(mesh, board.center), fold),
46465
+ board
46466
+ )
46467
+ ) : [...geometryMeshes];
46468
+ const textures = fold && flatBody ? textureMeshes.map((mesh) => {
46469
+ mesh.updateMatrix();
46470
+ const inverse = mesh.matrix.clone().invert();
46471
+ const bottom = mesh.name.startsWith("bottom");
46472
+ const dimensions = mesh.geometry.parameters;
46473
+ const triangles = flatBody.triangles.filter((t) => bottom ? t.normal.z < -0.9 : t.normal.z > 0.9).map((t) => {
46474
+ const vertices = t.vertices.map((p) => ({
46475
+ ...p,
46476
+ z: mesh.position.z
46477
+ }));
46478
+ const uvs = vertices.map((p) => {
46479
+ const local = new THREE44.Vector3(
46480
+ p.x + board.center.x,
46481
+ p.y + board.center.y,
46482
+ p.z
46483
+ ).applyMatrix4(inverse);
46484
+ return {
46485
+ u: local.x / dimensions.width + 0.5,
46486
+ v: local.y / dimensions.height + 0.5
46487
+ };
46488
+ });
46489
+ return { ...t, vertices, uvs };
46490
+ });
46491
+ const result = replaceGeometry(
46492
+ mesh,
46493
+ foldSurfaceMesh(
46494
+ { triangles, boundingBox: boundsOfTriangles(triangles) },
46495
+ fold
46496
+ ),
46497
+ board
46498
+ );
46499
+ mesh.geometry.dispose();
46500
+ return result;
46501
+ }) : textureMeshes;
46502
+ for (const stiffener of stiffeners) {
46503
+ const mesh = new THREE44.Mesh(
46504
+ surfaceToGeometry(
46505
+ createStiffenerMesh({
46506
+ stiffener,
46507
+ boardThickness: board.thickness ?? 1.6,
46508
+ fold
46509
+ }),
46510
+ board.center
46511
+ ),
46512
+ new THREE44.MeshStandardMaterial({
46513
+ color: stiffener.material === "fr4" ? "#879568" : stiffener.material === "polyimide" ? "#bd7f27" : "#b8bdc4",
46514
+ side: THREE44.DoubleSide
46515
+ })
46516
+ );
46517
+ mesh.name = "board-stiffener";
46518
+ configureObjectShadows(mesh);
46519
+ geometry.push(mesh);
46520
+ }
46521
+ const bounds = new THREE44.Box3();
46522
+ for (const mesh of [...geometry, ...textures]) bounds.expandByObject(mesh);
46523
+ return {
46524
+ geometryMeshes: geometry,
46525
+ textureMeshes: textures,
46526
+ bounds: {
46527
+ minX: bounds.min.x,
46528
+ maxX: bounds.max.x,
46529
+ minY: bounds.min.y,
46530
+ maxY: bounds.max.y,
46531
+ minZ: bounds.min.z,
46532
+ maxZ: bounds.max.z
46533
+ }
46534
+ };
46535
+ }
46536
+
45403
46537
  // src/CadViewerManifold.tsx
45404
46538
  import { su as su17 } from "@tscircuit/circuit-json-util";
45405
46539
  import { useEffect as useEffect28, useMemo as useMemo24, useState as useState17 } from "react";
45406
- import * as THREE50 from "three";
46540
+ import * as THREE51 from "three";
45407
46541
 
45408
46542
  // src/hooks/useManifoldBoardBuilder.ts
45409
46543
  import { su as su16 } from "@tscircuit/circuit-json-util";
45410
46544
  import { useEffect as useEffect27, useMemo as useMemo23, useRef as useRef9, useState as useState16 } from "react";
45411
- import * as THREE47 from "three";
46545
+ import * as THREE48 from "three";
45412
46546
 
45413
46547
  // src/utils/manifold/create-manifold-board.ts
45414
46548
  var arePointsClockwise2 = (points) => {
45415
- let area = 0;
46549
+ let area2 = 0;
45416
46550
  for (let i = 0; i < points.length; i++) {
45417
46551
  const j = (i + 1) % points.length;
45418
46552
  if (points[i] && points[j]) {
45419
- area += points[i][0] * points[j][1];
45420
- area -= points[j][0] * points[i][1];
46553
+ area2 += points[i][0] * points[j][1];
46554
+ area2 -= points[j][0] * points[i][1];
45421
46555
  }
45422
46556
  }
45423
- const signedArea = area / 2;
45424
- return signedArea <= 0;
46557
+ const signedArea2 = area2 / 2;
46558
+ return signedArea2 <= 0;
45425
46559
  };
45426
46560
  function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, manifoldInstancesForCleanup) {
45427
46561
  let boardOp;
@@ -45515,16 +46649,16 @@ function createRoundedRectPrism({
45515
46649
 
45516
46650
  // src/utils/manifold/process-cutouts.ts
45517
46651
  var arePointsClockwise3 = (points) => {
45518
- let area = 0;
46652
+ let area2 = 0;
45519
46653
  for (let i = 0; i < points.length; i++) {
45520
46654
  const j = (i + 1) % points.length;
45521
46655
  if (points[i] && points[j]) {
45522
- area += points[i][0] * points[j][1];
45523
- area -= points[j][0] * points[i][1];
46656
+ area2 += points[i][0] * points[j][1];
46657
+ area2 -= points[j][0] * points[i][1];
45524
46658
  }
45525
46659
  }
45526
- const signedArea = area / 2;
45527
- return signedArea <= 0;
46660
+ const signedArea2 = area2 / 2;
46661
+ return signedArea2 <= 0;
45528
46662
  };
45529
46663
  function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
45530
46664
  const cutoutOps = [];
@@ -45719,13 +46853,13 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
45719
46853
  holeOp = createRectOp(holeW, holeH, drillDepth);
45720
46854
  } else if (holeShape === "oval") {
45721
46855
  let points = createEllipsePoints2(holeW, holeH, SMOOTH_CIRCLE_SEGMENTS);
45722
- let area = 0;
46856
+ let area2 = 0;
45723
46857
  for (let i = 0; i < points.length; i++) {
45724
46858
  const j = (i + 1) % points.length;
45725
- area += points[i][0] * points[j][1];
45726
- area -= points[j][0] * points[i][1];
46859
+ area2 += points[i][0] * points[j][1];
46860
+ area2 -= points[j][0] * points[i][1];
45727
46861
  }
45728
- if (area <= 0) {
46862
+ if (area2 <= 0) {
45729
46863
  points = points.reverse();
45730
46864
  }
45731
46865
  const crossSection = CrossSection.ofPolygons([points]);
@@ -45757,17 +46891,17 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
45757
46891
 
45758
46892
  // src/utils/manifold/process-plated-holes.ts
45759
46893
  import { su as su15 } from "@tscircuit/circuit-json-util";
45760
- import * as THREE45 from "three";
46894
+ import * as THREE46 from "three";
45761
46895
 
45762
46896
  // src/utils/manifold-mesh-to-three-geometry.ts
45763
- import * as THREE44 from "three";
46897
+ import * as THREE45 from "three";
45764
46898
  function manifoldMeshToThreeGeometry(manifoldMesh) {
45765
- const geometry = new THREE44.BufferGeometry();
46899
+ const geometry = new THREE45.BufferGeometry();
45766
46900
  geometry.setAttribute(
45767
46901
  "position",
45768
- new THREE44.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
46902
+ new THREE45.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
45769
46903
  );
45770
- geometry.setIndex(new THREE44.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
46904
+ geometry.setIndex(new THREE45.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
45771
46905
  if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
45772
46906
  for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
45773
46907
  const start = manifoldMesh.runIndex[i];
@@ -45782,16 +46916,16 @@ function manifoldMeshToThreeGeometry(manifoldMesh) {
45782
46916
 
45783
46917
  // src/utils/manifold/process-plated-holes.ts
45784
46918
  var arePointsClockwise4 = (points) => {
45785
- let area = 0;
46919
+ let area2 = 0;
45786
46920
  for (let i = 0; i < points.length; i++) {
45787
46921
  const j = (i + 1) % points.length;
45788
46922
  if (points[i] && points[j]) {
45789
- area += points[i][0] * points[j][1];
45790
- area -= points[j][0] * points[i][1];
46923
+ area2 += points[i][0] * points[j][1];
46924
+ area2 -= points[j][0] * points[i][1];
45791
46925
  }
45792
46926
  }
45793
- const signedArea = area / 2;
45794
- return signedArea <= 0;
46927
+ const signedArea2 = area2 / 2;
46928
+ return signedArea2 <= 0;
45795
46929
  };
45796
46930
  var createEllipsePoints = (width10, height10, segments) => {
45797
46931
  const points = [];
@@ -45801,7 +46935,7 @@ var createEllipsePoints = (width10, height10, segments) => {
45801
46935
  }
45802
46936
  return points;
45803
46937
  };
45804
- var COPPER_COLOR = new THREE45.Color(...colors.copper);
46938
+ var COPPER_COLOR = new THREE46.Color(...colors.copper);
45805
46939
  var PLATED_HOLE_LIP_HEIGHT = 0.05;
45806
46940
  var PLATED_HOLE_PAD_THICKNESS = 3e-3;
45807
46941
  var PLATED_HOLE_SURFACE_CLEARANCE = 5e-4;
@@ -46431,7 +47565,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
46431
47565
  }
46432
47566
 
46433
47567
  // src/utils/manifold/process-vias.ts
46434
- import * as THREE46 from "three";
47568
+ import * as THREE47 from "three";
46435
47569
 
46436
47570
  // src/utils/via-geoms.ts
46437
47571
  function createViaCopper2({
@@ -46469,7 +47603,7 @@ function createViaCopper2({
46469
47603
  }
46470
47604
 
46471
47605
  // src/utils/manifold/process-vias.ts
46472
- var COPPER_COLOR2 = new THREE46.Color(...colors.copper);
47606
+ var COPPER_COLOR2 = new THREE47.Color(...colors.copper);
46473
47607
  function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
46474
47608
  const viaBoardDrills = [];
46475
47609
  const pcbVias = getPcbVias(circuitJson);
@@ -46690,7 +47824,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
46690
47824
  {
46691
47825
  key: "plated-holes-union",
46692
47826
  geometry: cutPlatedGeom,
46693
- color: new THREE47.Color(
47827
+ color: new THREE48.Color(
46694
47828
  colors.copper[0],
46695
47829
  colors.copper[1],
46696
47830
  colors.copper[2]
@@ -46760,11 +47894,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
46760
47894
  };
46761
47895
 
46762
47896
  // src/utils/manifold/create-three-geometry-meshes.ts
46763
- import * as THREE49 from "three";
47897
+ import * as THREE50 from "three";
46764
47898
 
46765
47899
  // src/utils/create-board-material.ts
46766
- import * as THREE48 from "three";
46767
- var DEFAULT_SIDE = THREE48.DoubleSide;
47900
+ import * as THREE49 from "three";
47901
+ var DEFAULT_SIDE = THREE49.DoubleSide;
46768
47902
  var createBoardMaterial = ({
46769
47903
  material,
46770
47904
  color,
@@ -46772,7 +47906,7 @@ var createBoardMaterial = ({
46772
47906
  isFaux = false
46773
47907
  }) => {
46774
47908
  if (material === "fr4") {
46775
- return new THREE48.MeshPhysicalMaterial({
47909
+ return new THREE49.MeshPhysicalMaterial({
46776
47910
  color,
46777
47911
  side,
46778
47912
  metalness: 0,
@@ -46790,7 +47924,7 @@ var createBoardMaterial = ({
46790
47924
  polygonOffsetUnits: 1
46791
47925
  });
46792
47926
  }
46793
- return new THREE48.MeshStandardMaterial({
47927
+ return new THREE49.MeshStandardMaterial({
46794
47928
  color,
46795
47929
  side,
46796
47930
  flatShading: true,
@@ -46809,12 +47943,12 @@ function createGeometryMeshes(geoms) {
46809
47943
  const meshes = [];
46810
47944
  if (!geoms) return meshes;
46811
47945
  if (geoms.board?.geometry) {
46812
- const mesh = new THREE49.Mesh(
47946
+ const mesh = new THREE50.Mesh(
46813
47947
  geoms.board.geometry,
46814
47948
  createBoardMaterial({
46815
47949
  material: geoms.board.material,
46816
47950
  color: geoms.board.color,
46817
- side: THREE49.DoubleSide,
47951
+ side: THREE50.DoubleSide,
46818
47952
  isFaux: geoms.board.isFaux
46819
47953
  })
46820
47954
  );
@@ -46825,11 +47959,11 @@ function createGeometryMeshes(geoms) {
46825
47959
  const createMeshesFromArray = (geomArray) => {
46826
47960
  if (geomArray) {
46827
47961
  for (const comp of geomArray) {
46828
- const mesh = new THREE49.Mesh(
47962
+ const mesh = new THREE50.Mesh(
46829
47963
  comp.geometry,
46830
- new THREE49.MeshStandardMaterial({
47964
+ new THREE50.MeshStandardMaterial({
46831
47965
  color: comp.color,
46832
- side: THREE49.DoubleSide,
47966
+ side: THREE50.DoubleSide,
46833
47967
  flatShading: true
46834
47968
  // Consistent with board
46835
47969
  })
@@ -46874,7 +48008,7 @@ var BoardMeshes = ({
46874
48008
  const typedMaterial = material;
46875
48009
  for (const prop of textureProps) {
46876
48010
  const texture = typedMaterial[prop];
46877
- if (texture && texture instanceof THREE50.Texture) {
48011
+ if (texture && texture instanceof THREE51.Texture) {
46878
48012
  texture.dispose();
46879
48013
  }
46880
48014
  }
@@ -46885,7 +48019,7 @@ var BoardMeshes = ({
46885
48019
  if (!rootObject) return;
46886
48020
  for (const mesh of geometryMeshes) {
46887
48021
  let shouldShow = true;
46888
- if (mesh.name === "board-geom") {
48022
+ if (mesh.name === "board-geom" || mesh.name === "board-stiffener") {
46889
48023
  shouldShow = visibility.boardBody;
46890
48024
  } else if (mesh.name.includes("plated_hole") || mesh.name.includes("via")) {
46891
48025
  shouldShow = visibility.topCopper || visibility.bottomCopper;
@@ -46922,6 +48056,7 @@ var BoardMeshes = ({
46922
48056
  var MANIFOLD_CDN_BASE_URL = "https://cdn.jsdelivr.net/npm/manifold-3d@3.2.1";
46923
48057
  var CadViewerManifold = ({
46924
48058
  circuitJson: circuitJsonProp,
48059
+ foldPcbs,
46925
48060
  autoRotateDisabled,
46926
48061
  clickToInteractEnabled,
46927
48062
  onUserInteraction,
@@ -47009,14 +48144,40 @@ try {
47009
48144
  boardData,
47010
48145
  isFauxBoard
47011
48146
  } = useManifoldBoardBuilder(manifoldJSModule, circuitJson, visibility);
47012
- const geometryMeshes = useMemo24(() => createGeometryMeshes(geoms), [geoms]);
47013
- const textureMeshes = useMemo24(
47014
- () => createTextureMeshes(textures, boardData, pcbThickness, isFauxBoard),
47015
- [textures, boardData, pcbThickness, isFauxBoard]
47016
- );
48147
+ const flex = useMemo24(() => {
48148
+ try {
48149
+ const resolvedFoldPcbs = resolveFoldPcbs(circuitJson, foldPcbs);
48150
+ const posedJson = transformCircuitJsonCadComponents(circuitJson, {
48151
+ foldPcbs: resolvedFoldPcbs
48152
+ });
48153
+ const meshes = createFlexMeshes(
48154
+ createGeometryMeshes(geoms),
48155
+ createTextureMeshes(textures, boardData, pcbThickness, isFauxBoard),
48156
+ circuitJson,
48157
+ resolvedFoldPcbs
48158
+ );
48159
+ return { ...meshes, posedJson, error: void 0 };
48160
+ } catch (error) {
48161
+ return {
48162
+ error: error instanceof Error ? error.message : String(error),
48163
+ geometryMeshes: [],
48164
+ textureMeshes: [],
48165
+ posedJson: circuitJson,
48166
+ bounds: void 0
48167
+ };
48168
+ }
48169
+ }, [
48170
+ geoms,
48171
+ textures,
48172
+ boardData,
48173
+ pcbThickness,
48174
+ isFauxBoard,
48175
+ circuitJson,
48176
+ foldPcbs
48177
+ ]);
47017
48178
  const cadComponents = useMemo24(
47018
- () => su17(circuitJson).cad_component.list(),
47019
- [circuitJson]
48179
+ () => su17(flex.posedJson).cad_component.list(),
48180
+ [flex.posedJson]
47020
48181
  );
47021
48182
  const boardDimensions = useMemo24(() => {
47022
48183
  if (!boardData) return void 0;
@@ -47063,10 +48224,11 @@ try {
47063
48224
  if (!manifoldJSModule) {
47064
48225
  return /* @__PURE__ */ jsx19("div", { style: { padding: "1em" }, children: "Loading Manifold module..." });
47065
48226
  }
47066
- if (builderError) {
48227
+ if (builderError || flex.error) {
47067
48228
  return /* @__PURE__ */ jsxs6(
47068
48229
  "div",
47069
48230
  {
48231
+ role: "alert",
47070
48232
  style: {
47071
48233
  color: "red",
47072
48234
  padding: "1em",
@@ -47075,7 +48237,7 @@ try {
47075
48237
  },
47076
48238
  children: [
47077
48239
  "Error: ",
47078
- builderError
48240
+ builderError ?? flex.error
47079
48241
  ]
47080
48242
  }
47081
48243
  );
@@ -47098,10 +48260,11 @@ try {
47098
48260
  /* @__PURE__ */ jsx19(
47099
48261
  BoardMeshes,
47100
48262
  {
47101
- geometryMeshes,
47102
- textureMeshes
48263
+ geometryMeshes: flex.geometryMeshes,
48264
+ textureMeshes: flex.textureMeshes
47103
48265
  }
47104
48266
  ),
48267
+ flex.bounds && /* @__PURE__ */ jsx19(FitCameraToComparison, { bounds: flex.bounds }),
47105
48268
  cadComponents.map((cad_component) => /* @__PURE__ */ jsx19(
47106
48269
  ThreeErrorBoundary,
47107
48270
  {
@@ -47110,7 +48273,7 @@ try {
47110
48273
  AnyCadComponent,
47111
48274
  {
47112
48275
  cad_component,
47113
- circuitJson,
48276
+ circuitJson: flex.posedJson,
47114
48277
  resolveStaticAsset
47115
48278
  }
47116
48279
  )
@@ -52820,6 +53983,27 @@ var MenuItemImpl = /* @__PURE__ */ React41.forwardRef(
52820
53983
  );
52821
53984
  }, "MenuItemImpl")
52822
53985
  );
53986
+ var MenuCheckboxItem = /* @__PURE__ */ React41.forwardRef(
53987
+ // blank line to reduce diff noise
53988
+ /* @__PURE__ */ __name21(function MenuCheckboxItem2(props, forwardedRef) {
53989
+ const { checked = false, onCheckedChange, ...checkboxItemProps } = props;
53990
+ return /* @__PURE__ */ jsx30(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ jsx30(
53991
+ MenuItem,
53992
+ {
53993
+ role: "menuitemcheckbox",
53994
+ "aria-checked": isIndeterminate(checked) ? "mixed" : checked,
53995
+ ...checkboxItemProps,
53996
+ ref: forwardedRef,
53997
+ "data-state": getCheckedState(checked),
53998
+ onSelect: composeEventHandlers(
53999
+ checkboxItemProps.onSelect,
54000
+ () => onCheckedChange?.(isIndeterminate(checked) ? true : !checked),
54001
+ { checkForDefaultPrevented: false }
54002
+ )
54003
+ }
54004
+ ) });
54005
+ }, "MenuCheckboxItem")
54006
+ );
52823
54007
  var RADIO_GROUP_NAME = "MenuRadioGroup";
52824
54008
  var [RadioGroupProvider, useRadioGroupContext] = createMenuContext(
52825
54009
  RADIO_GROUP_NAME,
@@ -53087,10 +54271,10 @@ function isPointInPolygon(point, polygon2) {
53087
54271
  return inside;
53088
54272
  }
53089
54273
  __name21(isPointInPolygon, "isPointInPolygon");
53090
- function isPointerInGraceArea(event, area) {
53091
- if (!area) return false;
54274
+ function isPointerInGraceArea(event, area2) {
54275
+ if (!area2) return false;
53092
54276
  const cursorPos = { x: event.clientX, y: event.clientY };
53093
- return isPointInPolygon(cursorPos, area);
54277
+ return isPointInPolygon(cursorPos, area2);
53094
54278
  }
53095
54279
  __name21(isPointerInGraceArea, "isPointerInGraceArea");
53096
54280
  function whenMouse(handler) {
@@ -53102,6 +54286,7 @@ var Anchor2 = MenuAnchor;
53102
54286
  var Portal3 = MenuPortal;
53103
54287
  var Content2 = MenuContent;
53104
54288
  var Item2 = MenuItem;
54289
+ var CheckboxItem = MenuCheckboxItem;
53105
54290
  var Separator = MenuSeparator;
53106
54291
  var Sub = MenuSub;
53107
54292
  var SubTrigger = MenuSubTrigger;
@@ -53243,6 +54428,11 @@ var DropdownMenuItem = /* @__PURE__ */ React42.forwardRef(
53243
54428
  return /* @__PURE__ */ jsx31(Item2, { ...menuScope, ...itemProps, ref: forwardedRef });
53244
54429
  }, "DropdownMenuItem")
53245
54430
  );
54431
+ var DropdownMenuCheckboxItem = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */ __name22(function DropdownMenuCheckboxItem2(props, forwardedRef) {
54432
+ const { __scopeDropdownMenu, ...checkboxItemProps } = props;
54433
+ const menuScope = useMenuScope(__scopeDropdownMenu);
54434
+ return /* @__PURE__ */ jsx31(CheckboxItem, { ...menuScope, ...checkboxItemProps, ref: forwardedRef });
54435
+ }, "DropdownMenuCheckboxItem"));
53246
54436
  var DropdownMenuSeparator = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */ __name22(function DropdownMenuSeparator2(props, forwardedRef) {
53247
54437
  const { __scopeDropdownMenu, ...separatorProps } = props;
53248
54438
  const menuScope = useMenuScope(__scopeDropdownMenu);
@@ -53292,6 +54482,7 @@ var Trigger = DropdownMenuTrigger;
53292
54482
  var Portal22 = DropdownMenuPortal;
53293
54483
  var Content22 = DropdownMenuContent;
53294
54484
  var Item22 = DropdownMenuItem;
54485
+ var CheckboxItem2 = DropdownMenuCheckboxItem;
53295
54486
  var Separator2 = DropdownMenuSeparator;
53296
54487
  var Sub2 = DropdownMenuSub;
53297
54488
  var SubTrigger2 = DropdownMenuSubTrigger;
@@ -53860,6 +55051,9 @@ var ContextMenu = ({
53860
55051
  engine,
53861
55052
  cameraPreset,
53862
55053
  autoRotate,
55054
+ foldPcbs = false,
55055
+ onFoldPcbsToggle,
55056
+ flexScene = false,
53863
55057
  referenceObject = null,
53864
55058
  onEngineSwitch,
53865
55059
  onCameraPresetSelect,
@@ -54078,6 +55272,23 @@ var ContextMenu = ({
54078
55272
  }
54079
55273
  ) })
54080
55274
  ] }),
55275
+ onFoldPcbsToggle && /* @__PURE__ */ jsxs8(
55276
+ CheckboxItem2,
55277
+ {
55278
+ checked: foldPcbs,
55279
+ onCheckedChange: onFoldPcbsToggle,
55280
+ style: {
55281
+ ...itemStyles2,
55282
+ backgroundColor: hoveredItem === "fold" ? "#404040" : "transparent"
55283
+ },
55284
+ onMouseEnter: () => setHoveredItem("fold"),
55285
+ onMouseLeave: () => setHoveredItem(null),
55286
+ children: [
55287
+ /* @__PURE__ */ jsx34("span", { style: iconContainerStyles2, children: foldPcbs && /* @__PURE__ */ jsx34(CheckIcon, {}) }),
55288
+ /* @__PURE__ */ jsx34("span", { children: "Fold PCBs" })
55289
+ ]
55290
+ }
55291
+ ),
54081
55292
  /* @__PURE__ */ jsxs8(
54082
55293
  Item22,
54083
55294
  {
@@ -54117,7 +55328,7 @@ var ContextMenu = ({
54117
55328
  }
54118
55329
  ),
54119
55330
  /* @__PURE__ */ jsx34(Separator2, { style: separatorStyles2 }),
54120
- /* @__PURE__ */ jsxs8(
55331
+ !flexScene && /* @__PURE__ */ jsxs8(
54121
55332
  Item22,
54122
55333
  {
54123
55334
  style: {
@@ -54134,11 +55345,17 @@ var ContextMenu = ({
54134
55345
  onMouseLeave: () => setHoveredItem(null),
54135
55346
  onTouchStart: () => setHoveredItem("engine"),
54136
55347
  children: [
54137
- /* @__PURE__ */ jsxs8("span", { style: { flex: 1, display: "flex", alignItems: "center" }, children: [
54138
- "Switch to ",
54139
- engine === "jscad" ? "Manifold" : "JSCAD",
54140
- " Engine"
54141
- ] }),
55348
+ /* @__PURE__ */ jsxs8(
55349
+ "span",
55350
+ {
55351
+ style: { flex: 1, display: "flex", alignItems: "center" },
55352
+ children: [
55353
+ "Switch to ",
55354
+ engine === "jscad" ? "Manifold" : "JSCAD",
55355
+ " Engine"
55356
+ ]
55357
+ }
55358
+ ),
54142
55359
  /* @__PURE__ */ jsx34(
54143
55360
  "div",
54144
55361
  {
@@ -54807,7 +56024,7 @@ var useGlobalDownloadGltf = () => {
54807
56024
 
54808
56025
  // src/CadViewer.tsx
54809
56026
  import { jsx as jsx37, jsxs as jsxs11 } from "react/jsx-runtime";
54810
- var DEFAULT_TARGET = new THREE51.Vector3(0, 0, 0);
56027
+ var DEFAULT_TARGET = new THREE52.Vector3(0, 0, 0);
54811
56028
  var INITIAL_CAMERA_POSITION = [5, -5, 5];
54812
56029
  var readStoredCameraType = () => {
54813
56030
  if (typeof window === "undefined") return void 0;
@@ -54815,6 +56032,18 @@ var readStoredCameraType = () => {
54815
56032
  return stored === "orthographic" || stored === "perspective" ? stored : void 0;
54816
56033
  };
54817
56034
  var CadViewerInner = (props) => {
56035
+ const childrenCircuitJson = useConvertChildrenToCircuitJson(
56036
+ props.circuitJson ? void 0 : props.children
56037
+ );
56038
+ const circuitJson = props.circuitJson ?? childrenCircuitJson;
56039
+ const hasBends = circuitJson.some((element) => element.type === "pcb_bend");
56040
+ const hasFlexGeometry = hasBends || circuitJson.some((element) => element.type === "pcb_stiffener");
56041
+ const [foldPcbsOverride, setFoldPcbs] = useState39(
56042
+ void 0
56043
+ );
56044
+ const foldPcbs = foldPcbsOverride ?? props.foldPcbs;
56045
+ const resolvedFoldPcbs = resolveFoldPcbs(circuitJson, foldPcbs);
56046
+ const resolvedProps = { ...props, circuitJson, children: void 0 };
54818
56047
  const [engine, setEngine] = useState39(() => {
54819
56048
  const stored = window.localStorage.getItem("cadViewerEngine");
54820
56049
  return stored === "jscad" || stored === "manifold" ? stored : "manifold";
@@ -54978,10 +56207,20 @@ var CadViewerInner = (props) => {
54978
56207
  },
54979
56208
  ...contextMenuEventHandlers,
54980
56209
  children: [
54981
- engine === "jscad" ? /* @__PURE__ */ jsx37(
56210
+ hasFlexGeometry ? /* @__PURE__ */ jsx37(
56211
+ CadViewerManifold_default,
56212
+ {
56213
+ ...resolvedProps,
56214
+ foldPcbs,
56215
+ autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
56216
+ onUserInteraction: handleUserInteraction,
56217
+ onCameraControllerReady: handleCameraControllerReady,
56218
+ referenceObject
56219
+ }
56220
+ ) : engine === "jscad" ? /* @__PURE__ */ jsx37(
54982
56221
  CadViewerJscad,
54983
56222
  {
54984
- ...props,
56223
+ ...resolvedProps,
54985
56224
  autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
54986
56225
  cameraType,
54987
56226
  onUserInteraction: handleUserInteraction,
@@ -54991,7 +56230,7 @@ var CadViewerInner = (props) => {
54991
56230
  ) : /* @__PURE__ */ jsx37(
54992
56231
  CadViewerManifold_default,
54993
56232
  {
54994
- ...props,
56233
+ ...resolvedProps,
54995
56234
  autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
54996
56235
  cameraType,
54997
56236
  onUserInteraction: handleUserInteraction,
@@ -55005,6 +56244,13 @@ var CadViewerInner = (props) => {
55005
56244
  menuRef,
55006
56245
  menuPos,
55007
56246
  engine,
56247
+ flexScene: hasFlexGeometry,
56248
+ foldPcbs: resolvedFoldPcbs,
56249
+ onFoldPcbsToggle: hasBends ? () => {
56250
+ setFoldPcbs(!resolvedFoldPcbs);
56251
+ setCameraPreset("Custom");
56252
+ closeMenu();
56253
+ } : void 0,
55008
56254
  cameraPreset,
55009
56255
  autoRotate,
55010
56256
  referenceObject,
@@ -55066,14 +56312,14 @@ var CadViewer = (props) => {
55066
56312
  // src/convert-circuit-json-to-3d-svg.ts
55067
56313
  var import_debug = __toESM(require_browser(), 1);
55068
56314
  import { su as su18 } from "@tscircuit/circuit-json-util";
55069
- import * as THREE55 from "three";
56315
+ import * as THREE56 from "three";
55070
56316
  import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
55071
56317
 
55072
56318
  // src/utils/create-geometry-from-polygons.ts
55073
- import * as THREE52 from "three";
55074
- import { BufferGeometry as BufferGeometry5, Float32BufferAttribute as Float32BufferAttribute4 } from "three";
56319
+ import * as THREE53 from "three";
56320
+ import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
55075
56321
  function createGeometryFromPolygons(polygons) {
55076
- const geometry = new BufferGeometry5();
56322
+ const geometry = new BufferGeometry6();
55077
56323
  const vertices = [];
55078
56324
  const normals = [];
55079
56325
  for (const polygon2 of polygons) {
@@ -55084,12 +56330,12 @@ function createGeometryFromPolygons(polygons) {
55084
56330
  ...polygon2.vertices[i + 1]
55085
56331
  // Third vertex
55086
56332
  );
55087
- const v1 = new THREE52.Vector3(...polygon2.vertices[0]);
55088
- const v2 = new THREE52.Vector3(...polygon2.vertices[i]);
55089
- const v3 = new THREE52.Vector3(...polygon2.vertices[i + 1]);
55090
- const normal = new THREE52.Vector3().crossVectors(
55091
- new THREE52.Vector3().subVectors(v2, v1),
55092
- new THREE52.Vector3().subVectors(v3, v1)
56333
+ const v1 = new THREE53.Vector3(...polygon2.vertices[0]);
56334
+ const v2 = new THREE53.Vector3(...polygon2.vertices[i]);
56335
+ const v3 = new THREE53.Vector3(...polygon2.vertices[i + 1]);
56336
+ const normal = new THREE53.Vector3().crossVectors(
56337
+ new THREE53.Vector3().subVectors(v2, v1),
56338
+ new THREE53.Vector3().subVectors(v3, v1)
55093
56339
  ).normalize();
55094
56340
  normals.push(
55095
56341
  normal.x,
@@ -55104,8 +56350,8 @@ function createGeometryFromPolygons(polygons) {
55104
56350
  );
55105
56351
  }
55106
56352
  }
55107
- geometry.setAttribute("position", new Float32BufferAttribute4(vertices, 3));
55108
- geometry.setAttribute("normal", new Float32BufferAttribute4(normals, 3));
56353
+ geometry.setAttribute("position", new Float32BufferAttribute5(vertices, 3));
56354
+ geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
55109
56355
  return geometry;
55110
56356
  }
55111
56357
 
@@ -55113,10 +56359,10 @@ function createGeometryFromPolygons(polygons) {
55113
56359
  var import_modeling2 = __toESM(require_src(), 1);
55114
56360
  var import_jscad_planner2 = __toESM(require_dist(), 1);
55115
56361
  var jscadModeling2 = __toESM(require_src(), 1);
55116
- import * as THREE54 from "three";
56362
+ import * as THREE55 from "three";
55117
56363
 
55118
56364
  // src/utils/load-model.ts
55119
- import * as THREE53 from "three";
56365
+ import * as THREE54 from "three";
55120
56366
  import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
55121
56367
  import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
55122
56368
  import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
@@ -55124,12 +56370,12 @@ async function load3DModel(url) {
55124
56370
  if (url.endsWith(".stl")) {
55125
56371
  const loader = new STLLoader2();
55126
56372
  const geometry = await loader.loadAsync(url);
55127
- const material = new THREE53.MeshStandardMaterial({
56373
+ const material = new THREE54.MeshStandardMaterial({
55128
56374
  color: 8947848,
55129
56375
  metalness: 0.5,
55130
56376
  roughness: 0.5
55131
56377
  });
55132
- return new THREE53.Mesh(geometry, material);
56378
+ return new THREE54.Mesh(geometry, material);
55133
56379
  }
55134
56380
  if (url.endsWith(".obj")) {
55135
56381
  const loader = new OBJLoader2();
@@ -55162,9 +56408,9 @@ async function renderComponent(component, scene) {
55162
56408
  }
55163
56409
  if (component.rotation) {
55164
56410
  model.rotation.set(
55165
- THREE54.MathUtils.degToRad(component.rotation.x ?? 0),
55166
- THREE54.MathUtils.degToRad(component.rotation.y ?? 0),
55167
- THREE54.MathUtils.degToRad(component.rotation.z ?? 0)
56411
+ THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
56412
+ THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
56413
+ THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
55168
56414
  );
55169
56415
  }
55170
56416
  scene.add(model);
@@ -55178,13 +56424,13 @@ async function renderComponent(component, scene) {
55178
56424
  );
55179
56425
  if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
55180
56426
  const threeGeom = convertCSGToThreeGeom(jscadObject);
55181
- const material2 = new THREE54.MeshStandardMaterial({
56427
+ const material2 = new THREE55.MeshStandardMaterial({
55182
56428
  color: 8947848,
55183
56429
  metalness: 0.5,
55184
56430
  roughness: 0.5,
55185
- side: THREE54.DoubleSide
56431
+ side: THREE55.DoubleSide
55186
56432
  });
55187
- const mesh2 = new THREE54.Mesh(threeGeom, material2);
56433
+ const mesh2 = new THREE55.Mesh(threeGeom, material2);
55188
56434
  if (component.position) {
55189
56435
  mesh2.position.set(
55190
56436
  component.position.x ?? 0,
@@ -55194,9 +56440,9 @@ async function renderComponent(component, scene) {
55194
56440
  }
55195
56441
  if (component.rotation) {
55196
56442
  mesh2.rotation.set(
55197
- THREE54.MathUtils.degToRad(component.rotation.x ?? 0),
55198
- THREE54.MathUtils.degToRad(component.rotation.y ?? 0),
55199
- THREE54.MathUtils.degToRad(component.rotation.z ?? 0)
56443
+ THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
56444
+ THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
56445
+ THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
55200
56446
  );
55201
56447
  }
55202
56448
  scene.add(mesh2);
@@ -55213,17 +56459,17 @@ async function renderComponent(component, scene) {
55213
56459
  if (!geom || !geom.polygons && !geom.sides) {
55214
56460
  continue;
55215
56461
  }
55216
- const color = new THREE54.Color(geomInfo.color);
56462
+ const color = new THREE55.Color(geomInfo.color);
55217
56463
  color.convertLinearToSRGB();
55218
56464
  const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
55219
56465
  const threeGeom = convertCSGToThreeGeom(geomWithColor);
55220
- const material2 = new THREE54.MeshStandardMaterial({
56466
+ const material2 = new THREE55.MeshStandardMaterial({
55221
56467
  vertexColors: true,
55222
56468
  metalness: 0.2,
55223
56469
  roughness: 0.8,
55224
- side: THREE54.DoubleSide
56470
+ side: THREE55.DoubleSide
55225
56471
  });
55226
- const mesh2 = new THREE54.Mesh(threeGeom, material2);
56472
+ const mesh2 = new THREE55.Mesh(threeGeom, material2);
55227
56473
  if (component.position) {
55228
56474
  mesh2.position.set(
55229
56475
  component.position.x ?? 0,
@@ -55233,22 +56479,22 @@ async function renderComponent(component, scene) {
55233
56479
  }
55234
56480
  if (component.rotation) {
55235
56481
  mesh2.rotation.set(
55236
- THREE54.MathUtils.degToRad(component.rotation.x ?? 0),
55237
- THREE54.MathUtils.degToRad(component.rotation.y ?? 0),
55238
- THREE54.MathUtils.degToRad(component.rotation.z ?? 0)
56482
+ THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
56483
+ THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
56484
+ THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
55239
56485
  );
55240
56486
  }
55241
56487
  scene.add(mesh2);
55242
56488
  }
55243
56489
  return;
55244
56490
  }
55245
- const geometry = new THREE54.BoxGeometry(0.5, 0.5, 0.5);
55246
- const material = new THREE54.MeshStandardMaterial({
56491
+ const geometry = new THREE55.BoxGeometry(0.5, 0.5, 0.5);
56492
+ const material = new THREE55.MeshStandardMaterial({
55247
56493
  color: 16711680,
55248
56494
  transparent: true,
55249
56495
  opacity: 0.25
55250
56496
  });
55251
- const mesh = new THREE54.Mesh(geometry, material);
56497
+ const mesh = new THREE55.Mesh(geometry, material);
55252
56498
  if (component.position) {
55253
56499
  mesh.position.set(
55254
56500
  component.position.x ?? 0,
@@ -55269,11 +56515,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
55269
56515
  padding = 20,
55270
56516
  zoom = 1.5
55271
56517
  } = options;
55272
- const scene = new THREE55.Scene();
56518
+ const scene = new THREE56.Scene();
55273
56519
  const renderer = new SVGRenderer();
55274
56520
  renderer.setSize(width10, height10);
55275
- renderer.setClearColor(new THREE55.Color(backgroundColor), 1);
55276
- const camera = new THREE55.OrthographicCamera();
56521
+ renderer.setClearColor(new THREE56.Color(backgroundColor), 1);
56522
+ const camera = new THREE56.OrthographicCamera();
55277
56523
  const aspect = width10 / height10;
55278
56524
  const frustumSize = 100;
55279
56525
  const halfFrustumSize = frustumSize / 2 / zoom;
@@ -55287,11 +56533,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
55287
56533
  camera.position.set(position.x, position.y, position.z);
55288
56534
  camera.up.set(0, 1, 0);
55289
56535
  const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
55290
- camera.lookAt(new THREE55.Vector3(lookAt.x, lookAt.y, lookAt.z));
56536
+ camera.lookAt(new THREE56.Vector3(lookAt.x, lookAt.y, lookAt.z));
55291
56537
  camera.updateProjectionMatrix();
55292
- const ambientLight = new THREE55.AmbientLight(16777215, Math.PI / 2);
56538
+ const ambientLight = new THREE56.AmbientLight(16777215, Math.PI / 2);
55293
56539
  scene.add(ambientLight);
55294
- const pointLight = new THREE55.PointLight(16777215, Math.PI / 4);
56540
+ const pointLight = new THREE56.PointLight(16777215, Math.PI / 4);
55295
56541
  pointLight.position.set(-10, -10, 10);
55296
56542
  scene.add(pointLight);
55297
56543
  const components = su18(circuitJson).cad_component.list();
@@ -55316,28 +56562,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
55316
56562
  const material = createBoardMaterial({
55317
56563
  material: boardData?.material,
55318
56564
  color: edgeColor,
55319
- side: THREE55.DoubleSide
56565
+ side: THREE56.DoubleSide
55320
56566
  });
55321
- const mesh = new THREE55.Mesh(geometry, material);
56567
+ const mesh = new THREE56.Mesh(geometry, material);
55322
56568
  scene.add(mesh);
55323
56569
  }
55324
56570
  }
55325
- const gridColor = new THREE55.Color(8947848);
55326
- const gridHelper = new THREE55.GridHelper(100, 100, gridColor, gridColor);
56571
+ const gridColor = new THREE56.Color(8947848);
56572
+ const gridHelper = new THREE56.GridHelper(100, 100, gridColor, gridColor);
55327
56573
  gridHelper.rotation.x = Math.PI / 2;
55328
56574
  const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
55329
56575
  for (const mat of materials) {
55330
56576
  mat.transparent = true;
55331
56577
  mat.opacity = 0.3;
55332
- if (mat instanceof THREE55.LineBasicMaterial) {
56578
+ if (mat instanceof THREE56.LineBasicMaterial) {
55333
56579
  mat.color = gridColor;
55334
56580
  mat.vertexColors = false;
55335
56581
  }
55336
56582
  }
55337
56583
  scene.add(gridHelper);
55338
- const box = new THREE55.Box3().setFromObject(scene);
55339
- const center = box.getCenter(new THREE55.Vector3());
55340
- const size4 = box.getSize(new THREE55.Vector3());
56584
+ const box = new THREE56.Box3().setFromObject(scene);
56585
+ const center = box.getCenter(new THREE56.Vector3());
56586
+ const size4 = box.getSize(new THREE56.Vector3());
55341
56587
  scene.position.sub(center);
55342
56588
  const maxDim = Math.max(size4.x, size4.y, size4.z);
55343
56589
  if (maxDim > 0) {