diff --git a/src/main.rs b/src/main.rs index 6f6e889..88424ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -269,6 +269,73 @@ impl Triangle { 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 = f32::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 = f32::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 { @@ -346,11 +413,18 @@ impl DelaunayDemo { } fn update(&mut self) { + if self.poisoned { + return + } for node in self.nodes.clone() { if node.get().1 != Vec2::ZERO { self.move_point(node); } } + if let Err(msg) = self.re_delaunize() { + eprintln!("POISONED: {}", msg); + self.poisoned = true; + } } fn click(&mut self, pos: Vec2) { @@ -362,7 +436,7 @@ impl DelaunayDemo { ); if let Err(msg) = self.add_point(Node(pos, direction * 2.0)) { self.poisoned = true; - eprintln!("{}", msg); + eprintln!("POISONED: {}", msg); } } @@ -488,11 +562,6 @@ impl DelaunayDemo { 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; @@ -516,88 +585,138 @@ impl DelaunayDemo { } node.set(node_inner); - */ - - // 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 - - /* - 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); - } - } - } - */ } + + 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(()) + } }