From 132cda6b4460e957858e697ffa3951fdbc1ded5b Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Mon, 16 Oct 2023 10:31:41 +0200 Subject: [PATCH 1/3] Refactor to simplify --- crates/fj-core/src/geometry/boundary/multiple.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/fj-core/src/geometry/boundary/multiple.rs b/crates/fj-core/src/geometry/boundary/multiple.rs index c2d494766..5bd7480d4 100644 --- a/crates/fj-core/src/geometry/boundary/multiple.rs +++ b/crates/fj-core/src/geometry/boundary/multiple.rs @@ -1,5 +1,3 @@ -use std::collections::VecDeque; - use fj_math::Point; use crate::geometry::CurveBoundary; @@ -66,7 +64,7 @@ impl CurveBoundaries { /// Create the union between this an another `CurveBoundaries` instance pub fn union(mut self, other: impl Into) -> Self { for (other_boundary, other_payload) in other.into().inner { - let mut overlapping_payloads = VecDeque::new(); + let mut overlapping_payloads = Vec::new(); let mut i = 0; loop { @@ -76,7 +74,7 @@ impl CurveBoundaries { if boundary.overlaps(&other_boundary) { let payload = self.inner.swap_remove(i); - overlapping_payloads.push_back(payload); + overlapping_payloads.push(payload); continue; } From 68955b1223328b897bb6dc770e654ee3877158f4 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Mon, 16 Oct 2023 10:58:01 +0200 Subject: [PATCH 2/3] Add `CurveBoundaries::difference` --- .../fj-core/src/geometry/boundary/multiple.rs | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/crates/fj-core/src/geometry/boundary/multiple.rs b/crates/fj-core/src/geometry/boundary/multiple.rs index 5bd7480d4..fb46a6c31 100644 --- a/crates/fj-core/src/geometry/boundary/multiple.rs +++ b/crates/fj-core/src/geometry/boundary/multiple.rs @@ -2,6 +2,8 @@ use fj_math::Point; use crate::geometry::CurveBoundary; +use super::single::OneOrTwoBoundaries; + /// A collection of multiple [`CurveBoundary`] instances /// /// Has a type parameter, `T`, which can be used to attach a payload to each @@ -102,6 +104,56 @@ impl CurveBoundaries { } } +impl CurveBoundaries<()> { + /// Compute the difference between this instance and another one + /// + /// # Implementation Note + /// + /// This method is only available for `CurveBoundaries` instances without + /// payloads, simply because more wasn't needed so far. Support for payloads + /// can be added by expanding [`CurveBoundariesPayload`] accordingly, and + /// integrating the new method here. + pub fn difference(mut self, other: impl Into) -> Self { + for (other_boundary, ()) in other.into().inner { + let mut i = 0; + + loop { + if i == self.inner.len() { + break; + } + + let (boundary, ()) = self.inner.remove(i); + + match boundary.difference(other_boundary) { + Some(OneOrTwoBoundaries::One(b)) => { + self.inner.insert(i, (b, ())); + i += 1; + } + Some(OneOrTwoBoundaries::Two([b1, b2])) => { + self.inner.insert(i, (b1, ())); + i += 1; + + self.inner.insert(i, (b2, ())); + i += 1; + } + None => { + // Nothing to do! + // + // We already removed the original boundary above, and + // if the difference leaves no result, we don't need to + // add anything back. + // + // Don't need to update `i` either. Thanks to the + // removal, it already points to the next item. + } + } + } + } + + self + } +} + impl Default for CurveBoundaries { fn default() -> Self { Self { inner: Vec::new() } @@ -167,6 +219,47 @@ impl CurveBoundariesPayload for () { mod tests { use super::CurveBoundaries; + #[test] + fn difference() { + // There are already extensive tests for `CurveBoundary::difference`, + // and we don't need to repeat those here. The following tests just make + // sure that all of the possible return values of that method are + // handled correctly. + + // Difference results in one boundary. + diff([[0., 2.]], [[1., 3.]], [[0., 1.]]); + + // Difference results in two boundaries. + diff([[0., 3.]], [[1., 2.]], [[0., 1.], [2., 3.]]); + + // Difference results in no boundaries. + diff([[1., 2.]], [[0., 3.]], []); + + // And a combined one, to make sure that everything works with multiple + // boundaries in the inputs. + diff( + [[0., 2.], [4., 7.], [9., 10.]], + [[1., 3.], [5., 6.], [8., 11.]], + [[0., 1.], [4., 5.], [6., 7.]], + ); + + fn diff( + a: [[f64; 2]; A], + b: [[f64; 2]; B], + x: [[f64; 2]; X], + ) { + let a = a.map(|boundary| boundary.map(|v| [v])); + let b = b.map(|boundary| boundary.map(|v| [v])); + let x = x.map(|boundary| boundary.map(|v| [v])); + + let a = CurveBoundaries::from_iter(a); + let b = CurveBoundaries::from_iter(b); + let x = CurveBoundaries::from_iter(x); + + assert_eq!(a.difference(b), x); + } + } + #[test] fn union() { union([[0., 1.]], [[1., 2.]], [[0., 2.]]); From 45558c983a2adc730ba8d659ce870e59545016cc Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Mon, 16 Oct 2023 11:21:53 +0200 Subject: [PATCH 3/3] Add `CurveBoundaries::symmetric_difference` --- crates/fj-core/src/geometry/boundary/multiple.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/fj-core/src/geometry/boundary/multiple.rs b/crates/fj-core/src/geometry/boundary/multiple.rs index fb46a6c31..2c456edfb 100644 --- a/crates/fj-core/src/geometry/boundary/multiple.rs +++ b/crates/fj-core/src/geometry/boundary/multiple.rs @@ -152,6 +152,21 @@ impl CurveBoundaries<()> { self } + + /// Compute the symmetric difference between this instance and another one + /// + /// # Implementation Note + /// + /// This method is only available for `CurveBoundaries` instances without + /// payloads, simply because more wasn't needed so far. Support for payloads + /// can be added by expanding [`CurveBoundariesPayload`] accordingly, and + /// integrating the new method here. + pub fn symmetric_difference(self, other: impl Into) -> Self { + let other = other.into(); + self.clone() + .difference(other.clone()) + .union(other.difference(self)) + } } impl Default for CurveBoundaries {