circuit-json-to-lbrn 0.0.14 → 0.0.16

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 (29) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +218 -90
  3. package/lib/ConvertContext.ts +3 -0
  4. package/lib/element-handlers/addPcbVia/index.ts +84 -0
  5. package/lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts +3 -2
  6. package/lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts +13 -2
  7. package/lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts +3 -0
  8. package/lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts +4 -7
  9. package/lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts +13 -2
  10. package/lib/element-handlers/addPlatedHole/addPillPlatedHole.ts +4 -7
  11. package/lib/element-handlers/addPlatedHole/addRotatedPillHoleWithRectPad.ts +15 -2
  12. package/lib/element-handlers/addSmtPad/addCircleSmtPad.ts +3 -1
  13. package/lib/element-handlers/addSmtPad/addPillSmtPad.ts +7 -2
  14. package/lib/element-handlers/addSmtPad/addPolygonSmtPad.ts +6 -0
  15. package/lib/element-handlers/addSmtPad/addRectSmtPad.ts +9 -5
  16. package/lib/element-handlers/addSmtPad/addRotatedPillSmtPad.ts +13 -2
  17. package/lib/element-handlers/addSmtPad/addRotatedRectSmtPad.ts +15 -2
  18. package/lib/index.ts +7 -0
  19. package/package.json +1 -1
  20. package/tests/examples/addPcbVia/__snapshots__/pcb-via-basic.snap.svg +8 -0
  21. package/tests/examples/addPcbVia/__snapshots__/pcb-via-with-net.snap.svg +8 -0
  22. package/tests/examples/addPcbVia/__snapshots__/pcb-via-with-soldermask.snap.svg +8 -0
  23. package/tests/examples/addPcbVia/pcb-via-basic.test.ts +49 -0
  24. package/tests/examples/addPcbVia/pcb-via-with-net.test.ts +126 -0
  25. package/tests/examples/addPcbVia/pcb-via-with-soldermask.test.ts +53 -0
  26. package/tests/examples/soldermask-margin/__snapshots__/negative-soldermask-margin.snap.svg +8 -0
  27. package/tests/examples/soldermask-margin/__snapshots__/positive-soldermask-margin.snap.svg +8 -0
  28. package/tests/examples/soldermask-margin/negative-soldermask-margin.test.ts +85 -0
  29. package/tests/examples/soldermask-margin/positive-soldermask-margin.test.ts +85 -0
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ declare const convertCircuitJsonToLbrn: (circuitJson: CircuitJson, options?: {
10
10
  margin?: number;
11
11
  includeCopper?: boolean;
12
12
  includeSoldermask?: boolean;
13
+ soldermaskMargin?: number;
13
14
  }) => LightBurnProject;
14
15
 
15
16
  export { convertCircuitJsonToLbrn };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // lib/index.ts
2
- import { LightBurnProject, CutSetting, ShapePath as ShapePath15 } from "lbrnts";
2
+ import { LightBurnProject, CutSetting, ShapePath as ShapePath16 } from "lbrnts";
3
3
  import { cju as cju2 } from "@tscircuit/circuit-json-util";
4
4
 
5
5
  // lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts
@@ -52,7 +52,8 @@ var addCirclePlatedHole = (platedHole, ctx) => {
52
52
  origin,
53
53
  includeCopper,
54
54
  includeSoldermask,
55
- connMap
55
+ connMap,
56
+ soldermaskMargin
56
57
  } = ctx;
57
58
  const centerX = platedHole.x + origin.x;
58
59
  const centerY = platedHole.y + origin.y;
@@ -76,8 +77,8 @@ var addCirclePlatedHole = (platedHole, ctx) => {
76
77
  }
77
78
  }
