@tscircuit/3d-viewer 0.0.604 → 0.0.606
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1723 -477
- package/package.json +7 -6
package/dist/index.js
CHANGED
|
@@ -215,8 +215,8 @@ var require_invert = __commonJS({
|
|
|
215
215
|
var require_equals = __commonJS({
|
|
216
216
|
"node_modules/@jscad/modeling/src/maths/mat4/equals.js"(exports, module) {
|
|
217
217
|
"use strict";
|
|
218
|
-
var
|
|
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,9 +14431,29 @@ var require_browser = __commonJS({
|
|
|
14431
14431
|
}
|
|
14432
14432
|
});
|
|
14433
14433
|
|
|
14434
|
+
// src/utils/resolve-fold-pcbs.ts
|
|
14435
|
+
function resolveFoldPcbs(circuitJson, foldPcbs) {
|
|
14436
|
+
return foldPcbs ?? circuitJson.some(
|
|
14437
|
+
(element) => element.type === "cad_component" && element.is_on_folded_board === true
|
|
14438
|
+
);
|
|
14439
|
+
}
|
|
14440
|
+
|
|
14434
14441
|
// src/CadViewer.tsx
|
|
14435
14442
|
import { useCallback as useCallback24, useEffect as useEffect49, useRef as useRef29, useState as useState39 } from "react";
|
|
14436
|
-
import * as
|
|
14443
|
+
import * as THREE52 from "three";
|
|
14444
|
+
|
|
14445
|
+
// src/hooks/use-convert-children-to-soup.ts
|
|
14446
|
+
import { Circuit } from "@tscircuit/core";
|
|
14447
|
+
import { useMemo } from "react";
|
|
14448
|
+
var useConvertChildrenToCircuitJson = (children) => {
|
|
14449
|
+
return useMemo(() => {
|
|
14450
|
+
if (!children) return [];
|
|
14451
|
+
const circuit = new Circuit();
|
|
14452
|
+
circuit.add(children);
|
|
14453
|
+
circuit.render();
|
|
14454
|
+
return circuit.getCircuitJson();
|
|
14455
|
+
}, [children]);
|
|
14456
|
+
};
|
|
14437
14457
|
|
|
14438
14458
|
// src/CadViewerJscad.tsx
|
|
14439
14459
|
import { su as su12 } from "@tscircuit/circuit-json-util";
|
|
@@ -14457,7 +14477,7 @@ var getCadPcbContext = (cad, circuitJson) => {
|
|
|
14457
14477
|
|
|
14458
14478
|
// src/AnyCadComponent.tsx
|
|
14459
14479
|
import { su as su2 } from "@tscircuit/circuit-json-util";
|
|
14460
|
-
import { useCallback as useCallback3, useEffect as useEffect11, useMemo as
|
|
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.605",
|
|
39208
39228
|
repository: {
|
|
39209
39229
|
type: "git",
|
|
39210
39230
|
url: "https://github.com/tscircuit/3d-viewer"
|
|
@@ -39242,7 +39262,7 @@ var package_default = {
|
|
|
39242
39262
|
dependencies: {
|
|
39243
39263
|
"@jscad/regl-renderer": "^2.6.12",
|
|
39244
39264
|
"@jscad/stl-serializer": "^2.1.20",
|
|
39245
|
-
"circuit-json": "^0.0.
|
|
39265
|
+
"circuit-json": "^0.0.500",
|
|
39246
39266
|
"circuit-to-canvas": "^0.0.131",
|
|
39247
39267
|
"react-hot-toast": "^2.6.0",
|
|
39248
39268
|
three: "^0.165.0",
|
|
@@ -39257,6 +39277,7 @@ var package_default = {
|
|
|
39257
39277
|
"@tscircuit/circuit-json-util": "*"
|
|
39258
39278
|
},
|
|
39259
39279
|
devDependencies: {
|
|
39280
|
+
"@tscircuit/flex-utils": "https://jscdn.tscircuit.com/@tscircuit/flex-utils/0.0.5.tgz",
|
|
39260
39281
|
"@biomejs/biome": "^2.1.4",
|
|
39261
39282
|
"@chromatic-com/storybook": "^1.9.0",
|
|
39262
39283
|
"@jscad/modeling": "^2.12.5",
|
|
@@ -39266,7 +39287,10 @@ var package_default = {
|
|
|
39266
39287
|
"@storybook/blocks": "9.0.0-alpha.17",
|
|
39267
39288
|
"@storybook/react-vite": "^9.1.5",
|
|
39268
39289
|
"@tscircuit/alphabet": "^0.0.25",
|
|
39290
|
+
"@tscircuit/circuit-json-util": "^0.0.116",
|
|
39269
39291
|
"@tscircuit/copper-pour-solver": "^0.0.29",
|
|
39292
|
+
"@tscircuit/core": "^0.0.1964",
|
|
39293
|
+
"@tscircuit/props": "^0.0.666",
|
|
39270
39294
|
"@tscircuit/solver-utils": "^0.0.4",
|
|
39271
39295
|
"@types/jsdom": "^21.1.7",
|
|
39272
39296
|
"@types/react": "19",
|
|
@@ -39275,7 +39299,6 @@ var package_default = {
|
|
|
39275
39299
|
"@vitejs/plugin-react": "^4.3.4",
|
|
39276
39300
|
"bun-match-svg": "^0.0.9",
|
|
39277
39301
|
"bun-types": "1.2.1",
|
|
39278
|
-
"circuit-json-to-gltf": "0.0.129",
|
|
39279
39302
|
debug: "^4.4.0",
|
|
39280
39303
|
"jscad-electronics": "^0.0.178",
|
|
39281
39304
|
"jscad-planner": "^0.0.13",
|
|
@@ -39289,9 +39312,7 @@ var package_default = {
|
|
|
39289
39312
|
typescript: "^5.7.3",
|
|
39290
39313
|
vite: "^7.1.5",
|
|
39291
39314
|
"vite-tsconfig-paths": "^4.3.2",
|
|
39292
|
-
"
|
|
39293
|
-
"@tscircuit/props": "^0.0.664",
|
|
39294
|
-
"@tscircuit/circuit-json-util": "^0.0.116"
|
|
39315
|
+
"circuit-json-to-gltf": "0.0.129"
|
|
39295
39316
|
},
|
|
39296
39317
|
patchedDependencies: {
|
|
39297
39318
|
"@tscircuit/fanout-solver@0.0.78": "patches/@tscircuit%2Ffanout-solver@0.0.78.patch"
|
|
@@ -39299,7 +39320,7 @@ var package_default = {
|
|
|
39299
39320
|
};
|
|
39300
39321
|
|
|
39301
39322
|
// src/contexts/appearance-context.tsx
|
|
39302
|
-
import { createContext as createContext4, useContext as useContext4, useEffect as useEffect12, useMemo as
|
|
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
|
}
|
|
@@ -39851,16 +39872,23 @@ var Canvas = forwardRef(
|
|
|
39851
39872
|
onCreatedRef.current?.({ camera, renderer });
|
|
39852
39873
|
let animationFrameId;
|
|
39853
39874
|
const clock = new THREE16.Clock();
|
|
39875
|
+
let isVisible = true;
|
|
39876
|
+
const visibilityObserver = new IntersectionObserver(([entry]) => {
|
|
39877
|
+
isVisible = entry?.isIntersecting ?? false;
|
|
39878
|
+
if (isVisible) handleResize();
|
|
39879
|
+
});
|
|
39880
|
+
visibilityObserver.observe(mountRef.current);
|
|
39854
39881
|
const animate = () => {
|
|
39882
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
39883
|
+
if (!isVisible) return;
|
|
39855
39884
|
const time = clock.getElapsedTime();
|
|
39856
39885
|
const delta = clock.getDelta();
|
|
39857
39886
|
frameListeners.current.forEach((listener) => listener(time, delta));
|
|
39858
39887
|
renderer.render(scene, camera);
|
|
39859
|
-
animationFrameId = requestAnimationFrame(animate);
|
|
39860
39888
|
};
|
|
39861
39889
|
animate();
|
|
39862
39890
|
const handleResize = () => {
|
|
39863
|
-
if (mountRef.current) {
|
|
39891
|
+
if (mountRef.current?.clientWidth && mountRef.current.clientHeight) {
|
|
39864
39892
|
const newAspect = mountRef.current.clientWidth / mountRef.current.clientHeight;
|
|
39865
39893
|
if (camera instanceof THREE16.PerspectiveCamera) {
|
|
39866
39894
|
camera.aspect = newAspect;
|
|
@@ -39886,6 +39914,7 @@ var Canvas = forwardRef(
|
|
|
39886
39914
|
};
|
|
39887
39915
|
window.removeEventListener("resize", handleResize);
|
|
39888
39916
|
cancelAnimationFrame(animationFrameId);
|
|
39917
|
+
visibilityObserver.disconnect();
|
|
39889
39918
|
if (mountRef.current && renderer.domElement) {
|
|
39890
39919
|
mountRef.current.removeChild(renderer.domElement);
|
|
39891
39920
|
}
|
|
@@ -39901,7 +39930,7 @@ var Canvas = forwardRef(
|
|
|
39901
39930
|
);
|
|
39902
39931
|
|
|
39903
39932
|
// src/react-three/Grid.tsx
|
|
39904
|
-
import { useEffect as useEffect15, useMemo as
|
|
39933
|
+
import { useEffect as useEffect15, useMemo as useMemo13 } from "react";
|
|
39905
39934
|
import * as THREE17 from "three";
|
|
39906
39935
|
var vertexShader = `
|
|
39907
39936
|
varying vec3 worldPosition;
|
|
@@ -39947,7 +39976,7 @@ var Grid = ({
|
|
|
39947
39976
|
}) => {
|
|
39948
39977
|
const { scene, camera } = useThree();
|
|
39949
39978
|
const size4 = 1e3;
|
|
39950
|
-
const gridMesh =
|
|
39979
|
+
const gridMesh = useMemo13(() => {
|
|
39951
39980
|
const geometry = new THREE17.PlaneGeometry(size4, size4);
|
|
39952
39981
|
geometry.rotateX(-Math.PI / 2);
|
|
39953
39982
|
const material = new THREE17.ShaderMaterial({
|
|
@@ -39993,7 +40022,7 @@ var Grid = ({
|
|
|
39993
40022
|
};
|
|
39994
40023
|
|
|
39995
40024
|
// src/react-three/Lights.tsx
|
|
39996
|
-
import { useEffect as useEffect16, useMemo as
|
|
40025
|
+
import { useEffect as useEffect16, useMemo as useMemo14 } from "react";
|
|
39997
40026
|
import * as THREE18 from "three";
|
|
39998
40027
|
var UNDERSIDE_LIGHT_FACTOR = 0.75;
|
|
39999
40028
|
var Lights = ({
|
|
@@ -40003,7 +40032,7 @@ var Lights = ({
|
|
|
40003
40032
|
shadowsEnabled = false
|
|
40004
40033
|
}) => {
|
|
40005
40034
|
const { scene } = useThree();
|
|
40006
|
-
const lightRig =
|
|
40035
|
+
const lightRig = useMemo14(() => {
|
|
40007
40036
|
const rig = new THREE18.Group();
|
|
40008
40037
|
rig.name = "cad-viewer-light-rig";
|
|
40009
40038
|
const centerX = boardCenter?.x ?? 0;
|
|
@@ -40118,7 +40147,7 @@ var Lights = ({
|
|
|
40118
40147
|
};
|
|
40119
40148
|
|
|
40120
40149
|
// src/react-three/OrbitControls.tsx
|
|
40121
|
-
import { useEffect as useEffect17, useMemo as
|
|
40150
|
+
import { useEffect as useEffect17, useMemo as useMemo15 } from "react";
|
|
40122
40151
|
import * as THREE19 from "three";
|
|
40123
40152
|
import { OrbitControls as ThreeOrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
|
40124
40153
|
var OrbitControls = ({
|
|
@@ -40134,7 +40163,7 @@ var OrbitControls = ({
|
|
|
40134
40163
|
onControlsChange
|
|
40135
40164
|
}) => {
|
|
40136
40165
|
const { camera, renderer } = useThree();
|
|
40137
|
-
const controls =
|
|
40166
|
+
const controls = useMemo15(() => {
|
|
40138
40167
|
if (!camera || !renderer) return null;
|
|
40139
40168
|
return new ThreeOrbitControls(camera, renderer.domElement);
|
|
40140
40169
|
}, [camera, renderer]);
|
|
@@ -40383,7 +40412,14 @@ var OrientationCubeCanvas = () => {
|
|
|
40383
40412
|
group.add(topText);
|
|
40384
40413
|
group.add(bottomText);
|
|
40385
40414
|
let animationFrameId = null;
|
|
40415
|
+
let isVisible = true;
|
|
40416
|
+
const visibilityObserver = new IntersectionObserver(([entry]) => {
|
|
40417
|
+
isVisible = entry?.isIntersecting ?? false;
|
|
40418
|
+
});
|
|
40419
|
+
visibilityObserver.observe(canvas);
|
|
40386
40420
|
const animate = () => {
|
|
40421
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
40422
|
+
if (!isVisible) return;
|
|
40387
40423
|
if (mainCameraRef.current) {
|
|
40388
40424
|
const cameraPosition = computePointInFront(
|
|
40389
40425
|
mainCameraRef.current.rotation ?? new THREE20.Euler(0, 0, 0),
|
|
@@ -40395,10 +40431,10 @@ var OrientationCubeCanvas = () => {
|
|
|
40395
40431
|
}
|
|
40396
40432
|
}
|
|
40397
40433
|
renderer.render(scene, camera);
|
|
40398
|
-
animationFrameId = requestAnimationFrame(animate);
|
|
40399
40434
|
};
|
|
40400
40435
|
animate();
|
|
40401
40436
|
return () => {
|
|
40437
|
+
visibilityObserver.disconnect();
|
|
40402
40438
|
canvas.remove();
|
|
40403
40439
|
if (animationFrameId !== null) {
|
|
40404
40440
|
cancelAnimationFrame(animationFrameId);
|
|
@@ -40435,7 +40471,7 @@ var OrientationCubeCanvas = () => {
|
|
|
40435
40471
|
};
|
|
40436
40472
|
|
|
40437
40473
|
// src/three-components/reference-object.tsx
|
|
40438
|
-
import { useEffect as useEffect19, useMemo as
|
|
40474
|
+
import { useEffect as useEffect19, useMemo as useMemo16 } from "react";
|
|
40439
40475
|
|
|
40440
40476
|
// src/reference-objects/create-reference-object.ts
|
|
40441
40477
|
import * as THREE21 from "three";
|
|
@@ -40821,7 +40857,7 @@ var ReferenceObject = ({
|
|
|
40821
40857
|
boardCenter
|
|
40822
40858
|
}) => {
|
|
40823
40859
|
const { scene } = useThree();
|
|
40824
|
-
const object =
|
|
40860
|
+
const object = useMemo16(() => {
|
|
40825
40861
|
const nextObject = createReferenceObject(type);
|
|
40826
40862
|
const position = getReferenceObjectPosition(
|
|
40827
40863
|
type,
|
|
@@ -40887,17 +40923,17 @@ var CadViewerContainer = forwardRef2(
|
|
|
40887
40923
|
onCameraControllerReady(controller);
|
|
40888
40924
|
}
|
|
40889
40925
|
}, [controller, onCameraControllerReady]);
|
|
40890
|
-
const comparisonBounds =
|
|
40926
|
+
const comparisonBounds = useMemo17(() => {
|
|
40891
40927
|
if (!referenceObject) return void 0;
|
|
40892
40928
|
return getComparisonBounds(referenceObject, boardDimensions, boardCenter);
|
|
40893
40929
|
}, [referenceObject, boardDimensions, boardCenter]);
|
|
40894
|
-
const gridSectionSize =
|
|
40930
|
+
const gridSectionSize = useMemo17(() => {
|
|
40895
40931
|
if (!boardDimensions) return 10;
|
|
40896
40932
|
const width10 = boardDimensions.width ?? 0;
|
|
40897
40933
|
const height10 = boardDimensions.height ?? 0;
|
|
40898
40934
|
return Math.max(Math.max(width10, height10) * 1.5, 10);
|
|
40899
40935
|
}, [boardDimensions]);
|
|
40900
|
-
const orbitTarget =
|
|
40936
|
+
const orbitTarget = useMemo17(() => {
|
|
40901
40937
|
if (comparisonBounds) {
|
|
40902
40938
|
return [
|
|
40903
40939
|
(comparisonBounds.minX + comparisonBounds.maxX) / 2,
|
|
@@ -41030,19 +41066,6 @@ var CadViewerContainer = forwardRef2(
|
|
|
41030
41066
|
}
|
|
41031
41067
|
);
|
|
41032
41068
|
|
|
41033
|
-
// src/hooks/use-convert-children-to-soup.ts
|
|
41034
|
-
import { Circuit } from "@tscircuit/core";
|
|
41035
|
-
import { useMemo as useMemo17 } from "react";
|
|
41036
|
-
var useConvertChildrenToCircuitJson = (children) => {
|
|
41037
|
-
return useMemo17(() => {
|
|
41038
|
-
if (!children) return [];
|
|
41039
|
-
const circuit = new Circuit();
|
|
41040
|
-
circuit.add(children);
|
|
41041
|
-
circuit.render();
|
|
41042
|
-
return circuit.getCircuitJson();
|
|
41043
|
-
}, [children]);
|
|
41044
|
-
};
|
|
41045
|
-
|
|
41046
41069
|
// src/hooks/use-stls-from-geom.ts
|
|
41047
41070
|
import { useState as useState12, useEffect as useEffect21 } from "react";
|
|
41048
41071
|
import stlSerializer from "@jscad/stl-serializer";
|
|
@@ -41091,14 +41114,14 @@ var import_primitives = __toESM(require_primitives(), 1);
|
|
|
41091
41114
|
var import_transforms = __toESM(require_transforms(), 1);
|
|
41092
41115
|
var import_expansions = __toESM(require_expansions(), 1);
|
|
41093
41116
|
var arePointsClockwise = (points) => {
|
|
41094
|
-
let
|
|
41117
|
+
let area2 = 0;
|
|
41095
41118
|
for (let i = 0; i < points.length; i++) {
|
|
41096
41119
|
const j = (i + 1) % points.length;
|
|
41097
|
-
|
|
41098
|
-
|
|
41120
|
+
area2 += points[i][0] * points[j][1];
|
|
41121
|
+
area2 -= points[j][0] * points[i][1];
|
|
41099
41122
|
}
|
|
41100
|
-
const
|
|
41101
|
-
return
|
|
41123
|
+
const signedArea2 = area2 / 2;
|
|
41124
|
+
return signedArea2 <= 0;
|
|
41102
41125
|
};
|
|
41103
41126
|
var createBoardGeomWithOutline = (board, depth = 1.2, options = {}) => {
|
|
41104
41127
|
const { xyOutset = 0 } = options;
|
|
@@ -41129,6 +41152,7 @@ var colors = {
|
|
|
41129
41152
|
fr4SolderMaskGreen: [0.06, 0.31, 0.19],
|
|
41130
41153
|
fr4TracesWithMaskGreen: [0.09, 0.38, 0.23],
|
|
41131
41154
|
fr4TracesWithoutMaskTan: [0.6, 0.43, 0.28],
|
|
41155
|
+
flexAmber: [0.8, 0.61, 0.2],
|
|
41132
41156
|
fr1Tan: [0.8, 0.4, 0.2],
|
|
41133
41157
|
fr1TracesWithMaskCopper: [0.9, 0.6, 0.2],
|
|
41134
41158
|
fr1SolderMaskGreen: [0.02, 0.1, 0.04]
|
|
@@ -41139,11 +41163,13 @@ var TRACE_TEXTURE_RESOLUTION = 150;
|
|
|
41139
41163
|
var FAUX_BOARD_OPACITY = 0.6;
|
|
41140
41164
|
var boardMaterialColors = {
|
|
41141
41165
|
fr1: colors.fr1Tan,
|
|
41142
|
-
fr4: colors.fr4Tan
|
|
41166
|
+
fr4: colors.fr4Tan,
|
|
41167
|
+
flex: colors.flexAmber
|
|
41143
41168
|
};
|
|
41144
41169
|
var soldermaskColors = {
|
|
41145
41170
|
fr1: colors.fr1SolderMaskGreen,
|
|
41146
|
-
fr4: colors.fr4SolderMaskGreen
|
|
41171
|
+
fr4: colors.fr4SolderMaskGreen,
|
|
41172
|
+
flex: colors.flexAmber
|
|
41147
41173
|
};
|
|
41148
41174
|
|
|
41149
41175
|
// src/utils/soldermask-color.ts
|
|
@@ -44646,6 +44672,7 @@ var createDataTexture = (canvas) => {
|
|
|
44646
44672
|
var createBoardReliefTextures = (texture, maskedCopperMask) => {
|
|
44647
44673
|
const sourceCanvas = texture.image;
|
|
44648
44674
|
if (!sourceCanvas?.width || !sourceCanvas.height) return null;
|
|
44675
|
+
const { width: canvasWidth, height: canvasHeight } = sourceCanvas;
|
|
44649
44676
|
const sourceCtx = sourceCanvas.getContext("2d");
|
|
44650
44677
|
if (!sourceCtx) return null;
|
|
44651
44678
|
const maskCanvas = maskedCopperMask?.image;
|
|
@@ -44653,48 +44680,37 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
|
|
|
44653
44680
|
const maskWidth = maskCanvas?.width ?? 0;
|
|
44654
44681
|
const maskHeight = maskCanvas?.height ?? 0;
|
|
44655
44682
|
const maskImageData = maskCtx && maskWidth && maskHeight ? maskCtx.getImageData(0, 0, maskWidth, maskHeight) : null;
|
|
44656
|
-
const imageData = sourceCtx.getImageData(
|
|
44657
|
-
0,
|
|
44658
|
-
0,
|
|
44659
|
-
sourceCanvas.width,
|
|
44660
|
-
sourceCanvas.height
|
|
44661
|
-
);
|
|
44683
|
+
const imageData = sourceCtx.getImageData(0, 0, canvasWidth, canvasHeight);
|
|
44662
44684
|
const data = imageData.data;
|
|
44663
|
-
const heights = new Float32Array(
|
|
44685
|
+
const heights = new Float32Array(canvasWidth * canvasHeight);
|
|
44664
44686
|
const roughnessCanvas = document.createElement("canvas");
|
|
44665
44687
|
const metalnessCanvas = document.createElement("canvas");
|
|
44666
|
-
roughnessCanvas.width = metalnessCanvas.width =
|
|
44667
|
-
roughnessCanvas.height = metalnessCanvas.height =
|
|
44688
|
+
roughnessCanvas.width = metalnessCanvas.width = canvasWidth;
|
|
44689
|
+
roughnessCanvas.height = metalnessCanvas.height = canvasHeight;
|
|
44668
44690
|
const roughnessCtx = roughnessCanvas.getContext("2d");
|
|
44669
44691
|
const metalnessCtx = metalnessCanvas.getContext("2d");
|
|
44670
44692
|
if (!roughnessCtx || !metalnessCtx) return null;
|
|
44671
44693
|
const roughnessImageData = roughnessCtx.createImageData(
|
|
44672
|
-
|
|
44673
|
-
|
|
44694
|
+
canvasWidth,
|
|
44695
|
+
canvasHeight
|
|
44674
44696
|
);
|
|
44675
44697
|
const metalnessImageData = metalnessCtx.createImageData(
|
|
44676
|
-
|
|
44677
|
-
|
|
44698
|
+
canvasWidth,
|
|
44699
|
+
canvasHeight
|
|
44678
44700
|
);
|
|
44679
44701
|
const roughnessData = roughnessImageData.data;
|
|
44680
44702
|
const metalnessData = metalnessImageData.data;
|
|
44681
44703
|
for (let i = 0; i < data.length; i += 4) {
|
|
44682
44704
|
const pixelIndex = i / 4;
|
|
44683
|
-
const x = pixelIndex %
|
|
44684
|
-
const y = Math.floor(pixelIndex /
|
|
44705
|
+
const x = pixelIndex % canvasWidth;
|
|
44706
|
+
const y = Math.floor(pixelIndex / canvasWidth);
|
|
44685
44707
|
const alpha = data[i + 3] ?? 0;
|
|
44686
44708
|
if (alpha < 16) {
|
|
44687
44709
|
heights[pixelIndex] = invertSurfaceHeight(PLAIN_SOLDERMASK_HEIGHT);
|
|
44688
44710
|
continue;
|
|
44689
44711
|
}
|
|
44690
|
-
const maskX = maskImageData ? Math.min(
|
|
44691
|
-
|
|
44692
|
-
Math.floor(x / sourceCanvas.width * maskWidth)
|
|
44693
|
-
) : 0;
|
|
44694
|
-
const maskY = maskImageData ? Math.min(
|
|
44695
|
-
maskHeight - 1,
|
|
44696
|
-
Math.floor(y / sourceCanvas.height * maskHeight)
|
|
44697
|
-
) : 0;
|
|
44712
|
+
const maskX = maskImageData ? Math.min(maskWidth - 1, Math.floor(x / canvasWidth * maskWidth)) : 0;
|
|
44713
|
+
const maskY = maskImageData ? Math.min(maskHeight - 1, Math.floor(y / canvasHeight * maskHeight)) : 0;
|
|
44698
44714
|
const maskAlpha = maskImageData ? maskImageData.data[(maskY * maskWidth + maskX) * 4 + 3] ?? 0 : 0;
|
|
44699
44715
|
const profile = getBoardSurfaceProfile(
|
|
44700
44716
|
data[i] ?? 0,
|
|
@@ -44702,13 +44718,13 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
|
|
|
44702
44718
|
data[i + 2] ?? 0,
|
|
44703
44719
|
maskAlpha >= 16
|
|
44704
44720
|
);
|
|
44705
|
-
const salt =
|
|
44721
|
+
const salt = canvasWidth + canvasHeight;
|
|
44706
44722
|
const fineGrain = profile.isExposedCopper ? createCopperDetail(x, y, salt) : profile.isMaskedCopper ? createMaskedTraceDetail(x, y, salt) : 0;
|
|
44707
|
-
const
|
|
44723
|
+
const surfaceHeight = clamp01(
|
|
44708
44724
|
invertSurfaceHeight(profile.height) + fineGrain * profile.microSurfaceWeight
|
|
44709
44725
|
);
|
|
44710
|
-
heights[pixelIndex] =
|
|
44711
|
-
const heightChannel =
|
|
44726
|
+
heights[pixelIndex] = surfaceHeight;
|
|
44727
|
+
const heightChannel = surfaceHeight * 255;
|
|
44712
44728
|
data[i] = data[i + 1] = data[i + 2] = heightChannel;
|
|
44713
44729
|
data[i + 3] = 255;
|
|
44714
44730
|
const roughness = profile.isExposedCopper ? clamp01(
|
|
@@ -44726,31 +44742,28 @@ var createBoardReliefTextures = (texture, maskedCopperMask) => {
|
|
|
44726
44742
|
roughnessCtx.putImageData(roughnessImageData, 0, 0);
|
|
44727
44743
|
metalnessCtx.putImageData(metalnessImageData, 0, 0);
|
|
44728
44744
|
const bumpCanvas = document.createElement("canvas");
|
|
44729
|
-
bumpCanvas.width =
|
|
44730
|
-
bumpCanvas.height =
|
|
44745
|
+
bumpCanvas.width = canvasWidth;
|
|
44746
|
+
bumpCanvas.height = canvasHeight;
|
|
44731
44747
|
const bumpCtx = bumpCanvas.getContext("2d");
|
|
44732
44748
|
if (!bumpCtx) return null;
|
|
44733
44749
|
bumpCtx.putImageData(imageData, 0, 0);
|
|
44734
44750
|
const normalCanvas = document.createElement("canvas");
|
|
44735
|
-
normalCanvas.width =
|
|
44736
|
-
normalCanvas.height =
|
|
44751
|
+
normalCanvas.width = canvasWidth;
|
|
44752
|
+
normalCanvas.height = canvasHeight;
|
|
44737
44753
|
const normalCtx = normalCanvas.getContext("2d");
|
|
44738
44754
|
if (!normalCtx) return null;
|
|
44739
|
-
const normalImageData = normalCtx.createImageData(
|
|
44740
|
-
sourceCanvas.width,
|
|
44741
|
-
sourceCanvas.height
|
|
44742
|
-
);
|
|
44755
|
+
const normalImageData = normalCtx.createImageData(canvasWidth, canvasHeight);
|
|
44743
44756
|
const normalData = normalImageData.data;
|
|
44744
|
-
const getHeight4 = (x, y) => heights[Math.max(0, Math.min(
|
|
44745
|
-
for (let y = 0; y <
|
|
44746
|
-
for (let x = 0; x <
|
|
44757
|
+
const getHeight4 = (x, y) => heights[Math.max(0, Math.min(canvasHeight - 1, y)) * canvasWidth + Math.max(0, Math.min(canvasWidth - 1, x))] ?? 0;
|
|
44758
|
+
for (let y = 0; y < canvasHeight; y++) {
|
|
44759
|
+
for (let x = 0; x < canvasWidth; x++) {
|
|
44747
44760
|
const dx = (getHeight4(x + 1, y) - getHeight4(x - 1, y)) * 4;
|
|
44748
44761
|
const dy = (getHeight4(x, y + 1) - getHeight4(x, y - 1)) * 4;
|
|
44749
|
-
const
|
|
44750
|
-
const i = (y *
|
|
44751
|
-
normalData[i] = (
|
|
44752
|
-
normalData[i + 1] = (
|
|
44753
|
-
normalData[i + 2] = (
|
|
44762
|
+
const inverseLength = 1 / Math.sqrt(dx * dx + dy * dy + 1);
|
|
44763
|
+
const i = (y * canvasWidth + x) * 4;
|
|
44764
|
+
normalData[i] = (-dx * inverseLength * 0.5 + 0.5) * 255;
|
|
44765
|
+
normalData[i + 1] = (-dy * inverseLength * 0.5 + 0.5) * 255;
|
|
44766
|
+
normalData[i + 2] = (inverseLength * 0.5 + 0.5) * 255;
|
|
44754
44767
|
normalData[i + 3] = 255;
|
|
44755
44768
|
}
|
|
44756
44769
|
}
|
|
@@ -45400,28 +45413,1149 @@ var CadViewerJscad = forwardRef3(
|
|
|
45400
45413
|
}
|
|
45401
45414
|
);
|
|
45402
45415
|
|
|
45416
|
+
// node_modules/earcut/src/earcut.js
|
|
45417
|
+
var steiners = /* @__PURE__ */ new Set();
|
|
45418
|
+
var filteredOut = false;
|
|
45419
|
+
function earcut(data, holeIndices, dim = 2) {
|
|
45420
|
+
const hasHoles = holeIndices && holeIndices.length;
|
|
45421
|
+
const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
|
|
45422
|
+
if (steiners.size) steiners.clear();
|
|
45423
|
+
let outerNode = linkedList(data, 0, outerLen, dim, true);
|
|
45424
|
+
const triangles = [];
|
|
45425
|
+
if (!outerNode || outerNode.next === outerNode.prev) return triangles;
|
|
45426
|
+
let minX = 0, minY = 0, invSize = 0;
|
|
45427
|
+
if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
|
|
45428
|
+
if (data.length > 80 * dim) {
|
|
45429
|
+
minX = data[0];
|
|
45430
|
+
minY = data[1];
|
|
45431
|
+
let maxX = minX;
|
|
45432
|
+
let maxY = minY;
|
|
45433
|
+
for (let i = dim; i < outerLen; i += dim) {
|
|
45434
|
+
const x = data[i];
|
|
45435
|
+
const y = data[i + 1];
|
|
45436
|
+
if (x < minX) minX = x;
|
|
45437
|
+
if (y < minY) minY = y;
|
|
45438
|
+
if (x > maxX) maxX = x;
|
|
45439
|
+
if (y > maxY) maxY = y;
|
|
45440
|
+
}
|
|
45441
|
+
invSize = Math.max(maxX - minX, maxY - minY);
|
|
45442
|
+
invSize = invSize !== 0 ? 32767 / invSize : 0;
|
|
45443
|
+
}
|
|
45444
|
+
earcutLinked(outerNode, triangles, minX, minY, invSize);
|
|
45445
|
+
return triangles;
|
|
45446
|
+
}
|
|
45447
|
+
function linkedList(data, start, end, dim, clockwise) {
|
|
45448
|
+
let last = null;
|
|
45449
|
+
if (clockwise === signedArea(data, start, end, dim) > 0) {
|
|
45450
|
+
for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
45451
|
+
} else {
|
|
45452
|
+
for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
45453
|
+
}
|
|
45454
|
+
if (last && equals(last, last.next)) {
|
|
45455
|
+
removeNode(last);
|
|
45456
|
+
last = last.next;
|
|
45457
|
+
}
|
|
45458
|
+
return last;
|
|
45459
|
+
}
|
|
45460
|
+
function filterPoints(start, end = start) {
|
|
45461
|
+
const full = end === start;
|
|
45462
|
+
let p = start, again;
|
|
45463
|
+
do {
|
|
45464
|
+
again = false;
|
|
45465
|
+
if (p !== p.next && (steiners.size === 0 || !steiners.has(p)) && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
|
|
45466
|
+
if (full || p === end) end = p.prev;
|
|
45467
|
+
filteredOut = true;
|
|
45468
|
+
removeNode(p);
|
|
45469
|
+
p = p.prev;
|
|
45470
|
+
again = true;
|
|
45471
|
+
} else if (full || p !== end) {
|
|
45472
|
+
p = p.next;
|
|
45473
|
+
again = !full;
|
|
45474
|
+
}
|
|
45475
|
+
} while (again || p !== end);
|
|
45476
|
+
return end;
|
|
45477
|
+
}
|
|
45478
|
+
function earcutLinked(ear, triangles, minX, minY, invSize) {
|
|
45479
|
+
if (invSize) indexCurve(ear, minX, minY, invSize);
|
|
45480
|
+
let stop = ear, cured = false;
|
|
45481
|
+
while (ear.prev !== ear.next) {
|
|
45482
|
+
const prev = ear.prev;
|
|
45483
|
+
const next = ear.next;
|
|
45484
|
+
if (area(prev, ear, next) < 0 && (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear))) {
|
|
45485
|
+
triangles.push(prev.i, ear.i, next.i);
|
|
45486
|
+
removeNode(ear);
|
|
45487
|
+
ear = next;
|
|
45488
|
+
stop = next;
|
|
45489
|
+
continue;
|
|
45490
|
+
}
|
|
45491
|
+
ear = next;
|
|
45492
|
+
if (ear === stop) {
|
|
45493
|
+
filteredOut = false;
|
|
45494
|
+
ear = filterPoints(ear);
|
|
45495
|
+
if (filteredOut) {
|
|
45496
|
+
stop = ear;
|
|
45497
|
+
continue;
|
|
45498
|
+
}
|
|
45499
|
+
if (!cured) {
|
|
45500
|
+
ear = cureLocalIntersections(ear, triangles);
|
|
45501
|
+
stop = ear;
|
|
45502
|
+
cured = true;
|
|
45503
|
+
continue;
|
|
45504
|
+
}
|
|
45505
|
+
splitEarcut(ear, triangles, minX, minY, invSize);
|
|
45506
|
+
break;
|
|
45507
|
+
}
|
|
45508
|
+
}
|
|
45509
|
+
}
|
|
45510
|
+
function isEar(ear) {
|
|
45511
|
+
const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy);
|
|
45512
|
+
let p = c.next;
|
|
45513
|
+
while (p !== a) {
|
|
45514
|
+
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
|
|
45515
|
+
p = p.next;
|
|
45516
|
+
}
|
|
45517
|
+
return true;
|
|
45518
|
+
}
|
|
45519
|
+
function isEarHashed(ear, minX, minY, invSize) {
|
|
45520
|
+
const a = ear.prev, b = ear, c = ear.next, ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y, x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy), minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize);
|
|
45521
|
+
let p = ear.prevZ;
|
|
45522
|
+
while (p && p.z >= minZ) {
|
|
45523
|
+
if (p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== c && !(ax === p.x && ay === p.y) && pointInTriangle(ax, ay, bx, by, cx, cy, p.x, p.y) && area(p.prev, p, p.next) >= 0) return false;
|
|
45524
|
+
p = p.prevZ;
|
|
45525
|
+
}
|
|
45526
|
+
let n = ear.nextZ;
|
|
45527
|
+
while (n && n.z <= maxZ) {
|
|
45528
|
+
if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== c && !(ax === n.x && ay === n.y) && pointInTriangle(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
|
|
45529
|
+
n = n.nextZ;
|
|
45530
|
+
}
|
|
45531
|
+
return true;
|
|
45532
|
+
}
|
|
45533
|
+
function cureLocalIntersections(start, triangles) {
|
|
45534
|
+
let p = start;
|
|
45535
|
+
let cured = false;
|
|
45536
|
+
do {
|
|
45537
|
+
const a = p.prev, b = p.next.next;
|
|
45538
|
+
if (intersects(a, p, p.next, b, false) && locallyInside(a, b) && locallyInside(b, a)) {
|
|
45539
|
+
triangles.push(a.i, p.i, b.i);
|
|
45540
|
+
removeNode(p);
|
|
45541
|
+
removeNode(p.next);
|
|
45542
|
+
p = start = b;
|
|
45543
|
+
cured = true;
|
|
45544
|
+
}
|
|
45545
|
+
p = p.next;
|
|
45546
|
+
} while (p !== start);
|
|
45547
|
+
return cured ? filterPoints(p) : p;
|
|
45548
|
+
}
|
|
45549
|
+
function splitEarcut(start, triangles, minX, minY, invSize) {
|
|
45550
|
+
let a = start;
|
|
45551
|
+
do {
|
|
45552
|
+
let b = a.next.next;
|
|
45553
|
+
while (b !== a.prev) {
|
|
45554
|
+
if (a.i !== b.i && isValidDiagonal(a, b)) {
|
|
45555
|
+
let c = splitPolygon(a, b);
|
|
45556
|
+
a = filterPoints(a, a.next);
|
|
45557
|
+
c = filterPoints(c, c.next);
|
|
45558
|
+
earcutLinked(a, triangles, minX, minY, invSize);
|
|
45559
|
+
earcutLinked(c, triangles, minX, minY, invSize);
|
|
45560
|
+
return;
|
|
45561
|
+
}
|
|
45562
|
+
b = b.next;
|
|
45563
|
+
}
|
|
45564
|
+
a = a.next;
|
|
45565
|
+
} while (a !== start);
|
|
45566
|
+
}
|
|
45567
|
+
var indexActive = false;
|
|
45568
|
+
function eliminateHoles(data, holeIndices, outerNode, dim) {
|
|
45569
|
+
const queue = [];
|
|
45570
|
+
for (let i = 0, len = holeIndices.length; i < len; i++) {
|
|
45571
|
+
const start = holeIndices[i] * dim;
|
|
45572
|
+
const end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
45573
|
+
const list = (
|
|
45574
|
+
/** @type {Node} */
|
|
45575
|
+
linkedList(data, start, end, dim, false)
|
|
45576
|
+
);
|
|
45577
|
+
if (list === list.next) steiners.add(list);
|
|
45578
|
+
queue.push(getLeftmost(list));
|
|
45579
|
+
}
|
|
45580
|
+
queue.sort(compareXYSlope);
|
|
45581
|
+
buildBlockIndex(data.length / dim, holeIndices.length);
|
|
45582
|
+
indexSegment(outerNode, outerNode);
|
|
45583
|
+
indexActive = true;
|
|
45584
|
+
for (let i = 0; i < queue.length; i++) {
|
|
45585
|
+
outerNode = eliminateHole(queue[i], outerNode);
|
|
45586
|
+
}
|
|
45587
|
+
indexActive = false;
|
|
45588
|
+
return filterPoints(outerNode);
|
|
45589
|
+
}
|
|
45590
|
+
function compareXYSlope(a, b) {
|
|
45591
|
+
return a.x - b.x || a.y - b.y || (a.next.y - a.y) / (a.next.x - a.x) - (b.next.y - b.y) / (b.next.x - b.x);
|
|
45592
|
+
}
|
|
45593
|
+
function eliminateHole(hole, outerNode) {
|
|
45594
|
+
const bridge = findHoleBridge(hole, outerNode);
|
|
45595
|
+
if (!bridge) {
|
|
45596
|
+
return outerNode;
|
|
45597
|
+
}
|
|
45598
|
+
const bridgeReverse = splitPolygon(bridge, hole);
|
|
45599
|
+
const bridge2 = bridgeReverse.next;
|
|
45600
|
+
indexSegment(bridge, bridge2.next);
|
|
45601
|
+
filterPoints(bridgeReverse, bridgeReverse.next);
|
|
45602
|
+
return filterPoints(bridge, bridge.next);
|
|
45603
|
+
}
|
|
45604
|
+
var K = 16;
|
|
45605
|
+
var blockBBox = new Float64Array(0);
|
|
45606
|
+
var numBlocks = 0;
|
|
45607
|
+
var blockHead = [];
|
|
45608
|
+
var blockStop = [];
|
|
45609
|
+
function buildBlockIndex(maxNodes, numHoles) {
|
|
45610
|
+
const maxBlocks = Math.ceil((maxNodes + 2 * numHoles) / K) + numHoles + 2;
|
|
45611
|
+
if (blockBBox.length < maxBlocks * 4) blockBBox = new Float64Array(maxBlocks * 4);
|
|
45612
|
+
numBlocks = 0;
|
|
45613
|
+
}
|
|
45614
|
+
function indexSegment(head, stop) {
|
|
45615
|
+
let p = head;
|
|
45616
|
+
do {
|
|
45617
|
+
const b = numBlocks++;
|
|
45618
|
+
blockHead[b] = p;
|
|
45619
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
45620
|
+
let k = 0;
|
|
45621
|
+
do {
|
|
45622
|
+
const c = p.next;
|
|
45623
|
+
p.z = b;
|
|
45624
|
+
if (p.x < minX) minX = p.x;
|
|
45625
|
+
if (p.x > maxX) maxX = p.x;
|
|
45626
|
+
if (p.y < minY) minY = p.y;
|
|
45627
|
+
if (p.y > maxY) maxY = p.y;
|
|
45628
|
+
if (c.x < minX) minX = c.x;
|
|
45629
|
+
if (c.x > maxX) maxX = c.x;
|
|
45630
|
+
if (c.y < minY) minY = c.y;
|
|
45631
|
+
if (c.y > maxY) maxY = c.y;
|
|
45632
|
+
p = c;
|
|
45633
|
+
} while (++k < K && p !== stop);
|
|
45634
|
+
blockStop[b] = p;
|
|
45635
|
+
const g = b * 4;
|
|
45636
|
+
blockBBox[g] = minX;
|
|
45637
|
+
blockBBox[g + 1] = minY;
|
|
45638
|
+
blockBBox[g + 2] = maxX;
|
|
45639
|
+
blockBBox[g + 3] = maxY;
|
|
45640
|
+
} while (p !== stop);
|
|
45641
|
+
}
|
|
45642
|
+
function growBlock(head, tail) {
|
|
45643
|
+
const g = head.z * 4;
|
|
45644
|
+
if (tail.x < blockBBox[g]) blockBBox[g] = tail.x;
|
|
45645
|
+
if (tail.y < blockBBox[g + 1]) blockBBox[g + 1] = tail.y;
|
|
45646
|
+
if (tail.x > blockBBox[g + 2]) blockBBox[g + 2] = tail.x;
|
|
45647
|
+
if (tail.y > blockBBox[g + 3]) blockBBox[g + 3] = tail.y;
|
|
45648
|
+
}
|
|
45649
|
+
function liveBlockStop(b) {
|
|
45650
|
+
let stop = blockStop[b];
|
|
45651
|
+
while (stop.prev.next !== stop) stop = stop.next;
|
|
45652
|
+
blockStop[b] = stop;
|
|
45653
|
+
return stop;
|
|
45654
|
+
}
|
|
45655
|
+
function liveBlockHead(b) {
|
|
45656
|
+
let head = blockHead[b];
|
|
45657
|
+
while (head.prev.next !== head) head = head.next;
|
|
45658
|
+
blockHead[b] = head;
|
|
45659
|
+
return head;
|
|
45660
|
+
}
|
|
45661
|
+
function findHoleBridge(hole, outerNode) {
|
|
45662
|
+
let p = outerNode;
|
|
45663
|
+
const hx = hole.x;
|
|
45664
|
+
const hy = hole.y;
|
|
45665
|
+
let qx = -Infinity;
|
|
45666
|
+
let m;
|
|
45667
|
+
if (equals(hole, p)) return p;
|
|
45668
|
+
for (let b = 0, g = 0; b < numBlocks; b++, g += 4) {
|
|
45669
|
+
if (hy < blockBBox[g + 1] || hy > blockBBox[g + 3] || blockBBox[g] > hx || blockBBox[g + 2] <= qx) continue;
|
|
45670
|
+
const stop = liveBlockStop(b);
|
|
45671
|
+
p = liveBlockHead(b);
|
|
45672
|
+
do {
|
|
45673
|
+
if (p.prev.next === p) {
|
|
45674
|
+
if (equals(hole, p.next)) return p.next;
|
|
45675
|
+
else if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
|
|
45676
|
+
const x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
|
|
45677
|
+
if (x <= hx && x > qx) {
|
|
45678
|
+
qx = x;
|
|
45679
|
+
m = p.x < p.next.x ? p : p.next;
|
|
45680
|
+
if (x === hx) return m;
|
|
45681
|
+
}
|
|
45682
|
+
}
|
|
45683
|
+
}
|
|
45684
|
+
p = p.next;
|
|
45685
|
+
} while (p !== stop);
|
|
45686
|
+
}
|
|
45687
|
+
if (!m) return null;
|
|
45688
|
+
const mx = m.x;
|
|
45689
|
+
const my = m.y;
|
|
45690
|
+
const tminY = Math.min(hy, my);
|
|
45691
|
+
const tmaxY = Math.max(hy, my);
|
|
45692
|
+
let tanMin = Infinity;
|
|
45693
|
+
for (let b = 0, g = 0; b < numBlocks; b++, g += 4) {
|
|
45694
|
+
if (blockBBox[g + 2] < mx || blockBBox[g] > hx || blockBBox[g + 3] < tminY || blockBBox[g + 1] > tmaxY) continue;
|
|
45695
|
+
const stop = liveBlockStop(b);
|
|
45696
|
+
p = liveBlockHead(b);
|
|
45697
|
+
do {
|
|
45698
|
+
if (p.prev.next === p && hx >= p.x && p.x >= mx && hx !== p.x && // skip dead nodes
|
|
45699
|
+
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
|
|
45700
|
+
const tan = Math.abs(hy - p.y) / (hx - p.x);
|
|
45701
|
+
if ((locallyInside(p, hole) || p.y === hy && p.next.y === hy && p.next.x > hx) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
|
|
45702
|
+
m = p;
|
|
45703
|
+
tanMin = tan;
|
|
45704
|
+
}
|
|
45705
|
+
}
|
|
45706
|
+
p = p.next;
|
|
45707
|
+
} while (p !== stop);
|
|
45708
|
+
}
|
|
45709
|
+
return m;
|
|
45710
|
+
}
|
|
45711
|
+
function sectorContainsSector(m, p) {
|
|
45712
|
+
return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
|
|
45713
|
+
}
|
|
45714
|
+
var sortArr = [];
|
|
45715
|
+
var sortBuf = [];
|
|
45716
|
+
var zArr = new Uint32Array(0);
|
|
45717
|
+
var zBuf = new Uint32Array(0);
|
|
45718
|
+
var counts = new Uint32Array(256);
|
|
45719
|
+
function indexCurve(start, minX, minY, invSize) {
|
|
45720
|
+
let p = start;
|
|
45721
|
+
let n = 0;
|
|
45722
|
+
do {
|
|
45723
|
+
p.z = zOrder(p.x, p.y, minX, minY, invSize);
|
|
45724
|
+
sortArr[n++] = p;
|
|
45725
|
+
p = p.next;
|
|
45726
|
+
} while (p !== start);
|
|
45727
|
+
sortNodes(n);
|
|
45728
|
+
let prev = null;
|
|
45729
|
+
for (let i = 0; i < n; i++) {
|
|
45730
|
+
const node = sortArr[i];
|
|
45731
|
+
node.prevZ = prev;
|
|
45732
|
+
if (prev) prev.nextZ = node;
|
|
45733
|
+
prev = node;
|
|
45734
|
+
}
|
|
45735
|
+
prev.nextZ = null;
|
|
45736
|
+
}
|
|
45737
|
+
function sortNodes(n) {
|
|
45738
|
+
if (n <= 32) {
|
|
45739
|
+
for (let i = 1; i < n; i++) {
|
|
45740
|
+
const node = sortArr[i], z42 = node.z;
|
|
45741
|
+
let j = i - 1;
|
|
45742
|
+
while (j >= 0 && sortArr[j].z > z42) {
|
|
45743
|
+
sortArr[j + 1] = sortArr[j];
|
|
45744
|
+
j--;
|
|
45745
|
+
}
|
|
45746
|
+
sortArr[j + 1] = node;
|
|
45747
|
+
}
|
|
45748
|
+
return;
|
|
45749
|
+
}
|
|
45750
|
+
if (zArr.length < n) {
|
|
45751
|
+
zArr = new Uint32Array(n);
|
|
45752
|
+
zBuf = new Uint32Array(n);
|
|
45753
|
+
sortBuf = new Array(n);
|
|
45754
|
+
}
|
|
45755
|
+
for (let i = 0; i < n; i++) zArr[i] = sortArr[i].z;
|
|
45756
|
+
radixPass(n, sortArr, zArr, sortBuf, zBuf, 0);
|
|
45757
|
+
radixPass(n, sortBuf, zBuf, sortArr, zArr, 8);
|
|
45758
|
+
radixPass(n, sortArr, zArr, sortBuf, zBuf, 16);
|
|
45759
|
+
radixPass(n, sortBuf, zBuf, sortArr, zArr, 24);
|
|
45760
|
+
}
|
|
45761
|
+
function radixPass(n, src, srcZ, dst, dstZ, shift4) {
|
|
45762
|
+
counts.fill(0);
|
|
45763
|
+
for (let i = 0; i < n; i++) counts[srcZ[i] >>> shift4 & 255]++;
|
|
45764
|
+
let sum = 0;
|
|
45765
|
+
for (let b = 0; b < 256; b++) {
|
|
45766
|
+
const c = counts[b];
|
|
45767
|
+
counts[b] = sum;
|
|
45768
|
+
sum += c;
|
|
45769
|
+
}
|
|
45770
|
+
for (let i = 0; i < n; i++) {
|
|
45771
|
+
const z42 = srcZ[i];
|
|
45772
|
+
const pos = counts[z42 >>> shift4 & 255]++;
|
|
45773
|
+
dst[pos] = src[i];
|
|
45774
|
+
dstZ[pos] = z42;
|
|
45775
|
+
}
|
|
45776
|
+
}
|
|
45777
|
+
function zOrder(x, y, minX, minY, invSize) {
|
|
45778
|
+
x = (x - minX) * invSize | 0;
|
|
45779
|
+
y = (y - minY) * invSize | 0;
|
|
45780
|
+
x = (x | x << 8) & 16711935;
|
|
45781
|
+
x = (x | x << 4) & 252645135;
|
|
45782
|
+
x = (x | x << 2) & 858993459;
|
|
45783
|
+
x = (x | x << 1) & 1431655765;
|
|
45784
|
+
y = (y | y << 8) & 16711935;
|
|
45785
|
+
y = (y | y << 4) & 252645135;
|
|
45786
|
+
y = (y | y << 2) & 858993459;
|
|
45787
|
+
y = (y | y << 1) & 1431655765;
|
|
45788
|
+
return x | y << 1;
|
|
45789
|
+
}
|
|
45790
|
+
function getLeftmost(start) {
|
|
45791
|
+
let p = start, leftmost = start;
|
|
45792
|
+
do {
|
|
45793
|
+
if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y) leftmost = p;
|
|
45794
|
+
p = p.next;
|
|
45795
|
+
} while (p !== start);
|
|
45796
|
+
return leftmost;
|
|
45797
|
+
}
|
|
45798
|
+
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
|
|
45799
|
+
return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
|
|
45800
|
+
}
|
|
45801
|
+
function isValidDiagonal(a, b) {
|
|
45802
|
+
const zeroLength = equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0;
|
|
45803
|
+
return a.next.i !== b.i && (zeroLength || locallyInside(a, b) && locallyInside(b, a) && // // locally visible
|
|
45804
|
+
(area(a.prev, a, b.prev) !== 0 || area(a, b.prev, b) !== 0)) && // no opposite-facing sectors
|
|
45805
|
+
!intersectsPolygon(a, b) && (zeroLength || middleInside(a, b));
|
|
45806
|
+
}
|
|
45807
|
+
function area(p, q, r) {
|
|
45808
|
+
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
|
|
45809
|
+
}
|
|
45810
|
+
function equals(p1, p2) {
|
|
45811
|
+
return p1.x === p2.x && p1.y === p2.y;
|
|
45812
|
+
}
|
|
45813
|
+
function intersects(p1, q1, p2, q2, includeBoundary = true) {
|
|
45814
|
+
const o1 = area(p1, q1, p2);
|
|
45815
|
+
const o2 = area(p1, q1, q2);
|
|
45816
|
+
const o3 = area(p2, q2, p1);
|
|
45817
|
+
const o4 = area(p2, q2, q1);
|
|
45818
|
+
if ((o1 > 0 && o2 < 0 || o1 < 0 && o2 > 0) && (o3 > 0 && o4 < 0 || o3 < 0 && o4 > 0)) return true;
|
|
45819
|
+
if (!includeBoundary) return false;
|
|
45820
|
+
if (o1 === 0 && onSegment2(p1, p2, q1)) return true;
|
|
45821
|
+
if (o2 === 0 && onSegment2(p1, q2, q1)) return true;
|
|
45822
|
+
if (o3 === 0 && onSegment2(p2, p1, q2)) return true;
|
|
45823
|
+
if (o4 === 0 && onSegment2(p2, q1, q2)) return true;
|
|
45824
|
+
return false;
|
|
45825
|
+
}
|
|
45826
|
+
function onSegment2(p, q, r) {
|
|
45827
|
+
return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
|
|
45828
|
+
}
|
|
45829
|
+
function intersectsPolygon(a, b) {
|
|
45830
|
+
const minX = Math.min(a.x, b.x);
|
|
45831
|
+
const maxX = Math.max(a.x, b.x);
|
|
45832
|
+
const minY = Math.min(a.y, b.y);
|
|
45833
|
+
const maxY = Math.max(a.y, b.y);
|
|
45834
|
+
let p = a;
|
|
45835
|
+
do {
|
|
45836
|
+
const n = p.next;
|
|
45837
|
+
if (p.x > maxX && n.x > maxX || p.x < minX && n.x < minX || p.y > maxY && n.y > maxY || p.y < minY && n.y < minY) {
|
|
45838
|
+
p = n;
|
|
45839
|
+
continue;
|
|
45840
|
+
}
|
|
45841
|
+
if (p.i !== a.i && n.i !== a.i && p.i !== b.i && n.i !== b.i && intersects(p, n, a, b)) return true;
|
|
45842
|
+
p = n;
|
|
45843
|
+
} while (p !== a);
|
|
45844
|
+
return false;
|
|
45845
|
+
}
|
|
45846
|
+
function locallyInside(a, b) {
|
|
45847
|
+
return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
|
|
45848
|
+
}
|
|
45849
|
+
function middleInside(a, b) {
|
|
45850
|
+
let p = a;
|
|
45851
|
+
let inside = false;
|
|
45852
|
+
const px = (a.x + b.x) / 2;
|
|
45853
|
+
const py = (a.y + b.y) / 2;
|
|
45854
|
+
do {
|
|
45855
|
+
const n = p.next;
|
|
45856
|
+
if (p.y > py !== n.y > py && px < (n.x - p.x) * (py - p.y) / (n.y - p.y) + p.x)
|
|
45857
|
+
inside = !inside;
|
|
45858
|
+
p = n;
|
|
45859
|
+
} while (p !== a);
|
|
45860
|
+
return inside;
|
|
45861
|
+
}
|
|
45862
|
+
function splitPolygon(a, b) {
|
|
45863
|
+
const a2 = createNode(a.i, a.x, a.y), b2 = createNode(b.i, b.x, b.y), an = a.next, bp = b.prev;
|
|
45864
|
+
a.next = b;
|
|
45865
|
+
b.prev = a;
|
|
45866
|
+
a2.next = an;
|
|
45867
|
+
an.prev = a2;
|
|
45868
|
+
b2.next = a2;
|
|
45869
|
+
a2.prev = b2;
|
|
45870
|
+
bp.next = b2;
|
|
45871
|
+
b2.prev = bp;
|
|
45872
|
+
return b2;
|
|
45873
|
+
}
|
|
45874
|
+
function insertNode(i, x, y, last) {
|
|
45875
|
+
const p = createNode(i, x, y);
|
|
45876
|
+
if (!last) {
|
|
45877
|
+
p.prev = p;
|
|
45878
|
+
p.next = p;
|
|
45879
|
+
} else {
|
|
45880
|
+
p.next = last.next;
|
|
45881
|
+
p.prev = last;
|
|
45882
|
+
last.next.prev = p;
|
|
45883
|
+
last.next = p;
|
|
45884
|
+
}
|
|
45885
|
+
return p;
|
|
45886
|
+
}
|
|
45887
|
+
function removeNode(p) {
|
|
45888
|
+
p.next.prev = p.prev;
|
|
45889
|
+
p.prev.next = p.next;
|
|
45890
|
+
if (p.prevZ) p.prevZ.nextZ = p.nextZ;
|
|
45891
|
+
if (p.nextZ) p.nextZ.prevZ = p.prevZ;
|
|
45892
|
+
if (indexActive) growBlock(p.prev, p.next);
|
|
45893
|
+
}
|
|
45894
|
+
function createNode(i, x, y) {
|
|
45895
|
+
return (
|
|
45896
|
+
/** @type {Node} */
|
|
45897
|
+
/** @type {unknown} */
|
|
45898
|
+
{
|
|
45899
|
+
i,
|
|
45900
|
+
// vertex index in coordinates array
|
|
45901
|
+
x,
|
|
45902
|
+
y,
|
|
45903
|
+
// vertex coordinates
|
|
45904
|
+
prev: null,
|
|
45905
|
+
// previous and next vertex nodes in a polygon ring
|
|
45906
|
+
next: null,
|
|
45907
|
+
z: 0,
|
|
45908
|
+
// z-order curve value; doubles as owning block in the hole-bridge index during eliminateHoles
|
|
45909
|
+
prevZ: null,
|
|
45910
|
+
// previous and next nodes in z-order
|
|
45911
|
+
nextZ: null
|
|
45912
|
+
}
|
|
45913
|
+
);
|
|
45914
|
+
}
|
|
45915
|
+
function signedArea(data, start, end, dim) {
|
|
45916
|
+
let sum = 0;
|
|
45917
|
+
for (let i = start, j = end - dim; i < end; i += dim) {
|
|
45918
|
+
sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
|
|
45919
|
+
j = i;
|
|
45920
|
+
}
|
|
45921
|
+
return sum;
|
|
45922
|
+
}
|
|
45923
|
+
|
|
45924
|
+
// node_modules/@tscircuit/flex-utils/dist/index.js
|
|
45925
|
+
var EPS = 1e-7;
|
|
45926
|
+
function createPcbFold(records, thickness) {
|
|
45927
|
+
if (!Number.isFinite(thickness) || thickness < 0)
|
|
45928
|
+
throw new Error("Board thickness must be finite and nonnegative");
|
|
45929
|
+
const bends = records.map((b) => {
|
|
45930
|
+
const { start, end, bend_angle: degrees, bend_radius: radius } = b;
|
|
45931
|
+
const values = [start?.x, start?.y, end?.x, end?.y, degrees, radius];
|
|
45932
|
+
if (values.some((v) => !Number.isFinite(v)) || radius <= thickness / 2 || !["left", "right"].includes(b.bend_side)) {
|
|
45933
|
+
throw new Error(
|
|
45934
|
+
`Invalid PCB bend ${b.pcb_bend_id}: finite geometry and radius greater than half the board thickness are required`
|
|
45935
|
+
);
|
|
45936
|
+
}
|
|
45937
|
+
const length83 = Math.hypot(end.x - start.x, end.y - start.y);
|
|
45938
|
+
if (length83 < EPS || Math.abs(degrees) > 180)
|
|
45939
|
+
throw new Error(
|
|
45940
|
+
`Unsupported PCB bend ${b.pcb_bend_id}: distinct endpoints and angles within \xB1180 degrees are required`
|
|
45941
|
+
);
|
|
45942
|
+
const sign = b.bend_side === "right" ? 1 : -1;
|
|
45943
|
+
const nx = sign * (end.y - start.y) / length83;
|
|
45944
|
+
const ny = -sign * (end.x - start.x) / length83;
|
|
45945
|
+
const angle = degrees * Math.PI / 180;
|
|
45946
|
+
const width10 = radius * Math.abs(angle);
|
|
45947
|
+
const center = start.x * nx + start.y * ny;
|
|
45948
|
+
return {
|
|
45949
|
+
id: b.pcb_bend_id,
|
|
45950
|
+
nx,
|
|
45951
|
+
ny,
|
|
45952
|
+
start: center - width10 / 2,
|
|
45953
|
+
end: center + width10 / 2,
|
|
45954
|
+
angle,
|
|
45955
|
+
radius,
|
|
45956
|
+
axisMin: Math.min(
|
|
45957
|
+
-ny * start.x + nx * start.y,
|
|
45958
|
+
-ny * end.x + nx * end.y
|
|
45959
|
+
),
|
|
45960
|
+
axisMax: Math.max(
|
|
45961
|
+
-ny * start.x + nx * start.y,
|
|
45962
|
+
-ny * end.x + nx * end.y
|
|
45963
|
+
)
|
|
45964
|
+
};
|
|
45965
|
+
}).filter((b) => Math.abs(b.angle) > EPS);
|
|
45966
|
+
const first = bends[0];
|
|
45967
|
+
if (first && bends.some(
|
|
45968
|
+
(b) => Math.abs(b.nx - first.nx) > EPS || Math.abs(b.ny - first.ny) > EPS
|
|
45969
|
+
)) {
|
|
45970
|
+
throw new Error(
|
|
45971
|
+
"Folded PCB rendering currently requires parallel bends with the same moving direction"
|
|
45972
|
+
);
|
|
45973
|
+
}
|
|
45974
|
+
bends.sort((a, b) => a.start - b.start);
|
|
45975
|
+
for (let i = 1; i < bends.length; i++) {
|
|
45976
|
+
if (bends[i].start < bends[i - 1].end - EPS)
|
|
45977
|
+
throw new Error("Overlapping PCB bend zones are not supported");
|
|
45978
|
+
}
|
|
45979
|
+
const distalFirst = [...bends].reverse();
|
|
45980
|
+
const transform = ({
|
|
45981
|
+
p,
|
|
45982
|
+
anchor,
|
|
45983
|
+
direction
|
|
45984
|
+
}) => {
|
|
45985
|
+
let result = { ...p };
|
|
45986
|
+
for (const b of distalFirst) {
|
|
45987
|
+
const width10 = b.end - b.start;
|
|
45988
|
+
const s = anchor.x * b.nx + anchor.y * b.ny - b.start;
|
|
45989
|
+
const q = Math.max(0, Math.min(width10, s));
|
|
45990
|
+
const theta = b.angle * q / width10;
|
|
45991
|
+
const cos = Math.cos(theta), sin = Math.sin(theta);
|
|
45992
|
+
const projected = result.x * b.nx + result.y * b.ny - (direction ? 0 : b.start);
|
|
45993
|
+
const tangentX = result.x - (projected + (direction ? 0 : b.start)) * b.nx;
|
|
45994
|
+
const tangentY = result.y - (projected + (direction ? 0 : b.start)) * b.ny;
|
|
45995
|
+
const signedRadius = Math.sign(b.angle) * b.radius;
|
|
45996
|
+
const tx = direction ? 0 : signedRadius * sin - q * cos;
|
|
45997
|
+
const tz = direction ? 0 : signedRadius * (1 - cos) - q * sin;
|
|
45998
|
+
const folded = projected * cos - result.z * sin + tx;
|
|
45999
|
+
result = {
|
|
46000
|
+
x: tangentX + (folded + (direction ? 0 : b.start)) * b.nx,
|
|
46001
|
+
y: tangentY + (folded + (direction ? 0 : b.start)) * b.ny,
|
|
46002
|
+
z: projected * sin + result.z * cos + tz
|
|
46003
|
+
};
|
|
46004
|
+
}
|
|
46005
|
+
return result;
|
|
46006
|
+
};
|
|
46007
|
+
const inverse = ({
|
|
46008
|
+
p,
|
|
46009
|
+
anchor,
|
|
46010
|
+
direction
|
|
46011
|
+
}) => {
|
|
46012
|
+
const origin = direction ? { x: 0, y: 0, z: 0 } : transform({
|
|
46013
|
+
p: { x: 0, y: 0, z: 0 },
|
|
46014
|
+
anchor,
|
|
46015
|
+
direction: false
|
|
46016
|
+
});
|
|
46017
|
+
const d = { x: p.x - origin.x, y: p.y - origin.y, z: p.z - origin.z };
|
|
46018
|
+
const axes2 = [
|
|
46019
|
+
{ x: 1, y: 0, z: 0 },
|
|
46020
|
+
{ x: 0, y: 1, z: 0 },
|
|
46021
|
+
{ x: 0, y: 0, z: 1 }
|
|
46022
|
+
].map((v) => transform({ p: v, anchor, direction: true }));
|
|
46023
|
+
const dot = (v) => v.x * d.x + v.y * d.y + v.z * d.z;
|
|
46024
|
+
return { x: dot(axes2[0]), y: dot(axes2[1]), z: dot(axes2[2]) };
|
|
46025
|
+
};
|
|
46026
|
+
return {
|
|
46027
|
+
bends,
|
|
46028
|
+
inversePoint: (p, anchor) => inverse({ p, anchor, direction: false }),
|
|
46029
|
+
inverseDirection: (p, anchor) => inverse({ p, anchor, direction: true }),
|
|
46030
|
+
point: (p, anchor = p) => transform({ p, anchor, direction: false }),
|
|
46031
|
+
direction: (p, anchor) => transform({ p, anchor, direction: true }),
|
|
46032
|
+
assertRigid(points, label) {
|
|
46033
|
+
for (const b of bends) {
|
|
46034
|
+
const ds = points.map((p) => p.x * b.nx + p.y * b.ny);
|
|
46035
|
+
if (Math.max(...ds) > b.start + EPS && Math.min(...ds) < b.end - EPS)
|
|
46036
|
+
throw new Error(`${label} intersects PCB bend zone ${b.id}`);
|
|
46037
|
+
}
|
|
46038
|
+
}
|
|
46039
|
+
};
|
|
46040
|
+
}
|
|
46041
|
+
var EPS2 = 1e-7;
|
|
46042
|
+
function boundsOfTriangles(triangles) {
|
|
46043
|
+
const points = triangles.flatMap((t) => t.vertices);
|
|
46044
|
+
if (!points.length)
|
|
46045
|
+
return { min: { x: 0, y: 0, z: 0 }, max: { x: 0, y: 0, z: 0 } };
|
|
46046
|
+
const min2 = { x: Infinity, y: Infinity, z: Infinity };
|
|
46047
|
+
const max2 = { x: -Infinity, y: -Infinity, z: -Infinity };
|
|
46048
|
+
for (const p of points)
|
|
46049
|
+
for (const key of ["x", "y", "z"]) {
|
|
46050
|
+
min2[key] = Math.min(min2[key], p[key]);
|
|
46051
|
+
max2[key] = Math.max(max2[key], p[key]);
|
|
46052
|
+
}
|
|
46053
|
+
return { min: min2, max: max2 };
|
|
46054
|
+
}
|
|
46055
|
+
function foldSurfaceMesh(mesh, fold) {
|
|
46056
|
+
const planes = fold.bends.flatMap((b) => {
|
|
46057
|
+
const steps = Math.ceil(Math.abs(b.angle) / (Math.PI / 36));
|
|
46058
|
+
return Array.from({ length: steps + 1 }, (_, i) => ({
|
|
46059
|
+
b,
|
|
46060
|
+
d: b.start + (b.end - b.start) * i / steps
|
|
46061
|
+
}));
|
|
46062
|
+
});
|
|
46063
|
+
const { min: min2, max: max2 } = mesh.boundingBox;
|
|
46064
|
+
const split = ({
|
|
46065
|
+
polygon: polygon2,
|
|
46066
|
+
nx,
|
|
46067
|
+
ny,
|
|
46068
|
+
d
|
|
46069
|
+
}) => {
|
|
46070
|
+
const distances = polygon2.map(({ p }) => nx * p.x + ny * p.y - d);
|
|
46071
|
+
if (Math.min(...distances) >= -EPS2 || Math.max(...distances) <= EPS2)
|
|
46072
|
+
return [polygon2];
|
|
46073
|
+
const halves = [[], []];
|
|
46074
|
+
for (let side = 0; side < 2; side++) {
|
|
46075
|
+
const sign = side === 0 ? 1 : -1;
|
|
46076
|
+
for (let i = 0; i < polygon2.length; i++) {
|
|
46077
|
+
const a = polygon2[i], next = (i + 1) % polygon2.length, b = polygon2[next];
|
|
46078
|
+
const da = distances[i] * sign, db = distances[next] * sign;
|
|
46079
|
+
if (da >= -EPS2) halves[side].push(a);
|
|
46080
|
+
if (da > EPS2 && db < -EPS2 || da < -EPS2 && db > EPS2) {
|
|
46081
|
+
const t = da / (da - db);
|
|
46082
|
+
halves[side].push({
|
|
46083
|
+
p: {
|
|
46084
|
+
x: a.p.x + (b.p.x - a.p.x) * t,
|
|
46085
|
+
y: a.p.y + (b.p.y - a.p.y) * t,
|
|
46086
|
+
z: a.p.z + (b.p.z - a.p.z) * t
|
|
46087
|
+
},
|
|
46088
|
+
uv: {
|
|
46089
|
+
u: a.uv.u + (b.uv.u - a.uv.u) * t,
|
|
46090
|
+
v: a.uv.v + (b.uv.v - a.uv.v) * t
|
|
46091
|
+
}
|
|
46092
|
+
});
|
|
46093
|
+
}
|
|
46094
|
+
}
|
|
46095
|
+
}
|
|
46096
|
+
return halves.filter((p) => p.length >= 3);
|
|
46097
|
+
};
|
|
46098
|
+
const triangles = [];
|
|
46099
|
+
for (const triangle of mesh.triangles) {
|
|
46100
|
+
const face = triangle.pcbFace ?? (triangle.normal.z > 0.8 ? "top" : triangle.normal.z < -0.8 ? "bottom" : "side");
|
|
46101
|
+
let polygons = [
|
|
46102
|
+
triangle.vertices.map((p, index2) => ({
|
|
46103
|
+
p,
|
|
46104
|
+
uv: triangle.uvs?.[index2] ?? {
|
|
46105
|
+
u: (p.x - min2.x) / (max2.x - min2.x),
|
|
46106
|
+
v: 1 - (p.y - min2.y) / (max2.y - min2.y)
|
|
46107
|
+
}
|
|
46108
|
+
}))
|
|
46109
|
+
];
|
|
46110
|
+
for (const { b, d } of planes)
|
|
46111
|
+
polygons = polygons.flatMap(
|
|
46112
|
+
(p) => split({ polygon: p, nx: b.nx, ny: b.ny, d })
|
|
46113
|
+
);
|
|
46114
|
+
for (const polygon2 of polygons) {
|
|
46115
|
+
for (const b of fold.bends) {
|
|
46116
|
+
const mid = polygon2.reduce((sum, { p }) => sum + p.x * b.nx + p.y * b.ny, 0) / polygon2.length;
|
|
46117
|
+
if (mid > b.start + EPS2 && mid < b.end - EPS2 && polygon2.some(({ p }) => {
|
|
46118
|
+
const along = -b.ny * p.x + b.nx * p.y;
|
|
46119
|
+
return along < b.axisMin - EPS2 || along > b.axisMax + EPS2;
|
|
46120
|
+
}))
|
|
46121
|
+
throw new Error(
|
|
46122
|
+
`PCB bend ${b.id} must span the full board cross-section through its bend zone`
|
|
46123
|
+
);
|
|
46124
|
+
}
|
|
46125
|
+
for (let i = 1; i + 1 < polygon2.length; i++) {
|
|
46126
|
+
const verts = [polygon2[0], polygon2[i], polygon2[i + 1]];
|
|
46127
|
+
const vertices = verts.map(
|
|
46128
|
+
({ p }) => fold.point(p)
|
|
46129
|
+
);
|
|
46130
|
+
const [a, b, c] = vertices;
|
|
46131
|
+
const u = { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z }, v = { x: c.x - a.x, y: c.y - a.y, z: c.z - a.z };
|
|
46132
|
+
const n = {
|
|
46133
|
+
x: u.y * v.z - u.z * v.y,
|
|
46134
|
+
y: u.z * v.x - u.x * v.z,
|
|
46135
|
+
z: u.x * v.y - u.y * v.x
|
|
46136
|
+
};
|
|
46137
|
+
const l = Math.hypot(n.x, n.y, n.z);
|
|
46138
|
+
if (l < 1e-12) continue;
|
|
46139
|
+
triangles.push({
|
|
46140
|
+
...triangle,
|
|
46141
|
+
vertices,
|
|
46142
|
+
normal: { x: n.x / l, y: n.y / l, z: n.z / l },
|
|
46143
|
+
pcbFace: face,
|
|
46144
|
+
uvs: verts.map(({ uv }) => uv)
|
|
46145
|
+
});
|
|
46146
|
+
}
|
|
46147
|
+
}
|
|
46148
|
+
}
|
|
46149
|
+
return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46150
|
+
}
|
|
46151
|
+
var axes = [
|
|
46152
|
+
{ x: 1, y: 0, z: 0 },
|
|
46153
|
+
{ x: 0, y: 1, z: 0 },
|
|
46154
|
+
{ x: 0, y: 0, z: 1 }
|
|
46155
|
+
];
|
|
46156
|
+
function rotateVector(v, degrees) {
|
|
46157
|
+
const [x, y, z42] = [degrees.x, degrees.y, degrees.z].map(
|
|
46158
|
+
(a2) => a2 * Math.PI / 180
|
|
46159
|
+
);
|
|
46160
|
+
const a = {
|
|
46161
|
+
x: Math.cos(z42) * v.x - Math.sin(z42) * v.y,
|
|
46162
|
+
y: Math.sin(z42) * v.x + Math.cos(z42) * v.y,
|
|
46163
|
+
z: v.z
|
|
46164
|
+
};
|
|
46165
|
+
const b = {
|
|
46166
|
+
x: Math.cos(y) * a.x + Math.sin(y) * a.z,
|
|
46167
|
+
y: a.y,
|
|
46168
|
+
z: -Math.sin(y) * a.x + Math.cos(y) * a.z
|
|
46169
|
+
};
|
|
46170
|
+
return {
|
|
46171
|
+
x: b.x,
|
|
46172
|
+
y: Math.cos(x) * b.y - Math.sin(x) * b.z,
|
|
46173
|
+
z: Math.sin(x) * b.y + Math.cos(x) * b.z
|
|
46174
|
+
};
|
|
46175
|
+
}
|
|
46176
|
+
function rotationFromAxes([a, b, c]) {
|
|
46177
|
+
const y = Math.asin(Math.max(-1, Math.min(1, c.x)));
|
|
46178
|
+
const regular = Math.abs(c.x) < 1 - 1e-12;
|
|
46179
|
+
return {
|
|
46180
|
+
x: (regular ? Math.atan2(-c.y, c.z) : Math.atan2(b.z, b.y)) * 180 / Math.PI,
|
|
46181
|
+
y: y * 180 / Math.PI,
|
|
46182
|
+
z: (regular ? Math.atan2(-b.x, a.x) : 0) * 180 / Math.PI
|
|
46183
|
+
};
|
|
46184
|
+
}
|
|
46185
|
+
function transformCadComponent({ cadComponent, foldPcbs }, context) {
|
|
46186
|
+
return transformCadComponentPlacement(
|
|
46187
|
+
{ cadComponentPlacement: cadComponent, foldPcbs },
|
|
46188
|
+
context
|
|
46189
|
+
);
|
|
46190
|
+
}
|
|
46191
|
+
function transformCadComponentPlacement({
|
|
46192
|
+
cadComponentPlacement,
|
|
46193
|
+
foldPcbs
|
|
46194
|
+
}, context) {
|
|
46195
|
+
if (cadComponentPlacement.is_on_folded_board === true === foldPcbs)
|
|
46196
|
+
return cadComponentPlacement;
|
|
46197
|
+
const { fold, boardCenter, flatMount } = context;
|
|
46198
|
+
const anchor = {
|
|
46199
|
+
x: flatMount.x - boardCenter.x,
|
|
46200
|
+
y: flatMount.y - boardCenter.y,
|
|
46201
|
+
z: 0
|
|
46202
|
+
};
|
|
46203
|
+
fold.assertRigid([anchor], "CAD mount");
|
|
46204
|
+
const point = {
|
|
46205
|
+
x: cadComponentPlacement.position.x - boardCenter.x,
|
|
46206
|
+
y: cadComponentPlacement.position.y - boardCenter.y,
|
|
46207
|
+
z: cadComponentPlacement.position.z
|
|
46208
|
+
};
|
|
46209
|
+
const direction = foldPcbs ? fold.direction : fold.inverseDirection;
|
|
46210
|
+
const transformed = foldPcbs ? fold.point(point, anchor) : fold.inversePoint(point, anchor);
|
|
46211
|
+
const rotation = cadComponentPlacement.rotation ?? context.defaultRotation ?? { x: 0, y: 0, z: 0 };
|
|
46212
|
+
const basis = axes.map((v) => direction(rotateVector(v, rotation), anchor));
|
|
46213
|
+
return {
|
|
46214
|
+
...cadComponentPlacement,
|
|
46215
|
+
position: {
|
|
46216
|
+
x: transformed.x + boardCenter.x,
|
|
46217
|
+
y: transformed.y + boardCenter.y,
|
|
46218
|
+
z: transformed.z
|
|
46219
|
+
},
|
|
46220
|
+
rotation: rotationFromAxes(basis),
|
|
46221
|
+
is_on_folded_board: foldPcbs
|
|
46222
|
+
};
|
|
46223
|
+
}
|
|
46224
|
+
function getCadFoldContext(cadComponent, json) {
|
|
46225
|
+
const pcb = json.find(
|
|
46226
|
+
(e) => e.type === "pcb_component" && e.pcb_component_id === cadComponent.pcb_component_id
|
|
46227
|
+
);
|
|
46228
|
+
if (pcb?.type !== "pcb_component") {
|
|
46229
|
+
if (cadComponent.is_on_folded_board)
|
|
46230
|
+
throw new Error(
|
|
46231
|
+
`Folded CAD ${cadComponent.cad_component_id} requires its flat pcb_component reference`
|
|
46232
|
+
);
|
|
46233
|
+
return void 0;
|
|
46234
|
+
}
|
|
46235
|
+
const boards = json.filter((e) => e.type === "pcb_board");
|
|
46236
|
+
const explicit = pcb.positioned_relative_to_pcb_board_id;
|
|
46237
|
+
const matching = explicit ? boards.filter((b) => b.pcb_board_id === explicit) : boards.filter(
|
|
46238
|
+
(b) => b.subcircuit_id && b.subcircuit_id === pcb.subcircuit_id
|
|
46239
|
+
);
|
|
46240
|
+
const board = matching.length === 1 ? matching[0] : !explicit && !matching.length && boards.length === 1 ? boards[0] : void 0;
|
|
46241
|
+
if (!board)
|
|
46242
|
+
throw new Error(
|
|
46243
|
+
`Cannot unambiguously resolve board for CAD ${cadComponent.cad_component_id}`
|
|
46244
|
+
);
|
|
46245
|
+
const bends = json.filter(
|
|
46246
|
+
(e) => e.type === "pcb_bend" && e.pcb_board_id === board.pcb_board_id
|
|
46247
|
+
);
|
|
46248
|
+
return {
|
|
46249
|
+
fold: createPcbFold(bends, board.thickness ?? 1.6),
|
|
46250
|
+
boardCenter: board.center,
|
|
46251
|
+
flatMount: pcb.center,
|
|
46252
|
+
defaultRotation: {
|
|
46253
|
+
x: (cadComponent.layer ?? pcb.layer) === "bottom" ? 180 : 0,
|
|
46254
|
+
y: 0,
|
|
46255
|
+
z: 0
|
|
46256
|
+
}
|
|
46257
|
+
};
|
|
46258
|
+
}
|
|
46259
|
+
function transformCircuitJsonCadComponents(json, options) {
|
|
46260
|
+
const hasBends = json.some((element) => element.type === "pcb_bend");
|
|
46261
|
+
return json.map((element) => {
|
|
46262
|
+
if (element.type !== "cad_component") return element;
|
|
46263
|
+
const cadComponent = element;
|
|
46264
|
+
if (!hasBends && !cadComponent.is_on_folded_board) return element;
|
|
46265
|
+
if (cadComponent.is_on_folded_board === true === options.foldPcbs)
|
|
46266
|
+
return element;
|
|
46267
|
+
const context = getCadFoldContext(cadComponent, json);
|
|
46268
|
+
if (!context || !context.fold.bends.length && !cadComponent.is_on_folded_board)
|
|
46269
|
+
return element;
|
|
46270
|
+
return transformCadComponent(
|
|
46271
|
+
{ cadComponent, foldPcbs: options.foldPcbs },
|
|
46272
|
+
context
|
|
46273
|
+
);
|
|
46274
|
+
});
|
|
46275
|
+
}
|
|
46276
|
+
function extrudePolygon({
|
|
46277
|
+
outline,
|
|
46278
|
+
bottom,
|
|
46279
|
+
top
|
|
46280
|
+
}) {
|
|
46281
|
+
if (outline.length < 3 || !Number.isFinite(bottom) || !Number.isFinite(top) || top <= bottom || outline.some((p) => !Number.isFinite(p.x) || !Number.isFinite(p.y)))
|
|
46282
|
+
throw new Error(
|
|
46283
|
+
"A finite polygon and positive extrusion thickness are required"
|
|
46284
|
+
);
|
|
46285
|
+
let area2 = 0;
|
|
46286
|
+
for (const [i, a] of outline.entries()) {
|
|
46287
|
+
const b = outline[(i + 1) % outline.length];
|
|
46288
|
+
area2 += a.x * b.y - b.x * a.y;
|
|
46289
|
+
}
|
|
46290
|
+
if (Math.abs(area2) < 1e-12) throw new Error("Degenerate polygon");
|
|
46291
|
+
const polygon2 = area2 > 0 ? outline : [...outline].reverse();
|
|
46292
|
+
const triangles = [];
|
|
46293
|
+
const add = ({
|
|
46294
|
+
a,
|
|
46295
|
+
b,
|
|
46296
|
+
c,
|
|
46297
|
+
pcbFace
|
|
46298
|
+
}) => {
|
|
46299
|
+
const u = { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z }, v = { x: c.x - a.x, y: c.y - a.y, z: c.z - a.z };
|
|
46300
|
+
const n = {
|
|
46301
|
+
x: u.y * v.z - u.z * v.y,
|
|
46302
|
+
y: u.z * v.x - u.x * v.z,
|
|
46303
|
+
z: u.x * v.y - u.y * v.x
|
|
46304
|
+
};
|
|
46305
|
+
const l = Math.hypot(n.x, n.y, n.z);
|
|
46306
|
+
if (l > 1e-12)
|
|
46307
|
+
triangles.push({
|
|
46308
|
+
vertices: [a, b, c],
|
|
46309
|
+
normal: { x: n.x / l, y: n.y / l, z: n.z / l },
|
|
46310
|
+
pcbFace
|
|
46311
|
+
});
|
|
46312
|
+
};
|
|
46313
|
+
const indices = earcut(polygon2.flatMap((p) => [p.x, p.y]));
|
|
46314
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
46315
|
+
const [a, b, c] = indices.slice(i, i + 3).map((j) => polygon2[j]);
|
|
46316
|
+
add({
|
|
46317
|
+
a: { ...a, z: top },
|
|
46318
|
+
b: { ...b, z: top },
|
|
46319
|
+
c: { ...c, z: top },
|
|
46320
|
+
pcbFace: "top"
|
|
46321
|
+
});
|
|
46322
|
+
add({
|
|
46323
|
+
a: { ...c, z: bottom },
|
|
46324
|
+
b: { ...b, z: bottom },
|
|
46325
|
+
c: { ...a, z: bottom },
|
|
46326
|
+
pcbFace: "bottom"
|
|
46327
|
+
});
|
|
46328
|
+
}
|
|
46329
|
+
for (let i = 0; i < polygon2.length; i++) {
|
|
46330
|
+
const a = polygon2[i], b = polygon2[(i + 1) % polygon2.length];
|
|
46331
|
+
add({
|
|
46332
|
+
a: { ...a, z: bottom },
|
|
46333
|
+
b: { ...b, z: bottom },
|
|
46334
|
+
c: { ...b, z: top },
|
|
46335
|
+
pcbFace: "side"
|
|
46336
|
+
});
|
|
46337
|
+
add({
|
|
46338
|
+
a: { ...a, z: bottom },
|
|
46339
|
+
b: { ...b, z: top },
|
|
46340
|
+
c: { ...a, z: top },
|
|
46341
|
+
pcbFace: "side"
|
|
46342
|
+
});
|
|
46343
|
+
}
|
|
46344
|
+
return { triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46345
|
+
}
|
|
46346
|
+
function createStiffenerMesh({
|
|
46347
|
+
stiffener,
|
|
46348
|
+
boardThickness,
|
|
46349
|
+
fold
|
|
46350
|
+
}) {
|
|
46351
|
+
const adhesive = stiffener.adhesive_thickness ?? 0;
|
|
46352
|
+
if (!Number.isFinite(adhesive) || adhesive < 0 || !Number.isFinite(stiffener.thickness) || stiffener.thickness <= 0 || !["top", "bottom"].includes(stiffener.layer))
|
|
46353
|
+
throw new Error(`Invalid PCB stiffener ${stiffener.pcb_stiffener_id}`);
|
|
46354
|
+
const outline = stiffener.shape === "polygon" ? stiffener.outline : (() => {
|
|
46355
|
+
if (!(stiffener.width > 0 && stiffener.height > 0))
|
|
46356
|
+
throw new Error("Invalid stiffener dimensions");
|
|
46357
|
+
const a = (stiffener.rotation ?? 0) * Math.PI / 180;
|
|
46358
|
+
return [
|
|
46359
|
+
[-1, -1],
|
|
46360
|
+
[1, -1],
|
|
46361
|
+
[1, 1],
|
|
46362
|
+
[-1, 1]
|
|
46363
|
+
].map(([x, y]) => ({
|
|
46364
|
+
x: stiffener.center.x + x * stiffener.width / 2 * Math.cos(a) - y * stiffener.height / 2 * Math.sin(a),
|
|
46365
|
+
y: stiffener.center.y + x * stiffener.width / 2 * Math.sin(a) + y * stiffener.height / 2 * Math.cos(a)
|
|
46366
|
+
}));
|
|
46367
|
+
})();
|
|
46368
|
+
const near = boardThickness / 2 + adhesive, far = near + stiffener.thickness;
|
|
46369
|
+
const mesh = extrudePolygon({
|
|
46370
|
+
outline,
|
|
46371
|
+
bottom: stiffener.layer === "top" ? near : -far,
|
|
46372
|
+
top: stiffener.layer === "top" ? far : -near
|
|
46373
|
+
});
|
|
46374
|
+
if (!fold) return mesh;
|
|
46375
|
+
fold.assertRigid(
|
|
46376
|
+
mesh.triangles.flatMap((t) => t.vertices),
|
|
46377
|
+
stiffener.pcb_stiffener_id
|
|
46378
|
+
);
|
|
46379
|
+
const anchor = {
|
|
46380
|
+
x: outline.reduce((s, p) => s + p.x, 0) / outline.length,
|
|
46381
|
+
y: outline.reduce((s, p) => s + p.y, 0) / outline.length,
|
|
46382
|
+
z: 0
|
|
46383
|
+
};
|
|
46384
|
+
const triangles = mesh.triangles.map((t) => ({
|
|
46385
|
+
...t,
|
|
46386
|
+
vertices: t.vertices.map((p) => fold.point(p, anchor)),
|
|
46387
|
+
normal: fold.direction(t.normal, anchor)
|
|
46388
|
+
}));
|
|
46389
|
+
return { ...mesh, triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46390
|
+
}
|
|
46391
|
+
|
|
46392
|
+
// src/utils/flex-meshes.ts
|
|
46393
|
+
import * as THREE44 from "three";
|
|
46394
|
+
function meshToSurface(mesh, center) {
|
|
46395
|
+
mesh.updateMatrix();
|
|
46396
|
+
const geometry = mesh.geometry.index ? mesh.geometry.toNonIndexed() : mesh.geometry;
|
|
46397
|
+
const position = geometry.getAttribute("position"), uv = geometry.getAttribute("uv");
|
|
46398
|
+
const triangles = [];
|
|
46399
|
+
for (let i = 0; i < position.count; i += 3) {
|
|
46400
|
+
const vertices = [0, 1, 2].map((j) => {
|
|
46401
|
+
const v = new THREE44.Vector3().fromBufferAttribute(position, i + j).applyMatrix4(mesh.matrix);
|
|
46402
|
+
return { x: v.x - center.x, y: v.y - center.y, z: v.z };
|
|
46403
|
+
});
|
|
46404
|
+
const [a, b, c] = vertices;
|
|
46405
|
+
const n = new THREE44.Vector3(b.x - a.x, b.y - a.y, b.z - a.z).cross(new THREE44.Vector3(c.x - a.x, c.y - a.y, c.z - a.z)).normalize();
|
|
46406
|
+
triangles.push({
|
|
46407
|
+
vertices,
|
|
46408
|
+
normal: { x: n.x, y: n.y, z: n.z },
|
|
46409
|
+
...uv ? {
|
|
46410
|
+
uvs: [0, 1, 2].map((j) => ({
|
|
46411
|
+
u: uv.getX(i + j),
|
|
46412
|
+
v: uv.getY(i + j)
|
|
46413
|
+
}))
|
|
46414
|
+
} : {}
|
|
46415
|
+
});
|
|
46416
|
+
}
|
|
46417
|
+
if (geometry !== mesh.geometry) geometry.dispose();
|
|
46418
|
+
return { triangles, boundingBox: boundsOfTriangles(triangles) };
|
|
46419
|
+
}
|
|
46420
|
+
function surfaceToGeometry(surface, center) {
|
|
46421
|
+
const positions = [], normals = [], uvs = [];
|
|
46422
|
+
for (const triangle of surface.triangles)
|
|
46423
|
+
triangle.vertices.forEach((p, i) => {
|
|
46424
|
+
positions.push(p.x + center.x, p.y + center.y, p.z);
|
|
46425
|
+
normals.push(triangle.normal.x, triangle.normal.y, triangle.normal.z);
|
|
46426
|
+
uvs.push(triangle.uvs?.[i]?.u ?? 0, triangle.uvs?.[i]?.v ?? 0);
|
|
46427
|
+
});
|
|
46428
|
+
const geometry = new THREE44.BufferGeometry();
|
|
46429
|
+
geometry.setAttribute(
|
|
46430
|
+
"position",
|
|
46431
|
+
new THREE44.Float32BufferAttribute(positions, 3)
|
|
46432
|
+
);
|
|
46433
|
+
geometry.setAttribute("normal", new THREE44.Float32BufferAttribute(normals, 3));
|
|
46434
|
+
geometry.setAttribute("uv", new THREE44.Float32BufferAttribute(uvs, 2));
|
|
46435
|
+
geometry.computeBoundingBox();
|
|
46436
|
+
geometry.computeBoundingSphere();
|
|
46437
|
+
return geometry;
|
|
46438
|
+
}
|
|
46439
|
+
function replaceGeometry(mesh, surface, board) {
|
|
46440
|
+
const output = mesh.clone();
|
|
46441
|
+
output.geometry = surfaceToGeometry(surface, board.center);
|
|
46442
|
+
output.position.set(0, 0, 0);
|
|
46443
|
+
output.rotation.set(0, 0, 0);
|
|
46444
|
+
output.scale.set(1, 1, 1);
|
|
46445
|
+
output.updateMatrix();
|
|
46446
|
+
return output;
|
|
46447
|
+
}
|
|
46448
|
+
function createFlexMeshes(geometryMeshes, textureMeshes, json, foldPcbs) {
|
|
46449
|
+
const boards = json.filter((e) => e.type === "pcb_board");
|
|
46450
|
+
const bends = json.filter((e) => e.type === "pcb_bend"), stiffeners = json.filter((e) => e.type === "pcb_stiffener");
|
|
46451
|
+
if (!bends.length && !stiffeners.length)
|
|
46452
|
+
return { geometryMeshes, textureMeshes };
|
|
46453
|
+
const board = boards[0];
|
|
46454
|
+
if (!board || boards.length !== 1 || json.some((e) => e.type === "pcb_panel") || [...bends, ...stiffeners].some((e) => e.pcb_board_id !== board.pcb_board_id))
|
|
46455
|
+
throw new Error(
|
|
46456
|
+
"Flex rendering requires one board, matching board references, and no panel"
|
|
46457
|
+
);
|
|
46458
|
+
const fold = foldPcbs ? createPcbFold(bends, board.thickness ?? 1.6) : void 0;
|
|
46459
|
+
const body = geometryMeshes.find((m) => m.name === "board-geom");
|
|
46460
|
+
const flatBody = body ? meshToSurface(body, board.center) : void 0;
|
|
46461
|
+
const geometry = fold ? geometryMeshes.map(
|
|
46462
|
+
(mesh) => replaceGeometry(
|
|
46463
|
+
mesh,
|
|
46464
|
+
foldSurfaceMesh(meshToSurface(mesh, board.center), fold),
|
|
46465
|
+
board
|
|
46466
|
+
)
|
|
46467
|
+
) : [...geometryMeshes];
|
|
46468
|
+
const textures = fold && flatBody ? textureMeshes.map((mesh) => {
|
|
46469
|
+
mesh.updateMatrix();
|
|
46470
|
+
const inverse = mesh.matrix.clone().invert();
|
|
46471
|
+
const bottom = mesh.name.startsWith("bottom");
|
|
46472
|
+
const dimensions = mesh.geometry.parameters;
|
|
46473
|
+
const triangles = flatBody.triangles.filter((t) => bottom ? t.normal.z < -0.9 : t.normal.z > 0.9).map((t) => {
|
|
46474
|
+
const vertices = t.vertices.map((p) => ({
|
|
46475
|
+
...p,
|
|
46476
|
+
z: mesh.position.z
|
|
46477
|
+
}));
|
|
46478
|
+
const uvs = vertices.map((p) => {
|
|
46479
|
+
const local = new THREE44.Vector3(
|
|
46480
|
+
p.x + board.center.x,
|
|
46481
|
+
p.y + board.center.y,
|
|
46482
|
+
p.z
|
|
46483
|
+
).applyMatrix4(inverse);
|
|
46484
|
+
return {
|
|
46485
|
+
u: local.x / dimensions.width + 0.5,
|
|
46486
|
+
v: local.y / dimensions.height + 0.5
|
|
46487
|
+
};
|
|
46488
|
+
});
|
|
46489
|
+
return { ...t, vertices, uvs };
|
|
46490
|
+
});
|
|
46491
|
+
const result = replaceGeometry(
|
|
46492
|
+
mesh,
|
|
46493
|
+
foldSurfaceMesh(
|
|
46494
|
+
{ triangles, boundingBox: boundsOfTriangles(triangles) },
|
|
46495
|
+
fold
|
|
46496
|
+
),
|
|
46497
|
+
board
|
|
46498
|
+
);
|
|
46499
|
+
mesh.geometry.dispose();
|
|
46500
|
+
return result;
|
|
46501
|
+
}) : textureMeshes;
|
|
46502
|
+
for (const stiffener of stiffeners) {
|
|
46503
|
+
const mesh = new THREE44.Mesh(
|
|
46504
|
+
surfaceToGeometry(
|
|
46505
|
+
createStiffenerMesh({
|
|
46506
|
+
stiffener,
|
|
46507
|
+
boardThickness: board.thickness ?? 1.6,
|
|
46508
|
+
fold
|
|
46509
|
+
}),
|
|
46510
|
+
board.center
|
|
46511
|
+
),
|
|
46512
|
+
new THREE44.MeshStandardMaterial({
|
|
46513
|
+
color: stiffener.material === "fr4" ? "#879568" : stiffener.material === "polyimide" ? "#bd7f27" : "#b8bdc4",
|
|
46514
|
+
side: THREE44.DoubleSide
|
|
46515
|
+
})
|
|
46516
|
+
);
|
|
46517
|
+
mesh.name = "board-stiffener";
|
|
46518
|
+
configureObjectShadows(mesh);
|
|
46519
|
+
geometry.push(mesh);
|
|
46520
|
+
}
|
|
46521
|
+
const bounds = new THREE44.Box3();
|
|
46522
|
+
for (const mesh of [...geometry, ...textures]) bounds.expandByObject(mesh);
|
|
46523
|
+
return {
|
|
46524
|
+
geometryMeshes: geometry,
|
|
46525
|
+
textureMeshes: textures,
|
|
46526
|
+
bounds: {
|
|
46527
|
+
minX: bounds.min.x,
|
|
46528
|
+
maxX: bounds.max.x,
|
|
46529
|
+
minY: bounds.min.y,
|
|
46530
|
+
maxY: bounds.max.y,
|
|
46531
|
+
minZ: bounds.min.z,
|
|
46532
|
+
maxZ: bounds.max.z
|
|
46533
|
+
}
|
|
46534
|
+
};
|
|
46535
|
+
}
|
|
46536
|
+
|
|
45403
46537
|
// src/CadViewerManifold.tsx
|
|
45404
46538
|
import { su as su17 } from "@tscircuit/circuit-json-util";
|
|
45405
46539
|
import { useEffect as useEffect28, useMemo as useMemo24, useState as useState17 } from "react";
|
|
45406
|
-
import * as
|
|
46540
|
+
import * as THREE51 from "three";
|
|
45407
46541
|
|
|
45408
46542
|
// src/hooks/useManifoldBoardBuilder.ts
|
|
45409
46543
|
import { su as su16 } from "@tscircuit/circuit-json-util";
|
|
45410
46544
|
import { useEffect as useEffect27, useMemo as useMemo23, useRef as useRef9, useState as useState16 } from "react";
|
|
45411
|
-
import * as
|
|
46545
|
+
import * as THREE48 from "three";
|
|
45412
46546
|
|
|
45413
46547
|
// src/utils/manifold/create-manifold-board.ts
|
|
45414
46548
|
var arePointsClockwise2 = (points) => {
|
|
45415
|
-
let
|
|
46549
|
+
let area2 = 0;
|
|
45416
46550
|
for (let i = 0; i < points.length; i++) {
|
|
45417
46551
|
const j = (i + 1) % points.length;
|
|
45418
46552
|
if (points[i] && points[j]) {
|
|
45419
|
-
|
|
45420
|
-
|
|
46553
|
+
area2 += points[i][0] * points[j][1];
|
|
46554
|
+
area2 -= points[j][0] * points[i][1];
|
|
45421
46555
|
}
|
|
45422
46556
|
}
|
|
45423
|
-
const
|
|
45424
|
-
return
|
|
46557
|
+
const signedArea2 = area2 / 2;
|
|
46558
|
+
return signedArea2 <= 0;
|
|
45425
46559
|
};
|
|
45426
46560
|
function createManifoldBoard(Manifold, CrossSection, boardData, pcbThickness, manifoldInstancesForCleanup) {
|
|
45427
46561
|
let boardOp;
|
|
@@ -45515,16 +46649,16 @@ function createRoundedRectPrism({
|
|
|
45515
46649
|
|
|
45516
46650
|
// src/utils/manifold/process-cutouts.ts
|
|
45517
46651
|
var arePointsClockwise3 = (points) => {
|
|
45518
|
-
let
|
|
46652
|
+
let area2 = 0;
|
|
45519
46653
|
for (let i = 0; i < points.length; i++) {
|
|
45520
46654
|
const j = (i + 1) % points.length;
|
|
45521
46655
|
if (points[i] && points[j]) {
|
|
45522
|
-
|
|
45523
|
-
|
|
46656
|
+
area2 += points[i][0] * points[j][1];
|
|
46657
|
+
area2 -= points[j][0] * points[i][1];
|
|
45524
46658
|
}
|
|
45525
46659
|
}
|
|
45526
|
-
const
|
|
45527
|
-
return
|
|
46660
|
+
const signedArea2 = area2 / 2;
|
|
46661
|
+
return signedArea2 <= 0;
|
|
45528
46662
|
};
|
|
45529
46663
|
function processCutoutsForManifold(Manifold, CrossSection, circuitJson, pcbThickness, manifoldInstancesForCleanup) {
|
|
45530
46664
|
const cutoutOps = [];
|
|
@@ -45719,13 +46853,13 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
|
|
|
45719
46853
|
holeOp = createRectOp(holeW, holeH, drillDepth);
|
|
45720
46854
|
} else if (holeShape === "oval") {
|
|
45721
46855
|
let points = createEllipsePoints2(holeW, holeH, SMOOTH_CIRCLE_SEGMENTS);
|
|
45722
|
-
let
|
|
46856
|
+
let area2 = 0;
|
|
45723
46857
|
for (let i = 0; i < points.length; i++) {
|
|
45724
46858
|
const j = (i + 1) % points.length;
|
|
45725
|
-
|
|
45726
|
-
|
|
46859
|
+
area2 += points[i][0] * points[j][1];
|
|
46860
|
+
area2 -= points[j][0] * points[i][1];
|
|
45727
46861
|
}
|
|
45728
|
-
if (
|
|
46862
|
+
if (area2 <= 0) {
|
|
45729
46863
|
points = points.reverse();
|
|
45730
46864
|
}
|
|
45731
46865
|
const crossSection = CrossSection.ofPolygons([points]);
|
|
@@ -45757,17 +46891,17 @@ function processNonPlatedHolesForManifold(Manifold, CrossSection, circuitJson, p
|
|
|
45757
46891
|
|
|
45758
46892
|
// src/utils/manifold/process-plated-holes.ts
|
|
45759
46893
|
import { su as su15 } from "@tscircuit/circuit-json-util";
|
|
45760
|
-
import * as
|
|
46894
|
+
import * as THREE46 from "three";
|
|
45761
46895
|
|
|
45762
46896
|
// src/utils/manifold-mesh-to-three-geometry.ts
|
|
45763
|
-
import * as
|
|
46897
|
+
import * as THREE45 from "three";
|
|
45764
46898
|
function manifoldMeshToThreeGeometry(manifoldMesh) {
|
|
45765
|
-
const geometry = new
|
|
46899
|
+
const geometry = new THREE45.BufferGeometry();
|
|
45766
46900
|
geometry.setAttribute(
|
|
45767
46901
|
"position",
|
|
45768
|
-
new
|
|
46902
|
+
new THREE45.Float32BufferAttribute(manifoldMesh.vertProperties, 3)
|
|
45769
46903
|
);
|
|
45770
|
-
geometry.setIndex(new
|
|
46904
|
+
geometry.setIndex(new THREE45.Uint32BufferAttribute(manifoldMesh.triVerts, 1));
|
|
45771
46905
|
if (manifoldMesh.runIndex && manifoldMesh.runIndex.length > 1 && manifoldMesh.runOriginalID) {
|
|
45772
46906
|
for (let i = 0; i < manifoldMesh.runIndex.length - 1; i++) {
|
|
45773
46907
|
const start = manifoldMesh.runIndex[i];
|
|
@@ -45782,16 +46916,16 @@ function manifoldMeshToThreeGeometry(manifoldMesh) {
|
|
|
45782
46916
|
|
|
45783
46917
|
// src/utils/manifold/process-plated-holes.ts
|
|
45784
46918
|
var arePointsClockwise4 = (points) => {
|
|
45785
|
-
let
|
|
46919
|
+
let area2 = 0;
|
|
45786
46920
|
for (let i = 0; i < points.length; i++) {
|
|
45787
46921
|
const j = (i + 1) % points.length;
|
|
45788
46922
|
if (points[i] && points[j]) {
|
|
45789
|
-
|
|
45790
|
-
|
|
46923
|
+
area2 += points[i][0] * points[j][1];
|
|
46924
|
+
area2 -= points[j][0] * points[i][1];
|
|
45791
46925
|
}
|
|
45792
46926
|
}
|
|
45793
|
-
const
|
|
45794
|
-
return
|
|
46927
|
+
const signedArea2 = area2 / 2;
|
|
46928
|
+
return signedArea2 <= 0;
|
|
45795
46929
|
};
|
|
45796
46930
|
var createEllipsePoints = (width10, height10, segments) => {
|
|
45797
46931
|
const points = [];
|
|
@@ -45801,7 +46935,7 @@ var createEllipsePoints = (width10, height10, segments) => {
|
|
|
45801
46935
|
}
|
|
45802
46936
|
return points;
|
|
45803
46937
|
};
|
|
45804
|
-
var COPPER_COLOR = new
|
|
46938
|
+
var COPPER_COLOR = new THREE46.Color(...colors.copper);
|
|
45805
46939
|
var PLATED_HOLE_LIP_HEIGHT = 0.05;
|
|
45806
46940
|
var PLATED_HOLE_PAD_THICKNESS = 3e-3;
|
|
45807
46941
|
var PLATED_HOLE_SURFACE_CLEARANCE = 5e-4;
|
|
@@ -46431,7 +47565,7 @@ function processPlatedHolesForManifold(Manifold, CrossSection, circuitJson, pcbT
|
|
|
46431
47565
|
}
|
|
46432
47566
|
|
|
46433
47567
|
// src/utils/manifold/process-vias.ts
|
|
46434
|
-
import * as
|
|
47568
|
+
import * as THREE47 from "three";
|
|
46435
47569
|
|
|
46436
47570
|
// src/utils/via-geoms.ts
|
|
46437
47571
|
function createViaCopper2({
|
|
@@ -46469,7 +47603,7 @@ function createViaCopper2({
|
|
|
46469
47603
|
}
|
|
46470
47604
|
|
|
46471
47605
|
// src/utils/manifold/process-vias.ts
|
|
46472
|
-
var COPPER_COLOR2 = new
|
|
47606
|
+
var COPPER_COLOR2 = new THREE47.Color(...colors.copper);
|
|
46473
47607
|
function processViasForManifold(Manifold, circuitJson, pcbThickness, manifoldInstancesForCleanup, boardClipVolume) {
|
|
46474
47608
|
const viaBoardDrills = [];
|
|
46475
47609
|
const pcbVias = getPcbVias(circuitJson);
|
|
@@ -46690,7 +47824,7 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
|
|
|
46690
47824
|
{
|
|
46691
47825
|
key: "plated-holes-union",
|
|
46692
47826
|
geometry: cutPlatedGeom,
|
|
46693
|
-
color: new
|
|
47827
|
+
color: new THREE48.Color(
|
|
46694
47828
|
colors.copper[0],
|
|
46695
47829
|
colors.copper[1],
|
|
46696
47830
|
colors.copper[2]
|
|
@@ -46760,11 +47894,11 @@ var useManifoldBoardBuilder = (manifoldJSModule, circuitJson, visibility) => {
|
|
|
46760
47894
|
};
|
|
46761
47895
|
|
|
46762
47896
|
// src/utils/manifold/create-three-geometry-meshes.ts
|
|
46763
|
-
import * as
|
|
47897
|
+
import * as THREE50 from "three";
|
|
46764
47898
|
|
|
46765
47899
|
// src/utils/create-board-material.ts
|
|
46766
|
-
import * as
|
|
46767
|
-
var DEFAULT_SIDE =
|
|
47900
|
+
import * as THREE49 from "three";
|
|
47901
|
+
var DEFAULT_SIDE = THREE49.DoubleSide;
|
|
46768
47902
|
var createBoardMaterial = ({
|
|
46769
47903
|
material,
|
|
46770
47904
|
color,
|
|
@@ -46772,7 +47906,7 @@ var createBoardMaterial = ({
|
|
|
46772
47906
|
isFaux = false
|
|
46773
47907
|
}) => {
|
|
46774
47908
|
if (material === "fr4") {
|
|
46775
|
-
return new
|
|
47909
|
+
return new THREE49.MeshPhysicalMaterial({
|
|
46776
47910
|
color,
|
|
46777
47911
|
side,
|
|
46778
47912
|
metalness: 0,
|
|
@@ -46790,7 +47924,7 @@ var createBoardMaterial = ({
|
|
|
46790
47924
|
polygonOffsetUnits: 1
|
|
46791
47925
|
});
|
|
46792
47926
|
}
|
|
46793
|
-
return new
|
|
47927
|
+
return new THREE49.MeshStandardMaterial({
|
|
46794
47928
|
color,
|
|
46795
47929
|
side,
|
|
46796
47930
|
flatShading: true,
|
|
@@ -46809,12 +47943,12 @@ function createGeometryMeshes(geoms) {
|
|
|
46809
47943
|
const meshes = [];
|
|
46810
47944
|
if (!geoms) return meshes;
|
|
46811
47945
|
if (geoms.board?.geometry) {
|
|
46812
|
-
const mesh = new
|
|
47946
|
+
const mesh = new THREE50.Mesh(
|
|
46813
47947
|
geoms.board.geometry,
|
|
46814
47948
|
createBoardMaterial({
|
|
46815
47949
|
material: geoms.board.material,
|
|
46816
47950
|
color: geoms.board.color,
|
|
46817
|
-
side:
|
|
47951
|
+
side: THREE50.DoubleSide,
|
|
46818
47952
|
isFaux: geoms.board.isFaux
|
|
46819
47953
|
})
|
|
46820
47954
|
);
|
|
@@ -46825,11 +47959,11 @@ function createGeometryMeshes(geoms) {
|
|
|
46825
47959
|
const createMeshesFromArray = (geomArray) => {
|
|
46826
47960
|
if (geomArray) {
|
|
46827
47961
|
for (const comp of geomArray) {
|
|
46828
|
-
const mesh = new
|
|
47962
|
+
const mesh = new THREE50.Mesh(
|
|
46829
47963
|
comp.geometry,
|
|
46830
|
-
new
|
|
47964
|
+
new THREE50.MeshStandardMaterial({
|
|
46831
47965
|
color: comp.color,
|
|
46832
|
-
side:
|
|
47966
|
+
side: THREE50.DoubleSide,
|
|
46833
47967
|
flatShading: true
|
|
46834
47968
|
// Consistent with board
|
|
46835
47969
|
})
|
|
@@ -46874,7 +48008,7 @@ var BoardMeshes = ({
|
|
|
46874
48008
|
const typedMaterial = material;
|
|
46875
48009
|
for (const prop of textureProps) {
|
|
46876
48010
|
const texture = typedMaterial[prop];
|
|
46877
|
-
if (texture && texture instanceof
|
|
48011
|
+
if (texture && texture instanceof THREE51.Texture) {
|
|
46878
48012
|
texture.dispose();
|
|
46879
48013
|
}
|
|
46880
48014
|
}
|
|
@@ -46885,7 +48019,7 @@ var BoardMeshes = ({
|
|
|
46885
48019
|
if (!rootObject) return;
|
|
46886
48020
|
for (const mesh of geometryMeshes) {
|
|
46887
48021
|
let shouldShow = true;
|
|
46888
|
-
if (mesh.name === "board-geom") {
|
|
48022
|
+
if (mesh.name === "board-geom" || mesh.name === "board-stiffener") {
|
|
46889
48023
|
shouldShow = visibility.boardBody;
|
|
46890
48024
|
} else if (mesh.name.includes("plated_hole") || mesh.name.includes("via")) {
|
|
46891
48025
|
shouldShow = visibility.topCopper || visibility.bottomCopper;
|
|
@@ -46922,6 +48056,7 @@ var BoardMeshes = ({
|
|
|
46922
48056
|
var MANIFOLD_CDN_BASE_URL = "https://cdn.jsdelivr.net/npm/manifold-3d@3.2.1";
|
|
46923
48057
|
var CadViewerManifold = ({
|
|
46924
48058
|
circuitJson: circuitJsonProp,
|
|
48059
|
+
foldPcbs,
|
|
46925
48060
|
autoRotateDisabled,
|
|
46926
48061
|
clickToInteractEnabled,
|
|
46927
48062
|
onUserInteraction,
|
|
@@ -47009,14 +48144,40 @@ try {
|
|
|
47009
48144
|
boardData,
|
|
47010
48145
|
isFauxBoard
|
|
47011
48146
|
} = useManifoldBoardBuilder(manifoldJSModule, circuitJson, visibility);
|
|
47012
|
-
const
|
|
47013
|
-
|
|
47014
|
-
|
|
47015
|
-
|
|
47016
|
-
|
|
48147
|
+
const flex = useMemo24(() => {
|
|
48148
|
+
try {
|
|
48149
|
+
const resolvedFoldPcbs = resolveFoldPcbs(circuitJson, foldPcbs);
|
|
48150
|
+
const posedJson = transformCircuitJsonCadComponents(circuitJson, {
|
|
48151
|
+
foldPcbs: resolvedFoldPcbs
|
|
48152
|
+
});
|
|
48153
|
+
const meshes = createFlexMeshes(
|
|
48154
|
+
createGeometryMeshes(geoms),
|
|
48155
|
+
createTextureMeshes(textures, boardData, pcbThickness, isFauxBoard),
|
|
48156
|
+
circuitJson,
|
|
48157
|
+
resolvedFoldPcbs
|
|
48158
|
+
);
|
|
48159
|
+
return { ...meshes, posedJson, error: void 0 };
|
|
48160
|
+
} catch (error) {
|
|
48161
|
+
return {
|
|
48162
|
+
error: error instanceof Error ? error.message : String(error),
|
|
48163
|
+
geometryMeshes: [],
|
|
48164
|
+
textureMeshes: [],
|
|
48165
|
+
posedJson: circuitJson,
|
|
48166
|
+
bounds: void 0
|
|
48167
|
+
};
|
|
48168
|
+
}
|
|
48169
|
+
}, [
|
|
48170
|
+
geoms,
|
|
48171
|
+
textures,
|
|
48172
|
+
boardData,
|
|
48173
|
+
pcbThickness,
|
|
48174
|
+
isFauxBoard,
|
|
48175
|
+
circuitJson,
|
|
48176
|
+
foldPcbs
|
|
48177
|
+
]);
|
|
47017
48178
|
const cadComponents = useMemo24(
|
|
47018
|
-
() => su17(
|
|
47019
|
-
[
|
|
48179
|
+
() => su17(flex.posedJson).cad_component.list(),
|
|
48180
|
+
[flex.posedJson]
|
|
47020
48181
|
);
|
|
47021
48182
|
const boardDimensions = useMemo24(() => {
|
|
47022
48183
|
if (!boardData) return void 0;
|
|
@@ -47063,10 +48224,11 @@ try {
|
|
|
47063
48224
|
if (!manifoldJSModule) {
|
|
47064
48225
|
return /* @__PURE__ */ jsx19("div", { style: { padding: "1em" }, children: "Loading Manifold module..." });
|
|
47065
48226
|
}
|
|
47066
|
-
if (builderError) {
|
|
48227
|
+
if (builderError || flex.error) {
|
|
47067
48228
|
return /* @__PURE__ */ jsxs6(
|
|
47068
48229
|
"div",
|
|
47069
48230
|
{
|
|
48231
|
+
role: "alert",
|
|
47070
48232
|
style: {
|
|
47071
48233
|
color: "red",
|
|
47072
48234
|
padding: "1em",
|
|
@@ -47075,7 +48237,7 @@ try {
|
|
|
47075
48237
|
},
|
|
47076
48238
|
children: [
|
|
47077
48239
|
"Error: ",
|
|
47078
|
-
builderError
|
|
48240
|
+
builderError ?? flex.error
|
|
47079
48241
|
]
|
|
47080
48242
|
}
|
|
47081
48243
|
);
|
|
@@ -47098,10 +48260,11 @@ try {
|
|
|
47098
48260
|
/* @__PURE__ */ jsx19(
|
|
47099
48261
|
BoardMeshes,
|
|
47100
48262
|
{
|
|
47101
|
-
geometryMeshes,
|
|
47102
|
-
textureMeshes
|
|
48263
|
+
geometryMeshes: flex.geometryMeshes,
|
|
48264
|
+
textureMeshes: flex.textureMeshes
|
|
47103
48265
|
}
|
|
47104
48266
|
),
|
|
48267
|
+
flex.bounds && /* @__PURE__ */ jsx19(FitCameraToComparison, { bounds: flex.bounds }),
|
|
47105
48268
|
cadComponents.map((cad_component) => /* @__PURE__ */ jsx19(
|
|
47106
48269
|
ThreeErrorBoundary,
|
|
47107
48270
|
{
|
|
@@ -47110,7 +48273,7 @@ try {
|
|
|
47110
48273
|
AnyCadComponent,
|
|
47111
48274
|
{
|
|
47112
48275
|
cad_component,
|
|
47113
|
-
circuitJson,
|
|
48276
|
+
circuitJson: flex.posedJson,
|
|
47114
48277
|
resolveStaticAsset
|
|
47115
48278
|
}
|
|
47116
48279
|
)
|
|
@@ -52820,6 +53983,27 @@ var MenuItemImpl = /* @__PURE__ */ React41.forwardRef(
|
|
|
52820
53983
|
);
|
|
52821
53984
|
}, "MenuItemImpl")
|
|
52822
53985
|
);
|
|
53986
|
+
var MenuCheckboxItem = /* @__PURE__ */ React41.forwardRef(
|
|
53987
|
+
// blank line to reduce diff noise
|
|
53988
|
+
/* @__PURE__ */ __name21(function MenuCheckboxItem2(props, forwardedRef) {
|
|
53989
|
+
const { checked = false, onCheckedChange, ...checkboxItemProps } = props;
|
|
53990
|
+
return /* @__PURE__ */ jsx30(ItemIndicatorProvider, { scope: props.__scopeMenu, checked, children: /* @__PURE__ */ jsx30(
|
|
53991
|
+
MenuItem,
|
|
53992
|
+
{
|
|
53993
|
+
role: "menuitemcheckbox",
|
|
53994
|
+
"aria-checked": isIndeterminate(checked) ? "mixed" : checked,
|
|
53995
|
+
...checkboxItemProps,
|
|
53996
|
+
ref: forwardedRef,
|
|
53997
|
+
"data-state": getCheckedState(checked),
|
|
53998
|
+
onSelect: composeEventHandlers(
|
|
53999
|
+
checkboxItemProps.onSelect,
|
|
54000
|
+
() => onCheckedChange?.(isIndeterminate(checked) ? true : !checked),
|
|
54001
|
+
{ checkForDefaultPrevented: false }
|
|
54002
|
+
)
|
|
54003
|
+
}
|
|
54004
|
+
) });
|
|
54005
|
+
}, "MenuCheckboxItem")
|
|
54006
|
+
);
|
|
52823
54007
|
var RADIO_GROUP_NAME = "MenuRadioGroup";
|
|
52824
54008
|
var [RadioGroupProvider, useRadioGroupContext] = createMenuContext(
|
|
52825
54009
|
RADIO_GROUP_NAME,
|
|
@@ -53087,10 +54271,10 @@ function isPointInPolygon(point, polygon2) {
|
|
|
53087
54271
|
return inside;
|
|
53088
54272
|
}
|
|
53089
54273
|
__name21(isPointInPolygon, "isPointInPolygon");
|
|
53090
|
-
function isPointerInGraceArea(event,
|
|
53091
|
-
if (!
|
|
54274
|
+
function isPointerInGraceArea(event, area2) {
|
|
54275
|
+
if (!area2) return false;
|
|
53092
54276
|
const cursorPos = { x: event.clientX, y: event.clientY };
|
|
53093
|
-
return isPointInPolygon(cursorPos,
|
|
54277
|
+
return isPointInPolygon(cursorPos, area2);
|
|
53094
54278
|
}
|
|
53095
54279
|
__name21(isPointerInGraceArea, "isPointerInGraceArea");
|
|
53096
54280
|
function whenMouse(handler) {
|
|
@@ -53102,6 +54286,7 @@ var Anchor2 = MenuAnchor;
|
|
|
53102
54286
|
var Portal3 = MenuPortal;
|
|
53103
54287
|
var Content2 = MenuContent;
|
|
53104
54288
|
var Item2 = MenuItem;
|
|
54289
|
+
var CheckboxItem = MenuCheckboxItem;
|
|
53105
54290
|
var Separator = MenuSeparator;
|
|
53106
54291
|
var Sub = MenuSub;
|
|
53107
54292
|
var SubTrigger = MenuSubTrigger;
|
|
@@ -53243,6 +54428,11 @@ var DropdownMenuItem = /* @__PURE__ */ React42.forwardRef(
|
|
|
53243
54428
|
return /* @__PURE__ */ jsx31(Item2, { ...menuScope, ...itemProps, ref: forwardedRef });
|
|
53244
54429
|
}, "DropdownMenuItem")
|
|
53245
54430
|
);
|
|
54431
|
+
var DropdownMenuCheckboxItem = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */ __name22(function DropdownMenuCheckboxItem2(props, forwardedRef) {
|
|
54432
|
+
const { __scopeDropdownMenu, ...checkboxItemProps } = props;
|
|
54433
|
+
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
54434
|
+
return /* @__PURE__ */ jsx31(CheckboxItem, { ...menuScope, ...checkboxItemProps, ref: forwardedRef });
|
|
54435
|
+
}, "DropdownMenuCheckboxItem"));
|
|
53246
54436
|
var DropdownMenuSeparator = /* @__PURE__ */ React42.forwardRef(/* @__PURE__ */ __name22(function DropdownMenuSeparator2(props, forwardedRef) {
|
|
53247
54437
|
const { __scopeDropdownMenu, ...separatorProps } = props;
|
|
53248
54438
|
const menuScope = useMenuScope(__scopeDropdownMenu);
|
|
@@ -53292,6 +54482,7 @@ var Trigger = DropdownMenuTrigger;
|
|
|
53292
54482
|
var Portal22 = DropdownMenuPortal;
|
|
53293
54483
|
var Content22 = DropdownMenuContent;
|
|
53294
54484
|
var Item22 = DropdownMenuItem;
|
|
54485
|
+
var CheckboxItem2 = DropdownMenuCheckboxItem;
|
|
53295
54486
|
var Separator2 = DropdownMenuSeparator;
|
|
53296
54487
|
var Sub2 = DropdownMenuSub;
|
|
53297
54488
|
var SubTrigger2 = DropdownMenuSubTrigger;
|
|
@@ -53860,6 +55051,9 @@ var ContextMenu = ({
|
|
|
53860
55051
|
engine,
|
|
53861
55052
|
cameraPreset,
|
|
53862
55053
|
autoRotate,
|
|
55054
|
+
foldPcbs = false,
|
|
55055
|
+
onFoldPcbsToggle,
|
|
55056
|
+
flexScene = false,
|
|
53863
55057
|
referenceObject = null,
|
|
53864
55058
|
onEngineSwitch,
|
|
53865
55059
|
onCameraPresetSelect,
|
|
@@ -54078,6 +55272,23 @@ var ContextMenu = ({
|
|
|
54078
55272
|
}
|
|
54079
55273
|
) })
|
|
54080
55274
|
] }),
|
|
55275
|
+
onFoldPcbsToggle && /* @__PURE__ */ jsxs8(
|
|
55276
|
+
CheckboxItem2,
|
|
55277
|
+
{
|
|
55278
|
+
checked: foldPcbs,
|
|
55279
|
+
onCheckedChange: onFoldPcbsToggle,
|
|
55280
|
+
style: {
|
|
55281
|
+
...itemStyles2,
|
|
55282
|
+
backgroundColor: hoveredItem === "fold" ? "#404040" : "transparent"
|
|
55283
|
+
},
|
|
55284
|
+
onMouseEnter: () => setHoveredItem("fold"),
|
|
55285
|
+
onMouseLeave: () => setHoveredItem(null),
|
|
55286
|
+
children: [
|
|
55287
|
+
/* @__PURE__ */ jsx34("span", { style: iconContainerStyles2, children: foldPcbs && /* @__PURE__ */ jsx34(CheckIcon, {}) }),
|
|
55288
|
+
/* @__PURE__ */ jsx34("span", { children: "Fold PCBs" })
|
|
55289
|
+
]
|
|
55290
|
+
}
|
|
55291
|
+
),
|
|
54081
55292
|
/* @__PURE__ */ jsxs8(
|
|
54082
55293
|
Item22,
|
|
54083
55294
|
{
|
|
@@ -54117,7 +55328,7 @@ var ContextMenu = ({
|
|
|
54117
55328
|
}
|
|
54118
55329
|
),
|
|
54119
55330
|
/* @__PURE__ */ jsx34(Separator2, { style: separatorStyles2 }),
|
|
54120
|
-
/* @__PURE__ */ jsxs8(
|
|
55331
|
+
!flexScene && /* @__PURE__ */ jsxs8(
|
|
54121
55332
|
Item22,
|
|
54122
55333
|
{
|
|
54123
55334
|
style: {
|
|
@@ -54134,11 +55345,17 @@ var ContextMenu = ({
|
|
|
54134
55345
|
onMouseLeave: () => setHoveredItem(null),
|
|
54135
55346
|
onTouchStart: () => setHoveredItem("engine"),
|
|
54136
55347
|
children: [
|
|
54137
|
-
/* @__PURE__ */ jsxs8(
|
|
54138
|
-
"
|
|
54139
|
-
|
|
54140
|
-
|
|
54141
|
-
|
|
55348
|
+
/* @__PURE__ */ jsxs8(
|
|
55349
|
+
"span",
|
|
55350
|
+
{
|
|
55351
|
+
style: { flex: 1, display: "flex", alignItems: "center" },
|
|
55352
|
+
children: [
|
|
55353
|
+
"Switch to ",
|
|
55354
|
+
engine === "jscad" ? "Manifold" : "JSCAD",
|
|
55355
|
+
" Engine"
|
|
55356
|
+
]
|
|
55357
|
+
}
|
|
55358
|
+
),
|
|
54142
55359
|
/* @__PURE__ */ jsx34(
|
|
54143
55360
|
"div",
|
|
54144
55361
|
{
|
|
@@ -54807,7 +56024,7 @@ var useGlobalDownloadGltf = () => {
|
|
|
54807
56024
|
|
|
54808
56025
|
// src/CadViewer.tsx
|
|
54809
56026
|
import { jsx as jsx37, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
54810
|
-
var DEFAULT_TARGET = new
|
|
56027
|
+
var DEFAULT_TARGET = new THREE52.Vector3(0, 0, 0);
|
|
54811
56028
|
var INITIAL_CAMERA_POSITION = [5, -5, 5];
|
|
54812
56029
|
var readStoredCameraType = () => {
|
|
54813
56030
|
if (typeof window === "undefined") return void 0;
|
|
@@ -54815,6 +56032,18 @@ var readStoredCameraType = () => {
|
|
|
54815
56032
|
return stored === "orthographic" || stored === "perspective" ? stored : void 0;
|
|
54816
56033
|
};
|
|
54817
56034
|
var CadViewerInner = (props) => {
|
|
56035
|
+
const childrenCircuitJson = useConvertChildrenToCircuitJson(
|
|
56036
|
+
props.circuitJson ? void 0 : props.children
|
|
56037
|
+
);
|
|
56038
|
+
const circuitJson = props.circuitJson ?? childrenCircuitJson;
|
|
56039
|
+
const hasBends = circuitJson.some((element) => element.type === "pcb_bend");
|
|
56040
|
+
const hasFlexGeometry = hasBends || circuitJson.some((element) => element.type === "pcb_stiffener");
|
|
56041
|
+
const [foldPcbsOverride, setFoldPcbs] = useState39(
|
|
56042
|
+
void 0
|
|
56043
|
+
);
|
|
56044
|
+
const foldPcbs = foldPcbsOverride ?? props.foldPcbs;
|
|
56045
|
+
const resolvedFoldPcbs = resolveFoldPcbs(circuitJson, foldPcbs);
|
|
56046
|
+
const resolvedProps = { ...props, circuitJson, children: void 0 };
|
|
54818
56047
|
const [engine, setEngine] = useState39(() => {
|
|
54819
56048
|
const stored = window.localStorage.getItem("cadViewerEngine");
|
|
54820
56049
|
return stored === "jscad" || stored === "manifold" ? stored : "manifold";
|
|
@@ -54978,10 +56207,20 @@ var CadViewerInner = (props) => {
|
|
|
54978
56207
|
},
|
|
54979
56208
|
...contextMenuEventHandlers,
|
|
54980
56209
|
children: [
|
|
54981
|
-
|
|
56210
|
+
hasFlexGeometry ? /* @__PURE__ */ jsx37(
|
|
56211
|
+
CadViewerManifold_default,
|
|
56212
|
+
{
|
|
56213
|
+
...resolvedProps,
|
|
56214
|
+
foldPcbs,
|
|
56215
|
+
autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
|
|
56216
|
+
onUserInteraction: handleUserInteraction,
|
|
56217
|
+
onCameraControllerReady: handleCameraControllerReady,
|
|
56218
|
+
referenceObject
|
|
56219
|
+
}
|
|
56220
|
+
) : engine === "jscad" ? /* @__PURE__ */ jsx37(
|
|
54982
56221
|
CadViewerJscad,
|
|
54983
56222
|
{
|
|
54984
|
-
...
|
|
56223
|
+
...resolvedProps,
|
|
54985
56224
|
autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
|
|
54986
56225
|
cameraType,
|
|
54987
56226
|
onUserInteraction: handleUserInteraction,
|
|
@@ -54991,7 +56230,7 @@ var CadViewerInner = (props) => {
|
|
|
54991
56230
|
) : /* @__PURE__ */ jsx37(
|
|
54992
56231
|
CadViewerManifold_default,
|
|
54993
56232
|
{
|
|
54994
|
-
...
|
|
56233
|
+
...resolvedProps,
|
|
54995
56234
|
autoRotateDisabled: props.autoRotateDisabled || !autoRotate,
|
|
54996
56235
|
cameraType,
|
|
54997
56236
|
onUserInteraction: handleUserInteraction,
|
|
@@ -55005,6 +56244,13 @@ var CadViewerInner = (props) => {
|
|
|
55005
56244
|
menuRef,
|
|
55006
56245
|
menuPos,
|
|
55007
56246
|
engine,
|
|
56247
|
+
flexScene: hasFlexGeometry,
|
|
56248
|
+
foldPcbs: resolvedFoldPcbs,
|
|
56249
|
+
onFoldPcbsToggle: hasBends ? () => {
|
|
56250
|
+
setFoldPcbs(!resolvedFoldPcbs);
|
|
56251
|
+
setCameraPreset("Custom");
|
|
56252
|
+
closeMenu();
|
|
56253
|
+
} : void 0,
|
|
55008
56254
|
cameraPreset,
|
|
55009
56255
|
autoRotate,
|
|
55010
56256
|
referenceObject,
|
|
@@ -55066,14 +56312,14 @@ var CadViewer = (props) => {
|
|
|
55066
56312
|
// src/convert-circuit-json-to-3d-svg.ts
|
|
55067
56313
|
var import_debug = __toESM(require_browser(), 1);
|
|
55068
56314
|
import { su as su18 } from "@tscircuit/circuit-json-util";
|
|
55069
|
-
import * as
|
|
56315
|
+
import * as THREE56 from "three";
|
|
55070
56316
|
import { SVGRenderer } from "three/examples/jsm/renderers/SVGRenderer.js";
|
|
55071
56317
|
|
|
55072
56318
|
// src/utils/create-geometry-from-polygons.ts
|
|
55073
|
-
import * as
|
|
55074
|
-
import { BufferGeometry as
|
|
56319
|
+
import * as THREE53 from "three";
|
|
56320
|
+
import { BufferGeometry as BufferGeometry6, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
|
|
55075
56321
|
function createGeometryFromPolygons(polygons) {
|
|
55076
|
-
const geometry = new
|
|
56322
|
+
const geometry = new BufferGeometry6();
|
|
55077
56323
|
const vertices = [];
|
|
55078
56324
|
const normals = [];
|
|
55079
56325
|
for (const polygon2 of polygons) {
|
|
@@ -55084,12 +56330,12 @@ function createGeometryFromPolygons(polygons) {
|
|
|
55084
56330
|
...polygon2.vertices[i + 1]
|
|
55085
56331
|
// Third vertex
|
|
55086
56332
|
);
|
|
55087
|
-
const v1 = new
|
|
55088
|
-
const v2 = new
|
|
55089
|
-
const v3 = new
|
|
55090
|
-
const normal = new
|
|
55091
|
-
new
|
|
55092
|
-
new
|
|
56333
|
+
const v1 = new THREE53.Vector3(...polygon2.vertices[0]);
|
|
56334
|
+
const v2 = new THREE53.Vector3(...polygon2.vertices[i]);
|
|
56335
|
+
const v3 = new THREE53.Vector3(...polygon2.vertices[i + 1]);
|
|
56336
|
+
const normal = new THREE53.Vector3().crossVectors(
|
|
56337
|
+
new THREE53.Vector3().subVectors(v2, v1),
|
|
56338
|
+
new THREE53.Vector3().subVectors(v3, v1)
|
|
55093
56339
|
).normalize();
|
|
55094
56340
|
normals.push(
|
|
55095
56341
|
normal.x,
|
|
@@ -55104,8 +56350,8 @@ function createGeometryFromPolygons(polygons) {
|
|
|
55104
56350
|
);
|
|
55105
56351
|
}
|
|
55106
56352
|
}
|
|
55107
|
-
geometry.setAttribute("position", new
|
|
55108
|
-
geometry.setAttribute("normal", new
|
|
56353
|
+
geometry.setAttribute("position", new Float32BufferAttribute5(vertices, 3));
|
|
56354
|
+
geometry.setAttribute("normal", new Float32BufferAttribute5(normals, 3));
|
|
55109
56355
|
return geometry;
|
|
55110
56356
|
}
|
|
55111
56357
|
|
|
@@ -55113,10 +56359,10 @@ function createGeometryFromPolygons(polygons) {
|
|
|
55113
56359
|
var import_modeling2 = __toESM(require_src(), 1);
|
|
55114
56360
|
var import_jscad_planner2 = __toESM(require_dist(), 1);
|
|
55115
56361
|
var jscadModeling2 = __toESM(require_src(), 1);
|
|
55116
|
-
import * as
|
|
56362
|
+
import * as THREE55 from "three";
|
|
55117
56363
|
|
|
55118
56364
|
// src/utils/load-model.ts
|
|
55119
|
-
import * as
|
|
56365
|
+
import * as THREE54 from "three";
|
|
55120
56366
|
import { GLTFLoader as GLTFLoader2 } from "three/examples/jsm/loaders/GLTFLoader.js";
|
|
55121
56367
|
import { OBJLoader as OBJLoader2 } from "three/examples/jsm/loaders/OBJLoader.js";
|
|
55122
56368
|
import { STLLoader as STLLoader2 } from "three/examples/jsm/loaders/STLLoader.js";
|
|
@@ -55124,12 +56370,12 @@ async function load3DModel(url) {
|
|
|
55124
56370
|
if (url.endsWith(".stl")) {
|
|
55125
56371
|
const loader = new STLLoader2();
|
|
55126
56372
|
const geometry = await loader.loadAsync(url);
|
|
55127
|
-
const material = new
|
|
56373
|
+
const material = new THREE54.MeshStandardMaterial({
|
|
55128
56374
|
color: 8947848,
|
|
55129
56375
|
metalness: 0.5,
|
|
55130
56376
|
roughness: 0.5
|
|
55131
56377
|
});
|
|
55132
|
-
return new
|
|
56378
|
+
return new THREE54.Mesh(geometry, material);
|
|
55133
56379
|
}
|
|
55134
56380
|
if (url.endsWith(".obj")) {
|
|
55135
56381
|
const loader = new OBJLoader2();
|
|
@@ -55162,9 +56408,9 @@ async function renderComponent(component, scene) {
|
|
|
55162
56408
|
}
|
|
55163
56409
|
if (component.rotation) {
|
|
55164
56410
|
model.rotation.set(
|
|
55165
|
-
|
|
55166
|
-
|
|
55167
|
-
|
|
56411
|
+
THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
56412
|
+
THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
56413
|
+
THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
55168
56414
|
);
|
|
55169
56415
|
}
|
|
55170
56416
|
scene.add(model);
|
|
@@ -55178,13 +56424,13 @@ async function renderComponent(component, scene) {
|
|
|
55178
56424
|
);
|
|
55179
56425
|
if (jscadObject && (jscadObject.polygons || jscadObject.sides)) {
|
|
55180
56426
|
const threeGeom = convertCSGToThreeGeom(jscadObject);
|
|
55181
|
-
const material2 = new
|
|
56427
|
+
const material2 = new THREE55.MeshStandardMaterial({
|
|
55182
56428
|
color: 8947848,
|
|
55183
56429
|
metalness: 0.5,
|
|
55184
56430
|
roughness: 0.5,
|
|
55185
|
-
side:
|
|
56431
|
+
side: THREE55.DoubleSide
|
|
55186
56432
|
});
|
|
55187
|
-
const mesh2 = new
|
|
56433
|
+
const mesh2 = new THREE55.Mesh(threeGeom, material2);
|
|
55188
56434
|
if (component.position) {
|
|
55189
56435
|
mesh2.position.set(
|
|
55190
56436
|
component.position.x ?? 0,
|
|
@@ -55194,9 +56440,9 @@ async function renderComponent(component, scene) {
|
|
|
55194
56440
|
}
|
|
55195
56441
|
if (component.rotation) {
|
|
55196
56442
|
mesh2.rotation.set(
|
|
55197
|
-
|
|
55198
|
-
|
|
55199
|
-
|
|
56443
|
+
THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
56444
|
+
THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
56445
|
+
THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
55200
56446
|
);
|
|
55201
56447
|
}
|
|
55202
56448
|
scene.add(mesh2);
|
|
@@ -55213,17 +56459,17 @@ async function renderComponent(component, scene) {
|
|
|
55213
56459
|
if (!geom || !geom.polygons && !geom.sides) {
|
|
55214
56460
|
continue;
|
|
55215
56461
|
}
|
|
55216
|
-
const color = new
|
|
56462
|
+
const color = new THREE55.Color(geomInfo.color);
|
|
55217
56463
|
color.convertLinearToSRGB();
|
|
55218
56464
|
const geomWithColor = { ...geom, color: [color.r, color.g, color.b] };
|
|
55219
56465
|
const threeGeom = convertCSGToThreeGeom(geomWithColor);
|
|
55220
|
-
const material2 = new
|
|
56466
|
+
const material2 = new THREE55.MeshStandardMaterial({
|
|
55221
56467
|
vertexColors: true,
|
|
55222
56468
|
metalness: 0.2,
|
|
55223
56469
|
roughness: 0.8,
|
|
55224
|
-
side:
|
|
56470
|
+
side: THREE55.DoubleSide
|
|
55225
56471
|
});
|
|
55226
|
-
const mesh2 = new
|
|
56472
|
+
const mesh2 = new THREE55.Mesh(threeGeom, material2);
|
|
55227
56473
|
if (component.position) {
|
|
55228
56474
|
mesh2.position.set(
|
|
55229
56475
|
component.position.x ?? 0,
|
|
@@ -55233,22 +56479,22 @@ async function renderComponent(component, scene) {
|
|
|
55233
56479
|
}
|
|
55234
56480
|
if (component.rotation) {
|
|
55235
56481
|
mesh2.rotation.set(
|
|
55236
|
-
|
|
55237
|
-
|
|
55238
|
-
|
|
56482
|
+
THREE55.MathUtils.degToRad(component.rotation.x ?? 0),
|
|
56483
|
+
THREE55.MathUtils.degToRad(component.rotation.y ?? 0),
|
|
56484
|
+
THREE55.MathUtils.degToRad(component.rotation.z ?? 0)
|
|
55239
56485
|
);
|
|
55240
56486
|
}
|
|
55241
56487
|
scene.add(mesh2);
|
|
55242
56488
|
}
|
|
55243
56489
|
return;
|
|
55244
56490
|
}
|
|
55245
|
-
const geometry = new
|
|
55246
|
-
const material = new
|
|
56491
|
+
const geometry = new THREE55.BoxGeometry(0.5, 0.5, 0.5);
|
|
56492
|
+
const material = new THREE55.MeshStandardMaterial({
|
|
55247
56493
|
color: 16711680,
|
|
55248
56494
|
transparent: true,
|
|
55249
56495
|
opacity: 0.25
|
|
55250
56496
|
});
|
|
55251
|
-
const mesh = new
|
|
56497
|
+
const mesh = new THREE55.Mesh(geometry, material);
|
|
55252
56498
|
if (component.position) {
|
|
55253
56499
|
mesh.position.set(
|
|
55254
56500
|
component.position.x ?? 0,
|
|
@@ -55269,11 +56515,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
55269
56515
|
padding = 20,
|
|
55270
56516
|
zoom = 1.5
|
|
55271
56517
|
} = options;
|
|
55272
|
-
const scene = new
|
|
56518
|
+
const scene = new THREE56.Scene();
|
|
55273
56519
|
const renderer = new SVGRenderer();
|
|
55274
56520
|
renderer.setSize(width10, height10);
|
|
55275
|
-
renderer.setClearColor(new
|
|
55276
|
-
const camera = new
|
|
56521
|
+
renderer.setClearColor(new THREE56.Color(backgroundColor), 1);
|
|
56522
|
+
const camera = new THREE56.OrthographicCamera();
|
|
55277
56523
|
const aspect = width10 / height10;
|
|
55278
56524
|
const frustumSize = 100;
|
|
55279
56525
|
const halfFrustumSize = frustumSize / 2 / zoom;
|
|
@@ -55287,11 +56533,11 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
55287
56533
|
camera.position.set(position.x, position.y, position.z);
|
|
55288
56534
|
camera.up.set(0, 1, 0);
|
|
55289
56535
|
const lookAt = options.camera?.lookAt ?? { x: 0, y: 0, z: 0 };
|
|
55290
|
-
camera.lookAt(new
|
|
56536
|
+
camera.lookAt(new THREE56.Vector3(lookAt.x, lookAt.y, lookAt.z));
|
|
55291
56537
|
camera.updateProjectionMatrix();
|
|
55292
|
-
const ambientLight = new
|
|
56538
|
+
const ambientLight = new THREE56.AmbientLight(16777215, Math.PI / 2);
|
|
55293
56539
|
scene.add(ambientLight);
|
|
55294
|
-
const pointLight = new
|
|
56540
|
+
const pointLight = new THREE56.PointLight(16777215, Math.PI / 4);
|
|
55295
56541
|
pointLight.position.set(-10, -10, 10);
|
|
55296
56542
|
scene.add(pointLight);
|
|
55297
56543
|
const components = su18(circuitJson).cad_component.list();
|
|
@@ -55316,28 +56562,28 @@ async function convertCircuitJsonTo3dSvg(circuitJson, options = {}) {
|
|
|
55316
56562
|
const material = createBoardMaterial({
|
|
55317
56563
|
material: boardData?.material,
|
|
55318
56564
|
color: edgeColor,
|
|
55319
|
-
side:
|
|
56565
|
+
side: THREE56.DoubleSide
|
|
55320
56566
|
});
|
|
55321
|
-
const mesh = new
|
|
56567
|
+
const mesh = new THREE56.Mesh(geometry, material);
|
|
55322
56568
|
scene.add(mesh);
|
|
55323
56569
|
}
|
|
55324
56570
|
}
|
|
55325
|
-
const gridColor = new
|
|
55326
|
-
const gridHelper = new
|
|
56571
|
+
const gridColor = new THREE56.Color(8947848);
|
|
56572
|
+
const gridHelper = new THREE56.GridHelper(100, 100, gridColor, gridColor);
|
|
55327
56573
|
gridHelper.rotation.x = Math.PI / 2;
|
|
55328
56574
|
const materials = Array.isArray(gridHelper.material) ? gridHelper.material : [gridHelper.material];
|
|
55329
56575
|
for (const mat of materials) {
|
|
55330
56576
|
mat.transparent = true;
|
|
55331
56577
|
mat.opacity = 0.3;
|
|
55332
|
-
if (mat instanceof
|
|
56578
|
+
if (mat instanceof THREE56.LineBasicMaterial) {
|
|
55333
56579
|
mat.color = gridColor;
|
|
55334
56580
|
mat.vertexColors = false;
|
|
55335
56581
|
}
|
|
55336
56582
|
}
|
|
55337
56583
|
scene.add(gridHelper);
|
|
55338
|
-
const box = new
|
|
55339
|
-
const center = box.getCenter(new
|
|
55340
|
-
const size4 = box.getSize(new
|
|
56584
|
+
const box = new THREE56.Box3().setFromObject(scene);
|
|
56585
|
+
const center = box.getCenter(new THREE56.Vector3());
|
|
56586
|
+
const size4 = box.getSize(new THREE56.Vector3());
|
|
55341
56587
|
scene.position.sub(center);
|
|
55342
56588
|
const maxDim = Math.max(size4.x, size4.y, size4.z);
|
|
55343
56589
|
if (maxDim > 0) {
|