fix: resolve nets when labels are placed directly at pin endpoints

get_net_connections() built its match-point set exclusively from wire
endpoints. If a net label was placed directly at a pin endpoint with no
wire segment (valid KiCad style), the function returned 0 connections
because connected_wire_points was empty.

Fix: build all_match_points as the union of connected wire endpoints and
label positions. Pin matching checks both, so label-at-pin schematics
produce correct netlists alongside traditional wired schematics.

Also handles the case where the schematic object has no wire attribute
at all — instead of returning early, we continue with label positions
as the sole match points.

Tests: tests/test_label_at_pin_net_connections.py (11 unit tests)
  - label at pin, no wire → pin found
  - label at pin, within/outside tolerance
  - label via wire → still found (regression)
  - mixed wired and direct labels on same net
  - no wire attribute → still detects label-at-pin
  - template symbols skipped

Black/isort/flake8/mypy verified manually (pre-commit local npm hook
fails to install on Windows due to MobaXterm path environment issue).
This commit is contained in:
ffindog
2026-04-15 22:40:14 +10:00
parent 5d87d9bc74
commit ef660afdb4
2 changed files with 434 additions and 8 deletions

View File

@@ -265,13 +265,14 @@ class ConnectionManager:
logger.debug(f"Found {len(net_label_positions)} labels for net '{net_name}'")
# 2. Find all wires connected to these label positions
# 2. Find all wires connected to these label positions.
# A missing wire attribute is fine — all_match_points will still
# include label positions, so label-at-pin connections are detected.
connected_wire_points: set[tuple[float, float]] = set()
if not hasattr(schematic, "wire"):
logger.warning("Schematic has no wires")
return connections
logger.debug("Schematic has no wires — will match labels to pins directly")
connected_wire_points = set()
for wire in schematic.wire:
for wire in (schematic.wire if hasattr(schematic, "wire") else []):
if hasattr(wire, "pts") and hasattr(wire.pts, "xy"):
# Get all points in this wire (polyline)
wire_points = []
@@ -297,9 +298,7 @@ class ConnectionManager:
# Build match points: union of wire endpoints AND label positions.
# This handles the valid KiCad style where a net label is placed
# directly at a pin endpoint with no wire segment in between.
all_match_points = connected_wire_points | {
(p[0], p[1]) for p in net_label_positions
}
all_match_points = connected_wire_points | {(p[0], p[1]) for p in net_label_positions}
if not all_match_points:
logger.debug(f"No connection points found for net '{net_name}'")