refactor: remove find_unconnected_pins tool (redundant with run_erc)

KiCad's native ERC already checks for unconnected pins with better
accuracy (hierarchical sheets, bus connections, custom rules). Remove
the reimplemented version and its dead helper _parse_no_connects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eugene Mikhantyev
2026-03-15 14:15:46 +00:00
parent dc3dc06af1
commit 1ef4ce5cab
5 changed files with 0 additions and 227 deletions

View File

@@ -135,20 +135,6 @@ def _parse_symbols(sexp_data: list) -> List[Dict[str, Any]]:
return symbols
def _parse_no_connects(sexp_data: list) -> Set[Tuple[float, float]]:
"""Parse all no_connect elements and return their positions as (x, y) tuples in mm."""
positions: Set[Tuple[float, float]] = set()
for item in sexp_data:
if not isinstance(item, list) or len(item) < 2:
continue
if item[0] != Symbol("no_connect"):
continue
for sub in item:
if isinstance(sub, list) and len(sub) >= 3 and sub[0] == Symbol("at"):
positions.add((float(sub[1]), float(sub[2])))
break
return positions
def _parse_lib_symbol_graphics(symbol_def: list) -> List[Tuple[float, float]]:
"""
@@ -434,107 +420,6 @@ def _compute_symbol_bbox_direct(
return (min_x, min_y, max_x, max_y)
# ---------------------------------------------------------------------------
# Tool 2: find_unconnected_pins
# ---------------------------------------------------------------------------
def find_unconnected_pins(schematic_path: Path) -> List[Dict[str, Any]]:
"""
Find all component pins with no wire, label, or power symbol touching them.
Returns list of dicts: {reference, libId, pinNumber, pinName, position: {x, y}}
"""
sexp_data = _load_sexp(schematic_path)
symbols = _parse_symbols(sexp_data)
wires = _parse_wires(sexp_data)
labels = _parse_labels(sexp_data)
no_connects = _parse_no_connects(sexp_data)
# Build set of "connected" positions in mm
connected: Set[Tuple[float, float]] = set()
# Wire endpoints
for w in wires:
connected.add(w["start"])
connected.add(w["end"])
# Label positions
for lbl in labels:
connected.add((lbl["x"], lbl["y"]))
# Power symbol positions (they implicitly connect)
for sym in symbols:
if sym["is_power"]:
connected.add((sym["x"], sym["y"]))
tolerance = 0.05 # mm
def _snap(v: float) -> int:
"""Snap coordinate to grid for O(1) set lookup."""
return round(v / tolerance)
connected_grid: set = set()
for pos in connected:
connected_grid.add((_snap(pos[0]), _snap(pos[1])))
no_connect_grid: set = set()
for pos in no_connects:
no_connect_grid.add((_snap(pos[0]), _snap(pos[1])))
def is_connected(px: float, py: float) -> bool:
sx, sy = _snap(px), _snap(py)
# Check the snapped cell and immediate neighbors to handle edge cases
for dx in (-1, 0, 1):
for dy in (-1, 0, 1):
if (sx + dx, sy + dy) in connected_grid:
return True
return False
def is_no_connect(px: float, py: float) -> bool:
sx, sy = _snap(px), _snap(py)
for dx in (-1, 0, 1):
for dy in (-1, 0, 1):
if (sx + dx, sy + dy) in no_connect_grid:
return True
return False
lib_defs = _extract_lib_symbols(sexp_data)
unconnected = []
for sym in symbols:
ref = sym["reference"]
# Skip power symbols, templates, and empty references
if sym["is_power"] or ref.startswith("_TEMPLATE") or not ref:
continue
lib_data = lib_defs.get(sym["lib_id"], {})
pin_defs = lib_data.get("pins", {})
if not pin_defs:
continue
pin_positions = _compute_pin_positions_direct(sym, pin_defs)
if not pin_positions:
continue
for pin_num, pos in pin_positions.items():
px, py = pos[0], pos[1]
if is_no_connect(px, py):
continue
if is_connected(px, py):
continue
pin_name = pin_defs.get(pin_num, {}).get("name", pin_num)
unconnected.append({
"reference": ref,
"libId": sym["lib_id"],
"pinNumber": pin_num,
"pinName": pin_name,
"position": {"x": round(px, 4), "y": round(py, 4)},
})
return unconnected
# ---------------------------------------------------------------------------
# Tool 3: find_overlapping_elements