Persist diagram routing with atomic edits and grouped movement
This commit is contained in:
@@ -180,6 +180,59 @@ pub fn descendant_nodes(p: &Project, diagram: Id, node: Id) -> Vec<Id> {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
/// Actual endpoint-owner placements before folding promotes a hidden endpoint
|
||||
/// to an ancestor. Ports belong to their placed function/participant; they do not
|
||||
/// acquire independent placement identities. Missing placements are not inferred.
|
||||
pub fn edge_endpoint_placements(p: &Project, d: &Diagram, edge: Id) -> Option<(Id, Id)> {
|
||||
let (source, target) = if let Some(r) = p.relations.get(&edge) {
|
||||
(r.source(), r.target())
|
||||
} else {
|
||||
let trace = p.traces.get(&edge)?;
|
||||
(trace.oa, trace.sa)
|
||||
};
|
||||
let placement = |id| {
|
||||
let element = p.elements.get(&id)?;
|
||||
let owner = if element.kind() == Kind::Port {
|
||||
element.parent?
|
||||
} else {
|
||||
id
|
||||
};
|
||||
d.nodes.values().find(|n| n.element == owner).map(|n| n.id)
|
||||
};
|
||||
Some((placement(source)?, placement(target)?))
|
||||
}
|
||||
|
||||
/// Route updates for a simultaneous placement movement. `deltas` maps placement
|
||||
/// identities to diagram-space displacement. Only routes with two actual owners
|
||||
/// moving by the same nonzero delta translate; one-ended moves keep world pins.
|
||||
/// Returns changed records only, for the caller to apply with its node edits in
|
||||
/// one transaction. This pure helper also drives reflow and drag previews.
|
||||
pub fn translated_routes(
|
||||
p: &Project,
|
||||
d: &Diagram,
|
||||
deltas: &BTreeMap<Id, Position>,
|
||||
) -> Vec<EdgeRoute> {
|
||||
d.routes
|
||||
.iter()
|
||||
.filter_map(|route| {
|
||||
let (source, target) = edge_endpoint_placements(p, d, route.edge)?;
|
||||
let source_delta = deltas.get(&source)?;
|
||||
let target_delta = deltas.get(&target)?;
|
||||
if source_delta != target_delta
|
||||
|| (source_delta.x == 0. && source_delta.y == 0.)
|
||||
|| route.waypoints.is_empty()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let mut translated = route.clone();
|
||||
for point in &mut translated.waypoints {
|
||||
point.x += source_delta.x;
|
||||
point.y += source_delta.y;
|
||||
}
|
||||
Some(translated)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
/// One projection drives drawing, hit testing, Fit, SVG, and grouped movement.
|
||||
pub fn project_view(p: &Project, diagram: Id) -> ProjectedView {
|
||||
let Some(d) = p.diagrams.get(&diagram) else {
|
||||
|
||||
Reference in New Issue
Block a user