1use crate::{CoordNum, Polygon};
2
3use alloc::vec;
4use alloc::vec::Vec;
5
6use core::iter::FromIterator;
7use core::ops::{Index, IndexMut};
8use core::slice::SliceIndex;
9#[cfg(feature = "multithreading")]
10use rayon::prelude::*;
11
12#[derive(Eq, PartialEq, Clone, Hash)]
33#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
34pub struct MultiPolygon<T: CoordNum = f64>(pub Vec<Polygon<T>>);
35
36impl<T: CoordNum, IP: Into<Polygon<T>>> From<IP> for MultiPolygon<T> {
37 fn from(x: IP) -> Self {
38 Self(vec![x.into()])
39 }
40}
41
42impl<T: CoordNum, IP: Into<Polygon<T>>> From<Vec<IP>> for MultiPolygon<T> {
43 fn from(x: Vec<IP>) -> Self {
44 Self(x.into_iter().map(|p| p.into()).collect())
45 }
46}
47
48impl<T: CoordNum, IP: Into<Polygon<T>>> FromIterator<IP> for MultiPolygon<T> {
49 fn from_iter<I: IntoIterator<Item = IP>>(iter: I) -> Self {
50 Self(iter.into_iter().map(|p| p.into()).collect())
51 }
52}
53
54impl<T: CoordNum> IntoIterator for MultiPolygon<T> {
55 type Item = Polygon<T>;
56 type IntoIter = ::alloc::vec::IntoIter<Polygon<T>>;
57
58 fn into_iter(self) -> Self::IntoIter {
59 self.0.into_iter()
60 }
61}
62
63impl<'a, T: CoordNum> IntoIterator for &'a MultiPolygon<T> {
64 type Item = &'a Polygon<T>;
65 type IntoIter = ::alloc::slice::Iter<'a, Polygon<T>>;
66
67 fn into_iter(self) -> Self::IntoIter {
68 (self.0).iter()
69 }
70}
71
72impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPolygon<T> {
73 type Item = &'a mut Polygon<T>;
74 type IntoIter = ::alloc::slice::IterMut<'a, Polygon<T>>;
75
76 fn into_iter(self) -> Self::IntoIter {
77 (self.0).iter_mut()
78 }
79}
80
81#[cfg(feature = "multithreading")]
82impl<T: CoordNum + Send> IntoParallelIterator for MultiPolygon<T> {
83 type Item = Polygon<T>;
84 type Iter = rayon::vec::IntoIter<Polygon<T>>;
85
86 fn into_par_iter(self) -> Self::Iter {
87 self.0.into_par_iter()
88 }
89}
90
91#[cfg(feature = "multithreading")]
92impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiPolygon<T> {
93 type Item = &'a Polygon<T>;
94 type Iter = rayon::slice::Iter<'a, Polygon<T>>;
95
96 fn into_par_iter(self) -> Self::Iter {
97 self.0.par_iter()
98 }
99}
100
101#[cfg(feature = "multithreading")]
102impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiPolygon<T> {
103 type Item = &'a mut Polygon<T>;
104 type Iter = rayon::slice::IterMut<'a, Polygon<T>>;
105
106 fn into_par_iter(self) -> Self::Iter {
107 self.0.par_iter_mut()
108 }
109}
110
111impl<T: CoordNum> MultiPolygon<T> {
112 pub fn new(value: Vec<Polygon<T>>) -> Self {
114 Self(value)
115 }
116
117 pub fn empty() -> Self {
119 Self(Vec::new())
120 }
121
122 pub fn iter(&self) -> impl Iterator<Item = &Polygon<T>> {
123 self.0.iter()
124 }
125
126 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Polygon<T>> {
127 self.0.iter_mut()
128 }
129}
130
131impl<T: CoordNum, I: SliceIndex<[Polygon<T>]>> Index<I> for MultiPolygon<T> {
132 type Output = I::Output;
133
134 fn index(&self, index: I) -> &I::Output {
135 self.0.index(index)
136 }
137}
138
139impl<T: CoordNum, I: SliceIndex<[Polygon<T>]>> IndexMut<I> for MultiPolygon<T> {
140 fn index_mut(&mut self, index: I) -> &mut I::Output {
141 self.0.index_mut(index)
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 MultiPolygon<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]
175 fn relative_eq(
176 &self,
177 other: &Self,
178 epsilon: Self::Epsilon,
179 max_relative: Self::Epsilon,
180 ) -> bool {
181 if self.0.len() != other.0.len() {
182 return false;
183 }
184
185 let mut mp_zipper = self.iter().zip(other.iter());
186 mp_zipper.all(|(lhs, rhs)| lhs.relative_eq(rhs, epsilon, max_relative))
187 }
188 }
189
190 impl<T> AbsDiffEq for MultiPolygon<T>
191 where
192 T: CoordNum + AbsDiffEq<Epsilon = T>,
193 {
194 type Epsilon = T;
195
196 #[inline]
197 fn default_epsilon() -> Self::Epsilon {
198 T::default_epsilon()
199 }
200
201 #[inline]
217 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
218 if self.0.len() != other.0.len() {
219 return false;
220 }
221
222 let mut mp_zipper = self.into_iter().zip(other);
223 mp_zipper.all(|(lhs, rhs)| lhs.abs_diff_eq(rhs, epsilon))
224 }
225 }
226
227 impl<T> UlpsEq for MultiPolygon<T>
228 where
229 T: CoordNum + UlpsEq<Epsilon = T>,
230 {
231 fn default_max_ulps() -> u32 {
232 T::default_max_ulps()
233 }
234
235 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
236 if self.0.len() != other.0.len() {
237 return false;
238 }
239 let mut mp_zipper = self.into_iter().zip(other);
240 mp_zipper.all(|(lhs, rhs)| lhs.ulps_eq(rhs, epsilon, max_ulps))
241 }
242 }
243}
244
245#[cfg(any(
246 feature = "rstar_0_8",
247 feature = "rstar_0_9",
248 feature = "rstar_0_10",
249 feature = "rstar_0_11",
250 feature = "rstar_0_12"
251))]
252macro_rules! impl_rstar_multi_polygon {
253 ($rstar:ident) => {
254 impl<T> $rstar::RTreeObject for MultiPolygon<T>
255 where
256 T: ::num_traits::Float + ::$rstar::RTreeNum,
257 {
258 type Envelope = ::$rstar::AABB<$crate::Point<T>>;
259 fn envelope(&self) -> Self::Envelope {
260 use ::$rstar::Envelope;
261 self.iter()
262 .map(|p| p.envelope())
263 .fold(::$rstar::AABB::new_empty(), |a, b| a.merged(&b))
264 }
265 }
266 };
267}
268#[cfg(feature = "rstar_0_8")]
269impl_rstar_multi_polygon!(rstar_0_8);
270#[cfg(feature = "rstar_0_9")]
271impl_rstar_multi_polygon!(rstar_0_9);
272#[cfg(feature = "rstar_0_10")]
273impl_rstar_multi_polygon!(rstar_0_10);
274#[cfg(feature = "rstar_0_11")]
275impl_rstar_multi_polygon!(rstar_0_11);
276#[cfg(feature = "rstar_0_12")]
277impl_rstar_multi_polygon!(rstar_0_12);
278
279#[cfg(test)]
280mod test {
281 use super::*;
282 use crate::{polygon, wkt};
283
284 #[test]
285 fn test_iter() {
286 let multi = MultiPolygon::new(vec![
287 polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
288 polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
289 ]);
290
291 let mut first = true;
292 for p in &multi {
293 if first {
294 assert_eq!(
295 p,
296 &polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)]
297 );
298 first = false;
299 } else {
300 assert_eq!(
301 p,
302 &polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)]
303 );
304 }
305 }
306
307 first = true;
309 for p in &multi {
310 if first {
311 assert_eq!(
312 p,
313 &polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)]
314 );
315 first = false;
316 } else {
317 assert_eq!(
318 p,
319 &polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)]
320 );
321 }
322 }
323 }
324
325 #[cfg(feature = "multithreading")]
326 #[test]
327 fn test_par_iter() {
328 let multi = MultiPolygon::new(vec![
329 polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
330 polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
331 ]);
332 let mut multimut = MultiPolygon::new(vec![
333 polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
334 polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
335 ]);
336 multi.par_iter().for_each(|_p| ());
337 let _ = &multimut.par_iter_mut().for_each(|_p| ());
338 let _ = &multi.into_par_iter().for_each(|_p| ());
339 let _ = &mut multimut.par_iter_mut().for_each(|_p| ());
340 }
341 #[test]
342 fn test_iter_mut() {
343 let mut multi = MultiPolygon::new(vec![
344 polygon![(x: 0, y: 0), (x: 2, y: 0), (x: 1, y: 2), (x:0, y:0)],
345 polygon![(x: 10, y: 10), (x: 12, y: 10), (x: 11, y: 12), (x:10, y:10)],
346 ]);
347
348 for poly in &mut multi {
349 poly.exterior_mut(|exterior| {
350 for coord in exterior {
351 coord.x += 1;
352 coord.y += 1;
353 }
354 });
355 }
356
357 for poly in multi.iter_mut() {
358 poly.exterior_mut(|exterior| {
359 for coord in exterior {
360 coord.x += 1;
361 coord.y += 1;
362 }
363 });
364 }
365
366 let mut first = true;
367 for p in &multi {
368 if first {
369 assert_eq!(
370 p,
371 &polygon![(x: 2, y: 2), (x: 4, y: 2), (x: 3, y: 4), (x:2, y:2)]
372 );
373 first = false;
374 } else {
375 assert_eq!(
376 p,
377 &polygon![(x: 12, y: 12), (x: 14, y: 12), (x: 13, y: 14), (x:12, y:12)]
378 );
379 }
380 }
381 }
382
383 #[test]
384 fn empty() {
385 let empty = MultiPolygon::<f64>::empty();
386 let empty_2 = wkt! { MULTIPOLYGON EMPTY };
387 assert_eq!(empty, empty_2);
388 }
389
390 #[test]
391 fn test_indexing() {
392 let mut mp = wkt! { MULTIPOLYGON(((0. 0., 1. 0., 1. 1., 0. 0.)), ((2. 2., 3. 2., 3. 3., 2. 2.)), ((4. 4., 5. 4., 5. 5., 4. 4.))) };
393
394 assert_eq!(mp[0], wkt! { POLYGON((0. 0., 1. 0., 1. 1., 0. 0.)) });
396 assert_eq!(mp[1], wkt! { POLYGON((2. 2., 3. 2., 3. 3., 2. 2.)) });
397
398 mp[1] = wkt! { POLYGON((100. 100., 101. 100., 101. 101., 100. 100.)) };
400 assert_eq!(
401 mp[1],
402 wkt! { POLYGON((100. 100., 101. 100., 101. 101., 100. 100.)) }
403 );
404
405 assert_eq!(
407 mp[0..2],
408 [
409 wkt! { POLYGON((0. 0., 1. 0., 1. 1., 0. 0.)) },
410 wkt! { POLYGON((100. 100., 101. 100., 101. 101., 100. 100.)) }
411 ]
412 );
413 }
414
415 #[test]
416 #[should_panic]
417 fn test_indexing_out_of_bounds() {
418 let mp =
419 wkt! { MULTIPOLYGON(((0. 0., 1. 0., 1. 1., 0. 0.)), ((2. 2., 3. 2., 3. 3., 2. 2.))) };
420 let _ = mp[2];
421 }
422}