Skip to content

Commit ae578a8

Browse files
Fix rotation for CourtyardRect
1 parent 4e2ca5f commit ae578a8

File tree

6 files changed

+122
-2
lines changed

6 files changed

+122
-2
lines changed

lib/components/primitive-components/CourtyardRect.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export class CourtyardRect extends PrimitiveComponent<
3434
this.parent?.pcb_component_id ??
3535
this.getPrimitiveContainer()?.pcb_component_id!
3636

37+
const transform = this._computePcbGlobalTransformBeforeLayout()
38+
const ccw_rotation = (Math.atan2(transform.b, transform.a) * 180) / Math.PI
39+
3740
const pcb_courtyard_rect = db.pcb_courtyard_rect.insert({
3841
pcb_component_id,
3942
layer,
@@ -43,6 +46,7 @@ export class CourtyardRect extends PrimitiveComponent<
4346
},
4447
width: props.width,
4548
height: props.height,
49+
ccw_rotation: ccw_rotation || undefined,
4650
subcircuit_id: subcircuit?.subcircuit_id ?? undefined,
4751
pcb_group_id: this.getGroup()?.pcb_group_id ?? undefined,
4852
})

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,13 @@
6060
"bun-match-svg": "0.0.12",
6161
"calculate-elbow": "^0.0.12",
6262
"chokidar-cli": "^3.0.0",
63-
"circuit-json": "^0.0.402",
63+
"circuit-json": "^0.0.403",
6464
"circuit-json-to-bpc": "^0.0.13",
6565
"circuit-json-to-connectivity-map": "^0.0.23",
6666
"circuit-json-to-gltf": "^0.0.73",
6767
"circuit-json-to-simple-3d": "^0.0.9",
6868
"circuit-json-to-spice": "^0.0.34",
69-
"circuit-to-svg": "^0.0.336",
69+
"circuit-to-svg": "^0.0.337",
7070
"concurrently": "^9.1.2",
7171
"connectivity-map": "^1.0.0",
7272
"debug": "^4.3.6",
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { test, expect } from "bun:test"
2+
import { getTestFixture } from "../fixtures/get-test-fixture"
3+
4+
/**
5+
* Two 0805 inductors, L2 rotated 90°, placed so their courtyards overlap.
6+
*
7+
* 0805 courtyard: width=3.35mm, height=1.9mm.
8+
* L1 (0°) at (0,0): courtyard x=[-1.675, 1.675], y=[-0.95, 0.95].
9+
* L2 (90°) at (2.5, 0): with pcb_courtyard_outline the polygon rotates correctly,
10+
* so effective x=[-0.95,0.95], y=[-1.675,1.675] shifted → x=[1.55, 3.45].
11+
* Courtyards overlap in x at [1.55, 1.675].
12+
* Pads of L2 are at x=2.5±0.5125, well clear of L1's pads ending at x=1.425.
13+
*/
14+
test("drc courtyard overlap detects overlapping 0805 inductors (one rotated 90°)", async () => {
15+
const { circuit } = getTestFixture()
16+
17+
circuit.add(
18+
<board width="20mm" height="20mm">
19+
<inductor
20+
name="L1"
21+
footprint="0805"
22+
inductance="10uH"
23+
pcbX={0}
24+
pcbY={0}
25+
/>
26+
<inductor
27+
name="L2"
28+
footprint="0805"
29+
inductance="10uH"
30+
pcbX={2.5}
31+
pcbY={0}
32+
pcbRotation={90}
33+
/>
34+
</board>,
35+
)
36+
37+
await circuit.renderUntilSettled()
38+
39+
const circuitJson = circuit.getCircuitJson()
40+
41+
const padOverlapErrors = circuitJson.filter(
42+
(e: any) => e.type === "pcb_footprint_overlap_error",
43+
)
44+
expect(padOverlapErrors.length).toBe(0)
45+
46+
const courtyardErrors = circuitJson.filter(
47+
(e: any) => e.type === "pcb_courtyard_overlap_error",
48+
)
49+
expect(courtyardErrors.length).toBeGreaterThan(0)
50+
expect((courtyardErrors[0] as any).message).toContain("overlaps")
51+
52+
expect(circuit).toMatchPcbSnapshot(import.meta.path, {
53+
shouldDrawErrors: true,
54+
showCourtyards: true,
55+
})
56+
})
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { test, expect } from "bun:test"
2+
import { getTestFixture } from "../fixtures/get-test-fixture"
3+
4+
/**
5+
* Two 0603 capacitors, C2 rotated 45°, placed so their courtyards overlap.
6+
*
7+
* 0603 courtyard: width=2.95mm, height=1.45mm.
8+
* At 45°, AABB = (2.95 + 1.45) * cos(45°) ≈ 3.111mm on each side, half = 1.556mm.
9+
* C1 (0°) at (0,0): courtyard x=[-1.475, 1.475].
10+
* C2 (45°) at (2.7,0): courtyard x=[1.144, 4.256].
11+
* Courtyards overlap by ~0.331mm.
12+
*
13+
* 0603 pads: width=2.45mm, height=0.95mm.
14+
* C1 pads right edge = 1.225mm; C2 pads left edge ≈ 1.498mm → no pad overlap.
15+
*/
16+
test("drc courtyard overlap detects overlapping 0603 capacitors (one rotated 45°)", async () => {
17+
const { circuit } = getTestFixture()
18+
19+
circuit.add(
20+
<board width="20mm" height="20mm">
21+
<capacitor
22+
name="C1"
23+
footprint="0603"
24+
capacitance="100nF"
25+
pcbX={0}
26+
pcbY={0}
27+
/>
28+
<capacitor
29+
name="C2"
30+
footprint="0603"
31+
capacitance="100nF"
32+
pcbX={2.7}
33+
pcbY={0}
34+
pcbRotation={45}
35+
/>
36+
</board>,
37+
)
38+
39+
await circuit.renderUntilSettled()
40+
41+
const circuitJson = circuit.getCircuitJson()
42+
43+
const padOverlapErrors = circuitJson.filter(
44+
(e: any) => e.type === "pcb_footprint_overlap_error",
45+
)
46+
expect(padOverlapErrors.length).toBe(0)
47+
48+
const courtyardErrors = circuitJson.filter(
49+
(e: any) => e.type === "pcb_courtyard_overlap_error",
50+
)
51+
expect(courtyardErrors.length).toBeGreaterThan(0)
52+
expect((courtyardErrors[0] as any).message).toContain("overlaps")
53+
54+
expect(circuit).toMatchPcbSnapshot(import.meta.path, {
55+
shouldDrawErrors: true,
56+
showCourtyards: true,
57+
})
58+
})

0 commit comments

Comments
 (0)