Merge pull request #136 from mixelpixx/fix/auto-junction-sync-followups
Auto-sync schematic junctions on wire and symbol mutations
This commit is contained in:
@@ -15,7 +15,9 @@ import traceback
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
import sexpdata
|
||||
from annotations import AnnotationLoader
|
||||
from commands.wire_manager import WireManager
|
||||
from resources.resource_definitions import RESOURCE_DEFINITIONS, handle_resource_read
|
||||
|
||||
# Import tool schemas, resource definitions, and IPC API annotations
|
||||
@@ -389,7 +391,6 @@ class KiCADInterface:
|
||||
"get_schematic_component": self._handle_get_schematic_component,
|
||||
"add_schematic_wire": self._handle_add_schematic_wire,
|
||||
"add_schematic_net_label": self._handle_add_schematic_net_label,
|
||||
"add_schematic_junction": self._handle_add_schematic_junction,
|
||||
"connect_to_net": self._handle_connect_to_net,
|
||||
"connect_passthrough": self._handle_connect_passthrough,
|
||||
"get_schematic_pin_locations": self._handle_get_schematic_pin_locations,
|
||||
@@ -1629,39 +1630,6 @@ class KiCADInterface:
|
||||
"errorDetails": traceback.format_exc(),
|
||||
}
|
||||
|
||||
def _handle_add_schematic_junction(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Add a junction (connection dot) to a schematic using WireManager"""
|
||||
logger.info("Adding junction to schematic")
|
||||
try:
|
||||
from pathlib import Path
|
||||
|
||||
from commands.wire_manager import WireManager
|
||||
|
||||
schematic_path = params.get("schematicPath")
|
||||
position = params.get("position")
|
||||
|
||||
if not schematic_path:
|
||||
return {"success": False, "message": "Schematic path is required"}
|
||||
if not position:
|
||||
return {"success": False, "message": "Position is required"}
|
||||
|
||||
success = WireManager.add_junction(Path(schematic_path), position)
|
||||
|
||||
if success:
|
||||
return {"success": True, "message": "Junction added successfully"}
|
||||
else:
|
||||
return {"success": False, "message": "Failed to add junction"}
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding junction to schematic: {str(e)}")
|
||||
import traceback
|
||||
|
||||
logger.error(traceback.format_exc())
|
||||
return {
|
||||
"success": False,
|
||||
"message": str(e),
|
||||
"errorDetails": traceback.format_exc(),
|
||||
}
|
||||
|
||||
def _handle_list_schematic_libraries(self, params: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""List available symbol libraries"""
|
||||
logger.info("Listing schematic libraries")
|
||||
@@ -2660,7 +2628,6 @@ class KiCADInterface:
|
||||
"""Move a schematic component to a new position, dragging connected wires."""
|
||||
logger.info("Moving schematic component")
|
||||
try:
|
||||
import sexpdata as _sexpdata
|
||||
from commands.wire_dragger import WireDragger
|
||||
|
||||
schematic_path = params.get("schematicPath")
|
||||
@@ -2682,7 +2649,7 @@ class KiCADInterface:
|
||||
}
|
||||
|
||||
with open(schematic_path, "r", encoding="utf-8") as f:
|
||||
sch_data = _sexpdata.loads(f.read())
|
||||
sch_data = sexpdata.loads(f.read())
|
||||
|
||||
# Find symbol and record old position
|
||||
found = WireDragger.find_symbol(sch_data, reference)
|
||||
@@ -2721,8 +2688,10 @@ class KiCADInterface:
|
||||
# Update symbol position
|
||||
WireDragger.update_symbol_position(sch_data, reference, float(new_x), float(new_y))
|
||||
|
||||
WireManager.sync_junctions(sch_data)
|
||||
|
||||
with open(schematic_path, "w", encoding="utf-8") as f:
|
||||
f.write(_sexpdata.dumps(sch_data))
|
||||
f.write(sexpdata.dumps(sch_data))
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
@@ -2755,33 +2724,77 @@ class KiCADInterface:
|
||||
"message": "schematicPath and reference are required",
|
||||
}
|
||||
|
||||
schematic = SchematicManager.load_schematic(schematic_path)
|
||||
if not schematic:
|
||||
return {"success": False, "message": "Failed to load schematic"}
|
||||
sym_k = sexpdata.Symbol("symbol")
|
||||
prop_k = sexpdata.Symbol("property")
|
||||
at_k = sexpdata.Symbol("at")
|
||||
mirror_k = sexpdata.Symbol("mirror")
|
||||
|
||||
for symbol in schematic.symbol:
|
||||
if not hasattr(symbol.property, "Reference"):
|
||||
with open(schematic_path, "r", encoding="utf-8") as _f:
|
||||
sch_data = sexpdata.load(_f)
|
||||
|
||||
target = None
|
||||
for item in sch_data:
|
||||
if not (isinstance(item, list) and item and item[0] == sym_k):
|
||||
continue
|
||||
if symbol.property.Reference.value == reference:
|
||||
pos = list(symbol.at.value)
|
||||
while len(pos) < 3:
|
||||
pos.append(0)
|
||||
pos[2] = angle
|
||||
symbol.at.value = pos
|
||||
ref_val = None
|
||||
for sub in item[1:]:
|
||||
if (
|
||||
isinstance(sub, list)
|
||||
and len(sub) >= 3
|
||||
and sub[0] == prop_k
|
||||
and str(sub[1]).strip('"') == "Reference"
|
||||
):
|
||||
ref_val = str(sub[2]).strip('"')
|
||||
break
|
||||
if ref_val == reference:
|
||||
target = item
|
||||
break
|
||||
|
||||
if mirror:
|
||||
if hasattr(symbol, "mirror"):
|
||||
symbol.mirror.value = mirror
|
||||
else:
|
||||
logger.warning(
|
||||
f"Mirror '{mirror}' requested for {reference}, "
|
||||
f"but symbol has no mirror attribute; skipped"
|
||||
)
|
||||
if target is None:
|
||||
return {"success": False, "message": f"Component {reference} not found"}
|
||||
|
||||
SchematicManager.save_schematic(schematic, schematic_path)
|
||||
return {"success": True, "reference": reference, "angle": angle}
|
||||
# Update (at x y rot)
|
||||
at_node = None
|
||||
mirror_idx = None
|
||||
for idx, sub in enumerate(target[1:], start=1):
|
||||
if not isinstance(sub, list) or not sub:
|
||||
continue
|
||||
if sub[0] == at_k:
|
||||
at_node = sub
|
||||
elif sub[0] == mirror_k:
|
||||
mirror_idx = idx
|
||||
|
||||
return {"success": False, "message": f"Component {reference} not found"}
|
||||
if at_node is None:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Component {reference} has no (at ...) node",
|
||||
}
|
||||
while len(at_node) < 3:
|
||||
at_node.append(0)
|
||||
if len(at_node) < 4:
|
||||
at_node.append(angle)
|
||||
else:
|
||||
at_node[3] = angle
|
||||
|
||||
if mirror:
|
||||
mirror_node = [mirror_k, sexpdata.Symbol(str(mirror))]
|
||||
if mirror_idx is not None:
|
||||
target[mirror_idx] = mirror_node
|
||||
else:
|
||||
# Insert after (at ...) for stability
|
||||
insert_at = len(target)
|
||||
for idx, sub in enumerate(target[1:], start=1):
|
||||
if isinstance(sub, list) and sub and sub[0] == at_k:
|
||||
insert_at = idx + 1
|
||||
break
|
||||
target.insert(insert_at, mirror_node)
|
||||
|
||||
WireManager.sync_junctions(sch_data)
|
||||
|
||||
with open(schematic_path, "w", encoding="utf-8") as _f:
|
||||
_f.write(sexpdata.dumps(sch_data))
|
||||
|
||||
return {"success": True, "reference": reference, "angle": angle}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error rotating schematic component: {e}")
|
||||
|
||||
Reference in New Issue
Block a user