zerometry/
relation.rs

1use std::ops;
2
3/// This struct is used to query the specific relationship between two shapes.
4/// By default nothing is enabled and no relation are computed.
5///
6/// The difference between the strict and normal version of contains and contained are when dealing with multi-shape.
7/// Contains would return true if only one point of a multi-poins is contained in the first shape.
8/// The strict contains only returns true if all the points of the multi-points are contained in the
9/// first shape. It's also way more expensive to compute.
10#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
11pub struct InputRelation {
12    /// Return true if any part on the first shape contains any part of the second shape.
13    pub contains: bool,
14    /// Return true if any parts of the first shape contains all parts of the second shape.
15    pub strict_contains: bool,
16
17    /// Return true if any part of the first shape is contained in any part of the second shape.
18    pub contained: bool,
19    /// Return true if all parts of the first shape are contained in any part of the second shape.
20    pub strict_contained: bool,
21
22    /// Return true if all parts of the first shape are contained in any part of the second shape.
23    pub intersect: bool,
24
25    /// Return true if there is no relation between both shapes.
26    pub disjoint: bool,
27
28    /// If set to `true` the relation algorithm will stop as soon as possible after filling any value.
29    /// For example if you are asking if a shape contains, is contained or intersect with another but
30    /// don't really care about which of these happened you can set `early_exit` to true and the relation
31    /// algorithm will be able to exit directly after finding the first intersection for example.
32    pub early_exit: bool,
33}
34
35impl InputRelation {
36    /// Set everything to `true` and cannot early exit.
37    pub fn all() -> Self {
38        Self {
39            contains: true,
40            strict_contains: true,
41            contained: true,
42            strict_contained: true,
43            intersect: true,
44            disjoint: true,
45            early_exit: false,
46        }
47    }
48
49    /// Set everything to `true` but can early exit.
50    pub fn any() -> Self {
51        Self {
52            contains: true,
53            strict_contains: true,
54            contained: true,
55            strict_contained: true,
56            intersect: true,
57            disjoint: true,
58            early_exit: true,
59        }
60    }
61
62    /// Swap the contains and contained relation.
63    pub fn swap_contains_relation(mut self) -> Self {
64        std::mem::swap(&mut self.contains, &mut self.contained);
65        std::mem::swap(&mut self.strict_contains, &mut self.strict_contained);
66        self
67    }
68
69    /// Set everything to false, same as [`Self::default`].
70    pub fn none() -> Self {
71        Self::default()
72    }
73
74    /// Generates an [`OutputRelation`] where every `true` field of `Self` are set to `Some(false)`.
75    pub fn to_false(self) -> OutputRelation {
76        OutputRelation::false_from_input(self)
77    }
78
79    /// Generates an [`OutputRelation`] where every `true` field of `Self` are set to `Some(true)`.
80    pub fn to_true(self) -> OutputRelation {
81        OutputRelation::true_from_input(self)
82    }
83
84    /// Remove the strict contains and contained.
85    pub fn strip_strict(mut self) -> Self {
86        self.strict_contains = false;
87        self.strict_contained = false;
88        self
89    }
90
91    /// Remove only the strict contained.
92    pub fn strip_strict_contained(mut self) -> Self {
93        self.strict_contained = false;
94        self
95    }
96
97    /// Remove disjoint.
98    pub fn strip_disjoint(mut self) -> Self {
99        self.disjoint = false;
100        self
101    }
102}
103
104/// Returned by the `relation` function.
105/// All fields are made of a `Option<bool>`.
106/// There are two cases for which a field can be None:
107/// - If you didn't ask for it when filling the `InputRelation` struct
108/// - If the relation algorithm didn't evaluate this relation because the
109///   `early_exit` flag was set.
110///
111/// Note that when early exit is set, most fields will be set to `Some(false)` even
112/// though they were not evaluated at all.
113#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
114pub struct OutputRelation {
115    /// Return true if any part on the first shape contains any part of the second shape.
116    pub contains: Option<bool>,
117    /// Return true if any parts of the first shape contains all parts of the second shape.
118    pub strict_contains: Option<bool>,
119    /// Return true if any part of the first shape is contained in any part of the second shape.
120    pub contained: Option<bool>,
121    /// Return true if all parts of the first shape are contained in any part of the second shape.
122    pub strict_contained: Option<bool>,
123    /// Return true if all parts of the first shape are contained in any part of the second shape.
124    pub intersect: Option<bool>,
125    /// Return true if there is no relation between both shapes.
126    pub disjoint: Option<bool>,
127}
128
129impl OutputRelation {
130    pub(crate) fn false_from_input(relation: InputRelation) -> Self {
131        Self {
132            contains: relation.contains.then_some(false),
133            strict_contains: relation.strict_contains.then_some(false),
134            contained: relation.contained.then_some(false),
135            strict_contained: relation.strict_contained.then_some(false),
136            intersect: relation.intersect.then_some(false),
137            disjoint: relation.disjoint.then_some(false),
138        }
139    }
140
141    pub(crate) fn true_from_input(relation: InputRelation) -> Self {
142        Self {
143            contains: relation.contains.then_some(true),
144            strict_contains: relation.strict_contains.then_some(true),
145            contained: relation.contained.then_some(true),
146            strict_contained: relation.strict_contained.then_some(true),
147            intersect: relation.intersect.then_some(true),
148            disjoint: relation.disjoint.then_some(true),
149        }
150    }
151
152    pub(crate) fn make_contains_if_set(mut self) -> Self {
153        self.contains = self.contains.map(|_| true);
154        self
155    }
156
157    /// Set both the contains and strict_contains field to true if they are set
158    pub(crate) fn make_strict_contains_if_set(mut self) -> Self {
159        self.strict_contains = self.strict_contains.map(|_| true);
160        self.make_contains_if_set()
161    }
162
163    pub(crate) fn make_contained_if_set(mut self) -> Self {
164        self.contained = self.contained.map(|_| true);
165        self
166    }
167
168    /// Set both the contained and strict_contained field to true if they are set
169    pub(crate) fn make_strict_contained_if_set(mut self) -> Self {
170        self.strict_contained = self.strict_contained.map(|_| true);
171        self.make_contained_if_set()
172    }
173
174    pub(crate) fn make_intersect_if_set(mut self) -> Self {
175        self.intersect = self.intersect.map(|_| true);
176        self
177    }
178
179    pub(crate) fn make_disjoint_if_set(mut self) -> Self {
180        self.disjoint = self.disjoint.map(|_| true);
181        self
182    }
183
184    pub(crate) fn strip_strict(mut self) -> Self {
185        self.strict_contains = None;
186        self.strict_contained = None;
187        self
188    }
189
190    /// Return true if the output contains anything except disjoint.
191    pub fn any_relation(&self) -> bool {
192        // If the shape are distinct we don't need to check anything else and can stop early
193        (!self.disjoint.unwrap_or_default())
194            // otherwise we must check every single entry and return true if any contains a true
195            && (self.contains.unwrap_or_default()
196                || self.strict_contains.unwrap_or_default()
197                || self.contained.unwrap_or_default()
198                || self.strict_contained.unwrap_or_default()
199                || self.intersect.unwrap_or_default())
200    }
201
202    /// Swap the contains and contained relation.
203    pub fn swap_contains_relation(mut self) -> Self {
204        std::mem::swap(&mut self.contains, &mut self.contained);
205        std::mem::swap(&mut self.strict_contains, &mut self.strict_contained);
206        self
207    }
208}
209
210impl ops::BitOr for OutputRelation {
211    type Output = Self;
212
213    fn bitor(self, other: Self) -> Self::Output {
214        let Self {
215            mut contains,
216            mut strict_contains,
217            mut contained,
218            mut strict_contained,
219            mut intersect,
220            mut disjoint,
221        } = self;
222
223        if let Some(ref mut s) = contains {
224            *s |= other.contains.unwrap_or_default()
225        }
226
227        if let Some(ref mut s) = strict_contains {
228            *s |= other.strict_contains.unwrap_or_default()
229        }
230
231        if let Some(ref mut s) = contained {
232            *s |= other.contained.unwrap_or_default()
233        }
234
235        if let Some(ref mut s) = strict_contained {
236            *s |= other.strict_contained.unwrap_or_default()
237        }
238
239        if let Some(ref mut s) = intersect {
240            *s |= other.intersect.unwrap_or_default()
241        }
242
243        if let Some(ref mut s) = disjoint {
244            *s |= other.disjoint.unwrap_or_default()
245        }
246
247        Self {
248            contains,
249            strict_contains,
250            contained,
251            strict_contained,
252            intersect,
253            disjoint,
254        }
255    }
256}
257
258impl ops::BitOrAssign for OutputRelation {
259    fn bitor_assign(&mut self, rhs: Self) {
260        *self = *self | rhs;
261    }
262}
263
264/// Lets you query the relation between two shapes.
265pub trait RelationBetweenShapes<Other: ?Sized> {
266    /// Return the relation between two shapes.
267    /// The [`InputRelation`] lets you specify the kind of relation you want to retrieve.
268    ///
269    // ```
270    /// use zerometry::{Zoint, Zolygon, RelationBetweenShapes, InputRelation};
271    ///
272    /// let point = geo_types::Point::new(0.0, 0.0);
273    /// let polygon = geo_types::polygon![(x: -1.0, y: -1.0), (x: 1.0, y: -1.0), (x: 1.0, y: 1.0), (x: -1.0, y: 1.0)];
274    ///
275    /// let mut buffer = Vec::new();
276    /// Zoint::write_from_geometry(&mut buffer, &point).unwrap();
277    /// let zoint = Zoint::from_bytes(&buffer);
278    /// let mut buffer = Vec::new();
279    /// Zoint::write_from_geometry(&mut buffer, &polygon).unwrap();
280    /// let zolygon = Zolygon::from_bytes(&buffer);
281    ///
282    /// // Let's say we just want to know if the point is contained in the polygon,
283    /// // we could write
284    /// let relation = InputRelation { contains: true, ..InputRelation::default() };
285    /// // The we can ask the relation between our two shape with the `relation` method:
286    /// let relation = zolygon.relation(&zoint, relation);
287    /// assert_eq!(relation.contains, Some(true));
288    /// ```
289    fn relation(&self, other: &Other, relation: InputRelation) -> OutputRelation;
290
291    /// Return all relations with no early return.
292    fn all_relation(&self, other: &Other) -> OutputRelation {
293        self.relation(other, InputRelation::all())
294    }
295
296    /// Return the first relation we find with early return.
297    fn any_relation(&self, other: &Other) -> OutputRelation {
298        self.relation(other, InputRelation::any())
299    }
300
301    /// Return `true` if `Self` contains `Other`.
302    fn contains(&self, other: &Other) -> bool {
303        self.relation(
304            other,
305            InputRelation {
306                contains: true,
307                early_exit: true,
308                ..Default::default()
309            },
310        )
311        .contains
312        .unwrap_or_default()
313    }
314
315    /// Return `true` if `Self` strictly contains `Other`.
316    fn strict_contains(&self, other: &Other) -> bool {
317        self.relation(
318            other,
319            InputRelation {
320                strict_contains: true,
321                early_exit: true,
322                ..Default::default()
323            },
324        )
325        .strict_contains
326        .unwrap_or_default()
327    }
328
329    /// Return `true` if `Self` is contained in `Other`.
330    fn contained(&self, other: &Other) -> bool {
331        self.relation(
332            other,
333            InputRelation {
334                contained: true,
335                early_exit: true,
336                ..Default::default()
337            },
338        )
339        .contained
340        .unwrap_or_default()
341    }
342
343    /// Return `true` if `Self` is strictly contained in `Other`.
344    fn strict_contained(&self, other: &Other) -> bool {
345        self.relation(
346            other,
347            InputRelation {
348                strict_contained: true,
349                early_exit: true,
350                ..Default::default()
351            },
352        )
353        .strict_contained
354        .unwrap_or_default()
355    }
356
357    /// Return `true` if `Self` intersects with `Other`.
358    fn intersects(&self, other: &Other) -> bool {
359        self.relation(
360            other,
361            InputRelation {
362                intersect: true,
363                early_exit: true,
364                ..Default::default()
365            },
366        )
367        .intersect
368        .unwrap_or_default()
369    }
370
371    /// Return `true` if `Self` is disjoint of `Other`.
372    fn disjoint(&self, other: &Other) -> bool {
373        self.relation(
374            other,
375            InputRelation {
376                disjoint: true,
377                early_exit: true,
378                ..Default::default()
379            },
380        )
381        .disjoint
382        .unwrap_or_default()
383    }
384}