Skip to content

Commit

Permalink
board-auto-size
Browse files Browse the repository at this point in the history
  • Loading branch information
AbhinavTheDev committed Feb 7, 2025
1 parent 0ff80bc commit 7dc292f
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 17 deletions.
1 change: 1 addition & 0 deletions lib/components/base-components/Renderable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const orderedRenderPhases = [
"SchematicPortRender",
"SchematicLayout",
"SchematicTraceRender",
"PcbBoardAutoSize",
"PcbComponentRender",
"PcbPrimitiveRender",
"PcbFootprintLayout",
Expand Down
35 changes: 35 additions & 0 deletions lib/components/normal-components/Board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { z } from "zod"
import { NormalComponent } from "../base-components/NormalComponent/NormalComponent"
import { identity, type Matrix } from "transformation-matrix"
import { Group } from "../primitive-components/Group/Group"
import { getBoundsOfPcbComponents } from "lib/utils/get-bounds-of-pcb-components"

export class Board extends Group<typeof boardProps> {
pcb_board_id: string | null = null
Expand Down Expand Up @@ -31,6 +32,40 @@ export class Board extends Group<typeof boardProps> {
return ["top", "bottom", "inner1", "inner2"]
}

doInitialPcbBoardAutoSize(): void {
if (this.root?.pcbDisabled) return

// Skip auto-size if dimensions already specified
if (
(this._parsedProps.width && this._parsedProps.height) ||
this._parsedProps.outline
) {
// console.log("Skipping auto-size - dimensions specified", this._parsedProps)
console.log("Skipping auto-size because dimensions are specified")
return
}

const bounds = getBoundsOfPcbComponents(this.children)

if (bounds.width === 0 || bounds.height === 0) {
console.log("No valid components found for auto-sizing")
return
}

const padding = 2
this._parsedProps = {
...this._parsedProps,
width: bounds.width + padding * 2,
height: bounds.height + padding * 2,
}

// Set board center based on component bounds
this._parsedProps.pcbX = (bounds.minX + bounds.maxX) / 2
this._parsedProps.pcbY = (bounds.minY + bounds.maxY) / 2

// console.log("Auto-sized dimensions:", bounds.width, bounds.height)
// console.log("Center position:", this._parsedProps.pcbX, this._parsedProps.pcbY)
}
doInitialPcbComponentRender(): void {
if (this.root?.pcbDisabled) return
const { db } = this.root!
Expand Down
46 changes: 29 additions & 17 deletions lib/utils/get-bounds-of-pcb-components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,47 @@ export function getBoundsOfPcbComponents(components: PrimitiveComponent[]) {
let maxY = -Infinity

for (const child of components) {
let bounds

if (child.isPcbPrimitive) {
const { x, y } = child._getGlobalPcbPositionBeforeLayout()
const { width, height } = child.getPcbSize()
minX = Math.min(minX, x - width / 2)
minY = Math.min(minY, y - height / 2)
maxX = Math.max(maxX, x + width / 2)
maxY = Math.max(maxY, y + height / 2)
continue
}

if (child.pcb_component_id) {
bounds = child._getPcbCircuitJsonBounds()
} else if (child.componentName === "Footprint") {
const childBounds = getBoundsOfPcbComponents(child.children)
bounds = getBoundsOfPcbComponents(child.children)
} else if (child.children.length > 0) {
bounds = getBoundsOfPcbComponents(child.children)
}

minX = Math.min(minX, childBounds.minX)
minY = Math.min(minY, childBounds.minY)
maxX = Math.max(maxX, childBounds.maxX)
maxY = Math.max(maxY, childBounds.maxY)
if (bounds) {
if ("bounds" in bounds) {
minX = Math.min(minX, bounds.bounds.left)
minY = Math.min(minY, bounds.bounds.top)
maxX = Math.max(maxX, bounds.bounds.right)
maxY = Math.max(maxY, bounds.bounds.bottom)
} else {
minX = Math.min(minX, bounds.minX)
minY = Math.min(minY, bounds.minY)
maxX = Math.max(maxX, bounds.maxX)
maxY = Math.max(maxY, bounds.maxY)
}
}
}

let width = maxX - minX
let height = maxY - minY

if (width < 0) width = 0
if (height < 0) height = 0

return {
minX,
minY,
maxX,
maxY,
width,
height,
minX: isFinite(minX) ? minX : 0,
minY: isFinite(minY) ? minY : 0,
maxX: isFinite(maxX) ? maxX : 0,
maxY: isFinite(maxY) ? maxY : 0,
width: Math.max(0, maxX - minX),
height: Math.max(0, maxY - minY),
}
}
81 changes: 81 additions & 0 deletions tests/components/normal-components/board-auto-size.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { test, expect } from "bun:test"
import { getTestFixture } from "tests/fixtures/get-test-fixture"

test("board auto-sizes when no dimensions provided", () => {
const { circuit } = getTestFixture()

circuit.add(
<board>
<resistor name="R1" resistance="10k" footprint="0402" pcbX={5} pcbY={5} />
<capacitor
name="C1"
capacitance="10uF"
footprint="0603"
pcbX={-5}
pcbY={-5}
/>
</board>,
)

circuit.render()

const pcb_board = circuit.db.pcb_board.list()[0]

// Board should be larger than component bounds
expect(pcb_board.width).toBeGreaterThan(10)
expect(pcb_board.height).toBeGreaterThan(10)
})

test("board respects explicit dimensions", () => {
const { circuit } = getTestFixture()
circuit.add(
<board width="50mm" height="50mm">
<resistor name="R1" resistance="10k" footprint="0402" pcbX={5} pcbY={5} />
</board>,
)
circuit.render()
const pcb_board = circuit.db.pcb_board.list()[0]
expect(pcb_board.width).toBe(50)
expect(pcb_board.height).toBe(50)
})

test("board auto-sizes with nested components", () => {
const { circuit } = getTestFixture()
circuit.add(
<board>
<resistor
name="R1"
resistance="10k"
footprint="0402"
pcbX={10}
pcbY={10}
/>
<resistor
name="R2"
resistance="10k"
footprint="0402"
pcbX={-10}
pcbY={-10}
/>
</board>,
)
circuit.render()
const pcb_board = circuit.db.pcb_board.list()[0]

// Should be at least 20mm (component spread) + padding
expect(pcb_board.width).toBeGreaterThan(22)
expect(pcb_board.height).toBeGreaterThan(22)
})

test("board centers around components", () => {
const { circuit } = getTestFixture()
circuit.add(
<board>
<resistor name="R1" resistance="10k" footprint="0402" pcbX={5} pcbY={0} />
</board>,
)
circuit.render()
const pcb_board = circuit.db.pcb_board.list()[0]
expect(pcb_board.center.x).toBe(5)
expect(pcb_board.center.y).toBe(0)
})

0 comments on commit 7dc292f

Please sign in to comment.