@tscircuit/3d-viewer 0.0.603 → 0.0.605
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1806 -531
- package/package.json +8 -7
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
|
|
219
|
-
module.exports =
|
|
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
|
|
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) <
|
|
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
|
|
589
|
-
module.exports =
|
|
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) <
|
|
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
|
|
1724
|
-
module.exports =
|
|
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
|
|
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
|
|
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
|
|
3544
|
-
module.exports =
|
|
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) <
|
|
3716
|
+
if (vec3.length(ba) < EPS3) {
|
|
3717
3717
|
ba = vec3.orthogonal(ba, ca);
|
|
3718
3718
|
}
|
|
3719
|
-
if (vec3.length(ca) <
|
|
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) <
|
|
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
|
|
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
|
-
|
|
3972
|
+
area2 += vertices[i][1] * (vertices[j][2] - vertices[h2][2]);
|
|
3973
3973
|
}
|
|
3974
|
-
|
|
3975
|
-
|
|
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
|
-
|
|
3981
|
+
area2 += vertices[i][2] * (vertices[j][0] - vertices[h2][0]);
|
|
3982
3982
|
}
|
|
3983
|
-
|
|
3984
|
-
|
|
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
|
-
|
|
3992
|
+
area2 += vertices[i][0] * (vertices[j][1] - vertices[h2][1]);
|
|
3993
3993
|
}
|
|
3994
|
-
|
|
3995
|
-
|
|
3994
|
+
area2 += vertices[0][0] * (vertices[1][1] - vertices[n - 1][1]);
|
|
3995
|
+
area2 /= 2 * normal[2];
|
|
3996
3996
|
break;
|
|
3997
3997
|
}
|
|
3998
|
-
return
|
|
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 >
|
|
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) <
|
|
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) <
|
|
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 &&
|
|
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
|
|
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 =
|
|
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
|
|
5931
|
-
let
|
|
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
|
-
|
|
5935
|
-
|
|
5934
|
+
area3 += points[i][0] * points[j][1];
|
|
5935
|
+
area3 -= points[j][0] * points[i][1];
|
|
5936
5936
|
}
|
|
5937
|
-
return
|
|
5937
|
+
return area3 / 2;
|
|
5938
5938
|
};
|
|
5939
|
-
module.exports =
|
|
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
|
|
5948
|
-
var measureArea = (polygon2) =>
|
|
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
|
|
6157
|
-
module.exports =
|
|
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
|
|
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 =
|
|
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 <
|
|
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
|
|
6688
|
-
if (
|
|
6687
|
+
let area2 = cache.get(geometry);
|
|
6688
|
+
if (area2) return area2;
|
|
6689
6689
|
const sides2 = geom2.toSides(geometry);
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
cache.set(geometry,
|
|
6693
|
-
return
|
|
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
|
|
6697
|
-
if (
|
|
6696
|
+
let area2 = cache.get(geometry);
|
|
6697
|
+
if (area2) return area2;
|
|
6698
6698
|
const polygons = geom3.toPolygons(geometry);
|
|
6699
|
-
|
|
6700
|
-
cache.set(geometry,
|
|
6701
|
-
return
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
7090
|
+
area2 += a;
|
|
7091
7091
|
x += (p1[0] + p2[0]) * a;
|
|
7092
7092
|
y += (p1[1] + p2[1]) * a;
|
|
7093
7093
|
}
|
|
7094
|
-
|
|
7095
|
-
const f = 1 / (
|
|
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 -
|
|
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 -
|
|
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 -
|
|
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(),
|
|
7594
|
-
const yvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(),
|
|
7595
|
-
const zvector = vec3.scale(vec3.create(), vec3.normalize(vec3.create(),
|
|
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 >
|
|
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] -
|
|
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 -
|
|
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] -
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
8661
|
-
var
|
|
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 ===
|
|
8674
|
+
if (clockwise === signedArea2(data, start, end, dim) > 0) {
|
|
8675
8675
|
for (let i = start; i < end; i += dim) {
|
|
8676
|
-
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 =
|
|
8680
|
+
last = insertNode2(i, data[i], data[i + 1], last);
|
|
8681
8681
|
}
|
|
8682
8682
|
}
|
|
8683
|
-
if (last &&
|
|
8684
|
-
|
|
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
|
|
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 && (
|
|
8697
|
-
|
|
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
|
|
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 (!
|
|
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
|
-
|
|
8717
|
-
|
|
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
|
|
8722
|
+
return filterPoints2(p);
|
|
8723
8723
|
};
|
|
8724
|
-
var
|
|
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 &&
|
|
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
|
|
8733
|
-
var
|
|
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
|
|
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
|
|
8762
|
-
(
|
|
8763
|
-
(
|
|
8764
|
-
|
|
8765
|
-
var
|
|
8766
|
-
const o1 = Math.sign(
|
|
8767
|
-
const o2 = Math.sign(
|
|
8768
|
-
const o3 = Math.sign(
|
|
8769
|
-
const o4 = Math.sign(
|
|
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 &&
|
|
8772
|
-
if (o2 === 0 &&
|
|
8773
|
-
if (o3 === 0 &&
|
|
8774
|
-
if (o4 === 0 &&
|
|
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
|
|
8778
|
-
var
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
8809
|
-
outerNode =
|
|
8808
|
+
outerNode = eliminateHole2(queue[i], outerNode);
|
|
8809
|
+
outerNode = filterPoints2(outerNode, outerNode.next);
|
|
8810
8810
|
}
|
|
8811
8811
|
return outerNode;
|
|
8812
8812
|
};
|
|
8813
|
-
var
|
|
8814
|
-
const bridge =
|
|
8813
|
+
var eliminateHole2 = (hole, outerNode) => {
|
|
8814
|
+
const bridge = findHoleBridge2(hole, outerNode);
|
|
8815
8815
|
if (!bridge) {
|
|
8816
8816
|
return outerNode;
|
|
8817
8817
|
}
|
|
8818
|
-
const bridgeReverse =
|
|
8819
|
-
const filteredBridge =
|
|
8820
|
-
|
|
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
|
|
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 &&
|
|
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 (
|
|
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
|
|
8863
|
-
var
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
-
|
|
8906
|
+
earcutLinked2(outerNode, triangles, dim, minX, minY, invSize);
|
|
8907
8907
|
return triangles;
|
|
8908
8908
|
};
|
|
8909
|
-
var
|
|
8909
|
+
var earcutLinked2 = (ear, triangles, dim, minX, minY, invSize, pass) => {
|
|
8910
8910
|
if (!ear) return;
|
|
8911
|
-
if (!pass && 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 ?
|
|
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
|
-
|
|
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
|
-
|
|
8930
|
+
earcutLinked2(filterPoints2(ear), triangles, dim, minX, minY, invSize, 1);
|
|
8931
8931
|
} else if (pass === 1) {
|
|
8932
|
-
ear =
|
|
8933
|
-
|
|
8932
|
+
ear = cureLocalIntersections2(filterPoints2(ear), triangles, dim);
|
|
8933
|
+
earcutLinked2(ear, triangles, dim, minX, minY, invSize, 2);
|
|
8934
8934
|
} else if (pass === 2) {
|
|
8935
|
-
|
|
8935
|
+
splitEarcut2(ear, triangles, dim, minX, minY, invSize);
|
|
8936
8936
|
}
|
|
8937
8937
|
break;
|
|
8938
8938
|
}
|
|
8939
8939
|
}
|
|
8940
8940
|
};
|
|
8941
|
-
var
|
|
8941
|
+
var isEar2 = (ear) => {
|
|
8942
8942
|
const a = ear.prev;
|
|
8943
8943
|
const b = ear;
|
|
8944
8944
|
const c = ear.next;
|
|
8945
|
-
if (
|
|
8945
|
+
if (area2(a, b, c) >= 0) return false;
|
|
8946
8946
|
let p = ear.next.next;
|
|
8947
8947
|
while (p !== ear.prev) {
|
|
8948
|
-
if (
|
|
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
|
|
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 (
|
|
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 =
|
|
8965
|
-
const maxZ =
|
|
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 &&
|
|
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 &&
|
|
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 &&
|
|
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 &&
|
|
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
|
|
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 &&
|
|
8990
|
-
let c =
|
|
8991
|
-
a =
|
|
8992
|
-
c =
|
|
8993
|
-
|
|
8994
|
-
|
|
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
|
|
9002
|
+
var indexCurve2 = (start, minX, minY, invSize) => {
|
|
9003
9003
|
let p = start;
|
|
9004
9004
|
do {
|
|
9005
|
-
if (p.z === null) p.z =
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 /
|
|
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 <
|
|
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) <
|
|
10518
|
-
if (vec2.distance(prevpolygon.bottomright, thispolygon.topright) <
|
|
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) <
|
|
10527
|
-
const rightlinecontinues = Math.abs(d2) <
|
|
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) >
|
|
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) >
|
|
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] >
|
|
10679
|
-
if (min1[0] - max2[0] >
|
|
10680
|
-
if (min2[1] - max1[1] >
|
|
10681
|
-
if (min1[1] - max2[1] >
|
|
10682
|
-
if (min2[2] - max1[2] >
|
|
10683
|
-
if (min1[2] - max2[2] >
|
|
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 =
|
|
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 = -
|
|
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 >
|
|
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] +
|
|
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
|
|
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) <
|
|
11769
|
-
let rotation = options.closed ?
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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) <
|
|
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
|
|
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 (
|
|
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 (
|
|
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
|
|
12880
|
-
return Number.isFinite(
|
|
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 (
|
|
13570
|
-
if (
|
|
13571
|
-
if (
|
|
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,12 +14431,32 @@ 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
|
|
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
|
-
import { su as
|
|
14459
|
+
import { su as su12 } from "@tscircuit/circuit-json-util";
|
|
14440
14460
|
import { forwardRef as forwardRef3, useMemo as useMemo22 } from "react";
|
|
14441
14461
|
|
|
14442
14462
|
// src/utils/get-cad-pcb-context.ts
|
|
@@ -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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
37461
|
-
const mouse =
|
|
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
|
|
37514
|
-
if (
|
|
37515
|
-
const firstIntersect =
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
37792
|
-
const fitTransformGroup =
|
|
37793
|
-
const modelTransformGroup =
|
|
37794
|
-
const loaderTransformGroup =
|
|
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
|
|
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 } =
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 } =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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.
|
|
39227
|
+
version: "0.0.604",
|
|
39208
39228
|
repository: {
|
|
39209
39229
|
type: "git",
|
|
39210
39230
|
url: "https://github.com/tscircuit/3d-viewer"
|
|
@@ -39242,8 +39262,8 @@ 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.
|
|
39246
|
-
"circuit-to-canvas": "^0.0.
|
|
39265
|
+
"circuit-json": "^0.0.500",
|
|
39266
|
+
"circuit-to-canvas": "^0.0.131",
|
|
39247
39267
|
"react-hot-toast": "^2.6.0",
|
|
39248
39268
|
three: "^0.165.0",
|
|
39249
39269
|
"three-stdlib": "^2.36.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
|
-
"
|
|
39293
|
-
"@tscircuit/props": "^0.0.664",
|
|
39294
|
-
"@tscircuit/circuit-json-util": "^0.0.114"
|
|
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
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
}
|
|
@@ -39901,7 +39922,7 @@ var Canvas = forwardRef(
|
|
|
39901
39922
|
);
|
|
39902
39923
|
|
|
39903
39924
|
// src/react-three/Grid.tsx
|
|
39904
|
-
import { useEffect as useEffect15, useMemo as
|
|
39925
|
+
import { useEffect as useEffect15, useMemo as useMemo13 } from "react";
|
|
39905
39926
|
import * as THREE17 from "three";
|
|
39906
39927
|
var vertexShader = `
|
|
39907
39928
|
varying vec3 worldPosition;
|
|
@@ -39947,7 +39968,7 @@ var Grid = ({
|
|
|
39947
39968
|
}) => {
|
|
39948
39969
|
const { scene, camera } = useThree();
|
|
39949
39970
|
const size4 = 1e3;
|
|
39950
|
-
const gridMesh =
|
|
39971
|
+
const gridMesh = useMemo13(() => {
|
|
39951
39972
|
const geometry = new THREE17.PlaneGeometry(size4, size4);
|
|
39952
39973
|
geometry.rotateX(-Math.PI / 2);
|
|
39953
39974
|
const material = new THREE17.ShaderMaterial({
|
|
@@ -39993,7 +40014,7 @@ var Grid = ({
|
|
|
39993
40014
|
};
|
|
39994
40015
|
|
|
39995
40016
|
// src/react-three/Lights.tsx
|
|
39996
|
-
import { useEffect as useEffect16, useMemo as
|
|
40017
|
+
import { useEffect as useEffect16, useMemo as useMemo14 } from "react";
|
|
39997
40018
|
import * as THREE18 from "three";
|
|
39998
40019
|
var UNDERSIDE_LIGHT_FACTOR = 0.75;
|
|
39999
40020
|
var Lights = ({
|
|
@@ -40003,7 +40024,7 @@ var Lights = ({
|
|
|
40003
40024
|
shadowsEnabled = false
|
|
40004
40025
|
}) => {
|
|
40005
40026
|
const { scene } = useThree();
|
|
40006
|
-
const lightRig =
|
|
40027
|
+
const lightRig = useMemo14(() => {
|
|
40007
40028
|
const rig = new THREE18.Group();
|
|
40008
40029
|
rig.name = "cad-viewer-light-rig";
|
|
40009
40030
|
const centerX = boardCenter?.x ?? 0;
|
|
@@ -40118,7 +40139,7 @@ var Lights = ({
|
|
|
40118
40139
|
};
|
|
40119
40140
|
|
|
40120
40141
|
// src/react-three/OrbitControls.tsx
|
|
40121
|
-
import { useEffect as useEffect17, useMemo as
|
|
40142
|
+
import { useEffect as useEffect17, useMemo as useMemo15 } from "react";
|
|
40122
40143
|
import * as THREE19 from "three";
|
|
40123
40144
|
import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
40124
40145
|
var OrbitControls = ({
|
|
@@ -40134,7 +40155,7 @@ var OrbitControls = ({
|
|
|
40134
40155
|
onControlsChange
|
|
40135
40156
|
}) => {
|
|
40136
40157
|
const { camera, renderer } = useThree();
|
|
40137
|
-
const controls =
|
|
40158
|
+
const controls = useMemo15(() => {
|
|
40138
40159
|
if (!camera || !renderer) return null;
|
|
40139
40160
|
return new ThreeOrbitControls(camera, renderer.domElement);
|
|
40140
40161
|
}, [camera, renderer]);
|
|
@@ -40435,7 +40456,7 @@ var OrientationCubeCanvas = () => {
|
|
|
40435
40456
|
};
|
|
40436
40457
|
|
|
40437
40458
|
// src/three-components/reference-object.tsx
|
|
40438
|
-
import { useEffect as useEffect19, useMemo as
|
|
40459
|
+
import { useEffect as useEffect19, useMemo as useMemo16 } from "react";
|
|
40439
40460
|
|
|
40440
40461
|
// src/reference-objects/create-reference-object.ts
|
|
40441
40462
|
import * as THREE21 from "three";
|
|
@@ -40821,7 +40842,7 @@ var ReferenceObject = ({
|
|
|
40821
40842
|
boardCenter
|
|
40822
40843
|
}) => {
|
|
40823
40844
|
const { scene } = useThree();
|
|
40824
|
-
const object =
|
|
40845
|
+
const object = useMemo16(() => {
|
|
40825
40846
|
const nextObject = createReferenceObject(type);
|
|
40826
40847
|
const position = getReferenceObjectPosition(
|
|
40827
40848
|
type,
|
|
@@ -40887,17 +40908,17 @@ var CadViewerContainer = forwardRef2(
|
|
|
40887
40908
|
onCameraControllerReady(controller);
|
|
40888
40909
|
}
|
|
40889
40910
|
}, [controller, onCameraControllerReady]);
|
|
40890
|
-
const comparisonBounds =
|
|
40911
|
+
const comparisonBounds = useMemo17(() => {
|
|
40891
40912
|
if (!referenceObject) return void 0;
|
|
40892
40913
|
return getComparisonBounds(referenceObject, boardDimensions, boardCenter);
|
|
40893
40914
|
}, [referenceObject, boardDimensions, boardCenter]);
|
|
40894
|
-
const gridSectionSize =
|
|
40915
|
+
const gridSectionSize = useMemo17(() => {
|
|
40895
40916
|
if (!boardDimensions) return 10;
|
|
40896
40917
|
const width10 = boardDimensions.width ?? 0;
|
|
40897
40918
|
const height10 = boardDimensions.height ?? 0;
|
|
40898
40919
|
return Math.max(Math.max(width10, height10) * 1.5, 10);
|
|
40899
40920
|
}, [boardDimensions]);
|
|
40900
|
-
const orbitTarget =
|
|
40921
|
+
const orbitTarget = useMemo17(() => {
|
|
40901
40922
|
if (comparisonBounds) {
|
|
40902
40923
|
return [
|
|
40903
40924
|
(comparisonBounds.minX + comparisonBounds.maxX) / 2,
|
|
@@ -41030,19 +41051,6 @@ var CadViewerContainer = forwardRef2(
|
|
|
41030
41051
|
}
|
|
41031
41052
|
);
|
|
41032
41053
|
|
|
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
41054
|
// src/hooks/use-stls-from-geom.ts
|
|
41047
41055
|
import { useState as useState12, useEffect as useEffect21 } from "react";
|
|
41048
41056
|
import stlSerializer from "@jscad/stl-serializer";
|
|
@@ -41091,14 +41099,14 @@ var import_primitives = __toESM(require_primitives(), 1);
|
|
|
41091
41099
|
var import_transforms = __toESM(require_transforms(), 1);
|
|
41092
41100
|
var import_expansions = __toESM(require_expansions(), 1);
|
|
41093
41101
|
var arePointsClockwise = (points) => {
|
|
41094
|
-
let
|
|
41102
|
+
let area2 = 0;
|
|
41095
41103
|
for (let i = 0; i < points.length; i++) {
|
|
41096
41104
|
const j = (i + 1) % points.length;
|
|
41097
|
-
|
|
41098
|
-
|
|
41105
|
+
area2 += points[i][0] * points[j][1];
|
|
41106
|
+
area2 -= points[j][0] * points[i][1];
|
|
41099
41107
|
}
|
|
41100
|
-
const
|
|
41101
|
-
return
|
|
41108
|
+
const signedArea2 = area2 / 2;
|
|
41109
|
+
return signedArea2 <= 0;
|
|
41102
41110
|
};
|
|
41103
41111
|
var createBoardGeomWithOutline = (board, depth = 1.2, options = {}) => {
|
|
41104
41112
|
const { xyOutset = 0 } = options;
|
|
@@ -41129,6 +41137,7 @@ var colors = {
|
|
|
41129
41137
|
fr4SolderMaskGreen: [0.06, 0.31, 0.19],
|
|
41130
41138
|
fr4TracesWithMaskGreen: [0.09, 0.38, 0.23],
|
|
41131
41139
|
fr4TracesWithoutMaskTan: [0.6, 0.43, 0.28],
|
|
41140
|
+
flexAmber: [0.8, 0.61, 0.2],
|
|
41132
41141
|
fr1Tan: [0.8, 0.4, 0.2],
|
|
41133
41142
|
fr1TracesWithMaskCopper: [0.9, 0.6, 0.2],
|
|
41134
41143
|
fr1SolderMaskGreen: [0.02, 0.1, 0.04]
|
|
@@ -41139,11 +41148,13 @@ var TRACE_TEXTURE_RESOLUTION = 150;
|
|
|
41139
41148
|
var FAUX_BOARD_OPACITY = 0.6;
|
|
41140
41149
|
var boardMaterialColors = {
|
|
41141
41150
|
fr1: colors.fr1Tan,
|
|
41142
|
-
fr4: colors.fr4Tan
|
|
41151
|
+
fr4: colors.fr4Tan,
|
|
41152
|
+
flex: colors.flexAmber
|
|
41143
41153
|
};
|
|
41144
41154
|
var soldermaskColors = {
|
|
41145
41155
|
fr1: colors.fr1SolderMaskGreen,
|
|
41146
|
-
fr4: colors.fr4SolderMaskGreen
|
|
41156
|
+
fr4: colors.fr4SolderMaskGreen,
|
|
41157
|
+
flex: colors.flexAmber
|
|
41147
41158
|
};
|
|
41148
41159
|
|
|
41149
41160
|
// src/utils/soldermask-color.ts
|
|
@@ -41273,7 +41284,7 @@ var import_booleans4 = __toESM(require_booleans(), 1);
|
|
|
41273
41284
|
var import_extrusions4 = __toESM(require_extrusions(), 1);
|
|
41274
41285
|
var import_transforms6 = __toESM(require_transforms(), 1);
|
|
41275
41286
|
var import_primitives6 = __toESM(require_primitives(), 1);
|
|
41276
|
-
import { su as
|
|
41287
|
+
import { su as su5 } from "@tscircuit/circuit-json-util";
|
|
41277
41288
|
|
|
41278
41289
|
// src/geoms/create-hole-with-polygon-pad.ts
|
|
41279
41290
|
var import_primitives3 = __toESM(require_primitives(), 1);
|
|
@@ -41933,6 +41944,51 @@ function createViaBoardDrill({
|
|
|
41933
41944
|
return drill;
|
|
41934
41945
|
}
|
|
41935
41946
|
|
|
41947
|
+
// src/utils/get-pcb-vias.ts
|
|
41948
|
+
import { createBoardOwnerMap, su as su4 } from "@tscircuit/circuit-json-util";
|
|
41949
|
+
function getPcbVias(circuitJson) {
|
|
41950
|
+
const boardOwnerMap = createBoardOwnerMap(circuitJson);
|
|
41951
|
+
const vias = [...su4(circuitJson).pcb_via.list()];
|
|
41952
|
+
const viasByPosition = /* @__PURE__ */ new Map();
|
|
41953
|
+
for (const via of vias) {
|
|
41954
|
+
const board = boardOwnerMap.get(via.pcb_via_id);
|
|
41955
|
+
const positionKey = `${board?.pcb_board_id ?? ""}:${via.x}:${via.y}`;
|
|
41956
|
+
const viasAtPosition = viasByPosition.get(positionKey) ?? [];
|
|
41957
|
+
viasAtPosition.push(via);
|
|
41958
|
+
viasByPosition.set(positionKey, viasAtPosition);
|
|
41959
|
+
}
|
|
41960
|
+
for (const trace of su4(circuitJson).pcb_trace.list()) {
|
|
41961
|
+
const board = boardOwnerMap.get(trace.pcb_trace_id);
|
|
41962
|
+
for (const [index2, point] of trace.route.entries()) {
|
|
41963
|
+
if (point.route_type !== "via") continue;
|
|
41964
|
+
const positionKey = `${board?.pcb_board_id ?? ""}:${point.x}:${point.y}`;
|
|
41965
|
+
const viasAtPosition = viasByPosition.get(positionKey) ?? [];
|
|
41966
|
+
const hasMatchingVia = viasAtPosition.some(
|
|
41967
|
+
(via2) => via2.layers.includes(point.from_layer) && via2.layers.includes(point.to_layer)
|
|
41968
|
+
);
|
|
41969
|
+
if (hasMatchingVia) continue;
|
|
41970
|
+
const via = {
|
|
41971
|
+
type: "pcb_via",
|
|
41972
|
+
pcb_via_id: `${trace.pcb_trace_id}_route_via_${index2}`,
|
|
41973
|
+
pcb_trace_id: trace.pcb_trace_id,
|
|
41974
|
+
subcircuit_id: trace.subcircuit_id,
|
|
41975
|
+
pcb_group_id: trace.pcb_group_id,
|
|
41976
|
+
x: point.x,
|
|
41977
|
+
y: point.y,
|
|
41978
|
+
layers: [point.from_layer, point.to_layer],
|
|
41979
|
+
hole_diameter: point.hole_diameter ?? board?.min_via_hole_diameter ?? 0.25,
|
|
41980
|
+
outer_diameter: point.outer_diameter ?? board?.min_via_pad_diameter ?? 0.6,
|
|
41981
|
+
tented_on_top: point.tented_on_top,
|
|
41982
|
+
tented_on_bottom: point.tented_on_bottom
|
|
41983
|
+
};
|
|
41984
|
+
vias.push(via);
|
|
41985
|
+
viasAtPosition.push(via);
|
|
41986
|
+
viasByPosition.set(positionKey, viasAtPosition);
|
|
41987
|
+
}
|
|
41988
|
+
}
|
|
41989
|
+
return vias;
|
|
41990
|
+
}
|
|
41991
|
+
|
|
41936
41992
|
// src/BoardGeomBuilder.ts
|
|
41937
41993
|
var PAD_ROUNDED_SEGMENTS = 64;
|
|
41938
41994
|
var BOARD_CLIP_Z_MARGIN = 1;
|
|
@@ -41967,7 +42023,7 @@ var BoardGeomBuilder = class {
|
|
|
41967
42023
|
const panels = circuitJson.filter(
|
|
41968
42024
|
(e) => e.type === "pcb_panel"
|
|
41969
42025
|
);
|
|
41970
|
-
const boards =
|
|
42026
|
+
const boards = su5(circuitJson).pcb_board.list();
|
|
41971
42027
|
if (panels.length > 0) {
|
|
41972
42028
|
const panel = panels[0];
|
|
41973
42029
|
const firstBoardInPanel = boards.find(
|
|
@@ -41988,10 +42044,10 @@ var BoardGeomBuilder = class {
|
|
|
41988
42044
|
const boardsNotInPanel = boards.filter((b) => !b.pcb_panel_id);
|
|
41989
42045
|
this.board = boardsNotInPanel[0];
|
|
41990
42046
|
}
|
|
41991
|
-
this.plated_holes =
|
|
41992
|
-
this.holes =
|
|
41993
|
-
this.pcb_vias =
|
|
41994
|
-
this.pcb_cutouts =
|
|
42047
|
+
this.plated_holes = su5(circuitJson).pcb_plated_hole.list();
|
|
42048
|
+
this.holes = su5(circuitJson).pcb_hole.list();
|
|
42049
|
+
this.pcb_vias = getPcbVias(circuitJson);
|
|
42050
|
+
this.pcb_cutouts = su5(circuitJson).pcb_cutout.list();
|
|
41995
42051
|
this.ctx = { pcbThickness: this.board.thickness ?? 1.2 };
|
|
41996
42052
|
this.initializeBoard();
|
|
41997
42053
|
}
|
|
@@ -42693,7 +42749,7 @@ var ErrorBox = ({ parent }) => {
|
|
|
42693
42749
|
};
|
|
42694
42750
|
|
|
42695
42751
|
// src/three-components/JscadBoardTextures.tsx
|
|
42696
|
-
import { su as
|
|
42752
|
+
import { su as su9 } from "@tscircuit/circuit-json-util";
|
|
42697
42753
|
import { useEffect as useEffect25, useMemo as useMemo20 } from "react";
|
|
42698
42754
|
|
|
42699
42755
|
// src/textures/create-combined-board-textures.ts
|
|
@@ -42750,7 +42806,7 @@ function calculateOutlineBounds(boardData) {
|
|
|
42750
42806
|
}
|
|
42751
42807
|
|
|
42752
42808
|
// src/utils/pad-texture.ts
|
|
42753
|
-
import { su as
|
|
42809
|
+
import { su as su6 } from "@tscircuit/circuit-json-util";
|
|
42754
42810
|
import { CircuitToCanvasDrawer } from "circuit-to-canvas";
|
|
42755
42811
|
import * as THREE27 from "three";
|
|
42756
42812
|
function createPadTextureForLayer({
|
|
@@ -42760,13 +42816,13 @@ function createPadTextureForLayer({
|
|
|
42760
42816
|
copperColor,
|
|
42761
42817
|
traceTextureResolution
|
|
42762
42818
|
}) {
|
|
42763
|
-
const pcbSmtPads =
|
|
42819
|
+
const pcbSmtPads = su6(circuitJson).pcb_smtpad.list();
|
|
42764
42820
|
const smtPadsOnLayer = pcbSmtPads.filter((pad2) => pad2.layer === layer);
|
|
42765
42821
|
if (smtPadsOnLayer.length === 0) return null;
|
|
42766
|
-
const holes =
|
|
42767
|
-
const platedHolesOnLayer =
|
|
42768
|
-
const viasOnLayer =
|
|
42769
|
-
const cutouts =
|
|
42822
|
+
const holes = su6(circuitJson).pcb_hole.list();
|
|
42823
|
+
const platedHolesOnLayer = su6(circuitJson).pcb_plated_hole.list().filter((e) => !Array.isArray(e.layers) || e.layers.includes(layer));
|
|
42824
|
+
const viasOnLayer = su6(circuitJson).pcb_via.list().filter((e) => !Array.isArray(e.layers) || e.layers.includes(layer));
|
|
42825
|
+
const cutouts = su6(circuitJson).pcb_cutout.list();
|
|
42770
42826
|
const drillElements = [...holes, ...platedHolesOnLayer, ...viasOnLayer];
|
|
42771
42827
|
const pcbRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
|
|
42772
42828
|
const boardOutlineBounds = calculateOutlineBounds(boardData);
|
|
@@ -42842,7 +42898,7 @@ function createPadTextureForLayer({
|
|
|
42842
42898
|
}
|
|
42843
42899
|
|
|
42844
42900
|
// src/utils/panel-outline-texture.ts
|
|
42845
|
-
import { su as
|
|
42901
|
+
import { su as su7 } from "@tscircuit/circuit-json-util";
|
|
42846
42902
|
import * as THREE28 from "three";
|
|
42847
42903
|
var resolvePanelIdForTexture = (circuitJson) => {
|
|
42848
42904
|
const panels = circuitJson.filter(
|
|
@@ -42861,7 +42917,7 @@ function createPanelOutlineTextureForLayer({
|
|
|
42861
42917
|
}) {
|
|
42862
42918
|
const panelId = resolvePanelIdForTexture(circuitJson);
|
|
42863
42919
|
if (!panelId) return null;
|
|
42864
|
-
const allBoards =
|
|
42920
|
+
const allBoards = su7(circuitJson).pcb_board.list();
|
|
42865
42921
|
const boardsInPanel = allBoards.filter(
|
|
42866
42922
|
(b) => b.pcb_panel_id === panelId || b.position_mode === "relative_to_panel_anchor" && !b.pcb_panel_id
|
|
42867
42923
|
);
|
|
@@ -42923,43 +42979,7 @@ function createPanelOutlineTextureForLayer({
|
|
|
42923
42979
|
// src/utils/trace-texture.ts
|
|
42924
42980
|
import * as THREE29 from "three";
|
|
42925
42981
|
import { CircuitToCanvasDrawer as CircuitToCanvasDrawer2 } from "circuit-to-canvas";
|
|
42926
|
-
import { getElementRenderLayers, su as
|
|
42927
|
-
|
|
42928
|
-
// src/utils/trace-layer-segments.ts
|
|
42929
|
-
function isWireRoutePoint(point) {
|
|
42930
|
-
return point && point.route_type === "wire" && typeof point.layer === "string" && typeof point.width === "number";
|
|
42931
|
-
}
|
|
42932
|
-
function splitTraceIntoLayerSegments(trace, layer) {
|
|
42933
|
-
const segments = [];
|
|
42934
|
-
let currentRoute = [];
|
|
42935
|
-
const pushCurrentSegment = () => {
|
|
42936
|
-
if (currentRoute.length < 2) {
|
|
42937
|
-
currentRoute = [];
|
|
42938
|
-
return;
|
|
42939
|
-
}
|
|
42940
|
-
segments.push({
|
|
42941
|
-
...trace,
|
|
42942
|
-
pcb_trace_id: `${trace.pcb_trace_id}_${layer}_${segments.length}`,
|
|
42943
|
-
route: currentRoute
|
|
42944
|
-
});
|
|
42945
|
-
currentRoute = [];
|
|
42946
|
-
};
|
|
42947
|
-
for (const point of trace.route) {
|
|
42948
|
-
if (!isWireRoutePoint(point)) {
|
|
42949
|
-
pushCurrentSegment();
|
|
42950
|
-
continue;
|
|
42951
|
-
}
|
|
42952
|
-
if (point.layer !== layer) {
|
|
42953
|
-
pushCurrentSegment();
|
|
42954
|
-
continue;
|
|
42955
|
-
}
|
|
42956
|
-
currentRoute.push(point);
|
|
42957
|
-
}
|
|
42958
|
-
pushCurrentSegment();
|
|
42959
|
-
return segments;
|
|
42960
|
-
}
|
|
42961
|
-
|
|
42962
|
-
// src/utils/trace-texture.ts
|
|
42982
|
+
import { getElementRenderLayers, su as su8 } from "@tscircuit/circuit-json-util";
|
|
42963
42983
|
function createTraceTextureForLayer({
|
|
42964
42984
|
layer,
|
|
42965
42985
|
circuitJson,
|
|
@@ -42967,11 +42987,13 @@ function createTraceTextureForLayer({
|
|
|
42967
42987
|
traceColor,
|
|
42968
42988
|
traceTextureResolution
|
|
42969
42989
|
}) {
|
|
42970
|
-
const pcbTraces =
|
|
42971
|
-
const pcbVias =
|
|
42972
|
-
const pcbPlatedHoles =
|
|
42990
|
+
const pcbTraces = su8(circuitJson).pcb_trace.list();
|
|
42991
|
+
const pcbVias = su8(circuitJson).pcb_via.list();
|
|
42992
|
+
const pcbPlatedHoles = su8(circuitJson).pcb_plated_hole.list();
|
|
42973
42993
|
const pcbRenderLayer = layer === "top" ? "top_copper" : "bottom_copper";
|
|
42974
|
-
const tracesOnLayer = pcbTraces.filter(
|
|
42994
|
+
const tracesOnLayer = pcbTraces.filter(
|
|
42995
|
+
(trace) => getElementRenderLayers(trace).includes(pcbRenderLayer)
|
|
42996
|
+
);
|
|
42975
42997
|
if (tracesOnLayer.length === 0) return null;
|
|
42976
42998
|
const platedHolesOnLayer = pcbPlatedHoles.filter(
|
|
42977
42999
|
(hole) => hole.layers.includes(layer)
|
|
@@ -43805,6 +43827,22 @@ import * as THREE35 from "three";
|
|
|
43805
43827
|
import { CircuitToCanvasDrawer as CircuitToCanvasDrawer8 } from "circuit-to-canvas";
|
|
43806
43828
|
var FABRICATION_NOTE_COLOR2 = "rgb(255,243,204)";
|
|
43807
43829
|
var TRANSPARENT3 = "rgba(0,0,0,0)";
|
|
43830
|
+
var isViaTented = (via, layer, board) => {
|
|
43831
|
+
const viaTenting = layer === "top" ? via.tented_on_top : via.tented_on_bottom;
|
|
43832
|
+
const legacyTenting = "is_tented" in via ? via.is_tented : void 0;
|
|
43833
|
+
const boardDefault = layer === "top" ? board?.default_via_tented_on_top : board?.default_via_tented_on_bottom;
|
|
43834
|
+
return viaTenting ?? legacyTenting ?? boardDefault ?? false;
|
|
43835
|
+
};
|
|
43836
|
+
var isOpenSurfaceAperture = (element, layer, board, soldermaskVisible) => {
|
|
43837
|
+
if (element.type === "pcb_cutout") return true;
|
|
43838
|
+
if (element.type === "pcb_via") {
|
|
43839
|
+
return !soldermaskVisible || !isViaTented(element, layer, board);
|
|
43840
|
+
}
|
|
43841
|
+
if (element.type === "pcb_hole" || element.type === "pcb_plated_hole") {
|
|
43842
|
+
return !soldermaskVisible || element.is_covered_with_solder_mask !== true;
|
|
43843
|
+
}
|
|
43844
|
+
return false;
|
|
43845
|
+
};
|
|
43808
43846
|
var setDrawerBounds5 = (drawer, bounds) => {
|
|
43809
43847
|
drawer.setCameraBounds({
|
|
43810
43848
|
minX: bounds.minX,
|
|
@@ -43818,8 +43856,9 @@ var drawSilkscreenLayer = ({
|
|
|
43818
43856
|
layer,
|
|
43819
43857
|
bounds,
|
|
43820
43858
|
elements,
|
|
43821
|
-
|
|
43822
|
-
silkscreenColor
|
|
43859
|
+
circuitJson,
|
|
43860
|
+
silkscreenColor,
|
|
43861
|
+
soldermaskVisible
|
|
43823
43862
|
}) => {
|
|
43824
43863
|
const renderLayer = layer === "top" ? "top_silkscreen" : "bottom_silkscreen";
|
|
43825
43864
|
const drawer = new CircuitToCanvasDrawer8(ctx);
|
|
@@ -43869,8 +43908,26 @@ var drawSilkscreenLayer = ({
|
|
|
43869
43908
|
}
|
|
43870
43909
|
});
|
|
43871
43910
|
setDrawerBounds5(drawer, bounds);
|
|
43872
|
-
drawer.drawElements(
|
|
43911
|
+
drawer.drawElements(elements, {
|
|
43873
43912
|
layers: [renderLayer],
|
|
43913
|
+
clipContextElements: circuitJson
|
|
43914
|
+
});
|
|
43915
|
+
const apertureElements = circuitJson.flatMap(
|
|
43916
|
+
(element) => {
|
|
43917
|
+
if (element.type === "pcb_trace") {
|
|
43918
|
+
const board2 = ctx.boardOwnerMap?.get(element.pcb_trace_id);
|
|
43919
|
+
const route = element.route.filter(
|
|
43920
|
+
(point) => point.route_type === "via" && (!soldermaskVisible || !isViaTented(point, layer, board2))
|
|
43921
|
+
);
|
|
43922
|
+
return route.length ? [{ ...element, route }] : [];
|
|
43923
|
+
}
|
|
43924
|
+
const board = element.type === "pcb_via" ? ctx.boardOwnerMap?.get(element.pcb_via_id) : void 0;
|
|
43925
|
+
return isOpenSurfaceAperture(element, layer, board, soldermaskVisible) ? [element] : [];
|
|
43926
|
+
}
|
|
43927
|
+
);
|
|
43928
|
+
drawer.drawElements(apertureElements, {
|
|
43929
|
+
layers: [renderLayer],
|
|
43930
|
+
clipContextElements: circuitJson,
|
|
43874
43931
|
clearDrillHoles: true
|
|
43875
43932
|
});
|
|
43876
43933
|
};
|
|
@@ -43881,18 +43938,6 @@ var isSilkscreenElement = (element, layer) => {
|
|
|
43881
43938
|
const elementType = element.type;
|
|
43882
43939
|
return elementType.startsWith("pcb_silkscreen_");
|
|
43883
43940
|
};
|
|
43884
|
-
var isOpenSurfaceAperture = (element, soldermaskVisible, layer) => {
|
|
43885
|
-
if (element.type === "pcb_cutout") return true;
|
|
43886
|
-
if (element.type === "pcb_via") {
|
|
43887
|
-
const legacyTented = element.is_tented;
|
|
43888
|
-
const tented = (layer === "top" ? element.tented_on_top : element.tented_on_bottom) ?? legacyTented;
|
|
43889
|
-
return !soldermaskVisible || tented !== true;
|
|
43890
|
-
}
|
|
43891
|
-
if (element.type === "pcb_hole" || element.type === "pcb_plated_hole") {
|
|
43892
|
-
return !soldermaskVisible || element.is_covered_with_solder_mask !== true;
|
|
43893
|
-
}
|
|
43894
|
-
return false;
|
|
43895
|
-
};
|
|
43896
43941
|
function createSilkscreenTextureForLayer({
|
|
43897
43942
|
layer,
|
|
43898
43943
|
circuitJson,
|
|
@@ -43905,9 +43950,6 @@ function createSilkscreenTextureForLayer({
|
|
|
43905
43950
|
(element) => isSilkscreenElement(element, layer)
|
|
43906
43951
|
);
|
|
43907
43952
|
if (elements.length === 0) return null;
|
|
43908
|
-
const apertureElements = circuitJson.filter(
|
|
43909
|
-
(element) => isOpenSurfaceAperture(element, soldermaskVisible, layer)
|
|
43910
|
-
);
|
|
43911
43953
|
const bounds = getSoldermaskRenderBounds(circuitJson, boardData);
|
|
43912
43954
|
const canvasWidth = Math.floor(bounds.width * traceTextureResolution);
|
|
43913
43955
|
const canvasHeight = Math.floor(bounds.height * traceTextureResolution);
|
|
@@ -43926,8 +43968,9 @@ function createSilkscreenTextureForLayer({
|
|
|
43926
43968
|
layer,
|
|
43927
43969
|
bounds,
|
|
43928
43970
|
elements,
|
|
43929
|
-
|
|
43930
|
-
silkscreenColor
|
|
43971
|
+
circuitJson,
|
|
43972
|
+
silkscreenColor,
|
|
43973
|
+
soldermaskVisible
|
|
43931
43974
|
});
|
|
43932
43975
|
const texture = new THREE35.CanvasTexture(canvas);
|
|
43933
43976
|
texture.generateMipmaps = true;
|
|
@@ -44870,7 +44913,7 @@ function JscadBoardTextures({
|
|
|
44870
44913
|
const panels = circuitJson.filter(
|
|
44871
44914
|
(e) => e.type === "pcb_panel"
|
|
44872
44915
|
);
|
|
44873
|
-
const boards =
|
|
44916
|
+
const boards = su9(circuitJson).pcb_board.list();
|
|
44874
44917
|
if (panels.length > 0) {
|
|
44875
44918
|
const panel = panels[0];
|
|
44876
44919
|
const firstBoardInPanel = boards.find(
|
|
@@ -45146,16 +45189,16 @@ function VisibleSTLModel({
|
|
|
45146
45189
|
}
|
|
45147
45190
|
|
|
45148
45191
|
// src/utils/preprocess-circuit-json.ts
|
|
45149
|
-
import { su as
|
|
45192
|
+
import { su as su11 } from "@tscircuit/circuit-json-util";
|
|
45150
45193
|
|
|
45151
45194
|
// src/utils/create-faux-board.ts
|
|
45152
|
-
import { su as
|
|
45195
|
+
import { su as su10, getBoundsOfPcbElements } from "@tscircuit/circuit-json-util";
|
|
45153
45196
|
function createFauxBoard(circuitJson) {
|
|
45154
|
-
const cadComponents =
|
|
45155
|
-
const pads =
|
|
45156
|
-
const holes =
|
|
45157
|
-
const platedHoles =
|
|
45158
|
-
const vias =
|
|
45197
|
+
const cadComponents = su10(circuitJson).cad_component.list().filter((cad) => cad.pcb_component_id);
|
|
45198
|
+
const pads = su10(circuitJson).pcb_smtpad.list();
|
|
45199
|
+
const holes = su10(circuitJson).pcb_hole.list();
|
|
45200
|
+
const platedHoles = su10(circuitJson).pcb_plated_hole.list();
|
|
45201
|
+
const vias = su10(circuitJson).pcb_via.list();
|
|
45159
45202
|
if (cadComponents.length === 0 && pads.length === 0 && holes.length === 0 && platedHoles.length === 0 && vias.length === 0) {
|
|
45160
45203
|
return null;
|
|
45161
45204
|
}
|
|
@@ -45204,7 +45247,7 @@ function createFauxBoard(circuitJson) {
|
|
|
45204
45247
|
|
|
45205
45248
|
// src/utils/preprocess-circuit-json.ts
|
|
45206
45249
|
function addFauxBoardIfNeeded(circuitJson) {
|
|
45207
|
-
const boards =
|
|
45250
|
+
const boards = su11(circuitJson).pcb_board.list();
|
|
45208
45251
|
if (boards.length > 0) {
|
|
45209
45252
|
return circuitJson;
|
|
45210
45253
|
}
|
|
@@ -45256,7 +45299,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
45256
45299
|
const initialCameraPosition = useMemo22(() => {
|
|
45257
45300
|
if (!internalCircuitJson) return [5, -5, 5];
|
|
45258
45301
|
try {
|
|
45259
|
-
const board =
|
|
45302
|
+
const board = su12(internalCircuitJson).pcb_board.list()[0];
|
|
45260
45303
|
if (!board) return [5, -5, 5];
|
|
45261
45304
|
const { width: width10, height: height10 } = board;
|
|
45262
45305
|
if (!width10 && !height10) {
|
|
@@ -45282,7 +45325,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
45282
45325
|
const isFauxBoard = useMemo22(() => {
|
|
45283
45326
|
if (!internalCircuitJson) return false;
|
|
45284
45327
|
try {
|
|
45285
|
-
const board =
|
|
45328
|
+
const board = su12(internalCircuitJson).pcb_board.list()[0];
|
|
45286
45329
|
return !!board && board.pcb_board_id === "faux-board";
|
|
45287
45330
|
} catch (e) {
|
|
45288
45331
|
return false;
|
|
@@ -45291,7 +45334,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
45291
45334
|
const boardDimensions = useMemo22(() => {
|
|
45292
45335
|
if (!internalCircuitJson) return void 0;
|
|
45293
45336
|
try {
|
|
45294
|
-
const board =
|
|
45337
|
+
const board = su12(internalCircuitJson).pcb_board.list()[0];
|
|
45295
45338
|
if (!board) return void 0;
|
|
45296
45339
|
const bounds = calculateOutlineBounds(board);
|
|
45297
45340
|
return { width: bounds.width, height: bounds.height };
|
|
@@ -45303,7 +45346,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
45303
45346
|
const boardCenter = useMemo22(() => {
|
|
45304
45347
|
if (!internalCircuitJson) return void 0;
|
|
45305
45348
|
try {
|
|
45306
|
-
const board =
|
|
45349
|
+
const board = su12(internalCircuitJson).pcb_board.list()[0];
|
|
45307
45350
|
if (!board) return void 0;
|
|
45308
45351
|
const bounds = calculateOutlineBounds(board);
|
|
45309
45352
|
return { x: bounds.centerX, y: bounds.centerY };
|
|
@@ -45314,7 +45357,7 @@ var CadViewerJscad = forwardRef3(
|
|
|
45314
45357
|
}, [internalCircuitJson]);
|
|
45315
45358
|
const pcbThickness = usePcbThickness(internalCircuitJson);
|
|
45316
45359
|
const { stls: boardStls, loading } = useStlsFromGeom(boardGeom);
|
|
45317
|
-
const cad_components =
|
|
45360
|
+
const cad_components = su12(internalCircuitJson).cad_component.list();
|
|
45318
45361
|
return /* @__PURE__ */ jsxs5(
|
|
45319
45362
|
CadViewerContainer,
|
|
45320
45363
|
{
|
|
@@ -45368,28 +45411,1149 @@ var CadViewerJscad = forwardRef3(
|
|
|
45368
45411
|
}
|
|
45369
45412
|
);
|
|
45370
45413
|
|
|
45414
|
+
// node_modules/earcut/src/earcut.js
|
|
45415
|
+
var steiners = /* @__PURE__ */ new Set();
|
|
45416
|
+
var filteredOut = false;
|
|
45417
|
+
function earcut(data, holeIndices, dim = 2) {
|
|
45418
|
+
const hasHoles = holeIndices && holeIndices.length;
|
|
45419
|
+
const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
|
|
45420
|
+
if (steiners.size) steiners.clear();
|
|
45421
|
+
let outerNode = linkedList(data, 0, outerLen, dim, true);
|
|
45422
|
+
const triangles = [];
|
|
45423
|
+
if (!outerNode || outerNode.next === outerNode.prev) return triangles;
|
|
45424
|
+
let minX = 0, minY = 0, invSize = 0;
|
|
45425
|
+
if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
|
|
45426
|
+
if (data.length > 80 * dim) {
|
|
45427
|
+
minX = data[0];
|
|
45428
|
+
minY = data[1];
|
|
45429
|
+
let maxX = minX;
|
|
45430
|
+
let maxY = minY;
|
|
45431
|
+
for (let i = dim; i < outerLen; i += dim) {
|
|
45432
|
+
const x = data[i];
|
|
45433
|
+
const y = data[i + 1];
|
|
45434
|
+
if (x < minX) minX = x;
|
|
45435
|
+
if (y < minY) minY = y;
|
|
45436
|
+
if (x > maxX) maxX = x;
|
|
45437
|
+
if (y > maxY) maxY = y;
|
|
45438
|
+
}
|
|
45439
|
+
invSize = Math.max(maxX - minX, maxY - minY);
|
|
45440
|
+
invSize = invSize !== 0 ? 32767 / invSize : 0;
|
|
45441
|
+
}
|
|
45442
|
+
earcutLinked(outerNode, triangles, minX, minY, invSize);
|
|
45443
|
+
return triangles;
|
|
45444
|
+
}
|
|
45445
|
+
function linkedList(data, start, end, dim, clockwise) {
|
|
45446
|
+
let last = null;
|
|
45447
|
+
if (clockwise === signedArea(data, start, end, dim) > 0) {
|
|
45448
|
+
for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
45449
|
+
} else {
|
|
45450
|
+
for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
45451
|
+
}
|
|
45452
|
+
if (last && equals(last, last.next)) {
|
|
45453
|
+
removeNode(last);
|
|
45454
|
+
last = last.next;
|
|
45455
|
+
}
|
|
45456
|
+
return last;
|
|
45457
|
+
}
|
|
45458
|
+
function filterPoints(start, end = start) {
|
|
45459
|
+
const full = end === start;
|
|
45460
|
+
let p = start, again;
|
|
45461
|
+
do {
|
|
45462
|
+
again = false;
|
|
45463
|
+
if (p !== p.next && (steiners.size === 0 || !steiners.has(p)) && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
|
|
45464
|
+
if (full || p === end) end = p.prev;
|
|
45465
|
+
filteredOut = true;
|
|
45466
|
+
removeNode(p);
|
|
45467
|
+
p = p.prev;
|
|
45468
|
+
again = true;
|
|
45469
|
+
} else if (full || p !== end) {
|
|
45470
|
+
p = p.next;
|
|
45471
|
+
again = !full;
|
|
45472
|
+
}
|
|
45473
|
+
} while (again || p !== end);
|
|
45474
|
+
return end;
|
|
45475
|
+
}
|
|
45476
|
+
function earcutLinked(ear, triangles, minX, minY, invSize) {
|
|
45477
|
+
if (invSize) indexCurve(ear, minX, minY, invSize);
|
|
45478
|
+
let stop = ear, cured = false;
|
|
45479
|
+
while (ear.prev !== ear.next) {
|
|
45480
|
+
const prev = ear.prev;
|
|
45481
|
+
const next = ear.next;
|
|
45482
|
+
if (area(prev, ear, next) < 0 && (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear))) {
|
|
45483
|
+
triangles.push(prev.i, ear.i, next.i);
|
|
45484
|
+
removeNode(ear);
|
|
45485
|
+
ear = next;
|
|
45486
|
+
stop = next;
|
|
45487
|
+
continue;
|
|
45488
|
+
}
|
|
45489
|
+
ear = next;
|
|
45490
|
+
if (ear === stop) {
|
|
45491
|
+
filteredOut = false;
|
|
45492
|
+
ear = filterPoints(ear);
|
|
45493
|
+
if (filteredOut) {
|
|
45494
|
+
stop = ear;
|
|
45495
|
+
continue;
|
|
45496
|
+
}
|
|
45497
|
+
if (!cured) {
|
|
45498
|
+
ear = cureLocalIntersections(ear, triangles);
|
|
45499
|
+
stop = ear;
|
|
45500
|
+
cured = true;
|
|
45501
|
+
continue;
|
|
45502
|
+
}
|
|
45503
|
+
splitEarcut(ear, triangles, minX, minY, invSize);
|
|
45504
|
+
break;
|
|
45505
|
+
}
|
|
45506
|
+
}
|
|
45507
|
+
}
|
|
45508
|
+
function isEar(ear) {
|
|
45509
|
+
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);
|
|
45510
|
+
let p = c.next;
|
|
45511
|
+
while (p !== a) {
|
|
45512
|
+
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;
|
|
45513
|
+
p = p.next;
|
|
45514
|
+
}
|
|
45515
|
+
return true;
|
|
45516
|
+
}
|
|
45517
|
+
function isEarHashed(ear, minX, minY, invSize) {
|
|
45518
|
+
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);
|
|
45519
|
+
let p = ear.prevZ;
|
|
45520
|
+
while (p && p.z >= minZ) {
|
|
45521
|
+
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;
|
|
45522
|
+
p = p.prevZ;
|
|
45523
|
+
}
|
|
45524
|
+
let n = ear.nextZ;
|
|
45525
|
+
while (n && n.z <= maxZ) {
|
|
45526
|
+
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;
|
|
45527
|
+
n = n.nextZ;
|
|
45528
|
+
}
|
|
45529
|
+
return true;
|
|
45530
|
+
}
|
|
45531
|
+
function cureLocalIntersections(start, triangles) {
|
|
45532
|
+
let p = start;
|
|
45533
|
+
let cured = false;
|
|
45534
|
+
do {
|
|
45535
|
+
const a = p.prev, b = p.next.next;
|
|
45536
|
+
if (intersects(a, p, p.next, b, false) && locallyInside(a, b) && locallyInside(b, a)) {
|
|
45537
|
+
triangles.push(a.i, p.i, b.i);
|
|
45538
|
+
removeNode(p);
|
|
45539
|
+
removeNode(p.next);
|
|
45540
|
+
p = start = b;
|
|
45541
|
+
cured = true;
|
|
45542
|
+
}
|
|
45543
|
+
p = p.next;
|
|
45544
|
+
} while (p !== start);
|
|
45545
|
+
return cured ? filterPoints(p) : p;
|
|
45546
|
+
}
|
|
45547
|
+
function splitEarcut(start, triangles, minX, minY, invSize) {
|
|
45548
|
+
let a = start;
|
|
45549
|
+
do {
|
|
45550
|
+
let b = a.next.next;
|
|
45551
|
+
while (b !== a.prev) {
|
|
45552
|
+
if (a.i !== b.i && isValidDiagonal(a, b)) {
|
|
45553
|
+
let c = splitPolygon(a, b);
|
|
45554
|
+
a = filterPoints(a, a.next);
|
|
45555
|
+
c = filterPoints(c, c.next);
|
|
45556
|
+
earcutLinked(a, triangles, minX, minY, invSize);
|
|
45557
|
+
earcutLinked(c, triangles, minX, minY, invSize);
|
|
45558
|
+
return;
|
|
45559
|
+
}
|
|
45560
|
+
b = b.next;
|
|
45561
|
+
}
|
|
45562
|
+
a = a.next;
|
|
45563
|
+
} while (a !== start);
|
|
45564
|
+
}
|
|
45565
|
+
var indexActive = false;
|
|
45566
|
+
function eliminateHoles(data, holeIndices, outerNode, dim) {
|
|
45567
|
+
const queue = [];
|
|
45568
|
+
for (let i = 0, len = holeIndices.length; i < len; i++) {
|
|
45569
|
+
const start = holeIndices[i] * dim;
|
|
45570
|
+
const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
45571
|
+
const list = (
|
|
45572
|
+
/** @type {Node} */
|
|
45573
|
+
linkedList(data, start, end, dim, false)
|
|
45574
|
+
);
|
|
45575
|
+
if (list === list.next) steiners.add(list);
|
|
45576
|
+
queue.push(getLeftmost(list));
|
|
45577
|
+
}
|
|
45578
|
+
queue.sort(compareXYSlope);
|
|
45579
|
+
buildBlockIndex(data.length / dim, holeIndices.length);
|
|
45580
|
+
indexSegment(outerNode, outerNode);
|
|
45581
|
+
indexActive = true;
|
|
45582
|
+
for (let i = 0; i < queue.length; i++) {
|
|
45583
|
+
outerNode = eliminateHole(queue[i], outerNode);
|
|
45584
|
+
}
|
|
45585
|
+
indexActive = false;
|
|
45586
|
+
return filterPoints(outerNode);
|
|
45587
|
+
}
|
|
45588
|
+
function compareXYSlope(a, b) {
|
|
45589
|
+
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);
|
|
45590
|
+
}
|
|
45591
|
+
function eliminateHole(hole, outerNode) {
|
|
45592
|
+
const bridge = findHoleBridge(hole, outerNode);
|
|
45593
|
+
if (!bridge) {
|
|
45594
|
+
return outerNode;
|
|
45595
|
+
}
|
|
45596
|
+
const bridgeReverse = splitPolygon(bridge, hole);
|
|
45597
|
+
const bridge2 = bridgeReverse.next;
|
|
45598
|
+
indexSegment(bridge, bridge2.next);
|
|
45599
|
+
filterPoints(bridgeReverse, bridgeReverse.next);
|
|
45600
|
+
return filterPoints(bridge, bridge.next);
|
|
45601
|
+
}
|
|
45602
|
+
var K = 16;
|
|
45603
|
+
var blockBBox = new Float64Array(0);
|
|
45604
|
+
var numBlocks = 0;
|
|
45605
|
+
var blockHead = [];
|
|
45606
|
+
var blockStop = [];
|
|
45607
|
+
function buildBlockIndex(maxNodes, numHoles) {
|
|
45608
|
+
const maxBlocks = Math.ceil((maxNodes + 2 * numHoles) / K) + numHoles + 2;
|
|
45609
|
+
if (blockBBox.length < maxBlocks * 4) blockBBox = new Float64Array(maxBlocks * 4);
|
|
45610
|
+
numBlocks = 0;
|
|
45611
|
+
}
|
|
45612
|
+
function indexSegment(head, stop) {
|
|
45613
|
+
let p = head;
|
|
45614
|
+
do {
|
|
45615
|
+
const b = numBlocks++;
|
|
45616
|
+
blockHead[b] = p;
|
|
45617
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
45618
|
+
let k = 0;
|
|
45619
|
+
do {
|
|
45620
|
+
const c = p.next;
|
|
45621
|
+
p.z = b;
|
|
45622
|
+
if (p.x < minX) minX = p.x;
|
|
45623
|
+
if (p.x > maxX) maxX = p.x;
|
|
45624
|
+
if (p.y < minY) minY = p.y;
|
|
45625
|
+
if (p.y > maxY) maxY = p.y;
|
|
45626
|
+
if (c.x < minX) minX = c.x;
|
|
45627
|
+
if (c.x > maxX) maxX = c.x;
|
|
45628
|
+
if (c.y < minY) minY = c.y;
|
|
45629
|
+
if (c.y > maxY) maxY = c.y;
|
|
45630
|
+
p = c;
|
|
45631
|
+
} while (++k < K && p !== stop);
|
|
45632
|
+
blockStop[b] = p;
|
|
45633
|
+
const g = b * 4;
|
|
45634
|
+
blockBBox[g] = minX;
|
|
45635
|
+
blockBBox[g + 1] = minY;
|
|
45636
|
+
blockBBox[g + 2] = maxX;
|
|
45637
|
+
blockBBox[g + 3] = maxY;
|
|
45638
|
+
} while (p !== stop);
|
|
45639
|
+
}
|
|
45640
|
+
function growBlock(head, tail) {
|
|
45641
|
+
const g = head.z * 4;
|
|
45642
|
+
if (tail.x < blockBBox[g]) blockBBox[g] = tail.x;
|
|
45643
|
+
if (tail.y < blockBBox[g + 1]) blockBBox[g + 1] = tail.y;
|
|
45644
|
+
if (tail.x > blockBBox[g + 2]) blockBBox[g + 2] = tail.x;
|
|
45645
|
+
if (tail.y > blockBBox[g + 3]) blockBBox[g + 3] = tail.y;
|
|
45646
|
+
}
|
|
45647
|
+
function liveBlockStop(b) {
|
|
45648
|
+
let stop = blockStop[b];
|
|
45649
|
+
while (stop.prev.next !== stop) stop = stop.next;
|
|
45650
|
+
blockStop[b] = stop;
|
|
45651
|
+
return stop;
|
|
45652
|
+
}
|
|
45653
|
+
function liveBlockHead(b) {
|
|
45654
|
+
let head = blockHead[b];
|
|
45655
|
+
while (head.prev.next !== head) head = head.next;
|
|
45656
|
+
blockHead[b] = head;
|
|
45657
|
+
return head;
|
|
45658
|
+
}
|
|
45659
|
+
function findHoleBridge(hole, outerNode) {
|
|
45660
|
+
let p = outerNode;
|
|
45661
|
+
const hx = hole.x;
|
|
45662
|
+
const hy = hole.y;
|
|
45663
|
+
let qx = -Infinity;
|
|
45664
|
+
let m;
|
|
45665
|
+
if (equals(hole, p)) return p;
|
|
45666
|
+
for (let b = 0, g = 0; b < numBlocks; b++, g += 4) {
|
|
45667
|
+
if (hy < blockBBox[g + 1] || hy > blockBBox[g + 3] || blockBBox[g] > hx || blockBBox[g + 2] <= qx) continue;
|
|
45668
|
+
const stop = liveBlockStop(b);
|
|
45669
|
+
p = liveBlockHead(b);
|
|
45670
|
+
do {
|
|
45671
|
+
if (p.prev.next === p) {
|
|
45672
|
+
if (equals(hole, p.next)) return p.next;
|
|
45673
|
+
else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
|
|
45674
|
+
const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
|
|
45675
|
+
if (x <= hx && x > qx) {
|
|
45676
|
+
qx = x;
|
|
45677
|
+
m = p.x < p.next.x ? p : p.next;
|
|
45678
|
+
if (x === hx) return m;
|
|
45679
|
+
}
|
|
45680
|
+
}
|
|
45681
|
+
}
|
|
45682
|
+
p = p.next;
|
|
45683
|
+
} while (p !== stop);
|
|
45684
|
+
}
|
|
45685
|
+
if (!m) return null;
|
|
45686
|
+
const mx = m.x;
|
|
45687
|
+
const my = m.y;
|
|
45688
|
+
const tminY = Math.min(hy, my);
|
|
45689
|
+
const tmaxY = Math.max(hy, my);
|
|
45690
|
+
let tanMin = Infinity;
|
|
45691
|
+
for (let b = 0, g = 0; b < numBlocks; b++, g += 4) {
|
|
45692
|
+
if (blockBBox[g + 2] < mx || blockBBox[g] > hx || blockBBox[g + 3] < tminY || blockBBox[g + 1] > tmaxY) continue;
|
|
45693
|
+
const stop = liveBlockStop(b);
|
|
45694
|
+
p = liveBlockHead(b);
|
|
45695
|
+
do {
|
|
45696
|
+
if (p.prev.next === p && hx >= p.x && p.x >= mx && hx !== p.x && // skip dead nodes
|
|
45697
|
+
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
|
|
45698
|
+
const tan = Math.abs(hy - p.y) / (hx - p.x);
|
|
45699
|
+
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)))) {
|
|
45700
|
+
m = p;
|
|
45701
|
+
tanMin = tan;
|
|
45702
|
+
}
|
|
45703
|
+
}
|
|
45704
|
+
p = p.next;
|
|
45705
|
+
} while (p !== stop);
|
|
45706
|
+
}
|
|
45707
|
+
return m;
|
|
45708
|
+
}
|
|
45709
|
+
function sectorContainsSector(m, p) {
|
|
45710
|
+
return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
|
|
45711
|
+
}
|
|
45712
|
+
var sortArr = [];
|
|
45713
|
+
var sortBuf = [];
|
|
45714
|
+
var zArr = new Uint32Array(0);
|
|
45715
|
+
var zBuf = new Uint32Array(0);
|
|
45716
|
+
var counts = new Uint32Array(256);
|
|
45717
|
+
function indexCurve(start, minX, minY, invSize) {
|
|
45718
|
+
let p = start;
|
|
45719
|
+
let n = 0;
|
|
45720
|
+
do {
|
|
45721
|
+
p.z = zOrder(p.x, p.y, minX, minY, invSize);
|
|
45722
|
+
sortArr[n++] = p;
|
|
45723
|
+
p = p.next;
|
|
45724
|
+
} while (p !== start);
|
|
45725
|
+
sortNodes(n);
|
|
45726
|
+
let prev = null;
|
|
45727
|
+
for (let i = 0; i < n; i++) {
|
|
45728
|
+
const node = sortArr[i];
|
|
45729
|
+
node.prevZ = prev;
|
|
45730
|
+
if (prev) prev.nextZ = node;
|
|
45731
|
+
prev = node;
|
|
45732
|
+
}
|
|
45733
|
+
prev.nextZ = null;
|
|
45734
|
+
}
|
|
45735
|
+
function sortNodes(n) {
|
|
45736
|
+
if (n <= 32) {
|
|
45737
|
+
for (let i = 1; i < n; i++) {
|
|
45738
|
+
const node = sortArr[i], z42 = node.z;
|
|
45739
|
+
let j = i - 1;
|
|
45740
|
+
while (j >= 0 && sortArr[j].z > z42) {
|
|
45741
|
+
sortArr[j + 1] = sortArr[j];
|
|
45742
|
+
j--;
|
|
45743
|
+
}
|
|
45744
|
+
sortArr[j + 1] = node;
|
|
45745
|
+
}
|
|
45746
|
+
return;
|
|
45747
|
+
}
|
|
45748
|
+
if (zArr.length < n) {
|
|
45749
|
+
zArr = new Uint32Array(n);
|
|
45750
|
+
zBuf = new Uint32Array(n);
|
|
45751
|
+
sortBuf = new Array(n);
|
|
45752
|
+
}
|
|
45753
|
+
for (let i = 0; i < n; i++) zArr[i] = sortArr[i].z;
|
|
45754
|
+
radixPass(n, sortArr, zArr, sortBuf, zBuf, 0);
|
|
45755
|
+
radixPass(n, sortBuf, zBuf, sortArr, zArr, 8);
|
|
45756
|
+
radixPass(n, sortArr, zArr, sortBuf, zBuf, 16);
|
|
45757
|
+
radixPass(n, sortBuf, zBuf, sortArr, zArr, 24);
|
|
45758
|
+
}
|
|
45759
|
+
function radixPass(n, src, srcZ, dst, dstZ, shift4) {
|
|
45760
|
+
counts.fill(0);
|
|
45761
|
+
for (let i = 0; i < n; i++) counts[srcZ[i] >>> shift4 & 255]++;
|
|
45762
|
+
let sum = 0;
|
|
45763
|
+
for (let b = 0; b < 256; b++) {
|
|
45764
|
+
const c = counts[b];
|
|
45765
|
+
counts[b] = sum;
|
|
45766
|
+
sum += c;
|
|
45767
|
+
}
|
|
45768
|
+
for (let i = 0; i < n; i++) {
|
|
45769
|
+
const z42 = srcZ[i];
|
|
45770
|
+
const pos = counts[z42 >>> shift4 & 255]++;
|
|
45771
|
+
dst[pos] = src[i];
|
|
45772
|
+
dstZ[pos] = z42;
|
|
45773
|
+
}
|
|
45774
|
+
}
|
|
45775
|
+
function zOrder(x, y, minX, minY, invSize) {
|
|
45776
|
+
x = (x - minX) * invSize | 0;
|
|
45777
|
+
y = (y - minY) * invSize | 0;
|
|
45778
|
+
x = (x | x << 8) & 16711935;
|
|
45779
|
+
x = (x | x << 4) & 252645135;
|
|
45780
|
+
x = (x | x << 2) & 858993459;
|
|
45781
|
+
x = (x | x << 1) & 1431655765;
|
|
45782
|
+
y = (y | y << 8) & 16711935;
|
|
45783
|
+
y = (y | y << 4) & 252645135;
|
|
45784
|
+
y = (y | y << 2) & 858993459;
|
|
45785
|
+
y = (y | y << 1) & 1431655765;
|
|
45786
|
+
return x | y << 1;
|
|
45787
|
+
}
|
|
45788
|
+
function getLeftmost(start) {
|
|
45789
|
+
let p = start, leftmost = start;
|
|
45790
|
+
do {
|
|
45791
|
+
if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y) leftmost = p;
|
|
45792
|
+
p = p.next;
|
|
45793
|
+
} while (p !== start);
|
|
45794
|
+
return leftmost;
|
|
45795
|
+
}
|
|
45796
|
+
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
|
|
45797
|
+
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);
|
|
45798
|
+
}
|
|
45799
|
+
function isValidDiagonal(a, b) {
|
|
45800
|
+
const zeroLength = equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0;
|
|
45801
|
+
return a.next.i !== b.i && (zeroLength || locallyInside(a, b) && locallyInside(b, a) && // // locally visible
|
|
45802
|
+
(area(a.prev, a, b.prev) !== 0 || area(a, b.prev, b) !== 0)) && // no opposite-facing sectors
|
|
45803
|
+
!intersectsPolygon(a, b) && (zeroLength || middleInside(a, b));
|
|
45804
|
+
}
|
|
45805
|
+
function area(p, q, r) {
|
|
45806
|
+
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
45807
|
+
}
|
|
45808
|
+
function equals(p1, p2) {
|
|
45809
|
+
return p1.x === p2.x && p1.y === p2.y;
|
|
45810
|
+
}
|
|
45811
|
+
function intersects(p1, q1, p2, q2, includeBoundary = true) {
|
|
45812
|
+
const o1 = area(p1, q1, p2);
|
|
45813
|
+
const o2 = area(p1, q1, q2);
|
|
45814
|
+
const o3 = area(p2, q2, p1);
|
|
45815
|
+
const o4 = area(p2, q2, q1);
|
|
45816
|
+
if ((o1 > 0 && o2 < 0 || o1 < 0 && o2 > 0) && (o3 > 0 && o4 < 0 || o3 < 0 && o4 > 0)) return true;
|
|
45817
|
+
if (!includeBoundary) return false;
|
|
45818
|
+
if (o1 === 0 && onSegment2(p1, p2, q1)) return true;
|
|
45819
|
+
if (o2 === 0 && onSegment2(p1, q2, q1)) return true;
|
|
45820
|
+
if (o3 === 0 && onSegment2(p2, p1, q2)) return true;
|
|
45821
|
+
if (o4 === 0 && onSegment2(p2, q1, q2)) return true;
|
|
45822
|
+
return false;
|
|
45823
|
+
}
|
|
45824
|
+
function onSegment2(p, q, r) {
|
|
45825
|
+
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);
|
|
45826
|
+
}
|
|
45827
|
+
function intersectsPolygon(a, b) {
|
|
45828
|
+
const minX = Math.min(a.x, b.x);
|
|
45829
|
+
const maxX = Math.max(a.x, b.x);
|
|
45830
|
+
const minY = Math.min(a.y, b.y);
|
|
45831
|
+
const maxY = Math.max(a.y, b.y);
|
|
45832
|
+
let p = a;
|
|
45833
|
+
do {
|
|
45834
|
+
const n = p.next;
|
|
45835
|
+
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) {
|
|
45836
|
+
p = n;
|
|
45837
|
+
continue;
|
|
45838
|
+
}
|
|
45839
|
+
if (p.i !== a.i && n.i !== a.i && p.i !== b.i && n.i !== b.i && intersects(p, n, a, b)) return true;
|
|
45840
|
+
p = n;
|
|
45841
|
+
} while (p !== a);
|
|
45842
|
+
return false;
|
|
45843
|
+
}
|
|
45844
|
+
function locallyInside(a, b) {
|
|
45845
|
+
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;
|
|
45846
|
+
}
|
|
45847
|
+
function middleInside(a, b) {
|
|
45848
|
+
let p = a;
|
|
45849
|
+
let inside = false;
|
|
45850
|
+
const px = (a.x + b.x) / 2;
|
|
45851
|
+
const py = (a.y + b.y) / 2;
|
|
45852
|
+
do {
|
|
45853
|
+
const n = p.next;
|
|
45854
|
+
if (p.y > py !== n.y > py && px < (n.x - p.x) * (py - p.y) / (n.y - p.y) + p.x)
|
|
45855
|
+
inside = !inside;
|
|
45856
|
+
p = n;
|
|
45857
|
+
} while (p !== a);
|
|
45858
|
+
return inside;
|
|
45859
|
+
}
|
|
45860
|
+
function splitPolygon(a, b) {
|
|
45861
|
+
const a2 = createNode(a.i, a.x, a.y), b2 = createNode(b.i, b.x, b.y), an = a.next, bp = b.prev;
|
|
45862
|
+
a.next = b;
|
|
45863
|
+
b.prev = a;
|
|
45864
|
+
a2.next = an;
|
|
45865
|
+
an.prev = a2;
|
|
45866
|
+
b2.next = a2;
|
|
45867
|
+
a2.prev = b2;
|
|
45868
|
+
bp.next = b2;
|
|
45869
|
+
b2.prev = bp;
|
|
45870
|
+
return b2;
|
|
45871
|
+
}
|
|
45872
|
+
function insertNode(i, x, y, last) {
|
|
45873
|
+
const p = createNode(i, x, y);
|
|
45874
|
+
if (!last) {
|
|
45875
|
+
p.prev = p;
|
|
45876
|
+
p.next = p;
|
|
45877
|
+
} else {
|
|
45878
|
+
p.next = last.next;
|
|
45879
|
+
p.prev = last;
|
|
45880
|
+
last.next.prev = p;
|
|
45881
|
+
last.next = p;
|
|
45882
|
+
}
|
|
45883
|
+
return p;
|
|
45884
|
+
}
|
|
45885
|
+
function removeNode(p) {
|
|
45886
|
+
p.next.prev = p.prev;
|
|
45887
|
+
p.prev.next = p.next;
|
|
45888
|
+
if (p.prevZ) p.prevZ.nextZ = p.nextZ;
|
|
45889
|
+
if (p.nextZ) p.nextZ.prevZ = p.prevZ;
|
|
45890
|
+
if (indexActive) growBlock(p.prev, p.next);
|
|
45891
|
+
}
|
|
45892
|
+
function createNode(i, x, y) {
|
|
45893
|
+
return (
|
|
45894
|
+
/** @type {Node} */
|
|
45895
|
+
/** @type {unknown} */
|
|
45896
|
+
{
|
|
45897
|
+
i,
|
|
45898
|
+
// vertex index in coordinates array
|
|
45899
|
+
x,
|
|
45900
|
+
y,
|
|
45901
|
+
// vertex coordinates
|
|
45902
|
+
prev: null,
|
|
45903
|
+
// previous and next vertex nodes in a polygon ring
|
|
45904
|
+
next: null,
|
|
45905
|
+
z: 0,
|
|
45906
|
+
// z-order curve value; doubles as owning block in the hole-bridge index during eliminateHoles
|
|
45907
|
+
prevZ: null,
|
|
45908
|
+
// previous and next nodes in z-order
|
|
45909
|
+
nextZ: null
|
|
45910
|
+
}
|
|
45911
|
+
);
|
|
45912
|
+
}
|
|
45913
|
+
function signedArea(data, start, end, dim) {
|
|
45914
|
+
let sum = 0;
|
|
45915
|
+
for (let i = start, j = end - dim; i < end; i += dim) {
|
|
45916
|
+
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
|
|
45917
|
+
j = i;
|
|
45918
|
+
}
|
|
45919
|
+
return sum;
|
|
45920
|
+
}
|
|
45921
|
+
|
|
45922
|
+
// node_modules/@tscircuit/flex-utils/dist/index.js
|
|
45923
|
+
var EPS = 1e-7;
|
|
45924
|
+
function createPcbFold(records, thickness) {
|
|
45925
|
+
if (!Number.isFinite(thickness) || thickness < 0)
|
|
45926
|
+
throw new Error("Board thickness must be finite and nonnegative");
|
|
45927
|
+
const bends = records.map((b) => {
|
|
45928
|
+
const { start, end, bend_angle: degrees, bend_radius: radius } = b;
|
|
45929
|
+
const values = [start?.x, start?.y, end?.x, end?.y, degrees, radius];
|
|
45930
|
+
if (values.some((v) => !Number.isFinite(v)) || radius <= thickness / 2 || !["left", "right"].includes(b.bend_side)) {
|
|
45931
|
+
throw new Error(
|
|
45932
|
+
`Invalid PCB bend ${b.pcb_bend_id}: finite geometry and radius greater than half the board thickness are required`
|
|
45933
|
+
);
|
|
45934
|
+
}
|
|
45935
|
+
const length83 = Math.hypot(end.x - start.x, end.y - start.y);
|
|
45936
|
+
if (length83 < EPS || Math.abs(degrees) > 180)
|
|
45937
|
+
throw new Error(
|
|
45938
|
+
`Unsupported PCB bend ${b.pcb_bend_id}: distinct endpoints and angles within \xB1180 degrees are required`
|
|
45939
|
+
);
|
|
45940
|
+
const sign = b.bend_side === "right" ? 1 : -1;
|
|
45941
|
+
const nx = sign * (end.y - start.y) / length83;
|
|
45942
|
+
const ny = -sign * (end.x - start.x) / length83;
|
|
45943
|
+
const angle = degrees * Math.PI / 180;
|
|
45944
|
+
const width10 = radius * Math.abs(angle);
|
|
45945
|
+
const center = start.x * nx + start.y * ny;
|
|
45946
|
+
return {
|
|
45947
|
+
id: b.pcb_bend_id,
|
|
45948
|
+
nx,
|
|
45949
|
+
ny,
|
|
45950
|
+
start: center - width10 / 2,
|
|
45951
|
+
end: center + width10 / 2,
|
|
45952
|
+
angle,
|
|
45953
|
+
radius,
|
|
45954
|
+
axisMin: Math.min(
|
|
45955
|
+
-ny * start.x + nx * start.y,
|
|
45956
|
+
-ny * end.x + nx * end.y
|
|
45957
|
+
),
|
|
45958
|
+
axisMax: Math.max(
|
|
45959
|
+
-ny * start.x + nx * start.y,
|
|
45960
|
+
-ny * end.x + nx * end.y
|
|
45961
|
+
)
|
|
45962
|
+
};
|
|
45963
|
+
}).filter((b) => Math.abs(b.angle) > EPS);
|
|
45964
|
+
const first = bends[0];
|
|
45965
|
+
if (first && bends.some(
|
|
45966
|
+
(b) => Math.abs(b.nx - first.nx) > EPS || Math.abs(b.ny - first.ny) > EPS
|
|
45967
|
+
)) {
|
|
45968
|
+
throw new Error(
|
|
45969
|
+
"Folded PCB rendering currently requires parallel bends with the same moving direction"
|
|
45970
|
+
);
|
|
45971
|
+
}
|
|
45972
|
+
bends.sort((a, b) => a.start - b.start);
|
|
45973
|
+
for (let i = 1; i < bends.length; i++) {
|
|
45974
|
+
if (bends[i].start < bends[i - 1].end - EPS)
|
|
45975
|
+
throw new Error("Overlapping PCB bend zones are not supported");
|
|
45976
|
+
}
|
|
45977
|
+
const distalFirst = [...bends].reverse();
|
|
45978
|
+
const transform = ({
|
|
45979
|
+
p,
|
|
45980
|
+
anchor,
|
|
45981
|
+
direction
|
|
45982
|
+
}) => {
|
|
45983
|
+
let result = { ...p };
|
|
45984
|
+
for (const b of distalFirst) {
|
|
45985
|
+
const width10 = b.end - b.start;
|
|
45986
|
+
const s = anchor.x * b.nx + anchor.y * b.ny - b.start;
|
|
45987
|
+
const q = Math.max(0, Math.min(width10, s));
|
|
45988
|
+
const theta = b.angle * q / width10;
|
|
45989
|
+
const cos = Math.cos(theta), sin = Math.sin(theta);
|
|
45990
|
+
const projected = result.x * b.nx + result.y * b.ny - (direction ? 0 : b.start);
|
|
45991
|
+
const tangentX = result.x - (projected + (direction ? 0 : b.start)) * b.nx;
|
|
45992
|
+
const tangentY = result.y - (projected + (direction ? 0 : b.start)) * b.ny;
|
|
45993
|
+
const signedRadius = Math.sign(b.angle) * b.radius;
|
|
45994
|
+
const tx = direction ? 0 : signedRadius * sin - q * cos;
|
|
45995
|
+
const tz = direction ? 0 : signedRadius * (1 - cos) - q * sin;
|
|
45996
|
+
const folded = projected * cos - result.z * sin + tx;
|
|
45997
|
+
result = {
|
|
45998
|
+
x: tangentX + (folded + (direction ? 0 : b.start)) * b.nx,
|
|
45999
|
+
y: tangentY + (folded + (direction ? 0 : b.start)) * b.ny,
|
|
46000
|
+
z: projected * sin + result.z * cos + tz
|
|
46001
|
+
};
|
|
46002
|
+
}
|
|
46003
|
+
return result;
|
|
46004
|
+
};
|
|
46005
|
+
const inverse = ({
|
|
46006
|
+
p,
|
|
46007
|
+
anchor,
|
|
46008
|
+
direction
|
|
46009
|
+
}) => {
|
|
46010
|
+
const origin = direction ? { x: 0, y: 0, z: 0 } : transform({
|
|
46011
|
+
p: { x: 0, y: 0, z: 0 },
|
|
46012
|
+
anchor,
|
|
46013
|
+
direction: false
|
|
46014
|
+
});
|
|
46015
|
+
const d = { x: p.x - origin.x, y: p.y - origin.y, z: p.z - origin.z };
|
|
46016
|
+
const axes2 = [
|
|
46017
|
+
{ x: 1, y: 0, z: 0 },
|
|
46018
|
+
{ x: 0, y: 1, z: 0 },
|
|
46019
|
+
{ x: 0, y: 0, z: 1 }
|
|
46020
|
+
].map((v) => transform({ p: v, anchor, direction: true }));
|
|
46021
|
+
const dot = (v) => v.x * d.x + v.y * d.y + v.z * d.z;
|
|
46022
|
+
return { x: dot(axes2[0]), y: dot(axes2[1]), z: dot(axes2[2]) };
|
|
46023
|
+
};
|
|
46024
|
+
return {
|
|
46025
|
+
bends,
|
|
46026
|
+
inversePoint: (p, anchor) => inverse({ p, anchor, direction: false }),
|
|
46027
|
+
inverseDirection: (p, anchor) => inverse({ p, anchor, direction: true }),
|
|
46028
|
+
point: (p, anchor = p) => transform({ p, anchor, direction: false }),
|
|
46029
|
+
direction: (p, anchor) => transform({ p, anchor, direction: true }),
|
|
46030
|
+
assertRigid(points, label) {
|
|
46031
|
+
for (const b of bends) {
|
|
46032
|
+
const ds = points.map((p) => p.x * b.nx + p.y * b.ny);
|
|
46033
|
+
if (Math.max(...ds) > b.start + EPS && Math.min(...ds) < b.end - EPS)
|
|
46034
|
+
throw new Error(`${label} intersects PCB bend zone ${b.id}`);
|
|
46035
|
+
}
|
|
46036
|
+
}
|
|
46037
|
+
};
|
|
46038
|
+
}
|
|
46039
|
+
var EPS2 = 1e-7;
|
|
46040
|
+
function boundsOfTriangles(triangles) {
|
|
46041
|
+
const points = triangles.flatMap((t) => t.vertices);
|
|
46042
|
+
if (!points.length)
|
|
46043
|
+
return { min: { x: 0, y: 0, z: 0 }, max: { x: 0, y: 0, z: 0 } };
|
|
46044
|
+
const min2 = { x: Infinity, y: Infinity, z: Infinity };
|
|
46045
|
+
const max2 = { x: -Infinity, y: -Infinity, z: -Infinity };
|
|
46046
|
+
for (const p of points)
|
|
46047
|
+
for (const key of ["x", "y", "z"]) {
|
|
46048
|
+
min2[key] = Math.min(min2[key], p[key]);
|
|
46049
|
+
max2[key] = Math.max(max2[key], p[key]);
|
|
46050
|
+
}
|
|
46051
|
+
return { min: min2, max: max2 };
|
|
46052
|
+
}
|
|
46053
|
+
function foldSurfaceMesh(mesh, fold) {
|
|
46054
|
+
const planes = fold.bends.flatMap((b) => {
|
|
46055
|
+
const steps = Math.ceil(Math.abs(b.angle) / (Math.PI / 36));
|
|
46056
|
+
return Array.from({ length: steps + 1 }, (_, i) => ({
|
|
46057
|
+
b,
|
|
46058
|
+
d: b.start + (b.end - b.start) * i / steps
|
|
46059
|
+
}));
|
|
46060
|
+
});
|
|
46061
|
+
const { min: min2, max: max2 } = mesh.boundingBox;
|
|
46062
|
+
const split = ({
|
|
46063
|
+
polygon: polygon2,
|
|
46064
|
+
nx,
|
|
46065
|
+
ny,
|
|
46066
|
+
d
|
|
46067
|
+
}) => {
|
|
46068
|
+
const distances = polygon2.map(({ p }) => nx * p.x + ny * p.y - d);
|
|
46069
|
+
if (Math.min(...distances) >= -EPS2 || Math.max(...distances) <= EPS2)
|
|
46070
|
+
return [polygon2];
|
|
46071
|
+
const halves = [[], []];
|
|
46072
|
+
for (let side = 0; side < 2; side++) {
|
|
46073
|
+
const sign = side === 0 ? 1 : -1;
|
|
46074
|
+
for (let i = 0; i < polygon2.length; i++) {
|
|
46075
|
+
const a = polygon2[i], next = (i + 1) % polygon2.length, b = polygon2[next];
|
|
46076
|
+
const da = distances[i] * sign, db = distances[next] * sign;
|
|
46077
|
+
if (da >= -EPS2) halves[side].push(a);
|
|
46078
|
+
if (da > EPS2 && db < -EPS2 || da < -EPS2 && db > EPS2) {
|
|
46079
|
+
const t = da / (da - db);
|
|
46080
|
+
halves[side].push({
|
|
46081
|
+
p: {
|
|
46082
|
+
x: a.p.x + (b.p.x - a.p.x) * t,
|
|
46083
|
+
y: a.p.y + (b.p.y - a.p.y) * t,
|
|
46084
|
+
z: a.p.z + (b.p.z - a.p.z) * t
|
|
46085
|
+
},
|
|
46086
|
+
uv: {
|
|
46087
|
+
u: a.uv.u + (b.uv.u - a.uv.u) * t,
|
|
46088
|
+
v: a.uv.v + (b.uv.v - a.uv.v) * t
|
|
46089
|
+
}
|
|
46090
|
+
});
|
|
46091
|
+
}
|
|
46092
|
+
}
|
|
46093
|
+
}
|
|
46094
|
+
return halves.filter((p) => p.length >= 3);
|
|
46095
|
+
};
|
|
46096
|
+
const triangles = [];
|
|
46097
|
+
for (const triangle of mesh.triangles) {
|
|
46098
|
+
const face = triangle.pcbFace ?? (triangle.normal.z > 0.8 ? "top" : triangle.normal.z < -0.8 ? "bottom" : "side");
|
|
46099
|
+
let polygons = [
|
|
46100
|
+
triangle.vertices.map((p, index2) => ({
|
|
46101
|
+
p,
|
|
46102
|
+
uv: triangle.uvs?.[index2] ?? {
|
|
46103
|
+
u: (p.x - min2.x) / (max2.x - min2.x),
|
|
46104
|
+
v: 1 - (p.y - min2.y) / (max2.y - min2.y)
|
|
46105
|
+
}
|
|
46106
|
+
}))
|
|
46107
|
+
];
|
|
46108
|
+
for (const { b, d } of planes)
|
|
46109
|
+
polygons = polygons.flatMap(
|
|
46110
|
+
(p) => split({ polygon: p, nx: b.nx, ny: b.ny, d })
|
|
46111
|
+
);
|
|
46112
|
+
for (const polygon2 of polygons) {
|
|
46113
|
+
for (const b of fold.bends) {
|
|
46114
|
+
const mid = polygon2.reduce((sum, { p }) => sum + p.x * b.nx + p.y * b.ny, 0) / polygon2.length;
|
|
46115
|
+
if (mid > b.start + EPS2 && mid < b.end - EPS2 && polygon2.some(({ p }) => {
|
|
46116
|
+
const along = -b.ny * p.x + b.nx * p.y;
|
|
46117
|
+
return along < b.axisMin - EPS2 || along > b.axisMax + EPS2;
|
|
46118
|
+
}))
|
|
46119
|
+
throw new Error(
|
|
46120
|
+
`PCB bend ${b.id} must span the full board cross-section through its bend zone`
|
|
46121
|
+
);
|
|
46122
|
+
}
|
|
46123
|
+
for (let i = 1; i + 1 < polygon2.length; i++) {
|
|
46124
|
+
const verts = [polygon2[0], polygon2[i], polygon2[i + 1]];
|
|
46125
|
+
const vertices = verts.map(
|
|
46126
|
+
({ p }) => fold.point(p)
|
|
46127
|
+
);
|
|
46128
|
+
const [a, b, c] = vertices;
|
|
46129
|
+
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 };
|
|
46130
|
+
const n = {
|
|
46131
|
+
x: u.y * v.z - u.z * v.y,
|
|
46132
|
+
y: u.z * v.x - u.x * v.z,
|
|
46133
|
+
z: u.x * v.y - u.y * v.x
|
|
46134
|
+
};
|
|
46135
|
+
const l = Math.hypot(n.x, n.y, n.z);
|
|
46136
|
+
if (l < 1e-12) continue;
|
|
46137
|
+
triangles.push({
|
|
46138
|
+
...triangle,
|
|
46139
|
+
vertices,
|
|
46140
|
+
normal: { x: n.x / l, y: n.y / l, z: n.z / l },
|
|
46141
|
+
pcbFace: face,
|
|
46142
|
+
uvs: verts.map(({ uv }) => uv)
|
|
46143
|
+
});
|
|
46144
|
+
}
|
|
46145
|
+
}
|
|
46146
|
+
}
|
|
46147
|
+
return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46148
|
+
}
|
|
46149
|
+
var axes = [
|
|
46150
|
+
{ x: 1, y: 0, z: 0 },
|
|
46151
|
+
{ x: 0, y: 1, z: 0 },
|
|
46152
|
+
{ x: 0, y: 0, z: 1 }
|
|
46153
|
+
];
|
|
46154
|
+
function rotateVector(v, degrees) {
|
|
46155
|
+
const [x, y, z42] = [degrees.x, degrees.y, degrees.z].map(
|
|
46156
|
+
(a2) => a2 * Math.PI / 180
|
|
46157
|
+
);
|
|
46158
|
+
const a = {
|
|
46159
|
+
x: Math.cos(z42) * v.x - Math.sin(z42) * v.y,
|
|
46160
|
+
y: Math.sin(z42) * v.x + Math.cos(z42) * v.y,
|
|
46161
|
+
z: v.z
|
|
46162
|
+
};
|
|
46163
|
+
const b = {
|
|
46164
|
+
x: Math.cos(y) * a.x + Math.sin(y) * a.z,
|
|
46165
|
+
y: a.y,
|
|
46166
|
+
z: -Math.sin(y) * a.x + Math.cos(y) * a.z
|
|
46167
|
+
};
|
|
46168
|
+
return {
|
|
46169
|
+
x: b.x,
|
|
46170
|
+
y: Math.cos(x) * b.y - Math.sin(x) * b.z,
|
|
46171
|
+
z: Math.sin(x) * b.y + Math.cos(x) * b.z
|
|
46172
|
+
};
|
|
46173
|
+
}
|
|
46174
|
+
function rotationFromAxes([a, b, c]) {
|
|
46175
|
+
const y = Math.asin(Math.max(-1, Math.min(1, c.x)));
|
|
46176
|
+
const regular = Math.abs(c.x) < 1 - 1e-12;
|
|
46177
|
+
return {
|
|
46178
|
+
x: (regular ? Math.atan2(-c.y, c.z) : Math.atan2(b.z, b.y)) * 180 / Math.PI,
|
|
46179
|
+
y: y * 180 / Math.PI,
|
|
46180
|
+
z: (regular ? Math.atan2(-b.x, a.x) : 0) * 180 / Math.PI
|
|
46181
|
+
};
|
|
46182
|
+
}
|
|
46183
|
+
function transformCadComponent({ cadComponent, foldPcbs }, context) {
|
|
46184
|
+
return transformCadComponentPlacement(
|
|
46185
|
+
{ cadComponentPlacement: cadComponent, foldPcbs },
|
|
46186
|
+
context
|
|
46187
|
+
);
|
|
46188
|
+
}
|
|
46189
|
+
function transformCadComponentPlacement({
|
|
46190
|
+
cadComponentPlacement,
|
|
46191
|
+
foldPcbs
|
|
46192
|
+
}, context) {
|
|
46193
|
+
if (cadComponentPlacement.is_on_folded_board === true === foldPcbs)
|
|
46194
|
+
return cadComponentPlacement;
|
|
46195
|
+
const { fold, boardCenter, flatMount } = context;
|
|
46196
|
+
const anchor = {
|
|
46197
|
+
x: flatMount.x - boardCenter.x,
|
|
46198
|
+
y: flatMount.y - boardCenter.y,
|
|
46199
|
+
z: 0
|
|
46200
|
+
};
|
|
46201
|
+
fold.assertRigid([anchor], "CAD mount");
|
|
46202
|
+
const point = {
|
|
46203
|
+
x: cadComponentPlacement.position.x - boardCenter.x,
|
|
46204
|
+
y: cadComponentPlacement.position.y - boardCenter.y,
|
|
46205
|
+
z: cadComponentPlacement.position.z
|
|
46206
|
+
};
|
|
46207
|
+
const direction = foldPcbs ? fold.direction : fold.inverseDirection;
|
|
46208
|
+
const transformed = foldPcbs ? fold.point(point, anchor) : fold.inversePoint(point, anchor);
|
|
46209
|
+
const rotation = cadComponentPlacement.rotation ?? context.defaultRotation ?? { x: 0, y: 0, z: 0 };
|
|
46210
|
+
const basis = axes.map((v) => direction(rotateVector(v, rotation), anchor));
|
|
46211
|
+
return {
|
|
46212
|
+
...cadComponentPlacement,
|
|
46213
|
+
position: {
|
|
46214
|
+
x: transformed.x + boardCenter.x,
|
|
46215
|
+
y: transformed.y + boardCenter.y,
|
|
46216
|
+
z: transformed.z
|
|
46217
|
+
},
|
|
46218
|
+
rotation: rotationFromAxes(basis),
|
|
46219
|
+
is_on_folded_board: foldPcbs
|
|
46220
|
+
};
|
|
46221
|
+
}
|
|
46222
|
+
function getCadFoldContext(cadComponent, json) {
|
|
46223
|
+
const pcb = json.find(
|
|
46224
|
+
(e) => e.type === "pcb_component" && e.pcb_component_id === cadComponent.pcb_component_id
|
|
46225
|
+
);
|
|
46226
|
+
if (pcb?.type !== "pcb_component") {
|
|
46227
|
+
if (cadComponent.is_on_folded_board)
|
|
46228
|
+
throw new Error(
|
|
46229
|
+
`Folded CAD ${cadComponent.cad_component_id} requires its flat pcb_component reference`
|
|
46230
|
+
);
|
|
46231
|
+
return void 0;
|
|
46232
|
+
}
|
|
46233
|
+
const boards = json.filter((e) => e.type === "pcb_board");
|
|
46234
|
+
const explicit = pcb.positioned_relative_to_pcb_board_id;
|
|
46235
|
+
const matching = explicit ? boards.filter((b) => b.pcb_board_id === explicit) : boards.filter(
|
|
46236
|
+
(b) => b.subcircuit_id && b.subcircuit_id === pcb.subcircuit_id
|
|
46237
|
+
);
|
|
46238
|
+
const board = matching.length === 1 ? matching[0] : !explicit && !matching.length && boards.length === 1 ? boards[0] : void 0;
|
|
46239
|
+
if (!board)
|
|
46240
|
+
throw new Error(
|
|
46241
|
+
`Cannot unambiguously resolve board for CAD ${cadComponent.cad_component_id}`
|
|
46242
|
+
);
|
|
46243
|
+
const bends = json.filter(
|
|
46244
|
+
(e) => e.type === "pcb_bend" && e.pcb_board_id === board.pcb_board_id
|
|
46245
|
+
);
|
|
46246
|
+
return {
|
|
46247
|
+
fold: createPcbFold(bends, board.thickness ?? 1.6),
|
|
46248
|
+
boardCenter: board.center,
|
|
46249
|
+
flatMount: pcb.center,
|
|
46250
|
+
defaultRotation: {
|
|
46251
|
+
x: (cadComponent.layer ?? pcb.layer) === "bottom" ? 180 : 0,
|
|
46252
|
+
y: 0,
|
|
46253
|
+
z: 0
|
|
46254
|
+
}
|
|
46255
|
+
};
|
|
46256
|
+
}
|
|
46257
|
+
function transformCircuitJsonCadComponents(json, options) {
|
|
46258
|
+
const hasBends = json.some((element) => element.type === "pcb_bend");
|
|
46259
|
+
return json.map((element) => {
|
|
46260
|
+
if (element.type !== "cad_component") return element;
|
|
46261
|
+
const cadComponent = element;
|
|
46262
|
+
if (!hasBends && !cadComponent.is_on_folded_board) return element;
|
|
46263
|
+
if (cadComponent.is_on_folded_board === true === options.foldPcbs)
|
|
46264
|
+
return element;
|
|
46265
|
+
const context = getCadFoldContext(cadComponent, json);
|
|
46266
|
+
if (!context || !context.fold.bends.length && !cadComponent.is_on_folded_board)
|
|
46267
|
+
return element;
|
|
46268
|
+
return transformCadComponent(
|
|
46269
|
+
{ cadComponent, foldPcbs: options.foldPcbs },
|
|
46270
|
+
context
|
|
46271
|
+
);
|
|
46272
|
+
});
|
|
46273
|
+
}
|
|
46274
|
+
function extrudePolygon({
|
|
46275
|
+
outline,
|
|
46276
|
+
bottom,
|
|
46277
|
+
top
|
|
46278
|
+
}) {
|
|
46279
|
+
if (outline.length < 3 || !Number.isFinite(bottom) || !Number.isFinite(top) || top <= bottom || outline.some((p) => !Number.isFinite(p.x) || !Number.isFinite(p.y)))
|
|
46280
|
+
throw new Error(
|
|
46281
|
+
"A finite polygon and positive extrusion thickness are required"
|
|
46282
|
+
);
|
|
46283
|
+
let area2 = 0;
|
|
46284
|
+
for (const [i, a] of outline.entries()) {
|
|
46285
|
+
const b = outline[(i + 1) % outline.length];
|
|
46286
|
+
area2 += a.x * b.y - b.x * a.y;
|
|
46287
|
+
}
|
|
46288
|
+
if (Math.abs(area2) < 1e-12) throw new Error("Degenerate polygon");
|
|
46289
|
+
const polygon2 = area2 > 0 ? outline : [...outline].reverse();
|
|
46290
|
+
const triangles = [];
|
|
46291
|
+
const add = ({
|
|
46292
|
+
a,
|
|
46293
|
+
b,
|
|
46294
|
+
c,
|
|
46295
|
+
pcbFace
|
|
46296
|
+
}) => {
|
|
46297
|
+
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 };
|
|
46298
|
+
const n = {
|
|
46299
|
+
x: u.y * v.z - u.z * v.y,
|
|
46300
|
+
y: u.z * v.x - u.x * v.z,
|
|
46301
|
+
z: u.x * v.y - u.y * v.x
|
|
46302
|
+
};
|
|
46303
|
+
const l = Math.hypot(n.x, n.y, n.z);
|
|
46304
|
+
if (l > 1e-12)
|
|
46305
|
+
triangles.push({
|
|
46306
|
+
vertices: [a, b, c],
|
|
46307
|
+
normal: { x: n.x / l, y: n.y / l, z: n.z / l },
|
|
46308
|
+
pcbFace
|
|
46309
|
+
});
|
|
46310
|
+
};
|
|
46311
|
+
const indices = earcut(polygon2.flatMap((p) => [p.x, p.y]));
|
|
46312
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
46313
|
+
const [a, b, c] = indices.slice(i, i + 3).map((j) => polygon2[j]);
|
|
46314
|
+
add({
|
|
46315
|
+
a: { ...a, z: top },
|
|
46316
|
+
b: { ...b, z: top },
|
|
46317
|
+
c: { ...c, z: top },
|
|
46318
|
+
pcbFace: "top"
|
|
46319
|
+
});
|
|
46320
|
+
add({
|
|
46321
|
+
a: { ...c, z: bottom },
|
|
46322
|
+
b: { ...b, z: bottom },
|
|
46323
|
+
c: { ...a, z: bottom },
|
|
46324
|
+
pcbFace: "bottom"
|
|
46325
|
+
});
|
|
46326
|
+
}
|
|
46327
|
+
for (let i = 0; i < polygon2.length; i++) {
|
|
46328
|
+
const a = polygon2[i], b = polygon2[(i + 1) % polygon2.length];
|
|
46329
|
+
add({
|
|
46330
|
+
a: { ...a, z: bottom },
|
|
46331
|
+
b: { ...b, z: bottom },
|
|
46332
|
+
c: { ...b, z: top },
|
|
46333
|
+
pcbFace: "side"
|
|
46334
|
+
});
|
|
46335
|
+
add({
|
|
46336
|
+
a: { ...a, z: bottom },
|
|
46337
|
+
b: { ...b, z: top },
|
|
46338
|
+
c: { ...a, z: top },
|
|
46339
|
+
pcbFace: "side"
|
|
46340
|
+
});
|
|
46341
|
+
}
|
|
46342
|
+
return { triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46343
|
+
}
|
|
46344
|
+
function createStiffenerMesh({
|
|
46345
|
+
stiffener,
|
|
46346
|
+
boardThickness,
|
|
46347
|
+
fold
|
|
46348
|
+
}) {
|
|
46349
|
+
const adhesive = stiffener.adhesive_thickness ?? 0;
|
|
46350
|
+
if (!Number.isFinite(adhesive) || adhesive < 0 || !Number.isFinite(stiffener.thickness) || stiffener.thickness <= 0 || !["top", "bottom"].includes(stiffener.layer))
|
|
46351
|
+
throw new Error(`Invalid PCB stiffener ${stiffener.pcb_stiffener_id}`);
|
|
46352
|
+
const outline = stiffener.shape === "polygon" ? stiffener.outline : (() => {
|
|
46353
|
+
if (!(stiffener.width > 0 && stiffener.height > 0))
|
|
46354
|
+
throw new Error("Invalid stiffener dimensions");
|
|
46355
|
+
const a = (stiffener.rotation ?? 0) * Math.PI / 180;
|
|
46356
|
+
return [
|
|
46357
|
+
[-1, -1],
|
|
46358
|
+
[1, -1],
|
|
46359
|
+
[1, 1],
|
|
46360
|
+
[-1, 1]
|
|
46361
|
+
].map(([x, y]) => ({
|
|
46362
|
+
x: stiffener.center.x + x * stiffener.width / 2 * Math.cos(a) - y * stiffener.height / 2 * Math.sin(a),
|
|
46363
|
+
y: stiffener.center.y + x * stiffener.width / 2 * Math.sin(a) + y * stiffener.height / 2 * Math.cos(a)
|
|
46364
|
+
}));
|
|
46365
|
+
})();
|
|
46366
|
+
const near = boardThickness / 2 + adhesive, far = near + stiffener.thickness;
|
|
46367
|
+
const mesh = extrudePolygon({
|
|
46368
|
+
outline,
|
|
46369
|
+
bottom: stiffener.layer === "top" ? near : -far,
|
|
46370
|
+
top: stiffener.layer === "top" ? far : -near
|
|
46371
|
+
});
|
|
46372
|
+
if (!fold) return mesh;
|
|
46373
|
+
fold.assertRigid(
|
|
46374
|
+
mesh.triangles.flatMap((t) => t.vertices),
|
|
46375
|
+
stiffener.pcb_stiffener_id
|
|
46376
|
+
);
|
|
46377
|
+
const anchor = {
|
|
46378
|
+
x: outline.reduce((s, p) => s + p.x, 0) / outline.length,
|
|
46379
|
+
y: outline.reduce((s, p) => s + p.y, 0) / outline.length,
|
|
46380
|
+
z: 0
|
|
46381
|
+
};
|
|
46382
|
+
const triangles = mesh.triangles.map((t) => ({
|
|
46383
|
+
...t,
|
|
46384
|
+
vertices: t.vertices.map((p) => fold.point(p, anchor)),
|
|
46385
|
+
normal: fold.direction(t.normal, anchor)
|
|
46386
|
+
}));
|
|
46387
|
+
return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46388
|
+
}
|
|
46389
|
+
|
|
46390
|
+
// src/utils/flex-meshes.ts
|
|
46391
|
+
import * as THREE44 from "three";
|
|
46392
|
+
function meshToSurface(mesh, center) {
|
|
46393
|
+
mesh.updateMatrix();
|
|
46394
|
+
const geometry = mesh.geometry.index ? mesh.geometry.toNonIndexed() : mesh.geometry;
|
|
46395
|
+
const position = geometry.getAttribute("position"), uv = geometry.getAttribute("uv");
|
|
46396
|
+
const triangles = [];
|
|
46397
|
+
for (let i = 0; i < position.count; i += 3) {
|
|
46398
|
+
const vertices = [0, 1, 2].map((j) => {
|
|
46399
|
+
const v = new THREE44.Vector3().fromBufferAttribute(position, i + j).applyMatrix4(mesh.matrix);
|
|
46400
|
+
return { x: v.x - center.x, y: v.y - center.y, z: v.z };
|
|
46401
|
+
});
|
|
46402
|
+
const [a, b, c] = vertices;
|
|
46403
|
+
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();
|
|
46404
|
+
triangles.push({
|
|
46405
|
+
vertices,
|
|
46406
|
+
normal: { x: n.x, y: n.y, z: n.z },
|
|
46407
|
+
...uv ? {
|
|
46408
|
+
uvs: [0, 1, 2].map((j) => ({
|
|
46409
|
+
u: uv.getX(i + j),
|
|
46410
|
+
v: uv.getY(i + j)
|
|
46411
|
+
}))
|
|
46412
|
+
} : {}
|
|
46413
|
+
});
|
|
46414
|
+
}
|
|
46415
|
+
if (geometry !== mesh.geometry) geometry.dispose();
|
|
46416
|
+
return { triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46417
|
+
}
|
|
46418
|
+
function surfaceToGeometry(surface, center) {
|
|
46419
|
+
const positions = [], normals = [], uvs = [];
|
|
46420
|
+
for (const triangle of surface.triangles)
|
|
46421
|
+
triangle.vertices.forEach((p, i) => {
|
|
46422
|
+
positions.push(p.x + center.x, p.y + center.y, p.z);
|
|
46423
|
+
normals.push(triangle.normal.x, triangle.normal.y, triangle.normal.z);
|
|
46424
|
+
uvs.push(triangle.uvs?.[i]?.u ?? 0, triangle.uvs?.[i]?.v ?? 0);
|
|
46425
|
+
});
|
|
46426
|
+
const geometry = new THREE44.BufferGeometry();
|
|
46427
|
+
geometry.setAttribute(
|
|
46428
|
+
"position",
|
|
46429
|
+
new THREE44.Float32BufferAttribute(positions, 3)
|
|
46430
|
+
);
|
|
46431
|
+
geometry.setAttribute("normal", new THREE44.Float32BufferAttribute(normals, 3));
|
|
46432
|
+
geometry.setAttribute("uv", new THREE44.Float32BufferAttribute(uvs, 2));
|
|
46433
|
+
geometry.computeBoundingBox();
|
|
46434
|
+
geometry.computeBoundingSphere();
|
|
46435
|
+
return geometry;
|
|
46436
|
+
}
|
|
46437
|
+
function replaceGeometry(mesh, surface, board) {
|
|
46438
|
+
const output = mesh.clone();
|
|
46439
|
+
output.geometry = surfaceToGeometry(surface, board.center);
|
|
46440
|
+
output.position.set(0, 0, 0);
|
|
46441
|
+
output.rotation.set(0, 0, 0);
|
|
46442
|
+
output.scale.set(1, 1, 1);
|
|
46443
|
+
output.updateMatrix();
|
|
46444
|
+
return output;
|
|
46445
|
+
}
|
|
46446
|
+
function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
|
|
46447
|
+
const boards = json.filter((e) => e.type === "pcb_board");
|
|
46448
|
+
const bends = json.filter((e) => e.type === "pcb_bend"), stiffeners = json.filter((e) => e.type === "pcb_stiffener");
|
|
46449
|
+
if (!bends.length && !stiffeners.length)
|
|
46450
|
+
return { geometryMeshes, textureMeshes };
|
|
46451
|
+
const board = boards[0];
|
|
46452
|
+
if (!board || boards.length !== 1 || json.some((e) => e.type === "pcb_panel") || [...bends, ...stiffeners].some((e) => e.pcb_board_id !== board.pcb_board_id))
|
|
46453
|
+
throw new Error(
|
|
46454
|
+
"Flex rendering requires one board, matching board references, and no panel"
|
|
46455
|
+
);
|
|
46456
|
+
const fold = foldPcbs ? createPcbFold(bends, board.thickness ?? 1.6) : void 0;
|
|
46457
|
+
const body = geometryMeshes.find((m) => m.name === "board-geom");
|
|
46458
|
+
const flatBody = body ? meshToSurface(body, board.center) : void 0;
|
|
46459
|
+
const geometry = fold ? geometryMeshes.map(
|
|
46460
|
+
(mesh) => replaceGeometry(
|
|
46461
|
+
mesh,
|
|
46462
|
+
foldSurfaceMesh(meshToSurface(mesh, board.center), fold),
|
|
46463
|
+
board
|
|
46464
|
+
)
|
|
46465
|
+
) : [...geometryMeshes];
|
|
46466
|
+
const textures = fold && flatBody ? textureMeshes.map((mesh) => {
|
|
46467
|
+
mesh.updateMatrix();
|
|
46468
|
+
const inverse = mesh.matrix.clone().invert();
|
|
46469
|
+
const bottom = mesh.name.startsWith("bottom");
|
|
46470
|
+
const dimensions = mesh.geometry.parameters;
|
|
46471
|
+
const triangles = flatBody.triangles.filter((t) => bottom ? t.normal.z < -0.9 : t.normal.z > 0.9).map((t) => {
|
|
46472
|
+
const vertices = t.vertices.map((p) => ({
|
|
46473
|
+
...p,
|
|
46474
|
+
z: mesh.position.z
|
|
46475
|
+
}));
|
|
46476
|
+
const uvs = vertices.map((p) => {
|
|
46477
|
+
const local = new THREE44.Vector3(
|
|
46478
|
+
p.x + board.center.x,
|
|
46479
|
+
p.y + board.center.y,
|
|
46480
|
+
p.z
|
|
46481
|
+
).applyMatrix4(inverse);
|
|
46482
|
+
return {
|
|
46483
|
+
u: local.x / dimensions.width + 0.5,
|
|
46484
|
+
v: local.y / dimensions.height + 0.5
|
|
46485
|
+
};
|
|
46486
|
+
});
|
|
46487
|
+
return { ...t, vertices, uvs };
|
|
46488
|
+
});
|
|
46489
|
+
const result = replaceGeometry(
|
|
46490
|
+
mesh,
|
|
46491
|
+
foldSurfaceMesh(
|
|
46492
|
+
{ triangles, boundingBox: boundsOfTriangles(triangles) },
|
|
46493
|
+
fold
|
|
46494
|
+
),
|
|
46495
|
+
board
|
|
46496
|
+
);
|
|
46497
|
+
mesh.geometry.dispose();
|
|
46498
|
+
return result;
|
|
46499
|
+
}) : textureMeshes;
|
|
46500
|
+
for (const stiffener of stiffeners) {
|
|
46501
|
+
const mesh = new THREE44.Mesh(
|
|
46502
|
+
surfaceToGeometry(
|
|
46503
|
+
createStiffenerMesh({
|
|
46504
|
+
stiffener,
|
|
46505
|
+
boardThickness: board.thickness ?? 1.6,
|
|
46506
|
+
fold
|
|
46507
|
+
}),
|
|
46508
|
+
board.center
|
|
46509
|
+
),
|
|
46510
|
+
new THREE44.MeshStandardMaterial({
|
|
46511
|
+
color: stiffener.material === "fr4" ? "#879568" : stiffener.material === "polyimide" ? "#bd7f27" : "#b8bdc4",
|
|
46512
|
+
side: THREE44.DoubleSide
|
|
46513
|
+
})
|
|
46514
|
+
);
|
|
46515
|
+
mesh.name = "board-stiffener";
|
|
46516
|
+
configureObjectShadows(mesh);
|
|
46517
|
+
geometry.push(mesh);
|
|
46518
|
+
}
|
|
46519
|
+
const bounds = new THREE44.Box3();
|
|
46520
|
+
for (const mesh of [...geometry, ...textures]) bounds.expandByObject(mesh);
|
|
46521
|
+
return {
|
|
46522
|
+
geometryMeshes: geometry,
|
|
46523
|
+
textureMeshes: textures,
|
|
46524
|
+
bounds: {
|
|
46525
|
+
minX: bounds.min.x,
|
|
46526
|
+
maxX: bounds.max.x,
|
|
46527
|
+
minY: bounds.min.y,
|
|
46528
|
+
maxY: bounds.max.y,
|
|
46529
|
+
minZ: bounds.min.z,
|
|
46530
|
+
maxZ: bounds.max.z
|
|
46531
|
+
}
|
|
46532
|
+
};
|
|
46533
|
+
}
|
|
46534
|
+
|
|
45371
46535
|
// src/CadViewerManifold.tsx
|
|
45372
46536
|
import { su as su17 } from "@tscircuit/circuit-json-util";
|
|
45373
46537
|
import { useEffect as useEffect28, useMemo as useMemo24, useState as useState17 } from "react";
|
|
45374
|
-
import * as
|
|
46538
|
+
import * as THREE51 from "three";
|
|
45375
46539
|
|
|
45376
46540
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
45377
46541
|
import { su as su16 } from "@tscircuit/circuit-json-util";
|
|
45378
46542
|
import { useEffect as useEffect27, useMemo as useMemo23, useRef as useRef9, useState as useState16 } from "react";
|
|
45379
|
-
import * as
|
|
46543
|
+
import * as THREE48 from "three";
|
|
45380
46544
|
|
|
45381
46545
|
// src/utils/manifold/create-manifold-board.ts
|
|
45382
46546
|
var arePointsClockwise2 = (points) => {
|
|
45383
|
-
let
|
|
46547
|
+
let area2 = 0;
|
|
45384
46548
|
for (let i = 0; i < points.length; i++) {
|
|
45385
46549
|
const j = (i + 1) % points.length;
|
|
45386
46550
|
if (points[i] && points[j]) {
|
|
45387
|
-
|
|
45388
|
-
|
|
46551
|
+
area2 += points[i][0] * points[j][1];
|
|
46552
|
+
area2 -= points[j][0] * points[i][1];
|
|
45389
46553
|
}
|
|
45390
46554
|
}
|
|
45391
|
-
const
|
|
45392
|
-
return
|
|
46555
|
+
const signedArea2 = area2 / 2;
|
|
46556
|
+
return signedArea2 <= 0;
|
|
45393
46557
|
};
|
|
45394
46558
|
function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, manifoldInstancesForCleanup) {
|
|
45395
46559
|
let boardOp;
|
|
@@ -45437,7 +46601,7 @@ function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, ma
|
|
|
45437
46601
|
}
|
|
45438
46602
|
|
|
45439
46603
|
// src/utils/manifold/process-cutouts.ts
|
|
45440
|
-
import { su as
|
|
46604
|
+
import { su as su13 } from "@tscircuit/circuit-json-util";
|
|
45441
46605
|
|
|
45442
46606
|
// src/utils/pad-geoms.ts
|
|
45443
46607
|
var RECT_PAD_SEGMENTS2 = 64;
|
|
@@ -45483,20 +46647,20 @@ function createRoundedRectPrism({
|
|
|
45483
46647
|
|
|
45484
46648
|
// src/utils/manifold/process-cutouts.ts
|
|
45485
46649
|
var arePointsClockwise3 = (points) => {
|
|
45486
|
-
let
|
|
46650
|
+
let area2 = 0;
|
|
45487
46651
|
for (let i = 0; i < points.length; i++) {
|
|
45488
46652
|
const j = (i + 1) % points.length;
|
|
45489
46653
|
if (points[i] && points[j]) {
|
|
45490
|
-
|
|
45491
|
-
|
|
46654
|
+
area2 += points[i][0] * points[j][1];
|
|
46655
|
+
area2 -= points[j][0] * points[i][1];
|
|
45492
46656
|
}
|
|
45493
46657
|
}
|
|
45494
|
-
const
|
|
45495
|
-
return
|
|
46658
|
+
const signedArea2 = area2 / 2;
|
|
46659
|
+
return signedArea2 <= 0;
|
|
45496
46660
|
};
|
|
45497
46661
|
function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
|
|
45498
46662
|
const cutoutOps = [];
|
|
45499
|
-
const pcbCutouts =
|
|
46663
|
+
const pcbCutouts = su13(circuitJson).pcb_cutout.list();
|
|
45500
46664
|
for (const cutout of pcbCutouts) {
|
|
45501
46665
|
let cutoutOp;
|
|
45502
46666
|
const cutoutHeight = pcbThickness * 1.5;
|
|
@@ -45591,7 +46755,7 @@ function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThick
|
|
|
45591
46755
|
}
|
|
45592
46756
|
|
|
45593
46757
|
// src/utils/manifold/process-non-plated-holes.ts
|
|
45594
|
-
import { su as
|
|
46758
|
+
import { su as su14 } from "@tscircuit/circuit-json-util";
|
|
45595
46759
|
|
|
45596
46760
|
// src/utils/hole-geoms.ts
|
|
45597
46761
|
function createCircleHoleDrill({
|
|
@@ -45634,7 +46798,7 @@ function createPlatedHoleDrill({
|
|
|
45634
46798
|
// src/utils/manifold/process-non-plated-holes.ts
|
|
45635
46799
|
function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
|
|
45636
46800
|
const nonPlatedHoleBoardDrills = [];
|
|
45637
|
-
const pcbHoles =
|
|
46801
|
+
const pcbHoles = su14(circuitJson).pcb_hole.list();
|
|
45638
46802
|
const createPillOp = (width10, height10, depth) => {
|
|
45639
46803
|
const pillOp = createRoundedRectPrism({
|
|
45640
46804
|
Manifold,
|
|
@@ -45687,13 +46851,13 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
|
|
|
45687
46851
|
holeOp = createRectOp(holeW, holeH, drillDepth);
|
|
45688
46852
|
} else if (holeShape === "oval") {
|
|
45689
46853
|
let points = createEllipsePoints2(holeW, holeH, SMOOTH_CIRCLE_SEGMENTS);
|
|
45690
|
-
let
|
|
46854
|
+
let area2 = 0;
|
|
45691
46855
|
for (let i = 0; i < points.length; i++) {
|
|
45692
46856
|
const j = (i + 1) % points.length;
|
|
45693
|
-
|
|
45694
|
-
|
|
46857
|
+
area2 += points[i][0] * points[j][1];
|
|
46858
|
+
area2 -= points[j][0] * points[i][1];
|
|
45695
46859
|
}
|
|
45696
|
-
if (
|
|
46860
|
+
if (area2 <= 0) {
|
|
45697
46861
|
points = points.reverse();
|
|
45698
46862
|
}
|
|
45699
46863
|
const crossSection = CrossSection.ofPolygons([points]);
|
|
@@ -45724,18 +46888,18 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
|
|
|
45724
46888
|
}
|
|
45725
46889
|
|
|
45726
46890
|
// src/utils/manifold/process-plated-holes.ts
|
|
45727
|
-
import { su as
|
|
45728
|
-
import * as
|
|
46891
|
+
import { su as su15 } from "@tscircuit/circuit-json-util";
|
|
46892
|
+
import * as THREE46 from "three";
|
|
45729
46893
|
|
|
45730
46894
|
// src/utils/manifold-mesh-to-three-geometry.ts
|
|
45731
|
-
import * as
|
|
46895
|
+
import * as THREE45 from "three";
|
|
45732
46896
|
function manifoldMeshToThreeGeometry(manifoldMesh) {
|
|
45733
|
-
const geometry = new
|
|
46897
|
+
const geometry = new THREE45.BufferGeometry();
|
|
45734
46898
|
geometry.setAttribute(
|
|
45735
46899
|
"position",
|
|
45736
|
-
new
|
|
46900
|
+
new THREE45.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
|
|
45737
46901
|
);
|
|
45738
|
-
geometry.setIndex(new
|
|
46902
|
+
geometry.setIndex(new THREE45.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
|
|
45739
46903
|
if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
|
|
45740
46904
|
for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
|
|
45741
46905
|
const start = manifoldMesh.runIndex[i];
|
|
@@ -45750,16 +46914,16 @@ function manifoldMeshToThreeGeometry(manifoldMesh) {
|
|
|
45750
46914
|
|
|
45751
46915
|
// src/utils/manifold/process-plated-holes.ts
|
|
45752
46916
|
var arePointsClockwise4 = (points) => {
|
|
45753
|
-
let
|
|
46917
|
+
let area2 = 0;
|
|
45754
46918
|
for (let i = 0; i < points.length; i++) {
|
|
45755
46919
|
const j = (i + 1) % points.length;
|
|
45756
46920
|
if (points[i] && points[j]) {
|
|
45757
|
-
|
|
45758
|
-
|
|
46921
|
+
area2 += points[i][0] * points[j][1];
|
|
46922
|
+
area2 -= points[j][0] * points[i][1];
|
|
45759
46923
|
}
|
|
45760
46924
|
}
|
|
45761
|
-
const
|
|
45762
|
-
return
|
|
46925
|
+
const signedArea2 = area2 / 2;
|
|
46926
|
+
return signedArea2 <= 0;
|
|
45763
46927
|
};
|
|
45764
46928
|
var createEllipsePoints = (width10, height10, segments) => {
|
|
45765
46929
|
const points = [];
|
|
@@ -45769,14 +46933,14 @@ var createEllipsePoints = (width10, height10, segments) => {
|
|
|
45769
46933
|
}
|
|
45770
46934
|
return points;
|
|
45771
46935
|
};
|
|
45772
|
-
var COPPER_COLOR = new
|
|
46936
|
+
var COPPER_COLOR = new THREE46.Color(...colors.copper);
|
|
45773
46937
|
var PLATED_HOLE_LIP_HEIGHT = 0.05;
|
|
45774
46938
|
var PLATED_HOLE_PAD_THICKNESS = 3e-3;
|
|
45775
46939
|
var PLATED_HOLE_SURFACE_CLEARANCE = 5e-4;
|
|
45776
46940
|
var PLATED_HOLE_FILL_CLEARANCE = 4e-3;
|
|
45777
46941
|
function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
|
|
45778
46942
|
const platedHoleBoardDrills = [];
|
|
45779
|
-
const pcbPlatedHoles =
|
|
46943
|
+
const pcbPlatedHoles = su15(circuitJson).pcb_plated_hole.list();
|
|
45780
46944
|
const platedHoleCopperGeoms = [];
|
|
45781
46945
|
const platedHoleCopperOpsForSubtract = [];
|
|
45782
46946
|
const createPillOp = (width10, height10, depth) => {
|
|
@@ -46399,8 +47563,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
46399
47563
|
}
|
|
46400
47564
|
|
|
46401
47565
|
// src/utils/manifold/process-vias.ts
|
|
46402
|
-
import
|
|
46403
|
-
import * as THREE46 from "three";
|
|
47566
|
+
import * as THREE47 from "three";
|
|
46404
47567
|
|
|
46405
47568
|
// src/utils/via-geoms.ts
|
|
46406
47569
|
function createViaCopper2({
|
|
@@ -46438,10 +47601,10 @@ function createViaCopper2({
|
|
|
46438
47601
|
}
|
|
46439
47602
|
|
|
46440
47603
|
// src/utils/manifold/process-vias.ts
|
|
46441
|
-
var COPPER_COLOR2 = new
|
|
47604
|
+
var COPPER_COLOR2 = new THREE47.Color(...colors.copper);
|
|
46442
47605
|
function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
|
|
46443
47606
|
const viaBoardDrills = [];
|
|
46444
|
-
const pcbVias =
|
|
47607
|
+
const pcbVias = getPcbVias(circuitJson);
|
|
46445
47608
|
const viaCopperGeoms = [];
|
|
46446
47609
|
pcbVias.forEach((via, index2) => {
|
|
46447
47610
|
if (typeof via.hole_diameter === "number") {
|
|
@@ -46659,7 +47822,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
|
|
|
46659
47822
|
{
|
|
46660
47823
|
key: "plated-holes-union",
|
|
46661
47824
|
geometry: cutPlatedGeom,
|
|
46662
|
-
color: new
|
|
47825
|
+
color: new THREE48.Color(
|
|
46663
47826
|
colors.copper[0],
|
|
46664
47827
|
colors.copper[1],
|
|
46665
47828
|
colors.copper[2]
|
|
@@ -46729,11 +47892,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
|
|
|
46729
47892
|
};
|
|
46730
47893
|
|
|
46731
47894
|
// src/utils/manifold/create-three-geometry-meshes.ts
|
|
46732
|
-
import * as
|
|
47895
|
+
import * as THREE50 from "three";
|
|
46733
47896
|
|
|
46734
47897
|
// src/utils/create-board-material.ts
|
|
46735
|
-
import * as
|
|
46736
|
-
var DEFAULT_SIDE =
|
|
47898
|
+
import * as THREE49 from "three";
|
|
47899
|
+
var DEFAULT_SIDE = THREE49.DoubleSide;
|
|
46737
47900
|
var createBoardMaterial = ({
|
|
46738
47901
|
material,
|
|
46739
47902
|
color,
|
|
@@ -46741,7 +47904,7 @@ var createBoardMaterial = ({
|
|
|
46741
47904
|
isFaux = false
|
|
46742
47905
|
}) => {
|
|
46743
47906
|
if (material === "fr4") {
|
|
46744
|
-
return new
|
|
47907
|
+
return new THREE49.MeshPhysicalMaterial({
|
|
46745
47908
|
color,
|
|
46746
47909
|
side,
|
|
46747
47910
|
metalness: 0,
|
|
@@ -46759,7 +47922,7 @@ var createBoardMaterial = ({
|
|
|
46759
47922
|
polygonOffsetUnits: 1
|
|
46760
47923
|
});
|
|
46761
47924
|
}
|
|
46762
|
-
return new
|
|
47925
|
+
return new THREE49.MeshStandardMaterial({
|
|
46763
47926
|
color,
|
|
46764
47927
|
side,
|
|
46765
47928
|
flatShading: true,
|
|
@@ -46778,12 +47941,12 @@ function createGeometryMeshes(geoms) {
|
|
|
46778
47941
|
const meshes = [];
|
|
46779
47942
|
if (!geoms) return meshes;
|
|
46780
47943
|
if (geoms.board?.geometry) {
|
|
46781
|
-
const mesh = new
|
|
47944
|
+
const mesh = new THREE50.Mesh(
|
|
46782
47945
|
geoms.board.geometry,
|
|
46783
47946
|
createBoardMaterial({
|
|
46784
47947
|
material: geoms.board.material,
|
|
46785
47948
|
color: geoms.board.color,
|
|
46786
|
-
side:
|
|
47949
|
+
side: THREE50.DoubleSide,
|
|
46787
47950
|
isFaux: geoms.board.isFaux
|
|
46788
47951
|
})
|
|
46789
47952
|
);
|
|
@@ -46794,11 +47957,11 @@ function createGeometryMeshes(geoms) {
|
|
|
46794
47957
|
const createMeshesFromArray = (geomArray) => {
|
|
46795
47958
|
if (geomArray) {
|
|
46796
47959
|
for (const comp of geomArray) {
|
|
46797
|
-
const mesh = new
|
|
47960
|
+
const mesh = new THREE50.Mesh(
|
|
46798
47961
|
comp.geometry,
|
|
46799
|
-
new
|
|
47962
|
+
new THREE50.MeshStandardMaterial({
|
|
46800
47963
|
color: comp.color,
|
|
46801
|
-
side:
|
|
47964
|
+
side: THREE50.DoubleSide,
|
|
46802
47965
|
flatShading: true
|
|
46803
47966
|
// Consistent with board
|
|
46804
47967
|
})
|
|
@@ -46843,7 +48006,7 @@ var BoardMeshes = ({
|
|
|
46843
48006
|
const typedMaterial = material;
|
|
46844
48007
|
for (const prop of textureProps) {
|
|
46845
48008
|
const texture = typedMaterial[prop];
|
|
46846
|
-
if (texture && texture instanceof
|
|
48009
|
+
if (texture && texture instanceof THREE51.Texture) {
|
|
46847
48010
|
texture.dispose();
|
|
46848
48011
|
}
|
|
46849
48012
|
}
|
|
@@ -46854,7 +48017,7 @@ var BoardMeshes = ({
|
|
|
46854
48017
|
if (!rootObject) return;
|
|
46855
48018
|
for (const mesh of geometryMeshes) {
|
|
46856
48019
|
let shouldShow = true;
|
|
46857
|
-
if (mesh.name === "board-geom") {
|
|
48020
|
+
if (mesh.name === "board-geom" || mesh.name === "board-stiffener") {
|
|
46858
48021
|
shouldShow = visibility.boardBody;
|
|
46859
48022
|
} else if (mesh.name.includes("plated_hole") || mesh.name.includes("via")) {
|
|
46860
48023
|
shouldShow = visibility.topCopper || visibility.bottomCopper;
|
|
@@ -46891,6 +48054,7 @@ var BoardMeshes = ({
|
|
|
46891
48054
|
var MANIFOLD_CDN_BASE_URL = "https://cdn.jsdelivr.net/npm/manifold-3d@3.2.1";
|
|
46892
48055
|
var CadViewerManifold = ({
|
|
46893
48056
|
circuitJson: circuitJsonProp,
|
|
48057
|
+
foldPcbs,
|
|
46894
48058
|
autoRotateDisabled,
|
|
46895
48059
|
clickToInteractEnabled,
|
|
46896
48060
|
onUserInteraction,
|
|
@@ -46978,14 +48142,40 @@ try {
|
|
|
46978
48142
|
boardData,
|
|
46979
48143
|
isFauxBoard
|
|
46980
48144
|
} = useManifoldBoardBuilder(manifoldJSModule, circuitJson, visibility);
|
|
46981
|
-
const
|
|
46982
|
-
|
|
46983
|
-
|
|
46984
|
-
|
|
46985
|
-
|
|
48145
|
+
const flex = useMemo24(() => {
|
|
48146
|
+
try {
|
|
48147
|
+
const resolvedFoldPcbs = resolveFoldPcbs(circuitJson, foldPcbs);
|
|
48148
|
+
const posedJson = transformCircuitJsonCadComponents(circuitJson, {
|
|
48149
|
+
foldPcbs: resolvedFoldPcbs
|
|
48150
|
+
});
|
|
48151
|
+
const meshes = createFlexMeshes(
|
|
48152
|
+
createGeometryMeshes(geoms),
|
|
48153
|
+
createTextureMeshes(textures, boardData, pcbThickness, isFauxBoard),
|
|
48154
|
+
circuitJson,
|
|
48155
|
+
resolvedFoldPcbs
|
|
48156
|
+
);
|
|
48157
|
+
return { ...meshes, posedJson, error: void 0 };
|
|
48158
|
+
} catch (error) {
|
|
48159
|
+
return {
|
|
48160
|
+
error: error instanceof Error ? error.message : String(error),
|
|
48161
|
+
geometryMeshes: [],
|
|
48162
|
+
textureMeshes: [],
|
|
48163
|
+
posedJson: circuitJson,
|
|
48164
|
+
bounds: void 0
|
|
48165
|
+
};
|
|
48166
|
+
}
|
|
48167
|
+
}, [
|
|
48168
|
+
geoms,
|
|
48169
|
+
textures,
|
|
48170
|
+
boardData,
|
|
48171
|
+
pcbThickness,
|
|
48172
|
+
isFauxBoard,
|
|
48173
|
+
circuitJson,
|
|
48174
|
+
foldPcbs
|
|
48175
|
+
]);
|
|
46986
48176
|
const cadComponents = useMemo24(
|
|
46987
|
-
() => su17(
|
|
46988
|
-
[
|
|
48177
|
+
() => su17(flex.posedJson).cad_component.list(),
|
|
48178
|
+
[flex.posedJson]
|
|
46989
48179
|
);
|
|
46990
48180
|
const boardDimensions = useMemo24(() => {
|
|
46991
48181
|
if (!boardData) return void 0;
|
|
@@ -47032,10 +48222,11 @@ try {
|
|
|
47032
48222
|
if (!manifoldJSModule) {
|
|
47033
48223
|
return /* @__PURE__ */ jsx19("div", { style: { padding: "1em" }, children: "Loading Manifold module..." });
|
|
47034
48224
|
}
|
|
47035
|
-
if (builderError) {
|
|
48225
|
+
if (builderError || flex.error) {
|
|
47036
48226
|
return /* @__PURE__ */ jsxs6(
|
|
47037
48227
|
"div",
|
|
47038
48228
|
{
|
|
48229
|
+
role: "alert",
|
|
47039
48230
|
style: {
|
|
47040
48231
|
color: "red",
|
|
47041
48232
|
padding: "1em",
|
|
@@ -47044,7 +48235,7 @@ try {
|
|
|
47044
48235
|
},
|
|
47045
48236
|
children: [
|
|
47046
48237
|
"Error: ",
|
|
47047
|
-
builderError
|
|
48238
|
+
builderError ?? flex.error
|
|
47048
48239
|
]
|
|
47049
48240
|
}
|
|
47050
48241
|
);
|
|
@@ -47067,10 +48258,11 @@ try {
|
|
|
47067
48258
|
/* @__PURE__ */ jsx19(
|
|
47068
48259
|
BoardMeshes,
|
|
47069
48260
|
{
|
|
47070
|
-
geometryMeshes,
|
|
47071
|
-
textureMeshes
|
|
48261
|
+
geometryMeshes: flex.geometryMeshes,
|
|
48262
|
+
textureMeshes: flex.textureMeshes
|
|
47072
48263
|
}
|
|
47073
48264
|
),
|
|
48265
|
+
flex.bounds && /* @__PURE__ */ jsx19(FitCameraToComparison, { bounds: flex.bounds }),
|
|
47074
48266
|
cadComponents.map((cad_component) => /* @__PURE__ */ jsx19(
|
|
47075
48267
|
ThreeErrorBoundary,
|
|
47076
48268
|
{
|
|
@@ -47079,7 +48271,7 @@ try {
|
|
|
47079
48271
|
AnyCadComponent,
|
|
47080
48272
|
{
|
|
47081
48273
|
cad_component,
|
|
47082
|
-
circuitJson,
|
|
48274
|
+
circuitJson: flex.posedJson,
|
|
47083
48275
|
resolveStaticAsset
|
|
47084
48276
|
}
|
|
47085
48277
|
)
|
|
@@ -52789,6 +53981,27 @@ var MenuItemImpl = /* @__PURE__ */ React41.forwardRef(
|
|
|
52789
53981
|
);
|
|
52790
53982
|
}, "MenuItemImpl")
|
|
52791
53983
|
);
|
|
53984
|
+
var MenuCheckboxItem = /* @__PURE__ */ React41.forwardRef(
|
|
53985
|
+
// blank line to reduce diff noise
|
|
53986
|
+
/* @__PURE__ */ __name21(function MenuCheckboxItem2(props, forwardedRef) {
|
|
53987
|
+
const { checked = false, onCheckedChange, ...checkboxItemProps } = props;
|
|
53988
|
+
return /* @__PURE__ */ jsx30(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ jsx30(
|
|
53989
|
+
MenuItem,
|
|
53990
|
+
{
|
|
53991
|
+
role: "menuitemcheckbox",
|
|
53992
|
+
"aria-checked": isIndeterminate(checked) ? "mixed" : checked,
|
|
53993
|
+
...checkboxItemProps,
|
|
53994
|
+
ref: forwardedRef,
|
|
53995
|
+
"data-state": getCheckedState(checked),
|
|
53996
|
+
onSelect: composeEventHandlers(
|
|
53997
|
+
checkboxItemProps.onSelect,
|
|
53998
|
+
() => onCheckedChange?.(isIndeterminate(checked) ? true : !checked),
|
|
53999
|
+
{ checkForDefaultPrevented: false }
|
|
54000
|
+
)
|
|
54001
|
+
}
|
|
54002
|
+
) });
|
|
54003
|
+
}, "MenuCheckboxItem")
|
|
54004
|
+
);
|
|
52792
54005
|
var RADIO_GROUP_NAME = "MenuRadioGroup";
|
|
52793
54006
|
var [RadioGroupProvider, useRadioGroupContext] = createMenuContext(
|
|
52794
54007
|
RADIO_GROUP_NAME,
|
|
@@ -53056,10 +54269,10 @@ function isPointInPolygon(point, polygon2) {
|
|
|
53056
54269
|
return inside;
|
|
53057
54270
|
}
|
|
53058
54271
|
__name21(isPointInPolygon, "isPointInPolygon");
|
|
53059
|
-
function isPointerInGraceArea(event,
|
|
53060
|
-
if (!
|
|
54272
|
+
function isPointerInGraceArea(event, area2) {
|
|
54273
|
+
if (!area2) return false;
|
|
53061
54274
|
const cursorPos = { x: event.clientX, y: event.clientY };
|
|
53062
|
-
return isPointInPolygon(cursorPos,
|
|
54275
|
+
return isPointInPolygon(cursorPos, area2);
|
|
53063
54276
|
}
|
|
53064
54277
|
__name21(isPointerInGraceArea, "isPointerInGraceArea");
|
|
53065
54278
|
function whenMouse(handler) {
|
|
@@ -53071,6 +54284,7 @@ var Anchor2 = MenuAnchor;
|
|
|
53071
54284
|
var Portal3 = MenuPortal;
|
|
53072
54285
|
var Content2 = MenuContent;
|
|
53073
54286
|
var Item2 = MenuItem;
|
|
54287
|
+
var CheckboxItem = MenuCheckboxItem;
|
|
53074
54288
|
var Separator = MenuSeparator;
|
|
53075
54289
|
var Sub = MenuSub;
|
|
53076
54290
|
var SubTrigger = MenuSubTrigger;
|
|
@@ -53212,6 +54426,11 @@ var DropdownMenuItem = /* @__PURE__ */ React42.forwardRef(
|
|
|
53212
54426
|
return /* @__PURE__ */ jsx31(Item2, { ...menuScope, ...itemProps, ref: forwardedRef });
|
|
53213
54427
|
}, "DropdownMenuItem")
|
|
53214
54428
|
);
|
|
54429
|
+
var DropdownMenuCheckboxItem = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */ __name22(function DropdownMenuCheckboxItem2(props, forwardedRef) {
|
|
54430
|
+
const { __scopeDropdownMenu, ...checkboxItemProps } = props;
|
|
54431
|
+
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
54432
|
+
return /* @__PURE__ */ jsx31(CheckboxItem, { ...menuScope, ...checkboxItemProps, ref: forwardedRef });
|
|
54433
|
+
}, "DropdownMenuCheckboxItem"));
|
|
53215
54434
|
var DropdownMenuSeparator = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */ __name22(function DropdownMenuSeparator2(props, forwardedRef) {
|
|
53216
54435
|
const { __scopeDropdownMenu, ...separatorProps } = props;
|
|
53217
54436
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
@@ -53261,6 +54480,7 @@ var Trigger = DropdownMenuTrigger;
|
|
|
53261
54480
|
var Portal22 = DropdownMenuPortal;
|
|
53262
54481
|
var Content22 = DropdownMenuContent;
|
|
53263
54482
|
var Item22 = DropdownMenuItem;
|
|
54483
|
+
var CheckboxItem2 = DropdownMenuCheckboxItem;
|
|
53264
54484
|
var Separator2 = DropdownMenuSeparator;
|
|
53265
54485
|
var Sub2 = DropdownMenuSub;
|
|
53266
54486
|
var SubTrigger2 = DropdownMenuSubTrigger;
|
|
@@ -53829,6 +55049,9 @@ var ContextMenu = ({
|
|
|
53829
55049
|
engine,
|
|
53830
55050
|
cameraPreset,
|
|
53831
55051
|
autoRotate,
|
|
55052
|
+
foldPcbs = false,
|
|
55053
|
+
onFoldPcbsToggle,
|
|
55054
|
+
flexScene = false,
|
|
53832
55055
|
referenceObject = null,
|
|
53833
55056
|
onEngineSwitch,
|
|
53834
55057
|
onCameraPresetSelect,
|
|
@@ -54047,6 +55270,23 @@ var ContextMenu = ({
|
|
|
54047
55270
|
}
|
|
54048
55271
|
) })
|
|
54049
55272
|
] }),
|
|
55273
|
+
onFoldPcbsToggle && /* @__PURE__ */ jsxs8(
|
|
55274
|
+
CheckboxItem2,
|
|
55275
|
+
{
|
|
55276
|
+
checked: foldPcbs,
|
|
55277
|
+
onCheckedChange: onFoldPcbsToggle,
|
|
55278
|
+
style: {
|
|
55279
|
+
...itemStyles2,
|
|
55280
|
+
backgroundColor: hoveredItem === "fold" ? "#404040" : "transparent"
|
|
55281
|
+
},
|
|
55282
|
+
onMouseEnter: () => setHoveredItem("fold"),
|
|
55283
|
+
onMouseLeave: () => setHoveredItem(null),
|
|
55284
|
+
children: [
|
|
55285
|
+
/* @__PURE__ */ jsx34("span", { style: iconContainerStyles2, children: foldPcbs && /* @__PURE__ */ jsx34(CheckIcon, {}) }),
|
|
55286
|
+
/* @__PURE__ */ jsx34("span", { children: "Fold PCBs" })
|
|
55287
|
+
]
|
|
55288
|
+
}
|
|
55289
|
+
),
|
|
54050
55290
|
/* @__PURE__ */ jsxs8(
|
|
54051
55291
|
Item22,
|
|
54052
55292
|
{
|
|
@@ -54086,7 +55326,7 @@ var ContextMenu = ({
|
|
|
54086
55326
|
}
|
|
54087
55327
|
),
|
|
54088
55328
|
/* @__PURE__ */ jsx34(Separator2, { style: separatorStyles2 }),
|
|
54089
|
-
/* @__PURE__ */ jsxs8(
|
|
55329
|
+
!flexScene && /* @__PURE__ */ jsxs8(
|
|
54090
55330
|
Item22,
|
|
54091
55331
|
{
|
|
54092
55332
|
style: {
|
|
@@ -54103,11 +55343,17 @@ var ContextMenu = ({
|
|
|
54103
55343
|
onMouseLeave: () => setHoveredItem(null),
|
|
54104
55344
|
onTouchStart: () => setHoveredItem("engine"),
|
|
54105
55345
|
children: [
|
|
54106
|
-
/* @__PURE__ */ jsxs8(
|
|
54107
|
-
"
|
|
54108
|
-
|
|
54109
|
-
|
|
54110
|
-
|
|
55346
|
+
/* @__PURE__ */ jsxs8(
|
|
55347
|
+
"span",
|
|
55348
|
+
{
|
|
55349
|
+
style: { flex: 1, display: "flex", alignItems: "center" },
|
|
55350
|
+
children: [
|
|
55351
|
+
"Switch to ",
|
|
55352
|
+
engine === "jscad" ? "Manifold" : "JSCAD",
|
|
55353
|
+
" Engine"
|
|
55354
|
+
]
|
|
55355
|
+
}
|
|
55356
|
+
),
|
|
54111
55357
|
/* @__PURE__ */ jsx34(
|
|
54112
55358
|
"div",
|
|
54113
55359
|
{
|
|
@@ -54776,7 +56022,7 @@ var useGlobalDownloadGltf = () => {
|
|
|
54776
56022
|
|
|
54777
56023
|
// src/CadViewer.tsx
|
|
54778
56024
|
import { jsx as jsx37, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
54779
|
-
var DEFAULT_TARGET = new
|
|
56025
|
+
var DEFAULT_TARGET = new THREE52.Vector3(0, 0, 0);
|
|
54780
56026
|
var INITIAL_CAMERA_POSITION = [5, -5, 5];
|
|
54781
56027
|
var readStoredCameraType = () => {
|
|
54782
56028
|
if (typeof window === "undefined") return void 0;
|
|
@@ -54784,6 +56030,18 @@ var readStoredCameraType = () => {
|
|
|
54784
56030
|
return stored === "orthographic" || stored === "perspective" ? stored : void 0;
|
|
54785
56031
|
};
|
|
54786
56032
|
var CadViewerInner = (props) => {
|
|
56033
|
+
const childrenCircuitJson = useConvertChildrenToCircuitJson(
|
|
56034
|
+
props.circuitJson ? void 0 : props.children
|
|
56035
|
+
);
|
|
56036
|
+
const circuitJson = props.circuitJson ?? childrenCircuitJson;
|
|
56037
|
+
const hasBends = circuitJson.some((element) => element.type === "pcb_bend");
|
|
56038
|
+
const hasFlexGeometry = hasBends || circuitJson.some((element) => element.type === "pcb_stiffener");
|
|
56039
|
+
const [foldPcbsOverride, setFoldPcbs] = useState39(
|
|
56040
|
+
void 0
|
|
56041
|
+
);
|
|
56042
|
+
const foldPcbs = foldPcbsOverride ?? props.foldPcbs;
|
|
56043
|
+
const resolvedFoldPcbs = resolveFoldPcbs(circuitJson, foldPcbs);
|
|
56044
|
+
const resolvedProps = { ...props, circuitJson, children: void 0 };
|
|
54787
56045
|
const [engine, setEngine] = useState39(() => {
|
|
54788
56046
|
const stored = window.localStorage.getItem("cadViewerEngine");
|
|
54789
56047
|
return stored === "jscad" || stored === "manifold" ? stored : "manifold";
|
|
@@ -54947,10 +56205,20 @@ var CadViewerInner = (props) => {
|
|
|
54947
56205
|
},
|
|
54948
56206
|
...contextMenuEventHandlers,
|
|
54949
56207
|
children: [
|
|
54950
|
-
|
|
56208
|
+
hasFlexGeometry ? /* @__PURE__ */ jsx37(
|
|
56209
|
+
CadViewerManifold_default,
|
|
56210
|
+
{
|
|
56211
|
+
...resolvedProps,
|
|
56212
|
+
foldPcbs,
|
|
56213
|
+
autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
|
|
56214
|
+
onUserInteraction: handleUserInteraction,
|
|
56215
|
+
onCameraControllerReady: handleCameraControllerReady,
|
|
56216
|
+
referenceObject
|
|
56217
|
+
}
|
|
56218
|
+
) : engine === "jscad" ? /* @__PURE__ */ jsx37(
|
|
54951
56219
|
CadViewerJscad,
|
|
54952
56220
|
{
|
|
54953
|
-
...
|
|
56221
|
+
...resolvedProps,
|
|
54954
56222
|
autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
|
|
54955
56223
|
cameraType,
|
|
54956
56224
|
onUserInteraction: handleUserInteraction,
|
|
@@ -54960,7 +56228,7 @@ var CadViewerInner = (props) => {
|
|
|
54960
56228
|
) : /* @__PURE__ */ jsx37(
|
|
54961
56229
|
CadViewerManifold_default,
|
|
54962
56230
|
{
|
|
54963
|
-
...
|
|
56231
|
+
...resolvedProps,
|
|
54964
56232
|
autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
|
|
54965
56233
|
cameraType,
|
|
54966
56234
|
onUserInteraction: handleUserInteraction,
|
|
@@ -54974,6 +56242,13 @@ var CadViewerInner = (props) => {
|
|
|
54974
56242
|
menuRef,
|
|
54975
56243
|
menuPos,
|
|
54976
56244
|
engine,
|
|
56245
|
+
flexScene: hasFlexGeometry,
|
|
56246
|
+
foldPcbs: resolvedFoldPcbs,
|
|
56247
|
+
onFoldPcbsToggle: hasBends ? () => {
|
|
56248
|
+
setFoldPcbs(!resolvedFoldPcbs);
|
|
56249
|
+
setCameraPreset("Custom");
|
|
56250
|
+
closeMenu();
|
|
56251
|
+
} : void 0,
|
|
54977
56252
|
cameraPreset,
|
|
54978
56253
|
autoRotate,
|
|
54979
56254
|
referenceObject,
|
|
@@ -55035,14 +56310,14 @@ var CadViewer = (props) => {
|
|
|
55035
56310
|
// src/convert-circuit-json-to-3d-svg.ts
|
|
55036
56311
|
var import_debug = __toESM(require_browser(), 1);
|
|
55037
56312
|
import { su as su18 } from "@tscircuit/circuit-json-util";
|
|
55038
|
-
import * as
|
|
56313
|
+
import * as THREE56 from "three";
|
|
55039
56314
|
import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
|
|
55040
56315
|
|
|
55041
56316
|
// src/utils/create-geometry-from-polygons.ts
|
|
55042
|
-
import * as
|
|
55043
|
-
import { BufferGeometry as
|
|
56317
|
+
import * as THREE53 from "three";
|
|
56318
|
+
import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
|
|
55044
56319
|
function createGeometryFromPolygons(polygons) {
|
|
55045
|
-
const geometry = new
|
|
56320
|
+
const geometry = new BufferGeometry6();
|
|
55046
56321
|
const vertices = [];
|
|
55047
56322
|
const normals = [];
|
|
55048
56323
|
for (const polygon2 of polygons) {
|
|
@@ -55053,12 +56328,12 @@ function createGeometryFromPolygons(polygons) {
|
|
|
55053
56328
|
...polygon2.vertices[i + 1]
|
|
55054
56329
|
// Third vertex
|
|
55055
56330
|
);
|
|
55056
|
-
const v1 = new
|
|
55057
|
-
const v2 = new
|
|
55058
|
-
const v3 = new
|
|
55059
|
-
const normal = new
|
|
55060
|
-
new
|
|
55061
|
-
new
|
|
56331
|
+
const v1 = new THREE53.Vector3(...polygon2.vertices[0]);
|
|
56332
|
+
const v2 = new THREE53.Vector3(...polygon2.vertices[i]);
|
|
56333
|
+
const v3 = new THREE53.Vector3(...polygon2.vertices[i + 1]);
|
|
56334
|
+
const normal = new THREE53.Vector3().crossVectors(
|
|
56335
|
+
new THREE53.Vector3().subVectors(v2, v1),
|
|
56336
|
+
new THREE53.Vector3().subVectors(v3, v1)
|
|
55062
56337
|
).normalize();
|
|
55063
56338
|
normals.push(
|
|
55064
56339
|
normal.x,
|
|
@@ -55073,8 +56348,8 @@ function createGeometryFromPolygons(polygons) {
|
|
|
55073
56348
|
);
|
|
55074
56349
|
}
|
|
55075
56350
|
}
|
|
55076
|
-
geometry.setAttribute("position", new
|
|
55077
|
-
geometry.setAttribute("normal", new
|
|
56351
|
+
geometry.setAttribute("position", new Float32BufferAttribute5(vertices, 3));
|
|
56352
|
+
geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
|
|
55078
56353
|
return geometry;
|
|
55079
56354
|
}
|
|
55080
56355
|
|
|
@@ -55082,10 +56357,10 @@ function createGeometryFromPolygons(polygons) {
|
|
|
55082
56357
|
var import_modeling2 = __toESM(require_src(), 1);
|
|
55083
56358
|
var import_jscad_planner2 = __toESM(require_dist(), 1);
|
|
55084
56359
|
var jscadModeling2 = __toESM(require_src(), 1);
|
|
55085
|
-
import * as
|
|
56360
|
+
import * as THREE55 from "three";
|
|
55086
56361
|
|
|
55087
56362
|
// src/utils/load-model.ts
|
|
55088
|
-
import * as
|
|
56363
|
+
import * as THREE54 from "three";
|
|
55089
56364
|
import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
55090
56365
|
import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
|
|
55091
56366
|
import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
|
|
@@ -55093,12 +56368,12 @@ async function load3DModel(url) {
|
|
|
55093
56368
|
if (url.endsWith(".stl")) {
|
|
55094
56369
|
const loader = new STLLoader2();
|
|
55095
56370
|
const geometry = await loader.loadAsync(url);
|
|
55096
|
-
const material = new
|
|
56371
|
+
const material = new THREE54.MeshStandardMaterial({
|
|
55097
56372
|
color: 8947848,
|
|
55098
56373
|
metalness: 0.5,
|
|
55099
56374
|
roughness: 0.5
|
|
55100
56375
|
});
|
|
55101
|
-
return new
|
|
56376
|
+
return new THREE54.Mesh(geometry, material);
|
|
55102
56377
|
}
|
|
55103
56378
|
if (url.endsWith(".obj")) {
|
|
55104
56379
|
const loader = new OBJLoader2();
|
|
@@ -55131,9 +56406,9 @@ async function renderComponent(component, scene) {
|
|
|
55131
56406
|
}
|
|
55132
56407
|
if (component.rotation) {
|
|
55133
56408
|
model.rotation.set(
|
|
55134
|
-
|
|
55135
|
-
|
|
55136
|
-
|
|
56409
|
+
THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
56410
|
+
THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
56411
|
+
THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
55137
56412
|
);
|
|
55138
56413
|
}
|
|
55139
56414
|
scene.add(model);
|
|
@@ -55147,13 +56422,13 @@ async function renderComponent(component, scene) {
|
|
|
55147
56422
|
);
|
|
55148
56423
|
if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
|
|
55149
56424
|
const threeGeom = convertCSGToThreeGeom(jscadObject);
|
|
55150
|
-
const material2 = new
|
|
56425
|
+
const material2 = new THREE55.MeshStandardMaterial({
|
|
55151
56426
|
color: 8947848,
|
|
55152
56427
|
metalness: 0.5,
|
|
55153
56428
|
roughness: 0.5,
|
|
55154
|
-
side:
|
|
56429
|
+
side: THREE55.DoubleSide
|
|
55155
56430
|
});
|
|
55156
|
-
const mesh2 = new
|
|
56431
|
+
const mesh2 = new THREE55.Mesh(threeGeom, material2);
|
|
55157
56432
|
if (component.position) {
|
|
55158
56433
|
mesh2.position.set(
|
|
55159
56434
|
component.position.x ?? 0,
|
|
@@ -55163,9 +56438,9 @@ async function renderComponent(component, scene) {
|
|
|
55163
56438
|
}
|
|
55164
56439
|
if (component.rotation) {
|
|
55165
56440
|
mesh2.rotation.set(
|
|
55166
|
-
|
|
55167
|
-
|
|
55168
|
-
|
|
56441
|
+
THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
56442
|
+
THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
56443
|
+
THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
55169
56444
|
);
|
|
55170
56445
|
}
|
|
55171
56446
|
scene.add(mesh2);
|
|
@@ -55182,17 +56457,17 @@ async function renderComponent(component, scene) {
|
|
|
55182
56457
|
if (!geom || !geom.polygons && !geom.sides) {
|
|
55183
56458
|
continue;
|
|
55184
56459
|
}
|
|
55185
|
-
const color = new
|
|
56460
|
+
const color = new THREE55.Color(geomInfo.color);
|
|
55186
56461
|
color.convertLinearToSRGB();
|
|
55187
56462
|
const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
|
|
55188
56463
|
const threeGeom = convertCSGToThreeGeom(geomWithColor);
|
|
55189
|
-
const material2 = new
|
|
56464
|
+
const material2 = new THREE55.MeshStandardMaterial({
|
|
55190
56465
|
vertexColors: true,
|
|
55191
56466
|
metalness: 0.2,
|
|
55192
56467
|
roughness: 0.8,
|
|
55193
|
-
side:
|
|
56468
|
+
side: THREE55.DoubleSide
|
|
55194
56469
|
});
|
|
55195
|
-
const mesh2 = new
|
|
56470
|
+
const mesh2 = new THREE55.Mesh(threeGeom, material2);
|
|
55196
56471
|
if (component.position) {
|
|
55197
56472
|
mesh2.position.set(
|
|
55198
56473
|
component.position.x ?? 0,
|
|
@@ -55202,22 +56477,22 @@ async function renderComponent(component, scene) {
|
|
|
55202
56477
|
}
|
|
55203
56478
|
if (component.rotation) {
|
|
55204
56479
|
mesh2.rotation.set(
|
|
55205
|
-
|
|
55206
|
-
|
|
55207
|
-
|
|
56480
|
+
THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
56481
|
+
THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
56482
|
+
THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
55208
56483
|
);
|
|
55209
56484
|
}
|
|
55210
56485
|
scene.add(mesh2);
|
|
55211
56486
|
}
|
|
55212
56487
|
return;
|
|
55213
56488
|
}
|
|
55214
|
-
const geometry = new
|
|
55215
|
-
const material = new
|
|
56489
|
+
const geometry = new THREE55.BoxGeometry(0.5, 0.5, 0.5);
|
|
56490
|
+
const material = new THREE55.MeshStandardMaterial({
|
|
55216
56491
|
color: 16711680,
|
|
55217
56492
|
transparent: true,
|
|
55218
56493
|
opacity: 0.25
|
|
55219
56494
|
});
|
|
55220
|
-
const mesh = new
|
|
56495
|
+
const mesh = new THREE55.Mesh(geometry, material);
|
|
55221
56496
|
if (component.position) {
|
|
55222
56497
|
mesh.position.set(
|
|
55223
56498
|
component.position.x ?? 0,
|
|
@@ -55238,11 +56513,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
55238
56513
|
padding = 20,
|
|
55239
56514
|
zoom = 1.5
|
|
55240
56515
|
} = options;
|
|
55241
|
-
const scene = new
|
|
56516
|
+
const scene = new THREE56.Scene();
|
|
55242
56517
|
const renderer = new SVGRenderer();
|
|
55243
56518
|
renderer.setSize(width10, height10);
|
|
55244
|
-
renderer.setClearColor(new
|
|
55245
|
-
const camera = new
|
|
56519
|
+
renderer.setClearColor(new THREE56.Color(backgroundColor), 1);
|
|
56520
|
+
const camera = new THREE56.OrthographicCamera();
|
|
55246
56521
|
const aspect = width10 / height10;
|
|
55247
56522
|
const frustumSize = 100;
|
|
55248
56523
|
const halfFrustumSize = frustumSize / 2 / zoom;
|
|
@@ -55256,11 +56531,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
55256
56531
|
camera.position.set(position.x, position.y, position.z);
|
|
55257
56532
|
camera.up.set(0, 1, 0);
|
|
55258
56533
|
const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
|
|
55259
|
-
camera.lookAt(new
|
|
56534
|
+
camera.lookAt(new THREE56.Vector3(lookAt.x, lookAt.y, lookAt.z));
|
|
55260
56535
|
camera.updateProjectionMatrix();
|
|
55261
|
-
const ambientLight = new
|
|
56536
|
+
const ambientLight = new THREE56.AmbientLight(16777215, Math.PI / 2);
|
|
55262
56537
|
scene.add(ambientLight);
|
|
55263
|
-
const pointLight = new
|
|
56538
|
+
const pointLight = new THREE56.PointLight(16777215, Math.PI / 4);
|
|
55264
56539
|
pointLight.position.set(-10, -10, 10);
|
|
55265
56540
|
scene.add(pointLight);
|
|
55266
56541
|
const components = su18(circuitJson).cad_component.list();
|
|
@@ -55285,28 +56560,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
55285
56560
|
const material = createBoardMaterial({
|
|
55286
56561
|
material: boardData?.material,
|
|
55287
56562
|
color: edgeColor,
|
|
55288
|
-
side:
|
|
56563
|
+
side: THREE56.DoubleSide
|
|
55289
56564
|
});
|
|
55290
|
-
const mesh = new
|
|
56565
|
+
const mesh = new THREE56.Mesh(geometry, material);
|
|
55291
56566
|
scene.add(mesh);
|
|
55292
56567
|
}
|
|
55293
56568
|
}
|
|
55294
|
-
const gridColor = new
|
|
55295
|
-
const gridHelper = new
|
|
56569
|
+
const gridColor = new THREE56.Color(8947848);
|
|
56570
|
+
const gridHelper = new THREE56.GridHelper(100, 100, gridColor, gridColor);
|
|
55296
56571
|
gridHelper.rotation.x = Math.PI / 2;
|
|
55297
56572
|
const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
|
|
55298
56573
|
for (const mat of materials) {
|
|
55299
56574
|
mat.transparent = true;
|
|
55300
56575
|
mat.opacity = 0.3;
|
|
55301
|
-
if (mat instanceof
|
|
56576
|
+
if (mat instanceof THREE56.LineBasicMaterial) {
|
|
55302
56577
|
mat.color = gridColor;
|
|
55303
56578
|
mat.vertexColors = false;
|
|
55304
56579
|
}
|
|
55305
56580
|
}
|
|
55306
56581
|
scene.add(gridHelper);
|
|
55307
|
-
const box = new
|
|
55308
|
-
const center = box.getCenter(new
|
|
55309
|
-
const size4 = box.getSize(new
|
|
56582
|
+
const box = new THREE56.Box3().setFromObject(scene);
|
|
56583
|
+
const center = box.getCenter(new THREE56.Vector3());
|
|
56584
|
+
const size4 = box.getSize(new THREE56.Vector3());
|
|
55310
56585
|
scene.position.sub(center);
|
|
55311
56586
|
const maxDim = Math.max(size4.x, size4.y, size4.z);
|
|
55312
56587
|
if (maxDim > 0) {
|