circuit-json-to-gerber 0.0.55 → 0.0.56
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-64R4GN2C.js → chunk-6BPSJ3NY.js} +181 -11
- package/dist/chunk-6BPSJ3NY.js.map +1 -0
- package/dist/cli.js +12 -14
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +13 -4
- package/dist/index.js +3 -1
- package/package.json +1 -1
- package/dist/chunk-64R4GN2C.js.map +0 -1
|
@@ -292,12 +292,117 @@ var ExcellonDrillBuilder = class {
|
|
|
292
292
|
var excellonDrill = () => new ExcellonDrillBuilder();
|
|
293
293
|
|
|
294
294
|
// src/excellon-drill/convert-soup-to-excellon-drill-commands.ts
|
|
295
|
+
var getLayerCount = (circuitJson) => {
|
|
296
|
+
const board = circuitJson.find((element) => element.type === "pcb_board");
|
|
297
|
+
if (!board || typeof board.num_layers !== "number") {
|
|
298
|
+
return 2;
|
|
299
|
+
}
|
|
300
|
+
return Math.max(2, board.num_layers);
|
|
301
|
+
};
|
|
302
|
+
var getLayerNumber = (layer, layerCount) => {
|
|
303
|
+
if (layer === "top") return 1;
|
|
304
|
+
if (layer === "bottom") return layerCount;
|
|
305
|
+
const innerLayerMatch = layer.match(/^inner([1-6])$/);
|
|
306
|
+
if (innerLayerMatch) {
|
|
307
|
+
const innerLayerNumber = Number(innerLayerMatch[1]);
|
|
308
|
+
if (innerLayerNumber >= 1 && innerLayerNumber <= layerCount - 2) {
|
|
309
|
+
return innerLayerNumber + 1;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
throw new Error(`Invalid layer "${layer}" for ${layerCount}-layer board`);
|
|
313
|
+
};
|
|
314
|
+
var normalizeLayerSpan = (span, layerCount) => {
|
|
315
|
+
const fromLayerNumber = getLayerNumber(span.from_layer, layerCount);
|
|
316
|
+
const toLayerNumber = getLayerNumber(span.to_layer, layerCount);
|
|
317
|
+
if (fromLayerNumber <= toLayerNumber) {
|
|
318
|
+
return span;
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
from_layer: span.to_layer,
|
|
322
|
+
to_layer: span.from_layer
|
|
323
|
+
};
|
|
324
|
+
};
|
|
325
|
+
var getPlatedElementLayerSpan = (element, layerCount) => {
|
|
326
|
+
if (element.type !== "pcb_plated_hole" && element.type !== "pcb_via") {
|
|
327
|
+
return void 0;
|
|
328
|
+
}
|
|
329
|
+
if ("from_layer" in element && typeof element.from_layer === "string" && "to_layer" in element && typeof element.to_layer === "string") {
|
|
330
|
+
return normalizeLayerSpan(
|
|
331
|
+
{
|
|
332
|
+
from_layer: element.from_layer,
|
|
333
|
+
to_layer: element.to_layer
|
|
334
|
+
},
|
|
335
|
+
layerCount
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
let layers = [];
|
|
339
|
+
if ("layers" in element && Array.isArray(element.layers)) {
|
|
340
|
+
layers = element.layers;
|
|
341
|
+
}
|
|
342
|
+
if (layers.length > 0) {
|
|
343
|
+
const sortedLayers = [...layers].sort(
|
|
344
|
+
(a, b) => getLayerNumber(a, layerCount) - getLayerNumber(b, layerCount)
|
|
345
|
+
);
|
|
346
|
+
return {
|
|
347
|
+
from_layer: sortedLayers[0],
|
|
348
|
+
to_layer: sortedLayers[sortedLayers.length - 1]
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
from_layer: "top",
|
|
353
|
+
to_layer: "bottom"
|
|
354
|
+
};
|
|
355
|
+
};
|
|
356
|
+
var getDefaultPlatedDrillLayerSpan = () => ({
|
|
357
|
+
from_layer: "top",
|
|
358
|
+
to_layer: "bottom"
|
|
359
|
+
});
|
|
360
|
+
var getRequestedLayerSpan = (layer_span) => {
|
|
361
|
+
if (layer_span) {
|
|
362
|
+
return layer_span;
|
|
363
|
+
}
|
|
364
|
+
return getDefaultPlatedDrillLayerSpan();
|
|
365
|
+
};
|
|
366
|
+
var isSameLayerSpan = (a, b, layerCount) => {
|
|
367
|
+
const normalizedA = normalizeLayerSpan(a, layerCount);
|
|
368
|
+
const normalizedB = normalizeLayerSpan(b, layerCount);
|
|
369
|
+
return normalizedA.from_layer === normalizedB.from_layer && normalizedA.to_layer === normalizedB.to_layer;
|
|
370
|
+
};
|
|
371
|
+
var shouldIncludeElement = ({
|
|
372
|
+
element,
|
|
373
|
+
is_plated,
|
|
374
|
+
layer_span,
|
|
375
|
+
layerCount
|
|
376
|
+
}) => {
|
|
377
|
+
if (element.type !== "pcb_plated_hole" && element.type !== "pcb_hole" && element.type !== "pcb_via") {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
if (!is_plated) return element.type === "pcb_hole";
|
|
381
|
+
if (element.type === "pcb_hole") return false;
|
|
382
|
+
const elementLayerSpan = getPlatedElementLayerSpan(element, layerCount);
|
|
383
|
+
if (!elementLayerSpan) return false;
|
|
384
|
+
const requestedLayerSpan = getRequestedLayerSpan(layer_span);
|
|
385
|
+
return isSameLayerSpan(elementLayerSpan, requestedLayerSpan, layerCount);
|
|
386
|
+
};
|
|
387
|
+
var getFileFunctionLayerSpan = ({
|
|
388
|
+
circuitJson,
|
|
389
|
+
is_plated,
|
|
390
|
+
layer_span
|
|
391
|
+
}) => {
|
|
392
|
+
const layerCount = getLayerCount(circuitJson);
|
|
393
|
+
if (!is_plated) return `NonPlated,1,${layerCount},NPTH`;
|
|
394
|
+
const requestedLayerSpan = getRequestedLayerSpan(layer_span);
|
|
395
|
+
const span = normalizeLayerSpan(requestedLayerSpan, layerCount);
|
|
396
|
+
return `Plated,${getLayerNumber(span.from_layer, layerCount)},${getLayerNumber(span.to_layer, layerCount)},PTH`;
|
|
397
|
+
};
|
|
295
398
|
var convertSoupToExcellonDrillCommands = ({
|
|
296
399
|
circuitJson,
|
|
297
400
|
is_plated,
|
|
298
|
-
flip_y_axis = false
|
|
401
|
+
flip_y_axis = false,
|
|
402
|
+
layer_span
|
|
299
403
|
}) => {
|
|
300
404
|
const builder = excellonDrill();
|
|
405
|
+
const layerCount = getLayerCount(circuitJson);
|
|
301
406
|
builder.add("M48", {});
|
|
302
407
|
const date_str = (/* @__PURE__ */ new Date()).toISOString();
|
|
303
408
|
builder.add("header_comment", {
|
|
@@ -312,15 +417,21 @@ var convertSoupToExcellonDrillCommands = ({
|
|
|
312
417
|
attribute_value: "tscircuit"
|
|
313
418
|
}).add("header_attribute", {
|
|
314
419
|
attribute_name: "TF.FileFunction",
|
|
315
|
-
attribute_value:
|
|
420
|
+
attribute_value: getFileFunctionLayerSpan({
|
|
421
|
+
circuitJson,
|
|
422
|
+
is_plated,
|
|
423
|
+
layer_span
|
|
424
|
+
})
|
|
316
425
|
}).add("FMAT", { format: 2 }).add("unit_format", { unit: "METRIC", lz: null });
|
|
317
426
|
let tool_counter = 10;
|
|
318
427
|
const diameterToToolNumber = {};
|
|
319
428
|
for (const element of circuitJson) {
|
|
320
|
-
if (
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
429
|
+
if (!shouldIncludeElement({
|
|
430
|
+
element,
|
|
431
|
+
is_plated,
|
|
432
|
+
layer_span,
|
|
433
|
+
layerCount
|
|
434
|
+
})) {
|
|
324
435
|
continue;
|
|
325
436
|
}
|
|
326
437
|
const holeDiameter = "hole_diameter" in element && typeof element.hole_diameter === "number" ? element.hole_diameter : "hole_width" in element && typeof element.hole_width === "number" && "hole_height" in element && typeof element.hole_height === "number" ? Math.min(element.hole_width, element.hole_height) : void 0;
|
|
@@ -344,7 +455,12 @@ var convertSoupToExcellonDrillCommands = ({
|
|
|
344
455
|
builder.add("use_tool", { tool_number: i });
|
|
345
456
|
for (const element of circuitJson) {
|
|
346
457
|
if (element.type === "pcb_plated_hole" || element.type === "pcb_hole" || element.type === "pcb_via") {
|
|
347
|
-
if (!
|
|
458
|
+
if (!shouldIncludeElement({
|
|
459
|
+
element,
|
|
460
|
+
is_plated,
|
|
461
|
+
layer_span,
|
|
462
|
+
layerCount
|
|
463
|
+
})) {
|
|
348
464
|
continue;
|
|
349
465
|
}
|
|
350
466
|
const holeDiameter = "hole_diameter" in element && typeof element.hole_diameter === "number" ? element.hole_diameter : "hole_width" in element && typeof element.hole_width === "number" && "hole_height" in element && typeof element.hole_height === "number" ? Math.min(element.hole_width, element.hole_height) : void 0;
|
|
@@ -408,6 +524,59 @@ var convertSoupToExcellonDrillCommands = ({
|
|
|
408
524
|
builder.add("M30", {});
|
|
409
525
|
return builder.build();
|
|
410
526
|
};
|
|
527
|
+
var getDrillLayerSpanKey = (span, layerCount) => {
|
|
528
|
+
const normalizedSpan = normalizeLayerSpan(span, layerCount);
|
|
529
|
+
return `L${getLayerNumber(normalizedSpan.from_layer, layerCount)}-L${getLayerNumber(normalizedSpan.to_layer, layerCount)}`;
|
|
530
|
+
};
|
|
531
|
+
var hasDrillGeometry = (element) => {
|
|
532
|
+
if ("hole_diameter" in element && typeof element.hole_diameter === "number") {
|
|
533
|
+
return true;
|
|
534
|
+
}
|
|
535
|
+
return "hole_width" in element && typeof element.hole_width === "number" && "hole_height" in element && typeof element.hole_height === "number";
|
|
536
|
+
};
|
|
537
|
+
var convertSoupToExcellonDrillCommandLayers = ({
|
|
538
|
+
circuitJson,
|
|
539
|
+
flip_y_axis = false
|
|
540
|
+
}) => {
|
|
541
|
+
const layerCount = getLayerCount(circuitJson);
|
|
542
|
+
const platedSpans = new Map(
|
|
543
|
+
circuitJson.flatMap((element) => {
|
|
544
|
+
const span = getPlatedElementLayerSpan(element, layerCount);
|
|
545
|
+
if (!span) {
|
|
546
|
+
return [];
|
|
547
|
+
}
|
|
548
|
+
return [[getDrillLayerSpanKey(span, layerCount), span]];
|
|
549
|
+
})
|
|
550
|
+
);
|
|
551
|
+
const platedDrillLayers = Object.fromEntries(
|
|
552
|
+
[...platedSpans.entries()].sort().map(([spanKey, span]) => [
|
|
553
|
+
`drill-${spanKey}.drl`,
|
|
554
|
+
convertSoupToExcellonDrillCommands({
|
|
555
|
+
circuitJson,
|
|
556
|
+
is_plated: true,
|
|
557
|
+
flip_y_axis,
|
|
558
|
+
layer_span: span
|
|
559
|
+
})
|
|
560
|
+
])
|
|
561
|
+
);
|
|
562
|
+
const hasNonPlatedDrill = circuitJson.some((element) => {
|
|
563
|
+
if (element.type !== "pcb_hole") {
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
return hasDrillGeometry(element);
|
|
567
|
+
});
|
|
568
|
+
if (!hasNonPlatedDrill) {
|
|
569
|
+
return platedDrillLayers;
|
|
570
|
+
}
|
|
571
|
+
return {
|
|
572
|
+
...platedDrillLayers,
|
|
573
|
+
"drill_npth.drl": convertSoupToExcellonDrillCommands({
|
|
574
|
+
circuitJson,
|
|
575
|
+
is_plated: false,
|
|
576
|
+
flip_y_axis
|
|
577
|
+
})
|
|
578
|
+
};
|
|
579
|
+
};
|
|
411
580
|
|
|
412
581
|
// src/gerber/commands/add_attribute_on_aperture.ts
|
|
413
582
|
import { z as z21 } from "zod";
|
|
@@ -1445,7 +1614,7 @@ var findApertureNumber = (glayer, search_params) => {
|
|
|
1445
1614
|
// package.json
|
|
1446
1615
|
var package_default = {
|
|
1447
1616
|
name: "circuit-json-to-gerber",
|
|
1448
|
-
version: "0.0.
|
|
1617
|
+
version: "0.0.55",
|
|
1449
1618
|
main: "dist/index.js",
|
|
1450
1619
|
type: "module",
|
|
1451
1620
|
scripts: {
|
|
@@ -1583,7 +1752,7 @@ import {
|
|
|
1583
1752
|
rotate,
|
|
1584
1753
|
translate
|
|
1585
1754
|
} from "transformation-matrix";
|
|
1586
|
-
var
|
|
1755
|
+
var getLayerCount2 = (circuitJson) => {
|
|
1587
1756
|
const board = circuitJson.find((element) => element.type === "pcb_board");
|
|
1588
1757
|
const numLayers = board?.num_layers ?? 2;
|
|
1589
1758
|
return Math.max(2, Math.min(8, numLayers));
|
|
@@ -1598,7 +1767,7 @@ var getGerberInnerLayerName = (layerRef) => {
|
|
|
1598
1767
|
var convertSoupToGerberCommands = (circuitJson, opts = {}) => {
|
|
1599
1768
|
opts.flip_y_axis ??= false;
|
|
1600
1769
|
const hasPanel = circuitJson.some((e) => e.type === "pcb_panel");
|
|
1601
|
-
const layerCount =
|
|
1770
|
+
const layerCount = getLayerCount2(circuitJson);
|
|
1602
1771
|
const innerLayerRefs = getInnerLayerRefs(layerCount);
|
|
1603
1772
|
const copperLayerRefs = ["top", ...innerLayerRefs, "bottom"];
|
|
1604
1773
|
const outerLayerRefs = ["top", "bottom"];
|
|
@@ -2524,10 +2693,11 @@ export {
|
|
|
2524
2693
|
stringifyExcellonDrill,
|
|
2525
2694
|
excellonDrill,
|
|
2526
2695
|
convertSoupToExcellonDrillCommands,
|
|
2696
|
+
convertSoupToExcellonDrillCommandLayers,
|
|
2527
2697
|
gerberBuilder,
|
|
2528
2698
|
stringifyGerberCommand,
|
|
2529
2699
|
stringifyGerberCommandLayers,
|
|
2530
2700
|
stringifyGerberCommands,
|
|
2531
2701
|
convertSoupToGerberCommands
|
|
2532
2702
|
};
|
|
2533
|
-
//# sourceMappingURL=chunk-
|
|
2703
|
+
//# sourceMappingURL=chunk-6BPSJ3NY.js.map
|