circuit-to-svg 0.0.272 → 0.0.273

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1580,9 +1580,12 @@ function createSvgObjectsFromPcbNoteLine(noteLine, ctx) {
1580
1580
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-plated-hole.ts
1581
1581
  import { applyToPoint as applyToPoint12 } from "transformation-matrix";
1582
1582
  function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1583
- const { transform, colorMap: colorMap2 } = ctx;
1583
+ const { transform, colorMap: colorMap2, showSolderMask } = ctx;
1584
1584
  const [x, y] = applyToPoint12(transform, [hole.x, hole.y]);
1585
1585
  const copperLayer = Array.isArray(hole.layers) && hole.layers[0] || hole.layer || "top";
1586
+ const soldermaskMargin = (hole.soldermask_margin ?? 0) * Math.abs(transform.a);
1587
+ const shouldShowSolderMask = showSolderMask && soldermaskMargin !== 0;
1588
+ const solderMaskColor = colorMap2.soldermask.top;
1586
1589
  if (hole.shape === "pill") {
1587
1590
  const scaledOuterWidth = hole.outer_width * Math.abs(transform.a);
1588
1591
  const scaledOuterHeight = hole.outer_height * Math.abs(transform.a);
@@ -1605,6 +1608,55 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1605
1608
  return `M${-radius},0 a${radius},${radius} 0 0 1 ${width},0 a${radius},${radius} 0 0 1 ${-width},0 z`;
1606
1609
  }
1607
1610
  };
1611
+ const children = [
1612
+ // Outer pill shape
1613
+ {
1614
+ name: "path",
1615
+ type: "element",
1616
+ attributes: {
1617
+ class: "pcb-hole-outer",
1618
+ fill: colorMap2.copper.top,
1619
+ d: createPillPath(scaledOuterWidth, scaledOuterHeight),
1620
+ transform: outerTransform,
1621
+ "data-type": "pcb_plated_hole",
1622
+ "data-pcb-layer": copperLayer
1623
+ },
1624
+ value: "",
1625
+ children: []
1626
+ },
1627
+ // Inner pill shape
1628
+ {
1629
+ name: "path",
1630
+ type: "element",
1631
+ attributes: {
1632
+ class: "pcb-hole-inner",
1633
+ fill: colorMap2.drill,
1634
+ d: createPillPath(scaledHoleWidth, scaledHoleHeight),
1635
+ transform: innerTransform,
1636
+ "data-type": "pcb_plated_hole_drill",
1637
+ "data-pcb-layer": "drill"
1638
+ },
1639
+ value: "",
1640
+ children: []
1641
+ }
1642
+ ];
1643
+ if (shouldShowSolderMask) {
1644
+ const maskWidth = scaledOuterWidth + 2 * soldermaskMargin;
1645
+ const maskHeight = scaledOuterHeight + 2 * soldermaskMargin;
1646
+ children.push({
1647
+ name: "path",
1648
+ type: "element",
1649
+ attributes: {
1650
+ class: "pcb-solder-mask",
1651
+ fill: solderMaskColor,
1652
+ d: createPillPath(maskWidth, maskHeight),
1653
+ transform: outerTransform,
1654
+ "data-type": "pcb_soldermask"
1655
+ },
1656
+ value: "",
1657
+ children: []
1658
+ });
1659
+ }
1608
1660
  return [
1609
1661
  {
1610
1662
  name: "g",
@@ -1613,38 +1665,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1613
1665
  "data-type": "pcb_plated_hole",
1614
1666
  "data-pcb-layer": "through"
1615
1667
  },
1616
- children: [
1617
- // Outer pill shape
1618
- {
1619
- name: "path",
1620
- type: "element",
1621
- attributes: {
1622
- class: "pcb-hole-outer",
1623
- fill: colorMap2.copper.top,
1624
- d: createPillPath(scaledOuterWidth, scaledOuterHeight),
1625
- transform: outerTransform,
1626
- "data-type": "pcb_plated_hole",
1627
- "data-pcb-layer": copperLayer
1628
- },
1629
- value: "",
1630
- children: []
1631
- },
1632
- // Inner pill shape
1633
- {
1634
- name: "path",
1635
- type: "element",
1636
- attributes: {
1637
- class: "pcb-hole-inner",
1638
- fill: colorMap2.drill,
1639
- d: createPillPath(scaledHoleWidth, scaledHoleHeight),
1640
- transform: innerTransform,
1641
- "data-type": "pcb_plated_hole_drill",
1642
- "data-pcb-layer": "drill"
1643
- },
1644
- value: "",
1645
- children: []
1646
- }
1647
- ],
1668
+ children,
1648
1669
  value: ""
1649
1670
  }
1650
1671
  ];
@@ -1656,6 +1677,55 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1656
1677
  const scaledHoleHeight = hole.hole_diameter * Math.abs(transform.a);
1657
1678
  const outerRadius = Math.min(scaledOuterWidth, scaledOuterHeight) / 2;
1658
1679
  const innerRadius = Math.min(scaledHoleWidth, scaledHoleHeight) / 2;
