pub mod util; 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 macroquad::prelude::draw_circle_lines; 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 macroquad::prelude::draw_line; 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::draw_circle; use macroquad::prelude::clear_background; use macroquad::prelude::Color; use macroquad::input::MouseButton; use std::sync::Arc; const BG: Color = Color::new(0.16863, 0.23922, 0.21176, 1.0); const FG: Color = Color::new(0.91569, 0.71765, 0.00000, 1.0); const DIM_FG: Color = Color::new(0.29412, 0.27451, 0.13333, 1.0); const HIL_FG: Color = Color::new(0.25806, 0.61290, 1.09032, 1.0); const SPEED: f64 = 0.1; const BOING_RADIUS: f64 = 30.0; const HILITE: bool = false; #[macroquad::main("BasicShapes")] async fn main() { let mut dd = DelaunayDemo::default(); let mut camera = dd.get_camera(); set_camera(&camera); let mut iter = 0; loop { if iter == 100 { iter = 0; dd.resize((screen_width()/screen_height()) as f64); camera = dd.get_camera(); set_camera(&mut camera); } if is_mouse_button_pressed(MouseButton::Left) { dd.click(camera.screen_to_world(mouse_position().into())); } if is_mouse_button_pressed(MouseButton::Right) { let mouse_position: Vec2 = camera.screen_to_world(mouse_position().into()); 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(BG); dd.update(); //dd.draw_delaunay(); dd.draw_voronoi(); iter += 1; next_frame().await; } } pub struct DelaunayDemo { pub nodes: Vec, pub triangles: Vec, 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 dd = DelaunayDemo { nodes, adjacency, triangles, height: HEIGHT, width: WIDTH, random_state: 1312_1312_1312, poisoned: false, }; /*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 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 len_a = b.distance(c); let len_b = c.distance(a); let len_c = a.distance(b); let cos_a = (len_b.powf(2.0) + len_c.powf(2.0) - len_a.powf(2.0)) / (2.0 * len_b * len_c ); let cos_b = (len_c.powf(2.0) + len_a.powf(2.0) - len_b.powf(2.0)) / (2.0 * len_c * len_a ); let ang_a = f64::acos(cos_a); let ang_b = f64::acos(cos_b); let ang_c = PI - ang_a - ang_b; let sin_2a = f64::sin(2.0 * ang_a); let sin_2b = f64::sin(2.0 * ang_b); let sin_2c = f64::sin(2.0 * ang_c); let circumcenter = DVec2::new( (a.x * sin_2a + b.x * sin_2b + c.x * sin_2c) / (sin_2a + sin_2b + sin_2c), (a.y * sin_2a + b.y * sin_2b + c.y * sin_2c) / (sin_2a + sin_2b + sin_2c), ); 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 draw_delaunay(&self) { let mut highlight_segments = Vec::new(); for triangle in &self.triangles { let (c, r) = triangle.circumcenter(); let mpos: Vec2 = mouse_position().into(); let color = if c.distance(mpos.as_f64()) < r && HILITE { highlight_segments.extend(&triangle.edges); HIL_FG } else { DIM_FG }; draw_circle_lines(c.x as f32, c.y as f32, r as f32, 1.0, color); } for edge in self.adjacency.keys() { let color = if highlight_segments.contains(&edge) { HIL_FG } else { FG }; let edge_0 = edge.0.get().as_f32(); let edge_1 = edge.1.get().as_f32(); if edge_0.x < 0.0 || edge_0.x > self.width as f32 || edge_0.y < 0.0 || edge_0.y > self.height as f32 || edge_1.x < 0.0 || edge_1.x > self.width as f32 || edge_1.y < 0.0 || edge_1.y > self.height as f32 { continue; //don't draw container nodes } draw_line( edge_0.x, edge_0.y, edge_1.x, edge_1.y, 3.0, color ); } for node in &self.nodes { let pos = node.get().as_f32(); draw_circle(pos.x, pos.y, 10.0, FG); } } fn draw_voronoi(&self) { for neighbors in self.adjacency.values() { if let (Occupant(tri1), Friend(tri2)) = neighbors { let (center1, _) = tri1.circumcenter(); let (center2, _) = tri2.circumcenter(); draw_line( center1.x as f32, center1.y as f32, center2.x as f32, center2.y as f32, 3.0, FG ); } } } 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) { 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), ); if let Err(msg) = self.add_point(Node(pos.as_f64(), direction * SPEED)) { self.poisoned = true; eprintln!("POISONED: {}", msg); } } fn add_point(&mut self, node: Node) -> Result<(), String> { // 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)); for edge in orphaned_edges { self.create_triangle([ Edge(edge.0.clone(), node.clone()), Edge(edge.1.clone(), node.clone()), edge, ])?; } 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.adjacency.remove(&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 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 mut node_inner = node.get(); node_inner.0 = node_inner.0 + node_inner.1; // Check if it is going to hit another point for other in &self.nodes { if !Arc::ptr_eq(other, &node) && node_inner.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 node_inner.0.y > self.height { node_inner.0.y = 2.0 * self.height - node_inner.0.y; node_inner.1.y = -node_inner.1.y; } if node_inner.0.y < 0.0 { node_inner.0.y = -node_inner.0.y; node_inner.1.y = -node_inner.1.y; } if node_inner.0.x > self.width { node_inner.0.x = 2.0 * self.width - node_inner.0.x; node_inner.1.x = -node_inner.1.x; } if node_inner.0.x < 0.0 { node_inner.0.x = -node_inner.0.x; node_inner.1.x = -node_inner.1.x; } node.set(node_inner); } 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(()) } }