geo_types/geometry/
geometry_collection.rs1use crate::{CoordNum, Geometry};
2
3use alloc::vec;
4use alloc::vec::Vec;
5use core::iter::FromIterator;
6use core::ops::{Index, IndexMut};
7use core::slice::SliceIndex;
8
9#[derive(Eq, PartialEq, Clone, Hash)]
74#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
75pub struct GeometryCollection<T: CoordNum = f64>(pub Vec<Geometry<T>>);
76
77impl<T: CoordNum> Default for GeometryCollection<T> {
80 fn default() -> Self {
81 Self(Vec::new())
82 }
83}
84
85impl<T: CoordNum> GeometryCollection<T> {
86 #[deprecated(
88 note = "Will be replaced with a parametrized version in upcoming version. Use GeometryCollection::empty() instead"
89 )]
90 pub fn new() -> Self {
91 GeometryCollection::default()
92 }
93
94 pub fn new_from(value: Vec<Geometry<T>>) -> Self {
98 Self(value)
99 }
100
101 pub fn empty() -> Self {
103 Self(Vec::new())
104 }
105
106 pub fn len(&self) -> usize {
108 self.0.len()
109 }
110
111 pub fn is_empty(&self) -> bool {
113 self.0.is_empty()
114 }
115}
116
117impl<T: CoordNum, IG: Into<Geometry<T>>> From<IG> for GeometryCollection<T> {
121 fn from(x: IG) -> Self {
122 Self(vec![x.into()])
123 }
124}
125
126impl<T: CoordNum, IG: Into<Geometry<T>>> From<Vec<IG>> for GeometryCollection<T> {
127 fn from(geoms: Vec<IG>) -> Self {
128 let geoms: Vec<Geometry<_>> = geoms.into_iter().map(Into::into).collect();
129 Self(geoms)
130 }
131}
132
133impl<T: CoordNum, IG: Into<Geometry<T>>> FromIterator<IG> for GeometryCollection<T> {
135 fn from_iter<I: IntoIterator<Item = IG>>(iter: I) -> Self {
136 Self(iter.into_iter().map(|g| g.into()).collect())
137 }
138}
139
140impl<T: CoordNum, I: SliceIndex<[Geometry<T>]>> Index<I> for GeometryCollection<T> {
141 type Output = I::Output;
142
143 fn index(&self, index: I) -> &I::Output {
144 self.0.index(index)
145 }
146}
147
148impl<T: CoordNum, I: SliceIndex<[Geometry<T>]>> IndexMut<I> for GeometryCollection<T> {
149 fn index_mut(&mut self, index: I) -> &mut I::Output {
150 self.0.index_mut(index)
151 }
152}
153
154#[derive(Debug)]
156pub struct IntoIteratorHelper<T: CoordNum> {
157 iter: ::alloc::vec::IntoIter<Geometry<T>>,
158}
159
160impl<T: CoordNum> IntoIterator for GeometryCollection<T> {
163 type Item = Geometry<T>;
164 type IntoIter = IntoIteratorHelper<T>;
165
166 fn into_iter(self) -> Self::IntoIter {
168 IntoIteratorHelper {
169 iter: self.0.into_iter(),
170 }
171 }
172}
173
174impl<T: CoordNum> Iterator for IntoIteratorHelper<T> {
176 type Item = Geometry<T>;
177
178 fn next(&mut self) -> Option<Self::Item> {
180 self.iter.next()
181 }
182}
183
184#[derive(Debug)]
186pub struct IterHelper<'a, T: CoordNum> {
187 iter: ::core::slice::Iter<'a, Geometry<T>>,
188}
189
190impl<'a, T: CoordNum> IntoIterator for &'a GeometryCollection<T> {
193 type Item = &'a Geometry<T>;
194 type IntoIter = IterHelper<'a, T>;
195
196 fn into_iter(self) -> Self::IntoIter {
198 IterHelper {
199 iter: self.0.iter(),
200 }
201 }
202}
203
204impl<'a, T: CoordNum> Iterator for IterHelper<'a, T> {
206 type Item = &'a Geometry<T>;
207
208 fn next(&mut self) -> Option<Self::Item> {
210 self.iter.next()
211 }
212}
213
214#[derive(Debug)]
216pub struct IterMutHelper<'a, T: CoordNum> {
217 iter: ::core::slice::IterMut<'a, Geometry<T>>,
218}
219
220impl<'a, T: CoordNum> IntoIterator for &'a mut GeometryCollection<T> {
223 type Item = &'a mut Geometry<T>;
224 type IntoIter = IterMutHelper<'a, T>;
225
226 fn into_iter(self) -> Self::IntoIter {
228 IterMutHelper {
229 iter: self.0.iter_mut(),
230 }
231 }
232}
233
234impl<'a, T: CoordNum> Iterator for IterMutHelper<'a, T> {
236 type Item = &'a mut Geometry<T>;
237
238 fn next(&mut self) -> Option<Self::Item> {
240 self.iter.next()
241 }
242}
243
244impl<'a, T: CoordNum> GeometryCollection<T> {
245 pub fn iter(&'a self) -> IterHelper<'a, T> {
246 self.into_iter()
247 }
248
249 pub fn iter_mut(&'a mut self) -> IterMutHelper<'a, T> {
250 self.into_iter()
251 }
252}
253
254#[cfg(any(feature = "approx", test))]
255mod approx_integration {
256 use super::*;
257 use approx::{AbsDiffEq, RelativeEq, UlpsEq};
258
259 impl<T> RelativeEq for GeometryCollection<T>
260 where
261 T: CoordNum + RelativeEq<Epsilon = T>,
262 {
263 #[inline]
264 fn default_max_relative() -> Self::Epsilon {
265 T::default_max_relative()
266 }
267
268 #[inline]
282 fn relative_eq(
283 &self,
284 other: &Self,
285 epsilon: Self::Epsilon,
286 max_relative: Self::Epsilon,
287 ) -> bool {
288 if self.0.len() != other.0.len() {
289 return false;
290 }
291
292 self.iter()
293 .zip(other.iter())
294 .all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
295 }
296 }
297
298 impl<T> AbsDiffEq for GeometryCollection<T>
299 where
300 T: CoordNum + AbsDiffEq<Epsilon = T>,
301 {
302 type Epsilon = T;
303
304 #[inline]
305 fn default_epsilon() -> Self::Epsilon {
306 T::default_epsilon()
307 }
308
309 #[inline]
323 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
324 if self.0.len() != other.0.len() {
325 return false;
326 }
327
328 self.into_iter()
329 .zip(other)
330 .all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
331 }
332 }
333
334 impl<T> UlpsEq for GeometryCollection<T>
335 where
336 T: CoordNum + UlpsEq<Epsilon = T>,
337 {
338 fn default_max_ulps() -> u32 {
339 T::default_max_ulps()
340 }
341
342 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
343 if self.0.len() != other.0.len() {
344 return false;
345 }
346 self.into_iter()
347 .zip(other)
348 .all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
349 }
350 }
351}
352
353#[cfg(test)]
354mod tests {
355 use alloc::vec;
356
357 use crate::{point, wkt, GeometryCollection, Point};
358
359 #[test]
360 fn from_vec() {
361 let gc = GeometryCollection::from(vec![Point::new(1i32, 2)]);
362 let p = Point::try_from(gc[0].clone()).unwrap();
363 assert_eq!(p.y(), 2);
364 }
365
366 #[test]
367 fn empty() {
368 let empty = GeometryCollection::<f64>::empty();
369 let empty_2 = wkt! { GEOMETRYCOLLECTION EMPTY };
370 assert_eq!(empty, empty_2);
371 }
372
373 #[test]
374 fn test_indexing() {
375 let mut gc = wkt! { GEOMETRYCOLLECTION(POINT(0. 0.), POINT(1. 1.), POINT(2. 2.)) };
376
377 assert_eq!(gc[0], point! { x: 0., y: 0. }.into());
379 assert_eq!(gc[1], point! { x: 1., y: 1. }.into());
380
381 gc[1] = point! { x: 100., y: 100. }.into();
383 assert_eq!(gc[1], point! { x: 100., y: 100. }.into());
384
385 assert_eq!(
387 gc[0..2],
388 [
389 point! { x: 0., y: 0. }.into(),
390 point! { x: 100., y: 100. }.into()
391 ]
392 );
393 }
394
395 #[test]
396 #[should_panic]
397 fn test_indexing_out_of_bounds() {
398 let gc = wkt! { GEOMETRYCOLLECTION(POINT(0. 0.), POINT(1. 1.)) };
399 let _ = gc[2];
400 }
401}