Repository navigation
fix(routing): turn rotated footprints' Specctra pins once - #847
Open
pauliuszaleckas wants to merge 1 commit into
Open
pauliuszaleckas wants to merge 1 commit into
pauliuszaleckas wants to merge 1 commit into
Conversation
A .kicad_pcb pad angle already includes the footprint's, and the DSN place turns the image again. Write a pin's rotate relative to its footprint, as KiCad does (%.6g, [0, 360)). Read an optional rotate when correlating a native DSN, and compare it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
export_specctra_dsn's Rust exporter, the defaultdisablepath, turned the pads of every rotated footprint twice. In a.kicad_pcb, a pad's(at x y angle)angle already includes its footprint's rotation. The exporter wrote that angle as the pin's(rotate ...), and the component's(place ... <rotation>)turned it again. So Freerouting routed around a 90° footprint's 600×500 µm pads as 500×600. The same(rotate ...)also brokeadopt_native_dsn, becausedsn_identityread the pin number at a fixed index. Any KiCad DSN with a rotated pad was refused withDSN is missing pin number.Closes #840
Approach
footprints()now stores a pad's angle relative to its footprint (pin_rotation), like itsx_um/y_um. It is normalized to [0, 360) and kept to six significant digits, which is how KiCad's exporter prints it (%.6g, measured below). The writer still omits(rotate ...)when it is 0.dsn_identityreads(pin <padstack> [(rotate <deg>)] <number> <x> <y>).correlate_componentscompares the pin rotation next to the existing x/y check, and refuses a mismatch withnative DSN changed pin rotation for component '<ref>' pin '<n>'.Departure from the issue. The issue's suggested direction is "pad angle minus footprint angle, normalized". Code review then pointed out that KiCad prints a pin's rotate with
%.6g. I measured it on KiCad 10.0.6: a pad 12.3456789° inside its footprint is written(rotate 12.3457). Rounding to six decimals would write12.345679, and native adoption would refuse that board. Sopin_rotationkeeps six significant digits. The same probe showed that KiCad writes(place ...)at full precision (33.3333333), so the placement comparison is unchanged.Architectural fit
This fixes the fail-closed Rust exporter and the native correlation that #670 set up in
specctra.rs. It adds no new module and no workaround.Out of scope:
dsn_identityaccepts only whole micrometres. The 45° board is used to compare pin rotations against KiCad's DSN.Branch and dependencies
main@9488e5f, one commit. Depends on nothing.specctra.rs(correlate_components,footprints(), the test module),pcb_export.rs(each adds a served test module at the end of the file) anddocs/API_MIGRATIONS.md. Whichever merges second needs a mechanical rebase. I'll do it once when asked.Compatibility and safety
There are no argument, response-field, manifest or schema changes. The DSN content changes for any board with a rotated footprint or an in-footprint pad rotation; the
API_MIGRATIONS.mdentry describes it.export_specctra_dsnwrites only the DSN and its manifest, so no board or schematic is mutated.Validation
Changed tool behavior
board,outputandnative_bridge_mode(defaultdisable) are the same.require, a native DSN whose pin rotation differs from the Rust export's is refused with the existing semantic-validation error, now namingpin rotation. Underprefer, it falls back to the Rust export and reports it in the bridge diagnostics.native_dsn_that_turns_a_pin_is_refusedcovers this.SaveDocumentToStringsnapshot of the requested board. The served test goes throughMcpHandler::handle_messageagainst a mock KiCad holding the fixture.(rotate ...)now equals KiCad's own DSN for the same board. This is checked pin by pin on 0°, 45° and 90° footprints, including in-footprint turns of 12.3456789°, 90° and −90° (rotated_footprint_pins_carry_the_rotation_kicad_writesand the served test). Placements, pin positions, padstacks, nets and rules are unchanged. KiCad's DSN of a rotated board is now adopted byte-for-byte (native_dsn_of_rotated_footprints_is_adopted).Fixtures and oracle.
specctra_rotated_footprints{,_45}.kicad_pcbwere built fromspecctra_two_resistors.kicad_pcbwith KiCad 10.0.6pcbnewPython and saved throughpcbnew.SaveBoard. The oracle is KiCad'spcbnew.ExportSpecctraDSNof each saved board; only the root path atom was normalized. The script and the per-pin table are inspecctra_rotated_footprints.README.md:(rotate ...)_45)Live KiCad. I ran pcbnew 10.0.6 under a headless Weston with IPC, opened a copy of
specctra_rotated_footprints_45.kicad_pcb, and calledexport_specctra_dsnover stdio:(rotate ...)written102.3456789×2, R345×2, R4-1180target/debug/konnect)12.3457×2, R4-190, R4-2270, which is KiCad's DSNThe installed plugin has no native bridge, so I didn't run
prefer/requirelive. Adoption is covered by the unit tests against KiCad's real DSN.Negative controls. Each guard was neutered in turn,
cargo test -p konnect-core --lib --tests --no-fail-fastwas run, and the file was restored. A diff hash confirmed the tree was unchanged.pin_rotationsubtracts the footprint angle (- 0.0 * footprint_degrees)rotated_footprint_pins_carry_the_rotation_kicad_writes,native_dsn_of_rotated_footprints_is_adopted,pin_rotation_drops_float_noise,served_export_turns_only_pins_turned_inside_their_footprintrem_euclidremoved)rotated_footprint_pins_carry_the_rotation_kicad_writes,native_dsn_of_rotated_footprints_is_adopted,served_export_…{turn:.5e}→{turn})rotated_footprint_pins_carry_the_rotation_kicad_writes,native_dsn_of_rotated_footprints_is_adopted,pin_rotation_drops_float_noise,served_export_…dsn_identityskips an optional(rotate ...)(false &&)native_dsn_of_rotated_footprints_is_adopted,native_dsn_that_turns_a_pin_is_refusedcorrelate_componentscompares pin rotation (false &&)native_dsn_that_turns_a_pin_is_refusedLocal gate on head
2db04ed:cargo fmt --all -- --check: cleancargo clippy --workspace --locked --all-targets -- -D warnings: cleancargo test -p konnect-core --locked reliability_contract: 2 passedcargo test --workspace --locked --lib --tests: 2394 passed, 0 failed, 45 ignoredcargo test --workspace --locked --doc: 9 passedcargo xtask fix-doc-counts --check: current#[ignore]d Freerouting tests, which need Java andFREEROUTING_JAR.Code review findings I did not apply:
%.6g: rejected. KiCad 10.0.6 writes(place ...)at full precision (33.3333333).Risk and rollback
The risk is low. The change is confined to Rust Specctra export and native correlation. Boards whose footprints are all at 0° with pad angles of at most six significant digits export byte-for-byte as before. Rolling back means reverting this commit, which restores the double rotation.
🤖 Generated with Claude Code