geo_types/geometry/
multi_point.rs

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