Skip to content

Commit 35f51a4

Browse files
feat: Implement rectangular and polygonal copper pours (#53)
* feat: Implement rectangular and polygonal copper pours * fix regression * ghost code * naming
1 parent c29e6d2 commit 35f51a4

31 files changed

Lines changed: 354 additions & 179 deletions

package.json

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,22 @@
1616
},
1717
"devDependencies": {
1818
"@biomejs/biome": "^1.8.3",
19-
"@tscircuit/core": "^0.0.580",
2019
"@types/archiver": "^6.0.3",
2120
"@types/bun": "^1.1.8",
2221
"@types/node": "^22.5.2",
23-
"@types/react": "^18.3.12",
2422
"archiver": "^7.0.1",
25-
"bun-match-svg": "^0.0.3",
23+
"react": "^19.1.0",
24+
"@types/react": "^19.1.8",
25+
"bun-match-svg": "^0.0.13",
2626
"commander": "^12.1.0",
2727
"gerber-to-svg": "^4.2.8",
2828
"pcb-stackup": "^4.2.8",
29-
"react": "^18.3.1",
3029
"tsup": "^8.2.4",
31-
"circuit-json": "^0.0.220"
30+
"tscircuit": "^0.0.622"
3231
},
3332
"peerDependencies": {
3433
"typescript": "^5.0.0",
35-
"circuit-json": "*"
34+
"tscircuit": "*"
3635
},
3736
"dependencies": {
3837
"@tscircuit/alphabet": "^0.0.2",

src/gerber/any_gerber_command.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ export const gerber_command_map = {
4545
end_of_file,
4646
move_operation,
4747
flash_operation,
48-
// end_region_statement,
49-
// flash_operation,
48+
end_region_statement,
5049
format_specification,
5150
// load_mirroring,
5251
// load_polarity,
@@ -62,7 +61,7 @@ export const gerber_command_map = {
6261
select_aperture,
6362
set_unit,
6463
set_layer_polarity,
65-
// start_region_statement,
64+
start_region_statement,
6665
// step_and_repeat,
6766
} as const satisfies Record<string, GerberCommandDef<any, any>>
6867

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
import { z } from "zod"
2+
import { defineGerberCommand } from "../define-gerber-command"
23

3-
export const end_region_statement = z
4-
.object({
5-
command_code: z.literal("G37"),
6-
statement: z.string(),
7-
})
8-
.describe("End region statement: Ends the region statement")
4+
export const end_region_statement = defineGerberCommand({
5+
command_code: "G37",
6+
schema: z
7+
.object({
8+
command_code: z.literal("G37").default("G37"),
9+
})
10+
.describe("End region statement: Ends the region statement"),
11+
stringify() {
12+
return "G37*"
13+
},
14+
})
915

10-
export type EndRegionStatement = z.infer<typeof end_region_statement>
16+
export type EndRegionStatement = z.infer<typeof end_region_statement.schema>
Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import { z } from "zod"
2+
import { defineGerberCommand } from "../define-gerber-command"
23

3-
export const start_region_statement = z
4-
.object({
5-
command_code: z.literal("G36"),
6-
statement: z.string(),
7-
})
8-
.describe(
9-
"Start region statement: Starts a region statement which creates a region by defining its contours.",
10-
)
4+
export const start_region_statement = defineGerberCommand({
5+
command_code: "G36",
6+
schema: z
7+
.object({
8+
command_code: z.literal("G36").default("G36"),
9+
})
10+
.describe(
11+
"Start region statement: Starts a region statement which creates a region by defining its contours.",
12+
),
13+
stringify() {
14+
return "G36*"
15+
},
16+
})
1117

12-
export type StartRegionStatement = z.infer<typeof start_region_statement>
18+
export type StartRegionStatement = z.infer<typeof start_region_statement.schema>

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ export const getCommandHeaders = (opts: {
8787
comment: `Created by tscircuit (builder) date ${new Date().toISOString()}`,
8888
})
8989
.add("set_movement_mode_to_linear", {})
90+
.add("set_layer_polarity", {
91+
polarity: "D",
92+
})
9093
.build()
9194
)
9295
}

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,79 @@ export const convertSoupToGerberCommands = (
637637
}
638638
ec_layer.push(...cutout_builder.build())
639639
}
640+
} else if (
641+
element.type === "pcb_copper_pour" &&
642+
layer === element.layer
643+
) {
644+
const glayer = glayers[getGerberLayerName(layer, "copper")]
645+
646+
const pour_builder = gerberBuilder()
647+
.add("select_aperture", { aperture_number: 10 })
648+
.add("start_region_statement", {})
649+
650+
if (element.shape === "rect") {
651+
const { center, width, height, rotation } = element
652+
const w = (width as number) / 2
653+
const h = (height as number) / 2
654+
655+
const points = [
656+
{ x: -w, y: h }, // Top-left
657+
{ x: w, y: h }, // Top-right
658+
{ x: w, y: -h }, // Bottom-right
659+
{ x: -w, y: -h }, // Bottom-left
660+
]
661+
662+
let transformMatrix = identity()
663+
if (rotation) {
664+
const angle_rad = ((rotation as number) * Math.PI) / 180
665+
transformMatrix = rotate(angle_rad)
666+
}
667+
transformMatrix = compose(
668+
translate(center.x, center.y),
669+
transformMatrix,
670+
)
671+
672+
const transformedPoints = points.map((p) =>
673+
applyToPoint(transformMatrix, p),
674+
)
675+
676+
pour_builder.add("move_operation", {
677+
x: transformedPoints[0].x,
678+
y: mfy(transformedPoints[0].y),
679+
})
680+
for (let i = 1; i < transformedPoints.length; i++) {
681+
pour_builder.add("plot_operation", {
682+
x: transformedPoints[i].x,
683+
y: mfy(transformedPoints[i].y),
684+
})
685+
}
686+
pour_builder.add("plot_operation", {
687+
x: transformedPoints[0].x,
688+
y: mfy(transformedPoints[0].y),
689+
})
690+
} else if (element.shape === "polygon") {
691+
const { points } = element as any
692+
if (points.length > 0) {
693+
pour_builder.add("move_operation", {
694+
x: points[0].x,
695+
y: mfy(points[0].y),
696+
})
697+
for (let i = 1; i < points.length; i++) {
698+
pour_builder.add("plot_operation", {
699+
x: points[i].x,
700+
y: mfy(points[i].y),
701+
})
702+
}
703+
pour_builder.add("plot_operation", {
704+
x: points[0].x,
705+
y: mfy(points[0].y),
706+
})
707+
}
708+
}
709+
710+
pour_builder.add("end_region_statement", {})
711+
712+
glayer.push(...pour_builder.build())
640713
}
641714
}
642715
}
Lines changed: 7 additions & 7 deletions
Loading

tests/gerber/__snapshots__/anchor-side-top.snap.svg

Lines changed: 7 additions & 7 deletions
Loading
Lines changed: 7 additions & 0 deletions
Loading
Lines changed: 7 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)