Fix two regressions from PR #88 (rotate/mirror)

1. add_schematic_net_label failed on schematics with no existing labels.
   The clone-based path required a pre-existing label to copy from;
   the documented "fallback to sexpdata" was a misleading log line —
   the RuntimeError was caught and the call silently returned False.
   Restore hand-built sexpdata construction (without the buggy
   fields_autoplaced token, with orientation-aware justify).

2. get_pin_angle returned the wrong angle for every mirrored symbol
   (off by exactly 180°, all rotations, both mirror axes). The
   mirror_x and mirror_y formulas were swapped relative to the
   pin_world_xy convention — pin_world_xy mirrors a position by
   flipping its local axis component, so the matching angle
   transform is (180 - θ) for mirror_x and -θ for mirror_y.

Add regression tests:
- test_add_label_empty_schematic.py — first label on empty schematic,
  orientation-aware justify.
- test_get_pin_angle.py — full 24-case matrix
  (4 rotations × 3 mirror states × 2 pins).
This commit is contained in:
Eugene Mikhantyev
2026-04-29 21:40:39 +01:00
parent 109ba3f23a
commit 5907954b3e
4 changed files with 309 additions and 21 deletions

View File

@@ -280,12 +280,12 @@ class PinLocator:
pin_def_angle = pins[pin_number].get("angle", 0)
# Mirror flips the angle before applying symbol rotation.
# mirror_x negates the Y component → reflects angle across X axis → negate angle.
# mirror_y negates the X component → reflects angle across Y axis → 180 - angle.
# mirror_x flips the X component of local vectors → reflects across Y axis → 180 - angle.
# mirror_y flips the Y component of local vectors → reflects across X axis → negate angle.
if mirror_x:
pin_def_angle = (-pin_def_angle) % 360
if mirror_y:
pin_def_angle = (180 - pin_def_angle) % 360
if mirror_y:
pin_def_angle = (-pin_def_angle) % 360
absolute_angle = (pin_def_angle + symbol_rotation) % 360
return absolute_angle
@@ -374,9 +374,13 @@ class PinLocator:
from commands.wire_dragger import WireDragger
abs_x, abs_y = WireDragger.pin_world_xy(
pin_data["x"], pin_data["y"],
symbol_x, symbol_y,
symbol_rotation, mirror_x, mirror_y,
pin_data["x"],
pin_data["y"],
symbol_x,
symbol_y,
symbol_rotation,
mirror_x,
mirror_y,
)
logger.info(f"Pin {symbol_reference}/{pin_number} located at ({abs_x}, {abs_y})")