From 453894585caad8d7fbf419bceca00eaec178752c Mon Sep 17 00:00:00 2001 From: seveibar Date: Mon, 23 Sep 2024 11:27:07 -0700 Subject: [PATCH] fix bad flipping to bottom layer when footprint has constraints --- .../primitive-components/Footprint.ts | 19 ++- .../keyswitch-socket-flip-pcb.snap.svg | 13 +++ .../keyswitch-socket-flip.test.tsx | 109 ++++++++++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 tests/components/normal-components/__snapshots__/keyswitch-socket-flip-pcb.snap.svg create mode 100644 tests/components/normal-components/keyswitch-socket-flip.test.tsx diff --git a/lib/components/primitive-components/Footprint.ts b/lib/components/primitive-components/Footprint.ts index 39f25e9..02d4d5d 100644 --- a/lib/components/primitive-components/Footprint.ts +++ b/lib/components/primitive-components/Footprint.ts @@ -18,6 +18,22 @@ export class Footprint extends PrimitiveComponent { if (constraints.length === 0) return + const { isFlipped } = this._getPcbPrimitiveFlippedHelpers() + + // If we're flipped, left/right is reversed for constraints + const maybeFlipLeftRight = (props: T): T => { + if (isFlipped) { + if ("left" in props && "right" in props) { + return { + ...props, + left: props.right, + right: props.left, + } + } + } + return props + } + const involvedComponents = constraints .flatMap( (constraint) => @@ -65,7 +81,8 @@ export class Footprint extends PrimitiveComponent { const props = constraint._parsedProps if ("xDist" in props) { - const { xDist, left, right, edgeToEdge, centerToCenter } = props + const { xDist, left, right, edgeToEdge, centerToCenter } = + maybeFlipLeftRight(props) const leftVar = getKVar(`${left}_x`) const rightVar = getKVar(`${right}_x`) const leftBounds = getComponentDetails(left)?.bounds! diff --git a/tests/components/normal-components/__snapshots__/keyswitch-socket-flip-pcb.snap.svg b/tests/components/normal-components/__snapshots__/keyswitch-socket-flip-pcb.snap.svg new file mode 100644 index 0000000..5b24035 --- /dev/null +++ b/tests/components/normal-components/__snapshots__/keyswitch-socket-flip-pcb.snap.svg @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/tests/components/normal-components/keyswitch-socket-flip.test.tsx b/tests/components/normal-components/keyswitch-socket-flip.test.tsx new file mode 100644 index 0000000..deae008 --- /dev/null +++ b/tests/components/normal-components/keyswitch-socket-flip.test.tsx @@ -0,0 +1,109 @@ +import { test, expect } from "bun:test" +import { getTestFixture } from "tests/fixtures/get-test-fixture" + +/** + * A switch shaft you can use to connect a pluggable Kailh socket. + * + * Datasheet: https://wmsc.lcsc.com/wmsc/upload/file/pdf/v2/lcsc/2211090930_Kailh-CPG151101S11-1_C5184526.pdf + */ +const KeyswitchSocket = (props: { + name: string + pcbX?: number + pcbY?: number + layer?: "top" | "bottom" +}) => ( + + {/* */} + + + + + + + + + + + + } + /> +) + +test("KeyswitchSocket flips correctly when placed on bottom layer", () => { + const { project } = getTestFixture() + + project.add( + + + + , + ) + + project.render() + + // Check SMT pads + const smtPads = project.db.pcb_smtpad.list() + expect(smtPads.length).toBe(4) + + const topPads = smtPads.filter((pad) => pad.layer === "top") + const bottomPads = smtPads.filter((pad) => pad.layer === "bottom") + + expect(topPads.length).toBe(2) + expect(bottomPads.length).toBe(2) + + // Check that bottom pads are mirrored + const topPad1 = topPads.find((pad) => pad.port_hints?.includes("pin1")) + const bottomPad1 = bottomPads.find((pad) => pad.port_hints?.includes("pin1")) + + expect(topPad1).toBeDefined() + expect(bottomPad1).toBeDefined() + + if (topPad1 && bottomPad1) { + // expect(topPad1.x).toBeCloseTo(-5.65, 2) + // expect(bottomPad1.x).toBeCloseTo(-5.65, 2) + // expect(topPad1.y).toBeCloseTo(bottomPad1.y - 10, 2) // Accounting for the 10mm Y offset + } + + // Check holes (should not be flipped) + const holes = project.db.pcb_hole.list() + expect(holes.length).toBe(4) + + const topHoles = holes.filter((hole) => hole.x < 0) // Assuming 5 is the midpoint between the two switches + const bottomHoles = holes.filter((hole) => hole.x > 0) + + expect(topHoles.length).toBe(2) + expect(bottomHoles.length).toBe(2) + + // Check that holes maintain their relative positions + const topHole1 = topHoles[0] + const bottomHole1 = bottomHoles[0] + + // expect(topHole1.x).toBeCloseTo(bottomHole1.x, 2) + // expect(topHole1.y).toBeCloseTo(bottomHole1.y - 10, 2) // Accounting for the 10mm Y offset + + // Visual check + expect(project).toMatchPcbSnapshot(import.meta.path) +})