diff --git a/src/space_colonization/mod.rs b/src/space_colonization/mod.rs index 80c84a0..1447000 100644 --- a/src/space_colonization/mod.rs +++ b/src/space_colonization/mod.rs @@ -27,6 +27,15 @@ impl Attractor { } } +/// A Node of the graph that is connected to one or more other nodes +/// +/// Use cases : +/// - Rendering +/// - Must be easy and fast to find connections +/// - Must know the number of descendent generations to calculate vein thickness +/// - Growing +/// - Must be easy and fast to find nodes in a cell +/// - Probably worth marking nodes as dead when no attractor is in range #[derive(Debug, PartialEq, Eq)] pub struct Node { pub position: Point, diff --git a/src/space_colonization/point.rs b/src/space_colonization/point.rs index fee5062..94e39ea 100644 --- a/src/space_colonization/point.rs +++ b/src/space_colonization/point.rs @@ -1,6 +1,4 @@ -use log::info; - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, PartialOrd)] pub struct Point { pub x: i32, pub y: i32, @@ -46,6 +44,25 @@ impl Point { } } +impl Ord for Point { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + if self.x > other.x { + return std::cmp::Ordering::Greater; + } + if self.x < other.x { + return std::cmp::Ordering::Less; + } + if self.y > other.y { + return std::cmp::Ordering::Greater; + } + if self.y < other.y { + return std::cmp::Ordering::Less; + } + + std::cmp::Ordering::Equal + } +} + #[cfg(test)] mod tests { use super::Point; @@ -164,28 +181,35 @@ mod tests { } #[test] - fn scale_does_nothing_when_right_length() { + fn movement_does_nothing_when_right_length() { let root = Point::new((0,0)); let node = Point::new((0,1)); assert_eq!(root.movement(node.clone(), 1), node); } #[test] - fn scale_adjusts_to_asked_length() { + fn movement_does_not_overlap() { + let root = Point::new((0,1)); + let node = Point::new((0,0)); + assert_eq!(root.movement(node.clone(), 2), node); + } + + #[test] + fn movement_adjusts_to_asked_length() { let root = Point::new((0,0)); let node = Point::new((0,1)); assert_eq!(root.movement(node, 10), Point::new((0,10))); } #[test] - fn scale_works_away_from_origin() { + fn movement_works_away_from_origin() { let root = Point::new((10,10)); let node = Point::new((10,11)); assert_eq!(root.movement(node, 10), Point::new((10,20))); } #[test] - fn scale_works_in_two_dimension() { + fn movement_works_in_two_dimension() { let root = Point::new((10,10)); let node = Point::new((40,50)); assert_eq!(root.movement(node, 50), Point::new((40,50))); @@ -196,7 +220,7 @@ mod tests { } #[test] - fn scale_works_in_all_directions() { + fn movement_works_in_all_directions() { let root = Point::new((40,50)); let node = Point::new((10,10)); assert_eq!(root.movement(node, 5), Point::new((37,46))); diff --git a/src/space_colonization/space_colonization.rs b/src/space_colonization/space_colonization.rs index 3b7e442..bb0babc 100644 --- a/src/space_colonization/space_colonization.rs +++ b/src/space_colonization/space_colonization.rs @@ -102,7 +102,7 @@ impl SpaceColonization { F: Copy + Fn(&Node, &Node), { info!("Rendering {} nodes", self.nodes.len()); - for n in self.nodes_tree.iter() { + for n in self.nodes.iter() { n.render(render_id, render_fn); } } @@ -221,8 +221,25 @@ impl SpaceColonization { #[cfg(test)] mod test { + use std::cell::RefCell; + use super::*; + fn assert_nodes(sc: &SpaceColonization, expected_nodes: Vec<(Point, Point)>) { + let rendered_nodes = RefCell::new(Vec::new()); + sc.render_nodes(0.0, |n1, n2| { + rendered_nodes.borrow_mut().push((n1.position, n2.position)); + }); + + rendered_nodes.borrow_mut().sort_by(|line1, line2| { + if line1.0 != line2.0 { + return line1.0.cmp(&line2.0); + } + + return line1.1.cmp(&line2.1); + }) + } + #[test] fn grow_should_reach_single_attractor_and_die() { let mut nodes = Vec::new(); @@ -232,62 +249,33 @@ mod test { let sc = SpaceColonization::new_for_tests(100, 100, nodes, attractors); + assert_nodes(&sc, Vec::from([(Point::new((0,0)), Point::new((10,0)))])); assert_eq!(sc.attractors.len(), 1); assert!(sc .attractors .iter() .find(|a| a.dead == true) .is_none()); - assert_eq!(sc.nodes_tree[0].children.len(), 0); sc.grow(); assert_eq!(sc.new_nodes.len(), 0); - assert_eq!(sc.nodes_tree.[0].children.len(), 1); assert!(sc .attractors .iter() .find(|a| a.dead == true) .is_none()); - assert_eq!( - sc.nodes_tree.[0].children.[0].position, - Point::new((3, 0)) - ); - assert_eq!( - sc.nodes_tree[0].children.len(), - 1, - ); - assert_eq!( - sc.nodes_tree.len(), - 1, - ); - println!("root node direct children iteration 1 {:?}", sc.nodes_tree.[0].children); + // TODO assert point 3,0 sc.grow(); - assert_eq!( - sc.nodes_tree.len(), - 1, - ); assert_eq!(sc .attractors .iter() .filter(|a| a.dead == true) .collect::>().len(), 1); - println!("root node direct children iteration 2 {:?}", sc.nodes_tree.[0].children); - assert_eq!( - sc.nodes_tree[0].children.len(), - 1, - ); - assert_eq!( - sc.nodes_tree[0].children[0].position, - Point::new((3, 0)) - ); - assert_eq!( - sc.nodes_tree[0].children[0].children[0].position, - Point::new((6, 0)) - ); + // TODO assert nodes 3,0 and 6,0 assert_eq!(sc.nodes.len(), 3); } }