1680
+ const children = [
1681
+ {
1682
+ name: "circle",
1683
+ type: "element",
1684
+ attributes: {
1685
+ class: "pcb-hole-outer",
1686
+ fill: colorMap2.copper.top,
1687
+ cx: x.toString(),
1688
+ cy: y.toString(),
1689
+ r: outerRadius.toString(),
1690
+ "data-type": "pcb_plated_hole",
1691
+ "data-pcb-layer": copperLayer
1692
+ },
1693
+ value: "",
1694
+ children: []
1695
+ },
1696
+ {
1697
+ name: "circle",
1698
+ type: "element",
1699
+ attributes: {
1700
+ class: "pcb-hole-inner",
1701
+ fill: colorMap2.drill,
1702
+ cx: x.toString(),
1703
+ cy: y.toString(),
1704
+ r: innerRadius.toString(),
1705
+ "data-type": "pcb_plated_hole_drill",
1706
+ "data-pcb-layer": "drill"
1707
+ },
1708
+ value: "",
1709
+ children: []
1710
+ }
1711
+ ];
1712
+ if (shouldShowSolderMask) {
1713
+ const maskRadius = outerRadius + soldermaskMargin;
1714
+ children.push({
1715
+ name: "circle",
1716
+ type: "element",
1717
+ attributes: {
1718
+ class: "pcb-solder-mask",
1719
+ fill: solderMaskColor,
1720
+ cx: x.toString(),
1721
+ cy: y.toString(),
1722
+ r: maskRadius.toString(),
1723
+ "data-type": "pcb_soldermask"
1724
+ },
1725
+ value: "",
1726
+ children: []
1727
+ });
1728
+ }
1659
1729
  return [
1660
1730
  {
1661
1731
  name: "g",
@@ -1664,38 +1734,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1664
1734
  "data-type": "pcb_plated_hole",
1665
1735
  "data-pcb-layer": "through"
1666
1736
  },
1667
- children: [
1668
- {
1669
- name: "circle",
1670
- type: "element",
1671
- attributes: {
1672
- class: "pcb-hole-outer",
1673
- fill: colorMap2.copper.top,
1674
- cx: x.toString(),
1675
- cy: y.toString(),
1676
- r: outerRadius.toString(),
1677
- "data-type": "pcb_plated_hole",
1678
- "data-pcb-layer": copperLayer
1679
- },
1680
- value: "",
1681
- children: []
1682
- },
1683
- {
1684
- name: "circle",
1685
- type: "element",
1686
- attributes: {
1687
- class: "pcb-hole-inner",
1688
- fill: colorMap2.drill,
1689
- cx: x.toString(),
1690
- cy: y.toString(),
1691
- r: innerRadius.toString(),
1692
- "data-type": "pcb_plated_hole_drill",
1693
- "data-pcb-layer": "drill"
1694
- },
1695
- value: "",
1696
- children: []
1697
- }
1698
- ],
1737
+ children,
1699
1738
  value: ""
1700
1739
  }
1701
1740
  ];
@@ -1711,6 +1750,69 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1711
1750
  h.x + (h.hole_offset_x ?? 0),
1712
1751
  h.y + (h.hole_offset_y ?? 0)
1713
1752
  ]);
1753
+ const children = [
1754
+ // Rectangular pad (outer shape)
1755
+ {
1756
+ name: "rect",
1757
+ type: "element",
1758
+ attributes: {
1759
+ class: "pcb-hole-outer-pad",
1760
+ fill: colorMap2.copper.top,
1761
+ x: (x - scaledRectPadWidth / 2).toString(),
1762
+ y: (y - scaledRectPadHeight / 2).toString(),
1763
+ width: scaledRectPadWidth.toString(),
1764
+ height: scaledRectPadHeight.toString(),
1765
+ ...scaledRectBorderRadius ? {
1766
+ rx: scaledRectBorderRadius.toString(),
1767
+ ry: scaledRectBorderRadius.toString()
1768
+ } : {},
1769
+ "data-type": "pcb_plated_hole",
1770
+ "data-pcb-layer": copperLayer
1771
+ },
1772
+ value: "",
1773
+ children: []
1774
+ },
1775
+ // Circular hole inside the rectangle (with optional offset)
1776
+ {
1777
+ name: "circle",
1778
+ type: "element",
1779
+ attributes: {
1780
+ class: "pcb-hole-inner",
1781
+ fill: colorMap2.drill,
1782
+ cx: holeCx.toString(),
1783
+ cy: holeCy.toString(),
1784
+ r: holeRadius.toString(),
1785
+ "data-type": "pcb_plated_hole_drill",
1786
+ "data-pcb-layer": "drill"
1787
+ },
1788
+ value: "",
1789
+ children: []
1790
+ }
1791
+ ];
1792
+ if (shouldShowSolderMask) {
1793
+ const maskWidth = scaledRectPadWidth + 2 * soldermaskMargin;
1794
+ const maskHeight = scaledRectPadHeight + 2 * soldermaskMargin;
1795
+ const maskBorderRadius = scaledRectBorderRadius + soldermaskMargin;
1796
+ children.push({
1797
+ name: "rect",
1798
+ type: "element",
1799
+ attributes: {
1800
+ class: "pcb-solder-mask",
1801
+ fill: solderMaskColor,
1802
+ x: (x - maskWidth / 2).toString(),
1803
+ y: (y - maskHeight / 2).toString(),
1804
+ width: maskWidth.toString(),
1805
+ height: maskHeight.toString(),
1806
+ ...scaledRectBorderRadius ? {
1807
+ rx: maskBorderRadius.toString(),
1808
+ ry: maskBorderRadius.toString()
1809
+ } : {},
1810
+ "data-type": "pcb_soldermask"
1811
+ },
1812
+ value: "",
1813
+ children: []
1814
+ });
1815
+ }
1714
1816
  return [
1715
1817
  {
1716
1818
  name: "g",
@@ -1719,45 +1821,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1719
1821
  "data-type": "pcb_plated_hole",
1720
1822
  "data-pcb-layer": "through"
1721
1823
  },
1722
- children: [
1723
- // Rectangular pad (outer shape)
1724
- {
1725
- name: "rect",
1726
- type: "element",
1727
- attributes: {
1728
- class: "pcb-hole-outer-pad",
1729
- fill: colorMap2.copper.top,
1730
- x: (x - scaledRectPadWidth / 2).toString(),
1731
- y: (y - scaledRectPadHeight / 2).toString(),
1732
- width: scaledRectPadWidth.toString(),
1733
- height: scaledRectPadHeight.toString(),
1734
- ...scaledRectBorderRadius ? {
1735
- rx: scaledRectBorderRadius.toString(),
1736
- ry: scaledRectBorderRadius.toString()
1737
- } : {},
1738
- "data-type": "pcb_plated_hole",
1739
- "data-pcb-layer": copperLayer
1740
- },
1741
- value: "",
1742
- children: []
1743
- },
1744
- // Circular hole inside the rectangle (with optional offset)
1745
- {
1746
- name: "circle",
1747
- type: "element",
1748
- attributes: {
1749
- class: "pcb-hole-inner",
1750
- fill: colorMap2.drill,
1751
- cx: holeCx.toString(),
1752
- cy: holeCy.toString(),
1753
- r: holeRadius.toString(),
1754
- "data-type": "pcb_plated_hole_drill",
1755
- "data-pcb-layer": "drill"
1756
- },
1757
- value: "",
1758
- children: []
1759
- }
1760
- ],
1824
+ children,
1761
1825
  value: ""
1762
1826
  }
