circuit-json-to-gerber 0.0.81 → 0.0.82
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.
|
@@ -1329,6 +1329,134 @@ var defineCommonMacros = (glayer) => {
|
|
|
1329
1329
|
);
|
|
1330
1330
|
};
|
|
1331
1331
|
|
|
1332
|
+
// src/gerber/convert-soup-to-gerber-commands/getSilkscreenShapeStroke.ts
|
|
1333
|
+
import {
|
|
1334
|
+
applyToPoint,
|
|
1335
|
+
compose,
|
|
1336
|
+
identity,
|
|
1337
|
+
rotate,
|
|
1338
|
+
translate
|
|
1339
|
+
} from "transformation-matrix";
|
|
1340
|
+
var SILKSCREEN_SHAPE_TYPES = [
|
|
1341
|
+
"pcb_silkscreen_line",
|
|
1342
|
+
"pcb_silkscreen_rect",
|
|
1343
|
+
"pcb_silkscreen_circle",
|
|
1344
|
+
"pcb_silkscreen_oval",
|
|
1345
|
+
"pcb_silkscreen_pill"
|
|
1346
|
+
];
|
|
1347
|
+
var isSilkscreenShape = (element) => SILKSCREEN_SHAPE_TYPES.includes(element.type);
|
|
1348
|
+
var DEFAULT_STROKE_WIDTH = 0.1;
|
|
1349
|
+
var ELLIPSE_SEGMENTS = 48;
|
|
1350
|
+
var CORNER_SEGMENTS = 12;
|
|
1351
|
+
var rotationAboutCenter = (center, ccwDegrees) => ccwDegrees ? compose(
|
|
1352
|
+
translate(center.x, center.y),
|
|
1353
|
+
rotate(ccwDegrees * Math.PI / 180),
|
|
1354
|
+
translate(-center.x, -center.y)
|
|
1355
|
+
) : identity();
|
|
1356
|
+
var ellipseRoute = (center, radiusX, radiusY, ccwDegrees = 0) => {
|
|
1357
|
+
const matrix = rotationAboutCenter(center, ccwDegrees);
|
|
1358
|
+
return Array.from({ length: ELLIPSE_SEGMENTS + 1 }, (_, i) => {
|
|
1359
|
+
const angle = i / ELLIPSE_SEGMENTS * Math.PI * 2;
|
|
1360
|
+
return applyToPoint(matrix, {
|
|
1361
|
+
x: center.x + radiusX * Math.cos(angle),
|
|
1362
|
+
y: center.y + radiusY * Math.sin(angle)
|
|
1363
|
+
});
|
|
1364
|
+
});
|
|
1365
|
+
};
|
|
1366
|
+
var rectangleRoute = (center, width, height, cornerRadius, ccwDegrees = 0) => {
|
|
1367
|
+
const halfW = width / 2;
|
|
1368
|
+
const halfH = height / 2;
|
|
1369
|
+
const route = [];
|
|
1370
|
+
if (cornerRadius <= 0) {
|
|
1371
|
+
route.push(
|
|
1372
|
+
{ x: center.x - halfW, y: center.y - halfH },
|
|
1373
|
+
{ x: center.x + halfW, y: center.y - halfH },
|
|
1374
|
+
{ x: center.x + halfW, y: center.y + halfH },
|
|
1375
|
+
{ x: center.x - halfW, y: center.y + halfH }
|
|
1376
|
+
);
|
|
1377
|
+
} else {
|
|
1378
|
+
const insetW = halfW - cornerRadius;
|
|
1379
|
+
const insetH = halfH - cornerRadius;
|
|
1380
|
+
const corners = [
|
|
1381
|
+
{ x: center.x + insetW, y: center.y + insetH, start: 0 },
|
|
1382
|
+
{ x: center.x - insetW, y: center.y + insetH, start: Math.PI / 2 },
|
|
1383
|
+
{ x: center.x - insetW, y: center.y - insetH, start: Math.PI },
|
|
1384
|
+
{ x: center.x + insetW, y: center.y - insetH, start: 3 * Math.PI / 2 }
|
|
1385
|
+
];
|
|
1386
|
+
for (const corner of corners) {
|
|
1387
|
+
for (let i = 0; i <= CORNER_SEGMENTS; i++) {
|
|
1388
|
+
const angle = corner.start + i / CORNER_SEGMENTS * (Math.PI / 2);
|
|
1389
|
+
route.push({
|
|
1390
|
+
x: corner.x + cornerRadius * Math.cos(angle),
|
|
1391
|
+
y: corner.y + cornerRadius * Math.sin(angle)
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
route.push(route[0]);
|
|
1397
|
+
const matrix = rotationAboutCenter(center, ccwDegrees);
|
|
1398
|
+
return route.map((point) => applyToPoint(matrix, point));
|
|
1399
|
+
};
|
|
1400
|
+
var clampCornerRadius = (width, height, cornerRadius) => {
|
|
1401
|
+
if (typeof cornerRadius !== "number" || cornerRadius <= 0) return 0;
|
|
1402
|
+
return Math.min(cornerRadius, width / 2, height / 2);
|
|
1403
|
+
};
|
|
1404
|
+
var getSilkscreenShapeStroke = (element) => {
|
|
1405
|
+
const strokeWidth = element.stroke_width ?? DEFAULT_STROKE_WIDTH;
|
|
1406
|
+
switch (element.type) {
|
|
1407
|
+
case "pcb_silkscreen_line":
|
|
1408
|
+
return {
|
|
1409
|
+
route: [
|
|
1410
|
+
{ x: element.x1, y: element.y1 },
|
|
1411
|
+
{ x: element.x2, y: element.y2 }
|
|
1412
|
+
],
|
|
1413
|
+
strokeWidth
|
|
1414
|
+
};
|
|
1415
|
+
case "pcb_silkscreen_rect":
|
|
1416
|
+
return {
|
|
1417
|
+
route: rectangleRoute(
|
|
1418
|
+
element.center,
|
|
1419
|
+
element.width,
|
|
1420
|
+
element.height,
|
|
1421
|
+
clampCornerRadius(
|
|
1422
|
+
element.width,
|
|
1423
|
+
element.height,
|
|
1424
|
+
element.corner_radius
|
|
1425
|
+
),
|
|
1426
|
+
element.ccw_rotation ?? 0
|
|
1427
|
+
),
|
|
1428
|
+
strokeWidth
|
|
1429
|
+
};
|
|
1430
|
+
case "pcb_silkscreen_circle":
|
|
1431
|
+
return {
|
|
1432
|
+
route: ellipseRoute(element.center, element.radius, element.radius),
|
|
1433
|
+
strokeWidth
|
|
1434
|
+
};
|
|
1435
|
+
case "pcb_silkscreen_oval":
|
|
1436
|
+
return {
|
|
1437
|
+
route: ellipseRoute(
|
|
1438
|
+
element.center,
|
|
1439
|
+
element.radius_x,
|
|
1440
|
+
element.radius_y,
|
|
1441
|
+
element.ccw_rotation ?? 0
|
|
1442
|
+
),
|
|
1443
|
+
strokeWidth
|
|
1444
|
+
};
|
|
1445
|
+
case "pcb_silkscreen_pill":
|
|
1446
|
+
return {
|
|
1447
|
+
route: rectangleRoute(
|
|
1448
|
+
element.center,
|
|
1449
|
+
element.width,
|
|
1450
|
+
element.height,
|
|
1451
|
+
Math.min(element.width, element.height) / 2
|
|
1452
|
+
),
|
|
1453
|
+
strokeWidth
|
|
1454
|
+
};
|
|
1455
|
+
default:
|
|
1456
|
+
return null;
|
|
1457
|
+
}
|
|
1458
|
+
};
|
|
1459
|
+
|
|
1332
1460
|
// src/gerber/convert-soup-to-gerber-commands/defineAperturesForLayer.ts
|
|
1333
1461
|
import stableStringify from "fast-json-stable-stringify";
|
|
1334
1462
|
|
|
@@ -1878,6 +2006,20 @@ function getAllApertureTemplateConfigsForLayer({
|
|
|
1878
2006
|
} else if (elm.type === "pcb_silkscreen_path") {
|
|
1879
2007
|
if (!isFabricationLayer)
|
|
1880
2008
|
addConfigIfNew(getApertureConfigFromPcbSilkscreenPath(elm));
|
|
2009
|
+
} else if (isSilkscreenShape(elm)) {
|
|
2010
|
+
if (!isFabricationLayer) {
|
|
2011
|
+
addConfigIfNew({
|
|
2012
|
+
standard_template_code: "C",
|
|
2013
|
+
diameter: elm.stroke_width ?? 0.1
|
|
2014
|
+
});
|
|
2015
|
+
if (elm.is_filled === true) {
|
|
2016
|
+
addConfigIfNew(REGION_APERTURE_CONFIG);
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
} else if (elm.type === "pcb_silkscreen_graphic") {
|
|
2020
|
+
if (glayer_name.endsWith("_SilkScreen")) {
|
|
2021
|
+
addConfigIfNew(REGION_APERTURE_CONFIG);
|
|
2022
|
+
}
|
|
1881
2023
|
} else if (elm.type === "pcb_silkscreen_text") {
|
|
1882
2024
|
if (!isFabricationLayer)
|
|
1883
2025
|
addConfigIfNew(getApertureConfigFromPcbSilkscreenText(elm));
|
|
@@ -1953,7 +2095,7 @@ var findApertureNumber = (glayer, search_params) => {
|
|
|
1953
2095
|
// package.json
|
|
1954
2096
|
var package_default = {
|
|
1955
2097
|
name: "circuit-json-to-gerber",
|
|
1956
|
-
version: "0.0.
|
|
2098
|
+
version: "0.0.81",
|
|
1957
2099
|
main: "dist/index.js",
|
|
1958
2100
|
type: "module",
|
|
1959
2101
|
scripts: {
|
|
@@ -2164,11 +2306,11 @@ var offsetPolygonOutline = (points, offset) => {
|
|
|
2164
2306
|
// src/gerber/convert-soup-to-gerber-commands/index.ts
|
|
2165
2307
|
import { lineAlphabet } from "@tscircuit/alphabet";
|
|
2166
2308
|
import {
|
|
2167
|
-
applyToPoint,
|
|
2168
|
-
compose,
|
|
2169
|
-
identity,
|
|
2170
|
-
rotate,
|
|
2171
|
-
translate
|
|
2309
|
+
applyToPoint as applyToPoint2,
|
|
2310
|
+
compose as compose2,
|
|
2311
|
+
identity as identity2,
|
|
2312
|
+
rotate as rotate2,
|
|
2313
|
+
translate as translate2
|
|
2172
2314
|
} from "transformation-matrix";
|
|
2173
2315
|
|
|
2174
2316
|
// src/gerber/convert-soup-to-gerber-commands/fabricationLayerRefs.ts
|
|
@@ -2597,18 +2739,18 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
2597
2739
|
const shouldMirror = element.is_mirrored !== void 0 ? element.is_mirrored : element.layer === "bottom";
|
|
2598
2740
|
if (shouldMirror) {
|
|
2599
2741
|
transforms.push(
|
|
2600
|
-
|
|
2742
|
+
translate2(cx, cy),
|
|
2601
2743
|
{ a: -1, b: 0, c: 0, d: 1, e: 0, f: 0 },
|
|
2602
|
-
|
|
2744
|
+
translate2(-cx, -cy)
|
|
2603
2745
|
);
|
|
2604
2746
|
rotation = -rotation;
|
|
2605
2747
|
}
|
|
2606
2748
|
if (rotation) {
|
|
2607
2749
|
const rad = rotation * Math.PI / 180;
|
|
2608
|
-
transforms.push(
|
|
2750
|
+
transforms.push(translate2(cx, cy), rotate2(rad), translate2(-cx, -cy));
|
|
2609
2751
|
}
|
|
2610
|
-
const transformMatrix = transforms.length > 0 ?
|
|
2611
|
-
const applyTransform = (point) => transformMatrix ?
|
|
2752
|
+
const transformMatrix = transforms.length > 0 ? compose2(...transforms) : void 0;
|
|
2753
|
+
const applyTransform = (point) => transformMatrix ? applyToPoint2(transformMatrix, point) : point;
|
|
2612
2754
|
if (element.is_knockout) {
|
|
2613
2755
|
const padding = element.knockout_padding ?? {
|
|
2614
2756
|
left: 0.2,
|
|
@@ -2797,17 +2939,17 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
2797
2939
|
{ x: -w, y: -h }
|
|
2798
2940
|
// Bottom-left
|
|
2799
2941
|
];
|
|
2800
|
-
let transformMatrix =
|
|
2942
|
+
let transformMatrix = identity2();
|
|
2801
2943
|
if (rotation) {
|
|
2802
2944
|
const angle_rad = rotation * Math.PI / 180;
|
|
2803
|
-
transformMatrix =
|
|
2945
|
+
transformMatrix = rotate2(angle_rad);
|
|
2804
2946
|
}
|
|
2805
|
-
transformMatrix =
|
|
2806
|
-
|
|
2947
|
+
transformMatrix = compose2(
|
|
2948
|
+
translate2(center.x, center.y),
|
|
2807
2949
|
transformMatrix
|
|
2808
2950
|
);
|
|
2809
2951
|
const transformedPoints = points.map(
|
|
2810
|
-
(p) =>
|
|
2952
|
+
(p) => applyToPoint2(transformMatrix, p)
|
|
2811
2953
|
);
|
|
2812
2954
|
const regionApertureNumber = getRegionApertureNumber(copper_glayer);
|
|
2813
2955
|
const rect_builder = gerberBuilder().add("select_aperture", { aperture_number: regionApertureNumber }).add("start_region_statement", {});
|
|
@@ -2931,6 +3073,69 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
2931
3073
|
}
|
|
2932
3074
|
glayer.push(...gerber.build());
|
|
2933
3075
|
}
|
|
3076
|
+
} else if (isSilkscreenShape(element) && isOuterLayerRef(layer)) {
|
|
3077
|
+
if (element.layer === layer) {
|
|
3078
|
+
const stroke = getSilkscreenShapeStroke(element);
|
|
3079
|
+
if (stroke) {
|
|
3080
|
+
const glayer = glayers[getGerberLayerName(layer, "silkscreen")];
|
|
3081
|
+
const isFilled = element.is_filled === true;
|
|
3082
|
+
const isStroked = element.has_stroke !== false;
|
|
3083
|
+
if (isFilled) {
|
|
3084
|
+
addClosedRegionFromPoints({
|
|
3085
|
+
target: glayer,
|
|
3086
|
+
apertureSource: glayer,
|
|
3087
|
+
points: stroke.route
|
|
3088
|
+
});
|
|
3089
|
+
}
|
|
3090
|
+
if (isStroked) {
|
|
3091
|
+
renderOpenPath({
|
|
3092
|
+
element: {
|
|
3093
|
+
type: element.type,
|
|
3094
|
+
stroke_width: stroke.strokeWidth,
|
|
3095
|
+
is_stroke_dashed: element.is_stroke_dashed
|
|
3096
|
+
},
|
|
3097
|
+
glayer,
|
|
3098
|
+
apertureConfig: {
|
|
3099
|
+
standard_template_code: "C",
|
|
3100
|
+
diameter: stroke.strokeWidth
|
|
3101
|
+
},
|
|
3102
|
+
route: stroke.route,
|
|
3103
|
+
mapY: mfy
|
|
3104
|
+
});
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
} else if (
|
|
3109
|
+
// pcb_silkscreen_graphic is newer than this repo's pinned circuit-json,
|
|
3110
|
+
// so it isn't in the AnyCircuitElement union yet — match it structurally.
|
|
3111
|
+
element.type === "pcb_silkscreen_graphic" && isOuterLayerRef(layer)
|
|
3112
|
+
) {
|
|
3113
|
+
const graphic = element;
|
|
3114
|
+
if (graphic.layer === layer && graphic.brep_shape) {
|
|
3115
|
+
const glayer = glayers[getGerberLayerName(layer, "silkscreen")];
|
|
3116
|
+
const { outer_ring, inner_rings } = graphic.brep_shape;
|
|
3117
|
+
const regionApertureNumber = getRegionApertureNumber(glayer);
|
|
3118
|
+
const outerBuilder = gerberBuilder().add("select_aperture", { aperture_number: regionApertureNumber }).add("start_region_statement", {});
|
|
3119
|
+
drawRingToBuilder(outerBuilder, reverseRing(outer_ring));
|
|
3120
|
+
outerBuilder.add("end_region_statement", {});
|
|
3121
|
+
glayer.push(...outerBuilder.build());
|
|
3122
|
+
if (inner_rings && inner_rings.length > 0) {
|
|
3123
|
+
glayer.push(
|
|
3124
|
+
...gerberBuilder().add("set_layer_polarity", { polarity: "C" }).build()
|
|
3125
|
+
);
|
|
3126
|
+
for (const inner_ring of inner_rings) {
|
|
3127
|
+
const innerBuilder = gerberBuilder().add("select_aperture", {
|
|
3128
|
+
aperture_number: regionApertureNumber
|
|
3129
|
+
}).add("start_region_statement", {});
|
|
3130
|
+
drawRingToBuilder(innerBuilder, inner_ring);
|
|
3131
|
+
innerBuilder.add("end_region_statement", {});
|
|
3132
|
+
glayer.push(...innerBuilder.build());
|
|
3133
|
+
}
|
|
3134
|
+
glayer.push(
|
|
3135
|
+
...gerberBuilder().add("set_layer_polarity", { polarity: "D" }).build()
|
|
3136
|
+
);
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
2934
3139
|
} else if (element.type === "pcb_silkscreen_text" && isOuterLayerRef(layer)) {
|
|
2935
3140
|
renderVectorText(
|
|
2936
3141
|
element,
|
|
@@ -3371,23 +3576,23 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
3371
3576
|
Math.min(corner_radius ?? 0, Math.abs(w), Math.abs(h))
|
|
3372
3577
|
);
|
|
3373
3578
|
const makeTransformMatrix = () => {
|
|
3374
|
-
let transformMatrix2 =
|
|
3579
|
+
let transformMatrix2 = identity2();
|
|
3375
3580
|
if (rotation) {
|
|
3376
3581
|
const angle_rad = rotation * Math.PI / 180;
|
|
3377
|
-
transformMatrix2 =
|
|
3582
|
+
transformMatrix2 = rotate2(angle_rad);
|
|
3378
3583
|
}
|
|
3379
|
-
return
|
|
3584
|
+
return compose2(translate2(center.x, center.y), transformMatrix2);
|
|
3380
3585
|
};
|
|
3381
3586
|
const transformMatrix = makeTransformMatrix();
|
|
3382
3587
|
if (r > 0) {
|
|
3383
3588
|
const startPoint = { x: -w + r, y: h };
|
|
3384
|
-
let currentPoint =
|
|
3589
|
+
let currentPoint = applyToPoint2(transformMatrix, startPoint);
|
|
3385
3590
|
cutout_builder.add("move_operation", {
|
|
3386
3591
|
x: currentPoint.x,
|
|
3387
3592
|
y: mfy(currentPoint.y)
|
|
3388
3593
|
});
|
|
3389
3594
|
const addLine = (point) => {
|
|
3390
|
-
const transformedPoint =
|
|
3595
|
+
const transformedPoint = applyToPoint2(transformMatrix, point);
|
|
3391
3596
|
cutout_builder.add("plot_operation", {
|
|
3392
3597
|
x: transformedPoint.x,
|
|
3393
3598
|
y: mfy(transformedPoint.y)
|
|
@@ -3395,11 +3600,11 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
3395
3600
|
currentPoint = transformedPoint;
|
|
3396
3601
|
};
|
|
3397
3602
|
const addArc = (options) => {
|
|
3398
|
-
const transformedPoint =
|
|
3603
|
+
const transformedPoint = applyToPoint2(
|
|
3399
3604
|
transformMatrix,
|
|
3400
3605
|
options.point
|
|
3401
3606
|
);
|
|
3402
|
-
const transformedCenter =
|
|
3607
|
+
const transformedCenter = applyToPoint2(
|
|
3403
3608
|
transformMatrix,
|
|
3404
3609
|
options.center
|
|
3405
3610
|
);
|
|
@@ -3443,7 +3648,7 @@ var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
|
3443
3648
|
// Bottom-left
|
|
3444
3649
|
];
|
|
3445
3650
|
const transformedPoints = points.map(
|
|
3446
|
-
(p) =>
|
|
3651
|
+
(p) => applyToPoint2(transformMatrix, p)
|
|
3447
3652
|
);
|
|
3448
3653
|
cutout_builder.add("move_operation", {
|
|
3449
3654
|
x: transformedPoints[0].x,
|
|
@@ -3521,4 +3726,4 @@ export {
|
|
|
3521
3726
|
stringifyGerberCommands,
|
|
3522
3727
|
convertSoupToGerberCommands
|
|
3523
3728
|
};
|
|
3524
|
-
//# sourceMappingURL=chunk-
|
|
3729
|
+
//# sourceMappingURL=chunk-7LG6NVYJ.js.map
|