geo_types/geometry/
multi_point.rs1use crate::{CoordNum, Point};
2
3use alloc::vec;
4use alloc::vec::Vec;
5use core::iter::FromIterator;
6#[cfg(feature = "multithreading")]
7use rayon::prelude::*;
8
9#[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 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 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 fn from_iter<I: IntoIterator<Item = IP>>(iter: I) -> Self {
55 Self(iter.into_iter().map(|p| p.into()).collect())
56 }
57}
58
59impl<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 {
120 Self(value)
121 }
122
123 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 #[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 #[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 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 let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
317 assert!(multi.relative_ne(&multi_undersized, 1., 1.));
318
319 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 let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
342 assert!(multi.abs_diff_ne(&multi_undersized, 1.));
343
344 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}