circuit-json-to-gerber 0.0.69 → 0.0.71
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.
|
@@ -1112,7 +1112,17 @@ var define_aperture_template = defineGerberCommand({
|
|
|
1112
1112
|
if (macro_name === "HORZPILL" || macro_name === "VERTPILL") {
|
|
1113
1113
|
commandString += `${props.x_size.toFixed(6)}X${props.y_size.toFixed(6)}X${props.circle_diameter.toFixed(6)}X${props.circle_center_offset.toFixed(6)}`;
|
|
1114
1114
|
} else if (macro_name === "ROUNDRECT") {
|
|
1115
|
-
|
|
1115
|
+
commandString += [
|
|
1116
|
+
props.corner_radius,
|
|
1117
|
+
props.corner_1_x,
|
|
1118
|
+
props.corner_1_y,
|
|
1119
|
+
props.corner_2_x,
|
|
1120
|
+
props.corner_2_y,
|
|
1121
|
+
props.corner_3_x,
|
|
1122
|
+
props.corner_3_y,
|
|
1123
|
+
props.corner_4_x,
|
|
1124
|
+
props.corner_4_y
|
|
1125
|
+
].map((value) => value.toFixed(6)).join("X");
|
|
1116
1126
|
}
|
|
1117
1127
|
commandString += "*%";
|
|
1118
1128
|
return commandString;
|
|
@@ -1270,7 +1280,7 @@ var defineCommonMacros = (glayer) => {
|
|
|
1270
1280
|
0 $4 = Circle center offset
|
|
1271
1281
|
0 21 = Center Line(Exposure, Width, Height, Center X, Center Y, Rotation)*
|
|
1272
1282
|
0 1 = Circle(Exposure, Diameter, Center X, Center Y, Rotation)*
|
|
1273
|
-
21,1,$1,$2,0.0,0.0,0.0*
|
|
1283
|
+
21,1,$1-$3,$2,0.0,0.0,0.0*
|
|
1274
1284
|
1,1,$3,0.0-$4,0.0*
|
|
1275
1285
|
1,1,$3,$4,0.0*
|
|
1276
1286
|
`.trim()
|
|
@@ -1284,12 +1294,12 @@ var defineCommonMacros = (glayer) => {
|
|
|
1284
1294
|
0 $3 = Circle diameter (equal to width)*
|
|
1285
1295
|
0 $4 = Circle center offset
|
|
1286
1296
|
0 21 = Center Line(Exposure, Width, Height, Center X, Center Y, Rotation)*
|
|
1287
|
-
21,1,$1,$2,0.0,0.0,0.0*
|
|
1297
|
+
21,1,$1,$2-$3,0.0,0.0,0.0*
|
|
1288
1298
|
1,1,$3,0.0,0.0-$4*
|
|
1289
1299
|
1,1,$3,0.0,$4*
|
|
1290
1300
|
`.trim()
|
|
1291
1301
|
}).add("define_macro_aperture_template", {
|
|
1292
|
-
macro_name: "
|
|
1302
|
+
macro_name: "ROUNDRECT",
|
|
1293
1303
|
template_code: `
|
|
1294
1304
|
0 Rectangle with rounded corners*
|
|
1295
1305
|
0 $1 Corner radius*
|
|
@@ -1355,6 +1365,26 @@ var getLayerRefFromGerberLayerName = (glayer_name) => {
|
|
|
1355
1365
|
if (innerLayerMatch) return `inner${innerLayerMatch[1]}`;
|
|
1356
1366
|
throw new Error(`Could not infer layer ref from ${glayer_name}`);
|
|
1357
1367
|
};
|
|
1368
|
+
var getClampedRoundedRectCornerRadius = (width, height, cornerRadius) => {
|
|
1369
|
+
if (typeof cornerRadius !== "number") return 0;
|
|
1370
|
+
return Math.max(0, Math.min(cornerRadius, width / 2, height / 2));
|
|
1371
|
+
};
|
|
1372
|
+
var getRoundedRectApertureConfig = (width, height, cornerRadius) => {
|
|
1373
|
+
const halfWidth = width / 2;
|
|
1374
|
+
const halfHeight = height / 2;
|
|
1375
|
+
return {
|
|
1376
|
+
macro_name: "ROUNDRECT",
|
|
1377
|
+
corner_radius: cornerRadius,
|
|
1378
|
+
corner_1_x: -halfWidth + cornerRadius,
|
|
1379
|
+
corner_1_y: halfHeight - cornerRadius,
|
|
1380
|
+
corner_2_x: halfWidth - cornerRadius,
|
|
1381
|
+
corner_2_y: halfHeight - cornerRadius,
|
|
1382
|
+
corner_3_x: halfWidth - cornerRadius,
|
|
1383
|
+
corner_3_y: -halfHeight + cornerRadius,
|
|
1384
|
+
corner_4_x: -halfWidth + cornerRadius,
|
|
1385
|
+
corner_4_y: -halfHeight + cornerRadius
|
|
1386
|
+
};
|
|
1387
|
+
};
|
|
1358
1388
|
function defineAperturesForLayer({
|
|
1359
1389
|
glayer,
|
|
1360
1390
|
circuitJson,
|
|
@@ -1408,6 +1438,16 @@ var REGION_APERTURE_CONFIG = {
|
|
|
1408
1438
|
diameter: 1e-3
|
|
1409
1439
|
};
|
|
1410
1440
|
var getApertureConfigFromPcbSmtpad = (elm) => {
|
|
1441
|
+
if (elm.shape === "rect" || elm.shape === "rotated_rect") {
|
|
1442
|
+
const cornerRadius = getClampedRoundedRectCornerRadius(
|
|
1443
|
+
elm.width,
|
|
1444
|
+
elm.height,
|
|
1445
|
+
"corner_radius" in elm ? elm.corner_radius : void 0
|
|
1446
|
+
);
|
|
1447
|
+
if (cornerRadius > 0) {
|
|
1448
|
+
return getRoundedRectApertureConfig(elm.width, elm.height, cornerRadius);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1411
1451
|
if (elm.shape === "rect") {
|
|
1412
1452
|
return {
|
|
1413
1453
|
standard_template_code: "R",
|
|
@@ -1428,27 +1468,15 @@ var getApertureConfigFromPcbSmtpad = (elm) => {
|
|
|
1428
1468
|
y_size: elm.height
|
|
1429
1469
|
};
|
|
1430
1470
|
}
|
|
1431
|
-
if (elm.shape === "pill") {
|
|
1471
|
+
if (elm.shape === "pill" || elm.shape === "rotated_pill") {
|
|
1432
1472
|
if (!("width" in elm && "height" in elm)) {
|
|
1433
1473
|
throw new Error(
|
|
1434
1474
|
"Invalid pill shape in getApertureConfigFromPcbSmtpad: missing dimensions"
|
|
1435
1475
|
);
|
|
1436
1476
|
}
|
|
1437
|
-
if (elm.width >= elm.height) {
|
|
1438
|
-
return {
|
|
1439
|
-
macro_name: "HORZPILL",
|
|
1440
|
-
x_size: elm.width,
|
|
1441
|
-
y_size: elm.height,
|
|
1442
|
-
circle_diameter: Math.min(elm.width, elm.height),
|
|
1443
|
-
circle_center_offset: elm.width / 2
|
|
1444
|
-
};
|
|
1445
|
-
}
|
|
1446
1477
|
return {
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
y_size: elm.height,
|
|
1450
|
-
circle_diameter: Math.min(elm.width, elm.height),
|
|
1451
|
-
circle_center_offset: elm.height / 2
|
|
1478
|
+
standard_template_code: "C",
|
|
1479
|
+
diameter: Math.min(elm.width, elm.height)
|
|
1452
1480
|
};
|
|
1453
1481
|
}
|
|
1454
1482
|
if (elm.shape === "polygon") {
|
|
@@ -1461,6 +1489,18 @@ var getApertureConfigFromPcbSmtpadSoldermask = (elm) => {
|
|
|
1461
1489
|
if ("soldermask_margin" in elm && typeof elm.soldermask_margin === "number") {
|
|
1462
1490
|
soldermaskMargin = elm.soldermask_margin;
|
|
1463
1491
|
}
|
|
1492
|
+
if (elm.shape === "rect" || elm.shape === "rotated_rect") {
|
|
1493
|
+
const width = elm.width + soldermaskMargin * 2;
|
|
1494
|
+
const height = elm.height + soldermaskMargin * 2;
|
|
1495
|
+
const cornerRadius = getClampedRoundedRectCornerRadius(
|
|
1496
|
+
width,
|
|
1497
|
+
height,
|
|
1498
|
+
"corner_radius" in elm && typeof elm.corner_radius === "number" ? elm.corner_radius + soldermaskMargin : void 0
|
|
1499
|
+
);
|
|
1500
|
+
if (cornerRadius > 0) {
|
|
1501
|
+
return getRoundedRectApertureConfig(width, height, cornerRadius);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1464
1504
|
if (elm.shape === "rect") {
|
|
1465
1505
|
return {
|
|
1466
1506
|
standard_template_code: "R",
|
|
@@ -1481,7 +1521,7 @@ var getApertureConfigFromPcbSmtpadSoldermask = (elm) => {
|
|
|
1481
1521
|
y_size: elm.height + soldermaskMargin * 2
|
|
1482
1522
|
};
|
|
1483
1523
|
}
|
|
1484
|
-
if (elm.shape === "pill") {
|
|
1524
|
+
if (elm.shape === "pill" || elm.shape === "rotated_pill") {
|
|
1485
1525
|
if (!("width" in elm && "height" in elm)) {
|
|
1486
1526
|
throw new Error(
|
|
1487
1527
|
"Invalid pill shape in getApertureConfigFromPcbSmtpadSoldermask: missing dimensions"
|
|
@@ -1489,21 +1529,9 @@ var getApertureConfigFromPcbSmtpadSoldermask = (elm) => {
|
|
|
1489
1529
|
}
|
|
1490
1530
|
const width = elm.width + soldermaskMargin * 2;
|
|
1491
1531
|
const height = elm.height + soldermaskMargin * 2;
|
|
1492
|
-
if (width >= height) {
|
|
1493
|
-
return {
|
|
1494
|
-
macro_name: "HORZPILL",
|
|
1495
|
-
x_size: width,
|
|
1496
|
-
y_size: height,
|
|
1497
|
-
circle_diameter: Math.min(width, height),
|
|
1498
|
-
circle_center_offset: width / 2
|
|
1499
|
-
};
|
|
1500
|
-
}
|
|
1501
1532
|
return {
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
y_size: height,
|
|
1505
|
-
circle_diameter: Math.min(width, height),
|
|
1506
|
-
circle_center_offset: height / 2
|
|
1533
|
+
standard_template_code: "C",
|
|
1534
|
+
diameter: Math.min(width, height)
|
|
1507
1535
|
};
|
|
1508
1536
|
}
|
|
1509
1537
|
if (elm.shape === "polygon") {
|
|
@@ -1573,7 +1601,7 @@ var getApertureConfigFromPcbSolderPaste = (elm) => {
|
|
|
1573
1601
|
x_size: elm.width,
|
|
1574
1602
|
y_size: elm.height,
|
|
1575
1603
|
circle_diameter: Math.min(elm.width, elm.height),
|
|
1576
|
-
circle_center_offset: elm.width / 2
|
|
1604
|
+
circle_center_offset: (elm.width - elm.height) / 2
|
|
1577
1605
|
};
|
|
1578
1606
|
}
|
|
1579
1607
|
return {
|
|
@@ -1581,7 +1609,7 @@ var getApertureConfigFromPcbSolderPaste = (elm) => {
|
|
|
1581
1609
|
x_size: elm.width,
|
|
1582
1610
|
y_size: elm.height,
|
|
1583
1611
|
circle_diameter: Math.min(elm.width, elm.height),
|
|
1584
|
-
circle_center_offset: elm.height / 2
|
|
1612
|
+
circle_center_offset: (elm.height - elm.width) / 2
|
|
1585
1613
|
};
|
|
1586
1614
|
}
|
|
1587
1615
|
throw new Error(`Unsupported shape ${elm.shape}`);
|
|
@@ -1610,7 +1638,7 @@ var getApertureConfigFromPcbPlatedHole = (elm) => {
|
|
|
1610
1638
|
x_size: elm.outer_width,
|
|
1611
1639
|
y_size: elm.outer_height,
|
|
1612
1640
|
circle_diameter: Math.min(elm.outer_width, elm.outer_height),
|
|
1613
|
-
circle_center_offset: elm.outer_width / 2
|
|
1641
|
+
circle_center_offset: (elm.outer_width - elm.outer_height) / 2
|
|
1614
1642
|
};
|
|
1615
1643
|
}
|
|
1616
1644
|
return {
|
|
@@ -1618,7 +1646,7 @@ var getApertureConfigFromPcbPlatedHole = (elm) => {
|
|
|
1618
1646
|
x_size: elm.outer_width,
|
|
1619
1647
|
y_size: elm.outer_height,
|
|
1620
1648
|
circle_diameter: Math.min(elm.outer_width, elm.outer_height),
|
|
1621
|
-
circle_center_offset: elm.outer_height / 2
|
|
1649
|
+
circle_center_offset: (elm.outer_height - elm.outer_width) / 2
|
|
1622
1650
|
};
|
|
1623
1651
|
}
|
|
1624
1652
|
const shape = elm.shape;
|
|
@@ -1668,7 +1696,7 @@ var getApertureConfigFromPcbPlatedHoleSoldermask = (elm) => {
|
|
|
1668
1696
|
x_size: outerWidth,
|
|
1669
1697
|
y_size: outerHeight,
|
|
1670
1698
|
circle_diameter: Math.min(outerWidth, outerHeight),
|
|
1671
|
-
circle_center_offset: outerWidth / 2
|
|
1699
|
+
circle_center_offset: (outerWidth - outerHeight) / 2
|
|
1672
1700
|
};
|
|
1673
1701
|
}
|
|
1674
1702
|
return {
|
|
@@ -1676,7 +1704,7 @@ var getApertureConfigFromPcbPlatedHoleSoldermask = (elm) => {
|
|
|
1676
1704
|
x_size: outerWidth,
|
|
1677
1705
|
y_size: outerHeight,
|
|
1678
1706
|
circle_diameter: Math.min(outerWidth, outerHeight),
|
|
1679
|
-
circle_center_offset: outerHeight / 2
|
|
1707
|
+
circle_center_offset: (outerHeight - outerWidth) / 2
|
|
1680
1708
|
};
|
|
1681
1709
|
}
|
|
1682
1710
|
const shape = elm.shape;
|
|
@@ -1864,7 +1892,7 @@ var findApertureNumber = (glayer, search_params) => {
|
|
|
1864
1892
|
// package.json
|
|
1865
1893
|
var package_default = {
|
|
1866
1894
|
name: "circuit-json-to-gerber",
|
|
1867
|
-
version: "0.0.
|
|
1895
|
+
version: "0.0.70",
|
|
1868
1896
|
main: "dist/index.js",
|
|
1869
1897
|
type: "module",
|
|
1870
1898
|
scripts: {
|
|
@@ -2097,6 +2125,55 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
2097
2125
|
}).build()
|
|
2098
2126
|
);
|
|
2099
2127
|
const mfy = (y) => opts.flip_y_axis ? -y : y;
|
|
2128
|
+
const renderPillFlash = ({
|
|
2129
|
+
glayer,
|
|
2130
|
+
x,
|
|
2131
|
+
y,
|
|
2132
|
+
width,
|
|
2133
|
+
height,
|
|
2134
|
+
rotationDegrees = 0
|
|
2135
|
+
}) => {
|
|
2136
|
+
const circleApertureConfig = {
|
|
2137
|
+
standard_template_code: "C",
|
|
2138
|
+
diameter: Math.min(width, height)
|
|
2139
|
+
};
|
|
2140
|
+
const apertureNumber = findApertureNumber(glayer, circleApertureConfig);
|
|
2141
|
+
const gb = gerberBuilder().add("select_aperture", {
|
|
2142
|
+
aperture_number: apertureNumber
|
|
2143
|
+
});
|
|
2144
|
+
const offset = Math.abs(width - height) / 2;
|
|
2145
|
+
const rotationRadians = rotationDegrees * Math.PI / 180;
|
|
2146
|
+
const cosTheta = Math.cos(rotationRadians);
|
|
2147
|
+
const sinTheta = Math.sin(rotationRadians);
|
|
2148
|
+
const rotateAndTranslate = (dx, dy) => ({
|
|
2149
|
+
x: x + dx * cosTheta - dy * sinTheta,
|
|
2150
|
+
y: y + dx * sinTheta + dy * cosTheta
|
|
2151
|
+
});
|
|
2152
|
+
if (offset <= 1e-9) {
|
|
2153
|
+
gb.add("flash_operation", { x, y: mfy(y) });
|
|
2154
|
+
glayer.push(...gb.build());
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2157
|
+
const isHorizontal = width >= height;
|
|
2158
|
+
const startRelative = isHorizontal ? { x: -offset, y: 0 } : { x: 0, y: -offset };
|
|
2159
|
+
const endRelative = isHorizontal ? { x: offset, y: 0 } : { x: 0, y: offset };
|
|
2160
|
+
const startPoint = rotateAndTranslate(startRelative.x, startRelative.y);
|
|
2161
|
+
const endPoint = rotateAndTranslate(endRelative.x, endRelative.y);
|
|
2162
|
+
gb.add("flash_operation", {
|
|
2163
|
+
x: startPoint.x,
|
|
2164
|
+
y: mfy(startPoint.y)
|
|
2165
|
+
}).add("move_operation", {
|
|
2166
|
+
x: startPoint.x,
|
|
2167
|
+
y: mfy(startPoint.y)
|
|
2168
|
+
}).add("plot_operation", {
|
|
2169
|
+
x: endPoint.x,
|
|
2170
|
+
y: mfy(endPoint.y)
|
|
2171
|
+
}).add("flash_operation", {
|
|
2172
|
+
x: endPoint.x,
|
|
2173
|
+
y: mfy(endPoint.y)
|
|
2174
|
+
});
|
|
2175
|
+
glayer.push(...gb.build());
|
|
2176
|
+
};
|
|
2100
2177
|
const getRegionApertureNumber = (glayer) => findApertureNumber(glayer, REGION_APERTURE_CONFIG);
|
|
2101
2178
|
const addClosedRegionFromPoints = ({
|
|
2102
2179
|
target,
|
|
@@ -2550,6 +2627,28 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
2550
2627
|
);
|
|
2551
2628
|
} else if (element.type === "pcb_smtpad" && element.shape !== "polygon") {
|
|
2552
2629
|
if (element.layer === layer && outerLayerRefs.includes(layer)) {
|
|
2630
|
+
if (element.shape === "pill" || element.shape === "rotated_pill") {
|
|
2631
|
+
const soldermaskMargin = typeof element.soldermask_margin === "number" ? element.soldermask_margin : 0;
|
|
2632
|
+
const rotation2 = element.shape === "rotated_pill" && typeof element.ccw_rotation === "number" ? element.ccw_rotation : 0;
|
|
2633
|
+
renderPillFlash({
|
|
2634
|
+
glayer: glayers[getGerberLayerName(layer, "copper")],
|
|
2635
|
+
x: element.x,
|
|
2636
|
+
y: element.y,
|
|
2637
|
+
width: element.width,
|
|
2638
|
+
height: element.height,
|
|
2639
|
+
rotationDegrees: rotation2
|
|
2640
|
+
});
|
|
2641
|
+
renderPillFlash({
|
|
2642
|
+
glayer: glayers[getGerberLayerName(layer, "soldermask")],
|
|
2643
|
+
x: element.x,
|
|
2644
|
+
y: element.y,
|
|
2645
|
+
width: element.width + soldermaskMargin * 2,
|
|
2646
|
+
height: element.height + soldermaskMargin * 2,
|
|
2647
|
+
rotationDegrees: rotation2
|
|
2648
|
+
});
|
|
2649
|
+
continue;
|
|
2650
|
+
}
|
|
2651
|
+
const rotation = element.shape === "rotated_rect" && typeof element.ccw_rotation === "number" ? element.ccw_rotation : 0;
|
|
2553
2652
|
for (const { glayer, apertureConfig } of [
|
|
2554
2653
|
{
|
|
2555
2654
|
glayer: glayers[getGerberLayerName(layer, "copper")],
|
|
@@ -2564,13 +2663,13 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
2564
2663
|
const gb = gerberBuilder().add("select_aperture", {
|
|
2565
2664
|
aperture_number: apertureNumber
|
|
2566
2665
|
});
|
|
2567
|
-
if (
|
|
2666
|
+
if (rotation) {
|
|
2568
2667
|
gb.add("load_rotation", {
|
|
2569
|
-
rotation_degrees:
|
|
2668
|
+
rotation_degrees: rotation
|
|
2570
2669
|
});
|
|
2571
2670
|
}
|
|
2572
2671
|
gb.add("flash_operation", { x: element.x, y: mfy(element.y) });
|
|
2573
|
-
if (
|
|
2672
|
+
if (rotation) {
|
|
2574
2673
|
gb.add("load_rotation", { rotation_degrees: 0 });
|
|
2575
2674
|
}
|
|
2576
2675
|
glayer.push(...gb.build());
|
|
@@ -3032,4 +3131,4 @@ export {
|
|
|
3032
3131
|
stringifyGerberCommands,
|
|
3033
3132
|
convertSoupToGerberCommands
|
|
3034
3133
|
};
|
|
3035
|
-
//# sourceMappingURL=chunk-
|
|
3134
|
+
//# sourceMappingURL=chunk-4OKFNZE6.js.map
|