circuit-json-to-lbrn 0.0.17 → 0.0.19

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 (32) hide show
  1. package/dist/index.js +246 -22
  2. package/lib/element-handlers/addPcbCutout/addCirclePcbCutout.ts +52 -0
  3. package/lib/element-handlers/addPcbCutout/addPathPcbCutout.ts +73 -0
  4. package/lib/element-handlers/addPcbCutout/addPolygonPcbCutout.ts +68 -0
  5. package/lib/element-handlers/addPcbCutout/addRectPcbCutout.ts +71 -0
  6. package/lib/element-handlers/addPcbCutout/index.ts +31 -0
  7. package/lib/element-handlers/addPcbHole/addCirclePcbHole.ts +2 -1
  8. package/lib/element-handlers/addPcbHole/addOvalPcbHole.ts +2 -1
  9. package/lib/element-handlers/addPcbHole/addPillPcbHole.ts +2 -1
  10. package/lib/element-handlers/addPcbHole/addRectPcbHole.ts +2 -1
  11. package/lib/element-handlers/addPcbHole/addRotatedPillPcbHole.ts +2 -1
  12. package/lib/element-handlers/addPcbVia/index.ts +1 -1
  13. package/lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts +1 -2
  14. package/lib/element-handlers/addPlatedHole/addCircularHoleWithRectPad.ts +1 -1
  15. package/lib/element-handlers/addPlatedHole/addHoleWithPolygonPad.ts +11 -3
  16. package/lib/element-handlers/addPlatedHole/addOvalPlatedHole.ts +6 -2
  17. package/lib/element-handlers/addPlatedHole/addPillHoleWithRectPad.ts +1 -1
  18. package/lib/element-handlers/addPlatedHole/addPillPlatedHole.ts +5 -1
  19. package/lib/element-handlers/addPlatedHole/addRotatedPillHoleWithRectPad.ts +1 -1
  20. package/lib/index.ts +5 -0
  21. package/package.json +1 -1
  22. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-circle.snap.svg +8 -0
  23. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-path.snap.svg +8 -0
  24. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-polygon.snap.svg +8 -0
  25. package/tests/examples/addPcbCutout/__snapshots__/pcb-cutout-rect.snap.svg +8 -0
  26. package/tests/examples/addPcbCutout/pcb-cutout-circle.test.ts +49 -0
  27. package/tests/examples/addPcbCutout/pcb-cutout-path.test.ts +44 -0
  28. package/tests/examples/addPcbCutout/pcb-cutout-polygon.test.ts +54 -0
  29. package/tests/examples/addPcbCutout/pcb-cutout-rect.test.ts +48 -0
  30. package/tests/examples/addPcbVia/__snapshots__/pcb-via-with-soldermask.snap.svg +1 -1
  31. package/tests/examples/soldermask/__snapshots__/soldermask-only.snap.svg +3 -3
  32. package/tests/examples/soldermask/soldermask-only.test.ts +10 -0
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // lib/index.ts
2
- import { LightBurnProject, CutSetting, ShapePath as ShapePath21 } from "lbrnts";
2
+ import { LightBurnProject, CutSetting, ShapePath as ShapePath25 } from "lbrnts";
3
3
  import { cju as cju2 } from "@tscircuit/circuit-json-util";
4
4
 
5
5
  // lib/element-handlers/addPlatedHole/addCirclePlatedHole.ts
@@ -88,7 +88,7 @@ var addCirclePlatedHole = (platedHole, ctx) => {
88
88
  })
89
89
  );
90
90
  }
91
- if (platedHole.hole_diameter > 0) {
91
+ if (platedHole.hole_diameter > 0 && includeCopper) {
92
92
  const innerRadius = platedHole.hole_diameter / 2;
93
93
  const inner = createCirclePath(centerX, centerY, innerRadius);
94
94
  project.children.push(
@@ -180,7 +180,7 @@ var addOvalPlatedHole = (platedHole, ctx) => {
180
180
  })
181
181
  );
182
182
  }
