fix: check_wire_collisions now detects wires that short two pins of the same component
Previously, the endpoint suppression logic skipped any wire where at least one endpoint touched a pin, hiding the case where both endpoints are pins of the same component (a direct pin-to-pin short through the body). Replace the single endpoint_matches_pin loop with separate start_at_pin / end_at_pin checks; suppress only when exactly one endpoint is at a pin. Add regression test to cover this case. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -654,19 +654,25 @@ def check_wire_collisions(schematic_path: Path) -> List[Dict[str, Any]]:
|
|||||||
if not _line_segment_intersects_aabb(sx, sy, ex, ey, bx1, by1, bx2, by2):
|
if not _line_segment_intersects_aabb(sx, sy, ex, ey, bx1, by1, bx2, by2):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Check if either wire endpoint matches a pin of this symbol
|
# Check which endpoints land on a pin of this symbol
|
||||||
endpoint_matches_pin = False
|
start_at_pin = any(
|
||||||
for px, py in sd["pin_set"]:
|
abs(sx - px) < pin_tolerance and abs(sy - py) < pin_tolerance
|
||||||
if (abs(sx - px) < pin_tolerance and abs(sy - py) < pin_tolerance):
|
for px, py in sd["pin_set"]
|
||||||
endpoint_matches_pin = True
|
)
|
||||||
break
|
end_at_pin = any(
|
||||||
if (abs(ex - px) < pin_tolerance and abs(ey - py) < pin_tolerance):
|
abs(ex - px) < pin_tolerance and abs(ey - py) < pin_tolerance
|
||||||
endpoint_matches_pin = True
|
for px, py in sd["pin_set"]
|
||||||
break
|
)
|
||||||
|
|
||||||
if not endpoint_matches_pin:
|
# Suppress only when exactly ONE endpoint is at a pin: the wire arrives
|
||||||
sym = sd["sym"]
|
# from elsewhere and terminates at this component (a valid connection).
|
||||||
collisions.append({
|
# If BOTH endpoints match pins of this same component, the wire shorts
|
||||||
|
# two pins while traversing the body — that IS a collision.
|
||||||
|
if (start_at_pin or end_at_pin) and not (start_at_pin and end_at_pin):
|
||||||
|
continue
|
||||||
|
|
||||||
|
sym = sd["sym"]
|
||||||
|
collisions.append({
|
||||||
"wire": {
|
"wire": {
|
||||||
"start": {"x": sx, "y": sy},
|
"start": {"x": sx, "y": sy},
|
||||||
"end": {"x": ex, "y": ey},
|
"end": {"x": ex, "y": ey},
|
||||||
|
|||||||
@@ -415,6 +415,23 @@ class TestIntegrationCheckWireCollisions:
|
|||||||
"likely caused by reference-lookup always returning the first 'R?'"
|
"likely caused by reference-lookup always returning the first 'R?'"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_wire_shorts_component_pins_detected_as_collision(self):
|
||||||
|
"""Regression: a wire connecting pin1→pin2 of the same component
|
||||||
|
must be reported even though both endpoints land on pins."""
|
||||||
|
r_sexp = _make_resistor_sexp("R_short", 100.0, 100.0)
|
||||||
|
wire_sexp = (
|
||||||
|
'(wire (pts (xy 100 103.81) (xy 100 96.19))\n'
|
||||||
|
' (stroke (width 0) (type default))\n'
|
||||||
|
' (uuid "aaaaaaaa-0000-0000-0000-000000000001"))'
|
||||||
|
)
|
||||||
|
sch = _make_temp_schematic(r_sexp + "\n" + wire_sexp)
|
||||||
|
collisions = check_wire_collisions(sch)
|
||||||
|
assert len(collisions) == 1
|
||||||
|
w = collisions[0]["wire"]
|
||||||
|
assert w["start"]["x"] == pytest.approx(100.0)
|
||||||
|
assert w["start"]["y"] == pytest.approx(103.81)
|
||||||
|
assert collisions[0]["component"]["reference"] == "R_short"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.integration
|
@pytest.mark.integration
|
||||||
class TestIntegrationGetElementsInRegion:
|
class TestIntegrationGetElementsInRegion:
|
||||||
|
|||||||
Reference in New Issue
Block a user