diff --git a/rust/crates/tidy-tree/src/layout/tidy_layout.rs b/rust/crates/tidy-tree/src/layout/tidy_layout.rs index ef0eccf..52f25d6 100644 --- a/rust/crates/tidy-tree/src/layout/tidy_layout.rs +++ b/rust/crates/tidy-tree/src/layout/tidy_layout.rs @@ -9,6 +9,8 @@ pub struct TidyLayout { pub peer_margin: Coord, } +const TEST: usize = 123123231; + impl TidyLayout { pub fn new(parent_child_margin: Coord, peer_margin: Coord) -> Self { TidyLayout { @@ -20,7 +22,7 @@ impl TidyLayout { struct Contour { is_left: bool, - current: Option>, + pub current: Option>, modifier_sum: Coord, } @@ -33,11 +35,6 @@ impl Contour { } } - pub fn left(&self) -> Coord { - let node = self.node(); - self.modifier_sum + node.relative_x + node.tidy().modifier_to_subtree - } - fn node(&self) -> &Node { match self.current { Some(node) => { @@ -52,8 +49,15 @@ impl Contour { self.current.is_none() } + pub fn left(&self) -> Coord { + let node = self.node(); + assert_eq!(node.tidy().test, TEST); + self.modifier_sum + node.relative_x + node.tidy().modifier_to_subtree + } + pub fn right(&self) -> Coord { let node = self.node(); + assert_eq!(node.tidy().test, TEST); node.width + self.modifier_sum + node.relative_x + node.tidy().modifier_to_subtree } @@ -71,6 +75,7 @@ impl Contour { if let Some(mut current) = self.current { let node = unsafe { current.as_mut() }; self.modifier_sum += node.tidy.as_ref().unwrap().modifier_to_subtree; + assert_eq!(node.tidy().test, TEST); if self.is_left { if node.children.len() > 0 { self.current = Some((&**node.children.first().unwrap()).into()); @@ -86,6 +91,10 @@ impl Contour { self.current = node.tidy().thread_right; } } + if self.current.is_some() { + let node = self.node(); + assert_eq!(node.tidy().test, TEST); + } } } } @@ -166,24 +175,17 @@ impl TidyLayout { let mut right = Contour::new(true, &node.children[child_index]); // let mut i = 0; while !left.is_none() && !right.is_none() { - let left_bottom = left.bottom(); - // println!("{} {}", i, left_bottom); - // i += 1; - // if (left_bottom - 39.) < 1e-6 { - // println!("{}", i); - // } - - if left_bottom > y_list.bottom() { + if left.bottom() > y_list.bottom() { y_list = y_list.pop().unwrap(); } let dist = left.right() - right.left() + self.peer_margin; - if dist > 1e6 { - println!("{}", dist); - } if dist > 0. { - // left contour is too wide, so we move it - left.modifier_sum += dist; + // left and right are too close. move right part with distance of dist + let ptr: *const _ = &*node.children[child_index]; + if ptr != &*right.node() { + right.modifier_sum += dist; + } self.move_subtree(node, child_index, y_list.index, dist); } @@ -347,11 +349,12 @@ impl Layout for TidyLayout { thread_right: None, modifier_thread_left: 0., modifier_thread_right: 0., + test: TEST, })); }); self.set_y(root); self.first_walk(root); - self.second_walk(root, 0.); + self.second_walk(root, -root.relative_x); } fn partial_layout( @@ -362,3 +365,33 @@ impl Layout for TidyLayout { todo!() } } + +#[cfg(test)] +mod test { + use super::*; + use crate::node::Node; + #[test] + fn test_tidy_layout() { + let mut tidy = TidyLayout::new(1., 1.); + let mut root = Node::new(0, 1., 1.); + let first_child = Node::new_with_child( + 1, + 1., + 1., + Node::new_with_child(10, 1., 1., Node::new(100, 1., 1.)), + ); + root.append_child(first_child); + + let second = Node::new_with_child( + 2, + 1., + 1., + Node::new_with_child(11, 1., 1., Node::new(101, 1., 1.)), + ); + root.append_child(second); + + root.append_child(Node::new(3, 1., 2.)); + tidy.layout(&mut root); + println!("{}", root.str()); + } +} diff --git a/rust/crates/tidy-tree/src/node.rs b/rust/crates/tidy-tree/src/node.rs index 10627cb..814de04 100644 --- a/rust/crates/tidy-tree/src/node.rs +++ b/rust/crates/tidy-tree/src/node.rs @@ -21,6 +21,7 @@ pub struct TidyData { pub shift_acceleration: Coord, /// Cached change of x position pub shift_change: Coord, + pub test: usize, /// this.x = parent.x + modifier_to_subtree pub modifier_to_subtree: Coord, @@ -109,6 +110,12 @@ impl Node { ptr } + pub fn new_with_child(id: usize, width: Coord, height: Coord, child: Self) -> Self { + let mut node = Node::new(id, width, height); + node.append_child(child); + node + } + pub fn intersects(&self, other: &Self) -> bool { self.x - self.width / 2. < other.x + other.width / 2. && self.x + self.width / 2. > other.x - other.width / 2. @@ -181,4 +188,35 @@ impl Node { } } } + + pub fn str(&self) -> String { + let mut s = String::new(); + if self.tidy.is_some() { + s.push_str(&format!( + "x: {}, y: {}, width: {}, height: {}, rx: {}, mod: {}\n", + self.x, + self.y, + self.width, + self.height, + self.relative_x, + self.tidy().modifier_to_subtree + )); + } else { + s.push_str(&format!( + "x: {}, y: {}, width: {}, height: {}, rx: {}\n", + self.x, self.y, self.width, self.height, self.relative_x, + )); + } + for child in self.children.iter() { + for line in child.str().split("\n") { + if line.len() == 0 { + continue; + } + + s.push_str(&format!(" {}\n", line)); + } + } + + s + } } diff --git a/rust/crates/tidy-tree/tests/aesthetic_rules.rs b/rust/crates/tidy-tree/tests/aesthetic_rules.rs index d94df32..ca64e19 100644 --- a/rust/crates/tidy-tree/tests/aesthetic_rules.rs +++ b/rust/crates/tidy-tree/tests/aesthetic_rules.rs @@ -8,7 +8,7 @@ pub fn assert_no_overlap_nodes(root: &Node) { for other in nodes.iter() { let other = unsafe { other.as_ref() }; if node.intersects(other) { - let msg = format!("{:#?} and {:#?} overlap", node, other); + let msg = format!("{} and {} overlap", node.str(), other.str()); panic!("{}", msg); } } diff --git a/rust/crates/tidy-tree/tests/layout_test.rs b/rust/crates/tidy-tree/tests/layout_test.rs index 16fb10c..a99379e 100644 --- a/rust/crates/tidy-tree/tests/layout_test.rs +++ b/rust/crates/tidy-tree/tests/layout_test.rs @@ -5,18 +5,17 @@ use rand::prelude::*; use tidy_tree::{geometry::Coord, BasicLayout, Layout, Node, TidyLayout}; pub fn test_layout(layout: &mut dyn Layout) { - let mut rng = StdRng::seed_from_u64(101); - // for _ in 0..1 { - let mut tree = gen_tree(&mut rng, 20); - layout.layout(&mut tree); - aesthetic_rules::assert_no_overlap_nodes(&tree); - aesthetic_rules::assert_no_crossed_lines(&tree); - // aesthetic_rules::assert_symmetric(&tree, layout); - aesthetic_rules::check_nodes_order(&tree); - aesthetic_rules::check_y_position_in_same_level(&tree); - aesthetic_rules::assert_parent_centered(&tree); - // } - println!("{:#?}", tree); + let mut rng = StdRng::seed_from_u64(1001); + for _ in 0..1 { + let mut tree = gen_tree(&mut rng, 200); + layout.layout(&mut tree); + // aesthetic_rules::assert_symmetric(&tree, layout); + aesthetic_rules::assert_no_overlap_nodes(&tree); + aesthetic_rules::assert_no_crossed_lines(&tree); + aesthetic_rules::check_nodes_order(&tree); + aesthetic_rules::check_y_position_in_same_level(&tree); + aesthetic_rules::assert_parent_centered(&tree); + } } pub fn gen_tree(rng: &mut StdRng, num: usize) -> Node {