Skip to content

Commit ba5b8c1

Browse files
author
64johnlee
committed
fix: emit In1_Cu/In2_Cu gerber layers for 4-layer boards
When circuit_json has traces on inner1/inner2 layers (detected via pcb_trace.route[].layer), automatically create In1_Cu and In2_Cu gerber layers alongside F_Cu/B_Cu. Previously convertSoupToGerberCommands only emitted top/bottom copper layers even for 4-layer boards, silently dropping inner layer traces. Fixes #78 (circuit-json-to-gerber)
1 parent 3f48c37 commit ba5b8c1

3 files changed

Lines changed: 36 additions & 7 deletions

File tree

src/gerber/convert-soup-to-gerber-commands/GerberLayerName.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export type LayerToGerberCommandsMap = {
66
F_SilkScreen: AnyGerberCommand[]
77
F_Mask: AnyGerberCommand[]
88
F_Paste: AnyGerberCommand[]
9+
In1_Cu: AnyGerberCommand[]
10+
In2_Cu: AnyGerberCommand[]
911
B_Cu: AnyGerberCommand[]
1012
B_SilkScreen: AnyGerberCommand[]
1113
B_Mask: AnyGerberCommand[]

src/gerber/convert-soup-to-gerber-commands/getGerberLayerName.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import type { LayerRef } from "circuit-json"
2-
import type { GerberLayerName } from "./GerberLayerName"
2+
import type { GerberLayerName, LayerToGerberCommandsMap } from "./GerberLayerName"
33

44
const layerRefToGerberPrefix = {
55
top: "F_",
66
bottom: "B_",
7+
inner1: "In1_",
8+
inner2: "In2_",
9+
inner3: "In3_",
10+
inner4: "In4_",
711
} as const
812
const layerTypeToGerberSuffix = {
913
copper: "Cu",
@@ -16,7 +20,8 @@ const layerTypeToGerberSuffix = {
1620
export const getGerberLayerName = (
1721
layer_ref: LayerRef | "edgecut",
1822
layer_type: "copper" | "silkscreen" | "soldermask" | "paste",
19-
): GerberLayerName => {
23+
): keyof LayerToGerberCommandsMap => {
2024
if (layer_ref === "edgecut") return "Edge_Cuts"
21-
return `${layerRefToGerberPrefix[layer_ref as keyof typeof layerRefToGerberPrefix]}${layerTypeToGerberSuffix[layer_type]}`
25+
const name = `${layerRefToGerberPrefix[layer_ref as keyof typeof layerRefToGerberPrefix]}${layerTypeToGerberSuffix[layer_type]}`
26+
return name as keyof LayerToGerberCommandsMap
2227
}

src/gerber/convert-soup-to-gerber-commands/index.ts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { AnyCircuitElement } from "circuit-json"
1+
import type { AnyCircuitElement, LayerRef } from "circuit-json"
22
import { pairs } from "../utils/pairs"
33
import { gerberBuilder } from "../gerber-builder"
44
import type { LayerToGerberCommandsMap } from "./GerberLayerName"
@@ -38,6 +38,13 @@ export const convertSoupToGerberCommands = (
3838
): LayerToGerberCommandsMap => {
3939
opts.flip_y_axis ??= false
4040
const hasPanel = soup.some((e) => e.type === "pcb_panel")
41+
// Detect if this is a 4+ layer board (has inner1/inner2 traces)
42+
const hasInnerLayers = soup.some(
43+
(e: any) =>
44+
e.type === "pcb_trace" &&
45+
e.route?.some((r: any) => r.layer === "inner1" || r.layer === "inner2"),
46+
)
47+
4148
const glayers: LayerToGerberCommandsMap = {
4249
F_Cu: getCommandHeaders({
4350
layer: "top",
@@ -55,6 +62,18 @@ export const convertSoupToGerberCommands = (
5562
layer: "top",
5663
layer_type: "paste",
5764
}),
65+
...(hasInnerLayers
66+
? {
67+
In1_Cu: getCommandHeaders({
68+
layer: "inner1",
69+
layer_type: "copper",
70+
}),
71+
In2_Cu: getCommandHeaders({
72+
layer: "inner2",
73+
layer_type: "copper",
74+
}),
75+
}
76+
: {}),
5877
B_Cu: getCommandHeaders({
5978
layer: "bottom",
6079
layer_type: "copper",
@@ -74,7 +93,7 @@ export const convertSoupToGerberCommands = (
7493
Edge_Cuts: getCommandHeaders({
7594
layer: "edgecut",
7695
}),
77-
}
96+
} as LayerToGerberCommandsMap
7897

7998
for (const glayer_name of [
8099
"F_Cu",
@@ -130,7 +149,7 @@ export const convertSoupToGerberCommands = (
130149

131150
const renderVectorText = (
132151
element: any,
133-
layer: "top" | "bottom",
152+
layer: LayerRef,
134153
layerType: "copper" | "silkscreen",
135154
getApertureConfig: (elm: any) => any,
136155
) => {
@@ -591,7 +610,10 @@ export const convertSoupToGerberCommands = (
591610
}
592611

593612
// SECOND PASS: Process all other elements (traces, pads, vias, etc.)
594-
for (const layer of ["top", "bottom", "edgecut"] as const) {
613+
const allLayers: Array<LayerRef | "edgecut"> = hasInnerLayers
614+
? ["top", "inner1", "inner2", "bottom", "edgecut"]
615+
: ["top", "bottom", "edgecut"]
616+
for (const layer of allLayers) {
595617
for (const element of soup) {
596618
if (element.type === "pcb_trace") {
597619
const { route } = element

0 commit comments

Comments
 (0)