From 0b2bc8c1f8efcdcb650ae565a00e0f450f2f63a3 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Mon, 11 Apr 2022 16:41:46 +0200 Subject: [PATCH] Fix triangulation edge case Triangular holes in a face were treated as part of the face. --- .../src/algorithms/triangulation/polygon.rs | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/fj-kernel/src/algorithms/triangulation/polygon.rs b/fj-kernel/src/algorithms/triangulation/polygon.rs index 37fa9f1aa..4b5e01bff 100644 --- a/fj-kernel/src/algorithms/triangulation/polygon.rs +++ b/fj-kernel/src/algorithms/triangulation/polygon.rs @@ -61,9 +61,13 @@ impl Polygon { pub fn contains_triangle( &self, - [a, b, c]: [Point<2>; 3], + triangle: [impl Into>; 3], debug_info: &mut DebugInfo, ) -> bool { + let [a, b, c] = triangle.map(Into::into); + + let mut might_be_hole = true; + for edge in [a, b, c, a].windows(2) { // This can't panic, as we passed `2` to `windows`. It can be // cleaned up a bit, once `array_windows` is stable. @@ -72,6 +76,13 @@ impl Polygon { let is_exterior_edge = self.contains_exterior_edge(edge); let is_interior_edge = self.contains_interior_edge(edge); + // If the triangle edge is not an interior edge of the polygon, we + // can rule out that the triangle is identical with a hole in the + // polygon. + if !is_interior_edge { + might_be_hole = false; + } + // If the triangle edge is an edge of the face, we don't need to // take a closer look. if is_exterior_edge || is_interior_edge { @@ -92,6 +103,12 @@ impl Polygon { } } + // We haven't rules out that the triangle is a polygon hole. Since we + // checked all its edges, this means we now know for certain that is is. + if might_be_hole { + return false; + } + // If we didn't throw away the triangle up till now, this means all its // edges are within the face. true @@ -208,6 +225,23 @@ mod tests { use super::Polygon; + #[test] + fn contains_triangle_with_triangular_hole() { + let a = [0., 0.]; + let b = [3., 0.]; + let c = [0., 3.]; + + let d = [1., 1.]; + let e = [2., 1.]; + let f = [1., 2.]; + + let polygon = Polygon::new(Surface::x_y_plane()) + .with_exterior(PolyChain::from([a, b, c]).close()) + .with_interiors([PolyChain::from([d, e, f]).close()]); + + assert!(!polygon.contains_triangle([d, e, f], &mut DebugInfo::new())); + } + #[test] fn contains_point_ray_hits_vertex_while_passing_outside() { let a = [0., 0.];