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 {
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 #[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 #[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 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 let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
310 assert!(multi.relative_ne(&multi_undersized, 1., 1.));
311
312 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 let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
335 assert!(multi.abs_diff_ne(&multi_undersized, 1.));
336
337 let multi_oversized = wkt! { MULTIPOINT(0. 0.,10. 10.,10. 100.) };
339 assert!(multi.abs_diff_ne(&multi_oversized, 1.));
340 }
341}