fix: harden get_wire_connections against edge cases and improve performance
- Add +1 safety margin to grid_radius to handle banker's rounding at cell boundaries in the spatial index - Move symbol property guards inside per-symbol try/except to prevent AttributeError from aborting all pin processing - Replace O(n) connected_points scan for pin matching with spatial index lookup (_frontier_has_neighbour), consistent with flood-fill approach - Wrap float(x)/float(y) conversion with clear user-facing error message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2335,7 +2335,10 @@ class KiCADInterface:
|
|||||||
if not all([schematic_path, x is not None, y is not None]):
|
if not all([schematic_path, x is not None, y is not None]):
|
||||||
return {"success": False, "message": "Missing required parameters: schematicPath, x, y"}
|
return {"success": False, "message": "Missing required parameters: schematicPath, x, y"}
|
||||||
|
|
||||||
x, y = float(x), float(y)
|
try:
|
||||||
|
x, y = float(x), float(y)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return {"success": False, "message": "Parameters x and y must be numeric"}
|
||||||
tolerance = 0.5
|
tolerance = 0.5
|
||||||
|
|
||||||
def points_coincide(p1, p2):
|
def points_coincide(p1, p2):
|
||||||
@@ -2379,7 +2382,7 @@ class KiCADInterface:
|
|||||||
# Spatial index: grid-snapped dict for O(1) proximity lookup
|
# Spatial index: grid-snapped dict for O(1) proximity lookup
|
||||||
import math
|
import math
|
||||||
GRID = 0.05 # mm, matches KiCAD schematic grid
|
GRID = 0.05 # mm, matches KiCAD schematic grid
|
||||||
grid_radius = math.ceil(tolerance / GRID) # cells to check per axis
|
grid_radius = math.ceil(tolerance / GRID) + 1 # cells to check per axis (+1 safety margin for banker's rounding)
|
||||||
|
|
||||||
def _grid_key(x_coord, y_coord):
|
def _grid_key(x_coord, y_coord):
|
||||||
return (round(x_coord / GRID), round(y_coord / GRID))
|
return (round(x_coord / GRID), round(y_coord / GRID))
|
||||||
@@ -2448,28 +2451,25 @@ class KiCADInterface:
|
|||||||
processed_refs = set()
|
processed_refs = set()
|
||||||
|
|
||||||
for symbol in schematic.symbol:
|
for symbol in schematic.symbol:
|
||||||
if not hasattr(symbol.property, "Reference"):
|
|
||||||
continue
|
|
||||||
ref = symbol.property.Reference.value
|
|
||||||
if ref.startswith("_TEMPLATE"):
|
|
||||||
continue
|
|
||||||
if ref in processed_refs:
|
|
||||||
continue
|
|
||||||
processed_refs.add(ref)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if not hasattr(symbol, 'property') or not hasattr(symbol.property, "Reference"):
|
||||||
|
continue
|
||||||
|
ref = symbol.property.Reference.value
|
||||||
|
if ref.startswith("_TEMPLATE"):
|
||||||
|
continue
|
||||||
|
if ref in processed_refs:
|
||||||
|
continue
|
||||||
|
processed_refs.add(ref)
|
||||||
all_pins = locator.get_all_symbol_pins(Path(schematic_path), ref)
|
all_pins = locator.get_all_symbol_pins(Path(schematic_path), ref)
|
||||||
if not all_pins:
|
if not all_pins:
|
||||||
continue
|
continue
|
||||||
for pin_num, pin_data in all_pins.items():
|
for pin_num, pin_data in all_pins.items():
|
||||||
pin_loc = [pin_data[0], pin_data[1]]
|
pin_loc = [pin_data[0], pin_data[1]]
|
||||||
for cp in connected_points:
|
if _frontier_has_neighbour(pin_loc[0], pin_loc[1]):
|
||||||
if points_coincide(pin_loc, list(cp)):
|
key = (ref, pin_num)
|
||||||
key = (ref, pin_num)
|
if key not in seen:
|
||||||
if key not in seen:
|
seen.add(key)
|
||||||
seen.add(key)
|
pins.append({"component": ref, "pin": pin_num})
|
||||||
pins.append({"component": ref, "pin": pin_num})
|
|
||||||
break
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"Error checking pins for {ref}: {e}")
|
logger.warning(f"Error checking pins for {ref}: {e}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user