153 lines
5.4 KiB
Rust
153 lines
5.4 KiB
Rust
use oa_core::{projection::project_diagram, routing::*, *};
|
|
|
|
fn crosses(bounds: RoutingBounds, a: Position, b: Position) -> bool {
|
|
let left = bounds.position.x;
|
|
let top = bounds.position.y;
|
|
let right = left + bounds.size.width;
|
|
let bottom = top + bounds.size.height;
|
|
if a.x == b.x {
|
|
a.x > left && a.x < right && a.y.min(b.y) < bottom && a.y.max(b.y) > top
|
|
} else {
|
|
a.y > top && a.y < bottom && a.x.min(b.x) < right && a.x.max(b.x) > left
|
|
}
|
|
}
|
|
|
|
fn fixture(functional_first: bool) -> (Project, Id, Id, Id) {
|
|
let mut project = Project::demo();
|
|
let diagram = project
|
|
.diagrams
|
|
.values()
|
|
.find(|d| d.layer == Layer::Sa && d.projection == ProjectionKind::Allocation)
|
|
.unwrap()
|
|
.id;
|
|
// Freeze the observed default arrangement independently of random demo
|
|
// identities. The two parallel border connections are only 20 units apart.
|
|
for node in project
|
|
.diagrams
|
|
.get_mut(&diagram)
|
|
.unwrap()
|
|
.nodes
|
|
.values_mut()
|
|
{
|
|
let (x, y, width, height) = match project.elements[&node.element].alias.as_str() {
|
|
"vessel_communication_service" => (60., 60., 272., 220.),
|
|
"rescue_coordination_system" => (572., 60., 272., 220.),
|
|
"transmit_distress_report" => (84., 124., 224., 132.),
|
|
"classify_incident_and_alert_operator" => (596., 124., 224., 132.),
|
|
alias => panic!("Unexpected demo placement {alias}"),
|
|
};
|
|
node.position = Position { x, y };
|
|
node.size = Size { width, height };
|
|
}
|
|
let old_fe = project
|
|
.relations
|
|
.values()
|
|
.find(|r| r.alias == "validated_distress_report")
|
|
.unwrap()
|
|
.id;
|
|
let old_boundary = project
|
|
.relations
|
|
.values()
|
|
.find(|r| r.alias == "distress_reporting_connection")
|
|
.unwrap()
|
|
.id;
|
|
let fe = Id::from_u128(if functional_first { 1 } else { 2 });
|
|
let boundary = Id::from_u128(if functional_first { 2 } else { 1 });
|
|
let project = execute_batch(
|
|
&project,
|
|
&[
|
|
Command::Reidentify(old_fe, fe),
|
|
Command::Reidentify(old_boundary, boundary),
|
|
],
|
|
)
|
|
.unwrap();
|
|
(project, diagram, fe, boundary)
|
|
}
|
|
|
|
fn stroke_collisions(project: &Project, routed: &RoutedView) -> Vec<String> {
|
|
let mut collisions = Vec::new();
|
|
for edge in routed.edges.values().filter(|e| !e.label.text.is_empty()) {
|
|
for other in routed.edges.values().filter(|e| e.id != edge.id) {
|
|
for segment in other.points.windows(2) {
|
|
if crosses(edge.label.bounds, segment[0], segment[1]) {
|
|
collisions.push(format!(
|
|
"{} ({}) label {:?} crosses {} ({}) segment {:?}",
|
|
edge.label.text,
|
|
edge.id,
|
|
edge.label.bounds,
|
|
project.named(other.id),
|
|
other.id,
|
|
segment
|
|
));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
collisions
|
|
}
|
|
|
|
#[test]
|
|
fn demo_architecture_labels_do_not_cover_earlier_or_later_connection_strokes() {
|
|
for functional_first in [true, false] {
|
|
let (project, diagram, _, _) = fixture(functional_first);
|
|
let before = project.clone();
|
|
let d = &project.diagrams[&diagram];
|
|
let view = project_diagram(&project, d);
|
|
let routed = route_diagram(&project, d, &view);
|
|
let collisions = stroke_collisions(&project, &routed);
|
|
assert!(collisions.is_empty(), "{collisions:#?}");
|
|
assert_eq!(project, before);
|
|
assert_eq!(routed, route_diagram(&project, d, &view));
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn authored_overlap_is_exact_and_reset_only_repositions_automatic_text() {
|
|
let (mut project, diagram, fe, _) = fixture(true);
|
|
let view = project_diagram(&project, &project.diagrams[&diagram]);
|
|
let automatic = route_diagram(&project, &project.diagrams[&diagram], &view);
|
|
let authored = EdgeLabel {
|
|
fraction: 0.5,
|
|
offset: Position { x: 0., y: -18. },
|
|
};
|
|
project
|
|
.diagrams
|
|
.get_mut(&diagram)
|
|
.unwrap()
|
|
.routes
|
|
.push(EdgeRoute {
|
|
edge: fe,
|
|
waypoints: vec![],
|
|
label: Some(authored.clone()),
|
|
});
|
|
let authored_snapshot = project.clone();
|
|
let explicit = route_diagram(&project, &project.diagrams[&diagram], &view);
|
|
let label = &explicit.edges[&fe].label;
|
|
assert_eq!(label.fraction, authored.fraction);
|
|
assert_eq!(
|
|
label.center,
|
|
Position {
|
|
x: label.anchor.x + authored.offset.x,
|
|
y: label.anchor.y + authored.offset.y
|
|
}
|
|
);
|
|
assert!(
|
|
!stroke_collisions(&project, &explicit).is_empty(),
|
|
"The authored label deliberately retains the native overlap"
|
|
);
|
|
assert_eq!(project, authored_snapshot);
|
|
for (&id, edge) in &automatic.edges {
|
|
assert_eq!(edge.points, explicit.edges[&id].points);
|
|
assert_eq!(edge.pins, explicit.edges[&id].pins);
|
|
assert_eq!(edge.warnings, explicit.edges[&id].warnings);
|
|
}
|
|
project.diagrams.get_mut(&diagram).unwrap().routes[0].label = None;
|
|
let reset = route_edge_preview(&project, &project.diagrams[&diagram], &view, &explicit, fe);
|
|
assert_eq!(reset.edges[&fe], automatic.edges[&fe]);
|
|
for (&id, edge) in &explicit.edges {
|
|
if id != fe {
|
|
assert_eq!(reset.edges[&id], *edge);
|
|
}
|
|
}
|
|
}
|