78
79
  if (platedHole.outer_diameter > 0 && includeSoldermask) {
79
- const outerRadius = platedHole.outer_diameter / 2;
80
- const outer = createCirclePath(centerX, centerY, outerRadius);
80
+ const smRadius = platedHole.outer_diameter / 2 + soldermaskMargin;
81
+ const outer = createCirclePath(centerX, centerY, smRadius);
81
82
  project.children.push(
82
83
  new ShapePath({
83
84
  cutIndex: soldermaskCutSetting.index,
@@ -140,7 +141,8 @@ var addOvalPlatedHole = (platedHole, ctx) => {
140
141
  throughBoardCutSetting,
141
142
  origin,
142
143
  includeCopper,
143
- includeSoldermask
144
+ includeSoldermask,
145
+ soldermaskMargin
144
146
  } = ctx;
145
147
  if (platedHole.outer_width <= 0 || platedHole.outer_height <= 0) {
146
148
  return;
@@ -166,13 +168,9 @@ var addOvalPlatedHole = (platedHole, ctx) => {
166
168
  );
167
169
  }
168
170
  if (platedHole.outer_width > 0 && platedHole.outer_height > 0 && includeSoldermask) {
169
- const outer = createOvalPath(
170
- centerX,
171
- centerY,
172
- platedHole.outer_width,
173
- platedHole.outer_height,
174
- rotation
175
- );
171
+ const smWidth = platedHole.outer_width + 2 * soldermaskMargin;
172
+ const smHeight = platedHole.outer_height + 2 * soldermaskMargin;
173
+ const outer = createOvalPath(centerX, centerY, smWidth, smHeight, rotation);
176
174
  project.children.push(
177
175
  new ShapePath2({
178
176
  cutIndex: soldermaskCutSetting.index,
@@ -294,7 +292,8 @@ var addCircularHoleWithRectPad = (platedHole, ctx) => {
294
292
  throughBoardCutSetting,
295
293
  origin,
296
294
  includeCopper,
297
- includeSoldermask
295
+ includeSoldermask,
296
+ soldermaskMargin
298
297
  } = ctx;
299
298
  const centerX = platedHole.x + origin.x;
300
299
  const centerY = platedHole.y + origin.y;
@@ -320,11 +319,20 @@ var addCircularHoleWithRectPad = (platedHole, ctx) => {
320
319
  );
321
320
  }
322
321
  if (includeSoldermask) {
322
+ const smPadWidth = padWidth + 2 * soldermaskMargin;
323
+ const smPadHeight = padHeight + 2 * soldermaskMargin;
324
+ const smPadPath = createRoundedRectPath(
325
+ centerX,
326
+ centerY,
327
+ smPadWidth,
328
+ smPadHeight,
329
+ borderRadius
330
+ );
323
331
  project.children.push(
324
332
  new ShapePath3({
325
333
  cutIndex: soldermaskCutSetting.index,
326
- verts: padPath.verts,
327
- prims: padPath.prims,
334
+ verts: smPadPath.verts,
335
+ prims: smPadPath.prims,
328
336
  isClosed: true
329
337
  })
330
338
  );
@@ -435,7 +443,8 @@ var addPillHoleWithRectPad = (platedHole, ctx) => {
435
443
  throughBoardCutSetting,
436
444
  origin,
437
445
  includeCopper,
438
- includeSoldermask
446
+ includeSoldermask,
447
+ soldermaskMargin
439
448
  } = ctx;
440
449
  const centerX = platedHole.x + origin.x;
441
450
  const centerY = platedHole.y + origin.y;
@@ -461,11 +470,20 @@ var addPillHoleWithRectPad = (platedHole, ctx) => {
461
470
  );
462
471
  }
463
472
  if (includeSoldermask) {
473
+ const smPadWidth = padWidth + 2 * soldermaskMargin;
474
+ const smPadHeight = padHeight + 2 * soldermaskMargin;
475
+ const smPadPath = createRoundedRectPath(
476
+ centerX,
477
+ centerY,
478
+ smPadWidth,
479
+ smPadHeight,
480
+ borderRadius
481
+ );
464
482
  project.children.push(
465
483
  new ShapePath4({
466
484
  cutIndex: soldermaskCutSetting.index,
467
- verts: padPath.verts,
468
- prims: padPath.prims,
485
+ verts: smPadPath.verts,
486
+ prims: smPadPath.prims,
469
487
  isClosed: true
470
488
  })
471
489
  );
@@ -503,7 +521,8 @@ var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
503
521
  throughBoardCutSetting,
504
522
  origin,
505
523
  includeCopper,
506
- includeSoldermask
524
+ includeSoldermask,
525
+ soldermaskMargin
507
526
  } = ctx;
508
527
  const centerX = platedHole.x + origin.x;
509
528
  const centerY = platedHole.y + origin.y;
@@ -532,11 +551,22 @@ var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
532
551
  );
533
552
  }
534
553
  if (includeSoldermask) {
554
+ const smPadWidth = padWidth + 2 * soldermaskMargin;
555
+ const smPadHeight = padHeight + 2 * soldermaskMargin;
556
+ const smPadPath = createRoundedRectPath(
557
+ centerX,
558
+ centerY,
559
+ smPadWidth,
560
+ smPadHeight,
561
+ borderRadius,
562
+ 4,
563
+ padRotation
564
+ );
535
565
  project.children.push(
536
566
  new ShapePath5({
537
567
  cutIndex: soldermaskCutSetting.index,
538
- verts: padPath.verts,
539
- prims: padPath.prims,
568
+ verts: smPadPath.verts,
569
+ prims: smPadPath.prims,
540
570
  isClosed: true
541
571
  })
542
572
  );
@@ -572,9 +602,9 @@ import { ShapePath as ShapePath6 } from "lbrnts";
572
602
  // lib/helpers/polygonShape.ts
573
603
  var createPolygonPathFromOutline = (outline, offsetX, offsetY) => {
574
604
  const verts = [];
575
- for (const point5 of outline) {
576
- const x = (point5.x ?? 0) + offsetX;
577
- const y = (point5.y ?? 0) + offsetY;
605
+ for (const point6 of outline) {
606
+ const x = (point6.x ?? 0) + offsetX;
607
+ const y = (point6.y ?? 0) + offsetY;
578
608
  verts.push({ x, y });
579
609
  }
580
610
  if (verts.length === 0) {
@@ -595,7 +625,8 @@ var addHoleWithPolygonPad = (platedHole, ctx) => {
595
625
  throughBoardCutSetting,
596
626
  origin,
597
627
  includeCopper,
598
- includeSoldermask
628
+ includeSoldermask,
629
+ soldermaskMargin
599
630
  } = ctx;
600
631
  if (platedHole.pad_outline.length >= 3) {
601
632
  const pad = createPolygonPathFromOutline(
@@ -664,7 +695,8 @@ var addPcbPlatedHolePill = (platedHole, ctx) => {
664
695
  throughBoardCutSetting,
665
696
  origin,
666
697
  includeCopper,
667
- includeSoldermask
698
+ includeSoldermask,
699
+ soldermaskMargin
668
700
  } = ctx;
669
701
  const centerX = platedHole.x + origin.x;
670
702
  const centerY = platedHole.y + origin.y;
@@ -687,13 +719,9 @@ var addPcbPlatedHolePill = (platedHole, ctx) => {
687
719
  );
688
720
  }
689
721
  if (platedHole.outer_width > 0 && platedHole.outer_height > 0 && includeSoldermask) {
690
- const outer = createPillPath(
691
- centerX,
692
- centerY,
693
- platedHole.outer_width,
694
- platedHole.outer_height,
695
- rotation
696
- );
722
+ const smWidth = platedHole.outer_width + 2 * soldermaskMargin;
723
+ const smHeight = platedHole.outer_height + 2 * soldermaskMargin;
724
+ const outer = createPillPath(centerX, centerY, smWidth, smHeight, rotation);
697
725
  project.children.push(
698
726
  new ShapePath7({
699
727
  cutIndex: soldermaskCutSetting.index,
@@ -757,7 +785,8 @@ var addRectSmtPad = (smtPad, ctx) => {
757
785
  netGeoms,
758
786
  origin,
759
787
  includeCopper,
760
- includeSoldermask
788
+ includeSoldermask,
789
+ soldermaskMargin
761
790
  } = ctx;
762
791
  const centerX = smtPad.x + origin.x;
763
792
  const centerY = smtPad.y + origin.y;
@@ -801,12 +830,14 @@ var addRectSmtPad = (smtPad, ctx) => {
801
830
  }
802
831
  }
803
832
  if (includeSoldermask) {
833
+ const smHalfWidth = halfWidth + soldermaskMargin;
834
+ const smHalfHeight = halfHeight + soldermaskMargin;
804
835
  const verts = [
805
- { x: centerX - halfWidth, y: centerY - halfHeight },
806
- { x: centerX + halfWidth, y: centerY - halfHeight },
807
- { x: centerX + halfWidth, y: centerY + halfHeight },
808
- { x: centerX - halfWidth, y: centerY + halfHeight },
809
- { x: centerX - halfWidth, y: centerY - halfHeight }
836
+ { x: centerX - smHalfWidth, y: centerY - smHalfHeight },
837
+ { x: centerX + smHalfWidth, y: centerY - smHalfHeight },
838
+ { x: centerX + smHalfWidth, y: centerY + smHalfHeight },
839
+ { x: centerX - smHalfWidth, y: centerY + smHalfHeight },
840
+ { x: centerX - smHalfWidth, y: centerY - smHalfHeight }
810
841
  // Close the path
811
842
  ];
812
843
  const prims = [
@@ -838,7 +869,8 @@ var addCircleSmtPad = (smtPad, ctx) => {
838
869
  origin,
839
870
  includeCopper,
840
871
  includeSoldermask,
841
- connMap
872
+ connMap,
873
+ soldermaskMargin
842
874
  } = ctx;
843
875
  const centerX = smtPad.x + origin.x;
844
876
  const centerY = smtPad.y + origin.y;
@@ -863,7 +895,8 @@ var addCircleSmtPad = (smtPad, ctx) => {
863
895
  }
864
896
  }
865
897
  if (includeSoldermask) {
866
- const outer = createCirclePath(centerX, centerY, outerRadius);
898
+ const smRadius = outerRadius + soldermaskMargin;
899
+ const outer = createCirclePath(centerX, centerY, smRadius);
867
900
  project.children.push(
868
901
  new ShapePath9({
869
902
  cutIndex: soldermaskCutSetting.index,
@@ -895,7 +928,8 @@ var addPillSmtPad = (smtPad, ctx) => {
895
928
  origin,
896
929
  includeCopper,
897
930
  includeSoldermask,
898
- connMap
931
+ connMap,
932
+ soldermaskMargin
899
933
  } = ctx;
900
934
  const centerX = smtPad.x + origin.x;
901
935
  const centerY = smtPad.y + origin.y;
@@ -918,11 +952,14 @@ var addPillSmtPad = (smtPad, ctx) => {
918
952
  }
919
953
  }
920
954
  if (includeSoldermask) {
955
+ const smWidth = smtPad.width + 2 * soldermaskMargin;
956
+ const smHeight = smtPad.height + 2 * soldermaskMargin;
957
+ const smOuter = createPillPath(centerX, centerY, smWidth, smHeight);
921
958
  project.children.push(
922
959
  new ShapePath10({
923
960
  cutIndex: soldermaskCutSetting.index,
924
- verts: outer.verts,
925
- prims: outer.prims,
961
+ verts: smOuter.verts,
962
+ prims: smOuter.prims,
926
963
  isClosed: true
927
964
  })
928
965
  );
@@ -940,7 +977,8 @@ var addRotatedPillSmtPad = (smtPad, ctx) => {
940
977
  origin,
941
978
  includeCopper,
942
979
  includeSoldermask,
943
- connMap
980
+ connMap,
981
+ soldermaskMargin
944
982
  } = ctx;
945
983
  const centerX = smtPad.x + origin.x;
946
984
  const centerY = smtPad.y + origin.y;
@@ -969,11 +1007,20 @@ var addRotatedPillSmtPad = (smtPad, ctx) => {
969
1007
  }
970
1008
  }
971
1009
  if (includeSoldermask) {
1010
+ const smWidth = smtPad.width + 2 * soldermaskMargin;
1011
+ const smHeight = smtPad.height + 2 * soldermaskMargin;
1012
+ const smOuter = createPillPath(
1013
+ centerX,
1014
+ centerY,
1015
+ smWidth,
1016
+ smHeight,
1017
+ (smtPad.ccw_rotation ?? 0) * (Math.PI / 180)
1018
+ );
972
1019
  project.children.push(
973
1020
  new ShapePath11({
974
1021
  cutIndex: soldermaskCutSetting.index,
975
- verts: outer.verts,
976
- prims: outer.prims,
1022
+ verts: smOuter.verts,
1023
+ prims: smOuter.prims,
977
1024
  isClosed: true
978
1025
  })
979
1026
  );
@@ -983,6 +1030,35 @@ var addRotatedPillSmtPad = (smtPad, ctx) => {
983
1030
 
984
1031
  // lib/element-handlers/addSmtPad/addPolygonSmtPad.ts
985
1032
  import { ShapePath as ShapePath12 } from "lbrnts";
1033
+
1034
+ // lib/polygon-to-shape-path.ts
1035
+ function polygonToShapePathData(polygon) {
1036
+ const verts = [];
1037
+ const prims = [];
1038
+ const svgString = polygon.svg();
1039
+ const dAttributeMatch = svgString.match(/\bd="([^"]+)"/);
1040
+ if (!dAttributeMatch || !dAttributeMatch[1]) {
1041
+ return { verts, prims };
1042
+ }
1043
+ const pathData = dAttributeMatch[1].trim();
1044
+ const commands = pathData.match(/[MLz][^MLz]*/g) || [];
1045
+ for (const command of commands) {
1046
+ const type = command[0];
1047
+ const coords = command.slice(1).trim();
1048
+ if (type === "M" || type === "L") {
1049
+ const parts = coords.split(",");
1050
+ const x = Number(parts[0]);
1051
+ const y = Number(parts[1]);
1052
+ if (!Number.isNaN(x) && !Number.isNaN(y)) {
1053
+ verts.push({ x, y });
1054
+ prims.push({ type: 0 });
1055
+ }
1056
+ }
1057
+ }
1058
+ return { verts, prims };
1059
+ }
1060
+
1061
+ // lib/element-handlers/addSmtPad/addPolygonSmtPad.ts
986
1062
  var addPolygonSmtPad = (smtPad, ctx) => {
987
1063
  const {
988
1064
  project,
@@ -991,7 +1067,8 @@ var addPolygonSmtPad = (smtPad, ctx) => {
991
1067
  origin,
992
1068
  includeCopper,
993
1069
  includeSoldermask,
994
- connMap
1070
+ connMap,
1071
+ soldermaskMargin
995
1072
  } = ctx;
996
1073
  if (smtPad.points.length >= 3) {
997
1074
  const pad = createPolygonPathFromOutline(smtPad.points, origin.x, origin.y);
@@ -1034,7 +1111,8 @@ var addRotatedRectSmtPad = (smtPad, ctx) => {
1034
1111
  origin,
1035
1112
  includeCopper,
1036
1113
  includeSoldermask,
1037
- connMap
1114
+ connMap,
1115
+ soldermaskMargin
1038
1116
  } = ctx;
1039
1117
  const centerX = smtPad.x + origin.x;
1040
1118
  const centerY = smtPad.y + origin.y;
@@ -1067,11 +1145,22 @@ var addRotatedRectSmtPad = (smtPad, ctx) => {
1067
1145
  }
1068
1146
  }
1069
1147
  if (includeSoldermask) {
1148
+ const smWidth = smtPad.width + 2 * soldermaskMargin;
1149
+ const smHeight = smtPad.height + 2 * soldermaskMargin;
1150
+ const smOuter = createRoundedRectPath(
1151
+ centerX,
1152
+ centerY,
1153
+ smWidth,
1154
+ smHeight,
1155
+ borderRadius,
1156
+ 4,
1157
+ rotation
1158
+ );
1070
1159
  project.children.push(
1071
1160
  new ShapePath13({
1072
1161
  cutIndex: soldermaskCutSetting.index,
1073
- verts: outer.verts,
1074
- prims: outer.prims,
1162
+ verts: smOuter.verts,
1163
+ prims: smOuter.prims,
1075
1164
  isClosed: true
1076
1165
  })
1077
1166
  );
@@ -1118,7 +1207,7 @@ var addPcbTrace = (trace, ctx) => {
1118
1207
  return;
1119
1208
  }
1120
1209
  const { route } = trace;
1121
- const traceWidth = route.find((point5) => point5.route_type === "wire")?.width ?? 0.15;
1210
+ const traceWidth = route.find((point6) => point6.route_type === "wire")?.width ?? 0.15;
1122
1211
  const polygons = [];
1123
1212
  for (const routePoint of route) {
1124
1213
  const circle = new Flatten2.Circle(
@@ -1169,35 +1258,6 @@ var addPcbTrace = (trace, ctx) => {
1169
1258
  // lib/element-handlers/addPcbBoard/index.ts
1170
1259
  import { Polygon as Polygon3, point as point4 } from "@flatten-js/core";
1171
1260
  import { ShapePath as ShapePath14 } from "lbrnts";
1172
-
1173
- // lib/polygon-to-shape-path.ts
1174
- function polygonToShapePathData(polygon) {
1175
- const verts = [];
1176
- const prims = [];
1177
- const svgString = polygon.svg();
1178
- const dAttributeMatch = svgString.match(/\bd="([^"]+)"/);
1179
- if (!dAttributeMatch || !dAttributeMatch[1]) {
1180
- return { verts, prims };
1181
- }
1182
- const pathData = dAttributeMatch[1].trim();
1183
- const commands = pathData.match(/[MLz][^MLz]*/g) || [];
1184
- for (const command of commands) {
1185
- const type = command[0];
1186
- const coords = command.slice(1).trim();
1187
- if (type === "M" || type === "L") {
1188
- const parts = coords.split(",");
1189
- const x = Number(parts[0]);
1190
- const y = Number(parts[1]);
1191
- if (!Number.isNaN(x) && !Number.isNaN(y)) {
1192
- verts.push({ x, y });
1193
- prims.push({ type: 0 });
1194
- }
1195
- }
1196
- }
1197
- return { verts, prims };
1198
- }
1199
-
1200
- // lib/element-handlers/addPcbBoard/index.ts
1201
1261
  var addPcbBoard = (board, ctx) => {
1202
1262
  const {
1203
1263
  origin,
@@ -1281,14 +1341,14 @@ var calculateCircuitBounds = (circuitJson) => {
1281
1341
  }
1282
1342
  }
1283
1343
  for (const trace of db.pcb_trace.list()) {
1284
- const isWidthPoint = (point5) => "width" in point5 && typeof point5.width === "number";
1344
+ const isWidthPoint = (point6) => "width" in point6 && typeof point6.width === "number";
1285
1345
  const halfWidth = trace.route_thickness_mode === "interpolated" ? 0 : (trace.route.find(isWidthPoint)?.width ?? 0) / 2;
1286
- for (const point5 of trace.route) {
1287
- const pointWidth = trace.route_thickness_mode === "interpolated" ? isWidthPoint(point5) ? point5.width / 2 : 0 : halfWidth;
1288
- minX = Math.min(minX, point5.x - pointWidth);
1289
- minY = Math.min(minY, point5.y - pointWidth);
1290
- maxX = Math.max(maxX, point5.x + pointWidth);
1291
- maxY = Math.max(maxY, point5.y + pointWidth);
1346
+ for (const point6 of trace.route) {
1347
+ const pointWidth = trace.route_thickness_mode === "interpolated" ? isWidthPoint(point6) ? point6.width / 2 : 0 : halfWidth;
1348
+ minX = Math.min(minX, point6.x - pointWidth);
1349
+ minY = Math.min(minY, point6.y - pointWidth);
1350
+ maxX = Math.max(maxX, point6.x + pointWidth);
1351
+ maxY = Math.max(maxY, point6.y + pointWidth);
1292
1352
  }
1293
1353
  }
1294
1354
  for (const hole of db.pcb_plated_hole.list()) {
@@ -1312,6 +1372,70 @@ var calculateOriginFromBounds = (bounds, margin) => {
1312
1372
  return { x: originX, y: originY };
1313
1373
  };
1314
1374
 
1375
+ // lib/element-handlers/addPcbVia/index.ts
1376
+ import { ShapePath as ShapePath15 } from "lbrnts";
1377
+ import { Circle as Circle3, point as point5 } from "@flatten-js/core";
1378
+ var addPcbVia = (via, ctx) => {
1379
+ const {
1380
+ db,
1381
+ project,
1382
+ copperCutSetting,
1383
+ soldermaskCutSetting,
1384
+ throughBoardCutSetting,
1385
+ origin,
1386
+ includeCopper,
1387
+ includeSoldermask,
1388
+ connMap,
1389
+ soldermaskMargin
1390
+ } = ctx;
1391
+ const centerX = via.x + origin.x;
1392
+ const centerY = via.y + origin.y;
1393
+ if (via.outer_diameter > 0 && includeCopper) {
1394
+ const viaPort = db.pcb_port.list().find((port) => port.x === via.x && port.y === via.y);
1395
+ const netId = viaPort ? connMap.getNetConnectedToId(viaPort.pcb_port_id) : void 0;
1396
+ const outerRadius = via.outer_diameter / 2;
1397
+ const circle = new Circle3(point5(centerX, centerY), outerRadius);
1398
+ const polygon = circleToPolygon(circle);
1399
+ if (netId) {
1400
+ ctx.netGeoms.get(netId)?.push(polygon);
1401
+ } else {
1402
+ const outer = createCirclePath(centerX, centerY, outerRadius);
1403
+ project.children.push(
1404
+ new ShapePath15({
1405
+ cutIndex: copperCutSetting.index,
1406
+ verts: outer.verts,
1407
+ prims: outer.prims,
1408
+ isClosed: true
1409
+ })
1410
+ );
1411
+ }
1412
+ }
1413
+ if (via.outer_diameter > 0 && includeSoldermask) {
1414
+ const smRadius = via.outer_diameter / 2 + soldermaskMargin;
1415
+ const outer = createCirclePath(centerX, centerY, smRadius);
1416
+ project.children.push(
1417
+ new ShapePath15({
1418
+ cutIndex: soldermaskCutSetting.index,
1419
+ verts: outer.verts,
1420
+ prims: outer.prims,
1421
+ isClosed: true
1422
+ })
1423
+ );
1424
+ }
1425
+ if (via.hole_diameter > 0) {
1426
+ const innerRadius = via.hole_diameter / 2;
1427
+ const inner = createCirclePath(centerX, centerY, innerRadius);
1428
+ project.children.push(
1429
+ new ShapePath15({
1430
+ cutIndex: throughBoardCutSetting.index,
1431
+ verts: inner.verts,
1432
+ prims: inner.prims,
1433
+ isClosed: true
1434
+ })
1435
+ );
1436
+ }
1437
+ };
1438
+
1315
1439
  // lib/index.ts
1316
1440
  var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1317
1441
  const db = cju2(circuitJson);
@@ -1365,7 +1489,8 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1365
1489
  netGeoms: /* @__PURE__ */ new Map(),
1366
1490
  origin,
1367
1491
  includeCopper: options.includeCopper ?? true,
1368
- includeSoldermask: options.includeSoldermask ?? false
1492
+ includeSoldermask: options.includeSoldermask ?? false,
1493
+ soldermaskMargin: options.soldermaskMargin ?? 0
1369
1494
  };
1370
1495
  for (const net of Object.keys(connMap.netMap)) {
1371
1496
  ctx.netGeoms.set(net, []);
@@ -1382,6 +1507,9 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1382
1507
  for (const board of db.pcb_board.list()) {
1383
1508
  addPcbBoard(board, ctx);
1384
1509
  }
1510
+ for (const via of db.pcb_via.list()) {
1511
+ addPcbVia(via, ctx);
1512
+ }
1385
1513
  if (ctx.includeCopper) {
1386
1514
  for (const net of Object.keys(connMap.netMap)) {
1387
1515
  const netGeoms = ctx.netGeoms.get(net);
@@ -1402,7 +1530,7 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1402
1530
  for (const island of union.splitToIslands()) {
1403
1531
  const { verts, prims } = polygonToShapePathData(island);
1404
1532
  project.children.push(
1405
- new ShapePath15({
1533
+ new ShapePath16({
1406
1534
  cutIndex: copperCutSetting.index,
1407
1535
  verts,
1408
1536
  prims,
@@ -22,4 +22,7 @@ export interface ConvertContext {
22
22
  // Include flags
23
23
  includeCopper: boolean
24
24
  includeSoldermask: boolean
25
+
26
+ // Soldermask margin (can be negative)
27
+ soldermaskMargin: number
25
28
  }
@@ -0,0 +1,84 @@
1
+ import type { PcbVia } from "circuit-json"
2
+ import type { ConvertContext } from "../../ConvertContext"
3
+ import { ShapePath } from "lbrnts"
4
+ import { createCirclePath } from "../../helpers/circleShape"
5
+ import { Circle, point } from "@flatten-js/core"
6
+ import { circleToPolygon } from "../addPcbTrace/circle-to-polygon"
7
+
8
+ export const addPcbVia = (via: PcbVia, ctx: ConvertContext): void => {
9
+ const {
10
+ db,
11
+ project,
12
+ copperCutSetting,
13
+ soldermaskCutSetting,
14
+ throughBoardCutSetting,
15
+ origin,
16
+ includeCopper,
17
+ includeSoldermask,
18
+ connMap,
19
+ soldermaskMargin,
20
+ } = ctx
21
+ const centerX = via.x + origin.x
22
+ const centerY = via.y + origin.y
23
+
24
+ // Add outer circle (copper annulus) if drawing copper - add to netGeoms for merging
25
+ if (via.outer_diameter > 0 && includeCopper) {
26
+ // Find the pcb_port associated with this via (vias don't have pcb_port_id property)
27
+ // We need to find a port at the same location as the via
28
+ const viaPort = db.pcb_port
29
+ .list()
30
+ .find((port) => port.x === via.x && port.y === via.y)
31
+
32
+ const netId = viaPort
33
+ ? connMap.getNetConnectedToId(viaPort.pcb_port_id)
34
+ : undefined
35
+
36
+ const outerRadius = via.outer_diameter / 2
37
+ const circle = new Circle(point(centerX, centerY), outerRadius)
38
+ const polygon = circleToPolygon(circle)
39
+
40
+ if (netId) {
41
+ // Add to netGeoms to be merged with other elements on the same net
42
+ ctx.netGeoms.get(netId)?.push(polygon)
43
+ } else {
44
+ // No net connection - draw directly
45
+ const outer = createCirclePath(centerX, centerY, outerRadius)
46
+ project.children.push(
47
+ new ShapePath({
48
+ cutIndex: copperCutSetting.index,
49
+ verts: outer.verts,
50
+ prims: outer.prims,
51
+ isClosed: true,
52
+ }),
53
+ )
54
+ }
55
+ }
56
+
57
+ // Add soldermask opening if drawing soldermask
58
+ if (via.outer_diameter > 0 && includeSoldermask) {
59
+ const smRadius = via.outer_diameter / 2 + soldermaskMargin
60
+ const outer = createCirclePath(centerX, centerY, smRadius)
61
+ project.children.push(
62
+ new ShapePath({
63
+ cutIndex: soldermaskCutSetting.index,
64
+ verts: outer.verts,
65
+ prims: outer.prims,
66
+ isClosed: true,
67
+ }),
68
+ )
69
+ }
70
+
71
+ // Add inner circle (hole) - always cut through the board regardless of mode
72
+ if (via.hole_diameter > 0) {
73
+ const innerRadius = via.hole_diameter / 2
74
+ const inner = createCirclePath(centerX, centerY, innerRadius)
75
+ project.children.push(
76
+ new ShapePath({
77
+ cutIndex: throughBoardCutSetting.index,
78
+ verts: inner.verts,
79
+ prims: inner.prims,
80
+ isClosed: true,
81
+ }),
82
+ )
83
+ }
84
+ }
@@ -18,6 +18,7 @@ export const addCirclePlatedHole = (
18
18
  includeCopper,
19
19
  includeSoldermask,
20
20
  connMap,
21
+ soldermaskMargin,
21
22
  } = ctx
22
23
  const centerX = platedHole.x + origin.x
23
24
  const centerY = platedHole.y + origin.y
@@ -48,8 +49,8 @@ export const addCirclePlatedHole = (
48
49
 
49
50
  // Add soldermask opening if drawing soldermask
50
51
  if (platedHole.outer_diameter > 0 && includeSoldermask) {
51
- const outerRadius = platedHole.outer_diameter / 2
52
- const outer = createCirclePath(centerX, centerY, outerRadius)
52
+ const smRadius = platedHole.outer_diameter / 2 + soldermaskMargin
53
+ const outer = createCirclePath(centerX, centerY, smRadius)
53
54
  project.children.push(
54
55
  new ShapePath({
55
56
  cutIndex: soldermaskCutSetting.index,