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    /// Instantiate Self from the raw content value
111    pub fn new(value: Vec<Polygon<T>>) -> Self {
112        Self(value)
113    }
114
115    pub fn iter(&self) -> impl Iterator<Item = &Polygon<T>> {
116        self.0.iter()
117    }
118
119    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Polygon<T>> {
120        self.0.iter_mut()
121    }
122}
123
124#[cfg(any(feature = "approx", test))]
125mod approx_integration {
126    use super::*;
127    use approx::{AbsDiffEq, RelativeEq, UlpsEq};
128
129    impl<T> RelativeEq for MultiPolygon<T>
130    where
131        T: CoordNum + RelativeEq<Epsilon = T>,
132    {
133        #[inline]
134        fn default_max_relative() -> Self::Epsilon {
135            T::default_max_relative()
136        }
137
138        /// Equality assertion within a relative limit.
139        ///
140        /// # Examples
141        ///
142        /// ```
143        /// use geo_types::{polygon, Polygon, MultiPolygon};
144        ///
145        /// let a_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7., y: 9.), (x: 0., y: 0.)];
146        /// let a = MultiPolygon::new(vec![a_el]);
147        /// let b_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7.01, y: 9.), (x: 0., y: 0.)];
148        /// let b = MultiPolygon::new(vec![b_el]);
149        ///
150        /// approx::assert_relative_eq!(a, b, max_relative=0.1);
151        /// approx::assert_relative_ne!(a, b, max_relative=0.001);
152        /// ```
153        #[inline]
154        fn relative_eq(
155            &self,
156            other: &Self,
157            epsilon: Self::Epsilon,
158            max_relative: Self::Epsilon,
159        ) -> bool {
160            if self.0.len() != other.0.len() {
161                return false;
162            }
163
164            let mut mp_zipper = self.iter().zip(other.iter());
165            mp_zipper.all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
166        }
167    }
168
169    impl<T> AbsDiffEq for MultiPolygon<T>
170    where
171        T: CoordNum + AbsDiffEq<Epsilon = T>,
172    {
173        type Epsilon = T;
174
175        #[inline]
176        fn default_epsilon() -> Self::Epsilon {
177            T::default_epsilon()
178        }
179
180        /// Equality assertion with an absolute limit.
181        ///
182        /// # Examples
183        ///
184        /// ```
185        /// use geo_types::{polygon, Polygon, MultiPolygon};
186        ///
187        /// let a_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7., y: 9.), (x: 0., y: 0.)];
188        /// let a = MultiPolygon::new(vec![a_el]);
189        /// let b_el: Polygon<f32> = polygon![(x: 0., y: 0.), (x: 5., y: 0.), (x: 7.01, y: 9.), (x: 0., y: 0.)];
190        /// let b = MultiPolygon::new(vec![b_el]);
191        ///
192        /// approx::abs_diff_eq!(a, b, epsilon=0.1);
193        /// approx::abs_diff_ne!(a, b, epsilon=0.001);
194        /// ```
195        #[inline]
196        fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
197            if self.0.len() != other.0.len() {
198                return false;
199            }
200
201            let mut mp_zipper = self.into_iter().zip(other);
202            mp_zipper.all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
203        }
204    }
205
206    impl<T> UlpsEq for MultiPolygon<T>
207    where
208        T: CoordNum + UlpsEq<Epsilon = T>,
209    {
210        fn default_max_ulps() -> u32 {
211            T::default_max_ulps()
212        }
213
214        fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
215            if self.0.len() != other.0.len() {
216                return false;
217            }
218            let mut mp_zipper = self.into_iter().zip(other);
219            mp_zipper.all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
220        }
221    }
222}
223
224#[cfg(any(
225    feature = "rstar_0_8",
226    feature = "rstar_0_9",
227    feature = "rstar_0_10",
228    feature = "rstar_0_11",
229    feature = "rstar_0_12"
230))]
231macro_rules! impl_rstar_multi_polygon {
232    ($rstar:ident) => {
233        impl<T> $rstar::RTreeObject for MultiPolygon<T>
234        where
235            T: ::num_traits::Float + ::$rstar::RTreeNum,
236        {
237            type Envelope = ::$rstar::AABB<$crate::Point<T>>;
238            fn envelope(&self) -> Self::Envelope {
239                use ::$rstar::Envelope;
240                self.iter()
241                    .map(|p| p.envelope())
242                    .fold(::$rstar::AABB::new_empty(), |a, b| a.merged(&b))
243            }
244        }
245    };
246}
247#[cfg(feature = "rstar_0_8")]
248impl_rstar_multi_polygon!(rstar_0_8);
249#[cfg(feature = "rstar_0_9")]
250impl_rstar_multi_polygon!(rstar_0_9);
251#[cfg(feature = "rstar_0_10")]
252impl_rstar_multi_polygon!(rstar_0_10);
253#[cfg(feature = "rstar_0_11")]
254impl_rstar_multi_polygon!(rstar_0_11);
255#[cfg(feature = "rstar_0_12")]
256impl_rstar_multi_polygon!(rstar_0_12);
257
258#[cfg(test)]
259mod test {
260    use super::*;
261    use crate::polygon;
262
263    #[test]
264    fn test_iter() {
265        let multi = MultiPolygon::new(vec![
266            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
267            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
268        ]);
269
270        let mut first = true;
271        for p in &multi {
272            if first {
273                assert_eq!(
274                    p,
275                    &polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)]
276                );
277                first = false;
278            } else {
279                assert_eq!(
280                    p,
281                    &polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)]
282                );
283            }
284        }
285
286        // Do it again to prove that `multi` wasn't `moved`.
287        first = true;
288        for p in &multi {
289            if first {
290                assert_eq!(
291                    p,
292                    &polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)]
293                );
294                first = false;
295            } else {
296                assert_eq!(
297                    p,
298                    &polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)]
299                );
300            }
301        }
302    }
303
304    #[cfg(feature = "multithreading")]
305    #[test]
306    fn test_par_iter() {
307        let multi = MultiPolygon::new(vec![
308            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
309            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
310        ]);
311        let mut multimut = MultiPolygon::new(vec![
312            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
313            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
314        ]);
315        multi.par_iter().for_each(|_p| ());
316        let _ = &multimut.par_iter_mut().for_each(|_p| ());
317        let _ = &multi.into_par_iter().for_each(|_p| ());
318        let _ = &mut multimut.par_iter_mut().for_each(|_p| ());
319    }
320    #[test]
321    fn test_iter_mut() {
322        let mut multi = MultiPolygon::new(vec![
323            polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
324            polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
325        ]);
326
327        for poly in &mut multi {
328            poly.exterior_mut(|exterior| {
329                for coord in exterior {
330                    coord.x += 1;
331                    coord.y += 1;
332                }
333            });
334        }
335
336        for poly in multi.iter_mut() {
337            poly.exterior_mut(|exterior| {
338                for coord in exterior {
339                    coord.x += 1;
340                    coord.y += 1;
341                }
342            });
343        }
344
345        let mut first = true;
346        for p in &multi {
347            if first {
348                assert_eq!(
349                    p,
350                    &polygon![(x: 2, y: 2), (x: 4, y: 2), (x: 3, y: 4), (x:2, y:2)]
351                );
352                first = false;
353            } else {
354                assert_eq!(
355                    p,
356                    &polygon![(x: 12, y: 12), (x: 14, y: 12), (x: 13, y: 14), (x:12, y:12)]
357                );
358            }
359        }
360    }
361}