Update wiring diagram maker: formboard router + frontend
Backend formboard router and frontend (canvas, formboard, connector library, app/api, index/css) updates. Ignore *.log.
This commit is contained in:
@@ -54,41 +54,87 @@ def get_layout(diagram_id: int, db: Session = Depends(get_db)):
|
||||
|
||||
@router.post("/{diagram_id}/sync")
|
||||
def sync_from_diagram(diagram_id: int, db: Session = Depends(get_db)):
|
||||
"""Import all devices from the main diagram as connector nodes.
|
||||
Existing nodes (matched by device_id) are label-synced but not moved."""
|
||||
"""Sync devices as connector nodes and build segments from wire connections.
|
||||
|
||||
Layout strategy:
|
||||
- Connectors alternate above/below a central trunk line (y=100 / y=300)
|
||||
- Segments are auto-created for each unique device-pair connected by wires,
|
||||
with wire_ids populated so thickness reflects the bundle size.
|
||||
Existing nodes are label-synced but not moved; existing segments are not duplicated.
|
||||
"""
|
||||
diagram = db.query(models.Diagram).filter_by(id=diagram_id).first()
|
||||
if not diagram:
|
||||
raise HTTPException(404, "Diagram not found")
|
||||
|
||||
layout = _get_or_create(diagram_id, db)
|
||||
existing_dev_ids = {n.device_id for n in layout.nodes if n.device_id is not None}
|
||||
dev_to_node: dict = {n.device_id: n for n in layout.nodes if n.device_id is not None}
|
||||
|
||||
added = 0
|
||||
x = 80
|
||||
for dev in diagram.devices:
|
||||
new_x = 80 + len([n for n in layout.nodes if n.device_id is not None]) * 200
|
||||
|
||||
for i, dev in enumerate(diagram.devices):
|
||||
label = dev.reference or dev.label or f"Dev {dev.id}"
|
||||
if dev.id in existing_dev_ids:
|
||||
# Keep label in sync if the node label is still the default
|
||||
node = next((n for n in layout.nodes if n.device_id == dev.id), None)
|
||||
if node:
|
||||
new_label = dev.reference or dev.label or f"Dev {dev.id}"
|
||||
if not node.label or node.label == f"Dev {dev.id}":
|
||||
node.label = new_label
|
||||
node = dev_to_node[dev.id]
|
||||
if not node.label or node.label == f"Dev {dev.id}":
|
||||
node.label = label
|
||||
else:
|
||||
# Alternate connectors above (y=80) and below (y=320) the trunk
|
||||
row_y = 80 if added % 2 == 0 else 320
|
||||
node = models.FormboardNode(
|
||||
layout_id=layout.id,
|
||||
node_type="connector",
|
||||
device_id=dev.id,
|
||||
x=new_x, y=row_y,
|
||||
label=label,
|
||||
)
|
||||
db.add(node)
|
||||
db.flush() # get node.id
|
||||
dev_to_node[dev.id] = node
|
||||
new_x += 200
|
||||
added += 1
|
||||
|
||||
# Build segments from wire connections
|
||||
# Group wires by (min_dev_id, max_dev_id) pair to avoid direction duplicates
|
||||
from collections import defaultdict
|
||||
pair_wires: dict = defaultdict(list)
|
||||
for wire in diagram.wires:
|
||||
a, b = wire.from_device_id, wire.to_device_id
|
||||
if a and b and a != b:
|
||||
pair_wires[(min(a, b), max(a, b))].append(wire.id)
|
||||
|
||||
# Find existing segments by node-pair to avoid duplicates
|
||||
existing_seg_pairs = set()
|
||||
for seg in layout.segments:
|
||||
existing_seg_pairs.add((min(seg.from_node_id, seg.to_node_id),
|
||||
max(seg.from_node_id, seg.to_node_id)))
|
||||
|
||||
segs_added = 0
|
||||
for (dev_a, dev_b), wire_ids in pair_wires.items():
|
||||
node_a = dev_to_node.get(dev_a)
|
||||
node_b = dev_to_node.get(dev_b)
|
||||
if not node_a or not node_b:
|
||||
continue
|
||||
node = models.FormboardNode(
|
||||
pair = (min(node_a.id, node_b.id), max(node_a.id, node_b.id))
|
||||
if pair in existing_seg_pairs:
|
||||
continue
|
||||
seg = models.FormboardSegment(
|
||||
layout_id=layout.id,
|
||||
node_type="connector",
|
||||
device_id=dev.id,
|
||||
x=x, y=180,
|
||||
label=dev.reference or dev.label or f"Dev {dev.id}",
|
||||
from_node_id=node_a.id,
|
||||
to_node_id=node_b.id,
|
||||
wire_ids=wire_ids,
|
||||
fitting_type="open",
|
||||
)
|
||||
db.add(node)
|
||||
x += 200
|
||||
added += 1
|
||||
db.add(seg)
|
||||
existing_seg_pairs.add(pair)
|
||||
segs_added += 1
|
||||
|
||||
db.commit()
|
||||
db.refresh(layout)
|
||||
return {
|
||||
"added": added,
|
||||
"segs_added": segs_added,
|
||||
"nodes": [_nd(n) for n in layout.nodes],
|
||||
"segments": [_sd(s) for s in layout.segments],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user