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    /// Returns a MultiPoint with the given Points as elements
119    pub fn new(value: Vec<Point<T>>) -> Self {
120        Self(value)
121    }
122
123    /// Returns an empty MultiPoint
124    pub fn empty() -> Self {
125        Self::new(Vec::new())
126    }
127
128    pub fn len(&self) -> usize {
129        self.0.len()
130    }
131
132    pub fn is_empty(&self) -> bool {
133        self.0.is_empty()
134    }
135
136    pub fn iter(&self) -> impl Iterator<Item = &Point<T>> {
137        self.0.iter()
138    }
139
140    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Point<T>> {
141        self.0.iter_mut()
142    }
143}
144
145#[cfg(any(feature = "approx", test))]
146mod approx_integration {
147    use super::*;
148    use approx::{AbsDiffEq, RelativeEq, UlpsEq};
149
150    impl<T> RelativeEq for MultiPoint<T>
151    where
152        T: CoordNum + RelativeEq<Epsilon = T>,
153    {
154        #[inline]
155        fn default_max_relative() -> Self::Epsilon {
156            T::default_max_relative()
157        }
158
159        /// Equality assertion within a relative limit.
160        ///
161        /// # Examples
162        ///
163        /// ```
164        /// use geo_types::MultiPoint;
165        /// use geo_types::point;
166        ///
167        /// let a = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10., y: 10.]]);
168        /// let b = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10.001, y: 10.]]);
169        ///
170        /// approx::assert_relative_eq!(a, b, max_relative=0.1)
171        /// ```
172        #[inline]
173        fn relative_eq(
174            &self,
175            other: &Self,
176            epsilon: Self::Epsilon,
177            max_relative: Self::Epsilon,
178        ) -> bool {
179            if self.0.len() != other.0.len() {
180                return false;
181            }
182
183            let mut mp_zipper = self.iter().zip(other.iter());
184            mp_zipper.all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
185        }
186    }
187
188    impl<T> AbsDiffEq for MultiPoint<T>
189    where
190        T: CoordNum + AbsDiffEq<Epsilon = T>,
191    {
192        type Epsilon = T;
193
194        #[inline]
195        fn default_epsilon() -> Self::Epsilon {
196            T::default_epsilon()
197        }
198
199        /// Equality assertion with an absolute limit.
200        ///
201        /// # Examples
202        ///
203        /// ```
204        /// use geo_types::MultiPoint;
205        /// use geo_types::point;
206        ///
207        /// let a = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10., y: 10.]]);
208        /// let b = MultiPoint::new(vec![point![x: 0., y: 0.], point![x: 10.001, y: 10.]]);
209        ///
210        /// approx::abs_diff_eq!(a, b, epsilon=0.1);
211        /// ```
212        #[inline]
213        fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
214            if self.0.len() != other.0.len() {
215                return false;
216            }
217
218            let mut mp_zipper = self.into_iter().zip(other);
219            mp_zipper.all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
220        }
221    }
222
223    impl<T> UlpsEq for MultiPoint<T>
224    where
225        T: CoordNum + UlpsEq<Epsilon = T>,
226    {
227        fn default_max_ulps() -> u32 {
228            T::default_max_ulps()
229        }
230
231        fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
232            if self.0.len() != other.0.len() {
233                return false;
234            }
235            let mut mp_zipper = self.into_iter().zip(other);
236            mp_zipper.all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
237        }
238    }
239}
240
241#[cfg(test)]
242mod test {
243    use super::*;
244    use crate::{point, wkt};
245    use approx::{AbsDiffEq, RelativeEq};
246
247    #[test]
248    fn test_iter() {
249        let multi = wkt! { MULTIPOINT(0 0,10 10) };
250
251        let mut first = true;
252        for p in &multi {
253            if first {
254                assert_eq!(p, &point![x: 0, y: 0]);
255                first = false;
256            } else {
257                assert_eq!(p, &point![x: 10, y: 10]);
258            }
259        }
260
261        // Do it again to prove that `multi` wasn't `moved`.
262        first = true;
263        for p in &multi {
264            if first {
265                assert_eq!(p, &point![x: 0, y: 0]);
266                first = false;
267            } else {
268                assert_eq!(p, &point![x: 10, y: 10]);
269            }
270        }
271    }
272
273    #[test]
274    fn test_iter_mut() {
275        let mut multi = wkt! { MULTIPOINT(0 0,10 10) };
276
277        for point in &mut multi {
278            point.0.x += 1;
279            point.0.y += 1;
280        }
281
282        for point in multi.iter_mut() {
283            point.0.x += 1;
284            point.0.y += 1;
285        }
286
287        let mut first = true;
288        for p in &multi {
289            if first {
290                assert_eq!(p, &point![x: 2, y: 2]);
291                first = false;
292            } else {
293                assert_eq!(p, &point![x: 12, y: 12]);
294            }
295        }
296    }
297
298    #[test]
299    fn test_relative_eq() {
300        let delta = 1e-6;
301
302        let multi = wkt! { MULTIPOINT(0. 0.,10. 10.) };
303
304        let mut multi_x = multi.clone();
305        *multi_x.0[0].x_mut() += delta;
306
307        assert!(multi.relative_eq(&multi_x, 1e-2, 1e-2));
308        assert!(multi.relative_ne(&multi_x, 1e-12, 1e-12));
309
310        let mut multi_y = multi.clone();
311        *multi_y.0[0].y_mut() += delta;
312        assert!(multi.relative_eq(&multi_y, 1e-2, 1e-2));
313        assert!(multi.relative_ne(&multi_y, 1e-12, 1e-12));
314
315        // Under-sized but otherwise equal.
316        let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
317        assert!(multi.relative_ne(&multi_undersized, 1., 1.));
318
319        // Over-sized but otherwise equal.
320        let multi_oversized = wkt! { MULTIPOINT(0. 0.,10. 10.,10. 100.) };
321        assert!(multi.relative_ne(&multi_oversized, 1., 1.));
322    }
323
324    #[test]
325    fn test_abs_diff_eq() {
326        let delta = 1e-6;
327
328        let multi = wkt! { MULTIPOINT(0. 0.,10. 10.) };
329
330        let mut multi_x = multi.clone();
331        *multi_x.0[0].x_mut() += delta;
332        assert!(multi.abs_diff_eq(&multi_x, 1e-2));
333        assert!(multi.abs_diff_ne(&multi_x, 1e-12));
334
335        let mut multi_y = multi.clone();
336        *multi_y.0[0].y_mut() += delta;
337        assert!(multi.abs_diff_eq(&multi_y, 1e-2));
338        assert!(multi.abs_diff_ne(&multi_y, 1e-12));
339
340        // Under-sized but otherwise equal.
341        let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
342        assert!(multi.abs_diff_ne(&multi_undersized, 1.));
343
344        // Over-sized but otherwise equal.
345        let multi_oversized = wkt! { MULTIPOINT(0. 0.,10. 10.,10. 100.) };
346        assert!(multi.abs_diff_ne(&multi_oversized, 1.));
347    }
348
349    #[test]
350    fn empty() {
351        let empty = MultiPoint::<f64>::empty();
352        let empty_2 = wkt! { MULTIPOINT EMPTY };
353        assert_eq!(empty, empty_2);
354    }
355}