Skip to content

Commit e59341f

Browse files
authored
Implement schematic symbol generation (#22)
* Implement schematic symbol generation * format * copilot review * clean * up * up * up * add timeout * Decrease timeout for PCB cutout tests Reduced timeout for multiple PCB cutout tests from 100000ms to 10000ms. * Decrease test timeout from 100 seconds to 10 seconds Reduced timeout for the test case to 10 seconds. * Update test timeout from 10000ms to 15000ms Increased timeout for test case to 15000ms. * up
1 parent 996f7b9 commit e59341f

6 files changed

Lines changed: 144 additions & 7 deletions

lib/generate-footprint-tsx.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { su } from "@tscircuit/soup-util"
44

55
export const generateFootprintTsx = (
66
circuitJson: AnyCircuitElement[],
7-
): string => {
7+
): string | null => {
88
const holes = su(circuitJson).pcb_hole.list()
99
const platedHoles = su(circuitJson).pcb_plated_hole.list()
1010
const smtPads = su(circuitJson).pcb_smtpad.list()
@@ -230,6 +230,10 @@ export const generateFootprintTsx = (
230230
elementStrings.push(`<pcbnotedimension ${attrs.join(" ")} />`)
231231
}
232232

233+
if (elementStrings.length === 0) {
234+
return null
235+
}
236+
233237
return `
234238
<footprint>
235239
${elementStrings.join("\n")}

lib/generate-symbol-tsx.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import type { AnyCircuitElement } from "circuit-json"
2+
import { su } from "@tscircuit/soup-util"
3+
4+
export const generateSymbolTsx = (
5+
circuitJson: AnyCircuitElement[],
6+
): string | null => {
7+
const schematicArcs = su(circuitJson).schematic_arc.list()
8+
const schematicLines = su(circuitJson).schematic_line.list()
9+
10+
const elementStrings: string[] = []
11+
12+
for (const arc of schematicArcs) {
13+
const center = arc.center ?? { x: 0, y: 0 }
14+
const radius = arc.radius ?? 0
15+
const startAngle = arc.start_angle_degrees ?? 0
16+
const endAngle = arc.end_angle_degrees ?? 0
17+
const strokeWidth = arc.stroke_width ?? 0.05
18+
const color = arc.color ?? "black"
19+
const isDashed = arc.is_dashed ?? false
20+
const direction = arc.direction ?? "counterclockwise"
21+
22+
elementStrings.push(
23+
`<schematicarc
24+
center={{ x: ${center.x}, y: ${center.y} }}
25+
radius={${radius}}
26+
startAngleDegrees={${startAngle}}
27+
endAngleDegrees={${endAngle}}
28+
strokeWidth={${strokeWidth}}
29+
color="${color}"
30+
isDashed={${isDashed}}
31+
direction="${direction}"
32+
/>`,
33+
)
34+
}
35+
36+
for (const line of schematicLines) {
37+
const x1 = line.x1 ?? 0
38+
const y1 = line.y1 ?? 0
39+
const x2 = line.x2 ?? 0
40+
const y2 = line.y2 ?? 0
41+
const strokeWidth = line.stroke_width ?? 0.05
42+
const color = line.color ?? "black"
43+
const isDashed = line.is_dashed ?? false
44+
45+
elementStrings.push(
46+
`<schematicline x1={${x1}} y1={${y1}} x2={${x2}} y2={${y2}} strokeWidth={${strokeWidth}} color="${color}" isDashed={${isDashed}}/>`,
47+
)
48+
}
49+
50+
if (elementStrings.length === 0) {
51+
return null
52+
}
53+
54+
return `
55+
<symbol>
56+
${elementStrings.map((s) => s.split("\n").join("\n ")).join("\n ")}
57+
</symbol>
58+
`.trim()
59+
}

lib/get-component-using-template.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { AnyCircuitElement } from "circuit-json"
22
import { generateFootprintTsx } from "./generate-footprint-tsx"
3+
import { generateSymbolTsx } from "./generate-symbol-tsx"
34

45
export interface ComponentTemplateParams {
56
pinLabels?: Record<string, string[]> | Record<string, string> // ChipProps["pinLabels"]
@@ -19,11 +20,13 @@ export const getComponentUsingTemplate = ({
1920
manufacturerPartNumber,
2021
}: ComponentTemplateParams) => {
2122
const footprintTsx = generateFootprintTsx(circuitJson)
23+
const symbolTsx = generateSymbolTsx(circuitJson)
2224
return `
2325
import { type ChipProps } from "tscircuit"
2426
${pinLabels ? `const pinLabels = ${JSON.stringify(pinLabels, null, " ")} as const\n` : ""}export const ${componentName} = (props: ChipProps${pinLabels ? `<typeof pinLabels>` : ""}) => (
2527
<chip
26-
footprint={${footprintTsx}}
28+
${footprintTsx ? `footprint={${footprintTsx}}` : ""}
29+
${symbolTsx ? `symbol={${symbolTsx}}` : ""}
2730
${pinLabels ? "pinLabels={pinLabels}" : ""}
2831
${objUrl ? `cadModel={{\n objUrl: \"${objUrl}\",\n rotationOffset: { x: 0, y: 0, z: 0 },\n positionOffset: { x: 0, y: 0, z: 0 },\n }}` : ""}
2932
${supplierPartNumbers ? `supplierPartNumbers={${JSON.stringify(supplierPartNumbers, null, " ")}}` : ""}

tests/test5-pcb-cutout.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ test("test pcb_cutout conversion - all shapes", async () => {
6161
const result = await runTscircuitCode(tscircuit)
6262
expect(Array.isArray(result)).toBe(true)
6363
expect(result).not.toHaveLength(0)
64-
})
64+
}, 10000)
6565

6666
test("test pcb_cutout conversion - rect without rotation", async () => {
6767
const circuitJson: AnyCircuitElement[] = [
@@ -94,7 +94,7 @@ test("test pcb_cutout conversion - rect without rotation", async () => {
9494
const result = await runTscircuitCode(tscircuit)
9595
expect(Array.isArray(result)).toBe(true)
9696
expect(result).not.toHaveLength(0)
97-
})
97+
}, 10000)
9898

9999
test("test pcb_cutout conversion - mixed with other elements", async () => {
100100
const circuitJson: AnyCircuitElement[] = [
@@ -147,4 +147,4 @@ test("test pcb_cutout conversion - mixed with other elements", async () => {
147147
const result = await runTscircuitCode(tscircuit)
148148
expect(Array.isArray(result)).toBe(true)
149149
expect(result).not.toHaveLength(0)
150-
})
150+
}, 10000)

tests/test6-support-pcb-notes.test.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,26 @@ test("test6 support pcb notes", async () => {
88
})
99

1010
expect(tscircuit).toMatchInlineSnapshot(`
11-
"import { type ChipProps } from \"tscircuit\"\n export const Test6Component = (props: ChipProps) => (\n <chip\n footprint={<footprint>\n <pcbnotetext pcbX={1} pcbY={2} anchorAlignment=\"top_left\" font=\"tscircuit2024\" fontSize={1.5} text=\"Assembly\" color=\"#ff0000\" />\n <pcbnoterect pcbX={0} pcbY={0} width={3.2} height={1.6} strokeWidth={0.2} isFilled={false} hasStroke={true} isStrokeDashed={true} color=\"#00ff00\" />\n <pcbnotepath route={[{\"x\":-1,\"y\":-1},{\"x\":1,\"y\":-1},{\"x\":1,\"y\":1}]} strokeWidth={0.15} color=\"#0000ff\" />\n <pcbnoteline x1={-0.5} y1={-0.5} x2={0.5} y2={0.5} strokeWidth={0.1} color=\"#123456\" isDashed={true} />\n <pcbnotedimension from={{ x: -2, y: 0 }} to={{ x: 2, y: 0 }} font=\"tscircuit2024\" fontSize={1.2} arrowSize={0.25} text=\"4mm\" color=\"#654321\" />\n </footprint>}\n {...props}\n />\n )"
11+
"import { type ChipProps } from "tscircuit"
12+
export const Test6Component = (props: ChipProps) => (
13+
<chip
14+
footprint={<footprint>
15+
<pcbnotetext pcbX={1} pcbY={2} anchorAlignment="top_left" font="tscircuit2024" fontSize={1.5} text="Assembly" color="#ff0000" />
16+
<pcbnoterect pcbX={0} pcbY={0} width={3.2} height={1.6} strokeWidth={0.2} isFilled={false} hasStroke={true} isStrokeDashed={true} color="#00ff00" />
17+
<pcbnotepath route={[{"x":-1,"y":-1},{"x":1,"y":-1},{"x":1,"y":1}]} strokeWidth={0.15} color="#0000ff" />
18+
<pcbnoteline x1={-0.5} y1={-0.5} x2={0.5} y2={0.5} strokeWidth={0.1} color="#123456" isDashed={true} />
19+
<pcbnotedimension from={{ x: -2, y: 0 }} to={{ x: 2, y: 0 }} font="tscircuit2024" fontSize={1.2} arrowSize={0.25} text="4mm" color="#654321" />
20+
</footprint>}
21+
{...props}
22+
/>
23+
)"
1224
`)
1325

1426
const result = await runTscircuitCode(tscircuit)
1527

1628
expect(Array.isArray(result)).toBe(true)
1729
expect(result).not.toHaveLength(0)
18-
})
30+
}, 15000)
1931

