Skip to content

fix(quad): throw on zero pitch instead of emitting NaN pad coordinates - #901

Closed
Furox-Art wants to merge 2 commits into
tscircuit:mainfrom
Furox-Art:fix/quad-zero-pitch-nan
Closed

Furox-Art wants to merge 2 commits into
tscircuit:mainfrom
Furox-Art:fix/quad-zero-pitch-nan

Conversation

@Furox-Art

Copy link
Copy Markdown

Fixes #871.

Problem

Passing an explicit zero pitch to a quad-family footprint (lcc_p0mm, qfn16_p0mm, ...) produced NaN pad x/y coordinates — serialized as null by JSON.stringify, silently invalidating the circuit-json.

Root cause

In src/fn/quad.ts, quadTransform uses falsy checks (if (!v.w && !v.h && v.p)) to decide whether to derive body size from pitch. With p=0 (explicitly set via p0mm), v.p is falsy → sizing branch skipped → v.w/v.h stay undefined → getQuadCoords computes x: -w/2 - pcdfe + 0.1 = NaN.

Fix

Throw a clear Invalid pitch error in quadTransform when p, px or py is exactly 0. The guard is unconditional (not wrapped in other option checks) because wrapper-level defaults like lcc's pl/pw would otherwise bypass it — and a zero pitch stacks all pads regardless of body size anyway.

Testing

New tests/quad-zero-pitch.test.ts (3 tests pass):

  • lcc_p0mm and qfn16_p0mm throw /Invalid pitch.*positive pitch/ instead of NaN
  • lcc_px0mm throws as well
  • Existing quad/lcc/qfn suites (10 tests) stay green

Passing an explicit zero pitch (e.g. lcc_p0mm) made quadTransform skip
the falsy-guarded sizing branch (v.p = 0 is falsy), leaving w/h
undefined; getQuadCoords then computed NaN pad x/y, which JSON.stringify
serializes as null into circuit-json with no error.

Throw a clear 'Invalid pitch' error at transform time instead. Covers
p, px and py zero values regardless of wrapper-level defaults (lcc sets
pl/pw), since a zero pitch stacks all pads regardless of body size.
@Furox-Art

Copy link
Copy Markdown
Author

Friendly maintainer review request: this contribution has been updated with the latest fixes and checks. Please review when convenient. Thank you.

The guard only matched `=== 0`, so a negative pitch survived it. With an
explicit body size (`w`/`h`) the falsy `v.p` checks all pass, so the
negative pitch silently mirrored/stacked the pad rows and was emitted as
valid circuit-json; without a body size it surfaced much later as an
unrelated "Each rectangle bound must have min < max on both axes" error.

Covered p, px and py. The post-guard pitch derivations stay unguarded on
purpose: they are gated on `!v.p`, and every quad family inherits the
0.5mm default for `p`, so once non-positive pitches throw those branches
are unreachable.
@Furox-Art

Copy link
Copy Markdown
Author

Re-verified against current main (69b6d99, v0.0.430) as a negative control:

run result
tests/quad-zero-pitch.test.ts with the fix 6 pass / 0 fail
same file on pristine main 1 pass / 5 fail — incl. negative pitch throws instead of silently mirroring pad coordinates, explicit negative px/py also throws

The NaN pad coordinates from the issue are still produced by today's main; this diff makes the parser throw instead.

Full suite: 589 pass / 3 fail here vs 583 pass / 3 fail on main — identical pre-existing Windows failures (smf, parity/sod523, diode-kicad-parity/sod523), so no regression. CI on this head is green (test, build, format-check) and the branch is MERGEABLE + CLEAN.

Ready to merge at your convenience. A conflict-free rebase onto 69b6d99 is prepared locally and can be pushed on request — not pushed now because it would reset green CI to pending.

@Furox-Art Furox-Art closed this by deleting the head repository Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: zero pitch on quad-family footprints produces NaN pad coordinates

1 participant