1763
1827
  ];
@@ -1777,6 +1841,72 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1777
1841
  pillHole.y + holeOffsetY
1778
1842
  ]);
1779
1843
  const holeRadius = Math.min(scaledHoleHeight, scaledHoleWidth) / 2;
1844
+ const children = [
1845
+ // Rectangular pad (outer shape)
1846
+ {
1847
+ name: "rect",
1848
+ type: "element",
1849
+ attributes: {
1850
+ class: "pcb-hole-outer-pad",
1851
+ fill: colorMap2.copper.top,
1852
+ x: (x - scaledRectPadWidth / 2).toString(),
1853
+ y: (y - scaledRectPadHeight / 2).toString(),
1854
+ width: scaledRectPadWidth.toString(),
1855
+ height: scaledRectPadHeight.toString(),
1856
+ ...scaledRectBorderRadius ? {
1857
+ rx: scaledRectBorderRadius.toString(),
1858
+ ry: scaledRectBorderRadius.toString()
1859
+ } : {},
1860
+ "data-type": "pcb_plated_hole",
1861
+ "data-pcb-layer": copperLayer
1862
+ },
1863
+ value: "",
1864
+ children: []
1865
+ },
1866
+ // pill hole inside the rectangle
1867
+ {
1868
+ name: "rect",
1869
+ type: "element",
1870
+ attributes: {
1871
+ class: "pcb-hole-inner",
1872
+ fill: colorMap2.drill,
1873
+ x: (holeCenterX - scaledHoleWidth / 2).toString(),
1874
+ y: (holeCenterY - scaledHoleHeight / 2).toString(),
1875
+ width: scaledHoleWidth.toString(),
1876
+ height: scaledHoleHeight.toString(),
1877
+ rx: holeRadius.toString(),
1878
+ ry: holeRadius.toString(),
1879
+ "data-type": "pcb_plated_hole_drill",
1880
+ "data-pcb-layer": "drill"
1881
+ },
1882
+ value: "",
1883
+ children: []
1884
+ }
1885
+ ];
1886
+ if (shouldShowSolderMask) {
1887
+ const maskWidth = scaledRectPadWidth + 2 * soldermaskMargin;
1888
+ const maskHeight = scaledRectPadHeight + 2 * soldermaskMargin;
1889
+ const maskBorderRadius = scaledRectBorderRadius + soldermaskMargin;
1890
+ children.push({
1891
+ name: "rect",
1892
+ type: "element",
1893
+ attributes: {
1894
+ class: "pcb-solder-mask",
1895
+ fill: solderMaskColor,
1896
+ x: (x - maskWidth / 2).toString(),
1897
+ y: (y - maskHeight / 2).toString(),
1898
+ width: maskWidth.toString(),
1899
+ height: maskHeight.toString(),
1900
+ ...scaledRectBorderRadius ? {
1901
+ rx: maskBorderRadius.toString(),
1902
+ ry: maskBorderRadius.toString()
1903
+ } : {},
1904
+ "data-type": "pcb_soldermask"
1905
+ },
1906
+ value: "",
1907
+ children: []
1908
+ });
1909
+ }
1780
1910
  return [
1781
1911
  {
1782
1912
  name: "g",
@@ -1785,67 +1915,93 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1785
1915
  "data-type": "pcb_plated_hole",
1786
1916
  "data-pcb-layer": "through"
1787
1917
  },
1788
- children: [
1789
- // Rectangular pad (outer shape)
1790
- {
1791
- name: "rect",
1792
- type: "element",
1793
- attributes: {
1794
- class: "pcb-hole-outer-pad",
1795
- fill: colorMap2.copper.top,
1796
- x: (x - scaledRectPadWidth / 2).toString(),
1797
- y: (y - scaledRectPadHeight / 2).toString(),
1798
- width: scaledRectPadWidth.toString(),
1799
- height: scaledRectPadHeight.toString(),
1800
- ...scaledRectBorderRadius ? {
1801
- rx: scaledRectBorderRadius.toString(),
1802
- ry: scaledRectBorderRadius.toString()
1803
- } : {},
1804
- "data-type": "pcb_plated_hole",
1805
- "data-pcb-layer": copperLayer
1806
- },
1807
- value: "",
1808
- children: []
1809
- },
1810
- // pill hole inside the rectangle
1811
- {
1812
- name: "rect",
1813
- type: "element",
1814
- attributes: {
1815
- class: "pcb-hole-inner",
1816
- fill: colorMap2.drill,
1817
- x: (holeCenterX - scaledHoleWidth / 2).toString(),
1818
- y: (holeCenterY - scaledHoleHeight / 2).toString(),
1819
- width: scaledHoleWidth.toString(),
1820
- height: scaledHoleHeight.toString(),
1821
- rx: holeRadius.toString(),
1822
- ry: holeRadius.toString(),
1823
- "data-type": "pcb_plated_hole_drill",
1824
- "data-pcb-layer": "drill"
1825
- },
1826
- value: "",
1827
- children: []
1828
- }
1829
- ],
1918
+ children,
1830
1919
  value: ""
1831
1920
  }
