feat: add get_net_at_point tool for coordinate-based net lookup

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Eugene Mikhantyev
2026-04-12 15:29:46 +01:00
parent 5f3c20d308
commit e826cf3d32
5 changed files with 564 additions and 0 deletions

View File

@@ -331,3 +331,53 @@ def get_pin_net(schematic: Any, schematic_path: str, x_mm: float, y_mm: float) -
pins = _find_pins_on_net(net_points, schematic_path, schematic)
return {"net": net, "pins": pins, "wires": wires_out, "query_point": {"x": x_mm, "y": y_mm}}
def get_net_at_point(
schematic: Any, schematic_path: str, x_mm: float, y_mm: float
) -> Dict[str, Any]:
"""Return the net name at the given coordinate, or null if none found.
Checks net label positions first (exact IU match within tolerance), then
wire endpoints. Returns a dict with keys:
- "net_name": str or None
- "position": {"x": float, "y": float}
- "source": "net_label" | "wire_endpoint" | None
"""
query_iu = _to_iu(x_mm, y_mm)
position = {"x": x_mm, "y": y_mm}
# Build label map from schematic
point_to_label, _ = _parse_virtual_connections(schematic, schematic_path)
# Check if query point is exactly on a net label / power symbol position
label_name = point_to_label.get(query_iu)
if label_name is not None:
return {"net_name": label_name, "position": position, "source": "net_label"}
# Check if query point is on a wire endpoint
all_wires = _parse_wires(schematic) if hasattr(schematic, "wire") else []
if all_wires:
_, iu_to_wires = _build_adjacency(all_wires)
if query_iu in iu_to_wires:
# Found a wire endpoint — trace the net to get the name
adjacency, _ = _build_adjacency(all_wires)
visited, net_points = _find_connected_wires(
x_mm,
y_mm,
all_wires,
iu_to_wires,
adjacency,
point_to_label=point_to_label,
label_to_points=None,
)
if visited is not None:
net: Optional[str] = None
if net_points:
for pt in net_points:
net = point_to_label.get(pt)
if net is not None:
break
return {"net_name": net, "position": position, "source": "wire_endpoint"}
return {"net_name": None, "position": position, "source": None}

View File

@@ -382,6 +382,7 @@ class KiCADInterface:
"get_schematic_pin_locations": self._handle_get_schematic_pin_locations,
"get_net_connections": self._handle_get_net_connections,
"get_wire_connections": self._handle_get_wire_connections,
"get_net_at_point": self._handle_get_net_at_point,
"get_pin_net": self._handle_get_pin_net,
"run_erc": self._handle_run_erc,
"generate_netlist": self._handle_generate_netlist,
@@ -2504,6 +2505,40 @@ class KiCADInterface:
logger.error(traceback.format_exc())
return {"success": False, "message": str(e)}
def _handle_get_net_at_point(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""Return the net name at a given (x, y) coordinate, or null if none found."""
logger.info("Getting net at point")
try:
from commands.wire_connectivity import get_net_at_point
schematic_path = params.get("schematicPath")
if not schematic_path:
return {"success": False, "message": "Missing required parameter: schematicPath"}
x = params.get("x")
y = params.get("y")
if x is None or y is None:
return {"success": False, "message": "Missing required parameters: x and y"}
try:
x, y = float(x), float(y)
except (TypeError, ValueError):
return {"success": False, "message": "Parameters x and y must be numeric"}
schematic = SchematicManager.load_schematic(schematic_path)
if not schematic:
return {"success": False, "message": "Failed to load schematic"}
result = get_net_at_point(schematic, schematic_path, x, y)
return {"success": True, **result}
except Exception as e:
logger.error(f"Error getting net at point: {str(e)}")
import traceback
logger.error(traceback.format_exc())
return {"success": False, "message": str(e)}
def _handle_get_pin_net(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""Find net name and all connected pins for a reference+pin or coordinate query"""
logger.info("Getting pin net")

View File

@@ -1523,6 +1523,35 @@ SCHEMATIC_TOOLS = [
"required": ["schematicPath", "x", "y"],
},
},
{
"name": "get_net_at_point",
"title": "Get Net At Point",
"description": (
"Returns the net name at a given (x, y) coordinate in a schematic, "
"or null if no net label or wire endpoint is present at that position. "
"Checks net label positions first, then wire endpoints. "
"Useful for quickly identifying what net occupies a specific coordinate "
"without traversing the full wire graph."
),
"inputSchema": {
"type": "object",
"properties": {
"schematicPath": {
"type": "string",
"description": "Path to the schematic file (.kicad_sch)",
},
"x": {
"type": "number",
"description": "X coordinate in mm",
},
"y": {
"type": "number",
"description": "Y coordinate in mm",
},
},
"required": ["schematicPath", "x", "y"],
},
},
{
"name": "get_pin_net",
"title": "Get Pin Net",