From 85dad8223c40aadd7940d218d437cc6f64c415b7 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 13:50:27 +0200 Subject: [PATCH 01/11] Implement `Approx` for `&Faces` --- crates/fj-kernel/src/algorithms/approx/face.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index d3f9819e1..ee0babe22 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -6,10 +6,20 @@ use std::collections::BTreeSet; use fj_interop::mesh::Color; -use crate::objects::Face; +use crate::objects::{Face, Faces}; use super::{cycle::CycleApprox, Approx, ApproxPoint, Tolerance}; +impl Approx for &Faces { + type Approximation = BTreeSet; + + fn approx(self, tolerance: Tolerance) -> Self::Approximation { + self.into_iter() + .map(|face| face.approx(tolerance)) + .collect() + } +} + impl Approx for &Face { type Approximation = FaceApprox; From 5c93dcf0c9554112cc6fe31c9791925547ea162d Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:14:59 +0200 Subject: [PATCH 02/11] Implement `Approx` for `&Sketch` --- crates/fj-kernel/src/algorithms/approx/mod.rs | 1 + crates/fj-kernel/src/algorithms/approx/sketch.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 crates/fj-kernel/src/algorithms/approx/sketch.rs diff --git a/crates/fj-kernel/src/algorithms/approx/mod.rs b/crates/fj-kernel/src/algorithms/approx/mod.rs index fc6bafcb1..15a2251f0 100644 --- a/crates/fj-kernel/src/algorithms/approx/mod.rs +++ b/crates/fj-kernel/src/algorithms/approx/mod.rs @@ -4,6 +4,7 @@ pub mod curve; pub mod cycle; pub mod edge; pub mod face; +pub mod sketch; pub mod tolerance; use std::{ diff --git a/crates/fj-kernel/src/algorithms/approx/sketch.rs b/crates/fj-kernel/src/algorithms/approx/sketch.rs new file mode 100644 index 000000000..43938b4b4 --- /dev/null +++ b/crates/fj-kernel/src/algorithms/approx/sketch.rs @@ -0,0 +1,15 @@ +//! Sketch approximation + +use std::collections::BTreeSet; + +use crate::objects::Sketch; + +use super::{face::FaceApprox, Approx, Tolerance}; + +impl Approx for &Sketch { + type Approximation = BTreeSet; + + fn approx(self, tolerance: Tolerance) -> Self::Approximation { + self.faces().approx(tolerance) + } +} From 5149a57b37cd98cf8f6406592414bca961b3fa11 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:16:39 +0200 Subject: [PATCH 03/11] Implement `Approx` for `&Shell` --- crates/fj-kernel/src/algorithms/approx/mod.rs | 1 + crates/fj-kernel/src/algorithms/approx/shell.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 crates/fj-kernel/src/algorithms/approx/shell.rs diff --git a/crates/fj-kernel/src/algorithms/approx/mod.rs b/crates/fj-kernel/src/algorithms/approx/mod.rs index 15a2251f0..eabb9832c 100644 --- a/crates/fj-kernel/src/algorithms/approx/mod.rs +++ b/crates/fj-kernel/src/algorithms/approx/mod.rs @@ -4,6 +4,7 @@ pub mod curve; pub mod cycle; pub mod edge; pub mod face; +pub mod shell; pub mod sketch; pub mod tolerance; diff --git a/crates/fj-kernel/src/algorithms/approx/shell.rs b/crates/fj-kernel/src/algorithms/approx/shell.rs new file mode 100644 index 000000000..fcce75511 --- /dev/null +++ b/crates/fj-kernel/src/algorithms/approx/shell.rs @@ -0,0 +1,15 @@ +//! Shell approximation + +use std::collections::BTreeSet; + +use crate::objects::Shell; + +use super::{face::FaceApprox, Approx, Tolerance}; + +impl Approx for &Shell { + type Approximation = BTreeSet; + + fn approx(self, tolerance: Tolerance) -> Self::Approximation { + self.faces().approx(tolerance) + } +} From c5c7ace4c4cd9b3173eafcac4caff06752f24918 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:18:56 +0200 Subject: [PATCH 04/11] Implement `Approx` for `&Solid` --- crates/fj-kernel/src/algorithms/approx/mod.rs | 1 + crates/fj-kernel/src/algorithms/approx/solid.rs | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 crates/fj-kernel/src/algorithms/approx/solid.rs diff --git a/crates/fj-kernel/src/algorithms/approx/mod.rs b/crates/fj-kernel/src/algorithms/approx/mod.rs index eabb9832c..0284b2b51 100644 --- a/crates/fj-kernel/src/algorithms/approx/mod.rs +++ b/crates/fj-kernel/src/algorithms/approx/mod.rs @@ -6,6 +6,7 @@ pub mod edge; pub mod face; pub mod shell; pub mod sketch; +pub mod solid; pub mod tolerance; use std::{ diff --git a/crates/fj-kernel/src/algorithms/approx/solid.rs b/crates/fj-kernel/src/algorithms/approx/solid.rs new file mode 100644 index 000000000..34126f82c --- /dev/null +++ b/crates/fj-kernel/src/algorithms/approx/solid.rs @@ -0,0 +1,17 @@ +//! Solid approximation + +use std::collections::BTreeSet; + +use crate::objects::Solid; + +use super::{face::FaceApprox, Approx, Tolerance}; + +impl Approx for &Solid { + type Approximation = BTreeSet; + + fn approx(self, tolerance: Tolerance) -> Self::Approximation { + self.shells() + .flat_map(|shell| shell.approx(tolerance)) + .collect() + } +} From 3a49292d9f3ca447f9854095ae583991e783d948 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:57:08 +0200 Subject: [PATCH 05/11] Remove `DebugInfo` from triangulation code It's not very useful in its current state, and it's getting in the way of some changes I need to make. I think re-adding something like it later, as necessary, will be easier than carrying it around the whole time. --- .../src/algorithms/triangulate/mod.rs | 27 ++++++------------- .../src/algorithms/triangulate/polygon.rs | 22 +++++---------- crates/fj-operations/src/shape_processor.rs | 2 +- 3 files changed, 15 insertions(+), 36 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 2355c4c61..a0246967e 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -3,7 +3,7 @@ mod delaunay; mod polygon; -use fj_interop::{debug::DebugInfo, mesh::Mesh}; +use fj_interop::mesh::Mesh; use fj_math::Point; use crate::objects::Face; @@ -15,13 +15,9 @@ use super::approx::{Approx, Tolerance}; /// Triangulate a shape pub trait Triangulate: Sized { /// Triangulate the shape - fn triangulate( - self, - tolerance: impl Into, - debug_info: &mut DebugInfo, - ) -> Mesh> { + fn triangulate(self, tolerance: impl Into) -> Mesh> { let mut mesh = Mesh::new(); - self.triangulate_into_mesh(tolerance, &mut mesh, debug_info); + self.triangulate_into_mesh(tolerance, &mut mesh); mesh } @@ -33,7 +29,6 @@ pub trait Triangulate: Sized { self, tolerance: impl Into, mesh: &mut Mesh>, - debug_info: &mut DebugInfo, ); } @@ -45,12 +40,11 @@ where self, tolerance: impl Into, mesh: &mut Mesh>, - debug_info: &mut DebugInfo, ) { let tolerance = tolerance.into(); for face in self { - face.triangulate_into_mesh(tolerance, mesh, debug_info); + face.triangulate_into_mesh(tolerance, mesh); } } } @@ -60,7 +54,6 @@ impl Triangulate for Face { self, tolerance: impl Into, mesh: &mut Mesh>, - debug_info: &mut DebugInfo, ) { let surface = self.surface(); let approx = self.approx(tolerance.into()); @@ -87,10 +80,8 @@ impl Triangulate for Face { let mut triangles = delaunay::triangulate(points); triangles.retain(|triangle| { - face_as_polygon.contains_triangle( - triangle.map(|point| point.point_surface), - debug_info, - ) + face_as_polygon + .contains_triangle(triangle.map(|point| point.point_surface)) }); for triangle in triangles { @@ -102,7 +93,7 @@ impl Triangulate for Face { #[cfg(test)] mod tests { - use fj_interop::{debug::DebugInfo, mesh::Mesh}; + use fj_interop::mesh::Mesh; use fj_math::{Point, Scalar}; use crate::{ @@ -221,8 +212,6 @@ mod tests { fn triangulate(face: impl Into) -> anyhow::Result>> { let tolerance = Tolerance::from_scalar(Scalar::ONE)?; - - let mut debug_info = DebugInfo::new(); - Ok(vec![face.into()].triangulate(tolerance, &mut debug_info)) + Ok(vec![face.into()].triangulate(tolerance)) } } diff --git a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs index d3043bc12..bf2cc769e 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs @@ -1,4 +1,4 @@ -use fj_interop::debug::{DebugInfo, TriangleEdgeCheck}; +use fj_interop::debug::TriangleEdgeCheck; use fj_math::{Point, PolyChain, Segment}; use crate::{ @@ -65,7 +65,6 @@ impl Polygon { pub fn contains_triangle( &self, triangle: [impl Into>; 3], - debug_info: &mut DebugInfo, ) -> bool { let [a, b, c] = triangle.map(Into::into); @@ -99,7 +98,7 @@ impl Polygon { // polygon edge (and if we reached this point, it isn't), we don't // need to care about the distinction between "inside the polygon" // and "on the polygon boundary". - if !self.contains_point(edge.center(), debug_info) { + if !self.contains_point(edge.center()) { // The segment is outside of the face. This means we can throw // away the whole triangle. return false; @@ -140,11 +139,7 @@ impl Polygon { /// This code is being duplicated by the `Contains>` implementation /// for `Face`. It would be nice to be able to consolidate the duplication, /// but this has turned out to be difficult. - pub fn contains_point( - &self, - point: impl Into>, - debug_info: &mut DebugInfo, - ) -> bool { + pub fn contains_point(&self, point: impl Into>) -> bool { let ray = HorizontalRayToTheRight { origin: point.into(), }; @@ -240,15 +235,12 @@ impl Polygon { } } - debug_info.triangle_edge_checks.push(check); - num_hits % 2 == 1 } } #[cfg(test)] mod tests { - use fj_interop::debug::DebugInfo; use fj_math::{Point, PolyChain}; use crate::objects::Surface; @@ -269,7 +261,7 @@ mod tests { .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())); + assert!(!polygon.contains_triangle([d, e, f])); } #[test] @@ -339,9 +331,7 @@ mod tests { fn assert_contains_point(polygon: Polygon, point: impl Into>) { let point = point.into(); - assert!(polygon.contains_point(point, &mut DebugInfo::new())); - assert!(polygon - .invert_winding() - .contains_point(point, &mut DebugInfo::new())); + assert!(polygon.contains_point(point)); + assert!(polygon.invert_winding().contains_point(point,)); } } diff --git a/crates/fj-operations/src/shape_processor.rs b/crates/fj-operations/src/shape_processor.rs index 77b1b7b97..559d8792f 100644 --- a/crates/fj-operations/src/shape_processor.rs +++ b/crates/fj-operations/src/shape_processor.rs @@ -42,7 +42,7 @@ impl ShapeProcessor { let config = ValidationConfig::default(); let mut debug_info = DebugInfo::new(); let shape = shape.compute_brep(&config, tolerance, &mut debug_info)?; - let mesh = shape.into_inner().triangulate(tolerance, &mut debug_info); + let mesh = shape.into_inner().triangulate(tolerance); Ok(ProcessedShape { aabb, From 6693045f07c38b2dc2ae193b5785f04a8dbb2f2d Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:58:25 +0200 Subject: [PATCH 06/11] Remove outdated implementation note --- .../src/algorithms/triangulate/polygon.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs index bf2cc769e..df7fc95fb 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs @@ -16,20 +16,6 @@ pub struct Polygon { impl Polygon { /// Construct an instance of `Polygon` - /// - /// # Implementation note - /// - /// This method takes a `Surface`, but `Polygon` only uses that for - /// generating debug info. It might be better, if `Polygon` had a field - /// where it stored debug info specific to its algorithm. Then code using - /// `Polygon` could access that `Polygon`-specific debug info and translate - /// that into `DebugInfo`, as necessary. - /// - /// This would have the advantage of removing this dependency on `Surface`. - /// It would also make the test code a bit cleaner, as it wouldn't have to - /// bother with the `DebugInfo` anymore. Also, the `Polygon`-specific debug - /// info could potentially be more useful in test code, as a debugging tool - /// there. pub fn new(surface: Surface) -> Self { Self { surface, From a9d0d77f4e1b17c74610cdb777c78918a3109c26 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 13:00:05 +0200 Subject: [PATCH 07/11] Remove unused code --- .../src/algorithms/triangulate/mod.rs | 3 +- .../src/algorithms/triangulate/polygon.rs | 42 ++++++------------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index a0246967e..1502b8ce2 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -55,7 +55,6 @@ impl Triangulate for Face { tolerance: impl Into, mesh: &mut Mesh>, ) { - let surface = self.surface(); let approx = self.approx(tolerance.into()); let points: Vec<_> = approx @@ -66,7 +65,7 @@ impl Triangulate for Face { point_global: point.global_form, }) .collect(); - let face_as_polygon = Polygon::new(*surface) + let face_as_polygon = Polygon::new() .with_exterior( approx .exterior diff --git a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs index df7fc95fb..21e057c69 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/polygon.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/polygon.rs @@ -1,24 +1,18 @@ -use fj_interop::debug::TriangleEdgeCheck; use fj_math::{Point, PolyChain, Segment}; -use crate::{ - algorithms::intersect::{ - ray_segment::RaySegmentIntersection, HorizontalRayToTheRight, Intersect, - }, - objects::Surface, +use crate::algorithms::intersect::{ + ray_segment::RaySegmentIntersection, HorizontalRayToTheRight, Intersect, }; pub struct Polygon { - surface: Surface, exterior: PolyChain<2>, interiors: Vec>, } impl Polygon { /// Construct an instance of `Polygon` - pub fn new(surface: Surface) -> Self { + pub fn new() -> Self { Self { - surface, exterior: PolyChain::new(), interiors: Vec::new(), } @@ -130,10 +124,6 @@ impl Polygon { origin: point.into(), }; - let mut check = TriangleEdgeCheck::new( - self.surface.point_from_surface_coords(ray.origin), - ); - let mut num_hits = 0; for chain in Some(&self.exterior).into_iter().chain(&self.interiors) { @@ -209,12 +199,6 @@ impl Polygon { if count_hit { num_hits += 1; - - let edge = - Segment::from_points(edge.points().map(|point| { - self.surface.point_from_surface_coords(point) - })); - check.hits.push(edge); } previous_hit = hit; @@ -229,8 +213,6 @@ impl Polygon { mod tests { use fj_math::{Point, PolyChain}; - use crate::objects::Surface; - use super::Polygon; #[test] @@ -243,7 +225,7 @@ mod tests { let e = [2., 1.]; let f = [1., 2.]; - let polygon = Polygon::new(Surface::xy_plane()) + let polygon = Polygon::new() .with_exterior(PolyChain::from([a, b, c]).close()) .with_interiors([PolyChain::from([d, e, f]).close()]); @@ -256,8 +238,8 @@ mod tests { let b = [2., 1.]; let c = [0., 2.]; - let polygon = Polygon::new(Surface::xy_plane()) - .with_exterior(PolyChain::from([a, b, c]).close()); + let polygon = + Polygon::new().with_exterior(PolyChain::from([a, b, c]).close()); assert_contains_point(polygon, [1., 1.]); } @@ -272,7 +254,7 @@ mod tests { let e = [2., 1.]; let f = [1., 3.]; - let polygon = Polygon::new(Surface::xy_plane()) + let polygon = Polygon::new() .with_exterior(PolyChain::from([a, b, c]).close()) .with_interiors([PolyChain::from([d, e, f]).close()]); @@ -286,8 +268,8 @@ mod tests { let c = [3., 0.]; let d = [3., 4.]; - let polygon = Polygon::new(Surface::xy_plane()) - .with_exterior(PolyChain::from([a, b, c, d]).close()); + let polygon = + Polygon::new().with_exterior(PolyChain::from([a, b, c, d]).close()); assert_contains_point(polygon, [1., 1.]); } @@ -299,8 +281,8 @@ mod tests { let b = [2., 1.]; let c = [3., 1.]; let d = [0., 2.]; - let polygon = Polygon::new(Surface::xy_plane()) - .with_exterior(PolyChain::from([a, b, c, d]).close()); + let polygon = + Polygon::new().with_exterior(PolyChain::from([a, b, c, d]).close()); assert_contains_point(polygon, [1., 1.]); // Ray hits a vertex, but doesn't pass polygon boundary there. @@ -309,7 +291,7 @@ mod tests { let c = [3., 1.]; let d = [4., 0.]; let e = [4., 5.]; - let polygon = Polygon::new(Surface::xy_plane()) + let polygon = Polygon::new() .with_exterior(PolyChain::from([a, b, c, d, e]).close()); assert_contains_point(polygon, [1., 1.]); } From e2bf613cec25619733b57470cdda32853a733933 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 13:08:43 +0200 Subject: [PATCH 08/11] Implement `Triangulate` for `FaceApprox` Instead of `Face` itself. This decouples the approximation from the triangulation, and provides the caller with more flexibility. --- .../src/algorithms/triangulate/mod.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 1502b8ce2..d273f728b 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -10,7 +10,7 @@ use crate::objects::Face; use self::{delaunay::TriangulationPoint, polygon::Polygon}; -use super::approx::{Approx, Tolerance}; +use super::approx::{face::FaceApprox, Approx, Tolerance}; /// Triangulate a shape pub trait Triangulate: Sized { @@ -44,20 +44,19 @@ where let tolerance = tolerance.into(); for face in self { - face.triangulate_into_mesh(tolerance, mesh); + let approx = face.approx(tolerance); + approx.triangulate_into_mesh(tolerance, mesh); } } } -impl Triangulate for Face { +impl Triangulate for FaceApprox { fn triangulate_into_mesh( self, - tolerance: impl Into, + _: impl Into, mesh: &mut Mesh>, ) { - let approx = self.approx(tolerance.into()); - - let points: Vec<_> = approx + let points: Vec<_> = self .points() .into_iter() .map(|point| TriangulationPoint { @@ -67,13 +66,12 @@ impl Triangulate for Face { .collect(); let face_as_polygon = Polygon::new() .with_exterior( - approx - .exterior + self.exterior .points() .into_iter() .map(|point| point.local_form), ) - .with_interiors(approx.interiors.into_iter().map(|interior| { + .with_interiors(self.interiors.into_iter().map(|interior| { interior.points().into_iter().map(|point| point.local_form) })); @@ -85,7 +83,7 @@ impl Triangulate for Face { for triangle in triangles { let points = triangle.map(|point| point.point_global); - mesh.push_triangle(points, self.color()); + mesh.push_triangle(points, self.color); } } } From 50960183636451c7d715f245c02ce7b2b61d0049 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 13:12:04 +0200 Subject: [PATCH 09/11] Refactor --- crates/fj-kernel/src/algorithms/triangulate/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index d273f728b..9a81c0030 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -94,7 +94,7 @@ mod tests { use fj_math::{Point, Scalar}; use crate::{ - algorithms::approx::Tolerance, + algorithms::approx::{Approx, Tolerance}, objects::{Face, Surface}, }; @@ -209,6 +209,6 @@ mod tests { fn triangulate(face: impl Into) -> anyhow::Result>> { let tolerance = Tolerance::from_scalar(Scalar::ONE)?; - Ok(vec![face.into()].triangulate(tolerance)) + Ok(face.into().approx(tolerance).triangulate(tolerance)) } } From c1761b54e8e7140c5542461ee9af94c387a53b44 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 13:12:39 +0200 Subject: [PATCH 10/11] Broaden `Triangulate` implementation Implement it for everything that approximates into faces. --- crates/fj-kernel/src/algorithms/triangulate/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 9a81c0030..67dc3eafc 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -6,8 +6,6 @@ mod polygon; use fj_interop::mesh::Mesh; use fj_math::Point; -use crate::objects::Face; - use self::{delaunay::TriangulationPoint, polygon::Polygon}; use super::approx::{face::FaceApprox, Approx, Tolerance}; @@ -34,7 +32,8 @@ pub trait Triangulate: Sized { impl Triangulate for T where - T: IntoIterator, + T: Approx, + T::Approximation: IntoIterator, { fn triangulate_into_mesh( self, @@ -42,9 +41,9 @@ where mesh: &mut Mesh>, ) { let tolerance = tolerance.into(); + let approx = self.approx(tolerance); - for face in self { - let approx = face.approx(tolerance); + for approx in approx { approx.triangulate_into_mesh(tolerance, mesh); } } From f28c7c08481a3ee09308572c5601e034f9ebbb45 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 14:22:27 +0200 Subject: [PATCH 11/11] Add validation code to `Faces` approximation --- .../fj-kernel/src/algorithms/approx/face.rs | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index ee0babe22..30b902a62 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -6,7 +6,10 @@ use std::collections::BTreeSet; use fj_interop::mesh::Color; -use crate::objects::{Face, Faces}; +use crate::{ + algorithms::validate::ValidationConfig, + objects::{Face, Faces}, +}; use super::{cycle::CycleApprox, Approx, ApproxPoint, Tolerance}; @@ -14,9 +17,44 @@ impl Approx for &Faces { type Approximation = BTreeSet; fn approx(self, tolerance: Tolerance) -> Self::Approximation { - self.into_iter() + let approx = self + .into_iter() .map(|face| face.approx(tolerance)) - .collect() + .collect(); + + let min_distance = ValidationConfig::default().distinct_min_distance; + let mut all_points: BTreeSet> = BTreeSet::new(); + + for approx in &approx { + let approx: &FaceApprox = approx; + + for point in &approx.points() { + for p in &all_points { + let distance = + (p.global_form - point.global_form).magnitude(); + + if p.global_form != point.global_form + && distance < min_distance + { + let a = p; + let b = point; + + panic!( + "Invalid approximation: \ + Distinct points are too close \ + (a: {:?}, b: {:?}, distance: {distance})\n\ + source of `a`: {:#?}\n\ + source of `b`: {:#?}\n", + a.global_form, b.global_form, a.source, b.source + ); + } + } + + all_points.insert(point.clone()); + } + } + + approx } }