geo_types/geometry/
multi_polygon.rs

1use crate::{CoordNum, Polygon};
2
3use alloc::vec;
4use alloc::vec::Vec;
5
6use core::iter::FromIterator;
7#[cfg(feature = "multithreading")]
8use rayon::prelude::*;
9
10/// A collection of [`Polygon`s](struct.Polygon.html). Can
11/// be created from a `Vec` of `Polygon`s, or from an
12/// Iterator which yields `Polygon`s. Iterating over this
13/// object yields the component `Polygon`s.
14///
15/// # Semantics
16///
17/// The _interior_ and the _boundary_ are the union of the
18/// interior and the boundary of the constituent polygons.
19///
20/// # Validity
21///
22/// - The interiors of no two constituent polygons may intersect.
23///
24/// - The boundaries of two (distinct) constituent polygons may only intersect at finitely many points.
25///
26/// Refer to section 6.1.14 of the OGC-SFA for a formal
27/// definition of validity. Note that the validity is not
28/// enforced, but expected by the operations and
29/// predicates that operate on it.
30#[derive(Eq, PartialEq, Clone, Hash)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32pub struct MultiPolygon<T: CoordNum = f64>(pub Vec<Polygon<T>>);
33
34impl<T: CoordNum, IP: Into<Polygon<T>>> From<IP> for MultiPolygon<T> {
35    fn from(x: IP) -> Self {
36        Self(vec![x.into()])
37    }
38}
39
40impl<T: CoordNum, IP: Into<Polygon<T>>> From<Vec<IP>> for MultiPolygon<T> {
41    fn from(x: Vec<IP>) -> Self {
42        Self(x.into_iter().map(|p| p.into()).collect())
43    }
44}
45
46impl<T: CoordNum, IP: Into<Polygon<T>>> FromIterator<IP> for MultiPolygon<T> {
47    fn from_iter<I: IntoIterator<Item = IP>>(iter: I) -> Self {
48        Self(iter.into_iter().map(|p| p.into()).collect())
49    }
50}
51
52impl<T: CoordNum> IntoIterator for MultiPolygon<T> {
53    type Item = Polygon<T>;
54    type IntoIter = ::alloc::vec::IntoIter<Polygon<T>>;
55
56    fn into_iter(self) -> Self::IntoIter {
57        self.0.into_iter()
58    }
59}
60
61impl<'a, T: CoordNum> IntoIterator for &'a MultiPolygon<T> {
62    type Item = &'a Polygon<T>;
63    type IntoIter = ::alloc::slice::Iter<'a, Polygon<T>>;
64
65    fn into_iter(self) -> Self::IntoIter {
66        (self.0).iter()
67    }
68}
69
70impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPolygon<T> {
71    type Item = &'a mut Polygon<T>;
72    type IntoIter = ::alloc::slice::IterMut<'a, Polygon<T>>;
73
74    fn into_iter(self) -> Self::IntoIter {
75        (self.0).iter_mut()
76    }
77}
78
79#[cfg(feature = "multithreading")]
80impl<T: CoordNum + Send> IntoParallelIterator for MultiPolygon<T> {
81    type Item = Polygon<T>;
82    type Iter = rayon::vec::IntoIter<Polygon<T>>;
83
84    fn into_par_iter(self) -> Self::Iter {
85        self.0.into_par_iter()
86    }
87}
88
89#[cfg(feature = "multithreading")]
90impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiPolygon<T> {
91    type Item = &'a Polygon<T>;
92    type Iter = rayon::slice::Iter<'a, Polygon<T>>;
93
94    fn into_par_iter(self) -> Self::Iter {
95        self.0.par_iter()
96    }
97}
98
99#[cfg(feature = "multithreading")]
100impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiPolygon<T> {
101    type Item = &'a mut Polygon<T>;
102    type Iter = rayon::slice::IterMut<'a, Polygon<T>>;
103
104    fn into_par_iter(self) -> Self::Iter {
105        self.0.par_iter_mut()
106    }
107}
108
109impl<T: CoordNum> MultiPolygon<T> {
110    /// Returns a MultiPolygon with the given Polygons as elements
111    pub fn new(value: Vec<Polygon<T>>) -> Self {
112        Self(value)
113    }
114
115    /// Returns an empty MultiPolygon
116    pub fn empty() -> Self {
117        Self(Vec::new())
118    }
119
120    pub fn iter(&self) -> impl Iterator<Item = &Polygon<T>> {
121        self.0.iter()
122    }
123
124    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Polygon<T>> {
125        self.0.iter_mut()
126    }
127}
128
129#[cfg(any(feature = "approx", test))]
130mod approx_integration {
131    use super::*;
132    use approx::{AbsDiffEq, RelativeEq, UlpsEq};
133
134    impl<T> RelativeEq for MultiPolygon<T>
135    where
136        T: CoordNum + RelativeEq<Epsilon = T>,
137    {
138        #[inline]
139        fn default_max_relative() -> Self::Epsilon {
140            T::default_max_relative()
141        }
142
143        /// Equality assertion within a relative limit.
144        ///
145        /// # Examples
146        ///
147        /// ```
148        /// use geo_types::{polygon, Polygon, MultiPolygon};
149        ///
150        /// let a_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7., y: 9.), (x: 0., y: 0.)];
151        /// let a = MultiPolygon::new(vec![a_el]);
152        /// let b_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7.01, y: 9.), (x: 0., y: 0.)];
153        /// let b = MultiPolygon::new(vec![b_el]);
154        ///
155        /// approx::assert_relative_eq!(a, b, max_relative=0.1);
156        /// approx::assert_relative_ne!(a, b, max_relative=0.001);
157        /// ```
158        #[inline]
159        fn relative_eq(
160            &self,
161            other: &Self,
162            epsilon: Self::Epsilon,
163            max_relative: Self::Epsilon,
164        ) -> bool {
165            if self.0.len() != other.0.len() {
166                return false;
167            }
168
169            let mut mp_zipper = self.iter().zip(other.iter());
170            mp_zipper.all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
171        }
172    }
173
174    impl<T> AbsDiffEq for MultiPolygon<T>
175    where
176        T: CoordNum + AbsDiffEq<Epsilon = T>,
177    {
178        type Epsilon = T;
179
180        #[inline]
181        fn default_epsilon() -> Self::Epsilon {
182            T::default_epsilon()
183        }
184
185        /// Equality assertion with an absolute limit.
186        ///
187        /// # Examples
188        ///
189        /// ```
190        /// use geo_types::{polygon, Polygon, MultiPolygon};
191        ///
192        /// let a_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7., y: 9.), (x: 0., y: 0.)];
193        /// let a = MultiPolygon::new(vec![a_el]);
194        /// let b_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7.01, y: 9.), (x: 0., y: 0.)];
195        /// let b = MultiPolygon::new(vec![b_el]);
196        ///
197        /// approx::abs_diff_eq!(a, b, epsilon=0.1);
198        /// approx::abs_diff_ne!(a, b, epsilon=0.001);
199        /// ```
200        #[inline]
201        fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
202            if self.0.len() != other.0.len() {
203                return false;
204            }
205
206            let mut mp_zipper = self.into_iter().zip(other);
207            mp_zipper.all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
208        }
209    }
210
211    impl<T> UlpsEq for MultiPolygon<T>
212    where
213        T: CoordNum + UlpsEq<Epsilon = T>,
214    {
215        fn default_max_ulps() -> u32 {
216            T::default_max_ulps()
217        }
218
219        fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
220            if self.0.len() != other.0.len() {
221                return false;
222            }
223            let mut mp_zipper = self.into_iter().zip(other);
224            mp_zipper.all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
225        }
226    }
227}
228
229#[cfg(any(
230    feature = "rstar_0_8",
231    feature = "rstar_0_9",
232    feature = "rstar_0_10",
233    feature = "rstar_0_11",
234    feature = "rstar_0_12"
235))]
236macro_rules! impl_rstar_multi_polygon {
237    ($rstar:ident) => {
238        impl<T> $rstar::RTreeObject for MultiPolygon<T>
239        where
240            T: ::num_traits::Float + ::$rstar::RTreeNum,
241        {
242            type Envelope = ::$rstar::AABB<$crate::Point<T>>;
243            fn envelope(&self) -> Self::Envelope {
244                use ::$rstar::Envelope;
245                self.iter()
246                    .map(|p| p.envelope())
247                    .fold(::$rstar::AABB::new_empty(), |a, b| a.merged(&b))
248            }
249        }
250    };
251}
252#[cfg(feature = "rstar_0_8")]
253impl_rstar_multi_polygon!(rstar_0_8);
254#[cfg(feature = "rstar_0_9")]
255impl_rstar_multi_polygon!(rstar_0_9);
256#[cfg(feature = "rstar_0_10")]
257impl_rstar_multi_polygon!(rstar_0_10);
258#[cfg(feature = "rstar_0_11")]
259impl_rstar_multi_polygon!(rstar_0_11);
260#[cfg(feature = "rstar_0_12")]
261impl_rstar_multi_polygon!(rstar_0_12);
262
263#[cfg(test)]
264mod test {
265    use super::*;
266    use crate::{polygon, wkt};
267
268    #[test]
269    fn test_iter() {
270        let multi = MultiPolygon::new(vec![
271            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
272            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
273        ]);
274
275        let mut first = true;
276        for p in &multi {
277            if first {
278                assert_eq!(
279                    p,
280                    &polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)]
281                );
282                first = false;
283            } else {
284                assert_eq!(
285                    p,
286                    &polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)]
287                );
288            }
289        }
290
291        // Do it again to prove that `multi` wasn't `moved`.
292        first = true;
293        for p in &multi {
294            if first {
295                assert_eq!(
296                    p,
297                    &polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)]
298                );
299                first = false;
300            } else {
301                assert_eq!(
302                    p,
303                    &polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)]
304                );
305            }
306        }
307    }
308
309    #[cfg(feature = "multithreading")]
310    #[test]
311    fn test_par_iter() {
312        let multi = MultiPolygon::new(vec![
313            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
314            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
315        ]);
316        let mut multimut = MultiPolygon::new(vec![
317            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
318            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
319        ]);
320        multi.par_iter().for_each(|_p| ());
321        let _ = &multimut.par_iter_mut().for_each(|_p| ());
322        let _ = &multi.into_par_iter().for_each(|_p| ());
323        let _ = &mut multimut.par_iter_mut().for_each(|_p| ());
324    }
325    #[test]
326    fn test_iter_mut() {
327        let mut multi = MultiPolygon::new(vec![
328            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
329            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
330        ]);
331
332        for poly in &mut multi {
333            poly.exterior_mut(|exterior| {
334                for coord in exterior {
335                    coord.x += 1;
336                    coord.y += 1;
337                }
338            });
339        }
340
341        for poly in multi.iter_mut() {
342            poly.exterior_mut(|exterior| {
343                for coord in exterior {
344                    coord.x += 1;
345                    coord.y += 1;
346                }
347            });
348        }
349
350        let mut first = true;
351        for p in &multi {
352            if first {
353                assert_eq!(
354                    p,
355                    &polygon![(x: 2, y: 2), (x: 4, y: 2), (x: 3, y: 4), (x:2, y:2)]
356                );
357                first = false;
358            } else {
359                assert_eq!(
360                    p,
361                    &polygon![(x: 12, y: 12), (x: 14, y: 12), (x: 13, y: 14), (x:12, y:12)]
362                );
363            }
364        }
365    }
366
367    #[test]
368    fn empty() {
369        let empty = MultiPolygon::<f64>::empty();
370        let empty_2 = wkt! { MULTIPOLYGON EMPTY };
371        assert_eq!(empty, empty_2);
372    }
373}