geo_types/geometry/
multi_point.rs

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