use std::collections::HashSet; use core::f32::consts::PI; use macroquad::prelude::draw_circle_lines; 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); #[macroquad::main("BasicShapes")] async fn main() { let mut dd = DelaunayDemo::default(); loop { if is_mouse_button_pressed(MouseButton::Left) { dd.click(mouse_position().into()) } dd.draw(); next_frame().await; } } pub struct DelaunayDemo { pub nodes: Vec>, pub triangles: Vec, pub edges: Vec, } impl Default for DelaunayDemo { fn default() -> Self { let nodes: Vec> = vec![ Arc::new((0.0, 0.0).into()), Arc::new((0.0, screen_height()).into()), Arc::new((screen_width(), 0.0).into()), Arc::new((screen_width(), screen_height()).into()), ]; let edges = vec![ 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()], ), ]; DelaunayDemo { nodes, edges, triangles, } } } #[derive(Copy, Clone, Debug)] pub struct Node(Vec2); impl Deref for Node { type Target = Vec2; fn deref(&self) -> &Vec2 { &self.0 } } impl DerefMut for Node { fn deref_mut(&mut self) -> &mut Vec2 { &mut self.0 } } impl From<(f32, f32)> for Node { fn from((x, y): (f32, f32)) -> Node { Node(Vec2::new(x, y)) } } #[derive(Clone, Debug)] pub struct Edge(Arc, Arc); 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); } } pub struct Triangle { nodes: [Arc; 3], edges: [Edge; 3], circumcenter: Vec2, radius: f32, } 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() } ]; let circumcenter = Self::circumcenter(**nodes[0], **nodes[1], **nodes[2]); let radius = circumcenter.distance(**nodes[0]); Triangle { nodes, edges, circumcenter, radius, } } fn circumcenter(a: Vec2, b: Vec2, c: Vec2) -> Vec2 { 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 = f32::acos(cos_a); let ang_b = f32::acos(cos_b); let ang_c = PI - ang_a - ang_b; let sin_2a = f32::sin(2.0 * ang_a); let sin_2b = f32::sin(2.0 * ang_b); let sin_2c = f32::sin(2.0 * ang_c); Vec2::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), ) } pub fn invalidated_by_point(&self, point: Vec2) -> bool { self.circumcenter.distance(point) < self.radius } } impl DelaunayDemo { fn draw(&self) { clear_background(BG); let mut danger_lines = Vec::with_capacity(3); for triangle in &self.triangles { let c = triangle.circumcenter; let color = if c.distance(mouse_position().into()) < triangle.radius { danger_lines.extend(&triangle.edges); DIM_FG //HIL_FG } else { DIM_FG }; draw_circle_lines(c.x, c.y, triangle.radius, 1.0, color); } for edge in &self.edges { let color = if danger_lines.contains(&edge) { FG //HIL_FG } else { FG }; draw_line(edge.0.x, edge.0.y, edge.1.x, edge.1.y, 3.0, color); } for node in &self.nodes { draw_circle(node.x, node.y, 10.0, FG); } } fn click(&mut self, pos: Vec2) { self.add_point(Node(pos)); } fn add_point(&mut self, node: Node) { // Remove invalid triangles and coalesce their edges let mut bad_triangle_sides: 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) { bad_triangle_sides.extend( self.triangles.remove(i).edges ); } else { i = i + 1; } } // For every edge // If it has a duplicate later in the list // Remove the edge from existance // Otherwise // Form a new triangle with that edge and this point let node = Arc::new(node); let mut new_edges = HashSet::with_capacity(bad_triangle_sides.len()); i = 0; while i < bad_triangle_sides.len() { let edge = &bad_triangle_sides[i]; let other_edge_i = bad_triangle_sides[(i + 1)..].iter() .position(|other_edge| edge == other_edge); if let Some(other_edge_i) = other_edge_i { bad_triangle_sides.remove(other_edge_i + i + 1); i = i + 1; } else { let edge = bad_triangle_sides.remove(i); let new_edge_a = Edge(edge.0.clone(), node.clone()); let new_edge_b = Edge(edge.1.clone(), node.clone()); self.triangles.push(Triangle::new([ edge, new_edge_a.clone(), new_edge_b.clone(), ])); new_edges.extend([new_edge_a, new_edge_b]); } } self.edges.retain(|e| !bad_triangle_sides.iter().any(|bad_e| e == bad_e)); self.edges.extend(new_edges); self.nodes.push(node); } /*fn move_point(&mut self, node: Arc) { // Update position // Check for broken triangles // Remove triange // Remove triangle consisting of common points + self // Form triangle consisting of common point A + self + opposite // Form triangle consisting of common point B + self + opposite }*/ }