pub mod util; pub mod shadows; use macroquad::prelude::draw_texture; use macroquad::prelude::DMat3; use smallvec::SmallVec; use smallvec::smallvec; use std::collections::HashSet; use macroquad::prelude::set_camera; use macroquad::prelude::DVec2; use macroquad::prelude::Camera2D; use core::mem::swap; use std::collections::HashMap; use core::fmt; use core::cell::Cell; use std::collections::hash_map::Entry; use core::f64::consts::PI; use macroquad::prelude::mouse_position; use macroquad::prelude::is_mouse_button_pressed; use macroquad::prelude::Vec2; use core::ops::DerefMut; use core::ops::Deref; use core::hash::Hasher; use core::hash::Hash; use macroquad::prelude::screen_height; use macroquad::prelude::next_frame; use macroquad::prelude::screen_width; use macroquad::prelude::clear_background; use macroquad::prelude::Color; use macroquad::input::MouseButton; use std::sync::Arc; const FG: Color = Color::new(0.7686, 0.7216, 0.4078, 1.0); const SPEED: f64 = 0.1; const BOING_RADIUS: f64 = 30.0; const LIGHT_RADIUS: f32 = 128.; const WALL_THICKNESS: f32 = 5.; #[macroquad::main("BasicShapes")] async fn main() { let mut dd = DelaunayDemo::default(); let mut camera = dd.get_camera(); set_camera(&camera); let mut iter = 0; for _ in 0..100 { dd.add_random_point().unwrap(); } let gradient = shadows::get_gradient(LIGHT_RADIUS); loop { if iter == 100 { iter = 0; dd.resize((screen_width()/screen_height()) as f64); camera = dd.get_camera(); set_camera(&mut camera); } let mouse_position: Vec2 = camera.screen_to_world(mouse_position().into()); if is_mouse_button_pressed(MouseButton::Left) { dd.click(mouse_position); } if is_mouse_button_pressed(MouseButton::Right) { println!("{}", mouse_position); for triangle in &dd.triangles { if triangle.invalidated_by_point(mouse_position.as_f64()) { println!( "{:?} has center {} with r={}", triangle, triangle.circumcenter().0, triangle.circumcenter().1, ); } } } clear_background(shadows::BLACK); draw_texture( gradient, mouse_position.x - LIGHT_RADIUS, mouse_position.y - LIGHT_RADIUS, FG ); for (w1, w2) in dd.get_walls() { let w1 = w1.as_f32(); let w2 = w2.as_f32(); if shadows::wall_needs_to_be_drawn(w1, w2, mouse_position, LIGHT_RADIUS) { let perpendicular = (w1 - w2).perp(); let shift = perpendicular / perpendicular.length() * WALL_THICKNESS; let points = [ w1 + shift, w1 - shift, w2 + shift, w2 - shift, ]; shadows::draw_wall(points[0], points[1], mouse_position, LIGHT_RADIUS); shadows::draw_wall(points[1], points[2], mouse_position, LIGHT_RADIUS); shadows::draw_wall(points[2], points[3], mouse_position, LIGHT_RADIUS); shadows::draw_wall(points[3], points[0], mouse_position, LIGHT_RADIUS); } } dd.update(); iter += 1; next_frame().await; } } pub struct DelaunayDemo { pub nodes: Vec, pub triangles: Vec, pub spanning_tree: HashSet, spanning_tree_conn: HashMap>, // usize is casted from a noderef adjacency: HashMap, poisoned: bool, random_state: u128, width: f64, height: f64, } #[derive(Debug)] enum NeighborOne { Occupant(Triangle), Border, } #[derive(Debug)] enum NeighborTwo { Friend(Triangle), Hole, } use NeighborOne::*; use NeighborTwo::*; impl From for NeighborOne { fn from(triangle: Triangle) -> NeighborOne { Occupant(triangle) } } impl From<&Triangle> for NeighborOne { fn from(triangle: &Triangle) -> NeighborOne { triangle.clone().into() } } impl From for NeighborTwo { fn from(triangle: Triangle) -> NeighborTwo { Friend(triangle) } } impl From<&Triangle> for NeighborTwo { fn from(triangle: &Triangle) -> NeighborTwo { triangle.clone().into() } } impl NeighborTwo { fn unwrap_mut(&mut self) -> &mut Triangle { if let Friend(triangle) = self { triangle } else { panic!("Tried to unwrap a neighbor that wasn't a friend"); } } } impl Default for DelaunayDemo { fn default() -> Self { const HEIGHT: f64 = 900.0; const WIDTH: f64 = 1200.0; let nodes: Vec = vec![ Arc::new(Cell::new((-5.0 - BOING_RADIUS, 0.0 - BOING_RADIUS).into())), Arc::new(Cell::new((0.0 - BOING_RADIUS, HEIGHT + BOING_RADIUS).into())), Arc::new(Cell::new((WIDTH + BOING_RADIUS, 0.0 - BOING_RADIUS).into())), Arc::new(Cell::new((WIDTH + BOING_RADIUS, HEIGHT + BOING_RADIUS).into())), ]; let edges = ( Edge(nodes[2].clone(), nodes[0].clone()), Edge(nodes[0].clone(), nodes[1].clone()), Edge(nodes[1].clone(), nodes[2].clone()), Edge(nodes[2].clone(), nodes[3].clone()), Edge(nodes[3].clone(), nodes[1].clone()), ); let triangles = vec![ Triangle::new( [edges.0.clone(), edges.1.clone(), edges.2.clone()], ), Triangle::new( [edges.2.clone(), edges.3.clone(), edges.4.clone()], ), ]; let adjacency = [ (edges.0, (Border, (&triangles[0]).into())), (edges.1, (Border, (&triangles[0]).into())), (edges.2, ((&triangles[0]).into(), (&triangles[1]).into())), (edges.3, (Border, (&triangles[1]).into())), (edges.4, (Border, (&triangles[1]).into())), ].into(); let mut random = 0xACAB_1312; util::pcg64_iterstate(&mut random); let dd = DelaunayDemo { nodes, adjacency, triangles, height: HEIGHT, width: WIDTH, random_state: random, poisoned: false, spanning_tree: HashSet::with_capacity(100), spanning_tree_conn: HashMap::with_capacity(100), }; /*let n_v_nodes = ((height / 50.0) - 1.0).round(); let v_inc = height / n_v_nodes; for i in 0..(n_v_nodes as usize) { println!("A"); let random = util::pcg64(&mut dd.random_state); let offset = (random as f64) / (u64::MAX as f64) * 10.0; dd.add_point((offset, (i + 1) as f64 * v_inc).into()).unwrap(); println!("B"); dd.add_point((width - offset, (i + 1) as f64 * v_inc).into()).unwrap(); } let n_h_nodes = ((width / 50.0) - 1.0).round(); let h_inc = width / n_h_nodes; for i in 0..(n_h_nodes as usize) { println!("C"); let random = util::pcg64(&mut dd.random_state); let offset = (random as f64) / (u64::MAX as f64) * 10.0; dd.add_point(((i + 1) as f64 * h_inc, offset).into()).unwrap(); println!("D"); dd.add_point(((i + 1) as f64 * h_inc, height - offset).into()).unwrap(); }*/ dd } } #[derive(Copy, Clone, Debug)] pub struct Node(DVec2, DVec2); impl Deref for Node { type Target = DVec2; fn deref(&self) -> &DVec2 { &self.0 } } impl DerefMut for Node { fn deref_mut(&mut self) -> &mut DVec2 { &mut self.0 } } impl From<(f64, f64)> for Node { fn from((x, y): (f64, f64)) -> Node { Node(DVec2::new(x, y), DVec2::ZERO) } } type NodeRef = Arc>; #[derive(Clone)] pub struct Edge(NodeRef, NodeRef); impl Edge { fn node_thats_not(&self, node: &NodeRef) -> Result<&NodeRef, String> { [&self.0, &self.1].into_iter() .filter(|n| !Arc::ptr_eq(n, node)) .next() .ok_or_else(|| format!("Edge {:?} connects two identical nodes", self)) } } impl PartialEq for Edge { fn eq(&self, other: &Edge) -> bool { let mut our_ptrs = [ Arc::as_ptr(&self.0), Arc::as_ptr(&self.1), ]; let mut other_ptrs = [ Arc::as_ptr(&other.0), Arc::as_ptr(&other.1), ]; our_ptrs.sort_unstable(); other_ptrs.sort_unstable(); our_ptrs[0] == other_ptrs[0] && our_ptrs[1] == other_ptrs[1] } } impl Eq for Edge {} impl Hash for Edge { fn hash(&self, state: &mut H) { let mut ptrs = [ Arc::as_ptr(&self.0), Arc::as_ptr(&self.1), ]; ptrs.sort_unstable(); ptrs.hash(state); } } impl fmt::Debug for Edge { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Edge({},{} -> {},{})", self.0.get().x, self.0.get().y, self.1.get().x, self.1.get().y, ) } } #[derive(Clone)] pub struct Triangle { nodes: [NodeRef; 3], edges: [Edge; 3], } impl Triangle { pub fn new(edges: [Edge; 3]) -> Triangle { let nodes = [ edges[0].0.clone(), edges[0].1.clone(), if Arc::ptr_eq(&edges[1].0, &edges[0].0) || Arc::ptr_eq(&edges[1].0, &edges[0].1) { edges[1].1.clone() } else { edges[1].0.clone() } ]; Triangle { nodes, edges, } } pub fn new_from_points(nodes: [NodeRef; 3]) -> Triangle { let edges = [ Edge(nodes[0].clone(), nodes[1].clone()), Edge(nodes[1].clone(), nodes[2].clone()), Edge(nodes[2].clone(), nodes[0].clone()), ]; Triangle { nodes, edges, } } pub fn circumcenter(&self) -> (DVec2, f64) { Self::calc_circumcenter(*self.nodes[0].get(), *self.nodes[1].get(), *self.nodes[2].get()) } fn calc_circumcenter(a: DVec2, b: DVec2, c: DVec2) -> (DVec2, f64) { let mag_a2 = a.powf(2.).dot(DVec2::ONE); let mag_b2 = b.powf(2.).dot(DVec2::ONE); let mag_c2 = c.powf(2.).dot(DVec2::ONE); let s = DVec2::new( DMat3::from_cols_array(&[ mag_a2, a.y, 1., mag_b2, b.y, 1., mag_c2, c.y, 1., ]).determinant() * 0.5, DMat3::from_cols_array(&[ a.x, mag_a2, 1., b.x, mag_b2, 1., c.x, mag_c2, 1., ]).determinant() * 0.5, ); let little_a = DMat3::from_cols_array(&[ a.x, a.y, 1., b.x, b.y, 1., c.x, c.y, 1., ]).determinant(); let circumcenter = s / little_a; let radius = circumcenter.distance(a); (circumcenter, radius) } pub fn invalidated_by_point(&self, point: DVec2) -> bool { let (c, r) = self.circumcenter(); c.distance(point) < r } pub fn common_edge(&self, other: &Triangle) -> Result<&Edge, String> { let common_edge = self.edges.iter() .filter(|e| other.edges.contains(e)) .collect::>(); if common_edge.len() > 1 { Err(format!( "Tried to call common_edge on two triangles which share more \ than one common edge?: {:?} and {:?}.", self, other )) } else if let Some(common_edge) = common_edge.first() { Ok(common_edge) } else { Err(format!( "Tried to call common_edge on two triangles which don't \ share a common edges: {:?} and {:?}.", self, other )) } } pub fn point_not_on(&self, edge: &Edge) -> Result<&NodeRef, String> { self.nodes.iter() .filter(|n| !Arc::ptr_eq(n, &edge.0) && !Arc::ptr_eq(n, &edge.1) ) .next() .ok_or_else(||format!( ".point_not_on called on {:?} with edge {:?}, but no points were found \ not on this edge", self, edge )) } pub fn invalidated_by_neighbor(&self, other: &Triangle) -> Result { let common_edge = self.common_edge(other)?; let self_point = self.point_not_on(common_edge)?; let othr_point = other.point_not_on(common_edge)?; let common_distance = common_edge.0.get().distance(*common_edge.1.get()); let self_sidea = common_edge.0.get().distance(*self_point.get()); let self_sideb = common_edge.1.get().distance(*self_point.get()); let othr_sidea = common_edge.0.get().distance(*othr_point.get()); let othr_sideb = common_edge.1.get().distance(*othr_point.get()); let self_angle = f64::acos( ( self_sidea.powf(2.0) + self_sideb.powf(2.0) - common_distance.powf(2.0) ) / (2.0 * self_sidea * self_sideb) ); let othr_angle = f64::acos( ( othr_sidea.powf(2.0) + othr_sideb.powf(2.0) - common_distance.powf(2.0) ) / (2.0 * othr_sidea * othr_sideb) ); return Ok(self_angle + othr_angle > PI) } } impl PartialEq for Triangle { fn eq(&self, other: &Triangle) -> bool { let mut our_ptrs = [ Arc::as_ptr(&self.nodes[0]), Arc::as_ptr(&self.nodes[1]), Arc::as_ptr(&self.nodes[2]), ]; let mut other_ptrs = [ Arc::as_ptr(&other.nodes[0]), Arc::as_ptr(&other.nodes[1]), Arc::as_ptr(&other.nodes[2]), ]; our_ptrs.sort_unstable(); other_ptrs.sort_unstable(); our_ptrs[0] == other_ptrs[0] && our_ptrs[1] == other_ptrs[1] && our_ptrs[2] == other_ptrs[2] } } impl Eq for Triangle {} impl Hash for Triangle { fn hash(&self, state: &mut H) { let mut ptrs = [ Arc::as_ptr(&self.nodes[0]), Arc::as_ptr(&self.nodes[1]), Arc::as_ptr(&self.nodes[2]), ]; ptrs.sort_unstable(); ptrs.hash(state); } } impl fmt::Debug for Triangle { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let coords: Vec<_> = self.nodes.iter() .flat_map(|n| [n.get().x, n.get().y]) .collect(); write!( f, "Triangle[({}, {}), ({}, {}), ({}, {}))", coords[0], coords[1], coords[2], coords[3], coords[4], coords[5], ) } } impl DelaunayDemo { pub fn get_camera(&self) -> Camera2D { let width = self.width as f32; let height = self.height as f32; Camera2D { target: Vec2::new(width / 2.0, height / 2.0), zoom: Vec2::new(2./width, 2./height), .. Default::default() } } pub fn resize(&mut self, aspect_ratio: f64) { let minimum_dimension = f64::min(self.width, self.height); let (new_width, new_height) = if aspect_ratio < 1.0 { (minimum_dimension, minimum_dimension / aspect_ratio) } else { (minimum_dimension * aspect_ratio, minimum_dimension) }; let resize_factor = DVec2::new( new_width / self.width, new_height / self.height, ); if resize_factor != DVec2::ONE { for node in &self.nodes { let mut node_inner = node.get(); node_inner.0 *= resize_factor; node.set(node_inner); } self.width = new_width; self.height = new_height; if let Err(msg) = self.re_delaunize() { eprintln!("POISONED: {}", msg); self.poisoned = true; } } } fn get_walls(&self) -> impl Iterator + '_ { self.adjacency.values() .filter_map(|n| if let (Occupant(tri1), Friend(tri2)) = n { Some((tri1, tri2)) } else { None } ) .filter(|(tri1, tri2)| !self.spanning_tree.contains(tri1.common_edge(tri2).unwrap())) .map(|(tri1, tri2)| (tri1.circumcenter().0, tri2.circumcenter().0)) } fn update(&mut self) { if self.poisoned { return } for node in self.nodes.clone() { if node.get().1 != DVec2::ZERO { self.move_point(node); } } if let Err(msg) = self.re_delaunize() { eprintln!("POISONED: {}", msg); self.poisoned = true; } } fn click(&mut self, pos: Vec2) { if let Err(msg) = self.add_point_random_dir(pos.as_f64()) { self.poisoned = true; eprintln!("POISONED: {}", msg); } } fn add_random_point(&mut self) -> Result<(), String> { let random = util::pcg64(&mut self.random_state); let x = (random & 0xffffffff) as f64 / (0xffffffffu32 as f64) * self.width; let y = (random >> 32) as f64 / (0xffffffffu32 as f64) * self.height; self.add_point_random_dir((x, y).into()) } fn add_point_random_dir(&mut self, pos: DVec2) -> Result<(), String> { let random = util::pcg64(&mut self.random_state); let angle = (random as f64) / (u64::MAX as f64) * (2.0 * std::f64::consts::PI); let direction = DVec2::new( f64::cos(angle), f64::sin(angle), ); self.add_point(Node(pos, direction * SPEED)) } fn add_point(&mut self, mut node: Node) -> Result<(), String> { // If this node is on top of an existing node, move it out of the way let mut cycle_completed = false; while !cycle_completed { cycle_completed = true; for other in &self.nodes { let other_pos = other.get(); if node.distance(other_pos.0) < BOING_RADIUS { let direction = node.0 - other_pos.0; let offset = direction / direction.length() * BOING_RADIUS; node.0 += offset; node.0.x = node.0.x.rem_euclid(self.width); node.0.y = node.0.y.rem_euclid(self.width); cycle_completed = false; break; } } } // Remove invalid triangles and coalesce their edges let mut orphaned_edges: Vec<_> = Vec::with_capacity(self.triangles.len() * 3); let mut i = 0; while i < self.triangles.len() { let triangle = &self.triangles[i]; if triangle.invalidated_by_point(*node) { orphaned_edges.extend( self.remove_triangle(i)?.edges ); } else { i = i + 1; } } orphaned_edges.retain(|e| self.adjacency.contains_key(e)); // For every edge form a new triangle with that edge and this point let node = Arc::new(Cell::new(node)); let mut node_connected_edges = HashSet::with_capacity(orphaned_edges.len()); for edge in orphaned_edges { let edges = [ Edge(edge.0.clone(), node.clone()), Edge(edge.1.clone(), node.clone()), edge, ]; for edge in &edges[..2] { if self.is_point_inbounds(*edge.0.get()) { node_connected_edges.insert(edge.clone()); } } self.create_triangle(edges)?; } // Update the spanning tree let our_id = node.as_ptr() as usize; if self.spanning_tree.is_empty() && self.nodes.len() == 5 { // Connect the two non-border points let other_node: &NodeRef = self.nodes.iter() .filter(|n| self.is_point_inbounds(*n.get())) .next() .unwrap(); let joining_edge = Edge(other_node.clone(), node.clone()); let node_a_id = other_node.as_ptr() as usize; let node_b_id = node.as_ptr() as usize; self.spanning_tree.insert(joining_edge); self.spanning_tree_conn.insert(node_a_id, smallvec![node_b_id]); self.spanning_tree_conn.insert(node_b_id, smallvec![node_a_id]); } else if !self.spanning_tree.is_empty() { // Pick a random edge off this node and add it to the spanning tree let random = util::pcg64(&mut self.random_state); let random = random as usize % node_connected_edges.len(); let lucky_edge = node_connected_edges.into_iter() .skip(random) .next() .unwrap(); let connected_node = lucky_edge.node_thats_not(&node) .unwrap() .as_ptr() as usize; self.spanning_tree.insert(lucky_edge.clone()); self.spanning_tree_conn.insert(our_id, smallvec![connected_node]); if let Some(other_edges) = self.spanning_tree_conn.get_mut(&connected_node) { other_edges.push(our_id); } else { return Err(format!( "Found node {} in triangle list, but it does not have an entry in \ the spanning tree connections list", *lucky_edge.node_thats_not(&node)?.get() )); } } self.nodes.push(node); Ok(()) } fn remove_triangle(&mut self, index: usize) -> Result { let triangle = self.triangles.remove(index); for edge in &triangle.edges { match self.adjacency.get_mut(edge) { Some((Occupant(side1), side2 @ Friend(_))) => { let side2_inner = side2.unwrap_mut(); if side1 == &triangle { swap(side1, side2_inner); } else if side2_inner != &triangle { return Err(format!( "{:?} does not contain triangle \ {:?}, but this triangle's list of edges includes this \ edge. Triangle was in the triangle index until now.", edge, triangle )); } *side2 = Hole; }, Some((Occupant(our_side), Hole)) => { if our_side != &triangle { return Err(format!( "{:?} does not contain triangle \ {:?}, but this triangle's list of edges includes this \ edge. Triangle was in the triangle index until now.", edge, triangle )); } self.remove_edge(&edge)?; }, Some((Border, our_side @ Friend(_))) => { *our_side = Hole; }, Some((Border, Hole)) => { return Err(format!( "{:?} removed from graph, but it's edge {:?} is \ already marked as a border-hole edge", triangle, edge )); } None => { return Err(format!( "{:?} removed from graph, but it's edge {:?} was \ missing from adjacency graph", triangle, edge )); }, } } Ok(triangle) } fn remove_edge(&mut self, edge: &Edge) -> Result { // Remove edge from the edge graph let edge = if let Some((edge, _)) = self.adjacency.remove_entry(edge) { edge } else { return Err(format!( "Tried to remove edge {:?} from the list of edges, but it wasn't present", edge )); }; // If the edge was part of the spanning tree and the tree is initialized if !self.spanning_tree.is_empty() && self.spanning_tree.remove(&edge) { let left_id = edge.0.as_ptr() as usize; let right_id = edge.1.as_ptr() as usize; // Remove it completely from the spanning tree for (node, to_node) in [(left_id, right_id), (right_id, left_id)] { if let Some(connected_nodes) = self.spanning_tree_conn.get_mut(&node) { connected_nodes.retain(|n| *n != to_node); } else { return Err(format!( "Edge {:?} was previously in edge graph, but it's node {} was not in \ the connections list", edge, node )); } } // Traverse the tree on either side of the edge let tree_a = self.traverse_spanning_tree(edge.0.as_ptr() as usize)?; let tree_b = self.traverse_spanning_tree(edge.1.as_ptr() as usize)?; // Find a list of edges that: // - Have one node from each tree // - Do not connect to an out-of-bounds node let candidate_edges: Vec<_> = self.adjacency.keys() .filter(|e| ( tree_a.contains(&(e.0.as_ptr() as usize)) && tree_b.contains(&(e.1.as_ptr() as usize)) ) || ( tree_a.contains(&(e.1.as_ptr() as usize)) && tree_b.contains(&(e.0.as_ptr() as usize)) ) ) .filter(|e| self.is_point_inbounds(*e.0.get()) && self.is_point_inbounds(*e.1.get()) ) .collect(); // Pick one at random and add it to the spanning tree let random = util::pcg64(&mut self.random_state); let random = random as usize % candidate_edges.len(); let new_edge = candidate_edges[random]; let node_a = new_edge.0.as_ptr() as usize; let node_b = new_edge.1.as_ptr() as usize; self.spanning_tree.insert(new_edge.clone()); for (from, to) in [(node_a, node_b), (node_b, node_a)] { let connected = self.spanning_tree_conn.get_mut(&from).unwrap(); connected.push(to); } } Ok(edge) } fn traverse_spanning_tree(&self, root: usize) -> Result, String> { let mut visited = HashSet::with_capacity(self.nodes.len()); let mut to_traverse: SmallVec<[usize; 40]> = smallvec![root]; while let Some(node) = to_traverse.pop() { visited.insert(node); if let Some(c) = self.spanning_tree_conn.get(&node) { to_traverse.extend( c.iter() .filter(|c| !visited.contains(c)) .map(|c| *c) ); } else { return Err(format!( "Spanning tree connection database lists a connection to node id {}, \ but that node lacks an entry in the database", node )); }; } Ok(visited) } fn is_point_inbounds(&self, p: DVec2) -> bool { p.x > 0. && p.y > 0. && p.x < self.width && p.y < self.height } fn create_triangle(&mut self, edges: [Edge; 3]) -> Result<&Triangle, String> { let triangle = Triangle::new(edges.clone()); for edge in edges { match self.adjacency.entry(edge) { Entry::Occupied(mut entry) => { match entry.get_mut() { (Occupant(tri1), Friend(tri2)) => { let (tri1, tri2) = (tri1.clone(), tri2.clone()); return Err(format!( "Tried to create a triangle with edge {:?}, \ but this edge is already in use by triangles {:?} and \ {:?}.", entry.key(), tri1, tri2 )); }, (Border, Friend(tri)) => { let tri = tri.clone(); return Err(format!( "Tried to create a triangle with edge {:?}, \ but this edge is already in use by triangle {:?} and \ is a border.", entry.key(), tri )); }, (Occupant(_) | Border, new_home @ Hole) => { *new_home = Friend(triangle.clone()); }, } }, Entry::Vacant(entry) => { entry.insert(((&triangle).into(), Hole)); } } } self.triangles.push(triangle); Ok(self.triangles.last().unwrap()) } fn move_point(&mut self, node: NodeRef) { // Update position let current_pos = node.get(); let mut new_pos = Node(current_pos.0 + current_pos.1, current_pos.1); // Check if it is going to hit another point for other in &self.nodes { // If we are currently inside the boing radius of the node (e.g. because we spawned // there), then move out. if !Arc::ptr_eq(other, &node) && current_pos.distance(other.get().0) < BOING_RADIUS { let other_pos = other.get(); let direction = current_pos.0 - other_pos.0; let offset = direction / direction.length() * BOING_RADIUS / 2.; node.set(Node(current_pos.0 + offset, current_pos.1)); other.set(Node(other_pos.0 - offset, other_pos.1)); return self.move_point(node); } // If we are going to walk into the boing radius of another node, boing! if !Arc::ptr_eq(other, &node) && new_pos.distance(other.get().0) < BOING_RADIUS { let mut node_inner = node.get(); let mut other_inner = other.get(); swap(&mut other_inner.1, &mut node_inner.1); other.set(other_inner); node.set(node_inner); return; } } // Check for a bounce if new_pos.0.y > self.height { new_pos.0.y = 2.0 * self.height - new_pos.0.y; new_pos.1.y = -new_pos.1.y; } if new_pos.0.y < 0.0 { new_pos.0.y = -new_pos.0.y; new_pos.1.y = -new_pos.1.y; } if new_pos.0.x > self.width { new_pos.0.x = 2.0 * self.width - new_pos.0.x; new_pos.1.x = -new_pos.1.x; } if new_pos.0.x < 0.0 { new_pos.0.x = -new_pos.0.x; new_pos.1.x = -new_pos.1.x; } node.set(new_pos); } fn get_neighbors(&self, triangle: &Triangle) -> Result, String> { triangle.edges.iter() .filter_map(|e| match self.adjacency.get(e) { Some((Occupant(a), Friend(b))) => { if a != triangle && b == triangle { Some(Ok(a)) } else if a == triangle && b != triangle { Some(Ok(b)) } else if a == triangle && b == triangle { Some(Err(format!( "{:?} has {:?} in adjacency graph which lists itself as \ its own neighbor", triangle, e ))) } else { Some(Err(format!( "{:?} has {:?}, but the adjacency graph reports that the \ triangles next to this edge are {:?} and {:?}", triangle, e, a, b ))) } }, Some((Border, Friend(tri))) => { if tri == triangle { None } else { Some(Err(format!( "{:?} has {:?}, but the adjacency graph reports that \ this edge is an edge between the graph hull and {:?}", triangle, e, tri ))) } }, Some((Occupant(tri), Hole)) => { if tri == triangle { None } else { Some(Err(format!( "{:?} has {:?}, but the adjacency graph reports that \ this edge is an edge between a polygonal hole and {:?}", triangle, e, tri ))) } }, Some((Border, Hole)) => { Some(Err(format!( "{:?} has {:?}, but the adjacency graph lists this edge as \ being between the graph hull and a polygonal hole (aka, it \ has no neighbors", triangle, e ))) }, None => { Some(Err(format!( "get_neighbors called on {:?}, but its edge {:?} is not \ present in the adjacency graph.", triangle, e ))) }, } ) .collect() } fn flip_triangles( &mut self, tri1: &Triangle, tri2: &Triangle ) -> Result<(Triangle, &Triangle), String> { let mut indices = self.triangles.iter() .enumerate() .filter(|(_, t)| t == &tri1 || t == &tri2) .map(|(i, _)| i); let err = || format!( "flip_triangles called on {:?} and {:?}, but not both of these were found in \ the list of triangles", tri1, tri2 ); let mut indices = [ indices.next().ok_or_else(err)?, indices.next().ok_or_else(err)?, ]; indices.sort_unstable(); let tri1 = self.remove_triangle(indices[1])?; let tri2 = self.remove_triangle(indices[0])?; let common_edge = tri1.common_edge(&tri2)?; let tri1_point = tri1.point_not_on(common_edge)?; let tri2_point = tri2.point_not_on(common_edge)?; Ok(( self.create_triangle([ Edge(tri1_point.clone(), common_edge.0.clone()), Edge(tri2_point.clone(), common_edge.0.clone()), Edge(tri1_point.clone(), tri2_point.clone()), ])?.clone(), self.create_triangle([ Edge(tri1_point.clone(), common_edge.1.clone()), Edge(tri2_point.clone(), common_edge.1.clone()), Edge(tri1_point.clone(), tri2_point.clone()), ])?, )) } fn re_delaunize(&mut self) -> Result<(), String> { let mut i = 0; while i < self.triangles.len() { let triangle = &self.triangles[i]; let neighbors: Vec<_> = self.get_neighbors(triangle)? .into_iter() .cloned() .collect(); let mut flipped = false; for neighbor in neighbors { if triangle.invalidated_by_neighbor(&neighbor)? { let triangle = triangle.clone(); self.flip_triangles(&triangle, &neighbor)?; i = 0; flipped = true; break; } } if !flipped { i = i + 1; } } Ok(()) } }