feat: add snap_to_grid schematic tool
Adds a new MCP tool that snaps wire endpoints, junction positions, and net label coordinates to the nearest grid point (default 2.54 mm). Off-grid coordinates cause wires that appear visually connected to fail ERC checks because KiCAD uses exact IU integer matching internally; this tool eliminates that class of error before running ERC. - python/commands/schematic_snap.py: core snap logic with in-place sexp mutation - python/kicad_interface.py: route + handler - python/schemas/tool_schemas.py: JSON schema (gridSize, elements params) - src/tools/schematic.ts: TypeScript MCP tool registration - tests/test_snap_to_grid.py: 20 unit + integration tests (all passing) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -404,6 +404,7 @@ class KiCADInterface:
|
||||
"get_elements_in_region": self._handle_get_elements_in_region,
|
||||
"find_wires_crossing_symbols": self._handle_find_wires_crossing_symbols,
|
||||
"find_orphaned_wires": self._handle_find_orphaned_wires,
|
||||
"snap_to_grid": self._handle_snap_to_grid,
|
||||
"import_svg_logo": self._handle_import_svg_logo,
|
||||
# UI/Process management commands
|
||||
"check_kicad_ui": self._handle_check_kicad_ui,
|
||||
@@ -2962,6 +2963,38 @@ class KiCADInterface:
|
||||
logger.error(traceback.format_exc())
|
||||
return {"success": False, "message": str(e)}
|
||||
|
||||
def _handle_snap_to_grid(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Snap schematic element coordinates to the nearest grid point"""
|
||||
logger.info("Snapping schematic elements to grid")
|
||||
try:
|
||||
from pathlib import Path
|
||||
|
||||
from commands.schematic_snap import snap_to_grid
|
||||
|
||||
schematic_path = params.get("schematicPath")
|
||||
if not schematic_path:
|
||||
return {"success": False, "message": "schematicPath is required"}
|
||||
|
||||
grid_size = float(params.get("gridSize", 2.54))
|
||||
elements = params.get("elements") # None → defaults inside snap_to_grid
|
||||
|
||||
result = snap_to_grid(Path(schematic_path), grid_size=grid_size, elements=elements)
|
||||
total = result["snapped"] + result["already_on_grid"]
|
||||
return {
|
||||
"success": True,
|
||||
**result,
|
||||
"message": (
|
||||
f"Snapped {result['snapped']} element(s) to {grid_size} mm grid "
|
||||
f"({result['already_on_grid']} of {total} were already on grid)"
|
||||
),
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error snapping to grid: {e}")
|
||||
import traceback
|
||||
|
||||
logger.error(traceback.format_exc())
|
||||
return {"success": False, "message": str(e)}
|
||||
|
||||
def _handle_import_svg_logo(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Import an SVG file as PCB graphic polygons on the silkscreen"""
|
||||
logger.info("Importing SVG logo into PCB")
|
||||
|
||||
Reference in New Issue
Block a user