diff --git a/src/main.rs b/src/main.rs index 417fb27..e389367 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,10 @@ -use std::collections::HashSet; +pub mod util; + +use core::mem::swap; +use std::collections::HashMap; +use core::fmt; +use core::cell::Cell; +use std::collections::hash_map::Entry; use core::f32::consts::PI; use macroquad::prelude::draw_circle_lines; use macroquad::prelude::mouse_position; @@ -30,48 +36,103 @@ async fn main() { if is_mouse_button_pressed(MouseButton::Left) { dd.click(mouse_position().into()) } + dd.update(); dd.draw(); next_frame().await; } } pub struct DelaunayDemo { - pub nodes: Vec>, + pub nodes: Vec, pub triangles: Vec, - pub edges: Vec, + adjacency: HashMap, + poisoned: bool, + random_state: u128 +} + +enum NeighborOne { + Occupant(Triangle), + Border, +} +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 { - 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 nodes: Vec = vec![ + Arc::new(Cell::new((0.0, 0.0).into())), + Arc::new(Cell::new((0.0, screen_height()).into())), + Arc::new(Cell::new((screen_width(), 0.0).into())), + Arc::new(Cell::new((screen_width(), screen_height()).into())), ]; - let edges = vec![ + 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()], + [edges.0.clone(), edges.1.clone(), edges.2.clone()], ), Triangle::new( - [edges[2].clone(), edges[3].clone(), edges[4].clone()], + [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(); DelaunayDemo { - nodes, edges, triangles, + nodes, adjacency, triangles, random_state: 1312_1312_1312, poisoned: false, } } } #[derive(Copy, Clone, Debug)] -pub struct Node(Vec2); +pub struct Node(Vec2, Vec2); impl Deref for Node { type Target = Vec2; @@ -89,12 +150,14 @@ impl DerefMut for Node { impl From<(f32, f32)> for Node { fn from((x, y): (f32, f32)) -> Node { - Node(Vec2::new(x, y)) + Node(Vec2::new(x, y), Vec2::ZERO) } } -#[derive(Clone, Debug)] -pub struct Edge(Arc, Arc); +type NodeRef = Arc>; + +#[derive(Clone)] +pub struct Edge(NodeRef, NodeRef); impl PartialEq for Edge { fn eq(&self, other: &Edge) -> bool { @@ -126,11 +189,22 @@ impl Hash for Edge { } } +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: [Arc; 3], + nodes: [NodeRef; 3], edges: [Edge; 3], - circumcenter: Vec2, - radius: f32, } impl Triangle { @@ -144,131 +218,308 @@ impl Triangle { 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); + 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, + } + } - 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 ); + pub fn circumcenter(&self) -> (Vec2, f32) { + Self::calc_circumcenter(*self.nodes[0].get(), *self.nodes[1].get(), *self.nodes[2].get()) + } - let ang_a = f32::acos(cos_a); - let ang_b = f32::acos(cos_b); - let ang_c = PI - ang_a - ang_b; + fn calc_circumcenter(a: Vec2, b: Vec2, c: Vec2) -> (Vec2, f32) { + let len_a = b.distance(c); + let len_b = c.distance(a); + let len_c = a.distance(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); + 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 ); - 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), - ) -} + 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); + + let circumcenter = 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), + ); + let radius = circumcenter.distance(a); + + (circumcenter, radius) + } pub fn invalidated_by_point(&self, point: Vec2) -> bool { - self.circumcenter.distance(point) < self.radius + let (c, r) = self.circumcenter(); + c.distance(point) < r + } +} + +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 { 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); + let (c, r) = triangle.circumcenter(); + draw_circle_lines(c.x, c.y, r, 1.0, DIM_FG); } - 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 edge in self.adjacency.keys() { + draw_line( + edge.0.get().x, + edge.0.get().y, + edge.1.get().x, + edge.1.get().y, + 3.0, FG + ); } for node in &self.nodes { - draw_circle(node.x, node.y, 10.0, FG); + draw_circle(node.get().x, node.get().y, 10.0, FG); + } + } + + fn update(&mut self) { + for node in self.nodes.clone() { + if node.get().1 != Vec2::ZERO { + self.move_point(node); + } } } fn click(&mut self, pos: Vec2) { - self.add_point(Node(pos)); + 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 = Vec2::new( + f64::cos(angle) as f32, + f64::sin(angle) as f32, + ); + if let Err(msg) = self.add_point(Node(pos, direction * 2.0)) { + self.poisoned = true; + eprintln!("{}", msg); + } } - fn add_point(&mut self, node: Node) { + fn add_point(&mut self, node: Node) -> Result<(), String> { + + println!("Adding point {:?}", node); // Remove invalid triangles and coalesce their edges - let mut bad_triangle_sides: Vec<_> = Vec::with_capacity(self.triangles.len() * 3); + 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) { - bad_triangle_sides.extend( - self.triangles.remove(i).edges + orphaned_edges.extend( + self.remove_triangle(i)?.edges ); } else { i = i + 1; } } + orphaned_edges.retain(|e| self.adjacency.contains_key(e)); + println!("Orphaned Edges: {:?}", orphaned_edges); - // 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]); - } + // 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 { + println!("Creating triangle with: {:?}", edge); + self.create_triangle([ + Edge(edge.0.clone(), node.clone()), + Edge(edge.1.clone(), node.clone()), + edge, + ])?; } - self.edges.retain(|e| !bad_triangle_sides.iter().any(|bad_e| e == bad_e)); - self.edges.extend(new_edges); + self.nodes.push(node); + + Ok(()) } - /*fn move_point(&mut self, node: Arc) { + 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) { + + if self.poisoned { + return + } + + /* // Update position + let mut node_inner = node.get(); + node_inner.0 = node_inner.0 + node_inner.1; + + // Check for a bounce + if node_inner.0.y > screen_height() { + node_inner.0.y = 2.0 * screen_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 > screen_width() { + node_inner.0.x = 2.0 * screen_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); + */ // Check for broken triangles @@ -279,5 +530,77 @@ impl DelaunayDemo { // Form triangle consisting of common point A + self + opposite // Form triangle consisting of common point B + self + opposite - }*/ + + /* + let mut i = 0; + let mut needs_rerun = false; + while i < self.triangles.len() { + if i == 0 { + needs_rerun = false; + } + let triangle = &self.triangles[i]; + if !triangle.nodes.iter().any(|n| Arc::ptr_eq(n, &node)) && + triangle.invalidated_by_point(*node_inner) + { + + println!("{:?} invalidated by {:?}", triangle, node_inner); + + let pair_triangle_i = self.triangles.iter() + .position(|t| { + t.nodes.iter() + .filter(|n| triangle.nodes + .iter() + .any(|n2| Arc::ptr_eq(n, n2)) + ) + .count() == 2 + }); + let pair_triangle_i = if let Some(i) = pair_triangle_i { + i + } else { + i = (i + 1) % self.triangles.len(); + needs_rerun = true; + continue + }; + // .expect("Invariant violated: All triangles invalidated by a moved \ + // point have a pair triangle"); + let pair_triangle = self.triangles.remove(pair_triangle_i); + let triangle = self.triangles.remove(i); + let common_edge = pair_triangle.edges.iter() + .filter(|e| + !Arc::ptr_eq(&e.0, &node) && + !Arc::ptr_eq(&e.1, &node) + ) + .next() + .expect("Invariant violated: Triangles must be a closed polygon"); + + let opposite_point = triangle.nodes.into_iter() + .filter(|n| + !Arc::ptr_eq(&common_edge.0, n) && + !Arc::ptr_eq(&common_edge.1, n) + ) + .next() + .expect("Invariant violated: Triangles must have three unique points"); + let new_common_edge = Edge(node.clone(), opposite_point.clone()); + self.edges.push(new_common_edge); + + let common_edge_i = self.edges.iter() + .position(|e| e == common_edge) + .expect("Invariant violated: Triangle edges must all be in the \ + master database"); + let common_edge = self.edges.remove(common_edge_i); + + self.triangles.extend([ + Triangle::new_from_points([node.clone(), opposite_point.clone(), common_edge.0]), + Triangle::new_from_points([node.clone(), opposite_point, common_edge.1]), + ]); + } else { + if needs_rerun { + i = (i + 1) % self.triangles.len(); + } else { + i = (i + 1); + } + } + } + */ + } } diff --git a/src/util.rs b/src/util.rs index e69de29..2330bec 100644 --- a/src/util.rs +++ b/src/util.rs @@ -0,0 +1,13 @@ +pub fn pcg64(state: &mut u128) -> u64 { + let mut x = *state; + pcg64_iterstate(state); + let count = (x >> (128 - 6)) as u32; // Highest 6 bits + x ^= x >> 35; + ((x >> 58) as u64).rotate_right(count) +} + +fn pcg64_iterstate(state: &mut u128) { + const MULTIPLIER: u128 = 0xde92a69f6e2f9f25fd0d90f576075fbd; + const INCREMENT: u128 = 621; + *state = state.wrapping_mul(MULTIPLIER).wrapping_add(INCREMENT); +}