circuit-json-to-step 0.0.21 → 0.0.23
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 +302 -293
- package/lib/index.ts +58 -28
- package/lib/mesh-generation.ts +30 -293
- package/lib/pill-geometry.ts +46 -41
- package/lib/scene-box-to-step.ts +91 -0
- package/lib/scene-geometry.ts +58 -0
- package/lib/step-brep-utils.ts +118 -0
- package/lib/step-model-merger.ts +4 -4
- package/package.json +3 -3
- package/test/basics/basics01/__snapshots__/basics01.snap.png +0 -0
- package/test/basics/basics04/__snapshots__/basics04.snap.png +0 -0
- package/test/basics/basics05/__snapshots__/basics05.snap.png +0 -0
- package/test/basics/basics06/__snapshots__/basics06.snap.png +0 -0
- package/test/basics/basics06/basics06.json +32 -7
- package/test/repros/kicad-step/__snapshots__/kicad-step-board.snap.png +0 -0
- package/test/repros/kicad-step/kicad-step.json +102 -22
- package/test/repros/repro01/__snapshots__/repro01.snap.png +0 -0
- package/test/repros/repro02/__snapshots__/repro02.snap.png +0 -0
package/lib/pill-geometry.ts
CHANGED
|
@@ -396,7 +396,8 @@ export function createPillHoleLoop(
|
|
|
396
396
|
export function createPillCylindricalFaces(
|
|
397
397
|
repo: Repository,
|
|
398
398
|
hole: any,
|
|
399
|
-
|
|
399
|
+
zMin: number,
|
|
400
|
+
zMax: number,
|
|
400
401
|
xDir: Ref<Direction>,
|
|
401
402
|
zDir: Ref<Direction>,
|
|
402
403
|
): Ref<AdvancedFace>[] {
|
|
@@ -428,7 +429,8 @@ export function createPillCylindricalFaces(
|
|
|
428
429
|
rotation,
|
|
429
430
|
centerX,
|
|
430
431
|
centerY,
|
|
431
|
-
|
|
432
|
+
zMin,
|
|
433
|
+
zMax,
|
|
432
434
|
zDir,
|
|
433
435
|
xDir,
|
|
434
436
|
),
|
|
@@ -445,7 +447,8 @@ export function createPillCylindricalFaces(
|
|
|
445
447
|
rotation,
|
|
446
448
|
centerX,
|
|
447
449
|
centerY,
|
|
448
|
-
|
|
450
|
+
zMin,
|
|
451
|
+
zMax,
|
|
449
452
|
zDir,
|
|
450
453
|
),
|
|
451
454
|
)
|
|
@@ -462,7 +465,8 @@ export function createPillCylindricalFaces(
|
|
|
462
465
|
rotation,
|
|
463
466
|
centerX,
|
|
464
467
|
centerY,
|
|
465
|
-
|
|
468
|
+
zMin,
|
|
469
|
+
zMax,
|
|
466
470
|
zDir,
|
|
467
471
|
xDir,
|
|
468
472
|
),
|
|
@@ -479,7 +483,8 @@ export function createPillCylindricalFaces(
|
|
|
479
483
|
rotation,
|
|
480
484
|
centerX,
|
|
481
485
|
centerY,
|
|
482
|
-
|
|
486
|
+
zMin,
|
|
487
|
+
zMax,
|
|
483
488
|
zDir,
|
|
484
489
|
),
|
|
485
490
|
)
|
|
@@ -499,7 +504,8 @@ export function createPillCylindricalFaces(
|
|
|
499
504
|
rotation,
|
|
500
505
|
centerX,
|
|
501
506
|
centerY,
|
|
502
|
-
|
|
507
|
+
zMin,
|
|
508
|
+
zMax,
|
|
503
509
|
zDir,
|
|
504
510
|
xDir,
|
|
505
511
|
),
|
|
@@ -516,7 +522,8 @@ export function createPillCylindricalFaces(
|
|
|
516
522
|
rotation,
|
|
517
523
|
centerX,
|
|
518
524
|
centerY,
|
|
519
|
-
|
|
525
|
+
zMin,
|
|
526
|
+
zMax,
|
|
520
527
|
zDir,
|
|
521
528
|
),
|
|
522
529
|
)
|
|
@@ -533,7 +540,8 @@ export function createPillCylindricalFaces(
|
|
|
533
540
|
rotation,
|
|
534
541
|
centerX,
|
|
535
542
|
centerY,
|
|
536
|
-
|
|
543
|
+
zMin,
|
|
544
|
+
zMax,
|
|
537
545
|
zDir,
|
|
538
546
|
xDir,
|
|
539
547
|
),
|
|
@@ -550,7 +558,8 @@ export function createPillCylindricalFaces(
|
|
|
550
558
|
rotation,
|
|
551
559
|
centerX,
|
|
552
560
|
centerY,
|
|
553
|
-
|
|
561
|
+
zMin,
|
|
562
|
+
zMax,
|
|
554
563
|
zDir,
|
|
555
564
|
),
|
|
556
565
|
)
|
|
@@ -572,7 +581,8 @@ function createCylindricalWall(
|
|
|
572
581
|
rotation: number,
|
|
573
582
|
centerX0: number,
|
|
574
583
|
centerY0: number,
|
|
575
|
-
|
|
584
|
+
zMin: number,
|
|
585
|
+
zMax: number,
|
|
576
586
|
zDir: Ref<Direction>,
|
|
577
587
|
xDir: Ref<Direction>,
|
|
578
588
|
): Ref<AdvancedFace> {
|
|
@@ -602,13 +612,13 @@ function createCylindricalWall(
|
|
|
602
612
|
const bottomStartVertex = repo.add(
|
|
603
613
|
new VertexPoint(
|
|
604
614
|
"",
|
|
605
|
-
repo.add(new CartesianPoint("", bottomStart.x, bottomStart.y,
|
|
615
|
+
repo.add(new CartesianPoint("", bottomStart.x, bottomStart.y, zMin)),
|
|
606
616
|
),
|
|
607
617
|
)
|
|
608
618
|
const bottomEndVertex = repo.add(
|
|
609
619
|
new VertexPoint(
|
|
610
620
|
"",
|
|
611
|
-
repo.add(new CartesianPoint("", bottomEnd.x, bottomEnd.y,
|
|
621
|
+
repo.add(new CartesianPoint("", bottomEnd.x, bottomEnd.y, zMin)),
|
|
612
622
|
),
|
|
613
623
|
)
|
|
614
624
|
|
|
@@ -616,17 +626,13 @@ function createCylindricalWall(
|
|
|
616
626
|
const topStart = repo.add(
|
|
617
627
|
new VertexPoint(
|
|
618
628
|
"",
|
|
619
|
-
repo.add(
|
|
620
|
-
new CartesianPoint("", bottomStart.x, bottomStart.y, boardThickness),
|
|
621
|
-
),
|
|
629
|
+
repo.add(new CartesianPoint("", bottomStart.x, bottomStart.y, zMax)),
|
|
622
630
|
),
|
|
623
631
|
)
|
|
624
632
|
const topEnd = repo.add(
|
|
625
633
|
new VertexPoint(
|
|
626
634
|
"",
|
|
627
|
-
repo.add(
|
|
628
|
-
new CartesianPoint("", bottomEnd.x, bottomEnd.y, boardThickness),
|
|
629
|
-
),
|
|
635
|
+
repo.add(new CartesianPoint("", bottomEnd.x, bottomEnd.y, zMax)),
|
|
630
636
|
),
|
|
631
637
|
)
|
|
632
638
|
|
|
@@ -639,7 +645,7 @@ function createCylindricalWall(
|
|
|
639
645
|
rotation,
|
|
640
646
|
)
|
|
641
647
|
const bottomCenter = repo.add(
|
|
642
|
-
new CartesianPoint("", centerRotated.x, centerRotated.y,
|
|
648
|
+
new CartesianPoint("", centerRotated.x, centerRotated.y, zMin),
|
|
643
649
|
)
|
|
644
650
|
const bottomPlacement = repo.add(
|
|
645
651
|
new Axis2Placement3D(
|
|
@@ -656,7 +662,7 @@ function createCylindricalWall(
|
|
|
656
662
|
|
|
657
663
|
// Create arc edge at top
|
|
658
664
|
const topCenter = repo.add(
|
|
659
|
-
new CartesianPoint("", centerRotated.x, centerRotated.y,
|
|
665
|
+
new CartesianPoint("", centerRotated.x, centerRotated.y, zMax),
|
|
660
666
|
)
|
|
661
667
|
const topPlacement = repo.add(new Axis2Placement3D("", topCenter, zDir, xDir))
|
|
662
668
|
const topCircle = repo.add(new Circle("", topPlacement, radius))
|
|
@@ -666,40 +672,37 @@ function createCylindricalWall(
|
|
|
666
672
|
const v1 = repo.add(
|
|
667
673
|
new VertexPoint(
|
|
668
674
|
"",
|
|
669
|
-
repo.add(new CartesianPoint("", bottomStart.x, bottomStart.y,
|
|
675
|
+
repo.add(new CartesianPoint("", bottomStart.x, bottomStart.y, zMin)),
|
|
670
676
|
),
|
|
671
677
|
)
|
|
672
678
|
const v2 = repo.add(
|
|
673
679
|
new VertexPoint(
|
|
674
680
|
"",
|
|
675
|
-
repo.add(
|
|
676
|
-
new CartesianPoint("", bottomStart.x, bottomStart.y, boardThickness),
|
|
677
|
-
),
|
|
681
|
+
repo.add(new CartesianPoint("", bottomStart.x, bottomStart.y, zMax)),
|
|
678
682
|
),
|
|
679
683
|
)
|
|
680
684
|
const v3 = repo.add(
|
|
681
685
|
new VertexPoint(
|
|
682
686
|
"",
|
|
683
|
-
repo.add(new CartesianPoint("", bottomEnd.x, bottomEnd.y,
|
|
687
|
+
repo.add(new CartesianPoint("", bottomEnd.x, bottomEnd.y, zMin)),
|
|
684
688
|
),
|
|
685
689
|
)
|
|
686
690
|
const v4 = repo.add(
|
|
687
691
|
new VertexPoint(
|
|
688
692
|
"",
|
|
689
|
-
repo.add(
|
|
690
|
-
new CartesianPoint("", bottomEnd.x, bottomEnd.y, boardThickness),
|
|
691
|
-
),
|
|
693
|
+
repo.add(new CartesianPoint("", bottomEnd.x, bottomEnd.y, zMax)),
|
|
692
694
|
),
|
|
693
695
|
)
|
|
694
696
|
|
|
695
697
|
// Create vertical line edges
|
|
696
698
|
const dir1 = repo.add(new Direction("", 0, 0, 1))
|
|
697
|
-
const
|
|
699
|
+
const height = zMax - zMin
|
|
700
|
+
const vec1 = repo.add(new Vector("", dir1, height))
|
|
698
701
|
const line1 = repo.add(new Line("", v1.resolve(repo).pnt, vec1))
|
|
699
702
|
const edge1 = repo.add(new EdgeCurve("", v1, v2, line1, true))
|
|
700
703
|
|
|
701
704
|
const dir2 = repo.add(new Direction("", 0, 0, 1))
|
|
702
|
-
const vec2 = repo.add(new Vector("", dir2,
|
|
705
|
+
const vec2 = repo.add(new Vector("", dir2, height))
|
|
703
706
|
const line2 = repo.add(new Line("", v3.resolve(repo).pnt, vec2))
|
|
704
707
|
const edge2 = repo.add(new EdgeCurve("", v3, v4, line2, true))
|
|
705
708
|
|
|
@@ -743,7 +746,8 @@ function createPlanarWall(
|
|
|
743
746
|
rotation: number,
|
|
744
747
|
centerX0: number,
|
|
745
748
|
centerY0: number,
|
|
746
|
-
|
|
749
|
+
zMin: number,
|
|
750
|
+
zMax: number,
|
|
747
751
|
zDir: Ref<Direction>,
|
|
748
752
|
): Ref<AdvancedFace> {
|
|
749
753
|
// Rotate points
|
|
@@ -752,21 +756,21 @@ function createPlanarWall(
|
|
|
752
756
|
|
|
753
757
|
// Create vertices
|
|
754
758
|
const v1 = repo.add(
|
|
755
|
-
new VertexPoint(
|
|
759
|
+
new VertexPoint(
|
|
760
|
+
"",
|
|
761
|
+
repo.add(new CartesianPoint("", start.x, start.y, zMin)),
|
|
762
|
+
),
|
|
756
763
|
)
|
|
757
764
|
const v2 = repo.add(
|
|
758
|
-
new VertexPoint("", repo.add(new CartesianPoint("", end.x, end.y,
|
|
765
|
+
new VertexPoint("", repo.add(new CartesianPoint("", end.x, end.y, zMin))),
|
|
759
766
|
)
|
|
760
767
|
const v3 = repo.add(
|
|
761
|
-
new VertexPoint(
|
|
762
|
-
"",
|
|
763
|
-
repo.add(new CartesianPoint("", end.x, end.y, boardThickness)),
|
|
764
|
-
),
|
|
768
|
+
new VertexPoint("", repo.add(new CartesianPoint("", end.x, end.y, zMax))),
|
|
765
769
|
)
|
|
766
770
|
const v4 = repo.add(
|
|
767
771
|
new VertexPoint(
|
|
768
772
|
"",
|
|
769
|
-
repo.add(new CartesianPoint("", start.x, start.y,
|
|
773
|
+
repo.add(new CartesianPoint("", start.x, start.y, zMax)),
|
|
770
774
|
),
|
|
771
775
|
)
|
|
772
776
|
|
|
@@ -793,11 +797,12 @@ function createPlanarWall(
|
|
|
793
797
|
|
|
794
798
|
// Create vertical edges
|
|
795
799
|
const vertDir = repo.add(new Direction("", 0, 0, 1))
|
|
796
|
-
const
|
|
800
|
+
const height = zMax - zMin
|
|
801
|
+
const vertVec1 = repo.add(new Vector("", vertDir, height))
|
|
797
802
|
const vertLine1 = repo.add(new Line("", v2.resolve(repo).pnt, vertVec1))
|
|
798
803
|
const vertEdge1 = repo.add(new EdgeCurve("", v2, v3, vertLine1, true))
|
|
799
804
|
|
|
800
|
-
const vertVec2 = repo.add(new Vector("", vertDir,
|
|
805
|
+
const vertVec2 = repo.add(new Vector("", vertDir, height))
|
|
801
806
|
const vertLine2 = repo.add(new Line("", v1.resolve(repo).pnt, vertVec2))
|
|
802
807
|
const vertEdge2 = repo.add(new EdgeCurve("", v1, v4, vertLine2, true))
|
|
803
808
|
|
|
@@ -819,7 +824,7 @@ function createPlanarWall(
|
|
|
819
824
|
const refDir = repo.add(
|
|
820
825
|
new Direction("", dx / edgeLength, dy / edgeLength, 0),
|
|
821
826
|
)
|
|
822
|
-
const planeOrigin = repo.add(new CartesianPoint("", start.x, start.y,
|
|
827
|
+
const planeOrigin = repo.add(new CartesianPoint("", start.x, start.y, zMin))
|
|
823
828
|
const placement = repo.add(
|
|
824
829
|
new Axis2Placement3D("", planeOrigin, normalDir, refDir),
|
|
825
830
|
)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Ref, Repository } from "stepts"
|
|
2
|
+
import { ClosedShell, ManifoldSolidBrep } from "stepts"
|
|
3
|
+
import type { SceneBox } from "./scene-geometry"
|
|
4
|
+
import { rotatePoint3 } from "./scene-geometry"
|
|
5
|
+
import { createFaceFromVertices, createVertex } from "./step-brep-utils"
|
|
6
|
+
|
|
7
|
+
export function createSceneBoxSolid(
|
|
8
|
+
repo: Repository,
|
|
9
|
+
box: SceneBox,
|
|
10
|
+
): Ref<ManifoldSolidBrep> {
|
|
11
|
+
if (box.mesh?.triangles?.length) {
|
|
12
|
+
return createSceneMeshSolid(repo, box)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const localBounds = box.mesh?.boundingBox
|
|
16
|
+
? {
|
|
17
|
+
min: box.mesh.boundingBox.min,
|
|
18
|
+
max: box.mesh.boundingBox.max,
|
|
19
|
+
}
|
|
20
|
+
: {
|
|
21
|
+
min: {
|
|
22
|
+
x: -box.size.x / 2,
|
|
23
|
+
y: -box.size.y / 2,
|
|
24
|
+
z: -box.size.z / 2,
|
|
25
|
+
},
|
|
26
|
+
max: {
|
|
27
|
+
x: box.size.x / 2,
|
|
28
|
+
y: box.size.y / 2,
|
|
29
|
+
z: box.size.z / 2,
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const corners = [
|
|
34
|
+
{ x: localBounds.min.x, y: localBounds.min.y, z: localBounds.min.z },
|
|
35
|
+
{ x: localBounds.max.x, y: localBounds.min.y, z: localBounds.min.z },
|
|
36
|
+
{ x: localBounds.max.x, y: localBounds.max.y, z: localBounds.min.z },
|
|
37
|
+
{ x: localBounds.min.x, y: localBounds.max.y, z: localBounds.min.z },
|
|
38
|
+
{ x: localBounds.min.x, y: localBounds.min.y, z: localBounds.max.z },
|
|
39
|
+
{ x: localBounds.max.x, y: localBounds.min.y, z: localBounds.max.z },
|
|
40
|
+
{ x: localBounds.max.x, y: localBounds.max.y, z: localBounds.max.z },
|
|
41
|
+
{ x: localBounds.min.x, y: localBounds.max.y, z: localBounds.max.z },
|
|
42
|
+
].map((corner) => {
|
|
43
|
+
const rotated = rotatePoint3(corner, box.rotation)
|
|
44
|
+
return {
|
|
45
|
+
x: rotated.x + box.center.x,
|
|
46
|
+
y: rotated.y + box.center.y,
|
|
47
|
+
z: rotated.z + box.center.z,
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const stepCorners = corners.map((corner) => ({
|
|
52
|
+
x: corner.x,
|
|
53
|
+
y: corner.z,
|
|
54
|
+
z: corner.y,
|
|
55
|
+
}))
|
|
56
|
+
|
|
57
|
+
const vertices = stepCorners.map((corner) => createVertex(repo, corner))
|
|
58
|
+
const faces = [
|
|
59
|
+
[vertices[0]!, vertices[1]!, vertices[2]!, vertices[3]!],
|
|
60
|
+
[vertices[4]!, vertices[7]!, vertices[6]!, vertices[5]!],
|
|
61
|
+
[vertices[0]!, vertices[4]!, vertices[5]!, vertices[1]!],
|
|
62
|
+
[vertices[1]!, vertices[5]!, vertices[6]!, vertices[2]!],
|
|
63
|
+
[vertices[2]!, vertices[6]!, vertices[7]!, vertices[3]!],
|
|
64
|
+
[vertices[3]!, vertices[7]!, vertices[4]!, vertices[0]!],
|
|
65
|
+
].map((faceVertices) => createFaceFromVertices(repo, faceVertices))
|
|
66
|
+
|
|
67
|
+
const shell = repo.add(new ClosedShell("", faces))
|
|
68
|
+
return repo.add(new ManifoldSolidBrep("Component", shell))
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function createSceneMeshSolid(
|
|
72
|
+
repo: Repository,
|
|
73
|
+
box: SceneBox,
|
|
74
|
+
): Ref<ManifoldSolidBrep> {
|
|
75
|
+
const faces = box.mesh!.triangles!.map((triangle) => {
|
|
76
|
+
const vertices = triangle.vertices.map((vertex) => {
|
|
77
|
+
const rotated = rotatePoint3(vertex, box.rotation)
|
|
78
|
+
const translated = {
|
|
79
|
+
x: rotated.x + box.center.x,
|
|
80
|
+
y: rotated.z + box.center.z,
|
|
81
|
+
z: rotated.y + box.center.y,
|
|
82
|
+
}
|
|
83
|
+
return createVertex(repo, translated)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return createFaceFromVertices(repo, vertices)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
const shell = repo.add(new ClosedShell("", faces))
|
|
90
|
+
return repo.add(new ManifoldSolidBrep("Component", shell))
|
|
91
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type Point3 = { x: number; y: number; z: number }
|
|
2
|
+
|
|
3
|
+
export type Rotation3 = { x: number; y: number; z: number }
|
|
4
|
+
|
|
5
|
+
export type Triangle = {
|
|
6
|
+
vertices: [Point3, Point3, Point3]
|
|
7
|
+
normal: Point3
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type BoundingBox = {
|
|
11
|
+
min: Point3
|
|
12
|
+
max: Point3
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type SceneBox = {
|
|
16
|
+
center: Point3
|
|
17
|
+
size: Point3
|
|
18
|
+
rotation?: Rotation3
|
|
19
|
+
mesh?: {
|
|
20
|
+
boundingBox: BoundingBox
|
|
21
|
+
triangles?: Triangle[]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function rotatePoint3(point: Point3, rotation?: Rotation3): Point3 {
|
|
26
|
+
if (!rotation) return point
|
|
27
|
+
|
|
28
|
+
let { x, y, z } = point
|
|
29
|
+
|
|
30
|
+
if (rotation.x) {
|
|
31
|
+
const cos = Math.cos(rotation.x)
|
|
32
|
+
const sin = Math.sin(rotation.x)
|
|
33
|
+
const nextY = y * cos - z * sin
|
|
34
|
+
const nextZ = y * sin + z * cos
|
|
35
|
+
y = nextY
|
|
36
|
+
z = nextZ
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (rotation.y) {
|
|
40
|
+
const cos = Math.cos(rotation.y)
|
|
41
|
+
const sin = Math.sin(rotation.y)
|
|
42
|
+
const nextX = x * cos + z * sin
|
|
43
|
+
const nextZ = -x * sin + z * cos
|
|
44
|
+
x = nextX
|
|
45
|
+
z = nextZ
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (rotation.z) {
|
|
49
|
+
const cos = Math.cos(rotation.z)
|
|
50
|
+
const sin = Math.sin(rotation.z)
|
|
51
|
+
const nextX = x * cos - y * sin
|
|
52
|
+
const nextY = x * sin + y * cos
|
|
53
|
+
x = nextX
|
|
54
|
+
y = nextY
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { x, y, z }
|
|
58
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { Ref, Repository } from "stepts"
|
|
2
|
+
import {
|
|
3
|
+
AdvancedFace,
|
|
4
|
+
Axis2Placement3D,
|
|
5
|
+
CartesianPoint,
|
|
6
|
+
Direction,
|
|
7
|
+
EdgeCurve,
|
|
8
|
+
EdgeLoop,
|
|
9
|
+
FaceOuterBound,
|
|
10
|
+
Line,
|
|
11
|
+
OrientedEdge,
|
|
12
|
+
Plane,
|
|
13
|
+
Vector,
|
|
14
|
+
VertexPoint,
|
|
15
|
+
} from "stepts"
|
|
16
|
+
import type { Point3 } from "./scene-geometry"
|
|
17
|
+
|
|
18
|
+
export function createVertex(
|
|
19
|
+
repo: Repository,
|
|
20
|
+
point: Point3,
|
|
21
|
+
): Ref<VertexPoint> {
|
|
22
|
+
return repo.add(
|
|
23
|
+
new VertexPoint(
|
|
24
|
+
"",
|
|
25
|
+
repo.add(new CartesianPoint("", point.x, point.y, point.z)),
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createEdge(
|
|
31
|
+
repo: Repository,
|
|
32
|
+
vStart: Ref<VertexPoint>,
|
|
33
|
+
vEnd: Ref<VertexPoint>,
|
|
34
|
+
): Ref<EdgeCurve> {
|
|
35
|
+
const pStart = vStart.resolve(repo).pnt.resolve(repo)
|
|
36
|
+
const pEnd = vEnd.resolve(repo).pnt.resolve(repo)
|
|
37
|
+
const dx = pEnd.x - pStart.x
|
|
38
|
+
const dy = pEnd.y - pStart.y
|
|
39
|
+
const dz = pEnd.z - pStart.z
|
|
40
|
+
const length = Math.sqrt(dx * dx + dy * dy + dz * dz)
|
|
41
|
+
|
|
42
|
+
if (length < 1e-10) {
|
|
43
|
+
const dir = repo.add(new Direction("", 1, 0, 0))
|
|
44
|
+
const vec = repo.add(new Vector("", dir, 1e-10))
|
|
45
|
+
const line = repo.add(new Line("", vStart.resolve(repo).pnt, vec))
|
|
46
|
+
return repo.add(new EdgeCurve("", vStart, vEnd, line, true))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const dir = repo.add(new Direction("", dx / length, dy / length, dz / length))
|
|
50
|
+
const vec = repo.add(new Vector("", dir, length))
|
|
51
|
+
const line = repo.add(new Line("", vStart.resolve(repo).pnt, vec))
|
|
52
|
+
return repo.add(new EdgeCurve("", vStart, vEnd, line, true))
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function createFaceFromVertices(
|
|
56
|
+
repo: Repository,
|
|
57
|
+
vertices: Ref<VertexPoint>[],
|
|
58
|
+
): Ref<AdvancedFace> {
|
|
59
|
+
const edges = vertices.map((vertex, index) =>
|
|
60
|
+
createEdge(repo, vertex, vertices[(index + 1) % vertices.length]!),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const edgeLoop = repo.add(
|
|
64
|
+
new EdgeLoop(
|
|
65
|
+
"",
|
|
66
|
+
edges.map((edge) => repo.add(new OrientedEdge("", edge, true))),
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
const p1 = vertices[0]!.resolve(repo).pnt.resolve(repo)
|
|
71
|
+
const p2 = vertices[1]!.resolve(repo).pnt.resolve(repo)
|
|
72
|
+
const p3 = vertices[2]!.resolve(repo).pnt.resolve(repo)
|
|
73
|
+
|
|
74
|
+
const ux = p2.x - p1.x
|
|
75
|
+
const uy = p2.y - p1.y
|
|
76
|
+
const uz = p2.z - p1.z
|
|
77
|
+
const vx = p3.x - p1.x
|
|
78
|
+
const vy = p3.y - p1.y
|
|
79
|
+
const vz = p3.z - p1.z
|
|
80
|
+
|
|
81
|
+
const nx = uy * vz - uz * vy
|
|
82
|
+
const ny = uz * vx - ux * vz
|
|
83
|
+
const nz = ux * vy - uy * vx
|
|
84
|
+
const normalLength = Math.sqrt(nx * nx + ny * ny + nz * nz)
|
|
85
|
+
const normal =
|
|
86
|
+
normalLength < 1e-10
|
|
87
|
+
? repo.add(new Direction("", 0, 0, 1))
|
|
88
|
+
: repo.add(
|
|
89
|
+
new Direction(
|
|
90
|
+
"",
|
|
91
|
+
nx / normalLength,
|
|
92
|
+
ny / normalLength,
|
|
93
|
+
nz / normalLength,
|
|
94
|
+
),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
const refLength = Math.sqrt(ux * ux + uy * uy + uz * uz)
|
|
98
|
+
const refDir =
|
|
99
|
+
refLength < 1e-10
|
|
100
|
+
? repo.add(new Direction("", 1, 0, 0))
|
|
101
|
+
: repo.add(
|
|
102
|
+
new Direction("", ux / refLength, uy / refLength, uz / refLength),
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
const placement = repo.add(
|
|
106
|
+
new Axis2Placement3D("", vertices[0]!.resolve(repo).pnt, normal, refDir),
|
|
107
|
+
)
|
|
108
|
+
const plane = repo.add(new Plane("", placement))
|
|
109
|
+
|
|
110
|
+
return repo.add(
|
|
111
|
+
new AdvancedFace(
|
|
112
|
+
"",
|
|
113
|
+
[repo.add(new FaceOuterBound("", edgeLoop, true))],
|
|
114
|
+
plane,
|
|
115
|
+
true,
|
|
116
|
+
),
|
|
117
|
+
)
|
|
118
|
+
}
|
package/lib/step-model-merger.ts
CHANGED
|
@@ -203,20 +203,20 @@ function adjustTransformForPlacement(
|
|
|
203
203
|
|
|
204
204
|
if (isThroughHoleComponent) {
|
|
205
205
|
// Place model's z=0 at board top surface.
|
|
206
|
-
// For through-hole components, the flange should always sit at board top (z=boardThickness),
|
|
206
|
+
// For through-hole components, the flange should always sit at board top (z=boardThickness/2),
|
|
207
207
|
// regardless of position.z from circuit JSON (which may include absolute coordinates or offsets
|
|
208
208
|
// that shouldn't affect the flange placement).
|
|
209
|
-
transform.translation.z = boardThickness
|
|
209
|
+
transform.translation.z = boardThickness / 2
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
if (!isThroughHoleComponent && boardThickness > 0) {
|
|
213
213
|
const halfThickness = boardThickness / 2
|
|
214
|
-
const offsetZ = targetZ
|
|
214
|
+
const offsetZ = targetZ
|
|
215
215
|
if (normalizedLayer === "bottom") {
|
|
216
216
|
transform.translation.z = -maxZ + offsetZ
|
|
217
217
|
transform.rotation.x = normalizeDegrees(transform.rotation.x + 180)
|
|
218
218
|
} else {
|
|
219
|
-
transform.translation.z =
|
|
219
|
+
transform.translation.z = halfThickness - minZ + offsetZ
|
|
220
220
|
}
|
|
221
221
|
} else if (!isThroughHoleComponent) {
|
|
222
222
|
// Only apply center-based Z for non-through-hole components without board thickness
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circuit-json-to-step",
|
|
3
3
|
"main": "dist/index.js",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.23",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"pull-reference": "git clone https://github.com/tscircuit/circuit-json.git && find circuit-json/tests -name '*.test.ts' -exec bash -c 'mv \"$0\" \"${0%.test.ts}.ts\"' {} \\; && git clone https://github.com/tscircuit/stepts.git && find stepts/tests -name '*.test.ts' -exec bash -c 'mv \"$0\" \"${0%.test.ts}.ts\"' {} \\;",
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"circuit-json-to-connectivity-map": "^0.0.22",
|
|
34
|
-
"circuit-json-to-gltf": "^0.0.
|
|
34
|
+
"circuit-json-to-gltf": "^0.0.93",
|
|
35
35
|
"circuit-to-svg": "^0.0.327",
|
|
36
36
|
"schematic-symbols": "^0.0.202",
|
|
37
|
-
"stepts": "^0.0.
|
|
37
|
+
"stepts": "^0.0.4"
|
|
38
38
|
}
|
|
39
39
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
"width": 12,
|
|
6
6
|
"height": 8,
|
|
7
7
|
"thickness": 1.6,
|
|
8
|
-
"center": {
|
|
8
|
+
"center": {
|
|
9
|
+
"x": 6,
|
|
10
|
+
"y": 4
|
|
11
|
+
}
|
|
9
12
|
},
|
|
10
13
|
{
|
|
11
14
|
"type": "pcb_hole",
|
|
@@ -26,7 +29,10 @@
|
|
|
26
29
|
"type": "pcb_component",
|
|
27
30
|
"pcb_component_id": "pcb_component_1",
|
|
28
31
|
"source_component_id": "source_component_1",
|
|
29
|
-
"center": {
|
|
32
|
+
"center": {
|
|
33
|
+
"x": 4,
|
|
34
|
+
"y": 4
|
|
35
|
+
},
|
|
30
36
|
"width": 1.6,
|
|
31
37
|
"height": 0.8,
|
|
32
38
|
"layer": "top",
|
|
@@ -37,8 +43,16 @@
|
|
|
37
43
|
"cad_component_id": "cad_component_1",
|
|
38
44
|
"pcb_component_id": "pcb_component_1",
|
|
39
45
|
"source_component_id": "source_component_1",
|
|
40
|
-
"position": {
|
|
41
|
-
|
|
46
|
+
"position": {
|
|
47
|
+
"x": 4,
|
|
48
|
+
"y": 4,
|
|
49
|
+
"z": 0
|
|
50
|
+
},
|
|
51
|
+
"rotation": {
|
|
52
|
+
"x": 0,
|
|
53
|
+
"y": 0,
|
|
54
|
+
"z": 0
|
|
55
|
+
},
|
|
42
56
|
"model_step_url": "test/fixtures/kicad-models/R_0603_1608Metric.step"
|
|
43
57
|
},
|
|
44
58
|
{
|
|
@@ -52,7 +66,10 @@
|
|
|
52
66
|
"type": "pcb_component",
|
|
53
67
|
"pcb_component_id": "pcb_component_2",
|
|
54
68
|
"source_component_id": "source_component_2",
|
|
55
|
-
"center": {
|
|
69
|
+
"center": {
|
|
70
|
+
"x": 9,
|
|
71
|
+
"y": 4
|
|
72
|
+
},
|
|
56
73
|
"width": 4.2,
|
|
57
74
|
"height": 2.8,
|
|
58
75
|
"layer": "top",
|
|
@@ -63,8 +80,16 @@
|
|
|
63
80
|
"cad_component_id": "cad_component_2",
|
|
64
81
|
"pcb_component_id": "pcb_component_2",
|
|
65
82
|
"source_component_id": "source_component_2",
|
|
66
|
-
"position": {
|
|
67
|
-
|
|
83
|
+
"position": {
|
|
84
|
+
"x": 9,
|
|
85
|
+
"y": 4,
|
|
86
|
+
"z": 0
|
|
87
|
+
},
|
|
88
|
+
"rotation": {
|
|
89
|
+
"x": 0,
|
|
90
|
+
"y": 0,
|
|
91
|
+
"z": 0
|
|
92
|
+
},
|
|
68
93
|
"model_step_url": "test/fixtures/kicad-models/SW_Push_1P1T_NO_CK_KMR2.step"
|
|
69
94
|
}
|
|
70
95
|
]
|
|
Binary file
|