diff --git a/src/fn/lga.ts b/src/fn/lga.ts index 1d7cab98..cbcb12d8 100644 --- a/src/fn/lga.ts +++ b/src/fn/lga.ts @@ -51,8 +51,20 @@ export const lga = ( ) } - const width = parameters.w ?? (grid.y - 1) * parameters.p + 2 * parameters.pl - const height = parameters.h ?? (grid.x - 1) * parameters.p + 2 * parameters.pl + // The default body size must leave room for the pads on the perpendicular + // sides: without the corner allowance, the inner edge of the left/right + // pads lands exactly on the center line of the outermost top/bottom pads + // (and vice versa), so corner pads overlap. Only needed when pads exist on + // adjacent sides. + const cornerPadClearance = 0.2 + const cornerAllowance = + grid.x > 0 && grid.y > 0 ? parameters.pw + 2 * cornerPadClearance : 0 + const width = + parameters.w ?? + (grid.y - 1) * parameters.p + 2 * parameters.pl + cornerAllowance + const height = + parameters.h ?? + (grid.x - 1) * parameters.p + 2 * parameters.pl + cornerAllowance const leftRightX = (width - parameters.pl) / 2 const topBottomY = (height - parameters.pl) / 2 const pads: AnyCircuitElement[] = [] diff --git a/tests/__snapshots__/lga14.snap.svg b/tests/__snapshots__/lga14.snap.svg new file mode 100644 index 00000000..ac444bc8 --- /dev/null +++ b/tests/__snapshots__/lga14.snap.svg @@ -0,0 +1 @@ +{REF} \ No newline at end of file diff --git a/tests/__snapshots__/lga8.snap.svg b/tests/__snapshots__/lga8.snap.svg new file mode 100644 index 00000000..7b763764 --- /dev/null +++ b/tests/__snapshots__/lga8.snap.svg @@ -0,0 +1 @@ +{REF} \ No newline at end of file diff --git a/tests/lga.test.ts b/tests/lga.test.ts index 65f3f3d4..716180ec 100644 --- a/tests/lga.test.ts +++ b/tests/lga.test.ts @@ -63,3 +63,34 @@ test("lga rejects a side grid that does not match its pad count", () => { "requires 16 pads, got 14", ) }) + +const getMinPadToPadClearance = (footprint: string) => { + const pads = getPads(footprint) + let minClearance = Number.POSITIVE_INFINITY + for (let i = 0; i < pads.length; i++) { + for (let j = i + 1; j < pads.length; j++) { + const a = pads[i] + const b = pads[j] + if (!a || !b) continue + const dx = Math.max(0, Math.abs(a.x - b.x) - (a.width + b.width) / 2) + const dy = Math.max(0, Math.abs(a.y - b.y) - (a.height + b.height) / 2) + minClearance = Math.min(minClearance, Math.hypot(dx, dy)) + } + } + return minClearance +} + +test("lga14 and lga8 keep clearance between corner pads", () => { + // Regression test: with the default (derived) body size, the inner edge of + // the left/right pads landed exactly on the center line of the outermost + // top/bottom pads, so corner pads overlapped with 0mm clearance. + expect(getMinPadToPadClearance("lga14")).toBeGreaterThan(0.1) + expect(getMinPadToPadClearance("lga8")).toBeGreaterThan(0.1) + + expect( + convertCircuitJsonToPcbSvg(fp.string("lga14").circuitJson()), + ).toMatchSvgSnapshot(import.meta.path, "lga14") + expect( + convertCircuitJsonToPcbSvg(fp.string("lga8").circuitJson()), + ).toMatchSvgSnapshot(import.meta.path, "lga8") +})