circuit-json-to-gltf 0.0.71 → 0.0.73
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.d.ts +33 -1
- package/dist/index.js +239 -64
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -196,6 +196,38 @@ declare const COORDINATE_TRANSFORMS: {
|
|
|
196
196
|
readonly OBJ_Z_UP_TO_Y_UP: CoordinateTransformConfig;
|
|
197
197
|
};
|
|
198
198
|
|
|
199
|
+
interface CameraFitOptions {
|
|
200
|
+
/**
|
|
201
|
+
* Target-to-camera direction vector used for solved camera position.
|
|
202
|
+
*/
|
|
203
|
+
direction?: readonly [number, number, number];
|
|
204
|
+
/**
|
|
205
|
+
* Vertical field of view in degrees.
|
|
206
|
+
*/
|
|
207
|
+
fov?: number;
|
|
208
|
+
/**
|
|
209
|
+
* Aspect ratio (width / height) used for horizontal fit calculations.
|
|
210
|
+
*/
|
|
211
|
+
aspectRatio?: number;
|
|
212
|
+
/**
|
|
213
|
+
* Focal length in millimeters. If provided with sensorHeight,
|
|
214
|
+
* it is used instead of fov.
|
|
215
|
+
*/
|
|
216
|
+
focalLength?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Sensor height in millimeters for focalLength->fov conversion.
|
|
219
|
+
*/
|
|
220
|
+
sensorHeight?: number;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Calculate optimal camera position for PCB viewing based on circuit dimensions
|
|
224
|
+
*/
|
|
225
|
+
declare function getBestCameraPosition(circuitJson: CircuitJson): {
|
|
226
|
+
camPos: readonly [number, number, number];
|
|
227
|
+
lookAt: readonly [number, number, number];
|
|
228
|
+
fov: number;
|
|
229
|
+
};
|
|
230
|
+
|
|
199
231
|
declare function convertCircuitJsonToGltf(circuitJson: CircuitJson, options?: ConversionOptions): Promise<ArrayBuffer | object>;
|
|
200
232
|
|
|
201
233
|
interface Point {
|
|
@@ -208,4 +240,4 @@ interface BRepShape {
|
|
|
208
240
|
is_negative?: boolean;
|
|
209
241
|
}
|
|
210
242
|
|
|
211
|
-
export { type BRepShape, type BoardRenderOptions, type BoundingBox, type Box3D, COORDINATE_TRANSFORMS, type Camera3D, type CircuitTo3DOptions, type Color, type ConversionOptions, type CoordinateTransformConfig, type GLTFExportOptions, type LayerRef, type Light3D, type OBJMaterial, type OBJMesh, type Point, type Point3, type STLMesh, type Scene3D, type Size3, type Triangle, applyCoordinateTransform, clearGLBCache, clearOBJCache, clearSTLCache, convertCircuitJsonTo3D, convertCircuitJsonToGltf, convertSceneToGLTF, loadGLB, loadOBJ, loadSTL, renderBoardLayer, renderBoardTextures, transformTriangles };
|
|
243
|
+
export { type BRepShape, type BoardRenderOptions, type BoundingBox, type Box3D, COORDINATE_TRANSFORMS, type Camera3D, type CameraFitOptions, type CircuitTo3DOptions, type Color, type ConversionOptions, type CoordinateTransformConfig, type GLTFExportOptions, type LayerRef, type Light3D, type OBJMaterial, type OBJMesh, type Point, type Point3, type STLMesh, type Scene3D, type Size3, type Triangle, applyCoordinateTransform, clearGLBCache, clearOBJCache, clearSTLCache, convertCircuitJsonTo3D, convertCircuitJsonToGltf, convertSceneToGLTF, getBestCameraPosition, loadGLB, loadOBJ, loadSTL, renderBoardLayer, renderBoardTextures, transformTriangles };
|
package/dist/index.js
CHANGED
|
@@ -446,8 +446,8 @@ var require_add2 = __commonJS({
|
|
|
446
446
|
var require_dot = __commonJS({
|
|
447
447
|
"node_modules/@jscad/modeling/src/maths/vec3/dot.js"(exports, module) {
|
|
448
448
|
"use strict";
|
|
449
|
-
var
|
|
450
|
-
module.exports =
|
|
449
|
+
var dot2 = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
450
|
+
module.exports = dot2;
|
|
451
451
|
}
|
|
452
452
|
});
|
|
453
453
|
|
|
@@ -455,7 +455,7 @@ var require_dot = __commonJS({
|
|
|
455
455
|
var require_angle = __commonJS({
|
|
456
456
|
"node_modules/@jscad/modeling/src/maths/vec3/angle.js"(exports, module) {
|
|
457
457
|
"use strict";
|
|
458
|
-
var
|
|
458
|
+
var dot2 = require_dot();
|
|
459
459
|
var angle = (a, b) => {
|
|
460
460
|
const ax = a[0];
|
|
461
461
|
const ay = a[1];
|
|
@@ -466,7 +466,7 @@ var require_angle = __commonJS({
|
|
|
466
466
|
const mag1 = Math.sqrt(ax * ax + ay * ay + az * az);
|
|
467
467
|
const mag2 = Math.sqrt(bx * bx + by * by + bz * bz);
|
|
468
468
|
const mag = mag1 * mag2;
|
|
469
|
-
const cosine = mag &&
|
|
469
|
+
const cosine = mag && dot2(a, b) / mag;
|
|
470
470
|
return Math.acos(Math.min(Math.max(cosine, -1), 1));
|
|
471
471
|
};
|
|
472
472
|
module.exports = angle;
|
|
@@ -516,7 +516,7 @@ var require_copy2 = __commonJS({
|
|
|
516
516
|
var require_cross = __commonJS({
|
|
517
517
|
"node_modules/@jscad/modeling/src/maths/vec3/cross.js"(exports, module) {
|
|
518
518
|
"use strict";
|
|
519
|
-
var
|
|
519
|
+
var cross2 = (out, a, b) => {
|
|
520
520
|
const ax = a[0];
|
|
521
521
|
const ay = a[1];
|
|
522
522
|
const az = a[2];
|
|
@@ -528,7 +528,7 @@ var require_cross = __commonJS({
|
|
|
528
528
|
out[2] = ax * by - ay * bx;
|
|
529
529
|
return out;
|
|
530
530
|
};
|
|
531
|
-
module.exports =
|
|
531
|
+
module.exports = cross2;
|
|
532
532
|
}
|
|
533
533
|
});
|
|
534
534
|
|
|
@@ -724,13 +724,13 @@ var require_orthogonal = __commonJS({
|
|
|
724
724
|
"use strict";
|
|
725
725
|
var abs = require_abs();
|
|
726
726
|
var create = require_create2();
|
|
727
|
-
var
|
|
727
|
+
var cross2 = require_cross();
|
|
728
728
|
var orthogonal = (out, vector) => {
|
|
729
729
|
const bV = abs(create(), vector);
|
|
730
730
|
const b0 = 0 + (bV[0] < bV[1] && bV[0] < bV[2]);
|
|
731
731
|
const b1 = 0 + (bV[1] <= bV[0] && bV[1] < bV[2]);
|
|
732
732
|
const b2 = 0 + (bV[2] <= bV[0] && bV[2] <= bV[1]);
|
|
733
|
-
return
|
|
733
|
+
return cross2(out, vector, [b0, b1, b2]);
|
|
734
734
|
};
|
|
735
735
|
module.exports = orthogonal;
|
|
736
736
|
}
|
|
@@ -1650,13 +1650,13 @@ var require_copy3 = __commonJS({
|
|
|
1650
1650
|
var require_cross2 = __commonJS({
|
|
1651
1651
|
"node_modules/@jscad/modeling/src/maths/vec2/cross.js"(exports, module) {
|
|
1652
1652
|
"use strict";
|
|
1653
|
-
var
|
|
1653
|
+
var cross2 = (out, a, b) => {
|
|
1654
1654
|
out[0] = 0;
|
|
1655
1655
|
out[1] = 0;
|
|
1656
1656
|
out[2] = a[0] * b[1] - a[1] * b[0];
|
|
1657
1657
|
return out;
|
|
1658
1658
|
};
|
|
1659
|
-
module.exports =
|
|
1659
|
+
module.exports = cross2;
|
|
1660
1660
|
}
|
|
1661
1661
|
});
|
|
1662
1662
|
|
|
@@ -1690,8 +1690,8 @@ var require_divide2 = __commonJS({
|
|
|
1690
1690
|
var require_dot2 = __commonJS({
|
|
1691
1691
|
"node_modules/@jscad/modeling/src/maths/vec2/dot.js"(exports, module) {
|
|
1692
1692
|
"use strict";
|
|
1693
|
-
var
|
|
1694
|
-
module.exports =
|
|
1693
|
+
var dot2 = (a, b) => a[0] * b[0] + a[1] * b[1];
|
|
1694
|
+
module.exports = dot2;
|
|
1695
1695
|
}
|
|
1696
1696
|
});
|
|
1697
1697
|
|
|
@@ -2401,7 +2401,7 @@ var require_create5 = __commonJS({
|
|
|
2401
2401
|
var require_point_line_distance = __commonJS({
|
|
2402
2402
|
"node_modules/@jscad/modeling/src/operations/hulls/quickhull/point-line-distance.js"(exports, module) {
|
|
2403
2403
|
"use strict";
|
|
2404
|
-
var
|
|
2404
|
+
var cross2 = require_cross();
|
|
2405
2405
|
var subtract3 = require_subtract();
|
|
2406
2406
|
var squaredLength = require_squaredLength();
|
|
2407
2407
|
var distanceSquared = (p, a, b) => {
|
|
@@ -2410,7 +2410,7 @@ var require_point_line_distance = __commonJS({
|
|
|
2410
2410
|
const cr = [];
|
|
2411
2411
|
subtract3(ab, b, a);
|
|
2412
2412
|
subtract3(ap, p, a);
|
|
2413
|
-
const area = squaredLength(
|
|
2413
|
+
const area = squaredLength(cross2(cr, ap, ab));
|
|
2414
2414
|
const s = squaredLength(ab);
|
|
2415
2415
|
if (s === 0) {
|
|
2416
2416
|
throw Error("a and b are the same point");
|
|
@@ -2426,14 +2426,14 @@ var require_point_line_distance = __commonJS({
|
|
|
2426
2426
|
var require_get_plane_normal = __commonJS({
|
|
2427
2427
|
"node_modules/@jscad/modeling/src/operations/hulls/quickhull/get-plane-normal.js"(exports, module) {
|
|
2428
2428
|
"use strict";
|
|
2429
|
-
var
|
|
2429
|
+
var cross2 = require_cross();
|
|
2430
2430
|
var normalize = require_normalize();
|
|
2431
2431
|
var subtract3 = require_subtract();
|
|
2432
2432
|
var planeNormal = (out, point1, point2, point3) => {
|
|
2433
2433
|
const tmp = [0, 0, 0];
|
|
2434
2434
|
subtract3(out, point1, point2);
|
|
2435
2435
|
subtract3(tmp, point2, point3);
|
|
2436
|
-
|
|
2436
|
+
cross2(out, out, tmp);
|
|
2437
2437
|
return normalize(out, out);
|
|
2438
2438
|
};
|
|
2439
2439
|
module.exports = planeNormal;
|
|
@@ -2641,8 +2641,8 @@ var require_Face = __commonJS({
|
|
|
2641
2641
|
"use strict";
|
|
2642
2642
|
var add = require_add2();
|
|
2643
2643
|
var copy = require_copy2();
|
|
2644
|
-
var
|
|
2645
|
-
var
|
|
2644
|
+
var cross2 = require_cross();
|
|
2645
|
+
var dot2 = require_dot();
|
|
2646
2646
|
var length = require_length();
|
|
2647
2647
|
var normalize = require_normalize();
|
|
2648
2648
|
var scale = require_scale();
|
|
@@ -2688,7 +2688,7 @@ var require_Face = __commonJS({
|
|
|
2688
2688
|
while (e2 !== e0) {
|
|
2689
2689
|
copy(v1, v2);
|
|
2690
2690
|
subtract3(v2, e2.head().point, e0.head().point);
|
|
2691
|
-
add(this.normal, this.normal,
|
|
2691
|
+
add(this.normal, this.normal, cross2(t, v1, v2));
|
|
2692
2692
|
e2 = e2.next;
|
|
2693
2693
|
this.nVertices += 1;
|
|
2694
2694
|
}
|
|
@@ -2714,7 +2714,7 @@ var require_Face = __commonJS({
|
|
|
2714
2714
|
const maxVector = subtract3([], p2, p1);
|
|
2715
2715
|
const maxLength = Math.sqrt(maxSquaredLength);
|
|
2716
2716
|
scale(maxVector, maxVector, 1 / maxLength);
|
|
2717
|
-
const maxProjection =
|
|
2717
|
+
const maxProjection = dot2(this.normal, maxVector);
|
|
2718
2718
|
scale(maxVector, maxVector, -maxProjection);
|
|
2719
2719
|
add(this.normal, this.normal, maxVector);
|
|
2720
2720
|
normalize(this.normal, this.normal);
|
|
@@ -2736,10 +2736,10 @@ var require_Face = __commonJS({
|
|
|
2736
2736
|
this.computeNormal();
|
|
2737
2737
|
}
|
|
2738
2738
|
this.computeCentroid();
|
|
2739
|
-
this.offset =
|
|
2739
|
+
this.offset = dot2(this.normal, this.centroid);
|
|
2740
2740
|
}
|
|
2741
2741
|
distanceToPlane(point) {
|
|
2742
|
-
return
|
|
2742
|
+
return dot2(this.normal, point) - this.offset;
|
|
2743
2743
|
}
|
|
2744
2744
|
/**
|
|
2745
2745
|
* @private
|
|
@@ -2848,7 +2848,7 @@ var require_Face = __commonJS({
|
|
|
2848
2848
|
var require_QuickHull = __commonJS({
|
|
2849
2849
|
"node_modules/@jscad/modeling/src/operations/hulls/quickhull/QuickHull.js"(exports, module) {
|
|
2850
2850
|
"use strict";
|
|
2851
|
-
var
|
|
2851
|
+
var dot2 = require_dot();
|
|
2852
2852
|
var pointLineDistance = require_point_line_distance();
|
|
2853
2853
|
var getPlaneNormal = require_get_plane_normal();
|
|
2854
2854
|
var VertexList = require_VertexList();
|
|
@@ -3059,12 +3059,12 @@ var require_QuickHull = __commonJS({
|
|
|
3059
3059
|
}
|
|
3060
3060
|
}
|
|
3061
3061
|
const normal = getPlaneNormal([], v0.point, v1.point, v2.point);
|
|
3062
|
-
const distPO =
|
|
3062
|
+
const distPO = dot2(v0.point, normal);
|
|
3063
3063
|
maxDistance = -1;
|
|
3064
3064
|
for (i = 0; i < this.vertices.length; i += 1) {
|
|
3065
3065
|
const vertex = this.vertices[i];
|
|
3066
3066
|
if (vertex !== v0 && vertex !== v1 && vertex !== v2) {
|
|
3067
|
-
const distance = Math.abs(
|
|
3067
|
+
const distance = Math.abs(dot2(normal, vertex.point) - distPO);
|
|
3068
3068
|
if (distance > maxDistance) {
|
|
3069
3069
|
maxDistance = distance;
|
|
3070
3070
|
v3 = vertex;
|
|
@@ -3072,7 +3072,7 @@ var require_QuickHull = __commonJS({
|
|
|
3072
3072
|
}
|
|
3073
3073
|
}
|
|
3074
3074
|
const faces = [];
|
|
3075
|
-
if (
|
|
3075
|
+
if (dot2(v3.point, normal) - distPO < 0) {
|
|
3076
3076
|
faces.push(
|
|
3077
3077
|
Face.createTriangle(v0, v1, v2),
|
|
3078
3078
|
Face.createTriangle(v3, v1, v0),
|
|
@@ -4004,8 +4004,8 @@ var require_measureBoundingBox = __commonJS({
|
|
|
4004
4004
|
var require_dot3 = __commonJS({
|
|
4005
4005
|
"node_modules/@jscad/modeling/src/maths/vec4/dot.js"(exports, module) {
|
|
4006
4006
|
"use strict";
|
|
4007
|
-
var
|
|
4008
|
-
module.exports =
|
|
4007
|
+
var dot2 = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
|
|
4008
|
+
module.exports = dot2;
|
|
4009
4009
|
}
|
|
4010
4010
|
});
|
|
4011
4011
|
|
|
@@ -4112,10 +4112,10 @@ var require_measureSignedVolume = __commonJS({
|
|
|
4112
4112
|
var measureSignedVolume = (polygon3) => {
|
|
4113
4113
|
let signedVolume = 0;
|
|
4114
4114
|
const vertices = polygon3.vertices;
|
|
4115
|
-
const
|
|
4115
|
+
const cross2 = vec3.create();
|
|
4116
4116
|
for (let i = 0; i < vertices.length - 2; i++) {
|
|
4117
|
-
vec3.cross(
|
|
4118
|
-
signedVolume += vec3.dot(vertices[0],
|
|
4117
|
+
vec3.cross(cross2, vertices[i + 1], vertices[i + 2]);
|
|
4118
|
+
signedVolume += vec3.dot(vertices[0], cross2);
|
|
4119
4119
|
}
|
|
4120
4120
|
signedVolume /= 6;
|
|
4121
4121
|
return signedVolume;
|
|
@@ -11459,7 +11459,7 @@ var require_unionGeom3 = __commonJS({
|
|
|
11459
11459
|
var flatten = require_flatten();
|
|
11460
11460
|
var retessellate = require_retessellate();
|
|
11461
11461
|
var unionSub = require_unionGeom3Sub();
|
|
11462
|
-
var
|
|
11462
|
+
var union3 = (...geometries) => {
|
|
11463
11463
|
geometries = flatten(geometries);
|
|
11464
11464
|
let i;
|
|
11465
11465
|
for (i = 1; i < geometries.length; i += 2) {
|
|
@@ -11469,7 +11469,7 @@ var require_unionGeom3 = __commonJS({
|
|
|
11469
11469
|
newgeometry = retessellate(newgeometry);
|
|
11470
11470
|
return newgeometry;
|
|
11471
11471
|
};
|
|
11472
|
-
module.exports =
|
|
11472
|
+
module.exports = union3;
|
|
11473
11473
|
}
|
|
11474
11474
|
});
|
|
11475
11475
|
|
|
@@ -11483,14 +11483,14 @@ var require_unionGeom2 = __commonJS({
|
|
|
11483
11483
|
var fromFakePolygons = require_fromFakePolygons();
|
|
11484
11484
|
var to3DWalls = require_to3DWalls();
|
|
11485
11485
|
var unionGeom3 = require_unionGeom3();
|
|
11486
|
-
var
|
|
11486
|
+
var union3 = (...geometries) => {
|
|
11487
11487
|
geometries = flatten(geometries);
|
|
11488
11488
|
const newgeometries = geometries.map((geometry) => to3DWalls({ z0: -1, z1: 1 }, geometry));
|
|
11489
11489
|
const newgeom3 = unionGeom3(newgeometries);
|
|
11490
11490
|
const epsilon = measureEpsilon(newgeom3);
|
|
11491
11491
|
return fromFakePolygons(epsilon, geom33.toPolygons(newgeom3));
|
|
11492
11492
|
};
|
|
11493
|
-
module.exports =
|
|
11493
|
+
module.exports = union3;
|
|
11494
11494
|
}
|
|
11495
11495
|
});
|
|
11496
11496
|
|
|
@@ -11504,7 +11504,7 @@ var require_union = __commonJS({
|
|
|
11504
11504
|
var geom33 = require_geom3();
|
|
11505
11505
|
var unionGeom2 = require_unionGeom2();
|
|
11506
11506
|
var unionGeom3 = require_unionGeom3();
|
|
11507
|
-
var
|
|
11507
|
+
var union3 = (...geometries) => {
|
|
11508
11508
|
geometries = flatten(geometries);
|
|
11509
11509
|
if (geometries.length === 0) throw new Error("wrong number of arguments");
|
|
11510
11510
|
if (!areAllShapesTheSameType(geometries)) {
|
|
@@ -11515,7 +11515,7 @@ var require_union = __commonJS({
|
|
|
11515
11515
|
if (geom33.isA(geometry)) return unionGeom3(geometries);
|
|
11516
11516
|
return geometry;
|
|
11517
11517
|
};
|
|
11518
|
-
module.exports =
|
|
11518
|
+
module.exports = union3;
|
|
11519
11519
|
}
|
|
11520
11520
|
});
|
|
11521
11521
|
|
|
@@ -11871,8 +11871,8 @@ var require_expandShell = __commonJS({
|
|
|
11871
11871
|
let bestzaxisorthogonality = 0;
|
|
11872
11872
|
for (let i = 1; i < planes.length; i++) {
|
|
11873
11873
|
const normal = planes[i];
|
|
11874
|
-
const
|
|
11875
|
-
const crosslength = vec3.length(
|
|
11874
|
+
const cross2 = vec3.cross(v1, xaxis, normal);
|
|
11875
|
+
const crosslength = vec3.length(cross2);
|
|
11876
11876
|
if (crosslength > 0.05) {
|
|
11877
11877
|
if (crosslength > bestzaxisorthogonality) {
|
|
11878
11878
|
bestzaxisorthogonality = crosslength;
|
|
@@ -11905,7 +11905,7 @@ var require_expandGeom3 = __commonJS({
|
|
|
11905
11905
|
"node_modules/@jscad/modeling/src/operations/expansions/expandGeom3.js"(exports, module) {
|
|
11906
11906
|
"use strict";
|
|
11907
11907
|
var geom33 = require_geom3();
|
|
11908
|
-
var
|
|
11908
|
+
var union3 = require_union();
|
|
11909
11909
|
var expandShell = require_expandShell();
|
|
11910
11910
|
var expandGeom3 = (options, geometry) => {
|
|
11911
11911
|
const defaults = {
|
|
@@ -11921,7 +11921,7 @@ var require_expandGeom3 = __commonJS({
|
|
|
11921
11921
|
if (polygons.length === 0) throw new Error("the given geometry cannot be empty");
|
|
11922
11922
|
options = { delta, corners, segments };
|
|
11923
11923
|
const expanded = expandShell(options, geometry);
|
|
11924
|
-
return
|
|
11924
|
+
return union3(geometry, expanded);
|
|
11925
11925
|
};
|
|
11926
11926
|
module.exports = expandGeom3;
|
|
11927
11927
|
}
|
|
@@ -12633,7 +12633,7 @@ var require_hullChain = __commonJS({
|
|
|
12633
12633
|
"node_modules/@jscad/modeling/src/operations/hulls/hullChain.js"(exports, module) {
|
|
12634
12634
|
"use strict";
|
|
12635
12635
|
var flatten = require_flatten();
|
|
12636
|
-
var
|
|
12636
|
+
var union3 = require_union();
|
|
12637
12637
|
var hull = require_hull();
|
|
12638
12638
|
var hullChain = (...geometries) => {
|
|
12639
12639
|
geometries = flatten(geometries);
|
|
@@ -12642,7 +12642,7 @@ var require_hullChain = __commonJS({
|
|
|
12642
12642
|
for (let i = 1; i < geometries.length; i++) {
|
|
12643
12643
|
hulls.push(hull(geometries[i - 1], geometries[i]));
|
|
12644
12644
|
}
|
|
12645
|
-
return
|
|
12645
|
+
return union3(hulls);
|
|
12646
12646
|
};
|
|
12647
12647
|
module.exports = hullChain;
|
|
12648
12648
|
}
|
|
@@ -15001,6 +15001,8 @@ var import_extrusions = __toESM(require_extrusions(), 1);
|
|
|
15001
15001
|
var import_primitives = __toESM(require_primitives(), 1);
|
|
15002
15002
|
var import_transforms = __toESM(require_transforms(), 1);
|
|
15003
15003
|
var DEFAULT_SEGMENTS = 64;
|
|
15004
|
+
var REDUCED_SEGMENTS = 16;
|
|
15005
|
+
var HOLE_COUNT_THRESHOLD = 50;
|
|
15004
15006
|
var toBoardSpaceVec2 = (point, center) => [point.x - center.x, -(point.y - center.y)];
|
|
15005
15007
|
var isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
15006
15008
|
var arePointsClockwise = (points) => {
|
|
@@ -15013,11 +15015,11 @@ var arePointsClockwise = (points) => {
|
|
|
15013
15015
|
const signedArea = area / 2;
|
|
15014
15016
|
return signedArea <= 0;
|
|
15015
15017
|
};
|
|
15016
|
-
var createCircularHole = (x, y, radius, thickness) => (0, import_primitives.cylinder)({
|
|
15018
|
+
var createCircularHole = (x, y, radius, thickness, segments = DEFAULT_SEGMENTS) => (0, import_primitives.cylinder)({
|
|
15017
15019
|
center: [x, y, 0],
|
|
15018
15020
|
height: thickness + 1,
|
|
15019
15021
|
radius,
|
|
15020
|
-
segments
|
|
15022
|
+
segments
|
|
15021
15023
|
});
|
|
15022
15024
|
var createCutoutGeoms = (boardCenter, thickness, cutouts = []) => {
|
|
15023
15025
|
const geoms = [];
|
|
@@ -15129,9 +15131,36 @@ var filterCutoutsForBoard = (cutouts, board) => {
|
|
|
15129
15131
|
var import_extrusions2 = __toESM(require_extrusions(), 1);
|
|
15130
15132
|
var import_primitives2 = __toESM(require_primitives(), 1);
|
|
15131
15133
|
var import_transforms2 = __toESM(require_transforms(), 1);
|
|
15132
|
-
var
|
|
15134
|
+
var import_booleans2 = __toESM(require_booleans(), 1);
|
|
15133
15135
|
var geom3 = __toESM(require_geom3(), 1);
|
|
15134
15136
|
var import_measureBoundingBox = __toESM(require_measureBoundingBox2(), 1);
|
|
15137
|
+
|
|
15138
|
+
// lib/utils/batched-union.ts
|
|
15139
|
+
var import_booleans = __toESM(require_booleans(), 1);
|
|
15140
|
+
var batchedUnion = (geoms, batchSize = 50) => {
|
|
15141
|
+
if (geoms.length === 0) {
|
|
15142
|
+
throw new Error("Cannot union empty array");
|
|
15143
|
+
}
|
|
15144
|
+
if (geoms.length === 1) {
|
|
15145
|
+
return geoms[0];
|
|
15146
|
+
}
|
|
15147
|
+
let results = [...geoms];
|
|
15148
|
+
while (results.length > 1) {
|
|
15149
|
+
const newResults = [];
|
|
15150
|
+
for (let i = 0; i < results.length; i += batchSize) {
|
|
15151
|
+
const batch = results.slice(i, i + batchSize);
|
|
15152
|
+
if (batch.length === 1) {
|
|
15153
|
+
newResults.push(batch[0]);
|
|
15154
|
+
} else {
|
|
15155
|
+
newResults.push((0, import_booleans.union)(...batch));
|
|
15156
|
+
}
|
|
15157
|
+
}
|
|
15158
|
+
results = newResults;
|
|
15159
|
+
}
|
|
15160
|
+
return results[0];
|
|
15161
|
+
};
|
|
15162
|
+
|
|
15163
|
+
// lib/utils/pcb-board-geometry.ts
|
|
15135
15164
|
var RADIUS_EPSILON = 1e-4;
|
|
15136
15165
|
var getNumberProperty = (obj, key) => {
|
|
15137
15166
|
const value = obj[key];
|
|
@@ -15157,14 +15186,14 @@ var createBoardOutlineGeom = (board, center, thickness) => {
|
|
|
15157
15186
|
geom = (0, import_transforms2.translate)([0, 0, -thickness / 2], geom);
|
|
15158
15187
|
return geom;
|
|
15159
15188
|
};
|
|
15160
|
-
var
|
|
15189
|
+
var createPillHoleWithSegments = (x, y, width, height, thickness, rotate, segments = DEFAULT_SEGMENTS) => {
|
|
15161
15190
|
const minDimension = Math.min(width, height);
|
|
15162
15191
|
const maxAllowedRadius = Math.max(0, minDimension / 2 - RADIUS_EPSILON);
|
|
15163
15192
|
const roundRadius = maxAllowedRadius <= 0 ? 0 : Math.min(height / 2, maxAllowedRadius);
|
|
15164
15193
|
const hole2d = (0, import_primitives2.roundedRectangle)({
|
|
15165
15194
|
size: [width, height],
|
|
15166
15195
|
roundRadius,
|
|
15167
|
-
segments
|
|
15196
|
+
segments
|
|
15168
15197
|
});
|
|
15169
15198
|
let hole3d = (0, import_extrusions2.extrudeLinear)({ height: thickness + 1 }, hole2d);
|
|
15170
15199
|
hole3d = (0, import_transforms2.translate)([0, 0, -(thickness + 1) / 2], hole3d);
|
|
@@ -15173,7 +15202,7 @@ var createPillHole = (x, y, width, height, thickness, rotate) => {
|
|
|
15173
15202
|
}
|
|
15174
15203
|
return (0, import_transforms2.translate)([x, y, 0], hole3d);
|
|
15175
15204
|
};
|
|
15176
|
-
var createHoleGeoms = (boardCenter, thickness, holes = [], platedHoles = []) => {
|
|
15205
|
+
var createHoleGeoms = (boardCenter, thickness, holes = [], platedHoles = [], segments = DEFAULT_SEGMENTS) => {
|
|
15177
15206
|
const holeGeoms = [];
|
|
15178
15207
|
for (const hole of holes) {
|
|
15179
15208
|
const holeRecord = hole;
|
|
@@ -15187,13 +15216,14 @@ var createHoleGeoms = (boardCenter, thickness, holes = [], platedHoles = []) =>
|
|
|
15187
15216
|
const rotate = holeHeight > holeWidth;
|
|
15188
15217
|
const width = rotate ? holeHeight : holeWidth;
|
|
15189
15218
|
const height = rotate ? holeWidth : holeHeight;
|
|
15190
|
-
const pillHole =
|
|
15219
|
+
const pillHole = createPillHoleWithSegments(
|
|
15191
15220
|
relX,
|
|
15192
15221
|
relY,
|
|
15193
15222
|
width,
|
|
15194
15223
|
height,
|
|
15195
15224
|
thickness,
|
|
15196
|
-
rotate
|
|
15225
|
+
rotate,
|
|
15226
|
+
segments
|
|
15197
15227
|
);
|
|
15198
15228
|
holeGeoms.push(pillHole);
|
|
15199
15229
|
continue;
|
|
@@ -15210,7 +15240,7 @@ var createHoleGeoms = (boardCenter, thickness, holes = [], platedHoles = []) =>
|
|
|
15210
15240
|
const hole2d = (0, import_primitives2.roundedRectangle)({
|
|
15211
15241
|
size: [holeWidth, holeHeight],
|
|
15212
15242
|
roundRadius,
|
|
15213
|
-
segments
|
|
15243
|
+
segments
|
|
15214
15244
|
});
|
|
15215
15245
|
let hole3d = (0, import_extrusions2.extrudeLinear)({ height: thickness + 1 }, hole2d);
|
|
15216
15246
|
hole3d = (0, import_transforms2.translate)([0, 0, -(thickness + 1) / 2], hole3d);
|
|
@@ -15224,7 +15254,7 @@ var createHoleGeoms = (boardCenter, thickness, holes = [], platedHoles = []) =>
|
|
|
15224
15254
|
const diameter = getNumberProperty(holeRecord, "hole_diameter") ?? getNumberProperty(holeRecord, "diameter");
|
|
15225
15255
|
if (!diameter) continue;
|
|
15226
15256
|
const radius = diameter / 2;
|
|
15227
|
-
holeGeoms.push(createCircularHole(relX, relY, radius, thickness));
|
|
15257
|
+
holeGeoms.push(createCircularHole(relX, relY, radius, thickness, segments));
|
|
15228
15258
|
}
|
|
15229
15259
|
for (const plated of platedHoles) {
|
|
15230
15260
|
const platedRecord = plated;
|
|
@@ -15240,13 +15270,23 @@ var createHoleGeoms = (boardCenter, thickness, holes = [], platedHoles = []) =>
|
|
|
15240
15270
|
const width = rotate ? holeHeight : holeWidth;
|
|
15241
15271
|
const height = rotate ? holeWidth : holeHeight;
|
|
15242
15272
|
holeGeoms.push(
|
|
15243
|
-
|
|
15273
|
+
createPillHoleWithSegments(
|
|
15274
|
+
relX,
|
|
15275
|
+
relY,
|
|
15276
|
+
width,
|
|
15277
|
+
height,
|
|
15278
|
+
thickness,
|
|
15279
|
+
rotate,
|
|
15280
|
+
segments
|
|
15281
|
+
)
|
|
15244
15282
|
);
|
|
15245
15283
|
continue;
|
|
15246
15284
|
}
|
|
15247
15285
|
const diameter = getNumberProperty(platedRecord, "hole_diameter") ?? getNumberProperty(platedRecord, "outer_diameter");
|
|
15248
15286
|
if (!diameter) continue;
|
|
15249
|
-
holeGeoms.push(
|
|
15287
|
+
holeGeoms.push(
|
|
15288
|
+
createCircularHole(relX, relY, diameter / 2, thickness, segments)
|
|
15289
|
+
);
|
|
15250
15290
|
}
|
|
15251
15291
|
return holeGeoms;
|
|
15252
15292
|
};
|
|
@@ -15264,16 +15304,16 @@ var geom3ToTriangles = (geometry, polygons) => {
|
|
|
15264
15304
|
next2[1] - base[1],
|
|
15265
15305
|
next2[2] - base[2]
|
|
15266
15306
|
];
|
|
15267
|
-
const
|
|
15307
|
+
const cross2 = [
|
|
15268
15308
|
ab[1] * ac[2] - ab[2] * ac[1],
|
|
15269
15309
|
ab[2] * ac[0] - ab[0] * ac[2],
|
|
15270
15310
|
ab[0] * ac[1] - ab[1] * ac[0]
|
|
15271
15311
|
];
|
|
15272
|
-
const length = Math.sqrt(
|
|
15312
|
+
const length = Math.sqrt(cross2[0] ** 2 + cross2[1] ** 2 + cross2[2] ** 2) || 1;
|
|
15273
15313
|
const normal = {
|
|
15274
|
-
x:
|
|
15275
|
-
y:
|
|
15276
|
-
z:
|
|
15314
|
+
x: cross2[0] / length,
|
|
15315
|
+
y: cross2[1] / length,
|
|
15316
|
+
z: cross2[2] / length
|
|
15277
15317
|
};
|
|
15278
15318
|
for (let i = 1; i < poly.vertices.length - 1; i++) {
|
|
15279
15319
|
const v1 = poly.vertices[i];
|
|
@@ -15302,11 +15342,21 @@ var createBoardMesh = (board, options) => {
|
|
|
15302
15342
|
const { thickness, holes = [], platedHoles = [], cutouts = [] } = options;
|
|
15303
15343
|
const center = board.center ?? { x: 0, y: 0 };
|
|
15304
15344
|
let boardGeom = createBoardOutlineGeom(board, center, thickness);
|
|
15305
|
-
const
|
|
15345
|
+
const totalHoleCount = holes.length + platedHoles.length;
|
|
15346
|
+
const useReducedSegments = totalHoleCount > HOLE_COUNT_THRESHOLD;
|
|
15347
|
+
const segments = useReducedSegments ? REDUCED_SEGMENTS : DEFAULT_SEGMENTS;
|
|
15348
|
+
const holeGeoms = createHoleGeoms(
|
|
15349
|
+
center,
|
|
15350
|
+
thickness,
|
|
15351
|
+
holes,
|
|
15352
|
+
platedHoles,
|
|
15353
|
+
segments
|
|
15354
|
+
);
|
|
15306
15355
|
const cutoutGeoms = createCutoutGeoms(center, thickness, cutouts);
|
|
15307
15356
|
const subtractGeoms = [...holeGeoms, ...cutoutGeoms];
|
|
15308
15357
|
if (subtractGeoms.length > 0) {
|
|
15309
|
-
|
|
15358
|
+
const unifiedHoles = batchedUnion(subtractGeoms);
|
|
15359
|
+
boardGeom = (0, import_booleans2.subtract)(boardGeom, unifiedHoles);
|
|
15310
15360
|
}
|
|
15311
15361
|
boardGeom = (0, import_transforms2.rotateX)(-Math.PI / 2, boardGeom);
|
|
15312
15362
|
const polygons = geom3.toPolygons(boardGeom);
|
|
@@ -15321,7 +15371,7 @@ var createBoardMesh = (board, options) => {
|
|
|
15321
15371
|
|
|
15322
15372
|
// lib/utils/pcb-panel-geometry.ts
|
|
15323
15373
|
var import_transforms3 = __toESM(require_transforms(), 1);
|
|
15324
|
-
var
|
|
15374
|
+
var import_booleans3 = __toESM(require_booleans(), 1);
|
|
15325
15375
|
var geom32 = __toESM(require_geom3(), 1);
|
|
15326
15376
|
var import_measureBoundingBox2 = __toESM(require_measureBoundingBox2(), 1);
|
|
15327
15377
|
var createPanelMesh = (panel, options) => {
|
|
@@ -15332,7 +15382,7 @@ var createPanelMesh = (panel, options) => {
|
|
|
15332
15382
|
const cutoutGeoms = createCutoutGeoms(center, thickness, cutouts);
|
|
15333
15383
|
const subtractGeoms = [...holeGeoms, ...cutoutGeoms];
|
|
15334
15384
|
if (subtractGeoms.length > 0) {
|
|
15335
|
-
panelGeom = (0,
|
|
15385
|
+
panelGeom = (0, import_booleans3.subtract)(panelGeom, ...subtractGeoms);
|
|
15336
15386
|
}
|
|
15337
15387
|
panelGeom = (0, import_transforms3.rotateX)(-Math.PI / 2, panelGeom);
|
|
15338
15388
|
const polygons = geom32.toPolygons(panelGeom);
|
|
@@ -17190,6 +17240,130 @@ async function convertSceneToGLTF(scene, options = {}) {
|
|
|
17190
17240
|
return result;
|
|
17191
17241
|
}
|
|
17192
17242
|
|
|
17243
|
+
// lib/utils/camera-position.ts
|
|
17244
|
+
var DEFAULT_CAMERA_DIRECTION = [-0.7, 1.2, -0.8];
|
|
17245
|
+
function normalizeVector([x, y, z]) {
|
|
17246
|
+
const length = Math.hypot(x, y, z);
|
|
17247
|
+
if (length === 0) {
|
|
17248
|
+
return [0, 1, 0];
|
|
17249
|
+
}
|
|
17250
|
+
return [x / length, y / length, z / length];
|
|
17251
|
+
}
|
|
17252
|
+
function dot([ax, ay, az], [bx, by, bz]) {
|
|
17253
|
+
return ax * bx + ay * by + az * bz;
|
|
17254
|
+
}
|
|
17255
|
+
function cross([ax, ay, az], [bx, by, bz]) {
|
|
17256
|
+
return [ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx];
|
|
17257
|
+
}
|
|
17258
|
+
function getVerticalFovRadians(opts) {
|
|
17259
|
+
if (opts?.focalLength !== void 0 && opts.sensorHeight !== void 0 && opts.focalLength > 0 && opts.sensorHeight > 0) {
|
|
17260
|
+
return 2 * Math.atan(opts.sensorHeight / (2 * opts.focalLength));
|
|
17261
|
+
}
|
|
17262
|
+
const fovDegrees = opts?.fov ?? 50;
|
|
17263
|
+
const fovRadians = fovDegrees * Math.PI / 180;
|
|
17264
|
+
if (!Number.isFinite(fovRadians) || fovRadians <= 0) {
|
|
17265
|
+
return 50 * Math.PI / 180;
|
|
17266
|
+
}
|
|
17267
|
+
return Math.min(Math.max(fovRadians, 0.01), Math.PI - 0.01);
|
|
17268
|
+
}
|
|
17269
|
+
function getVerticalFovDegrees(opts) {
|
|
17270
|
+
return getVerticalFovRadians(opts) * 180 / Math.PI;
|
|
17271
|
+
}
|
|
17272
|
+
function getRequiredDistanceForFrustum(corners, cameraDirection, right, up, tanHalfHorizontal, tanHalfVertical) {
|
|
17273
|
+
let requiredDistance = 0;
|
|
17274
|
+
for (const corner of corners) {
|
|
17275
|
+
const u = [corner[0], corner[1], corner[2]];
|
|
17276
|
+
const un = dot(u, cameraDirection);
|
|
17277
|
+
const ur = Math.abs(dot(u, right));
|
|
17278
|
+
const uu = Math.abs(dot(u, up));
|
|
17279
|
+
const distanceForHorizontal = un + ur / tanHalfHorizontal;
|
|
17280
|
+
const distanceForVertical = un + uu / tanHalfVertical;
|
|
17281
|
+
requiredDistance = Math.max(
|
|
17282
|
+
requiredDistance,
|
|
17283
|
+
distanceForHorizontal,
|
|
17284
|
+
distanceForVertical
|
|
17285
|
+
);
|
|
17286
|
+
}
|
|
17287
|
+
return requiredDistance;
|
|
17288
|
+
}
|
|
17289
|
+
function getBestCameraPosition(circuitJson, opts) {
|
|
17290
|
+
const verticalFovDegrees = getVerticalFovDegrees(opts);
|
|
17291
|
+
const panel = circuitJson.find((item) => item.type === "pcb_panel");
|
|
17292
|
+
const board = circuitJson.find((item) => item.type === "pcb_board");
|
|
17293
|
+
const surface = panel || board;
|
|
17294
|
+
if (!surface) {
|
|
17295
|
+
return {
|
|
17296
|
+
camPos: [30, 30, 25],
|
|
17297
|
+
lookAt: [0, 0, 0],
|
|
17298
|
+
fov: verticalFovDegrees
|
|
17299
|
+
};
|
|
17300
|
+
}
|
|
17301
|
+
const { width, height, center } = surface;
|
|
17302
|
+
if (!width || !height || !center) {
|
|
17303
|
+
return {
|
|
17304
|
+
camPos: [30, 30, 25],
|
|
17305
|
+
lookAt: [0, 0, 0],
|
|
17306
|
+
fov: verticalFovDegrees
|
|
17307
|
+
};
|
|
17308
|
+
}
|
|
17309
|
+
const lookAtX = center.x;
|
|
17310
|
+
const lookAtZ = center.y;
|
|
17311
|
+
const cameraDirection = normalizeVector(
|
|
17312
|
+
opts?.direction ?? DEFAULT_CAMERA_DIRECTION
|
|
17313
|
+
);
|
|
17314
|
+
const forward = [
|
|
17315
|
+
-cameraDirection[0],
|
|
17316
|
+
-cameraDirection[1],
|
|
17317
|
+
-cameraDirection[2]
|
|
17318
|
+
];
|
|
17319
|
+
const worldUp = [0, 1, 0];
|
|
17320
|
+
const right = normalizeVector(cross(forward, worldUp));
|
|
17321
|
+
const up = normalizeVector(cross(right, forward));
|
|
17322
|
+
const verticalFov = verticalFovDegrees * Math.PI / 180;
|
|
17323
|
+
const aspectRatio = opts?.aspectRatio !== void 0 && Number.isFinite(opts.aspectRatio) && opts.aspectRatio > 0 ? opts.aspectRatio : 4 / 3;
|
|
17324
|
+
const tanHalfVertical = Math.tan(verticalFov / 2);
|
|
17325
|
+
const tanHalfHorizontal = tanHalfVertical * aspectRatio;
|
|
17326
|
+
const halfWidth = width / 2;
|
|
17327
|
+
const halfHeight = height / 2;
|
|
17328
|
+
const boardCorners = [
|
|
17329
|
+
[halfWidth, 0, halfHeight],
|
|
17330
|
+
[halfWidth, 0, -halfHeight],
|
|
17331
|
+
[-halfWidth, 0, halfHeight],
|
|
17332
|
+
[-halfWidth, 0, -halfHeight]
|
|
17333
|
+
];
|
|
17334
|
+
const requiredDistanceAssumingVerticalFov = getRequiredDistanceForFrustum(
|
|
17335
|
+
boardCorners,
|
|
17336
|
+
cameraDirection,
|
|
17337
|
+
right,
|
|
17338
|
+
up,
|
|
17339
|
+
tanHalfHorizontal,
|
|
17340
|
+
tanHalfVertical
|
|
17341
|
+
);
|
|
17342
|
+
const tanHalfHorizontalIfFovIsHorizontal = tanHalfVertical;
|
|
17343
|
+
const tanHalfVerticalIfFovIsHorizontal = tanHalfHorizontalIfFovIsHorizontal / aspectRatio;
|
|
17344
|
+
const requiredDistanceAssumingHorizontalFov = getRequiredDistanceForFrustum(
|
|
17345
|
+
boardCorners,
|
|
17346
|
+
cameraDirection,
|
|
17347
|
+
right,
|
|
17348
|
+
up,
|
|
17349
|
+
tanHalfHorizontalIfFovIsHorizontal,
|
|
17350
|
+
tanHalfVerticalIfFovIsHorizontal
|
|
17351
|
+
);
|
|
17352
|
+
const requiredDistance = Math.max(
|
|
17353
|
+
requiredDistanceAssumingVerticalFov,
|
|
17354
|
+
requiredDistanceAssumingHorizontalFov
|
|
17355
|
+
);
|
|
17356
|
+
const distance = Math.max(requiredDistance, 1);
|
|
17357
|
+
const camX = lookAtX + cameraDirection[0] * distance;
|
|
17358
|
+
const camY = cameraDirection[1] * distance;
|
|
17359
|
+
const camZ = lookAtZ + cameraDirection[2] * distance;
|
|
17360
|
+
return {
|
|
17361
|
+
camPos: [-camX, camY, camZ],
|
|
17362
|
+
lookAt: [-lookAtX, 0, lookAtZ],
|
|
17363
|
+
fov: verticalFovDegrees
|
|
17364
|
+
};
|
|
17365
|
+
}
|
|
17366
|
+
|
|
17193
17367
|
// lib/index.ts
|
|
17194
17368
|
async function convertCircuitJsonToGltf(circuitJson, options = {}) {
|
|
17195
17369
|
const {
|
|
@@ -17227,6 +17401,7 @@ export {
|
|
|
17227
17401
|
convertCircuitJsonTo3D,
|
|
17228
17402
|
convertCircuitJsonToGltf,
|
|
17229
17403
|
convertSceneToGLTF,
|
|
17404
|
+
getBestCameraPosition,
|
|
17230
17405
|
loadGLB,
|
|
17231
17406
|
loadOBJ,
|
|
17232
17407
|
loadSTL,
|