diff --git a/lib/components/normal-components/Board.ts b/lib/components/normal-components/Board.ts index 00e04b555..3412fa309 100644 --- a/lib/components/normal-components/Board.ts +++ b/lib/components/normal-components/Board.ts @@ -383,10 +383,13 @@ export class Board super.doInitialSourceRender() const { db } = this.root! + const { minViaDiameter, minViaHole } = this._parsedProps const source_board = db.source_board.insert({ source_group_id: this.source_group_id!, title: this.props.title || this.props.name, + ...(minViaDiameter != null ? { min_via_diameter: minViaDiameter } : {}), + ...(minViaHole != null ? { min_via_hole: minViaHole } : {}), }) this.source_board_id = source_board.source_board_id @@ -509,6 +512,8 @@ export class Board } } + const { minViaDiameter, minViaHole } = this._parsedProps + const pcb_board = db.pcb_board.insert({ source_board_id: this.source_board_id, center, @@ -523,6 +528,8 @@ export class Board y: point.y + (props.outlineOffsetY ?? 0) + outlineTranslation.y, })), material: props.material, + ...(minViaDiameter != null ? { min_via_diameter: minViaDiameter } : {}), + ...(minViaHole != null ? { min_via_hole: minViaHole } : {}), } as Omit) this.pcb_board_id = pcb_board.pcb_board_id! diff --git a/lib/components/primitive-components/Group/Group.ts b/lib/components/primitive-components/Group/Group.ts index f3650c9b1..b52380756 100644 --- a/lib/components/primitive-components/Group/Group.ts +++ b/lib/components/primitive-components/Group/Group.ts @@ -133,6 +133,8 @@ export class Group = typeof groupProps> doInitialSourceGroupRender() { const { db } = this.root! + const { minViaDiameter, minViaHole } = this + ._parsedProps as SubcircuitGroupProps const hasExplicitName = typeof (this._parsedProps as { name?: unknown }).name === "string" && (this._parsedProps as { name?: string }).name!.length > 0 @@ -141,6 +143,8 @@ export class Group = typeof groupProps> name: this.name, is_subcircuit: this.isSubcircuit, was_automatically_named: !hasExplicitName, + ...(minViaDiameter != null ? { min_via_diameter: minViaDiameter } : {}), + ...(minViaHole != null ? { min_via_hole: minViaHole } : {}), }) this.source_group_id = source_group.source_group_id if (this.isSubcircuit) { @@ -185,6 +189,7 @@ export class Group = typeof groupProps> const groupProps = props as SubcircuitGroupProps const hasOutline = groupProps.outline && groupProps.outline.length > 0 + const { minViaDiameter, minViaHole } = groupProps const numericOutline = hasOutline ? groupProps.outline!.map((point) => ({ @@ -211,6 +216,8 @@ export class Group = typeof groupProps> } : undefined, anchor_alignment: props.pcbAnchorAlignment ?? null, + ...(minViaDiameter != null ? { min_via_diameter: minViaDiameter } : {}), + ...(minViaHole != null ? { min_via_hole: minViaHole } : {}), }) this.pcb_group_id = pcb_group.pcb_group_id @@ -609,7 +616,10 @@ export class Group = typeof groupProps> ) simpleRouteJson.obstacles = [ ...simpleRouteJson.obstacles, - ...Group_getObstaclesFromRoutedTraces(outputTraces), + ...Group_getObstaclesFromRoutedTraces( + outputTraces, + baseSimpleRouteJson.minViaDiameter, + ), ] } @@ -904,6 +914,8 @@ export class Group = typeof groupProps> // Apply each routed trace to the corresponding circuit trace const pcbStyle = this.getInheritedMergedProperty("pcbStyle") const { holeDiameter, padDiameter } = getViaDiameterDefaults(pcbStyle) + const { minViaDiameter, minViaHole } = this + ._parsedProps as SubcircuitGroupProps // First, create jumper components from getOutputJumpers() result if (output_jumpers && output_jumpers.length > 0) { @@ -958,12 +970,18 @@ export class Group = typeof groupProps> if (pcb_trace.type === "pcb_trace") { for (const point of pcb_trace.route) { if (point.route_type === "via") { + const routeVia = point as typeof point & { + via_diameter?: number + via_hole_diameter?: number + } db.pcb_via.insert({ pcb_trace_id: pcb_trace.pcb_trace_id, x: point.x, y: point.y, - hole_diameter: holeDiameter, - outer_diameter: padDiameter, + hole_diameter: + routeVia.via_hole_diameter ?? minViaHole ?? holeDiameter, + outer_diameter: + routeVia.via_diameter ?? minViaDiameter ?? padDiameter, layers: [ point.from_layer as LayerRef, point.to_layer as LayerRef, diff --git a/lib/components/primitive-components/Group/Group_phasedAutoroutingUtils.ts b/lib/components/primitive-components/Group/Group_phasedAutoroutingUtils.ts index b9d21e0ba..f997f471b 100644 --- a/lib/components/primitive-components/Group/Group_phasedAutoroutingUtils.ts +++ b/lib/components/primitive-components/Group/Group_phasedAutoroutingUtils.ts @@ -114,14 +114,15 @@ function createViaObstacle( point: Extract, connectedTo: string, obstacleIndex: number, + defaultViaDiameter: number, ): Obstacle { return { obstacleId: `${connectedTo}_phase_via_obstacle_${obstacleIndex}`, type: "rect", layers: [point.from_layer, point.to_layer], center: { x: point.x, y: point.y }, - width: 0.6, - height: 0.6, + width: point.via_diameter ?? defaultViaDiameter, + height: point.via_diameter ?? defaultViaDiameter, connectedTo: [connectedTo], } } @@ -129,13 +130,21 @@ function createViaObstacle( function addTraceObstacles( obstacles: Obstacle[], trace: SimplifiedPcbTrace, + defaultViaDiameter: number, ): void { const connectedTo = getTraceConnectionName(trace) for (let routeIndex = 0; routeIndex < trace.route.length; routeIndex++) { const routePoint = trace.route[routeIndex] if (isViaPoint(routePoint)) { - obstacles.push(createViaObstacle(routePoint, connectedTo, routeIndex)) + obstacles.push( + createViaObstacle( + routePoint, + connectedTo, + routeIndex, + defaultViaDiameter, + ), + ) } else if (isJumperPoint(routePoint)) { obstacles.push(createJumperObstacle(routePoint, connectedTo, routeIndex)) } @@ -198,10 +207,11 @@ export function Group_filterSimpleRouteJsonForPhase( export function Group_getObstaclesFromRoutedTraces( traces: SimplifiedPcbTrace[], + defaultViaDiameter = 0.6, ): Obstacle[] { const obstacles: Obstacle[] = [] for (const trace of traces) { - addTraceObstacles(obstacles, trace) + addTraceObstacles(obstacles, trace, defaultViaDiameter) } return obstacles } diff --git a/lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbBoard.ts b/lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbBoard.ts index 48e9bda5e..62d2988a0 100644 --- a/lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbBoard.ts +++ b/lib/components/primitive-components/Group/Subcircuit/inflators/inflatePcbBoard.ts @@ -38,6 +38,12 @@ export function inflatePcbBoard( if (pcbBoard.outline) boardProps.outline = pcbBoard.outline if (pcbBoard.thickness) boardProps.thickness = pcbBoard.thickness if (pcbBoard.material) boardProps.material = pcbBoard.material + if (pcbBoard.min_via_diameter != null) { + boardProps.minViaDiameter = pcbBoard.min_via_diameter + } + if (pcbBoard.min_via_hole != null) { + boardProps.minViaHole = pcbBoard.min_via_hole + } // Create the Board instance const board = new Board(boardProps) diff --git a/lib/utils/autorouting/SimpleRouteJson.ts b/lib/utils/autorouting/SimpleRouteJson.ts index d17cc193f..64d2b7615 100644 --- a/lib/utils/autorouting/SimpleRouteJson.ts +++ b/lib/utils/autorouting/SimpleRouteJson.ts @@ -16,6 +16,8 @@ export type SimplifiedPcbTrace = { y: number to_layer: string from_layer: string + via_diameter?: number + via_hole_diameter?: number } | { route_type: "jumper" @@ -60,6 +62,8 @@ export interface SimpleRouteJson { layerCount: number minTraceWidth: number nominalTraceWidth?: number + minViaDiameter?: number + minViaHole?: number obstacles: Obstacle[] connections: Array bounds: { minX: number; maxX: number; minY: number; maxY: number } diff --git a/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts b/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts index 06ce3d5e6..a08ff91b1 100644 --- a/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts +++ b/lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts @@ -464,6 +464,8 @@ export const getSimpleRouteJsonFromCircuitJson = ({ // subcircuit layerCount: board?.num_layers ?? 2, minTraceWidth, + minViaDiameter: board?.min_via_diameter ?? pcbGroup?.min_via_diameter, + minViaHole: board?.min_via_hole ?? pcbGroup?.min_via_hole, nominalTraceWidth, outline: board?.outline?.map((point) => ({ ...point })), }, diff --git a/tests/features/board-min-via-rules.test.tsx b/tests/features/board-min-via-rules.test.tsx new file mode 100644 index 000000000..4a62d48a2 --- /dev/null +++ b/tests/features/board-min-via-rules.test.tsx @@ -0,0 +1,69 @@ +import { expect, test } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" +import { createBasicAutorouter } from "tests/fixtures/createBasicAutorouter" +import type { SimpleRouteJson } from "lib/utils/autorouting/SimpleRouteJson" + +test("board min via rules flow into srj and routed vias", async () => { + const { circuit } = getTestFixture() + + let capturedSimpleRouteJson: SimpleRouteJson | undefined + + circuit.add( + { + capturedSimpleRouteJson = simpleRouteJson + + return [ + { + type: "pcb_trace", + pcb_trace_id: "trace_0", + connection_name: simpleRouteJson.connections[0]!.name, + route: [ + { + route_type: "wire", + x: -4, + y: 0, + width: 0.15, + layer: "top", + }, + { + route_type: "via", + x: 0, + y: 0, + from_layer: "top", + to_layer: "bottom", + }, + { + route_type: "wire", + x: 4, + y: 0, + width: 0.15, + layer: "bottom", + }, + ], + }, + ] + }), + }} + > + + + + , + ) + + await circuit.renderUntilSettled() + + expect(capturedSimpleRouteJson?.minViaDiameter).toBe(0.6) + expect(capturedSimpleRouteJson?.minViaHole).toBe(0.3) + + const via = circuit.db.pcb_via.list()[0] + expect(via?.outer_diameter).toBe(0.6) + expect(via?.hole_diameter).toBe(0.3) +}) diff --git a/tests/groups/group-min-via-rules.test.tsx b/tests/groups/group-min-via-rules.test.tsx new file mode 100644 index 000000000..8a8206196 --- /dev/null +++ b/tests/groups/group-min-via-rules.test.tsx @@ -0,0 +1,26 @@ +import { expect, test } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" +import { getSimpleRouteJsonFromCircuitJson } from "lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson" + +test("group min via rules flow into simple route json", async () => { + const { circuit } = getTestFixture() + + circuit.add( + + + + + , + ) + + await circuit.renderUntilSettled() + + const subcircuitId = circuit.db.source_group.list()[0]?.subcircuit_id + const { simpleRouteJson } = getSimpleRouteJsonFromCircuitJson({ + db: circuit.db, + subcircuit_id: subcircuitId, + }) + + expect(simpleRouteJson.minViaDiameter).toBe(0.55) + expect(simpleRouteJson.minViaHole).toBe(0.25) +})