circuit-json-to-lbrn 0.0.21 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +489 -182
  3. package/lib/ConvertContext.ts +6 -2
  4. package/lib/element-handlers/addPcbTrace/index.ts +145 -61
  5. package/lib/element-handlers/addPcbVia/index.ts +34 -12
  6. package/lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts +34 -12
  7. package/lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts +24 -9
  8. package/lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts +24 -9
  9. package/lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts +24 -9
  10. package/lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts +24 -9
  11. package/lib/element-handlers/addPlatedHole/addPillPlatedHole.ts +24 -9
  12. package/lib/element-handlers/addPlatedHole/addRotatedPillHoleWithRectPad.ts +24 -9
  13. package/lib/element-handlers/addSmtPad/addCircleSmtPad.ts +21 -2
  14. package/lib/element-handlers/addSmtPad/addPillSmtPad.ts +21 -2
  15. package/lib/element-handlers/addSmtPad/addPolygonSmtPad.ts +20 -2
  16. package/lib/element-handlers/addSmtPad/addRectSmtPad.ts +20 -3
  17. package/lib/element-handlers/addSmtPad/addRotatedPillSmtPad.ts +21 -2
  18. package/lib/element-handlers/addSmtPad/addRotatedRectSmtPad.ts +21 -2
  19. package/lib/index.ts +92 -41
  20. package/package.json +1 -1
  21. package/tests/assets/keyboard-default60.json +92565 -0
  22. package/tests/examples/__snapshots__/board-outline-soldermask-preset.snap.svg +1 -1
  23. package/tests/examples/__snapshots__/board-outline.snap.svg +1 -1
  24. package/tests/examples/__snapshots__/lga-interconnect.snap.svg +1 -1
  25. package/tests/examples/__snapshots__/single-trace.snap.svg +1 -1
  26. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-circle.snap.svg +1 -1
  27. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-path.snap.svg +1 -1
  28. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-polygon.snap.svg +1 -1
  29. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-rect.snap.svg +1 -1
  30. package/tests/examples/addPcbHole/__snapshots__/pcb-hole-circle.snap.svg +1 -1
  31. package/tests/examples/addPcbHole/__snapshots__/pcb-hole-oval.snap.svg +1 -1
  32. package/tests/examples/addPcbHole/__snapshots__/pcb-hole-pill.snap.svg +1 -1
  33. package/tests/examples/addPcbHole/__snapshots__/pcb-hole-rect.snap.svg +1 -1
  34. package/tests/examples/addPcbHole/__snapshots__/pcb-hole-rotated-pill.snap.svg +2 -2
  35. package/tests/examples/addPcbHole/__snapshots__/pcb-hole-with-soldermask.snap.svg +1 -1
  36. package/tests/examples/addPcbVia/__snapshots__/pcb-via-basic.snap.svg +1 -1
  37. package/tests/examples/addPcbVia/__snapshots__/pcb-via-with-net.snap.svg +1 -1
  38. package/tests/examples/addPcbVia/__snapshots__/pcb-via-with-soldermask.snap.svg +1 -1
  39. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-circle.snap.svg +1 -1
  40. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-circular-hole-with-rect-pad.snap.svg +1 -1
  41. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-oval.snap.svg +1 -1
  42. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-pill-with-rect-pad.snap.svg +1 -1
  43. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-pill.snap.svg +1 -1
  44. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-polygon.snap.svg +1 -1
  45. package/tests/examples/addPlatedHole/__snapshots__/pcb-plated-hole-rotated-pill-with-rect-pad.snap.svg +1 -1
  46. package/tests/examples/addSmtPad/__snapshots__/circleSmtPad.snap.svg +1 -1
  47. package/tests/examples/addSmtPad/__snapshots__/pillSmtPad.snap.svg +1 -1
  48. package/tests/examples/addSmtPad/__snapshots__/polygonSmtPad.snap.svg +1 -1
  49. package/tests/examples/addSmtPad/__snapshots__/rotatedPillSmtPad.snap.svg +1 -1
  50. package/tests/examples/addSmtPad/__snapshots__/rotatedRectSmtPad.snap.svg +1 -1
  51. package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-both-layer-includeSoldermask.snap.svg +8 -0
  52. package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-both-layers.snap.svg +8 -0
  53. package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-bottom-layer.snap.svg +8 -0
  54. package/tests/examples/keyboard-defaul60/__snapshots__/keyboard-top-layer.snap.svg +8 -0
  55. package/tests/examples/keyboard-defaul60/keyboard-both-layer-includeSoldermask.test.ts +27 -0
  56. package/tests/examples/keyboard-defaul60/keyboard-both-layers.test.ts +26 -0
  57. package/tests/examples/keyboard-defaul60/keyboard-bottom-layer.test.ts +26 -0
  58. package/tests/examples/keyboard-defaul60/keyboard-top-layer.test.ts +26 -0
  59. package/tests/examples/lga-interconnect.test.ts +3 -2
  60. package/tests/examples/soldermask/__snapshots__/copper-and-soldermask.snap.svg +1 -1
  61. package/tests/examples/soldermask/__snapshots__/copper-only.snap.svg +1 -1
  62. package/tests/examples/soldermask/__snapshots__/soldermask-only.snap.svg +1 -1
  63. package/tests/examples/soldermask/copper-and-soldermask.test.ts +18 -10
  64. package/tests/examples/soldermask/soldermask-only.test.ts +3 -3
  65. package/tests/examples/soldermask-margin/__snapshots__/negative-soldermask-margin.snap.svg +1 -1
  66. package/tests/examples/soldermask-margin/__snapshots__/positive-soldermask-margin.snap.svg +1 -1
  67. package/tsconfig.json +2 -1
