Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions lib/components/normal-components/Board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,13 @@ export class Board extends Group<typeof boardProps> {
}

const update: Record<string, unknown> = {
width: finalWidth,
height: finalHeight,
// Only set width/height when outline is not present
...(props.outline
? {}
: {
width: props.width ?? computedWidth,
height: props.height ?? computedHeight,
}),
center,
}

Expand Down Expand Up @@ -267,6 +272,9 @@ export class Board extends Group<typeof boardProps> {
const pcbBoard = this.root!.db.pcb_board.get(this.pcb_board_id!)
if (!pcbBoard) return

// Only add board information for rectangular boards with width/height
if (pcbBoard.shape !== "rect" || !pcbBoard.width || !pcbBoard.height) return

const boardInformation: string[] = []
if (platform.projectName) boardInformation.push(platform.projectName)
if (platform.version) boardInformation.push(`v${platform.version}`)
Expand All @@ -277,8 +285,8 @@ export class Board extends Group<typeof boardProps> {
const marginX = 0.25
const marginY = 1
const position = {
x: pcbBoard.center.x + pcbBoard.width! / 2 - marginX,
y: pcbBoard.center.y - pcbBoard.height! / 2 + marginY,
x: pcbBoard.center.x + pcbBoard.width / 2 - marginX,
y: pcbBoard.center.y - pcbBoard.height / 2 + marginY,
}

this.root!.db.pcb_silkscreen_text.insert({
Expand Down Expand Up @@ -341,8 +349,7 @@ export class Board extends Group<typeof boardProps> {
const minY = Math.min(...yValues)
const maxY = Math.max(...yValues)

computedWidth = maxX - minX
computedHeight = maxY - minY
// When outline is present, only calculate center, not width/height
center = {
x: (minX + maxX) / 2 + (props.outlineOffsetX ?? 0),
y: (minY + maxY) / 2 + (props.outlineOffsetY ?? 0),
Expand All @@ -365,12 +372,11 @@ export class Board extends Group<typeof boardProps> {

const pcb_board = db.pcb_board.insert({
center,

thickness: this.boardThickness,
num_layers: this.allLayers.length,

width: computedWidth!,
height: computedHeight!,
width: props.outline ? undefined : computedWidth,
height: props.outline ? undefined : computedHeight,
shape: props.outline ? "polygon" : "rect",
outline: outline?.map((point) => ({
x: point.x + (props.outlineOffsetX ?? 0),
y: point.y + (props.outlineOffsetY ?? 0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ export const getBoardPolygon = (board: PcbBoard): Flatten.Polygon => {
board.outline.map((p) => Flatten.point(p.x, p.y)),
)
}
return new Flatten.Polygon(
new Flatten.Box(
board.center.x - board.width! / 2,
board.center.y - board.height! / 2,
board.center.x + board.width! / 2,
board.center.y + board.height! / 2,
).toPoints(),
)

// For rectangular boards with width/height
if (board.width && board.height) {
return new Flatten.Polygon(
new Flatten.Box(
board.center.x - board.width / 2,
board.center.y - board.height / 2,
board.center.x + board.width / 2,
board.center.y + board.height / 2,
).toPoints(),
)
}

// Fallback: return empty polygon
return new Flatten.Polygon()
}
2 changes: 1 addition & 1 deletion lib/utils/autorouting/getSimpleRouteJsonFromCircuitJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const getSimpleRouteJsonFromCircuitJson = ({

let bounds: { minX: number; maxX: number; minY: number; maxY: number }

if (board && !board.outline) {
if (board && !board.outline && board.width && board.height) {
bounds = {
minX: board.center.x - board.width! / 2,
maxX: board.center.x + board.width! / 2,
Expand Down
6 changes: 6 additions & 0 deletions lib/utils/is-route-outside-board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ export const isRouteOutsideBoard = (
// New error handling for traces routed outside the board
const boardWidth = pcbBoard.width
const boardHeight = pcbBoard.height

// If board has no width/height (outline-based board without dimensions), skip check
if (!boardWidth || !boardHeight) {
return false
}

const boardCenterX = pcbBoard.center.x
const boardCenterY = pcbBoard.center.y

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ test("board outline dimension is calculated correctly", () => {
circuit.render()

const pcb_board = circuit.db.pcb_board.list()[0]
expect(pcb_board.width).toBe(16)
expect(pcb_board.height).toBe(16)
// When outline is provided, width and height should be undefined
expect(pcb_board.width).toBeUndefined()
expect(pcb_board.height).toBeUndefined()

expect(circuit).toMatchPcbSnapshot(import.meta.path)
})
67 changes: 52 additions & 15 deletions tests/fixtures/extend-expect-3d-matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,62 @@ export async function resolvePoppyglOptions(
if (!board) {
throw new Error("Can't use cameraPreset without pcb_board")
}
switch (cameraPreset) {
case "bottom_angled":
resolvedOpts.camPos = [
board.width! / 2,
-(board.width! + board.height!) / 2,
board.height! / 2,
]
break
default:
throw new Error(`Unknown camera preset: ${cameraPreset}`)
// Handle outlined boards differently
if (board.shape === "polygon" && board.outline) {
// Calculate bounds from outline for camera positioning
const xVals = board.outline.map((p) => p.x)
const yVals = board.outline.map((p) => p.y)
const outlineWidth = Math.max(...xVals) - Math.min(...xVals)
const outlineHeight = Math.max(...yVals) - Math.min(...yVals)

switch (cameraPreset) {
case "bottom_angled":
resolvedOpts.camPos = [
outlineWidth / 2,
-(outlineWidth + outlineHeight) / 2,
outlineHeight / 2,
]
break
default:
throw new Error(`Unknown camera preset: ${cameraPreset}`)
}
} else if (board.width && board.height) {
switch (cameraPreset) {
case "bottom_angled":
resolvedOpts.camPos = [
board.width / 2,
-(board.width + board.height) / 2,
board.height / 2,
]
break
default:
throw new Error(`Unknown camera preset: ${cameraPreset}`)
}
}
}

if (!resolvedOpts.camPos && board) {
resolvedOpts.camPos = [
board.width! / 2,
(board.width! + board.height!) / 2,
board.height! / 2,
]
// Handle outlined boards
if (board.shape === "polygon" && board.outline) {
// Calculate bounds from outline
const xVals = board.outline.map((p) => p.x)
const yVals = board.outline.map((p) => p.y)
const outlineWidth = Math.max(...xVals) - Math.min(...xVals)
const outlineHeight = Math.max(...yVals) - Math.min(...yVals)

resolvedOpts.camPos = [
outlineWidth / 2,
(outlineWidth + outlineHeight) / 2,
outlineHeight / 2,
]
} else if (board.width && board.height) {
// Rectangular board with width/height
resolvedOpts.camPos = [
board.width / 2,
(board.width + board.height) / 2,
board.height / 2,
]
}
}

return resolvedOpts
Expand Down
1 change: 1 addition & 0 deletions tests/footprint/footprint-library-map3.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ test("footprint library map 3", async () => {
"num_layers": 2,
"outline": undefined,
"pcb_board_id": "pcb_board_0",
"shape": "rect",
"thickness": 1.4,
"type": "pcb_board",
"width": 5.5600000000000005,
Expand Down
32 changes: 32 additions & 0 deletions tests/repros/repro70-board-outline.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { test, expect } from "bun:test"
import { getTestFixture } from "tests/fixtures/get-test-fixture"

test("board width and height should be undefined when outline is provided", async () => {
const { circuit } = getTestFixture()

circuit.add(
<board
outline={[
{ x: -8, y: -8 },
{ x: 8, y: -8 },
{ x: 8, y: 8 },
{ x: -8, y: 8 },
]}
>
<resistor name="R1" resistance="10k" footprint="0402" />
<capacitor name="C1" capacitance="10uF" footprint="0603" />
</board>,
)

circuit.render()

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

// EXPECTED: width and height should be undefined when outline is present
expect(pcb_board.width).toBeUndefined()
expect(pcb_board.height).toBeUndefined()

// EXPECTED: outline should exist and have the correct points
expect(pcb_board.outline).toBeDefined()
expect(pcb_board.outline).toHaveLength(4)
})