From 3120a4dcfcf358fdd842bd4f1730b93ea52ddbe3 Mon Sep 17 00:00:00 2001 From: Vahap Ogut Date: Thu, 25 Jun 2026 14:31:41 +0300 Subject: [PATCH] feat: add pcb trace preview element --- src/any_circuit_element.ts | 1 + src/pcb/index.ts | 3 ++ src/pcb/pcb_trace_preview.ts | 51 ++++++++++++++++++++++++++ tests/pcb-trace-preview.test.ts | 63 +++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 src/pcb/pcb_trace_preview.ts create mode 100644 tests/pcb-trace-preview.test.ts diff --git a/src/any_circuit_element.ts b/src/any_circuit_element.ts index 500ec53a..98956545 100644 --- a/src/any_circuit_element.ts +++ b/src/any_circuit_element.ts @@ -68,6 +68,7 @@ export const any_circuit_element = z.union([ pcb.pcb_net, pcb.pcb_text, pcb.pcb_trace, + pcb.pcb_trace_preview, pcb.pcb_trace_warning, pcb.pcb_via, pcb.pcb_smtpad, diff --git a/src/pcb/index.ts b/src/pcb/index.ts index b4b2f760..38790b7f 100644 --- a/src/pcb/index.ts +++ b/src/pcb/index.ts @@ -13,6 +13,7 @@ export * from "./pcb_smtpad" export * from "./pcb_solder_paste" export * from "./pcb_text" export * from "./pcb_trace" +export * from "./pcb_trace_preview" export * from "./pcb_trace_warning" export * from "./pcb_trace_error" export * from "./pcb_trace_missing_error" @@ -81,6 +82,7 @@ import type { PcbSmtPad } from "./pcb_smtpad" import type { PcbSolderPaste } from "./pcb_solder_paste" import type { PcbText } from "./pcb_text" import type { PcbTrace } from "./pcb_trace" +import type { PcbTracePreview } from "./pcb_trace_preview" import type { PcbTraceWarning } from "./pcb_trace_warning" import type { PcbTraceError } from "./pcb_trace_error" import type { PcbTraceMissingError } from "./pcb_trace_missing_error" @@ -145,6 +147,7 @@ export type PcbCircuitElement = | PcbSolderPaste | PcbText | PcbTrace + | PcbTracePreview | PcbTraceWarning | PcbTraceError | PcbTraceMissingError diff --git a/src/pcb/pcb_trace_preview.ts b/src/pcb/pcb_trace_preview.ts new file mode 100644 index 00000000..7c3b2030 --- /dev/null +++ b/src/pcb/pcb_trace_preview.ts @@ -0,0 +1,51 @@ +import { getZodPrefixedIdWithDefault } from "src/common" +import { + type PcbTraceRoutePoint, + pcb_trace_route_point, +} from "src/pcb/pcb_trace" +import { expectTypesMatch } from "src/utils/expect-types-match" +import { z } from "zod" + +export const pcb_trace_preview = z + .object({ + type: z.literal("pcb_trace_preview"), + pcb_trace_preview_id: getZodPrefixedIdWithDefault("pcb_trace_preview"), + source_trace_id: z.string().optional(), + pcb_trace_id: z.string().optional(), + pcb_group_id: z.string().optional(), + subcircuit_id: z.string().optional(), + route_order_index: z.number().optional(), + route_thickness_mode: z + .enum(["constant", "interpolated"]) + .default("constant") + .optional(), + should_round_corners: z.boolean().optional(), + trace_length: z.number().optional(), + highlight_color: z.string().optional(), + route: z.array(pcb_trace_route_point), + }) + .describe("Defines a preview trace on the PCB") + +export type PcbTracePreviewInput = z.input +type InferredPcbTracePreview = z.infer + +/** + * Defines a preview trace on the PCB. This is useful for showing autorouting + * candidates before they are committed as real pcb_trace elements. + */ +export interface PcbTracePreview { + type: "pcb_trace_preview" + pcb_trace_preview_id: string + source_trace_id?: string + pcb_trace_id?: string + pcb_group_id?: string + subcircuit_id?: string + route_order_index?: number + route_thickness_mode?: "constant" | "interpolated" + should_round_corners?: boolean + trace_length?: number + highlight_color?: string + route: Array +} + +expectTypesMatch(true) diff --git a/tests/pcb-trace-preview.test.ts b/tests/pcb-trace-preview.test.ts new file mode 100644 index 00000000..8aac4a20 --- /dev/null +++ b/tests/pcb-trace-preview.test.ts @@ -0,0 +1,63 @@ +import { expect, test } from "bun:test" +import { any_circuit_element } from "../src/any_circuit_element" +import { pcb_trace_preview } from "../src/pcb/pcb_trace_preview" + +test("pcb_trace_preview parses autorouting preview routes", () => { + const preview = pcb_trace_preview.parse({ + type: "pcb_trace_preview", + source_trace_id: "source_trace_1", + pcb_trace_id: "pcb_trace_candidate_1", + highlight_color: "#ff00aa", + route: [ + { + route_type: "wire", + x: "1mm", + y: "2mm", + width: "0.15mm", + layer: "top", + }, + { + route_type: "via", + x: "3mm", + y: "4mm", + from_layer: "top", + to_layer: "bottom", + }, + ], + }) + + expect(preview.pcb_trace_preview_id).toMatch(/^pcb_trace_preview/) + expect(preview.route).toEqual([ + { + route_type: "wire", + x: 1, + y: 2, + width: 0.15, + layer: "top", + }, + { + route_type: "via", + x: 3, + y: 4, + from_layer: "top", + to_layer: "bottom", + }, + ]) +}) + +test("any_circuit_element includes pcb_trace_preview", () => { + const parsed = any_circuit_element.parse({ + type: "pcb_trace_preview", + route: [ + { + route_type: "wire", + x: 0, + y: 0, + width: 0.2, + layer: "top", + }, + ], + }) + + expect(parsed.type).toBe("pcb_trace_preview") +})