fix(pin_locator): apply lib→screen Y-flip to get_pin_angle

PR #145 restored the Y-axis flip in WireDragger.pin_world_xy so pin
coordinates now match the schematic (Y-down) frame instead of the
library (Y-up) frame. PinLocator.get_pin_angle was the companion to
that transform but never received the matching fix: it was returning
the library-frame angle (with mirror handling but no Y-flip), so
angles came out 180° off along the Y axis.

This was masked before PR #145 because pin_world_xy was wrong in the
same direction — both functions skipped the Y-flip, so callers that
compared pin endpoints to angles saw a self-consistent picture. Once
pin_world_xy was corrected the inconsistency surfaced.

Apply the same lib→screen Y-flip (negate angle) after the mirror
handling and before the symbol-rotation add, matching pin_world_xy's
order: mirror in lib space → Y-flip → rotate → translate (no
translate for angles since angles are translation-invariant).

Fixes the 24 parametrized cases in
tests/test_get_pin_angle.py::test_get_pin_angle_matches_geometric_expectation
(pin × mirror × rotation matrix). The test derives its expected value
from pin_world_xy itself, making it the canonical geometric oracle.
test_pin_locator_y_flip and test_move_with_wire_preservation continue
to pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Eugene Mikhantyev
2026-05-03 21:50:14 +01:00
parent 84ba778d60
commit 3c225809b9

View File

@@ -287,6 +287,15 @@ class PinLocator:
if mirror_y: if mirror_y:
pin_def_angle = (-pin_def_angle) % 360 pin_def_angle = (-pin_def_angle) % 360
# Library symbols are Y-up; the schematic is Y-down. Match the
# lib→screen Y-flip applied by WireDragger.pin_world_xy (mirror in
# lib space → Y-flip → rotate → translate). For an angle this
# negates the Y component, i.e. negates the angle. Without this
# step pin angles are 180° off along the Y axis; before PR #145
# this was masked because pin_world_xy was missing the same flip,
# so the two were "wrong in the same direction" and consistent.
pin_def_angle = (-pin_def_angle) % 360
absolute_angle = (pin_def_angle + symbol_rotation) % 360 absolute_angle = (pin_def_angle + symbol_rotation) % 360
return absolute_angle return absolute_angle