diff --git a/src/sweeper.rs b/src/sweeper.rs index adcba6b..2246973 100644 --- a/src/sweeper.rs +++ b/src/sweeper.rs @@ -2,7 +2,7 @@ use crate::advancing_front::{AdvancingFront, NodeId, NodeRef}; use crate::points::{Points, PointsBuilder}; use crate::triangles::TriangleId; use crate::triangles::TriangleStore; -use crate::utils::{in_circle, in_scan_area, orient_2d, Orientation}; +use crate::utils::{in_circle, in_scan_area, orient_2d, Angle, Orientation}; use crate::{shape::*, Context, PointId, Triangle}; /// Observer for sweeper, used to monitor how sweeper works, quite useful @@ -627,10 +627,10 @@ impl Sweeper { } fn should_fill(node: &NodeRef) -> bool { - let next_node = node.next().unwrap(); + let next = node.next().unwrap(); let prev_node = node.prev().unwrap(); - let angle = crate::utils::Angle::new(node.point(), next_node.point(), prev_node.point()); + let angle = crate::utils::Angle::new(node.point(), next.point(), prev_node.point()); if angle.is_negative() { // negative means next -> node -> prev is cw, then it is not a hole @@ -642,6 +642,20 @@ impl Sweeper { return false; } + if let Some(next_next) = next.next() { + if Angle::new(node.point(), next_next.point(), prev_node.point()) + .between_0_to_90_degree() + { + return false; + } + } + + if let Some(prev_prev) = prev_node.prev() { + if Angle::new(node.point(), next.point(), prev_prev.point()).between_0_to_90_degree() { + return false; + } + } + true } } @@ -1589,7 +1603,7 @@ mod tests { .collect::>(); assert_eq!(triangles.len(), 273); assert!(cache_hit.hit_rate() > 0.63); - assert!(cache_hit.rotate_count <= 331); + assert!(cache_hit.rotate_count == 272); } #[test] @@ -1604,7 +1618,7 @@ mod tests { .collect::>(); assert_eq!(triangles.len(), 1034); assert!(cache_hit.hit_rate() > 0.71); - assert!(cache_hit.rotate_count <= 665); + assert!(cache_hit.rotate_count == 671); } #[test] diff --git a/src/utils.rs b/src/utils.rs index 00b1403..9581635 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -94,6 +94,21 @@ impl Angle { Angle { dy: y, dx: x } } + /// Check angle between 0 and 90, all exclusive + pub fn between_0_to_90_degree(&self) -> bool { + // * `x = 0`, `y = 0`: `0` + // * `x >= 0`: `arctan(y/x)` -> `[-pi/2, pi/2]` + // * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` + // * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` + if self.dx == 0. && self.dy == 0. { + true + } else if self.dx > 0. { + self.dy > 0. + } else { + false + } + } + /// whether the angle exceeds PI / 2 pub fn exceeds_90_degree(&self) -> bool { // * `x = 0`, `y = 0`: `0` @@ -161,16 +176,19 @@ mod tests { #[test] fn test_angle() { let angle = Angle::new(Point::new(0., 0.), Point::new(1., 0.), Point::new(1., 1.)); - assert!(!dbg!(angle).exceeds_90_degree()); + assert!(!angle.exceeds_90_degree()); assert!(!angle.is_negative()); + assert!(angle.between_0_to_90_degree()); let angle = Angle::new(Point::new(0., 0.), Point::new(0.1, 1.), Point::new(1., 0.)); assert!(!dbg!(angle).exceeds_90_degree()); assert!(angle.is_negative()); + assert!(!angle.between_0_to_90_degree()); - let angle = Angle::new(Point::new(0., 0.), Point::new(0., -1.), Point::new(1., 0.)); + let angle = Angle::new(Point::new(0., 0.), Point::new(0.1, -1.), Point::new(1., 0.)); assert!(!angle.exceeds_90_degree()); assert!(!angle.is_negative()); + assert!(angle.between_0_to_90_degree()); let angle = Angle::new( Point::new(0., 0.), @@ -179,6 +197,7 @@ mod tests { ); assert!(angle.exceeds_90_degree()); assert!(!angle.is_negative()); + assert!(!angle.between_0_to_90_degree()); let angle = Angle::new( Point::new(0., 0.), @@ -187,13 +206,15 @@ mod tests { ); assert!(angle.is_negative()); assert!(!angle.exceeds_90_degree()); + assert!(!angle.between_0_to_90_degree()); let angle = Angle::new( Point::new(0., 0.), Point::new(1.0, 0.), Point::new(-1., 0.1), ); - assert!(!dbg!(angle).is_negative()); + assert!(!angle.is_negative()); assert!(angle.exceeds_90_degree()); + assert!(!angle.between_0_to_90_degree()); } }