Skip to content

Commit d6082bd

Browse files
committed
add support for pcb cutouts
1 parent 6b21251 commit d6082bd

2 files changed

Lines changed: 169 additions & 0 deletions

File tree

lib/generate-footprint-tsx.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const generateFootprintTsx = (
1111
const silkscreenPaths = su(circuitJson).pcb_silkscreen_path.list()
1212
const fabricationNotePaths = su(circuitJson).pcb_fabrication_note_path.list()
1313
const silkscreenTexts = su(circuitJson).pcb_silkscreen_text.list()
14+
const pcbCutouts = su(circuitJson).pcb_cutout.list()
1415

1516
const elementStrings: string[] = []
1617

@@ -76,6 +77,37 @@ export const generateFootprintTsx = (
7677
)
7778
}
7879

80+
// Add pcb_cutout elements
81+
for (const cutout of pcbCutouts) {
82+
if (cutout.shape === "rect") {
83+
const pcbX = cutout.center.x
84+
const pcbY = cutout.center.y
85+
const width = mmStr(cutout.width)
86+
const height = mmStr(cutout.height)
87+
const rotation = cutout.rotation !== undefined ? ` pcbRotation="${mmStr(cutout.rotation)}"` : ""
88+
89+
elementStrings.push(
90+
`<pcbcutout shape="rect" pcbX="${mmStr(pcbX)}" pcbY="${mmStr(pcbY)}" width="${width}" height="${height}"${rotation} />`,
91+
)
92+
} else if (cutout.shape === "circle") {
93+
const pcbX = cutout.center.x
94+
const pcbY = cutout.center.y
95+
const radius = mmStr(cutout.radius)
96+
97+
elementStrings.push(
98+
`<pcbcutout shape="circle" pcbX="${mmStr(pcbX)}" pcbY="${mmStr(pcbY)}" radius="${radius}" />`,
99+
)
100+
} else if (cutout.shape === "polygon") {
101+
const pointsJson = JSON.stringify(cutout.points)
102+
103+
elementStrings.push(
104+
`<pcbcutout shape="polygon" points={${pointsJson}} />`,
105+
)
106+
} else {
107+
console.warn(`Unhandled pcb_cutout shape: ${(cutout as any).shape}`)
108+
}
109+
}
110+
79111
return `
80112
<footprint>
81113
${elementStrings.join("\n")}

tests/test5-pcb-cutout.test.tsx

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { test, expect } from "bun:test"
2+
import { convertCircuitJsonToTscircuit } from "lib/index"
3+
import type { AnyCircuitElement } from "circuit-json"
4+
5+
declare module "bun:test" {
6+
interface Matchers<T = unknown> {
7+
toMatchInlineSnapshot(snapshot?: string | null): Promise<MatcherResult>
8+
}
9+
}
10+
11+
test("test pcb_cutout conversion - all shapes", async () => {
12+
const circuitJson: AnyCircuitElement[] = [
13+
{
14+
type: "pcb_cutout",
15+
pcb_cutout_id: "cutout1",
16+
shape: "rect",
17+
center: { x: 0, y: 0 },
18+
width: 5,
19+
height: 3,
20+
rotation: 45,
21+
},
22+
{
23+
type: "pcb_cutout",
24+
pcb_cutout_id: "cutout2",
25+
shape: "circle",
26+
center: { x: 10, y: 10 },
27+
radius: 2.5,
28+
},
29+
{
30+
type: "pcb_cutout",
31+
pcb_cutout_id: "cutout3",
32+
shape: "polygon",
33+
points: [
34+
{ x: 0, y: 0 },
35+
{ x: 5, y: 0 },
36+
{ x: 5, y: 5 },
37+
{ x: 0, y: 5 },
38+
],
39+
},
40+
]
41+
42+
const tscircuit = convertCircuitJsonToTscircuit(circuitJson, {
43+
componentName: "ComponentWithCutouts",
44+
})
45+
46+
expect(tscircuit).toMatchInlineSnapshot(`
47+
"import { type ChipProps } from "tscircuit"
48+
export const ComponentWithCutouts = (props: ChipProps) => (
49+
<chip
50+
footprint={<footprint>
51+
<pcbcutout shape="rect" pcbX="0mm" pcbY="0mm" width="5mm" height="3mm" pcbRotation="45mm" />
52+
<pcbcutout shape="circle" pcbX="10mm" pcbY="10mm" radius="2.5mm" />
53+
<pcbcutout shape="polygon" points={[{"x":0,"y":0},{"x":5,"y":0},{"x":5,"y":5},{"x":0,"y":5}]} />
54+
</footprint>}
55+
{...props}
56+
/>
57+
)"
58+
`)
59+
})
60+
61+
test("test pcb_cutout conversion - rect without rotation", async () => {
62+
const circuitJson: AnyCircuitElement[] = [
63+
{
64+
type: "pcb_cutout",
65+
pcb_cutout_id: "cutout1",
66+
shape: "rect",
67+
center: { x: 2, y: 3 },
68+
width: 10,
69+
height: 5,
70+
},
71+
]
72+
73+
const tscircuit = convertCircuitJsonToTscircuit(circuitJson, {
74+
componentName: "ComponentWithRectCutout",
75+
})
76+
77+
expect(tscircuit).toMatchInlineSnapshot(`
78+
"import { type ChipProps } from "tscircuit"
79+
export const ComponentWithRectCutout = (props: ChipProps) => (
80+
<chip
81+
footprint={<footprint>
82+
<pcbcutout shape="rect" pcbX="2mm" pcbY="3mm" width="10mm" height="5mm" />
83+
</footprint>}
84+
{...props}
85+
/>
86+
)"
87+
`)
88+
})
89+
90+
test("test pcb_cutout conversion - mixed with other elements", async () => {
91+
const circuitJson: AnyCircuitElement[] = [
92+
{
93+
type: "pcb_smtpad",
94+
pcb_smtpad_id: "pad1",
95+
shape: "rect",
96+
x: 0,
97+
y: 0,
98+
width: 1,
99+
height: 1,
100+
layer: "top",
101+
port_hints: ["1"],
102+
},
103+
{
104+
type: "pcb_cutout",
105+
pcb_cutout_id: "cutout1",
106+
shape: "circle",
107+
center: { x: 5, y: 5 },
108+
radius: 1.5,
109+
},
110+
{
111+
type: "pcb_hole",
112+
pcb_hole_id: "hole1",
113+
hole_shape: "circle",
114+
x: 10,
115+
y: 10,
116+
hole_diameter: 0.5,
117+
},
118+
]
119+
120+
const tscircuit = convertCircuitJsonToTscircuit(circuitJson, {
121+
componentName: "ComponentWithMixedElements",
122+
})
123+
124+
expect(tscircuit).toMatchInlineSnapshot(`
125+
"import { type ChipProps } from "tscircuit"
126+
export const ComponentWithMixedElements = (props: ChipProps) => (
127+
<chip
128+
footprint={<footprint>
129+
<hole pcbX="10mm" pcbY="10mm" diameter="0.5mm" />
130+
<smtpad portHints={["1"]} pcbX="0mm" pcbY="0mm" width="1mm" height="1mm" shape="rect" />
131+
<pcbcutout shape="circle" pcbX="5mm" pcbY="5mm" radius="1.5mm" />
132+
</footprint>}
133+
{...props}
134+
/>
135+
)"
136+
`)
137+
})

0 commit comments

Comments
 (0)