geo_types/geometry/
multi_polygon.rs

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