package/dist/index.js CHANGED
@@ -51,14 +51,18 @@ var circleToPolygon = (circle, segments = 32) => {
51
51
  var addCirclePlatedHole = (platedHole, ctx) => {
52
52
  const {
53
53
  project,
54
- copperCutSetting,
54
+ topCopperCutSetting,
55
+ bottomCopperCutSetting,
55
56
  soldermaskCutSetting,
56
57
  throughBoardCutSetting,
58
+ topNetGeoms,
59
+ bottomNetGeoms,
57
60
  origin,
58
61
  includeCopper,
59
62
  includeSoldermask,
60
63
  connMap,
61
- soldermaskMargin
64
+ soldermaskMargin,
65
+ includeLayers
62
66
  } = ctx;
63
67
  const centerX = platedHole.x + origin.x;
64
68
  const centerY = platedHole.y + origin.y;
@@ -68,21 +72,38 @@ var addCirclePlatedHole = (platedHole, ctx) => {
68
72
  const circle = new Circle(point(centerX, centerY), outerRadius);
69
73
  const polygon = circleToPolygon(circle);
70
74
  if (netId) {
71
- ctx.netGeoms.get(netId)?.push(polygon);
75
+ if (includeLayers.includes("top")) {
76
+ topNetGeoms.get(netId)?.push(polygon.clone());
77
+ }
78
+ if (includeLayers.includes("bottom")) {
79
+ bottomNetGeoms.get(netId)?.push(polygon.clone());
80
+ }
72
81
  } else {
73
82
  const outer = createCirclePath({
74
83
  centerX,
75
84
  centerY,
76
85
  radius: outerRadius
77
86
  });
78
- project.children.push(
79
- new ShapePath({
80
- cutIndex: copperCutSetting.index,
81
- verts: outer.verts,
82
- prims: outer.prims,
83
- isClosed: true
84
- })
85
- );
87
+ if (includeLayers.includes("top")) {
88
+ project.children.push(
89
+ new ShapePath({
90
+ cutIndex: topCopperCutSetting.index,
91
+ verts: outer.verts,
92
+ prims: outer.prims,
93
+ isClosed: true
94
+ })
95
+ );
96
+ }
97
+ if (includeLayers.includes("bottom")) {
98
+ project.children.push(
99
+ new ShapePath({
100
+ cutIndex: bottomCopperCutSetting.index,
101
+ verts: outer.verts,
102
+ prims: outer.prims,
103
+ isClosed: true
104
+ })
105
+ );
106
+ }
86
107
  }
87
108
  }
88
109
  if (platedHole.outer_diameter > 0 && includeSoldermask) {
@@ -160,13 +181,15 @@ var createOvalPath = ({
160
181
  var addOvalPlatedHole = (platedHole, ctx) => {
161
182
  const {
162
183
  project,
163
- copperCutSetting,
184
+ topCopperCutSetting,
185
+ bottomCopperCutSetting,
164
186
  soldermaskCutSetting,
165
187
  throughBoardCutSetting,
166
188
  origin,
167
189
  includeCopper,
168
190
  includeSoldermask,
169
- soldermaskMargin
191
+ soldermaskMargin,
192
+ includeLayers
170
193
  } = ctx;
171
194
  if (platedHole.outer_width <= 0 || platedHole.outer_height <= 0) {
172
195
  return;
@@ -182,14 +205,26 @@ var addOvalPlatedHole = (platedHole, ctx) => {
182
205
  height: platedHole.outer_height,
183
206
  rotation
184
207
  });
185
- project.children.push(
186
- new ShapePath2({
187
- cutIndex: copperCutSetting.index,
188
- verts: outer.verts,
189
- prims: outer.prims,
190
- isClosed: true
191
- })
192
- );
208
+ if (includeLayers.includes("top")) {
209
+ project.children.push(
210
+ new ShapePath2({
211
+ cutIndex: topCopperCutSetting.index,
212
+ verts: outer.verts,
213
+ prims: outer.prims,
214
+ isClosed: true
215
+ })
216
+ );
217
+ }
218
+ if (includeLayers.includes("bottom")) {
219
+ project.children.push(
220
+ new ShapePath2({
221
+ cutIndex: bottomCopperCutSetting.index,
222
+ verts: outer.verts,
223
+ prims: outer.prims,
224
+ isClosed: true
225
+ })
226
+ );
227
+ }
193
228
  }
194
229
  if (platedHole.outer_width > 0 && platedHole.outer_height > 0 && includeSoldermask) {
195
230
  const smWidth = platedHole.outer_width + 2 * soldermaskMargin;
@@ -325,13 +360,15 @@ var createRoundedRectPath = ({
325
360
  var addCircularHoleWithRectPad = (platedHole, ctx) => {
326
361
  const {
327
362
  project,
328
- copperCutSetting,
363
+ topCopperCutSetting,
364
+ bottomCopperCutSetting,
329
365
  soldermaskCutSetting,
330
366
  throughBoardCutSetting,
331
367
  origin,
332
368
  includeCopper,
333
369
  includeSoldermask,
334
- soldermaskMargin
370
+ soldermaskMargin,
371
+ includeLayers
335
372
  } = ctx;
336
373
  const centerX = platedHole.x + origin.x;
337
374
  const centerY = platedHole.y + origin.y;
@@ -347,14 +384,26 @@ var addCircularHoleWithRectPad = (platedHole, ctx) => {
347
384
  borderRadius
348
385
  });
349
386
  if (includeCopper) {
350
- project.children.push(
351
- new ShapePath3({
352
- cutIndex: copperCutSetting.index,
353
- verts: padPath.verts,
354
- prims: padPath.prims,
355
- isClosed: true
356
- })
357
- );
387
+ if (includeLayers.includes("top")) {
388
+ project.children.push(
389
+ new ShapePath3({
390
+ cutIndex: topCopperCutSetting.index,
391
+ verts: padPath.verts,
392
+ prims: padPath.prims,
393
+ isClosed: true
394
+ })
395
+ );
396
+ }
397
+ if (includeLayers.includes("bottom")) {
398
+ project.children.push(
399
+ new ShapePath3({
400
+ cutIndex: bottomCopperCutSetting.index,
401
+ verts: padPath.verts,
402
+ prims: padPath.prims,
403
+ isClosed: true
404
+ })
405
+ );
406
+ }
358
407
  }
359
408
  if (includeSoldermask) {
360
409
  const smPadWidth = padWidth + 2 * soldermaskMargin;
@@ -496,13 +545,15 @@ var createPillPath = ({
496
545
  var addPillHoleWithRectPad = (platedHole, ctx) => {
497
546
  const {
498
547
  project,
499
- copperCutSetting,
548
+ topCopperCutSetting,
549
+ bottomCopperCutSetting,
500
550
  soldermaskCutSetting,
501
551
  throughBoardCutSetting,
502
552
  origin,
503
553
  includeCopper,
504
554
  includeSoldermask,
505
- soldermaskMargin
555
+ soldermaskMargin,
556
+ includeLayers
506
557
  } = ctx;
507
558
  const centerX = platedHole.x + origin.x;
508
559
  const centerY = platedHole.y + origin.y;
@@ -518,14 +569,26 @@ var addPillHoleWithRectPad = (platedHole, ctx) => {
518
569
  borderRadius
519
570
  });
520
571
  if (includeCopper) {
521
- project.children.push(
522
- new ShapePath4({
523
- cutIndex: copperCutSetting.index,
524
- verts: padPath.verts,
525
- prims: padPath.prims,
526
- isClosed: true
527
- })
528
- );
572
+ if (includeLayers.includes("top")) {
573
+ project.children.push(
574
+ new ShapePath4({
575
+ cutIndex: topCopperCutSetting.index,
576
+ verts: padPath.verts,
577
+ prims: padPath.prims,
578
+ isClosed: true
579
+ })
580
+ );
581
+ }
582
+ if (includeLayers.includes("bottom")) {
583
+ project.children.push(
584
+ new ShapePath4({
585
+ cutIndex: bottomCopperCutSetting.index,
586
+ verts: padPath.verts,
587
+ prims: padPath.prims,
588
+ isClosed: true
589
+ })
590
+ );
591
+ }
529
592
  }
530
593
  if (includeSoldermask) {
531
594
  const smPadWidth = padWidth + 2 * soldermaskMargin;
@@ -574,13 +637,15 @@ import { ShapePath as ShapePath5 } from "lbrnts";
574
637
  var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
575
638
  const {
576
639
  project,
577
- copperCutSetting,
640
+ topCopperCutSetting,
641
+ bottomCopperCutSetting,
578
642
  soldermaskCutSetting,
579
643
  throughBoardCutSetting,
580
644
  origin,
581
645
  includeCopper,
582
646
  includeSoldermask,
583
- soldermaskMargin
647
+ soldermaskMargin,
648
+ includeLayers
584
649
  } = ctx;
585
650
  const centerX = platedHole.x + origin.x;
586
651
  const centerY = platedHole.y + origin.y;
@@ -599,14 +664,26 @@ var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
599
664
  rotation: padRotation
600
665
  });
601
666
  if (includeCopper) {
602
- project.children.push(
603
- new ShapePath5({
604
- cutIndex: copperCutSetting.index,
605
- verts: padPath.verts,
606
- prims: padPath.prims,
607
- isClosed: true
608
- })
609
- );
667
+ if (includeLayers.includes("top")) {
668
+ project.children.push(
669
+ new ShapePath5({
670
+ cutIndex: topCopperCutSetting.index,
671
+ verts: padPath.verts,
672
+ prims: padPath.prims,
673
+ isClosed: true
674
+ })
675
+ );
676
+ }
677
+ if (includeLayers.includes("bottom")) {
678
+ project.children.push(
679
+ new ShapePath5({
680
+ cutIndex: bottomCopperCutSetting.index,
681
+ verts: padPath.verts,
682
+ prims: padPath.prims,
683
+ isClosed: true
684
+ })
685
+ );
686
+ }
610
687
  }
611
688
  if (includeSoldermask) {
612
689
  const smPadWidth = padWidth + 2 * soldermaskMargin;
@@ -682,13 +759,15 @@ var createPolygonPathFromOutline = ({
682
759
  var addHoleWithPolygonPad = (platedHole, ctx) => {
683
760
  const {
684
761
  project,
685
- copperCutSetting,
762
+ topCopperCutSetting,
763
+ bottomCopperCutSetting,
686
764
  soldermaskCutSetting,
687
765
  throughBoardCutSetting,
688
766
  origin,
689
767
  includeCopper,
690
768
  includeSoldermask,
691
- soldermaskMargin
769
+ soldermaskMargin,
770
+ includeLayers
692
771
  } = ctx;
693
772
  if (platedHole.pad_outline.length >= 3 && includeCopper) {
694
773
  const pad = createPolygonPathFromOutline({
@@ -697,14 +776,26 @@ var addHoleWithPolygonPad = (platedHole, ctx) => {
697
776
  offsetY: platedHole.y + origin.y
698
777
  });
699
778
  if (includeCopper) {
700
- project.children.push(
701
- new ShapePath6({
702
- cutIndex: copperCutSetting.index,
703
- verts: pad.verts,
704
- prims: pad.prims,
705
- isClosed: true
706
- })
707
- );
779
+ if (includeLayers.includes("top")) {
780
+ project.children.push(
781
+ new ShapePath6({
782
+ cutIndex: topCopperCutSetting.index,
783
+ verts: pad.verts,
784
+ prims: pad.prims,
785
+ isClosed: true
786
+ })
787
+ );
788
+ }
789
+ if (includeLayers.includes("bottom")) {
790
+ project.children.push(
791
+ new ShapePath6({
792
+ cutIndex: bottomCopperCutSetting.index,
793
+ verts: pad.verts,
794
+ prims: pad.prims,
795
+ isClosed: true
796
+ })
797
+ );
798
+ }
708
799
  }
709
800
  if (includeSoldermask) {
710
801
  project.children.push(
@@ -762,13 +853,15 @@ import { ShapePath as ShapePath7 } from "lbrnts";
762
853
  var addPcbPlatedHolePill = (platedHole, ctx) => {
763
854
  const {
764
855
  project,
765
- copperCutSetting,
856
+ topCopperCutSetting,
857
+ bottomCopperCutSetting,
766
858
  soldermaskCutSetting,
767
859
  throughBoardCutSetting,
768
860
  origin,
769
861
  includeCopper,
770
862
  includeSoldermask,
771
- soldermaskMargin
863
+ soldermaskMargin,
864
+ includeLayers
772
865
  } = ctx;
773
866
  const centerX = platedHole.x + origin.x;
774
867
  const centerY = platedHole.y + origin.y;
@@ -781,14 +874,26 @@ var addPcbPlatedHolePill = (platedHole, ctx) => {
781
874
  height: platedHole.outer_height,
782
875
  rotation
783
876
  });
784
- project.children.push(
785
- new ShapePath7({
786
- cutIndex: copperCutSetting.index,
787
- verts: outer.verts,
788
- prims: outer.prims,
789
- isClosed: true
790
- })
791
- );
877
+ if (includeLayers.includes("top")) {
878
+ project.children.push(
879
+ new ShapePath7({
880
+ cutIndex: topCopperCutSetting.index,
881
+ verts: outer.verts,
882
+ prims: outer.prims,
883
+ isClosed: true
884
+ })
885
+ );
886
+ }
887
+ if (includeLayers.includes("bottom")) {
888
+ project.children.push(
889
+ new ShapePath7({
890
+ cutIndex: bottomCopperCutSetting.index,
891
+ verts: outer.verts,
892
+ prims: outer.prims,
893
+ isClosed: true
894
+ })
895
+ );
896
+ }
792
897
  }
793
898
  if (platedHole.outer_width > 0 && platedHole.outer_height > 0 && includeSoldermask) {
794
899
  const smWidth = platedHole.outer_width + 2 * soldermaskMargin;
@@ -857,23 +962,35 @@ import { ShapePath as ShapePath8 } from "lbrnts";
857
962
  var addRectSmtPad = (smtPad, ctx) => {
858
963
  const {
859
964
  project,
860
- copperCutSetting,
965
+ topCopperCutSetting,
966
+ bottomCopperCutSetting,
861
967
  soldermaskCutSetting,
862
968
  connMap,
863
- netGeoms,
969
+ topNetGeoms,
970
+ bottomNetGeoms,
864
971
  origin,
865
972
  includeCopper,
866
973
  includeSoldermask,
867
- soldermaskMargin
974
+ soldermaskMargin,
975
+ includeLayers
868
976
  } = ctx;
977
+ const padLayer = smtPad.layer || "top";
978
+ if (padLayer !== "top" && padLayer !== "bottom") {
979
+ return;
980
+ }
981
+ if (!includeLayers.includes(padLayer)) {
982
+ return;
983
+ }
869
984
  const centerX = smtPad.x + origin.x;
870
985
  const centerY = smtPad.y + origin.y;
871
986
  const halfWidth = smtPad.width / 2;
872
987
  const halfHeight = smtPad.height / 2;
873
988
  const netId = connMap.getNetConnectedToId(smtPad.pcb_smtpad_id);
989
+ const copperCutSetting = padLayer === "top" ? topCopperCutSetting : bottomCopperCutSetting;
990
+ const netGeoms = padLayer === "top" ? topNetGeoms : bottomNetGeoms;
874
991
  if (includeCopper) {
875
992
  if (netId) {
876
- ctx.netGeoms.get(netId)?.push(
993
+ netGeoms.get(netId)?.push(
877
994
  new Box(
878
995
  centerX - halfWidth,
879
996
  centerY - halfHeight,
@@ -942,14 +1059,27 @@ import { Circle as Circle2, point as point2 } from "@flatten-js/core";
942
1059
  var addCircleSmtPad = (smtPad, ctx) => {
943
1060
  const {
944
1061
  project,
945
- copperCutSetting,
1062
+ topCopperCutSetting,
1063
+ bottomCopperCutSetting,
946
1064
  soldermaskCutSetting,
1065
+ topNetGeoms,
1066
+ bottomNetGeoms,
947
1067
  origin,
948
1068
  includeCopper,
949
1069
  includeSoldermask,
950
1070
  connMap,
951
- soldermaskMargin
1071
+ soldermaskMargin,
1072
+ includeLayers
952
1073
  } = ctx;
1074
+ const padLayer = smtPad.layer || "top";
1075
+ if (padLayer !== "top" && padLayer !== "bottom") {
1076
+ return;
1077
+ }
1078
+ if (!includeLayers.includes(padLayer)) {
1079
+ return;
1080
+ }
1081
+ const copperCutSetting = padLayer === "top" ? topCopperCutSetting : bottomCopperCutSetting;
1082
+ const netGeoms = padLayer === "top" ? topNetGeoms : bottomNetGeoms;
953
1083
  const centerX = smtPad.x + origin.x;
954
1084
  const centerY = smtPad.y + origin.y;
955
1085
  if (smtPad.radius > 0) {
@@ -959,7 +1089,7 @@ var addCircleSmtPad = (smtPad, ctx) => {
959
1089
  const circle = new Circle2(point2(centerX, centerY), outerRadius);
960
1090
  const polygon = circleToPolygon(circle);
961
1091
  if (netId) {
962
- ctx.netGeoms.get(netId)?.push(polygon);
1092
+ netGeoms.get(netId)?.push(polygon);
963
1093
  } else {
964
1094
  const outer = createCirclePath({
965
1095
  centerX,
@@ -1009,14 +1139,27 @@ var pathToPolygon = (verts) => {
1009
1139
  var addPillSmtPad = (smtPad, ctx) => {
1010
1140
  const {
1011
1141
  project,
1012
- copperCutSetting,
1142
+ topCopperCutSetting,
1143
+ bottomCopperCutSetting,
1013
1144
  soldermaskCutSetting,
1145
+ topNetGeoms,
1146
+ bottomNetGeoms,
1014
1147
  origin,
1015
1148
  includeCopper,
1016
1149
  includeSoldermask,
1017
1150
  connMap,
1018
- soldermaskMargin
1151
+ soldermaskMargin,
1152
+ includeLayers
1019
1153
  } = ctx;
1154
+ const padLayer = smtPad.layer || "top";
1155
+ if (padLayer !== "top" && padLayer !== "bottom") {
1156
+ return;
1157
+ }
1158
+ if (!includeLayers.includes(padLayer)) {
1159
+ return;
1160
+ }
1161
+ const copperCutSetting = padLayer === "top" ? topCopperCutSetting : bottomCopperCutSetting;
1162
+ const netGeoms = padLayer === "top" ? topNetGeoms : bottomNetGeoms;
1020
1163
  const centerX = smtPad.x + origin.x;
1021
1164
  const centerY = smtPad.y + origin.y;
1022
1165
  if (smtPad.width > 0 && smtPad.height > 0) {
@@ -1030,7 +1173,7 @@ var addPillSmtPad = (smtPad, ctx) => {
1030
1173
  const netId = connMap.getNetConnectedToId(smtPad.pcb_smtpad_id);
1031
1174
  const polygon = pathToPolygon(outer.verts);
1032
1175
  if (netId) {
1033
- ctx.netGeoms.get(netId)?.push(polygon);
1176
+ netGeoms.get(netId)?.push(polygon);
1034
1177
  } else {
1035
1178
  project.children.push(
1036
1179
  new ShapePath10({
@@ -1068,14 +1211,27 @@ import { ShapePath as ShapePath11 } from "lbrnts";
1068
1211
  var addRotatedPillSmtPad = (smtPad, ctx) => {
1069
1212
  const {
1070
1213
  project,
1071
- copperCutSetting,
1214
+ topCopperCutSetting,
1215
+ bottomCopperCutSetting,
1072
1216
  soldermaskCutSetting,
1217
+ topNetGeoms,
1218
+ bottomNetGeoms,
1073
1219
  origin,
1074
1220
  includeCopper,
1075
1221
  includeSoldermask,
1076
1222
  connMap,
1077
- soldermaskMargin
1223
+ soldermaskMargin,
1224
+ includeLayers
1078
1225
  } = ctx;
1226
+ const padLayer = smtPad.layer || "top";
1227
+ if (padLayer !== "top" && padLayer !== "bottom") {
1228
+ return;
1229
+ }
1230
+ if (!includeLayers.includes(padLayer)) {
1231
+ return;
1232
+ }
1233
+ const copperCutSetting = padLayer === "top" ? topCopperCutSetting : bottomCopperCutSetting;
1234
+ const netGeoms = padLayer === "top" ? topNetGeoms : bottomNetGeoms;
1079
1235
  const centerX = smtPad.x + origin.x;
1080
1236
  const centerY = smtPad.y + origin.y;
1081
1237
  if (smtPad.width > 0 && smtPad.height > 0) {
@@ -1090,7 +1246,7 @@ var addRotatedPillSmtPad = (smtPad, ctx) => {
1090
1246
  const netId = connMap.getNetConnectedToId(smtPad.pcb_smtpad_id);
1091
1247
  const polygon = pathToPolygon(outer.verts);
1092
1248
  if (netId) {
1093
- ctx.netGeoms.get(netId)?.push(polygon);
1249
+ netGeoms.get(netId)?.push(polygon);
1094
1250
  } else {
1095
1251
  project.children.push(
1096
1252
  new ShapePath11({
@@ -1158,14 +1314,27 @@ function polygonToShapePathData(polygon) {
1158
1314
  var addPolygonSmtPad = (smtPad, ctx) => {
1159
1315
  const {
1160
1316
  project,
1161
- copperCutSetting,
1317
+ topCopperCutSetting,
1318
+ bottomCopperCutSetting,
1162
1319
  soldermaskCutSetting,
1320
+ topNetGeoms,
1321
+ bottomNetGeoms,
1163
1322
  origin,
1164
1323
  includeCopper,
1165
1324
  includeSoldermask,
1166
1325
  connMap,
1167
- soldermaskMargin
1326
+ soldermaskMargin,
1327
+ includeLayers
1168
1328
  } = ctx;
1329
+ const padLayer = smtPad.layer || "top";
1330
+ if (padLayer !== "top" && padLayer !== "bottom") {
1331
+ return;
1332
+ }
1333
+ if (!includeLayers.includes(padLayer)) {
1334
+ return;
1335
+ }
1336
+ const copperCutSetting = padLayer === "top" ? topCopperCutSetting : bottomCopperCutSetting;
1337
+ const netGeoms = padLayer === "top" ? topNetGeoms : bottomNetGeoms;
1169
1338
  if (smtPad.points.length >= 3) {
1170
1339
  const pad = createPolygonPathFromOutline({
1171
1340
  outline: smtPad.points,
@@ -1176,7 +1345,7 @@ var addPolygonSmtPad = (smtPad, ctx) => {
1176
1345
  const netId = connMap.getNetConnectedToId(smtPad.pcb_smtpad_id);
1177
1346
  const polygon = pathToPolygon(pad.verts);
1178
1347
  if (netId) {
1179
- ctx.netGeoms.get(netId)?.push(polygon);
1348
+ netGeoms.get(netId)?.push(polygon);
1180
1349
  } else {
1181
1350
  project.children.push(
1182
1351
  new ShapePath12({
@@ -1206,14 +1375,27 @@ import { ShapePath as ShapePath13 } from "lbrnts";
1206
1375
  var addRotatedRectSmtPad = (smtPad, ctx) => {
1207
1376
  const {
1208
1377
  project,
1209
- copperCutSetting,
1378
+ topCopperCutSetting,
1379
+ bottomCopperCutSetting,
1210
1380
  soldermaskCutSetting,
1381
+ topNetGeoms,
1382
+ bottomNetGeoms,
1211
1383
  origin,
1212
1384
  includeCopper,
1213
1385
  includeSoldermask,
1214
1386
  connMap,
1215
- soldermaskMargin
1387
+ soldermaskMargin,
1388
+ includeLayers
1216
1389
  } = ctx;
1390
+ const padLayer = smtPad.layer || "top";
1391
+ if (padLayer !== "top" && padLayer !== "bottom") {
1392
+ return;
1393
+ }
1394
+ if (!includeLayers.includes(padLayer)) {
1395
+ return;
1396
+ }
1397
+ const copperCutSetting = padLayer === "top" ? topCopperCutSetting : bottomCopperCutSetting;
1398
+ const netGeoms = padLayer === "top" ? topNetGeoms : bottomNetGeoms;
1217
1399
  const centerX = smtPad.x + origin.x;
1218
1400
  const centerY = smtPad.y + origin.y;
1219
1401
  const rotation = (smtPad.ccw_rotation ?? 0) * (Math.PI / 180);
@@ -1232,7 +1414,7 @@ var addRotatedRectSmtPad = (smtPad, ctx) => {
1232
1414
  const netId = connMap.getNetConnectedToId(smtPad.pcb_smtpad_id);
1233
1415
  const polygon = pathToPolygon(outer.verts);
1234
1416
  if (netId) {
1235
- ctx.netGeoms.get(netId)?.push(polygon);
1417
+ netGeoms.get(netId)?.push(polygon);
1236
1418
  } else {
1237
1419
  project.children.push(
1238
1420
  new ShapePath13({
@@ -1291,7 +1473,14 @@ var addSmtPad = (smtPad, ctx) => {
1291
1473
  // lib/element-handlers/addPcbTrace/index.ts
1292
1474
  import Flatten2, { BooleanOperations } from "@flatten-js/core";
1293
1475
  var addPcbTrace = (trace, ctx) => {
1294
- const { netGeoms, connMap, origin, includeCopper, includeSoldermask } = ctx;
1476
+ const {
1477
+ topNetGeoms,
1478
+ bottomNetGeoms,
1479
+ connMap,
1480
+ origin,
1481
+ includeCopper,
1482
+ includeLayers
1483
+ } = ctx;
1295
1484
  if (!includeCopper) {
1296
1485
  return;
1297
1486
  }
@@ -1299,60 +1488,113 @@ var addPcbTrace = (trace, ctx) => {
1299
1488
  trace.source_trace_id ?? trace.pcb_trace_id
1300
1489
  );
1301
1490
  if (!netId) {
1302
- console.warn(`Trace ${trace.pcb_trace_id} is not connected to any net`);
1303
1491
  return;
1304
1492
  }
1305
1493
  if (!trace.route || trace.route.length < 2) {
1306
- console.warn(`Trace ${trace.pcb_trace_id} has insufficient route points`);
1307
1494
  return;
1308
1495
  }
1309
1496
  const { route } = trace;
1310
- const traceWidth = route.find((point6) => point6.route_type === "wire")?.width ?? 0.15;
1311
- const polygons = [];
1312
- for (const routePoint of route) {
1313
- const circle = new Flatten2.Circle(
1314
- new Flatten2.Point(routePoint.x + origin.x, routePoint.y + origin.y),
1315
- traceWidth / 2
1316
- );
1317
- polygons.push(circleToPolygon(circle));
1318
- }
1319
- for (let i = 0; i < route.length - 1; i++) {
1320
- const p1 = route[i];
1321
- const p2 = route[i + 1];
1322
- if (!p1 || !p2) continue;
1323
- const segmentLength = Math.hypot(p1.x - p2.x, p1.y - p2.y);
1324
- if (segmentLength === 0) continue;
1325
- const centerX = (p1.x + p2.x) / 2 + origin.x;
1326
- const centerY = (p1.y + p2.y) / 2 + origin.y;
1327
- const rotationDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
1328
- const w2 = segmentLength / 2;
1329
- const h2 = traceWidth / 2;
1330
- const angleRad = rotationDeg * Math.PI / 180;
1331
- const cosAngle = Math.cos(angleRad);
1332
- const sinAngle = Math.sin(angleRad);
1333
- const corners = [
1334
- { x: -w2, y: -h2 },
1335
- { x: w2, y: -h2 },
1336
- { x: w2, y: h2 },
1337
- { x: -w2, y: h2 }
1338
- ];
1339
- const rotatedCorners = corners.map((p) => ({
1340
- x: centerX + p.x * cosAngle - p.y * sinAngle,
1341
- y: centerY + p.x * sinAngle + p.y * cosAngle
1342
- }));
1343
- polygons.push(
1344
- new Flatten2.Polygon(rotatedCorners.map((p) => Flatten2.point(p.x, p.y)))
1345
- );
1497
+ const wirePoint = route.find((point6) => {
1498
+ if (!("route_type" in point6)) return true;
1499
+ return point6.route_type === "wire";
1500
+ });
1501
+ const traceWidth = wirePoint?.width ?? 0.15;
1502
+ const layerSegments = /* @__PURE__ */ new Map();
1503
+ let currentSegment = [];
1504
+ let currentLayer = null;
1505
+ for (const point6 of route) {
1506
+ if ("route_type" in point6 && point6.route_type === "via") {
1507
+ if (currentLayer && currentSegment.length > 0) {
1508
+ if (!layerSegments.has(currentLayer)) {
1509
+ layerSegments.set(currentLayer, []);
1510
+ }
1511
+ layerSegments.get(currentLayer).push(currentSegment);
1512
+ }
1513
+ currentSegment = [];
1514
+ currentLayer = null;
1515
+ continue;
1516
+ }
1517
+ const isWirePoint = !("route_type" in point6) || point6.route_type === "wire";
1518
+ if (isWirePoint && "layer" in point6 && point6.layer) {
1519
+ const pointLayer = point6.layer;
1520
+ if (pointLayer !== "top" && pointLayer !== "bottom") {
1521
+ continue;
1522
+ }
1523
+ if (currentLayer !== null && currentLayer !== pointLayer) {
1524
+ if (currentSegment.length > 0) {
1525
+ if (!layerSegments.has(currentLayer)) {
1526
+ layerSegments.set(currentLayer, []);
1527
+ }
1528
+ layerSegments.get(currentLayer).push(currentSegment);
1529
+ }
1530
+ currentSegment = [];
1531
+ }
1532
+ currentLayer = pointLayer;
1533
+ currentSegment.push({ x: point6.x, y: point6.y });
1534
+ }
1346
1535
  }
1347
- if (polygons.length === 0) return;
1348
- let tracePolygon = polygons[0];
1349
- for (let i = 1; i < polygons.length; i++) {
1350
- const poly = polygons[i];
1351
- if (poly) {
1352
- tracePolygon = BooleanOperations.unify(tracePolygon, poly);
1536
+ if (currentLayer && currentSegment.length > 0) {
1537
+ if (!layerSegments.has(currentLayer)) {
1538
+ layerSegments.set(currentLayer, []);
1353
1539
  }
1540
+ layerSegments.get(currentLayer).push(currentSegment);
1541
+ }
1542
+ for (const [layer, segments] of layerSegments.entries()) {
1543
+ if (!includeLayers.includes(layer)) {
1544
+ continue;
1545
+ }
1546
+ const polygons = [];
1547
+ for (const points of segments) {
1548
+ if (points.length < 2) continue;
1549
+ for (const routePoint of points) {
1550
+ const circle = new Flatten2.Circle(
1551
+ new Flatten2.Point(routePoint.x + origin.x, routePoint.y + origin.y),
1552
+ traceWidth / 2
1553
+ );
1554
+ polygons.push(circleToPolygon(circle));
1555
+ }
1556
+ for (let i = 0; i < points.length - 1; i++) {
1557
+ const p1 = points[i];
1558
+ const p2 = points[i + 1];
1559
+ if (!p1 || !p2) continue;
1560
+ const segmentLength = Math.hypot(p1.x - p2.x, p1.y - p2.y);
1561
+ if (segmentLength === 0) continue;
1562
+ const centerX = (p1.x + p2.x) / 2 + origin.x;
1563
+ const centerY = (p1.y + p2.y) / 2 + origin.y;
1564
+ const rotationDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
1565
+ const w2 = segmentLength / 2;
1566
+ const h2 = traceWidth / 2;
1567
+ const angleRad = rotationDeg * Math.PI / 180;
1568
+ const cosAngle = Math.cos(angleRad);
1569
+ const sinAngle = Math.sin(angleRad);
1570
+ const corners = [
1571
+ { x: -w2, y: -h2 },
1572
+ { x: w2, y: -h2 },
1573
+ { x: w2, y: h2 },
1574
+ { x: -w2, y: h2 }
1575
+ ];
1576
+ const rotatedCorners = corners.map((p) => ({
1577
+ x: centerX + p.x * cosAngle - p.y * sinAngle,
1578
+ y: centerY + p.x * sinAngle + p.y * cosAngle
1579
+ }));
1580
+ polygons.push(
1581
+ new Flatten2.Polygon(
1582
+ rotatedCorners.map((p) => Flatten2.point(p.x, p.y))
1583
+ )
1584
+ );
1585
+ }
1586
+ }
1587
+ if (polygons.length === 0) continue;
1588
+ let tracePolygon = polygons[0];
1589
+ for (let i = 1; i < polygons.length; i++) {
1590
+ const poly = polygons[i];
1591
+ if (poly) {
1592
+ tracePolygon = BooleanOperations.unify(tracePolygon, poly);
1593
+ }
1594
+ }
1595
+ const netGeoms = layer === "top" ? topNetGeoms : bottomNetGeoms;
1596
+ netGeoms.get(netId)?.push(tracePolygon);
1354
1597
  }
1355
- netGeoms.get(netId)?.push(tracePolygon);
1356
1598
  };
1357
1599
 
1358
1600
  // lib/element-handlers/addPcbBoard/index.ts
@@ -1479,14 +1721,18 @@ var addPcbVia = (via, ctx) => {
1479
1721
  const {
1480
1722
  db,
1481
1723
  project,
1482
- copperCutSetting,
1724
+ topCopperCutSetting,
1725
+ bottomCopperCutSetting,
1483
1726
  soldermaskCutSetting,
1484
1727
  throughBoardCutSetting,
1728
+ topNetGeoms,
1729
+ bottomNetGeoms,
1485
1730
  origin,
1486
1731
  includeCopper,
1487
1732
  includeSoldermask,
1488
1733
  connMap,
1489
- soldermaskMargin
1734
+ soldermaskMargin,
1735
+ includeLayers
1490
1736
  } = ctx;
1491
1737
  const centerX = via.x + origin.x;
1492
1738
  const centerY = via.y + origin.y;
@@ -1497,21 +1743,38 @@ var addPcbVia = (via, ctx) => {
1497
1743
  const circle = new Circle3(point5(centerX, centerY), outerRadius);
1498
1744
  const polygon = circleToPolygon(circle);
1499
1745
  if (netId) {
1500
- ctx.netGeoms.get(netId)?.push(polygon);
1746
+ if (includeLayers.includes("top")) {
1747
+ topNetGeoms.get(netId)?.push(polygon.clone());
1748
+ }
1749
+ if (includeLayers.includes("bottom")) {
1750
+ bottomNetGeoms.get(netId)?.push(polygon.clone());
1751
+ }
1501
1752
  } else {
1502
1753
  const outer = createCirclePath({
1503
1754
  centerX,
1504
1755
  centerY,
1505
1756
  radius: outerRadius
1506
1757
  });
1507
- project.children.push(
1508
- new ShapePath15({
1509
- cutIndex: copperCutSetting.index,
1510
- verts: outer.verts,
1511
- prims: outer.prims,
1512
- isClosed: true
1513
- })
1514
- );
1758
+ if (includeLayers.includes("top")) {
1759
+ project.children.push(
1760
+ new ShapePath15({
1761
+ cutIndex: topCopperCutSetting.index,
1762
+ verts: outer.verts,
1763
+ prims: outer.prims,
1764
+ isClosed: true
1765
+ })
1766
+ );
1767
+ }
1768
+ if (includeLayers.includes("bottom")) {
1769
+ project.children.push(
1770
+ new ShapePath15({
1771
+ cutIndex: bottomCopperCutSetting.index,
1772
+ verts: outer.verts,
1773
+ prims: outer.prims,
1774
+ isClosed: true
1775
+ })
1776
+ );
1777
+ }
1515
1778
  }
1516
1779
  }
1517
1780
  if (via.outer_diameter > 0 && includeSoldermask) {
@@ -2050,15 +2313,23 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
2050
2313
  appVersion: "1.7.03",
2051
2314
  formatVersion: "1"
2052
2315
  });
2053
- const copperCutSetting = new CutSetting({
2316
+ const includeLayers = options.includeLayers ?? ["top", "bottom"];
2317
+ const topCopperCutSetting = new CutSetting({
2054
2318
  index: 0,
2055
- name: "Cut Copper",
2319
+ name: "Cut Top Copper",
2056
2320
  numPasses: 12,
2057
2321
  speed: 100
2058
2322
  });
2059
- project.children.push(copperCutSetting);
2060
- const throughBoardCutSetting = new CutSetting({
2323
+ project.children.push(topCopperCutSetting);
2324
+ const bottomCopperCutSetting = new CutSetting({
2061
2325
  index: 1,
2326
+ name: "Cut Bottom Copper",
2327
+ numPasses: 12,
2328
+ speed: 100
2329
+ });
2330
+ project.children.push(bottomCopperCutSetting);
2331
+ const throughBoardCutSetting = new CutSetting({
2332
+ index: 2,
2062
2333
  name: "Cut Through Board",
2063
2334
  numPasses: 3,
2064
2335
  speed: 50
@@ -2066,8 +2337,8 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
2066
2337
  project.children.push(throughBoardCutSetting);
2067
2338
  const soldermaskCutSetting = new CutSetting({
2068
2339
  type: "Scan",
2069
- // Use Scan mode to fill the pad shapes for Kapton tape cutting
2070
- index: 2,
2340
+ // Use Scan mode to fill pad shapes for Kapton tape cutting
2341
+ index: 3,
2071
2342
  name: "Cut Soldermask",
2072
2343
  numPasses: 1,
2073
2344
  speed: 150,
@@ -2076,7 +2347,7 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
2076
2347
  interval: 0.18,
2077
2348
  // Distance between cross-hatch lines
2078
2349
  angle: 45,
2079
- // Angle of the cross-hatch lines
2350
+ // Angle of cross-hatch lines
2080
2351
  crossHatch: true
2081
2352
  });
2082
2353
  project.children.push(soldermaskCutSetting);
@@ -2089,18 +2360,22 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
2089
2360
  const ctx = {
2090
2361
  db,
2091
2362
  project,
2092
- copperCutSetting,
2363
+ topCopperCutSetting,
2364
+ bottomCopperCutSetting,
2093
2365
  throughBoardCutSetting,
2094
2366
  soldermaskCutSetting,
2095
2367
  connMap,
2096
- netGeoms: /* @__PURE__ */ new Map(),
2368
+ topNetGeoms: /* @__PURE__ */ new Map(),
2369
+ bottomNetGeoms: /* @__PURE__ */ new Map(),
2097
2370
  origin,
2098
2371
  includeCopper: options.includeCopper ?? true,
2099
2372
  includeSoldermask: options.includeSoldermask ?? false,
2100
- soldermaskMargin: options.soldermaskMargin ?? 0
2373
+ soldermaskMargin: options.soldermaskMargin ?? 0,
2374
+ includeLayers
2101
2375
  };
2102
2376
  for (const net of Object.keys(connMap.netMap)) {
2103
- ctx.netGeoms.set(net, []);
2377
+ ctx.topNetGeoms.set(net, []);
2378
+ ctx.bottomNetGeoms.set(net, []);
2104
2379
  }
2105
2380
  for (const smtpad of db.pcb_smtpad.list()) {
2106
2381
  addSmtPad(smtpad, ctx);
@@ -2124,32 +2399,64 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
2124
2399
  addPcbCutout(cutout, ctx);
2125
2400
  }
2126
2401
  if (ctx.includeCopper) {
2127
- for (const net of Object.keys(connMap.netMap)) {
2128
- const netGeoms = ctx.netGeoms.get(net);
2129
- if (netGeoms.length === 0) {
2130
- continue;
2131
- }
2132
- let union = netGeoms[0];
2133
- if (union instanceof Box2) {
2134
- union = new Polygon4(union);
2135
- }
2136
- for (const geom of netGeoms.slice(1)) {
2137
- if (geom instanceof Polygon4) {
2138
- union = BooleanOperations2.unify(union, geom);
2139
- } else if (geom instanceof Box2) {
2140
- union = BooleanOperations2.unify(union, new Polygon4(geom));
2402
+ if (includeLayers.includes("top")) {
2403
+ for (const net of Object.keys(connMap.netMap)) {
2404
+ const netGeoms = ctx.topNetGeoms.get(net);
2405
+ if (netGeoms.length === 0) {
2406
+ continue;
2407
+ }
2408
+ let union = netGeoms[0];
2409
+ if (union instanceof Box2) {
2410
+ union = new Polygon4(union);
2411
+ }
2412
+ for (const geom of netGeoms.slice(1)) {
2413
+ if (geom instanceof Polygon4) {
2414
+ union = BooleanOperations2.unify(union, geom);
2415
+ } else if (geom instanceof Box2) {
2416
+ union = BooleanOperations2.unify(union, new Polygon4(geom));
2417
+ }
2418
+ }
2419
+ for (const island of union.splitToIslands()) {
2420
+ const { verts, prims } = polygonToShapePathData(island);
2421
+ project.children.push(
2422
+ new ShapePath25({
2423
+ cutIndex: topCopperCutSetting.index,
2424
+ verts,
2425
+ prims,
2426
+ isClosed: false
2427
+ })
2428
+ );
2141
2429
  }
2142
2430
  }
2143
- for (const island of union.splitToIslands()) {
2144
- const { verts, prims } = polygonToShapePathData(island);
2145
- project.children.push(
2146
- new ShapePath25({
2147
- cutIndex: copperCutSetting.index,
2148
- verts,
2149
- prims,
2150
- isClosed: false
2151
- })
2152
- );
2431
+ }
2432
+ if (includeLayers.includes("bottom")) {
2433
+ for (const net of Object.keys(connMap.netMap)) {
2434
+ const netGeoms = ctx.bottomNetGeoms.get(net);
2435
+ if (netGeoms.length === 0) {
2436
+ continue;
2437
+ }
2438
+ let union = netGeoms[0];
2439
+ if (union instanceof Box2) {
2440
+ union = new Polygon4(union);
2441
+ }
2442
+ for (const geom of netGeoms.slice(1)) {
2443
+ if (geom instanceof Polygon4) {
2444
+ union = BooleanOperations2.unify(union, geom);
2445
+ } else if (geom instanceof Box2) {
2446
+ union = BooleanOperations2.unify(union, new Polygon4(geom));
2447
+ }
2448
+ }
2449
+ for (const island of union.splitToIslands()) {
2450
+ const { verts, prims } = polygonToShapePathData(island);
2451
+ project.children.push(
2452
+ new ShapePath25({
2453
+ cutIndex: bottomCopperCutSetting.index,
2454
+ verts,
2455
+ prims,
2456
+ isClosed: false
2457
+ })
2458
+ );
2459
+ }
2153
2460
  }
2154
2461
  }
2155
2462
  }