From dae666a711507502570e09b02aee97d21402d832 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:11:52 +0200 Subject: [PATCH 01/18] Derive `Ord` for `CycleApprox` --- crates/fj-kernel/src/algorithms/approx/cycle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index 29f2ea94b..82c0b0932 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -28,7 +28,7 @@ impl Approx for &Cycle { } /// An approximation of a [`Cycle`] -#[derive(Debug, Eq, PartialEq, Hash)] +#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct CycleApprox { /// The points that approximate the cycle pub points: Vec<(Point<2>, Point<3>)>, From 9908138927037ae35bd645b09e2de5a22303c473 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:13:40 +0200 Subject: [PATCH 02/18] Prepare `FaceApprox` for implementing `Ord` --- crates/fj-kernel/src/algorithms/approx/face.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index 55b7b0586..66c4c809e 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -2,7 +2,7 @@ //! //! See [`FaceApprox`]. -use std::collections::HashSet; +use std::collections::BTreeSet; use fj_math::Point; @@ -27,9 +27,9 @@ impl Approx for &Face { // would need to provide its own approximation, as the edges that bound // it have nothing to do with its curvature. - let mut points = HashSet::new(); + let mut points = BTreeSet::new(); let mut exteriors = Vec::new(); - let mut interiors = HashSet::new(); + let mut interiors = BTreeSet::new(); for cycle in self.exteriors() { let cycle = cycle.approx(tolerance); @@ -71,19 +71,19 @@ pub struct FaceApprox { /// /// These could be actual vertices from the model, points that approximate /// an edge, or points that approximate a face. - pub points: HashSet<(Point<2>, Point<3>)>, + pub points: BTreeSet<(Point<2>, Point<3>)>, /// Approximation of the exterior cycle pub exterior: CycleApprox, /// Approximations of the interior cycles - pub interiors: HashSet, + pub interiors: BTreeSet, } #[cfg(test)] mod tests { use fj_math::{Point, Scalar}; - use map_macro::set; + use map_macro::btree_set; use crate::{ algorithms::approx::Approx, @@ -124,11 +124,11 @@ mod tests { let approx = face.approx(tolerance); let expected = FaceApprox { - points: set![a, b, c, d, e, f, g, h], + points: btree_set![a, b, c, d, e, f, g, h], exterior: CycleApprox { points: vec![a, b, c, d, a], }, - interiors: set![CycleApprox { + interiors: btree_set![CycleApprox { points: vec![e, f, g, h, e], }], }; From 6b2e9c83f3562f470747b157c453b3948cb2a401 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 12:14:20 +0200 Subject: [PATCH 03/18] Derive `Ord` for `FaceApprox` --- crates/fj-kernel/src/algorithms/approx/face.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index 66c4c809e..e4ce0575f 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -65,7 +65,7 @@ impl Approx for &Face { } /// An approximation of a [`Face`] -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct FaceApprox { /// All points that make up the approximation /// From 8001cf2525720fe3c25e0a729148eb042c0be420 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 13:07:31 +0200 Subject: [PATCH 04/18] Add `color` field to `FaceApprox` --- crates/fj-kernel/src/algorithms/approx/face.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index e4ce0575f..ecb94071f 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -4,6 +4,7 @@ use std::collections::BTreeSet; +use fj_interop::mesh::Color; use fj_math::Point; use crate::objects::Face; @@ -60,6 +61,7 @@ impl Approx for &Face { points, exterior, interiors, + color: self.color(), } } } @@ -78,10 +80,14 @@ pub struct FaceApprox { /// Approximations of the interior cycles pub interiors: BTreeSet, + + /// The color of the approximated face + pub color: Color, } #[cfg(test)] mod tests { + use fj_interop::mesh::Color; use fj_math::{Point, Scalar}; use map_macro::btree_set; @@ -131,6 +137,7 @@ mod tests { interiors: btree_set![CycleApprox { points: vec![e, f, g, h, e], }], + color: Color::default(), }; assert_eq!(approx, expected); From 7a0b61a0b23dd8e48c103a535867c33f5cd75f43 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 14:39:21 +0200 Subject: [PATCH 05/18] Add `EdgeApprox` --- crates/fj-kernel/src/algorithms/approx/cycle.rs | 4 ++-- crates/fj-kernel/src/algorithms/approx/edge.rs | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index 82c0b0932..1167a2387 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -15,8 +15,8 @@ impl Approx for &Cycle { let mut points = Vec::new(); for edge in self.edges() { - let edge_points = edge.approx(tolerance); - points.extend(edge_points); + let approx = edge.approx(tolerance); + points.extend(approx.points); } if let Some(&point) = points.first() { diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 3cefdc3fc..92d8ee8ef 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -12,7 +12,7 @@ use crate::objects::{Edge, GlobalVertex, SurfaceVertex, Vertex}; use super::{curve::RangeOnCurve, Approx}; impl Approx for &Edge { - type Approximation = Vec<(Point<2>, Point<3>)>; + type Approximation = EdgeApprox; fn approx(self, tolerance: super::Tolerance) -> Self::Approximation { // The range is only used for circles right now. @@ -80,6 +80,13 @@ impl Approx for &Edge { ), ); - points + EdgeApprox { points } } } + +/// An approximation of an [`Edge`] +#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct EdgeApprox { + /// The points that approximate the [`Edge`] + pub points: Vec<(Point<2>, Point<3>)>, +} From 774c2324102dea0e9966a2e13574a0e06b82bbda Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 14:40:58 +0200 Subject: [PATCH 06/18] Remove unit test I have to update it all the time, which is tedious, and it's nowhere near the actually complicated code that would benefit from testing. If problems crop up, we can add back approximation tests, but for now, I think it's more important to have a clear path for the cleanups I'm working on. --- .../fj-kernel/src/algorithms/approx/face.rs | 61 ------------------- 1 file changed, 61 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index ecb94071f..0b2cbcb22 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -84,64 +84,3 @@ pub struct FaceApprox { /// The color of the approximated face pub color: Color, } - -#[cfg(test)] -mod tests { - use fj_interop::mesh::Color; - use fj_math::{Point, Scalar}; - use map_macro::btree_set; - - use crate::{ - algorithms::approx::Approx, - objects::{Face, Surface}, - }; - - use super::{CycleApprox, FaceApprox, Tolerance}; - - #[test] - fn for_face_closed() -> anyhow::Result<()> { - // Test a closed face, i.e. one that is completely encircled by edges. - - let tolerance = Tolerance::from_scalar(Scalar::ONE)?; - - let a = Point::from([0., 0.]); - let b = Point::from([3., 0.]); - let c = Point::from([3., 3.]); - let d = Point::from([0., 3.]); - - let e = Point::from([1., 1.]); - let f = Point::from([2., 1.]); - let g = Point::from([2., 2.]); - let h = Point::from([1., 2.]); - - let surface = Surface::xy_plane(); - let face = Face::build(surface) - .polygon_from_points([a, b, c, d]) - .with_hole([e, f, g, h]); - - let a = (a, a.to_xyz()); - let b = (b, b.to_xyz()); - let c = (c, c.to_xyz()); - let d = (d, d.to_xyz()); - let e = (e, e.to_xyz()); - let f = (f, f.to_xyz()); - let g = (g, g.to_xyz()); - let h = (h, h.to_xyz()); - - let approx = face.approx(tolerance); - let expected = FaceApprox { - points: btree_set![a, b, c, d, e, f, g, h], - exterior: CycleApprox { - points: vec![a, b, c, d, a], - }, - interiors: btree_set![CycleApprox { - points: vec![e, f, g, h, e], - }], - color: Color::default(), - }; - - assert_eq!(approx, expected); - - Ok(()) - } -} From 102cb3e29ba85896a815ead35d2cf14e7016dd39 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 14:50:50 +0200 Subject: [PATCH 07/18] Add `CycleApprox::points` --- crates/fj-kernel/src/algorithms/approx/cycle.rs | 7 ++++++- crates/fj-kernel/src/algorithms/approx/face.rs | 4 ++-- crates/fj-kernel/src/algorithms/triangulate/mod.rs | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index 1167a2387..57d17497f 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -35,11 +35,16 @@ pub struct CycleApprox { } impl CycleApprox { + /// Compute the points that approximate the cycle + pub fn points(&self) -> Vec<(Point<2>, Point<3>)> { + self.points.clone() + } + /// Construct the segments that approximate the cycle pub fn segments(&self) -> Vec> { let mut segments = Vec::new(); - for segment in self.points.windows(2) { + for segment in self.points().windows(2) { // This can't panic, as we passed `2` to `windows`. Can be cleaned // up, once `array_windows` is stable. let segment = [segment[0], segment[1]]; diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index 0b2cbcb22..a78074e8a 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -35,13 +35,13 @@ impl Approx for &Face { for cycle in self.exteriors() { let cycle = cycle.approx(tolerance); - points.extend(cycle.points.iter().copied()); + points.extend(cycle.points()); exteriors.push(cycle); } for cycle in self.interiors() { let cycle = cycle.approx(tolerance); - points.extend(cycle.points.iter().copied()); + points.extend(cycle.points()); interiors.insert(cycle); } diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 1d69b84ec..9095f0e56 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -84,13 +84,13 @@ impl Triangulate for Face { .with_exterior( approx .exterior - .points + .points() .into_iter() .map(|(point_surface, _)| point_surface), ) .with_interiors(approx.interiors.into_iter().map(|interior| { interior - .points + .points() .into_iter() .map(|(point_surface, _)| point_surface) })); From 8e9ff0bbf044203b2ec125aeb7be8eb750b815c9 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 14:52:10 +0200 Subject: [PATCH 08/18] Refactor --- crates/fj-kernel/src/algorithms/approx/cycle.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index 57d17497f..a6612d17e 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -19,10 +19,6 @@ impl Approx for &Cycle { points.extend(approx.points); } - if let Some(&point) = points.first() { - points.push(point); - } - CycleApprox { points } } } @@ -37,7 +33,13 @@ pub struct CycleApprox { impl CycleApprox { /// Compute the points that approximate the cycle pub fn points(&self) -> Vec<(Point<2>, Point<3>)> { - self.points.clone() + let mut points = self.points.clone(); + + if let Some(&point) = points.first() { + points.push(point); + } + + points } /// Construct the segments that approximate the cycle From 855e4cd521a23b57d9ca87f67c6db4c9cd448621 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 14:55:45 +0200 Subject: [PATCH 09/18] Re-use `EdgeApprox` in `CycleApprox` --- .../fj-kernel/src/algorithms/approx/cycle.rs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index a6612d17e..53a61cfd4 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -6,34 +6,32 @@ use fj_math::{Point, Segment}; use crate::objects::Cycle; -use super::{Approx, Tolerance}; +use super::{edge::EdgeApprox, Approx, Tolerance}; impl Approx for &Cycle { type Approximation = CycleApprox; fn approx(self, tolerance: Tolerance) -> Self::Approximation { - let mut points = Vec::new(); - - for edge in self.edges() { - let approx = edge.approx(tolerance); - points.extend(approx.points); - } - - CycleApprox { points } + let edges = self.edges().map(|edge| edge.approx(tolerance)).collect(); + CycleApprox { edges } } } /// An approximation of a [`Cycle`] #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct CycleApprox { - /// The points that approximate the cycle - pub points: Vec<(Point<2>, Point<3>)>, + /// The approximated edges that make up the approximated cycle + pub edges: Vec, } impl CycleApprox { /// Compute the points that approximate the cycle pub fn points(&self) -> Vec<(Point<2>, Point<3>)> { - let mut points = self.points.clone(); + let mut points = Vec::new(); + + for edge_approx in &self.edges { + points.extend(edge_approx.points.iter().copied()); + } if let Some(&point) = points.first() { points.push(point); From c75cf1fdfed2c858104362bf2fb72ae476595037 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 15:00:02 +0200 Subject: [PATCH 10/18] Add `EdgeApprox::points` --- crates/fj-kernel/src/algorithms/approx/cycle.rs | 2 +- crates/fj-kernel/src/algorithms/approx/edge.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index 53a61cfd4..da0de64e7 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -30,7 +30,7 @@ impl CycleApprox { let mut points = Vec::new(); for edge_approx in &self.edges { - points.extend(edge_approx.points.iter().copied()); + points.extend(edge_approx.points()); } if let Some(&point) = points.first() { diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 92d8ee8ef..f7e72bcc7 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -90,3 +90,10 @@ pub struct EdgeApprox { /// The points that approximate the [`Edge`] pub points: Vec<(Point<2>, Point<3>)>, } + +impl EdgeApprox { + /// Compute the points that approximate the edge + pub fn points(&self) -> Vec<(Point<2>, Point<3>)> { + self.points.clone() + } +} From 936ee9cae50060c5169c6bfd193b093cbca222b0 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 15:09:25 +0200 Subject: [PATCH 11/18] Add `CurveApprox` --- crates/fj-kernel/src/algorithms/approx/curve.rs | 15 ++++++++++++--- crates/fj-kernel/src/algorithms/approx/edge.rs | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index 9610e278d..c05efe89a 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -18,12 +18,12 @@ use crate::objects::{Curve, CurveKind, GlobalCurve, Vertex}; use super::{Approx, Tolerance}; impl Approx for (&Curve, RangeOnCurve) { - type Approximation = Vec<(Point<2>, Point<3>)>; + type Approximation = CurveApprox; fn approx(self, tolerance: Tolerance) -> Self::Approximation { let (curve, range) = self; - (curve.global_form(), range) + let points = (curve.global_form(), range) .approx(tolerance) .into_iter() .map(|(point_curve, point_global)| { @@ -31,7 +31,9 @@ impl Approx for (&Curve, RangeOnCurve) { curve.kind().point_from_curve_coords(point_curve); (point_surface, point_global) }) - .collect() + .collect(); + + CurveApprox { points } } } @@ -137,6 +139,13 @@ impl RangeOnCurve { } } +/// An approximation of a [`Curve`] +#[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct CurveApprox { + /// The points that approximate the curve + pub points: Vec<(Point<2>, Point<3>)>, +} + #[cfg(test)] mod tests { use fj_math::Scalar; diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index f7e72bcc7..9c6dde65a 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -71,7 +71,7 @@ impl Approx for &Edge { let range = RangeOnCurve { boundary }; - let mut points = (self.curve(), range).approx(tolerance); + let mut points = (self.curve(), range).approx(tolerance).points; points.insert( 0, ( From cfab8750be47e87e9700f9f19d1dae5d4176dce7 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 15:12:12 +0200 Subject: [PATCH 12/18] Refactor --- .../fj-kernel/src/algorithms/approx/edge.rs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 9c6dde65a..36792c917 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -71,22 +71,22 @@ impl Approx for &Edge { let range = RangeOnCurve { boundary }; - let mut points = (self.curve(), range).approx(tolerance).points; - points.insert( - 0, - ( - range.start().surface_form().position(), - range.start().global_form().position(), - ), + let first = ( + range.start().surface_form().position(), + range.start().global_form().position(), ); + let points = (self.curve(), range).approx(tolerance).points; - EdgeApprox { points } + EdgeApprox { first, points } } } /// An approximation of an [`Edge`] #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct EdgeApprox { + /// The point that approximates the first vertex of the curve + pub first: (Point<2>, Point<3>), + /// The points that approximate the [`Edge`] pub points: Vec<(Point<2>, Point<3>)>, } @@ -94,6 +94,11 @@ pub struct EdgeApprox { impl EdgeApprox { /// Compute the points that approximate the edge pub fn points(&self) -> Vec<(Point<2>, Point<3>)> { - self.points.clone() + let mut points = Vec::new(); + + points.push(self.first); + points.extend(self.points.clone()); + + points } } From 50566fa0436ab2df8ef3b37c374d469e0b53b118 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 15:13:29 +0200 Subject: [PATCH 13/18] Make use of `CurveApprox` in `EdgeApprox` --- crates/fj-kernel/src/algorithms/approx/edge.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 36792c917..eb9ecd2d9 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -9,7 +9,10 @@ use fj_math::{Point, Scalar}; use crate::objects::{Edge, GlobalVertex, SurfaceVertex, Vertex}; -use super::{curve::RangeOnCurve, Approx}; +use super::{ + curve::{CurveApprox, RangeOnCurve}, + Approx, +}; impl Approx for &Edge { type Approximation = EdgeApprox; @@ -75,9 +78,12 @@ impl Approx for &Edge { range.start().surface_form().position(), range.start().global_form().position(), ); - let points = (self.curve(), range).approx(tolerance).points; + let curve_approx = (self.curve(), range).approx(tolerance); - EdgeApprox { first, points } + EdgeApprox { + first, + curve_approx, + } } } @@ -87,8 +93,8 @@ pub struct EdgeApprox { /// The point that approximates the first vertex of the curve pub first: (Point<2>, Point<3>), - /// The points that approximate the [`Edge`] - pub points: Vec<(Point<2>, Point<3>)>, + /// The approximation of the edge's curve + pub curve_approx: CurveApprox, } impl EdgeApprox { @@ -97,7 +103,7 @@ impl EdgeApprox { let mut points = Vec::new(); points.push(self.first); - points.extend(self.points.clone()); + points.extend(self.curve_approx.points.clone()); points } From 0273ced347aba47ea190cbe58d329c74879e6e5b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 15:19:49 +0200 Subject: [PATCH 14/18] Add `FaceApprox::points` --- crates/fj-kernel/src/algorithms/approx/face.rs | 7 +++++++ crates/fj-kernel/src/algorithms/triangulate/mod.rs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index a78074e8a..1ac6b458e 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -84,3 +84,10 @@ pub struct FaceApprox { /// The color of the approximated face pub color: Color, } + +impl FaceApprox { + /// Compute all points that make up the approximation + pub fn points(&self) -> BTreeSet<(Point<2>, Point<3>)> { + self.points.clone() + } +} diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 9095f0e56..385a25f11 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -73,7 +73,7 @@ impl Triangulate for Face { let approx = self.approx(tolerance.into()); let points: Vec<_> = approx - .points + .points() .into_iter() .map(|(point_surface, point_global)| TriangulationPoint { point_surface, From 9a6301db78412c24edd302ff0cfcdfa0bd56185b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 15:21:45 +0200 Subject: [PATCH 15/18] Refactor --- .../fj-kernel/src/algorithms/approx/face.rs | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index 1ac6b458e..ccf870623 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -28,20 +28,15 @@ impl Approx for &Face { // would need to provide its own approximation, as the edges that bound // it have nothing to do with its curvature. - let mut points = BTreeSet::new(); let mut exteriors = Vec::new(); let mut interiors = BTreeSet::new(); for cycle in self.exteriors() { let cycle = cycle.approx(tolerance); - - points.extend(cycle.points()); exteriors.push(cycle); } for cycle in self.interiors() { let cycle = cycle.approx(tolerance); - - points.extend(cycle.points()); interiors.insert(cycle); } @@ -58,7 +53,6 @@ impl Approx for &Face { ); FaceApprox { - points, exterior, interiors, color: self.color(), @@ -69,12 +63,6 @@ impl Approx for &Face { /// An approximation of a [`Face`] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct FaceApprox { - /// All points that make up the approximation - /// - /// These could be actual vertices from the model, points that approximate - /// an edge, or points that approximate a face. - pub points: BTreeSet<(Point<2>, Point<3>)>, - /// Approximation of the exterior cycle pub exterior: CycleApprox, @@ -88,6 +76,14 @@ pub struct FaceApprox { impl FaceApprox { /// Compute all points that make up the approximation pub fn points(&self) -> BTreeSet<(Point<2>, Point<3>)> { - self.points.clone() + let mut points = BTreeSet::new(); + + points.extend(self.exterior.points()); + + for cycle_approx in &self.interiors { + points.extend(cycle_approx.points()); + } + + points } } From ed9a303dd29ecc8791e70c776919e72dfe5b150c Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 15:31:16 +0200 Subject: [PATCH 16/18] Add `ApproxPoint` --- .../fj-kernel/src/algorithms/approx/curve.rs | 22 ++++++++++++------- .../fj-kernel/src/algorithms/approx/cycle.rs | 18 +++++++-------- .../fj-kernel/src/algorithms/approx/edge.rs | 16 +++++++------- .../fj-kernel/src/algorithms/approx/face.rs | 5 ++--- crates/fj-kernel/src/algorithms/approx/mod.rs | 12 ++++++++++ .../src/algorithms/triangulate/mod.rs | 13 +++++------ 6 files changed, 49 insertions(+), 37 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index c05efe89a..bfeabd54a 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -15,7 +15,7 @@ use fj_math::{Circle, Point, Scalar}; use crate::objects::{Curve, CurveKind, GlobalCurve, Vertex}; -use super::{Approx, Tolerance}; +use super::{Approx, ApproxPoint, Tolerance}; impl Approx for (&Curve, RangeOnCurve) { type Approximation = CurveApprox; @@ -26,10 +26,13 @@ impl Approx for (&Curve, RangeOnCurve) { let points = (curve.global_form(), range) .approx(tolerance) .into_iter() - .map(|(point_curve, point_global)| { + .map(|point| { let point_surface = - curve.kind().point_from_curve_coords(point_curve); - (point_surface, point_global) + curve.kind().point_from_curve_coords(point.local_form); + ApproxPoint { + local_form: point_surface, + global_form: point.global_form, + } }) .collect(); @@ -38,7 +41,7 @@ impl Approx for (&Curve, RangeOnCurve) { } impl Approx for (&GlobalCurve, RangeOnCurve) { - type Approximation = Vec<(Point<1>, Point<3>)>; + type Approximation = Vec>; fn approx(self, tolerance: Tolerance) -> Self::Approximation { let (curve, range) = self; @@ -64,7 +67,7 @@ fn approx_circle( circle: &Circle<3>, range: impl Into, tolerance: Tolerance, - points: &mut Vec<(Point<1>, Point<3>)>, + points: &mut Vec>, ) { let radius = circle.a().magnitude(); let range = range.into(); @@ -84,7 +87,10 @@ fn approx_circle( let point_curve = Point::from([angle]); let point_global = circle.point_from_circle_coords(point_curve); - points.push((point_curve, point_global)); + points.push(ApproxPoint { + local_form: point_curve, + global_form: point_global, + }); } } @@ -143,7 +149,7 @@ impl RangeOnCurve { #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct CurveApprox { /// The points that approximate the curve - pub points: Vec<(Point<2>, Point<3>)>, + pub points: Vec>, } #[cfg(test)] diff --git a/crates/fj-kernel/src/algorithms/approx/cycle.rs b/crates/fj-kernel/src/algorithms/approx/cycle.rs index da0de64e7..9610202d7 100644 --- a/crates/fj-kernel/src/algorithms/approx/cycle.rs +++ b/crates/fj-kernel/src/algorithms/approx/cycle.rs @@ -2,11 +2,11 @@ //! //! See [`CycleApprox`]. -use fj_math::{Point, Segment}; +use fj_math::Segment; use crate::objects::Cycle; -use super::{edge::EdgeApprox, Approx, Tolerance}; +use super::{edge::EdgeApprox, Approx, ApproxPoint, Tolerance}; impl Approx for &Cycle { type Approximation = CycleApprox; @@ -26,15 +26,15 @@ pub struct CycleApprox { impl CycleApprox { /// Compute the points that approximate the cycle - pub fn points(&self) -> Vec<(Point<2>, Point<3>)> { + pub fn points(&self) -> Vec> { let mut points = Vec::new(); for edge_approx in &self.edges { points.extend(edge_approx.points()); } - if let Some(&point) = points.first() { - points.push(point); + if let Some(point) = points.first() { + points.push(point.clone()); } points @@ -47,12 +47,10 @@ impl CycleApprox { for segment in self.points().windows(2) { // This can't panic, as we passed `2` to `windows`. Can be cleaned // up, once `array_windows` is stable. - let segment = [segment[0], segment[1]]; + let segment = [&segment[0], &segment[1]]; - segments.push(Segment::from(segment.map(|point| { - let (_, point_global) = point; - point_global - }))); + segments + .push(Segment::from(segment.map(|point| point.global_form))); } segments diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index eb9ecd2d9..16c7c4faa 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -11,7 +11,7 @@ use crate::objects::{Edge, GlobalVertex, SurfaceVertex, Vertex}; use super::{ curve::{CurveApprox, RangeOnCurve}, - Approx, + Approx, ApproxPoint, }; impl Approx for &Edge { @@ -74,10 +74,10 @@ impl Approx for &Edge { let range = RangeOnCurve { boundary }; - let first = ( - range.start().surface_form().position(), - range.start().global_form().position(), - ); + let first = ApproxPoint { + local_form: range.start().surface_form().position(), + global_form: range.start().global_form().position(), + }; let curve_approx = (self.curve(), range).approx(tolerance); EdgeApprox { @@ -91,7 +91,7 @@ impl Approx for &Edge { #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct EdgeApprox { /// The point that approximates the first vertex of the curve - pub first: (Point<2>, Point<3>), + pub first: ApproxPoint<2>, /// The approximation of the edge's curve pub curve_approx: CurveApprox, @@ -99,10 +99,10 @@ pub struct EdgeApprox { impl EdgeApprox { /// Compute the points that approximate the edge - pub fn points(&self) -> Vec<(Point<2>, Point<3>)> { + pub fn points(&self) -> Vec> { let mut points = Vec::new(); - points.push(self.first); + points.push(self.first.clone()); points.extend(self.curve_approx.points.clone()); points diff --git a/crates/fj-kernel/src/algorithms/approx/face.rs b/crates/fj-kernel/src/algorithms/approx/face.rs index ccf870623..d3f9819e1 100644 --- a/crates/fj-kernel/src/algorithms/approx/face.rs +++ b/crates/fj-kernel/src/algorithms/approx/face.rs @@ -5,11 +5,10 @@ use std::collections::BTreeSet; use fj_interop::mesh::Color; -use fj_math::Point; use crate::objects::Face; -use super::{cycle::CycleApprox, Approx, Tolerance}; +use super::{cycle::CycleApprox, Approx, ApproxPoint, Tolerance}; impl Approx for &Face { type Approximation = FaceApprox; @@ -75,7 +74,7 @@ pub struct FaceApprox { impl FaceApprox { /// Compute all points that make up the approximation - pub fn points(&self) -> BTreeSet<(Point<2>, Point<3>)> { + pub fn points(&self) -> BTreeSet> { let mut points = BTreeSet::new(); points.extend(self.exterior.points()); diff --git a/crates/fj-kernel/src/algorithms/approx/mod.rs b/crates/fj-kernel/src/algorithms/approx/mod.rs index cf17774af..dcc4f0c17 100644 --- a/crates/fj-kernel/src/algorithms/approx/mod.rs +++ b/crates/fj-kernel/src/algorithms/approx/mod.rs @@ -6,6 +6,8 @@ pub mod edge; pub mod face; pub mod tolerance; +use fj_math::Point; + pub use self::tolerance::{InvalidTolerance, Tolerance}; /// Approximate an object @@ -19,3 +21,13 @@ pub trait Approx { /// the actual object. fn approx(self, tolerance: Tolerance) -> Self::Approximation; } + +/// A point from an approximation, with local and global forms +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct ApproxPoint { + /// The local form of the point + pub local_form: Point, + + /// The global form of the points + pub global_form: Point<3>, +} diff --git a/crates/fj-kernel/src/algorithms/triangulate/mod.rs b/crates/fj-kernel/src/algorithms/triangulate/mod.rs index 385a25f11..7927b9711 100644 --- a/crates/fj-kernel/src/algorithms/triangulate/mod.rs +++ b/crates/fj-kernel/src/algorithms/triangulate/mod.rs @@ -75,9 +75,9 @@ impl Triangulate for Face { let points: Vec<_> = approx .points() .into_iter() - .map(|(point_surface, point_global)| TriangulationPoint { - point_surface, - point_global, + .map(|point| TriangulationPoint { + point_surface: point.local_form, + point_global: point.global_form, }) .collect(); let face_as_polygon = Polygon::new(*surface) @@ -86,13 +86,10 @@ impl Triangulate for Face { .exterior .points() .into_iter() - .map(|(point_surface, _)| point_surface), + .map(|point| point.local_form), ) .with_interiors(approx.interiors.into_iter().map(|interior| { - interior - .points() - .into_iter() - .map(|(point_surface, _)| point_surface) + interior.points().into_iter().map(|point| point.local_form) })); let mut triangles = delaunay::triangulate(points); From fc7ecbb28b33b14c35658f8110e28b4e8d8c4a8b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 16:10:32 +0200 Subject: [PATCH 17/18] Add an optional source to `ApproxPoint` --- .../fj-kernel/src/algorithms/approx/curve.rs | 10 +--- .../fj-kernel/src/algorithms/approx/edge.rs | 8 +-- crates/fj-kernel/src/algorithms/approx/mod.rs | 59 ++++++++++++++++++- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index bfeabd54a..a5e186577 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -29,10 +29,7 @@ impl Approx for (&Curve, RangeOnCurve) { .map(|point| { let point_surface = curve.kind().point_from_curve_coords(point.local_form); - ApproxPoint { - local_form: point_surface, - global_form: point.global_form, - } + ApproxPoint::new(point_surface, point.global_form) }) .collect(); @@ -87,10 +84,7 @@ fn approx_circle( let point_curve = Point::from([angle]); let point_global = circle.point_from_circle_coords(point_curve); - points.push(ApproxPoint { - local_form: point_curve, - global_form: point_global, - }); + points.push(ApproxPoint::new(point_curve, point_global)); } } diff --git a/crates/fj-kernel/src/algorithms/approx/edge.rs b/crates/fj-kernel/src/algorithms/approx/edge.rs index 16c7c4faa..e5de04683 100644 --- a/crates/fj-kernel/src/algorithms/approx/edge.rs +++ b/crates/fj-kernel/src/algorithms/approx/edge.rs @@ -74,10 +74,10 @@ impl Approx for &Edge { let range = RangeOnCurve { boundary }; - let first = ApproxPoint { - local_form: range.start().surface_form().position(), - global_form: range.start().global_form().position(), - }; + let first = ApproxPoint::new( + range.start().surface_form().position(), + range.start().global_form().position(), + ); let curve_approx = (self.curve(), range).approx(tolerance); EdgeApprox { diff --git a/crates/fj-kernel/src/algorithms/approx/mod.rs b/crates/fj-kernel/src/algorithms/approx/mod.rs index dcc4f0c17..5dacf28ee 100644 --- a/crates/fj-kernel/src/algorithms/approx/mod.rs +++ b/crates/fj-kernel/src/algorithms/approx/mod.rs @@ -6,6 +6,14 @@ pub mod edge; pub mod face; pub mod tolerance; +use std::{ + any::Any, + cmp::Ordering, + fmt::Debug, + hash::{Hash, Hasher}, + rc::Rc, +}; + use fj_math::Point; pub use self::tolerance::{InvalidTolerance, Tolerance}; @@ -23,11 +31,60 @@ pub trait Approx { } /// A point from an approximation, with local and global forms -#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +#[derive(Debug, Clone)] pub struct ApproxPoint { /// The local form of the point pub local_form: Point, /// The global form of the points pub global_form: Point<3>, + + /// The optional source of the point + pub source: Option>, +} + +impl ApproxPoint { + /// Create an instance of `ApproxPoint`, without a source + pub fn new(local_form: Point, global_form: Point<3>) -> Self { + Self { + local_form, + global_form, + source: None, + } + } +} + +impl Eq for ApproxPoint {} + +impl PartialEq for ApproxPoint { + fn eq(&self, other: &Self) -> bool { + self.local_form == other.local_form + && self.global_form == other.global_form + } } + +impl Hash for ApproxPoint { + fn hash(&self, state: &mut H) { + self.local_form.hash(state); + self.global_form.hash(state); + } +} + +impl Ord for ApproxPoint { + fn cmp(&self, other: &Self) -> Ordering { + match self.local_form.cmp(&other.local_form) { + Ordering::Equal => {} + ord => return ord, + } + self.global_form.cmp(&other.global_form) + } +} + +impl PartialOrd for ApproxPoint { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// The source of an [`ApproxPoint`] +pub trait Source: Any + Debug {} From 44cba1ae91d6e586a79e2c75130dd0ce69efb91a Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Wed, 7 Sep 2022 16:13:33 +0200 Subject: [PATCH 18/18] Attach source to curve-generated approx points --- crates/fj-kernel/src/algorithms/approx/curve.rs | 1 + crates/fj-kernel/src/algorithms/approx/mod.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/crates/fj-kernel/src/algorithms/approx/curve.rs b/crates/fj-kernel/src/algorithms/approx/curve.rs index a5e186577..708bec430 100644 --- a/crates/fj-kernel/src/algorithms/approx/curve.rs +++ b/crates/fj-kernel/src/algorithms/approx/curve.rs @@ -30,6 +30,7 @@ impl Approx for (&Curve, RangeOnCurve) { let point_surface = curve.kind().point_from_curve_coords(point.local_form); ApproxPoint::new(point_surface, point.global_form) + .with_source((*curve, point.local_form)) }) .collect(); diff --git a/crates/fj-kernel/src/algorithms/approx/mod.rs b/crates/fj-kernel/src/algorithms/approx/mod.rs index 5dacf28ee..fc6bafcb1 100644 --- a/crates/fj-kernel/src/algorithms/approx/mod.rs +++ b/crates/fj-kernel/src/algorithms/approx/mod.rs @@ -16,6 +16,8 @@ use std::{ use fj_math::Point; +use crate::objects::Curve; + pub use self::tolerance::{InvalidTolerance, Tolerance}; /// Approximate an object @@ -52,6 +54,14 @@ impl ApproxPoint { source: None, } } + + /// Attach a source to the point + pub fn with_source(self, source: impl Source) -> Self { + Self { + source: Some(Rc::new(source)), + ..self + } + } } impl Eq for ApproxPoint {} @@ -88,3 +98,5 @@ impl PartialOrd for ApproxPoint { /// The source of an [`ApproxPoint`] pub trait Source: Any + Debug {} + +impl Source for (Curve, Point<1>) {}