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}