geo_types/geometry/
geometry_collection.rs

1use crate::{CoordNum, Geometry};
2
3use alloc::vec;
4use alloc::vec::Vec;
5use core::iter::FromIterator;
6use core::ops::{Index, IndexMut};
7
8/// A collection of [`Geometry`](enum.Geometry.html) types.
9///
10/// It can be created from a `Vec` of Geometries, or from an Iterator which yields Geometries.
11///
12/// Looping over this object yields its component **Geometry
13/// enum members** (_not_ the underlying geometry
14/// primitives), and it supports iteration and indexing as
15/// well as the various
16/// [`MapCoords`](algorithm/map_coords/index.html)
17/// functions, which _are_ directly applied to the
18/// underlying geometry primitives.
19///
20/// # Examples
21/// ## Looping
22///
23/// ```
24/// use std::convert::TryFrom;
25/// use geo_types::{Point, point, Geometry, GeometryCollection};
26/// let p = point!(x: 1.0, y: 1.0);
27/// let pe = Geometry::Point(p);
28/// let gc = GeometryCollection::new_from(vec![pe]);
29/// for geom in gc {
30///     println!("{:?}", Point::try_from(geom).unwrap().x());
31/// }
32/// ```
33/// ## Implements `iter()`
34///
35/// ```
36/// use std::convert::TryFrom;
37/// use geo_types::{Point, point, Geometry, GeometryCollection};
38/// let p = point!(x: 1.0, y: 1.0);
39/// let pe = Geometry::Point(p);
40/// let gc = GeometryCollection::new_from(vec![pe]);
41/// gc.iter().for_each(|geom| println!("{:?}", geom));
42/// ```
43///
44/// ## Mutable Iteration
45///
46/// ```
47/// use std::convert::TryFrom;
48/// use geo_types::{Point, point, Geometry, GeometryCollection};
49/// let p = point!(x: 1.0, y: 1.0);
50/// let pe = Geometry::Point(p);
51/// let mut gc = GeometryCollection::new_from(vec![pe]);
52/// gc.iter_mut().for_each(|geom| {
53///    if let Geometry::Point(p) = geom {
54///        p.set_x(0.2);
55///    }
56/// });
57/// let updated = gc[0].clone();
58/// assert_eq!(Point::try_from(updated).unwrap().x(), 0.2);
59/// ```
60///
61/// ## Indexing
62///
63/// ```
64/// use std::convert::TryFrom;
65/// use geo_types::{Point, point, Geometry, GeometryCollection};
66/// let p = point!(x: 1.0, y: 1.0);
67/// let pe = Geometry::Point(p);
68/// let gc = GeometryCollection::new_from(vec![pe]);
69/// println!("{:?}", gc[0]);
70/// ```
71///
72#[derive(Eq, PartialEq, Clone, Hash)]
73#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
74pub struct GeometryCollection<T: CoordNum = f64>(pub Vec<Geometry<T>>);
75
76// Implementing Default by hand because T does not have Default restriction
77// todo: consider adding Default as a CoordNum requirement
78impl<T: CoordNum> Default for GeometryCollection<T> {
79    fn default() -> Self {
80        Self(Vec::new())
81    }
82}
83
84impl<T: CoordNum> GeometryCollection<T> {
85    /// Return an empty GeometryCollection
86    #[deprecated(
87        note = "Will be replaced with a parametrized version in upcoming version. Use GeometryCollection::empty() instead"
88    )]
89    pub fn new() -> Self {
90        GeometryCollection::default()
91    }
92
93    /// DO NOT USE!
94    /// This fn will be renamed to `new` in the upcoming version.
95    /// This fn is not marked as deprecated because it would require extensive refactoring of the geo code.
96    pub fn new_from(value: Vec<Geometry<T>>) -> Self {
97        Self(value)
98    }
99
100    /// Returns an empty GeometryCollection
101    pub fn empty() -> Self {
102        Self(Vec::new())
103    }
104
105    /// Number of geometries in this GeometryCollection
106    pub fn len(&self) -> usize {
107        self.0.len()
108    }
109
110    /// Is this GeometryCollection empty
111    pub fn is_empty(&self) -> bool {
112        self.0.is_empty()
113    }
114}
115
116/// **DO NOT USE!** Deprecated since 0.7.5.
117///
118/// Use `GeometryCollection::from(vec![geom])` instead.
119impl<T: CoordNum, IG: Into<Geometry<T>>> From<IG> for GeometryCollection<T> {
120    fn from(x: IG) -> Self {
121        Self(vec![x.into()])
122    }
123}
124
125impl<T: CoordNum, IG: Into<Geometry<T>>> From<Vec<IG>> for GeometryCollection<T> {
126    fn from(geoms: Vec<IG>) -> Self {
127        let geoms: Vec<Geometry<_>> = geoms.into_iter().map(Into::into).collect();
128        Self(geoms)
129    }
130}
131
132/// Collect Geometries (or what can be converted to a Geometry) into a GeometryCollection
133impl<T: CoordNum, IG: Into<Geometry<T>>> FromIterator<IG> for GeometryCollection<T> {
134    fn from_iter<I: IntoIterator<Item = IG>>(iter: I) -> Self {
135        Self(iter.into_iter().map(|g| g.into()).collect())
136    }
137}
138
139impl<T: CoordNum> Index<usize> for GeometryCollection<T> {
140    type Output = Geometry<T>;
141
142    fn index(&self, index: usize) -> &Geometry<T> {
143        self.0.index(index)
144    }
145}
146
147impl<T: CoordNum> IndexMut<usize> for GeometryCollection<T> {
148    fn index_mut(&mut self, index: usize) -> &mut Geometry<T> {
149        self.0.index_mut(index)
150    }
151}
152
153// structure helper for consuming iterator
154#[derive(Debug)]
155pub struct IntoIteratorHelper<T: CoordNum> {
156    iter: ::alloc::vec::IntoIter<Geometry<T>>,
157}
158
159// implement the IntoIterator trait for a consuming iterator. Iteration will
160// consume the GeometryCollection
161impl<T: CoordNum> IntoIterator for GeometryCollection<T> {
162    type Item = Geometry<T>;
163    type IntoIter = IntoIteratorHelper<T>;
164
165    // note that into_iter() is consuming self
166    fn into_iter(self) -> Self::IntoIter {
167        IntoIteratorHelper {
168            iter: self.0.into_iter(),
169        }
170    }
171}
172
173// implement Iterator trait for the helper struct, to be used by adapters
174impl<T: CoordNum> Iterator for IntoIteratorHelper<T> {
175    type Item = Geometry<T>;
176
177    // just return the reference
178    fn next(&mut self) -> Option<Self::Item> {
179        self.iter.next()
180    }
181}
182
183// structure helper for non-consuming iterator
184#[derive(Debug)]
185pub struct IterHelper<'a, T: CoordNum> {
186    iter: ::core::slice::Iter<'a, Geometry<T>>,
187}
188
189// implement the IntoIterator trait for a non-consuming iterator. Iteration will
190// borrow the GeometryCollection
191impl<'a, T: CoordNum> IntoIterator for &'a GeometryCollection<T> {
192    type Item = &'a Geometry<T>;
193    type IntoIter = IterHelper<'a, T>;
194
195    // note that into_iter() is consuming self
196    fn into_iter(self) -> Self::IntoIter {
197        IterHelper {
198            iter: self.0.iter(),
199        }
200    }
201}
202
203// implement the Iterator trait for the helper struct, to be used by adapters
204impl<'a, T: CoordNum> Iterator for IterHelper<'a, T> {
205    type Item = &'a Geometry<T>;
206
207    // just return the str reference
208    fn next(&mut self) -> Option<Self::Item> {
209        self.iter.next()
210    }
211}
212
213// structure helper for mutable non-consuming iterator
214#[derive(Debug)]
215pub struct IterMutHelper<'a, T: CoordNum> {
216    iter: ::core::slice::IterMut<'a, Geometry<T>>,
217}
218
219// implement the IntoIterator trait for a mutable non-consuming iterator. Iteration will
220// mutably borrow the GeometryCollection
221impl<'a, T: CoordNum> IntoIterator for &'a mut GeometryCollection<T> {
222    type Item = &'a mut Geometry<T>;
223    type IntoIter = IterMutHelper<'a, T>;
224
225    // note that into_iter() is consuming self
226    fn into_iter(self) -> Self::IntoIter {
227        IterMutHelper {
228            iter: self.0.iter_mut(),
229        }
230    }
231}
232
233// implement the Iterator trait for the helper struct, to be used by adapters
234impl<'a, T: CoordNum> Iterator for IterMutHelper<'a, T> {
235    type Item = &'a mut Geometry<T>;
236
237    // just return the str reference
238    fn next(&mut self) -> Option<Self::Item> {
239        self.iter.next()
240    }
241}
242
243impl<'a, T: CoordNum> GeometryCollection<T> {
244    pub fn iter(&'a self) -> IterHelper<'a, T> {
245        self.into_iter()
246    }
247
248    pub fn iter_mut(&'a mut self) -> IterMutHelper<'a, T> {
249        self.into_iter()
250    }
251}
252
253#[cfg(any(feature = "approx", test))]
254mod approx_integration {
255    use super::*;
256    use approx::{AbsDiffEq, RelativeEq, UlpsEq};
257
258    impl<T> RelativeEq for GeometryCollection<T>
259    where
260        T: CoordNum + RelativeEq<Epsilon = T>,
261    {
262        #[inline]
263        fn default_max_relative() -> Self::Epsilon {
264            T::default_max_relative()
265        }
266
267        /// Equality assertion within a relative limit.
268        ///
269        /// # Examples
270        ///
271        /// ```
272        /// use geo_types::{GeometryCollection, point};
273        ///
274        /// let a = GeometryCollection::new_from(vec![point![x: 1.0, y: 2.0].into()]);
275        /// let b = GeometryCollection::new_from(vec![point![x: 1.0, y: 2.01].into()]);
276        ///
277        /// approx::assert_relative_eq!(a, b, max_relative=0.1);
278        /// approx::assert_relative_ne!(a, b, max_relative=0.0001);
279        /// ```
280        #[inline]
281        fn relative_eq(
282            &self,
283            other: &Self,
284            epsilon: Self::Epsilon,
285            max_relative: Self::Epsilon,
286        ) -> bool {
287            if self.0.len() != other.0.len() {
288                return false;
289            }
290
291            self.iter()
292                .zip(other.iter())
293                .all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
294        }
295    }
296
297    impl<T> AbsDiffEq for GeometryCollection<T>
298    where
299        T: CoordNum + AbsDiffEq<Epsilon = T>,
300    {
301        type Epsilon = T;
302
303        #[inline]
304        fn default_epsilon() -> Self::Epsilon {
305            T::default_epsilon()
306        }
307
308        /// Equality assertion with an absolute limit.
309        ///
310        /// # Examples
311        ///
312        /// ```
313        /// use geo_types::{GeometryCollection, point};
314        ///
315        /// let a = GeometryCollection::new_from(vec![point![x: 0.0, y: 0.0].into()]);
316        /// let b = GeometryCollection::new_from(vec![point![x: 0.0, y: 0.1].into()]);
317        ///
318        /// approx::abs_diff_eq!(a, b, epsilon=0.1);
319        /// approx::abs_diff_ne!(a, b, epsilon=0.001);
320        /// ```
321        #[inline]
322        fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
323            if self.0.len() != other.0.len() {
324                return false;
325            }
326
327            self.into_iter()
328                .zip(other)
329                .all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
330        }
331    }
332
333    impl<T> UlpsEq for GeometryCollection<T>
334    where
335        T: CoordNum + UlpsEq<Epsilon = T>,
336    {
337        fn default_max_ulps() -> u32 {
338            T::default_max_ulps()
339        }
340
341        fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
342            if self.0.len() != other.0.len() {
343                return false;
344            }
345            self.into_iter()
346                .zip(other)
347                .all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
348        }
349    }
350}
351
352#[cfg(test)]
353mod tests {
354    use alloc::vec;
355
356    use crate::{wkt, GeometryCollection, Point};
357
358    #[test]
359    fn from_vec() {
360        let gc = GeometryCollection::from(vec![Point::new(1i32, 2)]);
361        let p = Point::try_from(gc[0].clone()).unwrap();
362        assert_eq!(p.y(), 2);
363    }
364
365    #[test]
366    fn empty() {
367        let empty = GeometryCollection::<f64>::empty();
368        let empty_2 = wkt! { GEOMETRYCOLLECTION EMPTY };
369        assert_eq!(empty, empty_2);
370    }
371}