diff --git a/python/commands/wire_manager.py b/python/commands/wire_manager.py index 87d778d..265e38e 100644 --- a/python/commands/wire_manager.py +++ b/python/commands/wire_manager.py @@ -406,6 +406,66 @@ class WireManager: logger.error(traceback.format_exc()) return False + @staticmethod + def delete_label(schematic_path: Path, net_name: str, + position: Optional[List[float]] = None, + tolerance: float = 0.5) -> bool: + """ + Delete a net label from the schematic by name (and optionally position). + + Args: + schematic_path: Path to .kicad_sch file + net_name: Net label text to match + position: Optional [x, y] to disambiguate when multiple labels share a name + tolerance: Maximum coordinate difference to consider a match (mm) + + Returns: + True if a label was found and removed, False otherwise + """ + try: + with open(schematic_path, 'r', encoding='utf-8') as f: + sch_content = f.read() + + sch_data = sexpdata.loads(sch_content) + + for i, item in enumerate(sch_data): + if not (isinstance(item, list) and len(item) > 0 + and item[0] == Symbol('label')): + continue + + # Second element is the label text + if len(item) < 2 or item[1] != net_name: + continue + + if position is not None: + # Find (at x y ...) sub-expression and check coordinates + at_entry = next( + (p for p in item[1:] if isinstance(p, list) + and len(p) >= 3 and p[0] == Symbol('at')), + None, + ) + if at_entry is None: + continue + lx, ly = float(at_entry[1]), float(at_entry[2]) + if not (abs(lx - position[0]) < tolerance + and abs(ly - position[1]) < tolerance): + continue + + del sch_data[i] + with open(schematic_path, 'w', encoding='utf-8') as f: + f.write(sexpdata.dumps(sch_data)) + logger.info(f"Deleted label '{net_name}'") + return True + + logger.warning(f"No matching label found for '{net_name}'") + return False + + except Exception as e: + logger.error(f"Error deleting label: {e}") + import traceback + logger.error(traceback.format_exc()) + return False + @staticmethod def create_orthogonal_path(start: List[float], end: List[float], prefer_horizontal_first: bool = True) -> List[List[float]]: diff --git a/python/kicad_interface.py b/python/kicad_interface.py index b8f8935..1b1db68 100644 --- a/python/kicad_interface.py +++ b/python/kicad_interface.py @@ -1926,36 +1926,15 @@ class KiCADInterface: if not schematic_path or not net_name: return {"success": False, "message": "schematicPath and netName are required"} - schematic = SchematicManager.load_schematic(schematic_path) - if not schematic: - return {"success": False, "message": "Failed to load schematic"} + from pathlib import Path + from commands.wire_manager import WireManager - if not hasattr(schematic, "label"): - return {"success": False, "message": "Schematic has no labels"} + pos_list = None + if position: + pos_list = [position.get("x", 0), position.get("y", 0)] - tolerance = 0.5 - label_to_remove = None - - for label in schematic.label: - if not hasattr(label, "value") or label.value != net_name: - continue - - if position: - # Match by position too - pos = label.at.value if hasattr(label, "at") and hasattr(label.at, "value") else None - if pos: - px, py = position.get("x", 0), position.get("y", 0) - if abs(float(pos[0]) - px) < tolerance and abs(float(pos[1]) - py) < tolerance: - label_to_remove = label - break - else: - # First match - label_to_remove = label - break - - if label_to_remove: - schematic.label._elements.remove(label_to_remove) - SchematicManager.save_schematic(schematic, schematic_path) + deleted = WireManager.delete_label(Path(schematic_path), net_name, pos_list) + if deleted: return {"success": True} else: return {"success": False, "message": f"Label '{net_name}' not found"}