circuit-json-to-lbrn 0.0.10 → 0.0.11

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 (26) hide show
  1. package/dist/index.js +62 -22
  2. package/lib/ConvertContext.ts +2 -1
  3. package/lib/element-handlers/addPcbBoard/index.ts +28 -9
  4. package/lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts +2 -1
  5. package/lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts +2 -1
  6. package/lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts +2 -1
  7. package/lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts +2 -1
  8. package/lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts +2 -1
  9. package/lib/element-handlers/addPlatedHole/addPillPlatedHole.ts +3 -2
  10. package/lib/element-handlers/addPlatedHole/addRotatedPillHoleWithRectPad.ts +2 -1
  11. package/lib/element-handlers/addSmtPad/addCircleSmtPad.ts +2 -1
  12. package/lib/element-handlers/addSmtPad/addPillSmtPad.ts +2 -1
  13. package/lib/element-handlers/addSmtPad/addPolygonSmtPad.ts +2 -1
  14. package/lib/element-handlers/addSmtPad/addRectSmtPad.ts +2 -1
  15. package/lib/element-handlers/addSmtPad/addRotatedPillSmtPad.ts +2 -1
  16. package/lib/element-handlers/addSmtPad/addRotatedRectSmtPad.ts +2 -1
  17. package/lib/index.ts +9 -0
  18. package/package.json +1 -1
  19. package/tests/examples/__snapshots__/board-outline-soldermask-preset.snap.svg +8 -0
  20. package/tests/examples/board-outline-soldermask-preset.test.ts +44 -0
  21. package/tests/examples/soldermask/__snapshots__/copper-and-soldermask.snap.svg +1 -1
  22. package/tests/examples/soldermask/__snapshots__/copper-only.snap.svg +8 -0
  23. package/tests/examples/soldermask/__snapshots__/soldermask-only.snap.svg +1 -1
  24. package/tests/examples/soldermask/copper-and-soldermask.test.ts +21 -0
  25. package/tests/examples/soldermask/copper-only.test.ts +106 -0
  26. package/tests/examples/soldermask/soldermask-only.test.ts +13 -0
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ var addCirclePlatedHole = (platedHole, ctx) => {
47
47
  const {
48
48
  project,
49
49
  copperCutSetting,
50
+ soldermaskCutSetting,
50
51
  throughBoardCutSetting,
51
52
  origin,
52
53
  includeCopper,
@@ -79,7 +80,7 @@ var addCirclePlatedHole = (platedHole, ctx) => {
79
80
  const outer = createCirclePath(centerX, centerY, outerRadius);
80
81
  project.children.push(
81
82
  new ShapePath({
82
- cutIndex: copperCutSetting.index,
83
+ cutIndex: soldermaskCutSetting.index,
83
84
  verts: outer.verts,
84
85
  prims: outer.prims,
85
86
  isClosed: true
@@ -135,6 +136,7 @@ var addOvalPlatedHole = (platedHole, ctx) => {
135
136
  const {
136
137
  project,
137
138
  copperCutSetting,
139
+ soldermaskCutSetting,
138
140
  throughBoardCutSetting,
139
141
  origin,
140
142
  includeCopper,
@@ -173,7 +175,7 @@ var addOvalPlatedHole = (platedHole, ctx) => {
173
175
  );
174
176
  project.children.push(
175
177
  new ShapePath2({
176
- cutIndex: copperCutSetting.index,
178
+ cutIndex: soldermaskCutSetting.index,
177
179
  verts: outer.verts,
178
180
  prims: outer.prims,
179
181
  isClosed: true
@@ -288,6 +290,7 @@ var addCircularHoleWithRectPad = (platedHole, ctx) => {
288
290
  const {
289
291
  project,
290
292
  copperCutSetting,
293
+ soldermaskCutSetting,
291
294
  throughBoardCutSetting,
292
295
  origin,
293
296
  includeCopper,
@@ -319,7 +322,7 @@ var addCircularHoleWithRectPad = (platedHole, ctx) => {
319
322
  if (includeSoldermask) {
320
323
  project.children.push(
321
324
  new ShapePath3({
322
- cutIndex: copperCutSetting.index,
325
+ cutIndex: soldermaskCutSetting.index,
323
326
  verts: padPath.verts,
324
327
  prims: padPath.prims,
325
328
  isClosed: true
@@ -428,6 +431,7 @@ var addPillHoleWithRectPad = (platedHole, ctx) => {
428
431
  const {
429
432
  project,
430
433
  copperCutSetting,
434
+ soldermaskCutSetting,
431
435
  throughBoardCutSetting,
432
436
  origin,
433
437
  includeCopper,
@@ -459,7 +463,7 @@ var addPillHoleWithRectPad = (platedHole, ctx) => {
459
463
  if (includeSoldermask) {
460
464
  project.children.push(
461
465
  new ShapePath4({
462
- cutIndex: copperCutSetting.index,
466
+ cutIndex: soldermaskCutSetting.index,
463
467
  verts: padPath.verts,
464
468
  prims: padPath.prims,
465
469
  isClosed: true
@@ -495,6 +499,7 @@ var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
495
499
  const {
496
500
  project,
497
501
  copperCutSetting,
502
+ soldermaskCutSetting,
498
503
  throughBoardCutSetting,
499
504
  origin,
500
505
  includeCopper,
@@ -529,7 +534,7 @@ var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
529
534
  if (includeSoldermask) {
530
535
  project.children.push(
531
536
  new ShapePath5({
532
- cutIndex: copperCutSetting.index,
537
+ cutIndex: soldermaskCutSetting.index,
533
538
  verts: padPath.verts,
534
539
  prims: padPath.prims,
535
540
  isClosed: true
@@ -586,6 +591,7 @@ var addHoleWithPolygonPad = (platedHole, ctx) => {
586
591
  const {
587
592
  project,
588
593
  copperCutSetting,
594
+ soldermaskCutSetting,
589
595
  throughBoardCutSetting,
590
596
  origin,
591
597
  includeCopper,
@@ -610,7 +616,7 @@ var addHoleWithPolygonPad = (platedHole, ctx) => {
610
616
  if (includeSoldermask) {
611
617
  project.children.push(
612
618
  new ShapePath6({
613
- cutIndex: copperCutSetting.index,
619
+ cutIndex: soldermaskCutSetting.index,
614
620
  verts: pad.verts,
615
621
  prims: pad.prims,
616
622
  isClosed: true
@@ -654,6 +660,7 @@ var addPcbPlatedHolePill = (platedHole, ctx) => {
654
660
  const {
655
661
  project,
656
662
  copperCutSetting,
663
+ soldermaskCutSetting,
657
664
  throughBoardCutSetting,
658
665
  origin,
659
666
  includeCopper,
@@ -689,7 +696,7 @@ var addPcbPlatedHolePill = (platedHole, ctx) => {
689
696
  );
690
697
  project.children.push(
691
698
  new ShapePath7({
692
- cutIndex: copperCutSetting.index,
699
+ cutIndex: soldermaskCutSetting.index,
693
700
  verts: outer.verts,
694
701
  prims: outer.prims,
695
702
  isClosed: true
@@ -745,6 +752,7 @@ var addRectSmtPad = (smtPad, ctx) => {
745
752
  const {
746
753
  project,
747
754
  copperCutSetting,
755
+ soldermaskCutSetting,
748
756
  connMap,
749
757
  netGeoms,
750
758
  origin,
@@ -810,7 +818,7 @@ var addRectSmtPad = (smtPad, ctx) => {
810
818
  ];
811
819
  project.children.push(
812
820
  new ShapePath8({
813
- cutIndex: copperCutSetting.index,
821
+ cutIndex: soldermaskCutSetting.index,
814
822
  verts,
815
823
  prims,
816
824
  isClosed: true
@@ -826,6 +834,7 @@ var addCircleSmtPad = (smtPad, ctx) => {
826
834
  const {
827
835
  project,
828
836
  copperCutSetting,
837
+ soldermaskCutSetting,
829
838
  origin,
830
839
  includeCopper,
831
840
  includeSoldermask,
@@ -857,7 +866,7 @@ var addCircleSmtPad = (smtPad, ctx) => {
857
866
  const outer = createCirclePath(centerX, centerY, outerRadius);
858
867
  project.children.push(
859
868
  new ShapePath9({
860
- cutIndex: copperCutSetting.index,
869
+ cutIndex: soldermaskCutSetting.index,
861
870
  verts: outer.verts,
862
871
  prims: outer.prims,
863
872
  isClosed: true
@@ -882,6 +891,7 @@ var addPillSmtPad = (smtPad, ctx) => {
882
891
  const {
883
892
  project,
884
893
  copperCutSetting,
894
+ soldermaskCutSetting,
885
895
  origin,
886
896
  includeCopper,
887
897
  includeSoldermask,
@@ -910,7 +920,7 @@ var addPillSmtPad = (smtPad, ctx) => {
910
920
  if (includeSoldermask) {
911
921
  project.children.push(
912
922
  new ShapePath10({
913
- cutIndex: copperCutSetting.index,
923
+ cutIndex: soldermaskCutSetting.index,
914
924
  verts: outer.verts,
915
925
  prims: outer.prims,
916
926
  isClosed: true
@@ -926,6 +936,7 @@ var addRotatedPillSmtPad = (smtPad, ctx) => {
926
936
  const {
927
937
  project,
928
938
  copperCutSetting,
939
+ soldermaskCutSetting,
929
940
  origin,
930
941
  includeCopper,
931
942
  includeSoldermask,
@@ -960,7 +971,7 @@ var addRotatedPillSmtPad = (smtPad, ctx) => {
960
971
  if (includeSoldermask) {
961
972
  project.children.push(
962
973
  new ShapePath11({
963
- cutIndex: copperCutSetting.index,
974
+ cutIndex: soldermaskCutSetting.index,
964
975
  verts: outer.verts,
965
976
  prims: outer.prims,
966
977
  isClosed: true
@@ -976,6 +987,7 @@ var addPolygonSmtPad = (smtPad, ctx) => {
976
987
  const {
977
988
  project,
978
989
  copperCutSetting,
990
+ soldermaskCutSetting,
979
991
  origin,
980
992
  includeCopper,
981
993
  includeSoldermask,
@@ -1002,7 +1014,7 @@ var addPolygonSmtPad = (smtPad, ctx) => {
1002
1014
  if (includeSoldermask) {
1003
1015
  project.children.push(
1004
1016
  new ShapePath12({
1005
- cutIndex: copperCutSetting.index,
1017
+ cutIndex: soldermaskCutSetting.index,
1006
1018
  verts: pad.verts,
1007
1019
  prims: pad.prims,
1008
1020
  isClosed: true
@@ -1018,6 +1030,7 @@ var addRotatedRectSmtPad = (smtPad, ctx) => {
1018
1030
  const {
1019
1031
  project,
1020
1032
  copperCutSetting,
1033
+ soldermaskCutSetting,
1021
1034
  origin,
1022
1035
  includeCopper,
1023
1036
  includeSoldermask,
@@ -1056,7 +1069,7 @@ var addRotatedRectSmtPad = (smtPad, ctx) => {
1056
1069
  if (includeSoldermask) {
1057
1070
  project.children.push(
1058
1071
  new ShapePath13({
1059
- cutIndex: copperCutSetting.index,
1072
+ cutIndex: soldermaskCutSetting.index,
1060
1073
  verts: outer.verts,
1061
1074
  prims: outer.prims,
1062
1075
  isClosed: true
@@ -1186,7 +1199,14 @@ function polygonToShapePathData(polygon) {
1186
1199
 
1187
1200
  // lib/element-handlers/addPcbBoard/index.ts
1188
1201
  var addPcbBoard = (board, ctx) => {
1189
- const { origin, project, throughBoardCutSetting } = ctx;
1202
+ const {
1203
+ origin,
1204
+ project,
1205
+ throughBoardCutSetting,
1206
+ soldermaskCutSetting,
1207
+ includeCopper,
1208
+ includeSoldermask
1209
+ } = ctx;
1190
1210
  let polygon = null;
1191
1211
  if (board.outline?.length) {
1192
1212
  polygon = new Polygon3(
@@ -1210,14 +1230,26 @@ var addPcbBoard = (board, ctx) => {
1210
1230
  }
1211
1231
  if (!polygon) return;
1212
1232
  const { verts, prims } = polygonToShapePathData(polygon);
1213
- project.children.push(
1214
- new ShapePath14({
1215
- cutIndex: throughBoardCutSetting.index,
1216
- verts,
1217
- prims,
1218
- isClosed: true
1219
- })
1220
- );
1233
+ if (includeCopper) {
1234
+ project.children.push(
1235
+ new ShapePath14({
1236
+ cutIndex: throughBoardCutSetting.index,
1237
+ verts,
1238
+ prims,
1239
+ isClosed: true
1240
+ })
1241
+ );
1242
+ }
1243
+ if (includeSoldermask) {
1244
+ project.children.push(
1245
+ new ShapePath14({
1246
+ cutIndex: soldermaskCutSetting.index,
1247
+ verts,
1248
+ prims,
1249
+ isClosed: true
1250
+ })
1251
+ );
1252
+ }
1221
1253
  };
1222
1254
 
1223
1255
  // lib/index.ts
@@ -1301,6 +1333,13 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1301
1333
  speed: 50
1302
1334
  });
1303
1335
  project.children.push(throughBoardCutSetting);
1336
+ const soldermaskCutSetting = new CutSetting({
1337
+ index: 2,
1338
+ name: "Cut Soldermask",
1339
+ numPasses: 1,
1340
+ speed: 150
1341
+ });
1342
+ project.children.push(soldermaskCutSetting);
1304
1343
  const connMap = getFullConnectivityMapFromCircuitJson(circuitJson);
1305
1344
  let origin = options.origin;
1306
1345
  if (!origin) {
@@ -1312,6 +1351,7 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1312
1351
  project,
1313
1352
  copperCutSetting,
1314
1353
  throughBoardCutSetting,
1354
+ soldermaskCutSetting,
1315
1355
  connMap,
1316
1356
  netGeoms: /* @__PURE__ */ new Map(),
1317
1357
  origin,
@@ -1,6 +1,6 @@
1
1
  import type { CircuitJsonUtilObjects } from "@tscircuit/circuit-json-util"
2
2
  import type { CutSetting, LightBurnProject } from "lbrnts"
3
- import type { AnyShape, Box, Polygon } from "@flatten-js/core"
3
+ import type { Box, Polygon } from "@flatten-js/core"
4
4
  import type { ConnectivityMap } from "circuit-json-to-connectivity-map"
5
5
 
6
6
  export type ConnectivityMapKey = string
@@ -11,6 +11,7 @@ export interface ConvertContext {
11
11
 
12
12
  copperCutSetting: CutSetting
13
13
  throughBoardCutSetting: CutSetting
14
+ soldermaskCutSetting: CutSetting
14
15
 
15
16
  connMap: ConnectivityMap
16
17
 
@@ -5,7 +5,14 @@ import type { ConvertContext } from "../../ConvertContext"
5
5
  import { polygonToShapePathData } from "../../polygon-to-shape-path"
6
6
 
7
7
  export const addPcbBoard = (board: PcbBoard, ctx: ConvertContext) => {
8
- const { origin, project, throughBoardCutSetting } = ctx
8
+ const {
9
+ origin,
10
+ project,
11
+ throughBoardCutSetting,
12
+ soldermaskCutSetting,
13
+ includeCopper,
14
+ includeSoldermask,
15
+ } = ctx
9
16
 
10
17
  let polygon: Polygon | null = null
11
18
 
@@ -39,12 +46,24 @@ export const addPcbBoard = (board: PcbBoard, ctx: ConvertContext) => {
39
46
 
40
47
  const { verts, prims } = polygonToShapePathData(polygon)
41
48
 
42
- project.children.push(
43
- new ShapePath({
44
- cutIndex: throughBoardCutSetting.index,
45
- verts,
46
- prims,
47
- isClosed: true,
48
- }),
49
- )
49
+ if (includeCopper) {
50
+ project.children.push(
51
+ new ShapePath({
52
+ cutIndex: throughBoardCutSetting.index,
53
+ verts,
54
+ prims,
55
+ isClosed: true,
56
+ }),
57
+ )
58
+ }
59
+ if (includeSoldermask) {
60
+ project.children.push(
61
+ new ShapePath({
62
+ cutIndex: soldermaskCutSetting.index,
63
+ verts,
64
+ prims,
65
+ isClosed: true,
66
+ }),
67
+ )
68
+ }
50
69
  }
@@ -12,6 +12,7 @@ export const addCirclePlatedHole = (
12
12
  const {
13
13
  project,
14
14
  copperCutSetting,
15
+ soldermaskCutSetting,
15
16
  throughBoardCutSetting,
16
17
  origin,
17
18
  includeCopper,
@@ -51,7 +52,7 @@ export const addCirclePlatedHole = (
51
52
  const outer = createCirclePath(centerX, centerY, outerRadius)
52
53
  project.children.push(
53
54
  new ShapePath({
54
- cutIndex: copperCutSetting.index,
55
+ cutIndex: soldermaskCutSetting.index,
55
56
  verts: outer.verts,
56
57
  prims: outer.prims,
57
58
  isClosed: true,
@@ -11,6 +11,7 @@ export const addCircularHoleWithRectPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  throughBoardCutSetting,
15
16
  origin,
16
17
  includeCopper,
@@ -48,7 +49,7 @@ export const addCircularHoleWithRectPad = (
48
49
  if (includeSoldermask) {
49
50
  project.children.push(
50
51
  new ShapePath({
51
- cutIndex: copperCutSetting.index,
52
+ cutIndex: soldermaskCutSetting.index,
52
53
  verts: padPath.verts,
53
54
  prims: padPath.prims,
54
55
  isClosed: true,
@@ -11,6 +11,7 @@ export const addHoleWithPolygonPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  throughBoardCutSetting,
15
16
  origin,
16
17
  includeCopper,
@@ -41,7 +42,7 @@ export const addHoleWithPolygonPad = (
41
42
  if (includeSoldermask) {
42
43
  project.children.push(
43
44
  new ShapePath({
44
- cutIndex: copperCutSetting.index,
45
+ cutIndex: soldermaskCutSetting.index,
45
46
  verts: pad.verts,
46
47
  prims: pad.prims,
47
48
  isClosed: true,
@@ -10,6 +10,7 @@ export const addOvalPlatedHole = (
10
10
  const {
11
11
  project,
12
12
  copperCutSetting,
13
+ soldermaskCutSetting,
13
14
  throughBoardCutSetting,
14
15
  origin,
15
16
  includeCopper,
@@ -62,7 +63,7 @@ export const addOvalPlatedHole = (
62
63
  )
63
64
  project.children.push(
64
65
  new ShapePath({
65
- cutIndex: copperCutSetting.index,
66
+ cutIndex: soldermaskCutSetting.index,
66
67
  verts: outer.verts,
67
68
  prims: outer.prims,
68
69
  isClosed: true,
@@ -11,6 +11,7 @@ export const addPillHoleWithRectPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  throughBoardCutSetting,
15
16
  origin,
16
17
  includeCopper,
@@ -48,7 +49,7 @@ export const addPillHoleWithRectPad = (
48
49
  if (includeSoldermask) {
49
50
  project.children.push(
50
51
  new ShapePath({
51
- cutIndex: copperCutSetting.index,
52
+ cutIndex: soldermaskCutSetting.index,
52
53
  verts: padPath.verts,
53
54
  prims: padPath.prims,
54
55
  isClosed: true,
@@ -10,6 +10,7 @@ export const addPcbPlatedHolePill = (
10
10
  const {
11
11
  project,
12
12
  copperCutSetting,
13
+ soldermaskCutSetting,
13
14
  throughBoardCutSetting,
14
15
  origin,
15
16
  includeCopper,
@@ -57,7 +58,7 @@ export const addPcbPlatedHolePill = (
57
58
  )
58
59
  project.children.push(
59
60
  new ShapePath({
60
- cutIndex: copperCutSetting.index,
61
+ cutIndex: soldermaskCutSetting.index,
61
62
  verts: outer.verts,
62
63
  prims: outer.prims,
63
64
  isClosed: true,
@@ -65,7 +66,7 @@ export const addPcbPlatedHolePill = (
65
66
  )
66
67
  }
67
68
 
68
- // Add inner pill shape (hole) - always cut through the board regardless of mode
69
+ // Add inner pill shape (hole)
69
70
  if (platedHole.hole_width > 0 && platedHole.hole_height > 0) {
70
71
  const inner = createPillPath(
71
72
  centerX,
@@ -11,6 +11,7 @@ export const addRotatedPillHoleWithRectPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  throughBoardCutSetting,
15
16
  origin,
16
17
  includeCopper,
@@ -51,7 +52,7 @@ export const addRotatedPillHoleWithRectPad = (
51
52
  if (includeSoldermask) {
52
53
  project.children.push(
53
54
  new ShapePath({
54
- cutIndex: copperCutSetting.index,
55
+ cutIndex: soldermaskCutSetting.index,
55
56
  verts: padPath.verts,
56
57
  prims: padPath.prims,
57
58
  isClosed: true,
@@ -12,6 +12,7 @@ export const addCircleSmtPad = (
12
12
  const {
13
13
  project,
14
14
  copperCutSetting,
15
+ soldermaskCutSetting,
15
16
  origin,
16
17
  includeCopper,
17
18
  includeSoldermask,
@@ -51,7 +52,7 @@ export const addCircleSmtPad = (
51
52
  const outer = createCirclePath(centerX, centerY, outerRadius)
52
53
  project.children.push(
53
54
  new ShapePath({
54
- cutIndex: copperCutSetting.index,
55
+ cutIndex: soldermaskCutSetting.index,
55
56
  verts: outer.verts,
56
57
  prims: outer.prims,
57
58
  isClosed: true,
@@ -11,6 +11,7 @@ export const addPillSmtPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  origin,
15
16
  includeCopper,
16
17
  includeSoldermask,
@@ -47,7 +48,7 @@ export const addPillSmtPad = (
47
48
  if (includeSoldermask) {
48
49
  project.children.push(
49
50
  new ShapePath({
50
- cutIndex: copperCutSetting.index,
51
+ cutIndex: soldermaskCutSetting.index,
51
52
  verts: outer.verts,
52
53
  prims: outer.prims,
53
54
  isClosed: true,
@@ -11,6 +11,7 @@ export const addPolygonSmtPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  origin,
15
16
  includeCopper,
16
17
  includeSoldermask,
@@ -46,7 +47,7 @@ export const addPolygonSmtPad = (
46
47
  if (includeSoldermask) {
47
48
  project.children.push(
48
49
  new ShapePath({
49
- cutIndex: copperCutSetting.index,
50
+ cutIndex: soldermaskCutSetting.index,
50
51
  verts: pad.verts,
51
52
  prims: pad.prims,
52
53
  isClosed: true,
@@ -7,6 +7,7 @@ export const addRectSmtPad = (smtPad: PcbSmtPadRect, ctx: ConvertContext) => {
7
7
  const {
8
8
  project,
9
9
  copperCutSetting,
10
+ soldermaskCutSetting,
10
11
  connMap,
11
12
  netGeoms,
12
13
  origin,
@@ -84,7 +85,7 @@ export const addRectSmtPad = (smtPad: PcbSmtPadRect, ctx: ConvertContext) => {
84
85
 
85
86
  project.children.push(
86
87
  new ShapePath({
87
- cutIndex: copperCutSetting.index,
88
+ cutIndex: soldermaskCutSetting.index,
88
89
  verts,
89
90
  prims,
90
91
  isClosed: true,
@@ -11,6 +11,7 @@ export const addRotatedPillSmtPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  origin,
15
16
  includeCopper,
16
17
  includeSoldermask,
@@ -53,7 +54,7 @@ export const addRotatedPillSmtPad = (
53
54
  if (includeSoldermask) {
54
55
  project.children.push(
55
56
  new ShapePath({
56
- cutIndex: copperCutSetting.index,
57
+ cutIndex: soldermaskCutSetting.index,
57
58
  verts: outer.verts,
58
59
  prims: outer.prims,
59
60
  isClosed: true,
@@ -11,6 +11,7 @@ export const addRotatedRectSmtPad = (
11
11
  const {
12
12
  project,
13
13
  copperCutSetting,
14
+ soldermaskCutSetting,
14
15
  origin,
15
16
  includeCopper,
16
17
  includeSoldermask,
@@ -57,7 +58,7 @@ export const addRotatedRectSmtPad = (
57
58
  if (includeSoldermask) {
58
59
  project.children.push(
59
60
  new ShapePath({
60
- cutIndex: copperCutSetting.index,
61
+ cutIndex: soldermaskCutSetting.index,
61
62
  verts: outer.verts,
62
63
  prims: outer.prims,
63
64
  isClosed: true,
package/lib/index.ts CHANGED
@@ -47,6 +47,14 @@ export const convertCircuitJsonToLbrn = (
47
47
  })
48
48
  project.children.push(throughBoardCutSetting)
49
49
 
50
+ const soldermaskCutSetting = new CutSetting({
51
+ index: 2,
52
+ name: "Cut Soldermask",
53
+ numPasses: 1,
54
+ speed: 150,
55
+ })
56
+ project.children.push(soldermaskCutSetting)
57
+
50
58
  const connMap = getFullConnectivityMapFromCircuitJson(circuitJson)
51
59
 
52
60
  // Auto-calculate origin if not provided to ensure all elements are in positive quadrant
@@ -61,6 +69,7 @@ export const convertCircuitJsonToLbrn = (
61
69
  project,
62
70
  copperCutSetting,
63
71
  throughBoardCutSetting,
72
+ soldermaskCutSetting,
64
73
  connMap,
65
74
  netGeoms: new Map(),
66
75
  origin,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "circuit-json-to-lbrn",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.10",
4
+ "version": "0.0.11",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "start": "bun run site/index.html",
@@ -0,0 +1,8 @@
1
+ <svg width="800" height="1400" viewBox="0 0 800 1400" xmlns="http://www.w3.org/2000/svg">
2
+ <g transform="translate(0, 0)">
3
+ <style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><circle class="pcb-pad" fill="rgb(200, 52, 52)" cx="400" cy="300" r="50" data-type="pcb_smtpad" data-pcb-layer="top"/>
4
+ </g>
5
+ <g transform="translate(0, 600) scale(26.666666666666668, 26.666666666666668) translate(13.9, 13.9)">
6
+ <rect x="-13.9" y="-13.9" width="30" height="30" fill="white"/><g transform="matrix(1 0 0 -1 0 2.200000000000001)"><g transform="matrix(1,0,0,1,0,0)"><path d="M 2.1 1.1 L 2.095184726672197 1.1980171403295607 L 2.0807852804032305 1.2950903220161283 L 2.056940335732209 1.3902846772544624 L 2.0238795325112866 1.48268343236509 L 1.981921264348355 1.5713967368259978 L 1.9314696123025454 1.6555702330196023 L 1.873010453362737 1.7343932841636456 L 1.8071067811865476 1.8071067811865476 L 1.7343932841636456 1.873010453362737 L 1.6555702330196023 1.9314696123025454 L 1.571396736825998 1.981921264348355 L 1.48268343236509 2.0238795325112866 L 1.3902846772544624 2.056940335732209 L 1.2950903220161285 2.0807852804032305 L 1.198017140329561 2.095184726672197 L 1.1 2.1 L 1.0019828596704394 2.095184726672197 L 0.9049096779838719 2.0807852804032305 L 0.8097153227455379 2.056940335732209 L 0.7173165676349104 2.0238795325112866 L 0.6286032631740024 1.981921264348355 L 0.5444297669803981 1.9314696123025454 L 0.4656067158363547 1.8730104533627372 L 0.3928932188134526 1.8071067811865476 L 0.3269895466372631 1.7343932841636456 L 0.26853038769745474 1.6555702330196023 L 0.21807873565164515 1.571396736825998 L 0.17612046748871335 1.48268343236509 L 0.14305966426779126 1.3902846772544626 L 0.11921471959676966 1.2950903220161287 L 0.10481527332780327 1.198017140329561 L 0.10000000000000009 1.1000000000000003 L 0.10481527332780316 1.0019828596704394 L 0.11921471959676966 0.9049096779838717 L 0.14305966426779115 0.809715322745538 L 0.17612046748871324 0.7173165676349105 L 0.21807873565164504 0.6286032631740024 L 0.26853038769745463 0.5444297669803981 L 0.326989546637263 0.4656067158363548 L 0.3928932188134524 0.3928932188134526 L 0.46560671583635427 0.32698954663726343 L 0.5444297669803979 0.26853038769745485 L 0.6286032631740022 0.21807873565164515 L 0.7173165676349098 0.17612046748871357 L 0.8097153227455376 0.14305966426779126 L 0.9049096779838715 0.11921471959676977 L 1.0019828596704397 0.10481527332780316 L 1.0999999999999999 0.10000000000000009 L 1.19801714032956 0.10481527332780316 L 1.2950903220161285 0.11921471959676966 L 1.3902846772544621 0.14305966426779115 L 1.4826834323650901 0.17612046748871346 L 1.5713967368259976 0.21807873565164504 L 1.6555702330196018 0.26853038769745463 L 1.7343932841636458 0.3269895466372632 L 1.8071067811865476 0.3928932188134524 L 1.8730104533627367 0.46560671583635416 L 1.9314696123025454 0.5444297669803979 L 1.981921264348355 0.6286032631740022 L 2.0238795325112866 0.7173165676349097 L 2.056940335732209 0.8097153227455376 L 2.0807852804032305 0.9049096779838713 L 2.095184726672197 1.0019828596704397 L 2.1 1.1 L 2.1 1.1 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M -3.9 -3.9 L 6.1 -3.9 L 6.1 6.1 L -3.9 6.1 L -3.9 -3.9 L -3.9 -3.9 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g></g>
7
+ </g>
8
+ </svg>
@@ -0,0 +1,44 @@
1
+ import { test, expect } from "bun:test"
2
+ import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
3
+ import { generateLightBurnSvg } from "lbrnts"
4
+ import { convertCircuitJsonToLbrn } from "../../lib"
5
+ import { stackSvgsVertically } from "stack-svgs"
6
+ import type { CircuitJson } from "circuit-json"
7
+
8
+ const circuitJson: CircuitJson = [
9
+ {
10
+ type: "pcb_board",
11
+ pcb_board_id: "board",
12
+ width: 10,
13
+ height: 10,
14
+ center: { x: 0, y: 0 },
15
+ thickness: 1.6,
16
+ num_layers: 2,
17
+ material: "fr4",
18
+ },
19
+ {
20
+ type: "pcb_smtpad",
21
+ x: 0,
22
+ y: 0,
23
+ layer: "top",
24
+ shape: "circle",
25
+ pcb_smtpad_id: "pcb_smt_pad_1",
26
+ pcb_port_id: "pcb_port_1",
27
+ radius: 1,
28
+ },
29
+ ]
30
+
31
+ test("board outline with soldermask_cutout preset uses soldermask cut settings", async () => {
32
+ const pcbSvg = await convertCircuitJsonToPcbSvg(circuitJson)
33
+
34
+ const project = convertCircuitJsonToLbrn(circuitJson, {
35
+ includeCopper: false,
36
+ includeSoldermask: true,
37
+ })
38
+
39
+ const lbrnSvg = await generateLightBurnSvg(project)
40
+
41
+ expect(stackSvgsVertically([pcbSvg, lbrnSvg])).toMatchSvgSnapshot(
42
+ import.meta.filename,
43
+ )
44
+ })
@@ -3,6 +3,6 @@
3
3
  <style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><circle class="pcb-pad" fill="rgb(200, 52, 52)" cx="300" cy="300" r="25" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="475" y="275" width="50" height="50" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 300 300 L 500 300" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/>
4
4
  </g>
5
5
  <g transform="translate(0, 600) scale(26.666666666666668, 26.666666666666668) translate(12.4, 14.4)">
6
- <rect x="-12.4" y="-14.4" width="30" height="30" fill="white"/><g transform="matrix(1 0 0 -1 0 1.1999999999999993)"><g transform="matrix(1,0,0,1,0,0)"><path d="M 1.1 0.6 L 1.0975923633360987 0.6490085701647803 L 1.0903926402016153 0.6975451610080641 L 1.0784701678661044 0.7451423386272311 L 1.0619397662556436 0.7913417161825449 L 1.0409606321741776 0.8356983684129988 L 1.0157348061512728 0.8777851165098011 L 0.9865052266813685 0.9171966420818227 L 0.9535533905932738 0.9535533905932737 L 0.9171966420818228 0.9865052266813685 L 0.8777851165098012 1.0157348061512725 L 0.835698368412999 1.0409606321741776 L 0.791341716182545 1.0619397662556433 L 0.7451423386272312 1.0784701678661044 L 0.6975451610080643 1.0903926402016153 L 0.6490085701647805 1.0975923633360984 L 0.6000000000000001 1.1 L 0.5509914298352198 1.0975923633360984 L 0.502454838991936 1.0903926402016153 L 0.454857661372769 1.0784701678661044 L 0.4086582838174552 1.0619397662556433 L 0.36430163158700124 1.0409606321741776 L 0.3222148834901991 1.0157348061512725 L 0.2828033579181774 0.9865052266813685 L 0.24644660940672636 0.9535533905932738 L 0.2134947733186316 0.9171966420818227 L 0.18426519384872742 0.8777851165098011 L 0.15903936782582262 0.8356983684129989 L 0.13806023374435672 0.7913417161825449 L 0.12152983213389568 0.7451423386272311 L 0.10960735979838487 0.6975451610080643 L 0.10240763666390168 0.6490085701647804 L 0.10000000000000009 0.6000000000000001 L 0.10240763666390162 0.5509914298352196 L 0.10960735979838487 0.5024548389919358 L 0.12152983213389562 0.45485766137276895 L 0.13806023374435666 0.40865828381745517 L 0.15903936782582256 0.36430163158700113 L 0.18426519384872736 0.322214883490199 L 0.21349477331863154 0.28280335791817734 L 0.24644660940672625 0.24644660940672625 L 0.2828033579181772 0.21349477331863165 L 0.322214883490199 0.18426519384872736 L 0.36430163158700113 0.1590393678258225 L 0.40865828381745495 0.13806023374435672 L 0.45485766137276884 0.12152983213389557 L 0.5024548389919358 0.10960735979838482 L 0.5509914298352199 0.10240763666390151 L 0.6 0.09999999999999998 L 0.6490085701647801 0.10240763666390151 L 0.6975451610080643 0.10960735979838476 L 0.7451423386272311 0.12152983213389551 L 0.7913417161825451 0.13806023374435666 L 0.8356983684129988 0.15903936782582245 L 0.877785116509801 0.18426519384872725 L 0.9171966420818229 0.21349477331863154 L 0.9535533905932738 0.24644660940672614 L 0.9865052266813684 0.282803357918177 L 1.0157348061512728 0.3222148834901989 L 1.0409606321741776 0.364301631587001 L 1.0619397662556433 0.4086582838174548 L 1.0784701678661044 0.45485766137276873 L 1.0903926402016153 0.5024548389919357 L 1.0975923633360987 0.5509914298352198 L 1.1 0.6 L 1.1 0.6 Z" fill="none" stroke="#000000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M 4.1 0.09999999999999998 L 5.1 0.09999999999999998 L 5.1 1.1 L 4.1 1.1 L 4.1 0.09999999999999998 L 4.1 0.09999999999999998 Z" fill="none" stroke="#000000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M -2.4 -4.4 L 7.6 -4.4 L 7.6 5.6 L -2.4 5.6 L -2.4 -4.4 L -2.4 -4.4 Z" fill="none" stroke="#0000FF" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M 1.0896479729346218 0.7 L 1.0619397662556436 0.7913417161825449 L 1.0157348061512728 0.8777851165098011 L 0.9535533905932738 0.9535533905932737 L 0.8777851165098012 1.0157348061512725 L 0.791341716182545 1.0619397662556433 L 0.6975451610080643 1.0903926402016153 L 0.6000000000000001 1.1 L 0.502454838991936 1.0903926402016153 L 0.4086582838174552 1.0619397662556433 L 0.3222148834901991 1.0157348061512725 L 0.24644660940672636 0.9535533905932738 L 0.18426519384872742 0.8777851165098011 L 0.13806023374435672 0.7913417161825449 L 0.10960735979838487 0.6975451610080643 L 0.10000000000000009 0.6000000000000001 L 0.10960735979838487 0.5024548389919358 L 0.13806023374435666 0.40865828381745517 L 0.18426519384872736 0.322214883490199 L 0.24644660940672625 0.24644660940672625 L 0.322214883490199 0.18426519384872736 L 0.40865828381745495 0.13806023374435672 L 0.5024548389919358 0.10960735979838482 L 0.6 0.09999999999999998 L 0.6975451610080643 0.10960735979838476 L 0.7913417161825451 0.13806023374435666 L 0.877785116509801 0.18426519384872725 L 0.9535533905932738 0.24644660940672614 L 1.0157348061512728 0.3222148834901989 L 1.0619397662556433 0.4086582838174548 L 1.0896479729346216 0.5 L 4.1 0.5 L 4.1 0.09999999999999998 L 5.1 0.09999999999999998 L 5.1 1.1 L 4.1 1.1 L 4.1 0.7 L 1.0896479729346218 0.7 L 1.0896479729346218 0.7" fill="none" stroke="#000000" stroke-width="0.1"/></g></g>
6
+ <rect x="-12.4" y="-14.4" width="30" height="30" fill="white"/><g transform="matrix(1 0 0 -1 0 1.1999999999999993)"><g transform="matrix(1,0,0,1,0,0)"><path d="M 1.1 0.6 L 1.0975923633360987 0.6490085701647803 L 1.0903926402016153 0.6975451610080641 L 1.0784701678661044 0.7451423386272311 L 1.0619397662556436 0.7913417161825449 L 1.0409606321741776 0.8356983684129988 L 1.0157348061512728 0.8777851165098011 L 0.9865052266813685 0.9171966420818227 L 0.9535533905932738 0.9535533905932737 L 0.9171966420818228 0.9865052266813685 L 0.8777851165098012 1.0157348061512725 L 0.835698368412999 1.0409606321741776 L 0.791341716182545 1.0619397662556433 L 0.7451423386272312 1.0784701678661044 L 0.6975451610080643 1.0903926402016153 L 0.6490085701647805 1.0975923633360984 L 0.6000000000000001 1.1 L 0.5509914298352198 1.0975923633360984 L 0.502454838991936 1.0903926402016153 L 0.454857661372769 1.0784701678661044 L 0.4086582838174552 1.0619397662556433 L 0.36430163158700124 1.0409606321741776 L 0.3222148834901991 1.0157348061512725 L 0.2828033579181774 0.9865052266813685 L 0.24644660940672636 0.9535533905932738 L 0.2134947733186316 0.9171966420818227 L 0.18426519384872742 0.8777851165098011 L 0.15903936782582262 0.8356983684129989 L 0.13806023374435672 0.7913417161825449 L 0.12152983213389568 0.7451423386272311 L 0.10960735979838487 0.6975451610080643 L 0.10240763666390168 0.6490085701647804 L 0.10000000000000009 0.6000000000000001 L 0.10240763666390162 0.5509914298352196 L 0.10960735979838487 0.5024548389919358 L 0.12152983213389562 0.45485766137276895 L 0.13806023374435666 0.40865828381745517 L 0.15903936782582256 0.36430163158700113 L 0.18426519384872736 0.322214883490199 L 0.21349477331863154 0.28280335791817734 L 0.24644660940672625 0.24644660940672625 L 0.2828033579181772 0.21349477331863165 L 0.322214883490199 0.18426519384872736 L 0.36430163158700113 0.1590393678258225 L 0.40865828381745495 0.13806023374435672 L 0.45485766137276884 0.12152983213389557 L 0.5024548389919358 0.10960735979838482 L 0.5509914298352199 0.10240763666390151 L 0.6 0.09999999999999998 L 0.6490085701647801 0.10240763666390151 L 0.6975451610080643 0.10960735979838476 L 0.7451423386272311 0.12152983213389551 L 0.7913417161825451 0.13806023374435666 L 0.8356983684129988 0.15903936782582245 L 0.877785116509801 0.18426519384872725 L 0.9171966420818229 0.21349477331863154 L 0.9535533905932738 0.24644660940672614 L 0.9865052266813684 0.282803357918177 L 1.0157348061512728 0.3222148834901989 L 1.0409606321741776 0.364301631587001 L 1.0619397662556433 0.4086582838174548 L 1.0784701678661044 0.45485766137276873 L 1.0903926402016153 0.5024548389919357 L 1.0975923633360987 0.5509914298352198 L 1.1 0.6 L 1.1 0.6 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M 4.1 0.09999999999999998 L 5.1 0.09999999999999998 L 5.1 1.1 L 4.1 1.1 L 4.1 0.09999999999999998 L 4.1 0.09999999999999998 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M -2.4 -4.4 L 7.6 -4.4 L 7.6 5.6 L -2.4 5.6 L -2.4 -4.4 L -2.4 -4.4 Z" fill="none" stroke="#0000FF" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M -2.4 -4.4 L 7.6 -4.4 L 7.6 5.6 L -2.4 5.6 L -2.4 -4.4 L -2.4 -4.4 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M 1.0896479729346218 0.7 L 1.0619397662556436 0.7913417161825449 L 1.0157348061512728 0.8777851165098011 L 0.9535533905932738 0.9535533905932737 L 0.8777851165098012 1.0157348061512725 L 0.791341716182545 1.0619397662556433 L 0.6975451610080643 1.0903926402016153 L 0.6000000000000001 1.1 L 0.502454838991936 1.0903926402016153 L 0.4086582838174552 1.0619397662556433 L 0.3222148834901991 1.0157348061512725 L 0.24644660940672636 0.9535533905932738 L 0.18426519384872742 0.8777851165098011 L 0.13806023374435672 0.7913417161825449 L 0.10960735979838487 0.6975451610080643 L 0.10000000000000009 0.6000000000000001 L 0.10960735979838487 0.5024548389919358 L 0.13806023374435666 0.40865828381745517 L 0.18426519384872736 0.322214883490199 L 0.24644660940672625 0.24644660940672625 L 0.322214883490199 0.18426519384872736 L 0.40865828381745495 0.13806023374435672 L 0.5024548389919358 0.10960735979838482 L 0.6 0.09999999999999998 L 0.6975451610080643 0.10960735979838476 L 0.7913417161825451 0.13806023374435666 L 0.877785116509801 0.18426519384872725 L 0.9535533905932738 0.24644660940672614 L 1.0157348061512728 0.3222148834901989 L 1.0619397662556433 0.4086582838174548 L 1.0896479729346216 0.5 L 4.1 0.5 L 4.1 0.09999999999999998 L 5.1 0.09999999999999998 L 5.1 1.1 L 4.1 1.1 L 4.1 0.7 L 1.0896479729346218 0.7 L 1.0896479729346218 0.7" fill="none" stroke="#000000" stroke-width="0.1"/></g></g>
7
7
  </g>
8
8
  </svg>
@@ -0,0 +1,8 @@
1
+ <svg width="800" height="1400" viewBox="0 0 800 1400" xmlns="http://www.w3.org/2000/svg">
2
+ <g transform="translate(0, 0)">
3
+ <style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><circle class="pcb-pad" fill="rgb(200, 52, 52)" cx="300" cy="300" r="25" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="475" y="275" width="50" height="50" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 300 300 L 500 300" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/>
4
+ </g>
5
+ <g transform="translate(0, 600) scale(26.666666666666668, 26.666666666666668) translate(12.4, 14.4)">
6
+ <rect x="-12.4" y="-14.4" width="30" height="30" fill="white"/><g transform="matrix(1 0 0 -1 0 1.1999999999999993)"><g transform="matrix(1,0,0,1,0,0)"><path d="M -2.4 -4.4 L 7.6 -4.4 L 7.6 5.6 L -2.4 5.6 L -2.4 -4.4 L -2.4 -4.4 Z" fill="none" stroke="#0000FF" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M 1.0896479729346218 0.7 L 1.0619397662556436 0.7913417161825449 L 1.0157348061512728 0.8777851165098011 L 0.9535533905932738 0.9535533905932737 L 0.8777851165098012 1.0157348061512725 L 0.791341716182545 1.0619397662556433 L 0.6975451610080643 1.0903926402016153 L 0.6000000000000001 1.1 L 0.502454838991936 1.0903926402016153 L 0.4086582838174552 1.0619397662556433 L 0.3222148834901991 1.0157348061512725 L 0.24644660940672636 0.9535533905932738 L 0.18426519384872742 0.8777851165098011 L 0.13806023374435672 0.7913417161825449 L 0.10960735979838487 0.6975451610080643 L 0.10000000000000009 0.6000000000000001 L 0.10960735979838487 0.5024548389919358 L 0.13806023374435666 0.40865828381745517 L 0.18426519384872736 0.322214883490199 L 0.24644660940672625 0.24644660940672625 L 0.322214883490199 0.18426519384872736 L 0.40865828381745495 0.13806023374435672 L 0.5024548389919358 0.10960735979838482 L 0.6 0.09999999999999998 L 0.6975451610080643 0.10960735979838476 L 0.7913417161825451 0.13806023374435666 L 0.877785116509801 0.18426519384872725 L 0.9535533905932738 0.24644660940672614 L 1.0157348061512728 0.3222148834901989 L 1.0619397662556433 0.4086582838174548 L 1.0896479729346216 0.5 L 4.1 0.5 L 4.1 0.09999999999999998 L 5.1 0.09999999999999998 L 5.1 1.1 L 4.1 1.1 L 4.1 0.7 L 1.0896479729346218 0.7 L 1.0896479729346218 0.7" fill="none" stroke="#000000" stroke-width="0.1"/></g></g>
7
+ </g>
8
+ </svg>
@@ -3,6 +3,6 @@
3
3
  <style></style><rect class="boundary" x="0" y="0" fill="#000" width="800" height="600" data-type="pcb_background" data-pcb-layer="global"/><rect class="pcb-boundary" fill="none" stroke="#fff" stroke-width="0.3" x="150" y="50" width="500" height="500" data-type="pcb_boundary" data-pcb-layer="global"/><path class="pcb-board" d="M 150 550 L 650 550 L 650 50 L 150 50 Z" fill="none" stroke="rgba(255, 255, 255, 0.5)" stroke-width="5" data-type="pcb_board" data-pcb-layer="board"/><circle class="pcb-pad" fill="rgb(200, 52, 52)" cx="300" cy="300" r="25" data-type="pcb_smtpad" data-pcb-layer="top"/><rect class="pcb-pad" fill="rgb(200, 52, 52)" x="475" y="275" width="50" height="50" data-type="pcb_smtpad" data-pcb-layer="top"/><path class="pcb-trace" stroke="rgb(200, 52, 52)" fill="none" d="M 300 300 L 500 300" stroke-width="10" stroke-linecap="round" stroke-linejoin="round" shape-rendering="crispEdges" data-type="pcb_trace" data-pcb-layer="top"/>
4
4
  </g>
5
5
  <g transform="translate(0, 600) scale(26.666666666666668, 26.666666666666668) translate(12.4, 14.4)">
6
- <rect x="-12.4" y="-14.4" width="30" height="30" fill="white"/><g transform="matrix(1 0 0 -1 0 1.1999999999999993)"><g transform="matrix(1,0,0,1,0,0)"><path d="M 1.1 0.6 L 1.0975923633360987 0.6490085701647803 L 1.0903926402016153 0.6975451610080641 L 1.0784701678661044 0.7451423386272311 L 1.0619397662556436 0.7913417161825449 L 1.0409606321741776 0.8356983684129988 L 1.0157348061512728 0.8777851165098011 L 0.9865052266813685 0.9171966420818227 L 0.9535533905932738 0.9535533905932737 L 0.9171966420818228 0.9865052266813685 L 0.8777851165098012 1.0157348061512725 L 0.835698368412999 1.0409606321741776 L 0.791341716182545 1.0619397662556433 L 0.7451423386272312 1.0784701678661044 L 0.6975451610080643 1.0903926402016153 L 0.6490085701647805 1.0975923633360984 L 0.6000000000000001 1.1 L 0.5509914298352198 1.0975923633360984 L 0.502454838991936 1.0903926402016153 L 0.454857661372769 1.0784701678661044 L 0.4086582838174552 1.0619397662556433 L 0.36430163158700124 1.0409606321741776 L 0.3222148834901991 1.0157348061512725 L 0.2828033579181774 0.9865052266813685 L 0.24644660940672636 0.9535533905932738 L 0.2134947733186316 0.9171966420818227 L 0.18426519384872742 0.8777851165098011 L 0.15903936782582262 0.8356983684129989 L 0.13806023374435672 0.7913417161825449 L 0.12152983213389568 0.7451423386272311 L 0.10960735979838487 0.6975451610080643 L 0.10240763666390168 0.6490085701647804 L 0.10000000000000009 0.6000000000000001 L 0.10240763666390162 0.5509914298352196 L 0.10960735979838487 0.5024548389919358 L 0.12152983213389562 0.45485766137276895 L 0.13806023374435666 0.40865828381745517 L 0.15903936782582256 0.36430163158700113 L 0.18426519384872736 0.322214883490199 L 0.21349477331863154 0.28280335791817734 L 0.24644660940672625 0.24644660940672625 L 0.2828033579181772 0.21349477331863165 L 0.322214883490199 0.18426519384872736 L 0.36430163158700113 0.1590393678258225 L 0.40865828381745495 0.13806023374435672 L 0.45485766137276884 0.12152983213389557 L 0.5024548389919358 0.10960735979838482 L 0.5509914298352199 0.10240763666390151 L 0.6 0.09999999999999998 L 0.6490085701647801 0.10240763666390151 L 0.6975451610080643 0.10960735979838476 L 0.7451423386272311 0.12152983213389551 L 0.7913417161825451 0.13806023374435666 L 0.8356983684129988 0.15903936782582245 L 0.877785116509801 0.18426519384872725 L 0.9171966420818229 0.21349477331863154 L 0.9535533905932738 0.24644660940672614 L 0.9865052266813684 0.282803357918177 L 1.0157348061512728 0.3222148834901989 L 1.0409606321741776 0.364301631587001 L 1.0619397662556433 0.4086582838174548 L 1.0784701678661044 0.45485766137276873 L 1.0903926402016153 0.5024548389919357 L 1.0975923633360987 0.5509914298352198 L 1.1 0.6 L 1.1 0.6 Z" fill="none" stroke="#000000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M 4.1 0.09999999999999998 L 5.1 0.09999999999999998 L 5.1 1.1 L 4.1 1.1 L 4.1 0.09999999999999998 L 4.1 0.09999999999999998 Z" fill="none" stroke="#000000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M -2.4 -4.4 L 7.6 -4.4 L 7.6 5.6 L -2.4 5.6 L -2.4 -4.4 L -2.4 -4.4 Z" fill="none" stroke="#0000FF" stroke-width="0.1"/></g></g>
6
+ <rect x="-12.4" y="-14.4" width="30" height="30" fill="white"/><g transform="matrix(1 0 0 -1 0 1.1999999999999993)"><g transform="matrix(1,0,0,1,0,0)"><path d="M 1.1 0.6 L 1.0975923633360987 0.6490085701647803 L 1.0903926402016153 0.6975451610080641 L 1.0784701678661044 0.7451423386272311 L 1.0619397662556436 0.7913417161825449 L 1.0409606321741776 0.8356983684129988 L 1.0157348061512728 0.8777851165098011 L 0.9865052266813685 0.9171966420818227 L 0.9535533905932738 0.9535533905932737 L 0.9171966420818228 0.9865052266813685 L 0.8777851165098012 1.0157348061512725 L 0.835698368412999 1.0409606321741776 L 0.791341716182545 1.0619397662556433 L 0.7451423386272312 1.0784701678661044 L 0.6975451610080643 1.0903926402016153 L 0.6490085701647805 1.0975923633360984 L 0.6000000000000001 1.1 L 0.5509914298352198 1.0975923633360984 L 0.502454838991936 1.0903926402016153 L 0.454857661372769 1.0784701678661044 L 0.4086582838174552 1.0619397662556433 L 0.36430163158700124 1.0409606321741776 L 0.3222148834901991 1.0157348061512725 L 0.2828033579181774 0.9865052266813685 L 0.24644660940672636 0.9535533905932738 L 0.2134947733186316 0.9171966420818227 L 0.18426519384872742 0.8777851165098011 L 0.15903936782582262 0.8356983684129989 L 0.13806023374435672 0.7913417161825449 L 0.12152983213389568 0.7451423386272311 L 0.10960735979838487 0.6975451610080643 L 0.10240763666390168 0.6490085701647804 L 0.10000000000000009 0.6000000000000001 L 0.10240763666390162 0.5509914298352196 L 0.10960735979838487 0.5024548389919358 L 0.12152983213389562 0.45485766137276895 L 0.13806023374435666 0.40865828381745517 L 0.15903936782582256 0.36430163158700113 L 0.18426519384872736 0.322214883490199 L 0.21349477331863154 0.28280335791817734 L 0.24644660940672625 0.24644660940672625 L 0.2828033579181772 0.21349477331863165 L 0.322214883490199 0.18426519384872736 L 0.36430163158700113 0.1590393678258225 L 0.40865828381745495 0.13806023374435672 L 0.45485766137276884 0.12152983213389557 L 0.5024548389919358 0.10960735979838482 L 0.5509914298352199 0.10240763666390151 L 0.6 0.09999999999999998 L 0.6490085701647801 0.10240763666390151 L 0.6975451610080643 0.10960735979838476 L 0.7451423386272311 0.12152983213389551 L 0.7913417161825451 0.13806023374435666 L 0.8356983684129988 0.15903936782582245 L 0.877785116509801 0.18426519384872725 L 0.9171966420818229 0.21349477331863154 L 0.9535533905932738 0.24644660940672614 L 0.9865052266813684 0.282803357918177 L 1.0157348061512728 0.3222148834901989 L 1.0409606321741776 0.364301631587001 L 1.0619397662556433 0.4086582838174548 L 1.0784701678661044 0.45485766137276873 L 1.0903926402016153 0.5024548389919357 L 1.0975923633360987 0.5509914298352198 L 1.1 0.6 L 1.1 0.6 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M 4.1 0.09999999999999998 L 5.1 0.09999999999999998 L 5.1 1.1 L 4.1 1.1 L 4.1 0.09999999999999998 L 4.1 0.09999999999999998 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g><g transform="matrix(1,0,0,1,0,0)"><path d="M -2.4 -4.4 L 7.6 -4.4 L 7.6 5.6 L -2.4 5.6 L -2.4 -4.4 L -2.4 -4.4 Z" fill="none" stroke="#FF0000" stroke-width="0.1"/></g></g>
7
7
  </g>
8
8
  </svg>
@@ -88,6 +88,27 @@ test("renders both copper and soldermask", async () => {
88
88
  includeSoldermask: true,
89
89
  })
90
90
 
91
+ // Verify that both copper and soldermask cut settings exist
92
+ const copperCutSetting = project.children.find(
93
+ (child: any) => child.name === "Cut Copper",
94
+ )
95
+ const soldermaskCutSetting = project.children.find(
96
+ (child: any) => child.name === "Cut Soldermask",
97
+ )
98
+ expect(copperCutSetting).toBeDefined()
99
+ expect(soldermaskCutSetting).toBeDefined()
100
+ expect((copperCutSetting as any).index).toBe(0)
101
+ expect((soldermaskCutSetting as any).index).toBe(2)
102
+
103
+ // Verify that we have shapes using both cut settings
104
+ const shapePaths = project.children.filter(
105
+ (child: any) => child.isClosed !== undefined,
106
+ )
107
+ const copperShapes = shapePaths.filter((path: any) => path.cutIndex === 0)
108
+ const soldermaskShapes = shapePaths.filter((path: any) => path.cutIndex === 2)
109
+ expect(copperShapes.length).toBeGreaterThan(0)
110
+ expect(soldermaskShapes.length).toBeGreaterThan(0)
111
+
91
112
  const lbrnSvg = await generateLightBurnSvg(project)
92
113
 
93
114
  expect(stackSvgsVertically([pcbSvg, lbrnSvg])).toMatchSvgSnapshot(
@@ -0,0 +1,106 @@
1
+ import { test, expect } from "bun:test"
2
+ import { convertCircuitJsonToPcbSvg } from "circuit-to-svg"
3
+ import { generateLightBurnSvg } from "lbrnts"
4
+ import { convertCircuitJsonToLbrn } from "../../../lib"
5
+ import { stackSvgsVertically } from "stack-svgs"
6
+ import type { CircuitJson } from "circuit-json"
7
+
8
+ const circuitJson: CircuitJson = [
9
+ {
10
+ type: "source_port",
11
+ name: "pad1",
12
+ source_port_id: "source_port_1",
13
+ },
14
+ {
15
+ type: "source_port",
16
+ name: "pad2",
17
+ source_port_id: "source_port_2",
18
+ },
19
+ {
20
+ type: "source_trace",
21
+ source_trace_id: "source_trace_1",
22
+ connected_source_port_ids: ["source_port_1", "source_port_2"],
23
+ connected_source_net_ids: [],
24
+ },
25
+ {
26
+ type: "pcb_board",
27
+ pcb_board_id: "board",
28
+ width: 10,
29
+ height: 10,
30
+ center: { x: 0, y: 0 },
31
+ thickness: 1.6,
32
+ num_layers: 2,
33
+ material: "fr4",
34
+ },
35
+ {
36
+ type: "pcb_smtpad",
37
+ x: -2,
38
+ y: 0,
39
+ layer: "top",
40
+ shape: "circle",
41
+ pcb_smtpad_id: "pcb_smt_pad_1",
42
+ pcb_port_id: "pcb_port_1",
43
+ radius: 0.5,
44
+ },
45
+ {
46
+ type: "pcb_port",
47
+ pcb_port_id: "pcb_port_1",
48
+ source_port_id: "source_port_1",
49
+ x: -2,
50
+ y: 0,
51
+ layers: ["top"],
52
+ },
53
+ {
54
+ type: "pcb_smtpad",
55
+ x: 2,
56
+ y: 0,
57
+ layer: "top",
58
+ shape: "rect",
59
+ pcb_smtpad_id: "pcb_smt_pad_2",
60
+ pcb_port_id: "pcb_port_2",
61
+ width: 1,
62
+ height: 1,
63
+ },
64
+ {
65
+ type: "pcb_port",
66
+ pcb_port_id: "pcb_port_2",
67
+ source_port_id: "source_port_2",
68
+ x: 2,
69
+ y: 0,
70
+ layers: ["top"],
71
+ },
72
+ {
73
+ type: "pcb_trace",
74
+ pcb_trace_id: "trace_1",
75
+ source_trace_id: "source_trace_1",
76
+ route: [
77
+ { x: -2, y: 0, width: 0.2, route_type: "wire", layer: "top" },
78
+ { x: 2, y: 0, width: 0.2, route_type: "wire", layer: "top" },
79
+ ],
80
+ },
81
+ ]
82
+
83
+ test("renders copper only", async () => {
84
+ const pcbSvg = await convertCircuitJsonToPcbSvg(circuitJson)
85
+
86
+ const project = convertCircuitJsonToLbrn(circuitJson, {
87
+ includeCopper: true,
88
+ })
89
+
90
+ // Verify that we have shapes using both cut settings
91
+ const shapePaths = project.children.filter(
92
+ (child: any) => child.isClosed !== undefined,
93
+ )
94
+ const copperShapes = shapePaths.filter((path: any) => path.cutIndex === 0)
95
+ const soldermaskShapes = shapePaths.filter(
96
+ (path: any) => path.cutIndex === undefined,
97
+ )
98
+ expect(copperShapes.length).toBeGreaterThan(0)
99
+ expect(soldermaskShapes.length).toBe(0)
100
+
101
+ const lbrnSvg = await generateLightBurnSvg(project)
102
+
103
+ expect(stackSvgsVertically([pcbSvg, lbrnSvg])).toMatchSvgSnapshot(
104
+ import.meta.filename,
105
+ )
106
+ })
@@ -88,6 +88,19 @@ test("renders soldermask only (no copper, no traces)", async () => {
88
88
  includeSoldermask: true,
89
89
  })
90
90
 
91
+ // Verify that soldermask elements use soldermaskCutSetting (index 2)
92
+ const soldermaskCutSetting = project.children.find(
93
+ (child: any) => child.name === "Cut Soldermask",
94
+ )
95
+ expect(soldermaskCutSetting).toBeDefined()
96
+ expect((soldermaskCutSetting as any).index).toBe(2)
97
+
98
+ const shapePaths = project.children.filter(
99
+ (child: any) => child.isClosed !== undefined,
100
+ )
101
+ const soldermaskShapes = shapePaths.filter((path: any) => path.cutIndex === 2)
102
+ expect(soldermaskShapes.length).toBeGreaterThan(0)
103
+
91
104
  const lbrnSvg = await generateLightBurnSvg(project)
92
105
 
93
106
  expect(stackSvgsVertically([pcbSvg, lbrnSvg])).toMatchSvgSnapshot(