From 718f226c24c6414ec15002c3cb6af04acf6af80f Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Mon, 9 Mar 2026 02:01:59 -0600 Subject: [PATCH] Add Y-flip swap for vertical pin rotation in sexp fallback Pin angles in lib_symbol use Y-up convention. After applying component rotation, vertical directions (90/270) must be swapped to account for the lib Y-up to schematic Y-down coordinate transform. Without this, vertical stubs on non-mirrored components point into the body instead of away from it, causing label_multiple_wires ERC violations. --- src/mckicad/utils/sexp_parser.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/mckicad/utils/sexp_parser.py b/src/mckicad/utils/sexp_parser.py index 0facfd7..d2bf271 100644 --- a/src/mckicad/utils/sexp_parser.py +++ b/src/mckicad/utils/sexp_parser.py @@ -1128,11 +1128,22 @@ def resolve_pin_position_and_orientation( target_pin["x"], target_pin["y"], cx, cy, comp_rot, mirror_x, ) - # Compute schematic-space pin rotation + # Compute schematic-space pin rotation. + # Pin angles in lib_symbol use Y-up convention. After applying the + # component rotation, vertical directions must be swapped (90 <-> 270) + # to account for the lib Y-up -> schematic Y-down coordinate flip. + # For mirrored components, the mirror is applied first. pin_rot = target_pin["rotation"] if mirror_x: pin_rot = (180 - pin_rot) % 360 schematic_rot = (pin_rot + comp_rot) % 360 + # Y-flip: swap vertical directions for non-mirrored components. + # Mirror already handles the inversion via (180 - pin_rot). + if not mirror_x: + if schematic_rot == 90: + schematic_rot = 270 + elif schematic_rot == 270: + schematic_rot = 90 logger.debug( "Resolved pin %s.%s via sexp fallback: (%.2f, %.2f) @ %.0f°",