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::default() 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 /// Number of geometries in this GeometryCollection
101 pub fn len(&self) -> usize {
102 self.0.len()
103 }
104
105 /// Is this GeometryCollection empty
106 pub fn is_empty(&self) -> bool {
107 self.0.is_empty()
108 }
109}
110
111/// **DO NOT USE!** Deprecated since 0.7.5.
112///
113/// Use `GeometryCollection::from(vec![geom])` instead.
114impl<T: CoordNum, IG: Into<Geometry<T>>> From<IG> for GeometryCollection<T> {
115 fn from(x: IG) -> Self {
116 Self(vec![x.into()])
117 }
118}
119
120impl<T: CoordNum, IG: Into<Geometry<T>>> From<Vec<IG>> for GeometryCollection<T> {
121 fn from(geoms: Vec<IG>) -> Self {
122 let geoms: Vec<Geometry<_>> = geoms.into_iter().map(Into::into).collect();
123 Self(geoms)
124 }
125}
126
127/// Collect Geometries (or what can be converted to a Geometry) into a GeometryCollection
128impl<T: CoordNum, IG: Into<Geometry<T>>> FromIterator<IG> for GeometryCollection<T> {
129 fn from_iter<I: IntoIterator<Item = IG>>(iter: I) -> Self {
130 Self(iter.into_iter().map(|g| g.into()).collect())
131 }
132}
133
134impl<T: CoordNum> Index<usize> for GeometryCollection<T> {
135 type Output = Geometry<T>;
136
137 fn index(&self, index: usize) -> &Geometry<T> {
138 self.0.index(index)
139 }
140}
141
142impl<T: CoordNum> IndexMut<usize> for GeometryCollection<T> {
143 fn index_mut(&mut self, index: usize) -> &mut Geometry<T> {
144 self.0.index_mut(index)
145 }
146}
147
148// structure helper for consuming iterator
149#[derive(Debug)]
150pub struct IntoIteratorHelper<T: CoordNum> {
151 iter: ::alloc::vec::IntoIter<Geometry<T>>,
152}
153
154// implement the IntoIterator trait for a consuming iterator. Iteration will
155// consume the GeometryCollection
156impl<T: CoordNum> IntoIterator for GeometryCollection<T> {
157 type Item = Geometry<T>;
158 type IntoIter = IntoIteratorHelper<T>;
159
160 // note that into_iter() is consuming self
161 fn into_iter(self) -> Self::IntoIter {
162 IntoIteratorHelper {
163 iter: self.0.into_iter(),
164 }
165 }
166}
167
168// implement Iterator trait for the helper struct, to be used by adapters
169impl<T: CoordNum> Iterator for IntoIteratorHelper<T> {
170 type Item = Geometry<T>;
171
172 // just return the reference
173 fn next(&mut self) -> Option<Self::Item> {
174 self.iter.next()
175 }
176}
177
178// structure helper for non-consuming iterator
179#[derive(Debug)]
180pub struct IterHelper<'a, T: CoordNum> {
181 iter: ::core::slice::Iter<'a, Geometry<T>>,
182}
183
184// implement the IntoIterator trait for a non-consuming iterator. Iteration will
185// borrow the GeometryCollection
186impl<'a, T: CoordNum> IntoIterator for &'a GeometryCollection<T> {
187 type Item = &'a Geometry<T>;
188 type IntoIter = IterHelper<'a, T>;
189
190 // note that into_iter() is consuming self
191 fn into_iter(self) -> Self::IntoIter {
192 IterHelper {
193 iter: self.0.iter(),
194 }
195 }
196}
197
198// implement the Iterator trait for the helper struct, to be used by adapters
199impl<'a, T: CoordNum> Iterator for IterHelper<'a, T> {
200 type Item = &'a Geometry<T>;
201
202 // just return the str reference
203 fn next(&mut self) -> Option<Self::Item> {
204 self.iter.next()
205 }
206}
207
208// structure helper for mutable non-consuming iterator
209#[derive(Debug)]
210pub struct IterMutHelper<'a, T: CoordNum> {
211 iter: ::core::slice::IterMut<'a, Geometry<T>>,
212}
213
214// implement the IntoIterator trait for a mutable non-consuming iterator. Iteration will
215// mutably borrow the GeometryCollection
216impl<'a, T: CoordNum> IntoIterator for &'a mut GeometryCollection<T> {
217 type Item = &'a mut Geometry<T>;
218 type IntoIter = IterMutHelper<'a, T>;
219
220 // note that into_iter() is consuming self
221 fn into_iter(self) -> Self::IntoIter {
222 IterMutHelper {
223 iter: self.0.iter_mut(),
224 }
225 }
226}
227
228// implement the Iterator trait for the helper struct, to be used by adapters
229impl<'a, T: CoordNum> Iterator for IterMutHelper<'a, T> {
230 type Item = &'a mut Geometry<T>;
231
232 // just return the str reference
233 fn next(&mut self) -> Option<Self::Item> {
234 self.iter.next()
235 }
236}
237
238impl<'a, T: CoordNum> GeometryCollection<T> {
239 pub fn iter(&'a self) -> IterHelper<'a, T> {
240 self.into_iter()
241 }
242
243 pub fn iter_mut(&'a mut self) -> IterMutHelper<'a, T> {
244 self.into_iter()
245 }
246}
247
248#[cfg(any(feature = "approx", test))]
249mod approx_integration {
250 use super::*;
251 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
252
253 impl<T> RelativeEq for GeometryCollection<T>
254 where
255 T: CoordNum + RelativeEq<Epsilon = T>,
256 {
257 #[inline]
258 fn default_max_relative() -> Self::Epsilon {
259 T::default_max_relative()
260 }
261
262 /// Equality assertion within a relative limit.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// use geo_types::{GeometryCollection, point};
268 ///
269 /// let a = GeometryCollection::new_from(vec![point![x: 1.0, y: 2.0].into()]);
270 /// let b = GeometryCollection::new_from(vec![point![x: 1.0, y: 2.01].into()]);
271 ///
272 /// approx::assert_relative_eq!(a, b, max_relative=0.1);
273 /// approx::assert_relative_ne!(a, b, max_relative=0.0001);
274 /// ```
275 #[inline]
276 fn relative_eq(
277 &self,
278 other: &Self,
279 epsilon: Self::Epsilon,
280 max_relative: Self::Epsilon,
281 ) -> bool {
282 if self.0.len() != other.0.len() {
283 return false;
284 }
285
286 self.iter()
287 .zip(other.iter())
288 .all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
289 }
290 }
291
292 impl<T> AbsDiffEq for GeometryCollection<T>
293 where
294 T: CoordNum + AbsDiffEq<Epsilon = T>,
295 {
296 type Epsilon = T;
297
298 #[inline]
299 fn default_epsilon() -> Self::Epsilon {
300 T::default_epsilon()
301 }
302
303 /// Equality assertion with an absolute limit.
304 ///
305 /// # Examples
306 ///
307 /// ```
308 /// use geo_types::{GeometryCollection, point};
309 ///
310 /// let a = GeometryCollection::new_from(vec![point![x: 0.0, y: 0.0].into()]);
311 /// let b = GeometryCollection::new_from(vec![point![x: 0.0, y: 0.1].into()]);
312 ///
313 /// approx::abs_diff_eq!(a, b, epsilon=0.1);
314 /// approx::abs_diff_ne!(a, b, epsilon=0.001);
315 /// ```
316 #[inline]
317 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
318 if self.0.len() != other.0.len() {
319 return false;
320 }
321
322 self.into_iter()
323 .zip(other)
324 .all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
325 }
326 }
327
328 impl<T> UlpsEq for GeometryCollection<T>
329 where
330 T: CoordNum + UlpsEq<Epsilon = T>,
331 {
332 fn default_max_ulps() -> u32 {
333 T::default_max_ulps()
334 }
335
336 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
337 if self.0.len() != other.0.len() {
338 return false;
339 }
340 self.into_iter()
341 .zip(other)
342 .all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
343 }
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use alloc::vec;
350
351 use crate::{GeometryCollection, Point};
352
353 #[test]
354 fn from_vec() {
355 let gc = GeometryCollection::from(vec![Point::new(1i32, 2)]);
356 let p = Point::try_from(gc[0].clone()).unwrap();
357 assert_eq!(p.y(), 2);
358 }
359}