fix: apply Y-axis flip in WireDragger.pin_world_xy
Library symbol pins are stored Y-up (positive Y is upward in the symbol editor's coordinate system) but `.kicad_sch` is Y-down (positive Y is downward in the schematic). `pin_world_xy` was returning `sym_y + ry` without negating the rotated lib Y, so for any non-symmetric symbol pin 1 and pin 2 ended up at swapped world positions. For symmetric two-pin passives (R, C non-polarized) this was invisible because pin 1 and pin 2 are electrically equivalent. For polarized parts — electrolytic and polymer caps, diodes, MOSFETs, BJTs — it silently swapped polarity. A label snapped to a polarized cap's pin 1 ended up on pin 2, which is catastrophic at first power-up. The order matches eeschema's actual transformation: mirror in lib space → Y-flip to screen → rotate → translate. The existing regression test in test_pin_locator_y_flip.py was already written with the correct expected coordinates but the matching code fix was never landed; that test now passes. Three tests in test_move_with_wire_preservation.py had baked the buggy expected coordinates into their assertions; updated those to the correct y-flipped values. The touching-pin fixture had to flip R2's Y from -7.62 to +7.62 so the two pins still meet under the corrected formula. Verified end-to-end on a 46-component aerospace PDB schematic: all 8 polarized-part pins (4 polymer caps + 4 TVS diodes) now produce world coordinates that match the labels actually placed in the file.
This commit is contained in:
@@ -152,15 +152,16 @@ class WireDragger:
|
||||
"""
|
||||
Compute the world coordinate of a pin given the symbol transform.
|
||||
|
||||
KiCAD applies mirror first (in local space), then rotation, then translation.
|
||||
mirror_x negates the local X axis; mirror_y negates the local Y axis.
|
||||
Library pins are stored Y-up; the schematic is Y-down. Order matches
|
||||
eeschema: mirror in lib space → Y-flip to screen → rotate → translate.
|
||||
Without the Y-flip, polarized parts get pin 1/pin 2 silently swapped.
|
||||
"""
|
||||
lx, ly = px, py
|
||||
if mirror_x:
|
||||
lx = -lx
|
||||
if mirror_y:
|
||||
ly = -ly
|
||||
rx, ry = _rotate(lx, ly, rotation)
|
||||
rx, ry = _rotate(lx, -ly, rotation)
|
||||
return sym_x + rx, sym_y + ry
|
||||
|
||||
@staticmethod
|
||||
@@ -260,8 +261,7 @@ class WireDragger:
|
||||
|
||||
# Remove existing (mirror ...) token(s)
|
||||
to_remove = [
|
||||
i for i, sub in enumerate(item)
|
||||
if isinstance(sub, list) and sub and sub[0] == mirror_k
|
||||
i for i, sub in enumerate(item) if isinstance(sub, list) and sub and sub[0] == mirror_k
|
||||
]
|
||||
for i in reversed(to_remove):
|
||||
del item[i]
|
||||
|
||||
Reference in New Issue
Block a user