1832
1921
  ];
1833
- }
1834
- if (hole.shape === "rotated_pill_hole_with_rect_pad") {
1835
- const rotatedHole = hole;
1836
- const scaledRectPadWidth = rotatedHole.rect_pad_width * Math.abs(transform.a);
1837
- const scaledRectPadHeight = rotatedHole.rect_pad_height * Math.abs(transform.a);
1838
- const scaledRectBorderRadius = (rotatedHole.rect_border_radius ?? 0) * Math.abs(transform.a);
1839
- const scaledHoleHeight = rotatedHole.hole_height * Math.abs(transform.a);
1840
- const scaledHoleWidth = rotatedHole.hole_width * Math.abs(transform.a);
1841
- const rotatedHoleWithOffsets = rotatedHole;
1842
- const holeOffsetX = rotatedHoleWithOffsets.hole_offset_x ?? 0;
1843
- const holeOffsetY = rotatedHoleWithOffsets.hole_offset_y ?? 0;
1844
- const [holeCenterX, holeCenterY] = applyToPoint12(transform, [
1845
- rotatedHole.x + holeOffsetX,
1846
- rotatedHole.y + holeOffsetY
1847
- ]);
1848
- const holeRadius = Math.min(scaledHoleHeight, scaledHoleWidth) / 2;
1922
+ }
1923
+ if (hole.shape === "rotated_pill_hole_with_rect_pad") {
1924
+ const rotatedHole = hole;
1925
+ const scaledRectPadWidth = rotatedHole.rect_pad_width * Math.abs(transform.a);
1926
+ const scaledRectPadHeight = rotatedHole.rect_pad_height * Math.abs(transform.a);
1927
+ const scaledRectBorderRadius = (rotatedHole.rect_border_radius ?? 0) * Math.abs(transform.a);
1928
+ const scaledHoleHeight = rotatedHole.hole_height * Math.abs(transform.a);
1929
+ const scaledHoleWidth = rotatedHole.hole_width * Math.abs(transform.a);
1930
+ const rotatedHoleWithOffsets = rotatedHole;
1931
+ const holeOffsetX = rotatedHoleWithOffsets.hole_offset_x ?? 0;
1932
+ const holeOffsetY = rotatedHoleWithOffsets.hole_offset_y ?? 0;
1933
+ const [holeCenterX, holeCenterY] = applyToPoint12(transform, [
1934
+ rotatedHole.x + holeOffsetX,
1935
+ rotatedHole.y + holeOffsetY
1936
+ ]);
1937
+ const holeRadius = Math.min(scaledHoleHeight, scaledHoleWidth) / 2;
1938
+ const children = [
1939
+ {
1940
+ name: "rect",
1941
+ type: "element",
1942
+ attributes: {
1943
+ class: "pcb-hole-outer-pad",
1944
+ fill: colorMap2.copper.top,
1945
+ x: (-scaledRectPadWidth / 2).toString(),
1946
+ y: (-scaledRectPadHeight / 2).toString(),
1947
+ width: scaledRectPadWidth.toString(),
1948
+ height: scaledRectPadHeight.toString(),
1949
+ transform: `translate(${x} ${y}) rotate(${-rotatedHole.rect_ccw_rotation})`,
1950
+ ...scaledRectBorderRadius ? {
1951
+ rx: scaledRectBorderRadius.toString(),
1952
+ ry: scaledRectBorderRadius.toString()
1953
+ } : {},
1954
+ "data-type": "pcb_plated_hole",
1955
+ "data-pcb-layer": copperLayer
1956
+ },
1957
+ value: "",
1958
+ children: []
1959
+ },
1960
+ {
1961
+ name: "rect",
1962
+ type: "element",
1963
+ attributes: {
1964
+ class: "pcb-hole-inner",
1965
+ fill: colorMap2.drill,
1966
+ x: (-scaledHoleWidth / 2).toString(),
1967
+ y: (-scaledHoleHeight / 2).toString(),
1968
+ width: scaledHoleWidth.toString(),
1969
+ height: scaledHoleHeight.toString(),
1970
+ rx: holeRadius.toString(),
1971
+ ry: holeRadius.toString(),
1972
+ transform: `translate(${holeCenterX} ${holeCenterY}) rotate(${-rotatedHole.hole_ccw_rotation})`,
1973
+ "data-type": "pcb_plated_hole_drill",
1974
+ "data-pcb-layer": "drill"
1975
+ },
1976
+ value: "",
1977
+ children: []
1978
+ }
1979
+ ];
1980
+ if (shouldShowSolderMask) {
1981
+ const maskWidth = scaledRectPadWidth + 2 * soldermaskMargin;
1982
+ const maskHeight = scaledRectPadHeight + 2 * soldermaskMargin;
1983
+ const maskBorderRadius = scaledRectBorderRadius + soldermaskMargin;
1984
+ children.push({
1985
+ name: "rect",
1986
+ type: "element",
1987
+ attributes: {
1988
+ class: "pcb-solder-mask",
1989
+ fill: solderMaskColor,
1990
+ x: (-maskWidth / 2).toString(),
1991
+ y: (-maskHeight / 2).toString(),
1992
+ width: maskWidth.toString(),
1993
+ height: maskHeight.toString(),
1994
+ transform: `translate(${x} ${y}) rotate(${-rotatedHole.rect_ccw_rotation})`,
1995
+ ...scaledRectBorderRadius ? {
1996
+ rx: maskBorderRadius.toString(),
1997
+ ry: maskBorderRadius.toString()
1998
+ } : {},
1999
+ "data-type": "pcb_soldermask"
2000
+ },
2001
+ value: "",
2002
+ children: []
2003
+ });
2004
+ }
1849
2005
  return [
1850
2006
  {
1851
2007
  name: "g",
@@ -1854,48 +2010,7 @@ function createSvgObjectsFromPcbPlatedHole(hole, ctx) {
1854
2010
  "data-type": "pcb_plated_hole",
1855
2011
  "data-pcb-layer": "through"
1856
2012
  },
1857
- children: [
1858
- {
1859
- name: "rect",
1860
- type: "element",
1861
- attributes: {
1862
- class: "pcb-hole-outer-pad",
1863
- fill: colorMap2.copper.top,
1864
- x: (-scaledRectPadWidth / 2).toString(),
1865
- y: (-scaledRectPadHeight / 2).toString(),
1866
- width: scaledRectPadWidth.toString(),
1867
- height: scaledRectPadHeight.toString(),
1868
- transform: `translate(${x} ${y}) rotate(${-rotatedHole.rect_ccw_rotation})`,
1869
- ...scaledRectBorderRadius ? {
1870
- rx: scaledRectBorderRadius.toString(),
1871
- ry: scaledRectBorderRadius.toString()
1872
- } : {},
1873
- "data-type": "pcb_plated_hole",
1874
- "data-pcb-layer": copperLayer
1875
- },
1876
- value: "",
1877
- children: []
1878
- },
1879
- {
1880
- name: "rect",
1881
- type: "element",
1882
- attributes: {
1883
- class: "pcb-hole-inner",
1884
- fill: colorMap2.drill,
1885
- x: (-scaledHoleWidth / 2).toString(),
1886
- y: (-scaledHoleHeight / 2).toString(),
1887
- width: scaledHoleWidth.toString(),
1888
- height: scaledHoleHeight.toString(),
1889
- rx: holeRadius.toString(),
1890
- ry: holeRadius.toString(),
1891
- transform: `translate(${holeCenterX} ${holeCenterY}) rotate(${-rotatedHole.hole_ccw_rotation})`,
1892
- "data-type": "pcb_plated_hole_drill",
1893
- "data-pcb-layer": "drill"
1894
- },
1895
- value: "",
1896
- children: []
1897
- }
1898
- ],
2013
+ children,
1899
2014
  value: ""
1900
2015
  }
1901
2016
  ];
@@ -2951,94 +3066,170 @@ function createSvgObjectsFromPcbVia(hole, ctx) {
2951
3066
  // lib/pcb/svg-object-fns/create-svg-objects-from-pcb-hole.ts
2952
3067
  import { applyToPoint as applyToPoint24 } from "transformation-matrix";
2953
3068
  function createSvgObjectsFromPcbHole(hole, ctx) {
2954
- const { transform, colorMap: colorMap2 } = ctx;
3069
+ const { transform, colorMap: colorMap2, showSolderMask } = ctx;
2955
3070
  const [x, y] = applyToPoint24(transform, [hole.x, hole.y]);
3071
+ const soldermaskMargin = (hole.soldermask_margin ?? 0) * Math.abs(transform.a);
3072
+ const shouldShowSolderMask = showSolderMask && soldermaskMargin !== 0;
3073
+ const solderMaskColor = colorMap2.soldermask.top;
2956
3074
  if (hole.hole_shape === "circle" || hole.hole_shape === "square") {
2957
3075
  const scaledDiameter = hole.hole_diameter * Math.abs(transform.a);
2958
3076
  const radius = scaledDiameter / 2;
2959
3077
  if (hole.hole_shape === "circle") {
2960
- return [
2961
- {
2962
- name: "circle",
2963
- type: "element",
2964
- attributes: {
2965
- class: "pcb-hole",
2966
- cx: x.toString(),
2967
- cy: y.toString(),
2968
- r: radius.toString(),
2969
- fill: colorMap2.drill,
2970
- "data-type": "pcb_hole",
2971
- "data-pcb-layer": "drill"
2972
- },
2973
- children: [],
2974
- value: ""
2975
- }
2976
- ];
2977
- }
2978
- return [
2979
- {
2980
- name: "rect",
3078
+ const holeElement2 = {
3079
+ name: "circle",
2981
3080
  type: "element",
2982
3081
  attributes: {
2983
3082
  class: "pcb-hole",
2984
- x: (x - radius).toString(),
2985
- y: (y - radius).toString(),
2986
- width: scaledDiameter.toString(),
2987
- height: scaledDiameter.toString(),
3083
+ cx: x.toString(),
3084
+ cy: y.toString(),
3085
+ r: radius.toString(),
2988
3086
  fill: colorMap2.drill,
2989
3087
  "data-type": "pcb_hole",
2990
3088
  "data-pcb-layer": "drill"
2991
3089
  },
2992
3090
  children: [],
2993
3091
  value: ""
3092
+ };
3093
+ if (!shouldShowSolderMask) {
3094
+ return [holeElement2];
2994
3095
  }
2995
- ];
3096
+ const maskRadius = radius + soldermaskMargin;
3097
+ const maskElement2 = {
3098
+ name: holeElement2.name,
3099
+ type: holeElement2.type,
3100
+ value: "",
3101
+ children: [],
3102
+ attributes: {
3103
+ ...holeElement2.attributes,
3104
+ class: "pcb-solder-mask",
3105
+ fill: solderMaskColor,
3106
+ "data-type": "pcb_soldermask",
3107
+ r: maskRadius.toString()
3108
+ }
3109
+ };
3110
+ return [holeElement2, maskElement2];
3111
+ }
3112
+ const holeElement = {
3113
+ name: "rect",
3114
+ type: "element",
3115
+ attributes: {
3116
+ class: "pcb-hole",
3117
+ x: (x - radius).toString(),
3118
+ y: (y - radius).toString(),
3119
+ width: scaledDiameter.toString(),
3120
+ height: scaledDiameter.toString(),
3121
+ fill: colorMap2.drill,
3122
+ "data-type": "pcb_hole",
3123
+ "data-pcb-layer": "drill"
3124
+ },
3125
+ children: [],
3126
+ value: ""
3127
+ };
3128
+ if (!shouldShowSolderMask) {
3129
+ return [holeElement];
3130
+ }
3131
+ const maskDiameter = scaledDiameter + 2 * soldermaskMargin;
3132
+ const maskElement = {
3133
+ name: holeElement.name,
3134
+ type: holeElement.type,
3135
+ value: "",
3136
+ children: [],
3137
+ attributes: {
3138
+ ...holeElement.attributes,
3139
+ class: "pcb-solder-mask",
3140
+ fill: solderMaskColor,
3141
+ "data-type": "pcb_soldermask",
3142
+ x: (x - maskDiameter / 2).toString(),
3143
+ y: (y - maskDiameter / 2).toString(),
3144
+ width: maskDiameter.toString(),
3145
+ height: maskDiameter.toString()
3146
+ }
3147
+ };
3148
+ return [holeElement, maskElement];
2996
3149
  }
2997
3150
  if (hole.hole_shape === "oval") {
2998
3151
  const scaledWidth = hole.hole_width * Math.abs(transform.a);
2999
3152
  const scaledHeight = hole.hole_height * Math.abs(transform.a);
3000
3153
  const rx = scaledWidth / 2;
3001
3154
  const ry = scaledHeight / 2;
3002
- return [
3003
- {
3004
- name: "ellipse",
3005
- type: "element",
3006
- attributes: {
3007
- class: "pcb-hole",
3008
- cx: x.toString(),
3009
- cy: y.toString(),
3010
- rx: rx.toString(),
3011
- ry: ry.toString(),
3012
- fill: colorMap2.drill,
3013
- "data-type": "pcb_hole",
3014
- "data-pcb-layer": "drill"
3015
- },
3016
- children: [],
3017
- value: ""
3155
+ const holeElement = {
3156
+ name: "ellipse",
3157
+ type: "element",
3158
+ attributes: {
3159
+ class: "pcb-hole",
3160
+ cx: x.toString(),
3161
+ cy: y.toString(),
3162
+ rx: rx.toString(),
3163
+ ry: ry.toString(),
3164
+ fill: colorMap2.drill,
3165
+ "data-type": "pcb_hole",
3166
+ "data-pcb-layer": "drill"
3167
+ },
3168
+ children: [],
3169
+ value: ""
3170
+ };
3171
+ if (!shouldShowSolderMask) {
3172
+ return [holeElement];
3173
+ }
3174
+ const maskRx = rx + soldermaskMargin;
3175
+ const maskRy = ry + soldermaskMargin;
3176
+ const maskElement = {
3177
+ name: holeElement.name,
3178
+ type: holeElement.type,
3179
+ value: "",
3180
+ children: [],
3181
+ attributes: {
3182
+ ...holeElement.attributes,
3183
+ class: "pcb-solder-mask",
3184
+ fill: solderMaskColor,
3185
+ "data-type": "pcb_soldermask",
3186
+ rx: maskRx.toString(),
3187
+ ry: maskRy.toString()
3018
3188
  }
3019
- ];
3189
+ };
3190
+ return [holeElement, maskElement];
3020
3191
  }
3021
3192
  if (hole.hole_shape === "rect") {
3022
3193
  const scaledWidth = hole.hole_width * Math.abs(transform.a);
3023
3194
  const scaledHeight = hole.hole_height * Math.abs(transform.a);
3024
- return [
3025
- {
3026
- name: "rect",
3027
- type: "element",
3028
- attributes: {
3029
- class: "pcb-hole",
3030
- x: (x - scaledWidth / 2).toString(),
3031
- y: (y - scaledHeight / 2).toString(),
3032
- width: scaledWidth.toString(),
3033
- height: scaledHeight.toString(),
3034
- fill: colorMap2.drill,
3035
- "data-type": "pcb_hole",
3036
- "data-pcb-layer": "drill"
3037
- },
3038
- children: [],
3039
- value: ""
3195
+ const holeElement = {
3196
+ name: "rect",
3197
+ type: "element",
3198
+ attributes: {
3199
+ class: "pcb-hole",
3200
+ x: (x - scaledWidth / 2).toString(),
3201
+ y: (y - scaledHeight / 2).toString(),
3202
+ width: scaledWidth.toString(),
3203
+ height: scaledHeight.toString(),
3204
+ fill: colorMap2.drill,
3205
+ "data-type": "pcb_hole",
3206
+ "data-pcb-layer": "drill"
3207
+ },
3208
+ children: [],
3209
+ value: ""
3210
+ };
3211
+ if (!shouldShowSolderMask) {
3212
+ return [holeElement];
3213
+ }
3214
+ const maskWidth = scaledWidth + 2 * soldermaskMargin;
3215
+ const maskHeight = scaledHeight + 2 * soldermaskMargin;
3216
+ const maskElement = {
3217
+ name: holeElement.name,
3218
+ type: holeElement.type,
3219
+ value: "",
3220
+ children: [],
3221
+ attributes: {
3222
+ ...holeElement.attributes,
3223
+ class: "pcb-solder-mask",
3224
+ fill: solderMaskColor,
3225
+ "data-type": "pcb_soldermask",
3226
+ x: (x - maskWidth / 2).toString(),
3227
+ y: (y - maskHeight / 2).toString(),
3228
+ width: maskWidth.toString(),
3229
+ height: maskHeight.toString()
3040
3230
  }
3041
- ];
3231
+ };
3232
+ return [holeElement, maskElement];
3042
3233
  }
3043
3234
  if (hole.hole_shape === "pill") {
3044
3235
  const scaledWidth = hole.hole_width * Math.abs(transform.a);
@@ -3055,21 +3246,50 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3055
3246
  // Vertical pill (taller than wide)
3056
3247
  `M${x - radius},${y - straightLength / 2} v${straightLength} a${radius},${radius} 0 0 0 ${scaledWidth},0 v-${straightLength} a${radius},${radius} 0 0 0 -${scaledWidth},0 z`
3057
3248
  );
3058
- return [
3059
- {
3060
- name: "path",
3061
- type: "element",
3062
- attributes: {
3063
- class: "pcb-hole",
3064
- fill: colorMap2.drill,
3065
- d: pathD,
3066
- "data-type": "pcb_hole",
3067
- "data-pcb-layer": "drill"
3068
- },
3069
- children: [],
3070
- value: ""
3249
+ const holeElement = {
3250
+ name: "path",
3251
+ type: "element",
3252
+ attributes: {
3253
+ class: "pcb-hole",
3254
+ fill: colorMap2.drill,
3255
+ d: pathD,
3256
+ "data-type": "pcb_hole",
3257
+ "data-pcb-layer": "drill"
3258
+ },
3259
+ children: [],
3260
+ value: ""
3261
+ };
3262
+ if (!shouldShowSolderMask) {
3263
+ return [holeElement];
3264
+ }
3265
+ const maskWidth = scaledWidth + 2 * soldermaskMargin;
3266
+ const maskHeight = scaledHeight + 2 * soldermaskMargin;
3267
+ const maskIsHorizontal = maskWidth > maskHeight;
3268
+ const maskRadius = Math.min(maskWidth, maskHeight) / 2;
3269
+ const maskStraightLength = Math.abs(
3270
+ maskIsHorizontal ? maskWidth - maskHeight : maskHeight - maskWidth
3271
+ );
3272
+ const maskPathD = maskIsHorizontal ? (
3273
+ // Horizontal pill (wider than tall)
3274
+ `M${x - maskStraightLength / 2},${y - maskRadius} h${maskStraightLength} a${maskRadius},${maskRadius} 0 0 1 0,${maskHeight} h-${maskStraightLength} a${maskRadius},${maskRadius} 0 0 1 0,-${maskHeight} z`
3275
+ ) : (
3276
+ // Vertical pill (taller than wide)
3277
+ `M${x - maskRadius},${y - maskStraightLength / 2} v${maskStraightLength} a${maskRadius},${maskRadius} 0 0 0 ${maskWidth},0 v-${maskStraightLength} a${maskRadius},${maskRadius} 0 0 0 -${maskWidth},0 z`
3278
+ );
3279
+ const maskElement = {
3280
+ name: holeElement.name,
3281
+ type: holeElement.type,
3282
+ value: "",
3283
+ children: [],
3284
+ attributes: {
3285
+ ...holeElement.attributes,
3286
+ class: "pcb-solder-mask",
3287
+ fill: solderMaskColor,
3288
+ "data-type": "pcb_soldermask",
3289
+ d: maskPathD
3071
3290
  }
3072
- ];
3291
+ };
3292
+ return [holeElement, maskElement];
3073
3293
  }
3074
3294
  if (hole.hole_shape === "rotated_pill") {
3075
3295
  const scaledWidth = hole.hole_width * Math.abs(transform.a);
@@ -3087,22 +3307,51 @@ function createSvgObjectsFromPcbHole(hole, ctx) {
3087
3307
  // Vertical pill (taller than wide)
3088
3308
  `M${-radius},${-straightLength / 2} v${straightLength} a${radius},${radius} 0 0 0 ${scaledWidth},0 v-${straightLength} a${radius},${radius} 0 0 0 -${scaledWidth},0 z`
3089
3309
  );
3090
- return [
3091
- {
3092
- name: "path",
3093
- type: "element",
3094
- attributes: {
3095
- class: "pcb-hole",
3096
- fill: colorMap2.drill,
3097
- d: pathD,
3098
- transform: `translate(${x} ${y}) rotate(${-rotation})`,
3099
- "data-type": "pcb_hole",
3100
- "data-pcb-layer": "drill"
3101
- },
3102
- children: [],
3103
- value: ""
3310
+ const holeElement = {
3311
+ name: "path",
3312
+ type: "element",
3313
+ attributes: {
3314
+ class: "pcb-hole",
3315
+ fill: colorMap2.drill,
3316
+ d: pathD,
3317
+ transform: `translate(${x} ${y}) rotate(${-rotation})`,
3318
+ "data-type": "pcb_hole",
3319
+ "data-pcb-layer": "drill"
3320
+ },
3321
+ children: [],
3322
+ value: ""
3323
+ };
3324
+ if (!shouldShowSolderMask) {
3325
+ return [holeElement];
3326
+ }
3327
+ const maskWidth = scaledWidth + 2 * soldermaskMargin;
3328
+ const maskHeight = scaledHeight + 2 * soldermaskMargin;
3329
+ const maskIsHorizontal = maskWidth > maskHeight;
3330
+ const maskRadius = Math.min(maskWidth, maskHeight) / 2;
3331
+ const maskStraightLength = Math.abs(
3332
+ maskIsHorizontal ? maskWidth - maskHeight : maskHeight - maskWidth
3333
+ );
3334
+ const maskPathD = maskIsHorizontal ? (
3335
+ // Horizontal pill (wider than tall)
3336
+ `M${-maskStraightLength / 2},${-maskRadius} h${maskStraightLength} a${maskRadius},${maskRadius} 0 0 1 0,${maskHeight} h-${maskStraightLength} a${maskRadius},${maskRadius} 0 0 1 0,-${maskHeight} z`
3337
+ ) : (
3338
+ // Vertical pill (taller than wide)
3339
+ `M${-maskRadius},${-maskStraightLength / 2} v${maskStraightLength} a${maskRadius},${maskRadius} 0 0 0 ${maskWidth},0 v-${maskStraightLength} a${maskRadius},${maskRadius} 0 0 0 -${maskWidth},0 z`
3340
+ );
3341
+ const maskElement = {
3342
+ name: holeElement.name,
3343
+ type: holeElement.type,
3344
+ value: "",
3345
+ children: [],
3346
+ attributes: {
3347
+ ...holeElement.attributes,
3348
+ class: "pcb-solder-mask",
3349
+ fill: solderMaskColor,
3350
+ "data-type": "pcb_soldermask",
3351
+ d: maskPathD
3104
3352
  }
3105
- ];
3353
+ };
3354
+ return [holeElement, maskElement];
3106
3355
  }
3107
3356
  return [];
3108
3357
  }
@@ -4030,7 +4279,7 @@ function getSoftwareUsedString(circuitJson) {
4030
4279
  var package_default = {
4031
4280
  name: "circuit-to-svg",
4032
4281
  type: "module",
4033
- version: "0.0.271",
4282
+ version: "0.0.272",
4034
4283
  description: "Convert Circuit JSON to SVG",
4035
4284
  main: "dist/index.js",
4036
4285
  files: [