1use std::{
2 cmp::{self, Ordering},
3 hash::{Hash, Hasher},
4};
5
6use fj_math::Point;
7
8use crate::{objects::Vertex, storage::HandleWrapper};
9
10#[derive(Clone, Copy, Debug)]
16pub struct CurveBoundary<T: CurveBoundaryElement> {
17 pub inner: [T::Repr; 2],
19}
20
21impl<T: CurveBoundaryElement> CurveBoundary<T> {
22 pub fn is_normalized(&self) -> bool {
27 let [a, b] = &self.inner;
28 a <= b
29 }
30
31 #[must_use]
35 pub fn reverse(self) -> Self {
36 let [a, b] = self.inner;
37 Self { inner: [b, a] }
38 }
39
40 #[must_use]
46 pub fn normalize(self) -> Self {
47 if self.is_normalized() {
48 self
49 } else {
50 self.reverse()
51 }
52 }
53}
54
55impl CurveBoundary<Point<1>> {
62 pub fn is_empty(&self) -> bool {
64 let [min, max] = &self.inner;
65 min >= max
66 }
67
68 pub fn contains(&self, point: Point<1>) -> bool {
70 let [min, max] = self.normalize().inner;
71 point > min && point < max
72 }
73
74 pub fn overlaps(&self, other: &Self) -> bool {
79 let [a_low, a_high] = self.normalize().inner;
80 let [b_low, b_high] = other.normalize().inner;
81
82 a_low <= b_high && a_high >= b_low
83 }
84
85 pub fn difference(self, other: Self) -> Option<OneOrTwoBoundaries> {
89 let [self_min, self_max] = self.normalize().inner;
90 let [other_min, other_max] = other.normalize().inner;
91
92 match (
93 self_min <= other_min,
94 self_min <= other_max,
95 self_max <= other_min,
96 self_max <= other_max,
97 ) {
98 (true, true, true, true) => {
99 Some(OneOrTwoBoundaries::One(CurveBoundary {
100 inner: [self_min, self_max],
101 }))
102 }
103 (true, true, false, true) => {
104 let min = self_min;
105 let max = other_min;
106
107 if min == max {
108 return None;
109 }
110
111 Some(OneOrTwoBoundaries::One(CurveBoundary {
112 inner: [min, max],
113 }))
114 }
115 (true, true, false, false) => Some(OneOrTwoBoundaries::Two([
116 CurveBoundary {
117 inner: [self_min, other_min],
118 },
119 CurveBoundary {
120 inner: [other_max, self_max],
121 },
122 ])),
123 (false, true, false, true) => None,
124 (false, true, false, false) => {
125 Some(OneOrTwoBoundaries::One(CurveBoundary {
126 inner: [other_max, self_max],
127 }))
128 }
129 (false, false, false, false) => {
130 Some(OneOrTwoBoundaries::One(CurveBoundary {
131 inner: [self_min, self_max],
132 }))
133 }
134 case => {
135 unreachable!(
136 "{case:?} is impossible, due to normalization above"
137 );
138 }
139 }
140 }
141
142 #[must_use]
146 pub fn intersection(self, other: Self) -> Self {
147 let self_ = self.normalize();
148 let other = other.normalize();
149
150 let [self_min, self_max] = self_.inner;
151 let [other_min, other_max] = other.inner;
152
153 let min = cmp::max(self_min, other_min);
154 let max = cmp::min(self_max, other_max);
155
156 Self { inner: [min, max] }
157 }
158
159 pub fn union(self, other: Self) -> Self {
168 let self_ = self.normalize();
169 let other = other.normalize();
170
171 assert!(
172 self.overlaps(&other),
173 "Can't merge boundaries that don't at least touch"
174 );
175
176 let [self_min, self_max] = self_.inner;
177 let [other_min, other_max] = other.inner;
178
179 let min = cmp::min(self_min, other_min);
180 let max = cmp::max(self_max, other_max);
181
182 Self { inner: [min, max] }
183 }
184}
185
186impl<S, T: CurveBoundaryElement> From<[S; 2]> for CurveBoundary<T>
187where
188 S: Into<T::Repr>,
189{
190 fn from(boundary: [S; 2]) -> Self {
191 let inner = boundary.map(Into::into);
192 Self { inner }
193 }
194}
195
196impl<T: CurveBoundaryElement> Eq for CurveBoundary<T> {}
197
198impl<T: CurveBoundaryElement> PartialEq for CurveBoundary<T> {
199 fn eq(&self, other: &Self) -> bool {
200 self.inner == other.inner
201 }
202}
203
204impl<T: CurveBoundaryElement> Hash for CurveBoundary<T> {
205 fn hash<H: Hasher>(&self, state: &mut H) {
206 self.inner.hash(state);
207 }
208}
209
210impl<T: CurveBoundaryElement> Ord for CurveBoundary<T> {
211 fn cmp(&self, other: &Self) -> Ordering {
212 self.inner.cmp(&other.inner)
213 }
214}
215
216impl<T: CurveBoundaryElement> PartialOrd for CurveBoundary<T> {
217 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
218 Some(self.cmp(other))
219 }
220}
221
222#[derive(Debug, Eq, PartialEq)]
223pub enum OneOrTwoBoundaries {
224 One(CurveBoundary<Point<1>>),
225 Two([CurveBoundary<Point<1>>; 2]),
226}
227
228pub trait CurveBoundaryElement {
232 type Repr: Eq + Hash + Ord;
236}
237
238impl CurveBoundaryElement for Point<1> {
239 type Repr = Self;
240}
241
242impl CurveBoundaryElement for Vertex {
243 type Repr = HandleWrapper<Vertex>;
244}
245
246#[cfg(test)]
247mod tests {
248 use fj_math::Point;
249
250 use crate::geometry::{boundary::OneOrTwoBoundaries, CurveBoundary};
251
252 #[test]
253 fn overlaps() {
254 assert!(overlap([0., 2.], [1., 3.])); assert!(overlap([0., 1.], [1., 2.])); assert!(overlap([2., 0.], [3., 1.])); assert!(overlap([1., 3.], [0., 2.])); assert!(!overlap([0., 1.], [2., 3.])); assert!(!overlap([2., 3.], [0., 1.])); fn overlap(a: [f64; 2], b: [f64; 2]) -> bool {
263 let a = array_to_boundary(a);
264 let b = array_to_boundary(b);
265
266 a.overlaps(&b)
267 }
268 }
269
270 #[test]
271 fn difference() {
272 diff([1., 2.], [1., 2.], &[]);
276 diff([1., 2.], [2., 1.], &[]);
277 diff([2., 1.], [1., 2.], &[]);
278 diff([2., 1.], [2., 1.], &[]);
279
280 diff([1., 2.], [1., 3.], &[]);
282 diff([1., 2.], [3., 1.], &[]);
283 diff([2., 1.], [1., 3.], &[]);
284 diff([2., 1.], [3., 1.], &[]);
285
286 diff([1., 2.], [0., 2.], &[]);
288 diff([1., 2.], [2., 0.], &[]);
289 diff([2., 1.], [0., 2.], &[]);
290 diff([2., 1.], [2., 0.], &[]);
291
292 diff([1., 2.], [0., 3.], &[]);
294 diff([1., 2.], [3., 0.], &[]);
295 diff([2., 1.], [0., 3.], &[]);
296 diff([2., 1.], [3., 0.], &[]);
297
298 diff([0., 1.], [1., 2.], &[[0., 1.]]);
300 diff([0., 1.], [2., 1.], &[[0., 1.]]);
301 diff([1., 0.], [1., 2.], &[[0., 1.]]);
302 diff([1., 0.], [2., 1.], &[[0., 1.]]);
303
304 diff([0., 1.], [2., 3.], &[[0., 1.]]);
306 diff([0., 1.], [3., 2.], &[[0., 1.]]);
307 diff([1., 0.], [2., 3.], &[[0., 1.]]);
308 diff([1., 0.], [3., 2.], &[[0., 1.]]);
309
310 diff([2., 3.], [1., 2.], &[[2., 3.]]);
312 diff([2., 3.], [2., 1.], &[[2., 3.]]);
313 diff([3., 2.], [1., 2.], &[[2., 3.]]);
314 diff([3., 2.], [2., 1.], &[[2., 3.]]);
315
316 diff([2., 3.], [0., 1.], &[[2., 3.]]);
318 diff([2., 3.], [1., 0.], &[[2., 3.]]);
319 diff([3., 2.], [0., 1.], &[[2., 3.]]);
320 diff([3., 2.], [1., 0.], &[[2., 3.]]);
321
322 diff([0., 2.], [1., 3.], &[[0., 1.]]);
324 diff([0., 2.], [3., 1.], &[[0., 1.]]);
325 diff([2., 0.], [1., 3.], &[[0., 1.]]);
326 diff([2., 0.], [3., 1.], &[[0., 1.]]);
327
328 diff([1., 3.], [0., 2.], &[[2., 3.]]);
330 diff([1., 3.], [2., 0.], &[[2., 3.]]);
331 diff([3., 1.], [0., 2.], &[[2., 3.]]);
332 diff([3., 1.], [2., 0.], &[[2., 3.]]);
333
334 diff([0., 3.], [1., 2.], &[[0., 1.], [2., 3.]]);
336 diff([0., 3.], [2., 1.], &[[0., 1.], [2., 3.]]);
337 diff([3., 0.], [1., 2.], &[[0., 1.], [2., 3.]]);
338 diff([3., 0.], [2., 1.], &[[0., 1.], [2., 3.]]);
339
340 fn diff(a: [f64; 2], b: [f64; 2], x: &[[f64; 2]]) {
341 print!("{a:?} \\ {b:?} = ");
342
343 let a = array_to_boundary(a);
344 let b = array_to_boundary(b);
345
346 let x = match x {
347 [] => None,
348 &[x] => Some(OneOrTwoBoundaries::One(array_to_boundary(x))),
349 &[x1, x2] => Some(OneOrTwoBoundaries::Two(
350 [x1, x2].map(array_to_boundary),
351 )),
352 _ => panic!("Invalid result"),
353 };
354
355 let diff = a.difference(b);
356 println!("{diff:?}");
357 assert_eq!(diff, x);
358 }
359 }
360
361 fn array_to_boundary(array: [f64; 2]) -> CurveBoundary<Point<1>> {
362 CurveBoundary::from(array.map(|element| [element]))
363 }
364}