183
- if (platedHole.hole_width > 0 && platedHole.hole_height > 0) {
183
+ if (platedHole.hole_width > 0 && platedHole.hole_height > 0 && includeCopper) {
184
184
  const inner = createOvalPath(
185
185
  centerX,
186
186
  centerY,
@@ -337,7 +337,7 @@ var addCircularHoleWithRectPad = (platedHole, ctx) => {
337
337
  })
338
338
  );
339
339
  }
340
- if (holeRadius > 0) {
340
+ if (holeRadius > 0 && includeCopper) {
341
341
  const holeCenterX = centerX + platedHole.hole_offset_x;
342
342
  const holeCenterY = centerY + platedHole.hole_offset_y;
343
343
  const holePath = createCirclePath(holeCenterX, holeCenterY, holeRadius, 32);
@@ -491,7 +491,7 @@ var addPillHoleWithRectPad = (platedHole, ctx) => {
491
491
  }
492
492
  const holeWidth = platedHole.hole_width;
493
493
  const holeHeight = platedHole.hole_height;
494
- if (holeWidth > 0 && holeHeight > 0) {
494
+ if (holeWidth > 0 && holeHeight > 0 && includeCopper) {
495
495
  const holeCenterX = centerX + platedHole.hole_offset_x;
496
496
  const holeCenterY = centerY + platedHole.hole_offset_y;
497
497
  const holePath = createPillPath(
@@ -575,7 +575,7 @@ var addRotatedPillHoleWithRectPad = (platedHole, ctx) => {
575
575
  const holeWidth = platedHole.hole_width;
576
576
  const holeHeight = platedHole.hole_height;
577
577
  const holeRotation = (platedHole.hole_ccw_rotation ?? 0) * (Math.PI / 180);
578
- if (holeWidth > 0 && holeHeight > 0) {
578
+ if (holeWidth > 0 && holeHeight > 0 && includeCopper) {
579
579
  const holeCenterX = centerX + platedHole.hole_offset_x;
580
580
  const holeCenterY = centerY + platedHole.hole_offset_y;
581
581
  const holePath = createPillPath(
@@ -628,7 +628,7 @@ var addHoleWithPolygonPad = (platedHole, ctx) => {
628
628
  includeSoldermask,
629
629
  soldermaskMargin
630
630
  } = ctx;
631
- if (platedHole.pad_outline.length >= 3) {
631
+ if (platedHole.pad_outline.length >= 3 && includeCopper) {
632
632
  const pad = createPolygonPathFromOutline(
633
633
  platedHole.pad_outline,
634
634
  platedHole.x + origin.x,
@@ -655,7 +655,7 @@ var addHoleWithPolygonPad = (platedHole, ctx) => {
655
655
  );
656
656
  }
657
657
  }
658
- if (platedHole.hole_shape === "circle" && platedHole.hole_diameter) {
658
+ if (platedHole.hole_shape === "circle" && platedHole.hole_diameter && includeCopper) {
659
659
  const centerX = platedHole.x + platedHole.hole_offset_x + origin.x;
660
660
  const centerY = platedHole.y + platedHole.hole_offset_y + origin.y;
661
661
  const radius = platedHole.hole_diameter / 2;
@@ -669,7 +669,7 @@ var addHoleWithPolygonPad = (platedHole, ctx) => {
669
669
  })
670
670
  );
671
671
  }
672
- if (platedHole.hole_shape === "pill" && platedHole.hole_diameter) {
672
+ if (platedHole.hole_shape === "pill" && platedHole.hole_diameter && includeCopper) {
673
673
  const centerX = platedHole.x + platedHole.hole_offset_x + origin.x;
674
674
  const centerY = platedHole.y + platedHole.hole_offset_y + origin.y;
675
675
  const radius = platedHole.hole_diameter / 2;
@@ -731,7 +731,7 @@ var addPcbPlatedHolePill = (platedHole, ctx) => {
731
731
  })
732
732
  );
733
733
  }
734
- if (platedHole.hole_width > 0 && platedHole.hole_height > 0) {
734
+ if (platedHole.hole_width > 0 && platedHole.hole_height > 0 && includeCopper) {
735
735
  const inner = createPillPath(
736
736
  centerX,
737
737
  centerY,
@@ -1422,7 +1422,7 @@ var addPcbVia = (via, ctx) => {
1422
1422
  })
1423
1423
  );
1424
1424
  }
1425
- if (via.hole_diameter > 0) {
1425
+ if (via.hole_diameter > 0 && includeCopper) {
1426
1426
  const innerRadius = via.hole_diameter / 2;
1427
1427
  const inner = createCirclePath(centerX, centerY, innerRadius);
1428
1428
  project.children.push(
@@ -1445,7 +1445,8 @@ var addCirclePcbHole = (hole, ctx) => {
1445
1445
  soldermaskCutSetting,
1446
1446
  origin,
1447
1447
  includeSoldermask,
1448
- soldermaskMargin
1448
+ soldermaskMargin,
1449
+ includeCopper
1449
1450
  } = ctx;
1450
1451
  const centerX = hole.x + origin.x;
1451
1452
  const centerY = hole.y + origin.y;
@@ -1461,7 +1462,7 @@ var addCirclePcbHole = (hole, ctx) => {
1461
1462
  })
1462
1463
  );
1463
1464
  }
1464
- if (hole.hole_diameter > 0) {
1465
+ if (hole.hole_diameter > 0 && includeCopper) {
1465
1466
  const radius = hole.hole_diameter / 2;
1466
1467
  const circlePath = createCirclePath(centerX, centerY, radius);
1467
1468
  project.children.push(
@@ -1484,7 +1485,8 @@ var addRectPcbHole = (hole, ctx) => {
1484
1485
  soldermaskCutSetting,
1485
1486
  origin,
1486
1487
  includeSoldermask,
1487
- soldermaskMargin
1488
+ soldermaskMargin,
1489
+ includeCopper
1488
1490
  } = ctx;
1489
1491
  const centerX = hole.x + origin.x;
1490
1492
  const centerY = hole.y + origin.y;
@@ -1506,7 +1508,7 @@ var addRectPcbHole = (hole, ctx) => {
1506
1508
  })
1507
1509
  );
1508
1510
  }
1509
- if (hole.hole_width > 0 && hole.hole_height > 0) {
1511
+ if (hole.hole_width > 0 && hole.hole_height > 0 && includeCopper) {
1510
1512
  const rectPath = createRoundedRectPath(
1511
1513
  centerX,
1512
1514
  centerY,
@@ -1535,7 +1537,8 @@ var addOvalPcbHole = (hole, ctx) => {
1535
1537
  soldermaskCutSetting,
1536
1538
  origin,
1537
1539
  includeSoldermask,
1538
- soldermaskMargin
1540
+ soldermaskMargin,
1541
+ includeCopper
1539
1542
  } = ctx;
1540
1543
  const centerX = hole.x + origin.x;
1541
1544
  const centerY = hole.y + origin.y;
@@ -1555,7 +1558,7 @@ var addOvalPcbHole = (hole, ctx) => {
1555
1558
  })
1556
1559
  );
1557
1560
  }
1558
- if (hole.hole_width > 0 && hole.hole_height > 0) {
1561
+ if (hole.hole_width > 0 && hole.hole_height > 0 && includeCopper) {
1559
1562
  const ovalPath = createOvalPath(
1560
1563
  centerX,
1561
1564
  centerY,
@@ -1582,7 +1585,8 @@ var addPillPcbHole = (hole, ctx) => {
1582
1585
  soldermaskCutSetting,
1583
1586
  origin,
1584
1587
  includeSoldermask,
1585
- soldermaskMargin
1588
+ soldermaskMargin,
1589
+ includeCopper
1586
1590
  } = ctx;
1587
1591
  const centerX = hole.x + origin.x;
1588
1592
  const centerY = hole.y + origin.y;
@@ -1602,7 +1606,7 @@ var addPillPcbHole = (hole, ctx) => {
1602
1606
  })
1603
1607
  );
1604
1608
  }
1605
- if (hole.hole_width > 0 && hole.hole_height > 0) {
1609
+ if (hole.hole_width > 0 && hole.hole_height > 0 && includeCopper) {
1606
1610
  const pillPath = createPillPath(
1607
1611
  centerX,
1608
1612
  centerY,
@@ -1629,7 +1633,8 @@ var addRotatedPillPcbHole = (hole, ctx) => {
1629
1633
  soldermaskCutSetting,
1630
1634
  origin,
1631
1635
  includeSoldermask,
1632
- soldermaskMargin
1636
+ soldermaskMargin,
1637
+ includeCopper
1633
1638
  } = ctx;
1634
1639
  const centerX = hole.x + origin.x;
1635
1640
  const centerY = hole.y + origin.y;
@@ -1651,7 +1656,7 @@ var addRotatedPillPcbHole = (hole, ctx) => {
1651
1656
  })
1652
1657
  );
1653
1658
  }
1654
- if (hole.hole_width > 0 && hole.hole_height > 0) {
1659
+ if (hole.hole_width > 0 && hole.hole_height > 0 && includeCopper) {
1655
1660
  const pillPath = createPillPath(
1656
1661
  centerX,
1657
1662
  centerY,
@@ -1690,6 +1695,222 @@ var addPcbHole = (hole, ctx) => {
1690
1695
  }
1691
1696
  };
1692
1697
 
1698
+ // lib/element-handlers/addPcbCutout/addCirclePcbCutout.ts
1699
+ import { ShapePath as ShapePath21 } from "lbrnts";
1700
+ var addCirclePcbCutout = (cutout, ctx) => {
1701
+ const {
1702
+ project,
1703
+ throughBoardCutSetting,
1704
+ origin,
1705
+ includeCopper,
1706
+ includeSoldermask,
1707
+ soldermaskMargin,
1708
+ soldermaskCutSetting
1709
+ } = ctx;
1710
+ const centerX = cutout.center.x + origin.x;
1711
+ const centerY = cutout.center.y + origin.y;
1712
+ if (cutout.radius > 0 && includeCopper) {
1713
+ const circlePath = createCirclePath(centerX, centerY, cutout.radius);
1714
+ project.children.push(
1715
+ new ShapePath21({
1716
+ cutIndex: throughBoardCutSetting.index,
1717
+ verts: circlePath.verts,
1718
+ prims: circlePath.prims,
1719
+ isClosed: true
1720
+ })
1721
+ );
1722
+ }
1723
+ if (cutout.radius > 0 && includeSoldermask) {
1724
+ const smRadius = cutout.radius + soldermaskMargin;
1725
+ const outer = createCirclePath(centerX, centerY, smRadius);
1726
+ project.children.push(
1727
+ new ShapePath21({
1728
+ cutIndex: soldermaskCutSetting.index,
1729
+ verts: outer.verts,
1730
+ prims: outer.prims,
1731
+ isClosed: true
1732
+ })
1733
+ );
1734
+ }
1735
+ };
1736
+
1737
+ // lib/element-handlers/addPcbCutout/addRectPcbCutout.ts
1738
+ import { ShapePath as ShapePath22 } from "lbrnts";
1739
+ var addRectPcbCutout = (cutout, ctx) => {
1740
+ const {
1741
+ project,
1742
+ throughBoardCutSetting,
1743
+ origin,
1744
+ includeCopper,
1745
+ includeSoldermask,
1746
+ soldermaskMargin,
1747
+ soldermaskCutSetting
1748
+ } = ctx;
1749
+ const centerX = cutout.center.x + origin.x;
1750
+ const centerY = cutout.center.y + origin.y;
1751
+ if (cutout.width > 0 && cutout.height > 0 && includeCopper) {
1752
+ const rotation = (cutout.rotation ?? 0) * (Math.PI / 180);
1753
+ const rectPath = createRoundedRectPath(
1754
+ centerX,
1755
+ centerY,
1756
+ cutout.width,
1757
+ cutout.height,
1758
+ 0,
1759
+ // no border radius for cutouts
1760
+ 4,
1761
+ // segments
1762
+ rotation
1763
+ );
1764
+ project.children.push(
1765
+ new ShapePath22({
1766
+ cutIndex: throughBoardCutSetting.index,
1767
+ verts: rectPath.verts,
1768
+ prims: rectPath.prims,
1769
+ isClosed: true
1770
+ })
1771
+ );
1772
+ }
1773
+ if (cutout.width > 0 && cutout.height > 0 && includeSoldermask) {
1774
+ const rotation = (cutout.rotation ?? 0) * (Math.PI / 180);
1775
+ const smWidth = cutout.width + 2 * soldermaskMargin;
1776
+ const smHeight = cutout.height + 2 * soldermaskMargin;
1777
+ const rectPath = createRoundedRectPath(
1778
+ centerX,
1779
+ centerY,
1780
+ smWidth,
1781
+ smHeight,
1782
+ 0,
1783
+ // no border radius for cutouts
1784
+ 4,
1785
+ // segments
1786
+ rotation
1787
+ );
1788
+ project.children.push(
1789
+ new ShapePath22({
1790
+ cutIndex: soldermaskCutSetting.index,
1791
+ verts: rectPath.verts,
1792
+ prims: rectPath.prims,
1793
+ isClosed: true
1794
+ })
1795
+ );
1796
+ }
1797
+ };
1798
+
1799
+ // lib/element-handlers/addPcbCutout/addPolygonPcbCutout.ts
1800
+ import { ShapePath as ShapePath23 } from "lbrnts";
1801
+ var addPolygonPcbCutout = (cutout, ctx) => {
1802
+ const {
1803
+ project,
1804
+ throughBoardCutSetting,
1805
+ origin,
1806
+ includeCopper,
1807
+ includeSoldermask,
1808
+ soldermaskCutSetting,
1809
+ soldermaskMargin
1810
+ } = ctx;
1811
+ if (cutout.points.length >= 3 && includeCopper) {
1812
+ const polygonPath = createPolygonPathFromOutline(
1813
+ cutout.points,
1814
+ origin.x,
1815
+ origin.y
1816
+ );
1817
+ project.children.push(
1818
+ new ShapePath23({
1819
+ cutIndex: throughBoardCutSetting.index,
1820
+ verts: polygonPath.verts,
1821
+ prims: polygonPath.prims,
1822
+ isClosed: true
1823
+ })
1824
+ );
1825
+ }
1826
+ if (cutout.points.length >= 3 && includeSoldermask) {
1827
+ const points = soldermaskMargin && soldermaskMargin > 0 ? cutout.points.map((p) => ({
1828
+ x: (p.x ?? 0) + (p.x ?? 0) > 0 ? soldermaskMargin : -soldermaskMargin,
1829
+ y: (p.y ?? 0) + (p.y ?? 0) > 0 ? soldermaskMargin : -soldermaskMargin
1830
+ })) : cutout.points;
1831
+ const polygonPath = createPolygonPathFromOutline(points, origin.x, origin.y);
1832
+ project.children.push(
1833
+ new ShapePath23({
1834
+ cutIndex: soldermaskCutSetting.index,
1835
+ verts: polygonPath.verts,
1836
+ prims: polygonPath.prims,
1837
+ isClosed: true
1838
+ })
1839
+ );
1840
+ }
1841
+ };
1842
+
1843
+ // lib/element-handlers/addPcbCutout/addPathPcbCutout.ts
1844
+ import { ShapePath as ShapePath24 } from "lbrnts";
1845
+ var addPathPcbCutout = (cutout, ctx) => {
1846
+ const {
1847
+ project,
1848
+ throughBoardCutSetting,
1849
+ origin,
1850
+ includeCopper,
1851
+ includeSoldermask,
1852
+ soldermaskMargin,
1853
+ soldermaskCutSetting
1854
+ } = ctx;
1855
+ if (cutout.route.length >= 2 && includeCopper) {
1856
+ const verts = [];
1857
+ const prims = [];
1858
+ for (const point6 of cutout.route) {
1859
+ verts.push({
1860
+ x: point6.x + origin.x,
1861
+ y: point6.y + origin.y
1862
+ });
1863
+ prims.push({ type: 0 });
1864
+ }
1865
+ project.children.push(
1866
+ new ShapePath24({
1867
+ cutIndex: throughBoardCutSetting.index,
1868
+ verts,
1869
+ prims,
1870
+ isClosed: false
1871
+ // Paths are typically not closed
1872
+ })
1873
+ );
1874
+ }
1875
+ if (cutout.route.length >= 2 && includeSoldermask) {
1876
+ const verts = [];
1877
+ const prims = [];
1878
+ for (const point6 of cutout.route) {
1879
+ verts.push({
1880
+ x: point6.x + origin.x,
1881
+ y: point6.y + origin.y
1882
+ });
1883
+ prims.push({ type: 0 });
1884
+ }
1885
+ project.children.push(
1886
+ new ShapePath24({
1887
+ cutIndex: soldermaskCutSetting.index,
1888
+ verts,
1889
+ prims,
1890
+ isClosed: false
1891
+ // Match the same path as the copper cutout
1892
+ })
1893
+ );
1894
+ }
1895
+ };
1896
+
1897
+ // lib/element-handlers/addPcbCutout/index.ts
1898
+ var addPcbCutout = (cutout, ctx) => {
1899
+ switch (cutout.shape) {
1900
+ case "circle":
1901
+ return addCirclePcbCutout(cutout, ctx);
1902
+ case "rect":
1903
+ return addRectPcbCutout(cutout, ctx);
1904
+ case "polygon":
1905
+ return addPolygonPcbCutout(cutout, ctx);
1906
+ case "path":
1907
+ return addPathPcbCutout(cutout, ctx);
1908
+ default:
1909
+ const _exhaustive = cutout;
1910
+ console.warn(`Unknown cutout shape: ${cutout.shape}`);
1911
+ }
1912
+ };
1913
+
1693
1914
  // lib/index.ts
1694
1915
  var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1695
1916
  const db = cju2(circuitJson);
@@ -1767,6 +1988,9 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1767
1988
  for (const hole of db.pcb_hole.list()) {
1768
1989
  addPcbHole(hole, ctx);
1769
1990
  }
1991
+ for (const cutout of db.pcb_cutout.list()) {
1992
+ addPcbCutout(cutout, ctx);
1993
+ }
1770
1994
  if (ctx.includeCopper) {
1771
1995
  for (const net of Object.keys(connMap.netMap)) {
1772
1996
  const netGeoms = ctx.netGeoms.get(net);
@@ -1787,7 +2011,7 @@ var convertCircuitJsonToLbrn = (circuitJson, options = {}) => {
1787
2011
  for (const island of union.splitToIslands()) {
1788
2012
  const { verts, prims } = polygonToShapePathData(island);
1789
2013
  project.children.push(
1790
- new ShapePath21({
2014
+ new ShapePath25({
1791
2015
  cutIndex: copperCutSetting.index,
1792
2016
  verts,
1793
2017
  prims,
@@ -0,0 +1,52 @@
1
+ import type { PcbCutoutCircle } from "circuit-json"
2
+ import type { ConvertContext } from "../../ConvertContext"
3
+ import { ShapePath } from "lbrnts"
4
+ import { createCirclePath } from "../../helpers/circleShape"
5
+
6
+ /**
7
+ * Adds a circular PCB cutout to the project
8
+ * Cutouts are regions removed from the board entirely
9
+ */
10
+ export const addCirclePcbCutout = (
11
+ cutout: PcbCutoutCircle,
12
+ ctx: ConvertContext,
13
+ ): void => {
14
+ const {
15
+ project,
16
+ throughBoardCutSetting,
17
+ origin,
18
+ includeCopper,
19
+ includeSoldermask,
20
+ soldermaskMargin,
21
+ soldermaskCutSetting,
22
+ } = ctx
23
+ const centerX = cutout.center.x + origin.x
24
+ const centerY = cutout.center.y + origin.y
25
+
26
+ // Add the cutout - cut through the board
27
+ if (cutout.radius > 0 && includeCopper) {
28
+ const circlePath = createCirclePath(centerX, centerY, cutout.radius)
29
+ project.children.push(
30
+ new ShapePath({
31
+ cutIndex: throughBoardCutSetting.index,
32
+ verts: circlePath.verts,
33
+ prims: circlePath.prims,
34
+ isClosed: true,
35
+ }),
36
+ )
37
+ }
38
+
39
+ // Add soldermask opening if drawing soldermask
40
+ if (cutout.radius > 0 && includeSoldermask) {
41
+ const smRadius = cutout.radius + soldermaskMargin
42
+ const outer = createCirclePath(centerX, centerY, smRadius)
43
+ project.children.push(
44
+ new ShapePath({
45
+ cutIndex: soldermaskCutSetting.index,
46
+ verts: outer.verts,
47
+ prims: outer.prims,
48
+ isClosed: true,
49
+ }),
50
+ )
51
+ }
52
+ }
@@ -0,0 +1,73 @@
1
+ import type { PcbCutoutPath } from "circuit-json"
2
+ import type { ConvertContext } from "../../ConvertContext"
3
+ import { ShapePath } from "lbrnts"
4
+
5
+ /**
6
+ * Adds a path-based PCB cutout to the project
7
+ * Path cutouts create slots along a route (e.g., for routed slots or complex cutout paths)
8
+ */
9
+ export const addPathPcbCutout = (
10
+ cutout: PcbCutoutPath,
11
+ ctx: ConvertContext,
12
+ ): void => {
13
+ const {
14
+ project,
15
+ throughBoardCutSetting,
16
+ origin,
17
+ includeCopper,
18
+ includeSoldermask,
19
+ soldermaskMargin,
20
+ soldermaskCutSetting,
21
+ } = ctx
22
+
23
+ // For path cutouts, we need to create a stroke along the route with the given width
24
+ // For simplicity, we'll convert the path to a polyline
25
+ if (cutout.route.length >= 2 && includeCopper) {
26
+ const verts: { x: number; y: number }[] = []
27
+ const prims: { type: number }[] = []
28
+
29
+ for (const point of cutout.route) {
30
+ verts.push({
31
+ x: point.x + origin.x,
32
+ y: point.y + origin.y,
33
+ })
34
+ prims.push({ type: 0 })
35
+ }
36
+
37
+ // Note: slot_width, slot_length, space_between_slots, and slot_corner_radius
38
+ // would require more complex path offsetting and aren't currently implemented
39
+ // For now, we just create a simple path along the route
40
+ project.children.push(
41
+ new ShapePath({
42
+ cutIndex: throughBoardCutSetting.index,
43
+ verts,
44
+ prims,
45
+ isClosed: false, // Paths are typically not closed
46
+ }),
47
+ )
48
+ }
49
+
50
+ // Add soldermask opening if drawing soldermask
51
+ if (cutout.route.length >= 2 && includeSoldermask) {
52
+ const verts: { x: number; y: number }[] = []
53
+ const prims: { type: number }[] = []
54
+
55
+ // Create path with soldermask margin
56
+ for (const point of cutout.route) {
57
+ verts.push({
58
+ x: point.x + origin.x,
59
+ y: point.y + origin.y,
60
+ })
61
+ prims.push({ type: 0 })
62
+ }
63
+
64
+ project.children.push(
65
+ new ShapePath({
66
+ cutIndex: soldermaskCutSetting.index,
67
+ verts,
68
+ prims,
69
+ isClosed: false, // Match the same path as the copper cutout
70
+ }),
71
+ )
72
+ }
73
+ }
@@ -0,0 +1,68 @@
1
+ import type { PcbCutoutPolygon } from "circuit-json"
2
+ import type { ConvertContext } from "../../ConvertContext"
3
+ import { ShapePath } from "lbrnts"
4
+ import { createPolygonPathFromOutline } from "../../helpers/polygonShape"
5
+
6
+ /**
7
+ * Adds a polygon PCB cutout to the project
8
+ * Cutouts are regions removed from the board entirely
9
+ */
10
+ export const addPolygonPcbCutout = (
11
+ cutout: PcbCutoutPolygon,
12
+ ctx: ConvertContext,
13
+ ): void => {
14
+ const {
15
+ project,
16
+ throughBoardCutSetting,
17
+ origin,
18
+ includeCopper,
19
+ includeSoldermask,
20
+ soldermaskCutSetting,
21
+ soldermaskMargin,
22
+ } = ctx
23
+
24
+ // Add the cutout - cut through the board
25
+ if (cutout.points.length >= 3 && includeCopper) {
26
+ const polygonPath = createPolygonPathFromOutline(
27
+ cutout.points,
28
+ origin.x,
29
+ origin.y,
30
+ )
31
+ project.children.push(
32
+ new ShapePath({
33
+ cutIndex: throughBoardCutSetting.index,
34
+ verts: polygonPath.verts,
35
+ prims: polygonPath.prims,
36
+ isClosed: true,
37
+ }),
38
+ )
39
+ }
40
+
41
+ // Add soldermask opening if drawing soldermask
42
+ if (cutout.points.length >= 3 && includeSoldermask) {
43
+ // Apply soldermask margin to the points if margin is specified
44
+ const points =
45
+ soldermaskMargin && soldermaskMargin > 0
46
+ ? cutout.points.map((p) => ({
47
+ x:
48
+ (p.x ?? 0) + (p.x ?? 0) > 0
49
+ ? soldermaskMargin
50
+ : -soldermaskMargin,
51
+ y:
52
+ (p.y ?? 0) + (p.y ?? 0) > 0
53
+ ? soldermaskMargin
54
+ : -soldermaskMargin,
55
+ }))
56
+ : cutout.points
57
+
58
+ const polygonPath = createPolygonPathFromOutline(points, origin.x, origin.y)
59
+ project.children.push(
60
+ new ShapePath({
61
+ cutIndex: soldermaskCutSetting.index,
62
+ verts: polygonPath.verts,
63
+ prims: polygonPath.prims,
64
+ isClosed: true,
65
+ }),
66
+ )
67
+ }
68
+ }
@@ -0,0 +1,71 @@
1
+ import type { PcbCutoutRect } from "circuit-json"
2
+ import type { ConvertContext } from "../../ConvertContext"
3
+ import { ShapePath } from "lbrnts"
4
+ import { createRoundedRectPath } from "../../helpers/roundedRectShape"
5
+
6
+ /**
7
+ * Adds a rectangular PCB cutout to the project
8
+ * Cutouts are regions removed from the board entirely
9
+ */
10
+ export const addRectPcbCutout = (
11
+ cutout: PcbCutoutRect,
12
+ ctx: ConvertContext,
13
+ ): void => {
14
+ const {
15
+ project,
16
+ throughBoardCutSetting,
17
+ origin,
18
+ includeCopper,
19
+ includeSoldermask,
20
+ soldermaskMargin,
21
+ soldermaskCutSetting,
22
+ } = ctx
23
+ const centerX = cutout.center.x + origin.x
24
+ const centerY = cutout.center.y + origin.y
25
+
26
+ // Add the cutout - cut through the board
27
+ if (cutout.width > 0 && cutout.height > 0 && includeCopper) {
28
+ const rotation = (cutout.rotation ?? 0) * (Math.PI / 180) // Convert degrees to radians
29
+ const rectPath = createRoundedRectPath(
30
+ centerX,
31
+ centerY,
32
+ cutout.width,
33
+ cutout.height,
34
+ 0, // no border radius for cutouts
35
+ 4, // segments
36
+ rotation,
37
+ )
38
+ project.children.push(
39
+ new ShapePath({
40
+ cutIndex: throughBoardCutSetting.index,
41
+ verts: rectPath.verts,
42
+ prims: rectPath.prims,
43
+ isClosed: true,
44
+ }),
45
+ )
46
+ }
47
+
48
+ // Add soldermask opening if drawing soldermask
49
+ if (cutout.width > 0 && cutout.height > 0 && includeSoldermask) {
50
+ const rotation = (cutout.rotation ?? 0) * (Math.PI / 180) // Convert degrees to radians
51
+ const smWidth = cutout.width + 2 * soldermaskMargin
52
+ const smHeight = cutout.height + 2 * soldermaskMargin
53
+ const rectPath = createRoundedRectPath(
54
+ centerX,
55
+ centerY,
56
+ smWidth,
57
+ smHeight,
58
+ 0, // no border radius for cutouts
59
+ 4, // segments
60
+ rotation,
61
+ )
62
+ project.children.push(
63
+ new ShapePath({
64
+ cutIndex: soldermaskCutSetting.index,
65
+ verts: rectPath.verts,
66
+ prims: rectPath.prims,
67
+ isClosed: true,
68
+ }),
69
+ )
70
+ }
71
+ }