circuit-json-to-gerber 0.0.45 → 0.0.47
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/{chunk-4KGM4B43.js → chunk-LRAY3J4M.js} +191 -124
- package/dist/chunk-LRAY3J4M.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-4KGM4B43.js.map +0 -1
|
@@ -1225,6 +1225,16 @@ var getApertureConfigFromPcbSilkscreenText = (elm) => {
|
|
|
1225
1225
|
}
|
|
1226
1226
|
throw new Error(`Provide font_size for: ${elm}`);
|
|
1227
1227
|
};
|
|
1228
|
+
var getApertureConfigFromPcbCopperText = (elm) => {
|
|
1229
|
+
if ("font_size" in elm) {
|
|
1230
|
+
return {
|
|
1231
|
+
standard_template_code: "C",
|
|
1232
|
+
diameter: elm.font_size / 8
|
|
1233
|
+
// font size and diamater have different units of measurement
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
throw new Error(`Provide font_size for: ${elm}`);
|
|
1237
|
+
};
|
|
1228
1238
|
var getApertureConfigFromPcbSolderPaste = (elm) => {
|
|
1229
1239
|
if (elm.shape === "rect") {
|
|
1230
1240
|
return {
|
|
@@ -1378,6 +1388,10 @@ function getAllApertureTemplateConfigsForLayer(soup, layer) {
|
|
|
1378
1388
|
addConfigIfNew(getApertureConfigFromPcbSilkscreenPath(elm));
|
|
1379
1389
|
else if (elm.type === "pcb_silkscreen_text")
|
|
1380
1390
|
addConfigIfNew(getApertureConfigFromPcbSilkscreenText(elm));
|
|
1391
|
+
else if (elm.type === "pcb_copper_text") {
|
|
1392
|
+
if (elm.layer === layer)
|
|
1393
|
+
addConfigIfNew(getApertureConfigFromPcbCopperText(elm));
|
|
1394
|
+
}
|
|
1381
1395
|
}
|
|
1382
1396
|
return configs;
|
|
1383
1397
|
}
|
|
@@ -1408,7 +1422,7 @@ var findApertureNumber = (glayer, search_params) => {
|
|
|
1408
1422
|
// package.json
|
|
1409
1423
|
var package_default = {
|
|
1410
1424
|
name: "circuit-json-to-gerber",
|
|
1411
|
-
version: "0.0.
|
|
1425
|
+
version: "0.0.46",
|
|
1412
1426
|
main: "dist/index.js",
|
|
1413
1427
|
type: "module",
|
|
1414
1428
|
scripts: {
|
|
@@ -1433,7 +1447,7 @@ var package_default = {
|
|
|
1433
1447
|
"@types/react-dom": "^19.1.5",
|
|
1434
1448
|
archiver: "^7.0.1",
|
|
1435
1449
|
"bun-match-svg": "^0.0.13",
|
|
1436
|
-
"circuit-json": "^0.0.
|
|
1450
|
+
"circuit-json": "^0.0.378",
|
|
1437
1451
|
commander: "^12.1.0",
|
|
1438
1452
|
"gerber-to-svg": "^4.2.8",
|
|
1439
1453
|
gerberts: "^0.0.3",
|
|
@@ -1528,6 +1542,7 @@ import {
|
|
|
1528
1542
|
} from "transformation-matrix";
|
|
1529
1543
|
var convertSoupToGerberCommands = (soup, opts = {}) => {
|
|
1530
1544
|
opts.flip_y_axis ??= false;
|
|
1545
|
+
const hasPanel = soup.some((e) => e.type === "pcb_panel");
|
|
1531
1546
|
const glayers = {
|
|
1532
1547
|
F_Cu: getCommandHeaders({
|
|
1533
1548
|
layer: "top",
|
|
@@ -1599,6 +1614,164 @@ var convertSoupToGerberCommands = (soup, opts = {}) => {
|
|
|
1599
1614
|
rotationLookup.set(`${element.x}:${element.y}`, rotation);
|
|
1600
1615
|
}
|
|
1601
1616
|
}
|
|
1617
|
+
const renderVectorText = (element, layer, layerType, getApertureConfig) => {
|
|
1618
|
+
if (element.layer !== layer) return;
|
|
1619
|
+
const CAP_HEIGHT_SCALE = 0.7;
|
|
1620
|
+
const glayer = glayers[getGerberLayerName(layer, layerType)];
|
|
1621
|
+
const apertureConfig = getApertureConfig(element);
|
|
1622
|
+
const gerber = gerberBuilder().add("select_aperture", {
|
|
1623
|
+
aperture_number: findApertureNumber(glayer, apertureConfig)
|
|
1624
|
+
});
|
|
1625
|
+
let initialX = element.anchor_position.x;
|
|
1626
|
+
let initialY = element.anchor_position.y;
|
|
1627
|
+
const fontSize = element.font_size * CAP_HEIGHT_SCALE;
|
|
1628
|
+
const letterSpacing = fontSize * 0.4;
|
|
1629
|
+
const spaceWidth = fontSize * 0.5;
|
|
1630
|
+
const textWidth = element.text.split("").reduce((width, char) => {
|
|
1631
|
+
if (char === " ") {
|
|
1632
|
+
return width + spaceWidth + letterSpacing;
|
|
1633
|
+
}
|
|
1634
|
+
return width + fontSize + letterSpacing;
|
|
1635
|
+
}, 0) - letterSpacing;
|
|
1636
|
+
const textHeight = fontSize;
|
|
1637
|
+
const anchorAlignment = element.anchor_alignment || (() => {
|
|
1638
|
+
const side = element.anchor_side;
|
|
1639
|
+
if (!side) return void 0;
|
|
1640
|
+
switch (side) {
|
|
1641
|
+
case "top":
|
|
1642
|
+
return "top_center";
|
|
1643
|
+
case "bottom":
|
|
1644
|
+
return "bottom_center";
|
|
1645
|
+
case "left":
|
|
1646
|
+
return "center_left";
|
|
1647
|
+
case "right":
|
|
1648
|
+
return "center_right";
|
|
1649
|
+
}
|
|
1650
|
+
})() || "center";
|
|
1651
|
+
switch (anchorAlignment) {
|
|
1652
|
+
case "top_left":
|
|
1653
|
+
break;
|
|
1654
|
+
case "top_center":
|
|
1655
|
+
initialX -= textWidth / 2;
|
|
1656
|
+
break;
|
|
1657
|
+
case "top_right":
|
|
1658
|
+
initialX -= textWidth;
|
|
1659
|
+
break;
|
|
1660
|
+
case "center_right":
|
|
1661
|
+
initialY -= textHeight / 2;
|
|
1662
|
+
break;
|
|
1663
|
+
case "center_left":
|
|
1664
|
+
initialX -= textWidth;
|
|
1665
|
+
initialY -= textHeight / 2;
|
|
1666
|
+
break;
|
|
1667
|
+
case "bottom_left":
|
|
1668
|
+
initialY -= textHeight;
|
|
1669
|
+
break;
|
|
1670
|
+
case "bottom_center":
|
|
1671
|
+
initialX -= textWidth / 2;
|
|
1672
|
+
initialY -= textHeight;
|
|
1673
|
+
break;
|
|
1674
|
+
case "bottom_right":
|
|
1675
|
+
initialX -= textWidth;
|
|
1676
|
+
initialY -= textHeight;
|
|
1677
|
+
break;
|
|
1678
|
+
default:
|
|
1679
|
+
initialX -= textWidth / 2;
|
|
1680
|
+
initialY -= textHeight / 2;
|
|
1681
|
+
break;
|
|
1682
|
+
}
|
|
1683
|
+
let anchoredX = initialX;
|
|
1684
|
+
const anchoredY = initialY;
|
|
1685
|
+
let rotation = element.ccw_rotation || 0;
|
|
1686
|
+
const cx = anchoredX + textWidth / 2;
|
|
1687
|
+
const cy = anchoredY + textHeight / 2;
|
|
1688
|
+
const transforms = [];
|
|
1689
|
+
const shouldMirror = element.is_mirrored !== void 0 ? element.is_mirrored : element.layer === "bottom";
|
|
1690
|
+
if (shouldMirror) {
|
|
1691
|
+
transforms.push(
|
|
1692
|
+
translate(cx, cy),
|
|
1693
|
+
{ a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 },
|
|
1694
|
+
translate(-cx, -cy)
|
|
1695
|
+
);
|
|
1696
|
+
rotation = -rotation;
|
|
1697
|
+
}
|
|
1698
|
+
if (rotation) {
|
|
1699
|
+
const rad = rotation * Math.PI / 180;
|
|
1700
|
+
transforms.push(translate(cx, cy), rotate(rad), translate(-cx, -cy));
|
|
1701
|
+
}
|
|
1702
|
+
const transformMatrix = transforms.length > 0 ? compose(...transforms) : void 0;
|
|
1703
|
+
const applyTransform = (point) => transformMatrix ? applyToPoint(transformMatrix, point) : point;
|
|
1704
|
+
if (layerType === "copper" && element.is_knockout) {
|
|
1705
|
+
const padding = element.knockout_padding ?? {
|
|
1706
|
+
left: 0.2,
|
|
1707
|
+
right: 0.2,
|
|
1708
|
+
top: 0.2,
|
|
1709
|
+
bottom: 0.2
|
|
1710
|
+
};
|
|
1711
|
+
const paddedRect = [
|
|
1712
|
+
{ x: initialX - padding.left, y: initialY - padding.top },
|
|
1713
|
+
{
|
|
1714
|
+
x: initialX + textWidth + padding.right,
|
|
1715
|
+
y: initialY - padding.top
|
|
1716
|
+
},
|
|
1717
|
+
{
|
|
1718
|
+
x: initialX + textWidth + padding.right,
|
|
1719
|
+
y: initialY + textHeight + padding.bottom
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
x: initialX - padding.left,
|
|
1723
|
+
y: initialY + textHeight + padding.bottom
|
|
1724
|
+
}
|
|
1725
|
+
].map(applyTransform);
|
|
1726
|
+
glayer.push(
|
|
1727
|
+
...gerberBuilder().add("select_aperture", {
|
|
1728
|
+
aperture_number: findApertureNumber(glayer, apertureConfig)
|
|
1729
|
+
}).add("start_region_statement", {}).add("move_operation", {
|
|
1730
|
+
x: paddedRect[0].x,
|
|
1731
|
+
y: mfy(paddedRect[0].y)
|
|
1732
|
+
}).add("plot_operation", {
|
|
1733
|
+
x: paddedRect[1].x,
|
|
1734
|
+
y: mfy(paddedRect[1].y)
|
|
1735
|
+
}).add("plot_operation", {
|
|
1736
|
+
x: paddedRect[2].x,
|
|
1737
|
+
y: mfy(paddedRect[2].y)
|
|
1738
|
+
}).add("plot_operation", {
|
|
1739
|
+
x: paddedRect[3].x,
|
|
1740
|
+
y: mfy(paddedRect[3].y)
|
|
1741
|
+
}).add("plot_operation", {
|
|
1742
|
+
x: paddedRect[0].x,
|
|
1743
|
+
y: mfy(paddedRect[0].y)
|
|
1744
|
+
}).add("end_region_statement", {}).build()
|
|
1745
|
+
);
|
|
1746
|
+
glayer.push(
|
|
1747
|
+
...gerberBuilder().add("set_layer_polarity", { polarity: "C" }).build()
|
|
1748
|
+
);
|
|
1749
|
+
}
|
|
1750
|
+
for (const char of element.text.toUpperCase()) {
|
|
1751
|
+
if (char === " ") {
|
|
1752
|
+
anchoredX += spaceWidth + letterSpacing;
|
|
1753
|
+
continue;
|
|
1754
|
+
}
|
|
1755
|
+
const letterPaths = lineAlphabet[char] || [];
|
|
1756
|
+
for (const path of letterPaths) {
|
|
1757
|
+
const x1 = anchoredX + path.x1 * fontSize;
|
|
1758
|
+
const y1 = anchoredY + path.y1 * fontSize;
|
|
1759
|
+
const x2 = anchoredX + path.x2 * fontSize;
|
|
1760
|
+
const y2 = anchoredY + path.y2 * fontSize;
|
|
1761
|
+
const p1 = applyTransform({ x: x1, y: y1 });
|
|
1762
|
+
const p2 = applyTransform({ x: x2, y: y2 });
|
|
1763
|
+
gerber.add("move_operation", { x: p1.x, y: mfy(p1.y) });
|
|
1764
|
+
gerber.add("plot_operation", { x: p2.x, y: mfy(p2.y) });
|
|
1765
|
+
}
|
|
1766
|
+
anchoredX += fontSize + letterSpacing;
|
|
1767
|
+
}
|
|
1768
|
+
glayer.push(...gerber.build());
|
|
1769
|
+
if (layerType === "copper" && element.is_knockout) {
|
|
1770
|
+
glayer.push(
|
|
1771
|
+
...gerberBuilder().add("set_layer_polarity", { polarity: "D" }).build()
|
|
1772
|
+
);
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1602
1775
|
for (const layer of ["top", "bottom", "edgecut"]) {
|
|
1603
1776
|
for (const element of soup) {
|
|
1604
1777
|
if (element.type === "pcb_trace") {
|
|
@@ -1638,123 +1811,20 @@ var convertSoupToGerberCommands = (soup, opts = {}) => {
|
|
|
1638
1811
|
}
|
|
1639
1812
|
glayer.push(...gerber.build());
|
|
1640
1813
|
}
|
|
1641
|
-
} else if (element.type === "pcb_silkscreen_text") {
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
if (char === " ") {
|
|
1656
|
-
return width + spaceWidth + letterSpacing;
|
|
1657
|
-
}
|
|
1658
|
-
return width + fontSize + letterSpacing;
|
|
1659
|
-
}, 0) - letterSpacing;
|
|
1660
|
-
const textHeight = fontSize;
|
|
1661
|
-
const anchorAlignment = element.anchor_alignment || (() => {
|
|
1662
|
-
const side = element.anchor_side;
|
|
1663
|
-
if (!side) return void 0;
|
|
1664
|
-
switch (side) {
|
|
1665
|
-
case "top":
|
|
1666
|
-
return "top_center";
|
|
1667
|
-
case "bottom":
|
|
1668
|
-
return "bottom_center";
|
|
1669
|
-
case "left":
|
|
1670
|
-
return "center_left";
|
|
1671
|
-
case "right":
|
|
1672
|
-
return "center_right";
|
|
1673
|
-
}
|
|
1674
|
-
})() || "center";
|
|
1675
|
-
switch (anchorAlignment) {
|
|
1676
|
-
case "top_left":
|
|
1677
|
-
break;
|
|
1678
|
-
case "top_center":
|
|
1679
|
-
initialX -= textWidth / 2;
|
|
1680
|
-
break;
|
|
1681
|
-
case "top_right":
|
|
1682
|
-
initialX -= textWidth;
|
|
1683
|
-
break;
|
|
1684
|
-
case "center_right":
|
|
1685
|
-
initialY -= textHeight / 2;
|
|
1686
|
-
break;
|
|
1687
|
-
case "center_left":
|
|
1688
|
-
initialX -= textWidth;
|
|
1689
|
-
initialY -= textHeight / 2;
|
|
1690
|
-
break;
|
|
1691
|
-
case "bottom_left":
|
|
1692
|
-
initialY -= textHeight;
|
|
1693
|
-
break;
|
|
1694
|
-
case "bottom_center":
|
|
1695
|
-
initialX -= textWidth / 2;
|
|
1696
|
-
initialY -= textHeight;
|
|
1697
|
-
break;
|
|
1698
|
-
case "bottom_right":
|
|
1699
|
-
initialX -= textWidth;
|
|
1700
|
-
initialY -= textHeight;
|
|
1701
|
-
break;
|
|
1702
|
-
default:
|
|
1703
|
-
initialX -= textWidth / 2;
|
|
1704
|
-
initialY -= textHeight / 2;
|
|
1705
|
-
break;
|
|
1706
|
-
}
|
|
1707
|
-
let anchoredX = initialX;
|
|
1708
|
-
const anchoredY = initialY;
|
|
1709
|
-
let rotation = element.ccw_rotation || 0;
|
|
1710
|
-
const cx = anchoredX + textWidth / 2;
|
|
1711
|
-
const cy = anchoredY + textHeight / 2;
|
|
1712
|
-
const transforms = [];
|
|
1713
|
-
if (element.layer === "bottom") {
|
|
1714
|
-
transforms.push(
|
|
1715
|
-
translate(cx, cy),
|
|
1716
|
-
{ a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 },
|
|
1717
|
-
// Horizontal flip
|
|
1718
|
-
translate(-cx, -cy)
|
|
1719
|
-
);
|
|
1720
|
-
rotation = -rotation;
|
|
1721
|
-
}
|
|
1722
|
-
if (rotation) {
|
|
1723
|
-
const rad = rotation * Math.PI / 180;
|
|
1724
|
-
transforms.push(
|
|
1725
|
-
translate(cx, cy),
|
|
1726
|
-
// Translate to center of rotation
|
|
1727
|
-
rotate(rad),
|
|
1728
|
-
// Apply rotation
|
|
1729
|
-
translate(-cx, -cy)
|
|
1730
|
-
// Translate back
|
|
1731
|
-
);
|
|
1732
|
-
}
|
|
1733
|
-
for (const char of element.text.toUpperCase()) {
|
|
1734
|
-
if (char === " ") {
|
|
1735
|
-
anchoredX += spaceWidth + letterSpacing;
|
|
1736
|
-
continue;
|
|
1737
|
-
}
|
|
1738
|
-
const letterPaths = lineAlphabet[char] || [];
|
|
1739
|
-
for (const path of letterPaths) {
|
|
1740
|
-
const x1 = anchoredX + path.x1 * fontSize;
|
|
1741
|
-
const y1 = anchoredY + path.y1 * fontSize;
|
|
1742
|
-
const x2 = anchoredX + path.x2 * fontSize;
|
|
1743
|
-
const y2 = anchoredY + path.y2 * fontSize;
|
|
1744
|
-
let p1 = { x: x1, y: y1 };
|
|
1745
|
-
let p2 = { x: x2, y: y2 };
|
|
1746
|
-
if (transforms.length > 0) {
|
|
1747
|
-
const transformMatrix = compose(...transforms);
|
|
1748
|
-
p1 = applyToPoint(transformMatrix, p1);
|
|
1749
|
-
p2 = applyToPoint(transformMatrix, p2);
|
|
1750
|
-
}
|
|
1751
|
-
gerber.add("move_operation", { x: p1.x, y: mfy(p1.y) });
|
|
1752
|
-
gerber.add("plot_operation", { x: p2.x, y: mfy(p2.y) });
|
|
1753
|
-
}
|
|
1754
|
-
anchoredX += fontSize + letterSpacing;
|
|
1755
|
-
}
|
|
1756
|
-
glayer.push(...gerber.build());
|
|
1757
|
-
}
|
|
1814
|
+
} else if (element.type === "pcb_silkscreen_text" && layer !== "edgecut") {
|
|
1815
|
+
renderVectorText(
|
|
1816
|
+
element,
|
|
1817
|
+
layer,
|
|
1818
|
+
"silkscreen",
|
|
1819
|
+
getApertureConfigFromPcbSilkscreenText
|
|
1820
|
+
);
|
|
1821
|
+
} else if (element.type === "pcb_copper_text" && layer !== "edgecut") {
|
|
1822
|
+
renderVectorText(
|
|
1823
|
+
element,
|
|
1824
|
+
layer,
|
|
1825
|
+
"copper",
|
|
1826
|
+
getApertureConfigFromPcbCopperText
|
|
1827
|
+
);
|
|
1758
1828
|
} else if (element.type === "pcb_smtpad" && element.shape !== "polygon") {
|
|
1759
1829
|
if (element.layer === layer) {
|
|
1760
1830
|
for (const glayer of [
|
|
@@ -1975,10 +2045,7 @@ var convertSoupToGerberCommands = (soup, opts = {}) => {
|
|
|
1975
2045
|
}
|
|
1976
2046
|
}
|
|
1977
2047
|
} else if (element.type === "pcb_board" && layer === "edgecut") {
|
|
1978
|
-
|
|
1979
|
-
if (board.pcb_panel_id) {
|
|
1980
|
-
continue;
|
|
1981
|
-
}
|
|
2048
|
+
if (hasPanel) continue;
|
|
1982
2049
|
const glayer = glayers.Edge_Cuts;
|
|
1983
2050
|
const { width, height, center, outline } = element;
|
|
1984
2051
|
const gerberBuild = gerberBuilder().add("select_aperture", {
|
|
@@ -2363,4 +2430,4 @@ export {
|
|
|
2363
2430
|
stringifyGerberCommands,
|
|
2364
2431
|
convertSoupToGerberCommands
|
|
2365
2432
|
};
|
|
2366
|
-
//# sourceMappingURL=chunk-
|
|
2433
|
+
//# sourceMappingURL=chunk-LRAY3J4M.js.map
|