2032
const circuitJson = [
2133
{
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { test, expect } from "bun:test"
2+
import { convertCircuitJsonToTscircuit } from "lib/index"
3+
import type { AnyCircuitElement } from "circuit-json"
4+
5+
test("test7 schematic arc and line inline snapshot", async () => {
6+
const circuitJson: AnyCircuitElement[] = [
7+
{
8+
type: "schematic_arc",
9+
center: { x: 0, y: 0 },
10+
radius: 1,
11+
start_angle_degrees: 0,
12+
end_angle_degrees: 180,
13+
stroke_width: 0.05,
14+
color: "black",
15+
is_dashed: false,
16+
schematic_component_id: "schematic_component_id_1",
17+
direction: "counterclockwise",
18+
schematic_arc_id: "schematic_arc_id_1",
19+
},
20+
{
21+
type: "schematic_line",
22+
x1: -1,
23+
y1: 0,
24+
x2: 1,
25+
y2: 0,
26+
stroke_width: 0.05,
27+
schematic_line_id: "schematic_line_id_1",
28+
schematic_component_id: "schematic_component_id_1",
29+
color: "black",
30+
is_dashed: false,
31+
},
32+
]
33+
34+
const tscircuit = convertCircuitJsonToTscircuit(circuitJson, {
35+
componentName: "U1",
36+
})
37+
38+
expect(tscircuit).toMatchInlineSnapshot(`
39+
"import { type ChipProps } from "tscircuit"
40+
export const U1 = (props: ChipProps) => (
41+
<chip
42+
symbol={<symbol>
43+
<schematicarc
44+
center={{ x: 0, y: 0 }}
45+
radius={1}
46+
startAngleDegrees={0}
47+
endAngleDegrees={180}
48+
strokeWidth={0.05}
49+
color="black"
50+
isDashed={false}
51+
direction="counterclockwise"
52+
/>
53+
<schematicline x1={-1} y1={0} x2={1} y2={0} strokeWidth={0.05} color="black" isDashed={false}/>
54+
</symbol>}
55+
{...props}
56+
/>
57+
)"
58+
`)
59+
})

0 commit comments

Comments
 (0)