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#[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 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 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 fn from_iter<I: IntoIterator<Item = IP>>(iter: I) -> Self {
57 Self(iter.into_iter().map(|p| p.into()).collect())
58 }
59}
60
61impl<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 pub fn new(value: Vec<Point<T>>) -> Self {
136 Self(value)
137 }
138
139 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 #[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 #[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 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 let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
333 assert!(multi.relative_ne(&multi_undersized, 1., 1.));
334
335 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 let multi_undersized = wkt! { MULTIPOINT(0. 0.) };
358 assert!(multi.abs_diff_ne(&multi_undersized, 1.));
359
360 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 assert_eq!(mp[0], point! { x: 0., y: 0. });
378 assert_eq!(mp[1], point! { x: 1., y: 1. });
379
380 mp[1] = point! { x: 100., y: 100. };
382 assert_eq!(mp[1], point! { x: 100., y: 100. });
383
384 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}