use crate::model::{LayoutNode, LayoutPoint};
pub(crate) fn missing_rect_section_points(
start: &LayoutNode,
end: &LayoutNode,
) -> Vec<LayoutPoint> {
fn intersect(node: &LayoutNode, point: &LayoutPoint) -> LayoutPoint {
let dx = point.x - node.x;
let dy = point.y - node.y;
let w = node.width / 2.0;
let h = node.height / 2.0;
let (sx, sy) = if dy.abs() * w > dx.abs() * h {
let h = if dy < 0.0 { -h } else { h };
(if dy == 0.0 { 0.0 } else { h * dx / dy }, h)
} else {
let w = if dx < 0.0 { -w } else { w };
(w, if dx == 0.0 { 0.0 } else { w * dy / dx })
};
LayoutPoint {
x: node.x + sx,
y: node.y + sy,
}
}
let centers = [
LayoutPoint {
x: start.x,
y: start.y,
},
LayoutPoint { x: end.x, y: end.y },
];
let mut points = centers.clone();
if (end.x - start.x).abs() >= start.width / 2.0 || (end.y - start.y).abs() >= start.height / 2.0
{
points[0] = intersect(start, ¢ers[1]);
}
points[1] = intersect(end, &points[0]);
if (points[1].x - points[0].x).hypot(points[1].y - points[0].y) < 2.0
|| points.iter().any(|p| !p.x.is_finite() || !p.y.is_finite())
{
points = centers;
}
if (points[1].x - points[0].x).abs() <= 1e-6 && (points[1].y - points[0].y).abs() <= 1e-6 {
vec![points[0].clone()]
} else {
points.to_vec()
}
}
#[cfg(test)]
mod tests {
use super::missing_rect_section_points;
use crate::model::LayoutNode;
#[test]
fn overlapping_nodes_keep_a_drawable_end_intersection() {
let start = LayoutNode {
id: "A".into(),
x: 10.0,
y: 10.0,
width: 40.0,
height: 20.0,
is_cluster: false,
label_width: None,
label_height: None,
};
let end = LayoutNode {
id: "B".into(),
x: 10.0,
y: 10.0,
width: 40.0,
height: 20.0,
is_cluster: false,
label_width: None,
label_height: None,
};
let points = missing_rect_section_points(&start, &end);
assert_eq!(points.len(), 2);
assert!((points[0].x - 10.0).abs() < f64::EPSILON);
assert!((points[0].y - 10.0).abs() < f64::EPSILON);
assert!((points[1].x - 30.0).abs() < f64::EPSILON);
assert!((points[1].y - 10.0).abs() < f64::EPSILON);
let touching = LayoutNode { x: 50.0, ..end };
let points = missing_rect_section_points(&start, &touching);
assert_eq!(points.len(), 2);
assert_eq!(points[0].x, 10.0);
assert_eq!(points[1].x, 50.0);
let tiny = LayoutNode {
width: 1.0,
height: 1.0,
..start
};
let points = missing_rect_section_points(&tiny, &tiny);
assert_eq!(points.len(), 1);
assert_eq!((points[0].x, points[0].y), (10.0, 10.0));
}
}