circuit-json-to-gerber 0.0.55 → 0.0.57

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.
@@ -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: is_plated ? "Plated,1,2,PTH" : "NonPlated,1,2,NPTH"
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 (element.type !== "pcb_plated_hole" && element.type !== "pcb_hole" && element.type !== "pcb_via") {
321
- continue;
322
- }
323
- if (!is_plated && (element.type === "pcb_plated_hole" || element.type === "pcb_via")) {
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 (!is_plated && (element.type === "pcb_plated_hole" || element.type === "pcb_via")) {
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.54",
1617
+ version: "0.0.56",
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 getLayerCount = (circuitJson) => {
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 = getLayerCount(circuitJson);
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-64R4GN2C.js.map
2703
+ //# sourceMappingURL=chunk-HLGPXB3U.js.map