1#![cfg_attr(feature = "use-proj", doc = "```")]
4#![cfg_attr(not(feature = "use-proj"), doc = "```ignore")]
5pub use modern::*;
28mod modern {
29 pub(crate) use crate::geometry::*;
30 pub(crate) use crate::CoordNum;
31
32 pub trait MapCoords<T, NT> {
34 type Output;
35
36 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output
74 where
75 T: CoordNum,
76 NT: CoordNum;
77
78 #[cfg_attr(feature = "use-proj", doc = "```")]
99 #[cfg_attr(not(feature = "use-proj"), doc = "```ignore")]
100 fn try_map_coords<E>(
122 &self,
123 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
124 ) -> Result<Self::Output, E>
125 where
126 T: CoordNum,
127 NT: CoordNum;
128 }
129
130 pub trait MapCoordsInPlace<T> {
131 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy)
146 where
147 T: CoordNum;
148
149 fn try_map_coords_in_place<E>(
176 &mut self,
177 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
178 ) -> Result<(), E>
179 where
180 T: CoordNum;
181 }
182
183 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Point<T> {
188 type Output = Point<NT>;
189
190 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
191 Point(func(self.0))
192 }
193
194 fn try_map_coords<E>(
195 &self,
196 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E>,
197 ) -> Result<Self::Output, E> {
198 Ok(Point(func(self.0)?))
199 }
200 }
201
202 impl<T: CoordNum> MapCoordsInPlace<T> for Point<T> {
203 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
204 self.0 = func(self.0);
205 }
206
207 fn try_map_coords_in_place<E>(
208 &mut self,
209 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
210 ) -> Result<(), E> {
211 self.0 = func(self.0)?;
212 Ok(())
213 }
214 }
215
216 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Line<T> {
221 type Output = Line<NT>;
222
223 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
224 Line::new(
225 self.start_point().map_coords(func).0,
226 self.end_point().map_coords(func).0,
227 )
228 }
229
230 fn try_map_coords<E>(
231 &self,
232 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
233 ) -> Result<Self::Output, E> {
234 Ok(Line::new(
235 self.start_point().try_map_coords(func)?.0,
236 self.end_point().try_map_coords(func)?.0,
237 ))
238 }
239 }
240
241 impl<T: CoordNum> MapCoordsInPlace<T> for Line<T> {
242 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
243 self.start = func(self.start);
244 self.end = func(self.end);
245 }
246
247 fn try_map_coords_in_place<E>(
248 &mut self,
249 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
250 ) -> Result<(), E> {
251 self.start = func(self.start)?;
252 self.end = func(self.end)?;
253
254 Ok(())
255 }
256 }
257
258 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for LineString<T> {
263 type Output = LineString<NT>;
264
265 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
266 LineString::from(
267 self.points()
268 .map(|p| p.map_coords(func))
269 .collect::<Vec<_>>(),
270 )
271 }
272
273 fn try_map_coords<E>(
274 &self,
275 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
276 ) -> Result<Self::Output, E> {
277 Ok(LineString::from(
278 self.points()
279 .map(|p| p.try_map_coords(func))
280 .collect::<Result<Vec<_>, E>>()?,
281 ))
282 }
283 }
284
285 impl<T: CoordNum> MapCoordsInPlace<T> for LineString<T> {
286 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
287 for p in &mut self.0 {
288 *p = func(*p);
289 }
290 }
291
292 fn try_map_coords_in_place<E>(
293 &mut self,
294 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
295 ) -> Result<(), E> {
296 for p in &mut self.0 {
297 *p = func(*p)?;
298 }
299 Ok(())
300 }
301 }
302
303 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Polygon<T> {
308 type Output = Polygon<NT>;
309
310 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
311 Polygon::new(
312 self.exterior().map_coords(func),
313 self.interiors()
314 .iter()
315 .map(|l| l.map_coords(func))
316 .collect(),
317 )
318 }
319
320 fn try_map_coords<E>(
321 &self,
322 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
323 ) -> Result<Self::Output, E> {
324 Ok(Polygon::new(
325 self.exterior().try_map_coords(func)?,
326 self.interiors()
327 .iter()
328 .map(|l| l.try_map_coords(func))
329 .collect::<Result<Vec<_>, E>>()?,
330 ))
331 }
332 }
333
334 impl<T: CoordNum> MapCoordsInPlace<T> for Polygon<T> {
335 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
336 self.exterior_mut(|line_string| {
337 line_string.map_coords_in_place(func);
338 });
339
340 self.interiors_mut(|line_strings| {
341 for line_string in line_strings {
342 line_string.map_coords_in_place(func);
343 }
344 });
345 }
346
347 fn try_map_coords_in_place<E>(
348 &mut self,
349 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
350 ) -> Result<(), E> {
351 let mut result = Ok(());
352
353 self.exterior_mut(|line_string| {
354 if let Err(e) = line_string.try_map_coords_in_place(&func) {
355 result = Err(e);
356 }
357 });
358
359 if result.is_ok() {
360 self.interiors_mut(|line_strings| {
361 for line_string in line_strings {
362 if let Err(e) = line_string.try_map_coords_in_place(&func) {
363 result = Err(e);
364 break;
365 }
366 }
367 });
368 }
369
370 result
371 }
372 }
373
374 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for MultiPoint<T> {
379 type Output = MultiPoint<NT>;
380
381 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
382 MultiPoint::new(self.iter().map(|p| p.map_coords(func)).collect())
383 }
384
385 fn try_map_coords<E>(
386 &self,
387 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
388 ) -> Result<Self::Output, E> {
389 Ok(MultiPoint::new(
390 self.0
391 .iter()
392 .map(|p| p.try_map_coords(func))
393 .collect::<Result<Vec<_>, E>>()?,
394 ))
395 }
396 }
397
398 impl<T: CoordNum> MapCoordsInPlace<T> for MultiPoint<T> {
399 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
400 for p in &mut self.0 {
401 p.map_coords_in_place(func);
402 }
403 }
404
405 fn try_map_coords_in_place<E>(
406 &mut self,
407 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
408 ) -> Result<(), E> {
409 for p in &mut self.0 {
410 p.try_map_coords_in_place(&func)?;
411 }
412 Ok(())
413 }
414 }
415
416 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for MultiLineString<T> {
421 type Output = MultiLineString<NT>;
422
423 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
424 MultiLineString::new(self.iter().map(|l| l.map_coords(func)).collect())
425 }
426
427 fn try_map_coords<E>(
428 &self,
429 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
430 ) -> Result<Self::Output, E> {
431 Ok(MultiLineString::new(
432 self.0
433 .iter()
434 .map(|l| l.try_map_coords(func))
435 .collect::<Result<Vec<_>, E>>()?,
436 ))
437 }
438 }
439
440 impl<T: CoordNum> MapCoordsInPlace<T> for MultiLineString<T> {
441 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
442 for p in &mut self.0 {
443 p.map_coords_in_place(func);
444 }
445 }
446
447 fn try_map_coords_in_place<E>(
448 &mut self,
449 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
450 ) -> Result<(), E> {
451 for p in &mut self.0 {
452 p.try_map_coords_in_place(&func)?;
453 }
454 Ok(())
455 }
456 }
457
458 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for MultiPolygon<T> {
463 type Output = MultiPolygon<NT>;
464
465 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
466 MultiPolygon::new(self.iter().map(|p| p.map_coords(func)).collect())
467 }
468
469 fn try_map_coords<E>(
470 &self,
471 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
472 ) -> Result<Self::Output, E> {
473 Ok(MultiPolygon::new(
474 self.0
475 .iter()
476 .map(|p| p.try_map_coords(func))
477 .collect::<Result<Vec<_>, E>>()?,
478 ))
479 }
480 }
481
482 impl<T: CoordNum> MapCoordsInPlace<T> for MultiPolygon<T> {
483 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
484 for p in &mut self.0 {
485 p.map_coords_in_place(func);
486 }
487 }
488
489 fn try_map_coords_in_place<E>(
490 &mut self,
491 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
492 ) -> Result<(), E> {
493 for p in &mut self.0 {
494 p.try_map_coords_in_place(&func)?;
495 }
496 Ok(())
497 }
498 }
499
500 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Geometry<T> {
505 type Output = Geometry<NT>;
506
507 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
508 match *self {
509 Geometry::Point(ref x) => Geometry::Point(x.map_coords(func)),
510 Geometry::Line(ref x) => Geometry::Line(x.map_coords(func)),
511 Geometry::LineString(ref x) => Geometry::LineString(x.map_coords(func)),
512 Geometry::Polygon(ref x) => Geometry::Polygon(x.map_coords(func)),
513 Geometry::MultiPoint(ref x) => Geometry::MultiPoint(x.map_coords(func)),
514 Geometry::MultiLineString(ref x) => Geometry::MultiLineString(x.map_coords(func)),
515 Geometry::MultiPolygon(ref x) => Geometry::MultiPolygon(x.map_coords(func)),
516 Geometry::GeometryCollection(ref x) => {
517 Geometry::GeometryCollection(x.map_coords(func))
518 }
519 Geometry::Rect(ref x) => Geometry::Rect(x.map_coords(func)),
520 Geometry::Triangle(ref x) => Geometry::Triangle(x.map_coords(func)),
521 }
522 }
523
524 fn try_map_coords<E>(
525 &self,
526 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
527 ) -> Result<Self::Output, E> {
528 match *self {
529 Geometry::Point(ref x) => Ok(Geometry::Point(x.try_map_coords(func)?)),
530 Geometry::Line(ref x) => Ok(Geometry::Line(x.try_map_coords(func)?)),
531 Geometry::LineString(ref x) => Ok(Geometry::LineString(x.try_map_coords(func)?)),
532 Geometry::Polygon(ref x) => Ok(Geometry::Polygon(x.try_map_coords(func)?)),
533 Geometry::MultiPoint(ref x) => Ok(Geometry::MultiPoint(x.try_map_coords(func)?)),
534 Geometry::MultiLineString(ref x) => {
535 Ok(Geometry::MultiLineString(x.try_map_coords(func)?))
536 }
537 Geometry::MultiPolygon(ref x) => {
538 Ok(Geometry::MultiPolygon(x.try_map_coords(func)?))
539 }
540 Geometry::GeometryCollection(ref x) => {
541 Ok(Geometry::GeometryCollection(x.try_map_coords(func)?))
542 }
543 Geometry::Rect(ref x) => Ok(Geometry::Rect(x.try_map_coords(func)?)),
544 Geometry::Triangle(ref x) => Ok(Geometry::Triangle(x.try_map_coords(func)?)),
545 }
546 }
547 }
548
549 impl<T: CoordNum> MapCoordsInPlace<T> for Geometry<T> {
550 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
551 match *self {
552 Geometry::Point(ref mut x) => x.map_coords_in_place(func),
553 Geometry::Line(ref mut x) => x.map_coords_in_place(func),
554 Geometry::LineString(ref mut x) => x.map_coords_in_place(func),
555 Geometry::Polygon(ref mut x) => x.map_coords_in_place(func),
556 Geometry::MultiPoint(ref mut x) => x.map_coords_in_place(func),
557 Geometry::MultiLineString(ref mut x) => x.map_coords_in_place(func),
558 Geometry::MultiPolygon(ref mut x) => x.map_coords_in_place(func),
559 Geometry::GeometryCollection(ref mut x) => x.map_coords_in_place(func),
560 Geometry::Rect(ref mut x) => x.map_coords_in_place(func),
561 Geometry::Triangle(ref mut x) => x.map_coords_in_place(func),
562 }
563 }
564
565 fn try_map_coords_in_place<E>(
566 &mut self,
567 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
568 ) -> Result<(), E> {
569 match *self {
570 Geometry::Point(ref mut x) => x.try_map_coords_in_place(func),
571 Geometry::Line(ref mut x) => x.try_map_coords_in_place(func),
572 Geometry::LineString(ref mut x) => x.try_map_coords_in_place(func),
573 Geometry::Polygon(ref mut x) => x.try_map_coords_in_place(func),
574 Geometry::MultiPoint(ref mut x) => x.try_map_coords_in_place(func),
575 Geometry::MultiLineString(ref mut x) => x.try_map_coords_in_place(func),
576 Geometry::MultiPolygon(ref mut x) => x.try_map_coords_in_place(func),
577 Geometry::GeometryCollection(ref mut x) => x.try_map_coords_in_place(func),
578 Geometry::Rect(ref mut x) => x.try_map_coords_in_place(func),
579 Geometry::Triangle(ref mut x) => x.try_map_coords_in_place(func),
580 }
581 }
582 }
583
584 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for GeometryCollection<T> {
589 type Output = GeometryCollection<NT>;
590
591 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
592 GeometryCollection::new_from(self.iter().map(|g| g.map_coords(func)).collect())
593 }
594
595 fn try_map_coords<E>(
596 &self,
597 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
598 ) -> Result<Self::Output, E> {
599 Ok(GeometryCollection::new_from(
600 self.0
601 .iter()
602 .map(|g| g.try_map_coords(func))
603 .collect::<Result<Vec<_>, E>>()?,
604 ))
605 }
606 }
607
608 impl<T: CoordNum> MapCoordsInPlace<T> for GeometryCollection<T> {
609 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
610 for p in &mut self.0 {
611 p.map_coords_in_place(func);
612 }
613 }
614
615 fn try_map_coords_in_place<E>(
616 &mut self,
617 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
618 ) -> Result<(), E> {
619 for p in &mut self.0 {
620 p.try_map_coords_in_place(&func)?;
621 }
622 Ok(())
623 }
624 }
625
626 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Rect<T> {
631 type Output = Rect<NT>;
632
633 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
634 Rect::new(func(self.min()), func(self.max()))
635 }
636
637 fn try_map_coords<E>(
638 &self,
639 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E>,
640 ) -> Result<Self::Output, E> {
641 Ok(Rect::new(func(self.min())?, func(self.max())?))
642 }
643 }
644
645 impl<T: CoordNum> MapCoordsInPlace<T> for Rect<T> {
646 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
647 let mut new_rect = Rect::new(func(self.min()), func(self.max()));
648 ::std::mem::swap(self, &mut new_rect);
649 }
650
651 fn try_map_coords_in_place<E>(
652 &mut self,
653 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
654 ) -> Result<(), E> {
655 let mut new_rect = Rect::new(func(self.min())?, func(self.max())?);
656 ::std::mem::swap(self, &mut new_rect);
657 Ok(())
658 }
659 }
660
661 impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Triangle<T> {
666 type Output = Triangle<NT>;
667
668 fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
669 Triangle::new(func(self.0), func(self.1), func(self.2))
670 }
671
672 fn try_map_coords<E>(
673 &self,
674 func: impl Fn(Coord<T>) -> Result<Coord<NT>, E>,
675 ) -> Result<Self::Output, E> {
676 Ok(Triangle::new(func(self.0)?, func(self.1)?, func(self.2)?))
677 }
678 }
679
680 impl<T: CoordNum> MapCoordsInPlace<T> for Triangle<T> {
681 fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
682 let mut new_triangle = Triangle::new(func(self.0), func(self.1), func(self.2));
683
684 ::std::mem::swap(self, &mut new_triangle);
685 }
686
687 fn try_map_coords_in_place<E>(
688 &mut self,
689 func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
690 ) -> Result<(), E> {
691 let mut new_triangle = Triangle::new(func(self.0)?, func(self.1)?, func(self.2)?);
692
693 ::std::mem::swap(self, &mut new_triangle);
694
695 Ok(())
696 }
697 }
698}
699pub use deprecated::*;
700pub(crate) mod deprecated {
701 use super::*;
702
703 #[deprecated(
705 since = "0.21.0",
706 note = "use `MapCoords::try_map_coords` which takes a `Coord` instead of an (x,y) tuple"
707 )]
708 pub trait TryMapCoords<T, NT, E> {
709 type Output;
710
711 #[cfg_attr(feature = "use-proj", doc = "```")]
734 #[cfg_attr(not(feature = "use-proj"), doc = "```ignore")]
735 fn try_map_coords(
760 &self,
761 func: impl Fn((T, T)) -> Result<(NT, NT), E> + Copy,
762 ) -> Result<Self::Output, E>
763 where
764 T: CoordNum,
765 NT: CoordNum;
766 }
767
768 #[deprecated(
769 since = "0.21.0",
770 note = "use `MapCoordsInPlace::try_map_coords_in_place` which takes a `Coord` instead of an (x,y) tuple"
771 )]
772 pub trait TryMapCoordsInplace<T, E> {
773 fn try_map_coords_inplace(
801 &mut self,
802 func: impl Fn((T, T)) -> Result<(T, T), E>,
803 ) -> Result<(), E>
804 where
805 T: CoordNum;
806 }
807
808 #[deprecated(
810 since = "0.21.0",
811 note = "use `MapCoordsInPlace::map_coords_in_place` instead which takes a `Coord` instead of an (x,y) tuple"
812 )]
813 pub trait MapCoordsInplace<T>: MapCoordsInPlace<T> {
814 fn map_coords_inplace(&mut self, func: impl Fn((T, T)) -> (T, T) + Copy)
831 where
832 T: CoordNum;
833 }
834
835 macro_rules! impl_deprecated_map_coords {
836 ($geom:ident) => {
837 #[allow(deprecated)]
838 impl<T: CoordNum, NT: CoordNum, E> TryMapCoords<T, NT, E> for $geom<T> {
839 type Output = $geom<NT>;
840
841 fn try_map_coords(
842 &self,
843 func: impl Fn((T, T)) -> Result<(NT, NT), E> + Copy,
844 ) -> Result<Self::Output, E> {
845 MapCoords::try_map_coords(self, |c| Ok(Coord::from(func(c.x_y())?)))
846 }
847 }
848
849 #[allow(deprecated)]
850 impl<T: CoordNum, E> TryMapCoordsInplace<T, E> for $geom<T> {
851 fn try_map_coords_inplace(
852 &mut self,
853 func: impl Fn((T, T)) -> Result<(T, T), E>,
854 ) -> Result<(), E> {
855 MapCoordsInPlace::try_map_coords_in_place(self, |c| Ok(func(c.x_y())?.into()))
856 }
857 }
858
859 #[allow(deprecated)]
860 impl<T: CoordNum> MapCoordsInplace<T> for $geom<T> {
861 fn map_coords_inplace(&mut self, func: impl Fn((T, T)) -> (T, T) + Copy)
878 where
879 T: CoordNum,
880 {
881 MapCoordsInPlace::map_coords_in_place(self, |c| func(c.x_y()).into())
882 }
883 }
884 };
885 }
886
887 impl_deprecated_map_coords!(Point);
888 impl_deprecated_map_coords!(Line);
889 impl_deprecated_map_coords!(LineString);
890 impl_deprecated_map_coords!(Polygon);
891 impl_deprecated_map_coords!(MultiPoint);
892 impl_deprecated_map_coords!(MultiLineString);
893 impl_deprecated_map_coords!(MultiPolygon);
894 impl_deprecated_map_coords!(Geometry);
895 impl_deprecated_map_coords!(GeometryCollection);
896 impl_deprecated_map_coords!(Triangle);
897 impl_deprecated_map_coords!(Rect);
898}
899
900#[cfg(test)]
901mod test {
902 use super::{MapCoords, MapCoordsInPlace};
903 use crate::{
904 coord, polygon, Coord, Geometry, GeometryCollection, Line, LineString, MultiLineString,
905 MultiPoint, MultiPolygon, Point, Polygon, Rect,
906 };
907
908 #[test]
909 fn point() {
910 let p = Point::new(10., 10.);
911 let new_p = p.map_coords(|Coord { x, y }| (x + 10., y + 100.).into());
912 assert_relative_eq!(new_p.x(), 20.);
913 assert_relative_eq!(new_p.y(), 110.);
914 }
915
916 #[test]
917 fn point_inplace() {
918 let mut p2 = Point::new(10f32, 10f32);
919 p2.map_coords_in_place(|Coord { x, y }| (x + 10., y + 100.).into());
920 assert_relative_eq!(p2.x(), 20.);
921 assert_relative_eq!(p2.y(), 110.);
922 }
923
924 #[test]
925 fn rect_inplace() {
926 let mut rect = Rect::new((10, 10), (20, 20));
927 rect.map_coords_in_place(|Coord { x, y }| (x + 10, y + 20).into());
928 assert_eq!(rect.min(), coord! { x: 20, y: 30 });
929 assert_eq!(rect.max(), coord! { x: 30, y: 40 });
930 }
931
932 #[test]
933 fn rect_inplace_normalized() {
934 let mut rect = Rect::new((2, 2), (3, 3));
935 rect.map_coords_in_place(|pt| {
938 match pt.x_y() {
939 (2, 2) => (4, 4).into(),
941 (3, 3) => (1, 1).into(),
943 _ => panic!("unexpected point"),
944 }
945 });
946
947 assert_eq!(rect.min(), coord! { x: 1, y: 1 });
948 assert_eq!(rect.max(), coord! { x: 4, y: 4 });
949 }
950
951 #[test]
952 fn rect_map_coords() {
953 let rect = Rect::new((10, 10), (20, 20));
954 let another_rect = rect.map_coords(|Coord { x, y }| (x + 10, y + 20).into());
955 assert_eq!(another_rect.min(), coord! { x: 20, y: 30 });
956 assert_eq!(another_rect.max(), coord! { x: 30, y: 40 });
957 }
958
959 #[test]
960 fn rect_try_map_coords() {
961 let rect = Rect::new((10i32, 10), (20, 20));
962 let result = rect.try_map_coords(|Coord { x, y }| -> Result<_, &'static str> {
963 Ok((
964 x.checked_add(10).ok_or("overflow")?,
965 y.checked_add(20).ok_or("overflow")?,
966 )
967 .into())
968 });
969 assert!(result.is_ok());
970 }
971
972 #[test]
973 fn rect_try_map_coords_normalized() {
974 let rect = Rect::new((2, 2), (3, 3));
975 let result: Result<_, std::convert::Infallible> = rect.try_map_coords(|pt| {
978 match pt.x_y() {
979 (2, 2) => Ok((4, 4).into()),
981 (3, 3) => Ok((1, 1).into()),
983 _ => panic!("unexpected point"),
984 }
985 });
986 let new_rect = result.unwrap();
987 assert_eq!(new_rect.min(), coord! { x: 1, y: 1 });
988 assert_eq!(new_rect.max(), coord! { x: 4, y: 4 });
989 }
990
991 #[test]
992 fn line() {
993 let line = Line::from([(0., 0.), (1., 2.)]);
994 assert_relative_eq!(
995 line.map_coords(|Coord { x, y }| (x * 2., y).into()),
996 Line::from([(0., 0.), (2., 2.)]),
997 epsilon = 1e-6
998 );
999 }
1000
1001 #[test]
1002 fn linestring() {
1003 let line1: LineString<f32> = LineString::from(vec![(0., 0.), (1., 2.)]);
1004 let line2 = line1.map_coords(|Coord { x, y }| (x + 10., y - 100.).into());
1005 assert_relative_eq!(line2.0[0], Coord::from((10., -100.)), epsilon = 1e-6);
1006 assert_relative_eq!(line2.0[1], Coord::from((11., -98.)), epsilon = 1e-6);
1007 }
1008
1009 #[test]
1010 fn polygon() {
1011 let exterior = LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]);
1012 let interiors = vec![LineString::from(vec![
1013 (0.1, 0.1),
1014 (0.9, 0.9),
1015 (0.9, 0.1),
1016 (0.1, 0.1),
1017 ])];
1018 let p = Polygon::new(exterior, interiors);
1019
1020 let p2 = p.map_coords(|Coord { x, y }| (x + 10., y - 100.).into());
1021
1022 let exterior2 =
1023 LineString::from(vec![(10., -100.), (11., -99.), (11., -100.), (10., -100.)]);
1024 let interiors2 = vec![LineString::from(vec![
1025 (10.1, -99.9),
1026 (10.9, -99.1),
1027 (10.9, -99.9),
1028 (10.1, -99.9),
1029 ])];
1030 let expected_p2 = Polygon::new(exterior2, interiors2);
1031
1032 assert_relative_eq!(p2, expected_p2, epsilon = 1e-6);
1033 }
1034
1035 #[test]
1036 fn multipoint() {
1037 let p1 = Point::new(10., 10.);
1038 let p2 = Point::new(0., -100.);
1039 let mp = MultiPoint::new(vec![p1, p2]);
1040
1041 assert_eq!(
1042 mp.map_coords(|Coord { x, y }| (x + 10., y + 100.).into()),
1043 MultiPoint::new(vec![Point::new(20., 110.), Point::new(10., 0.)])
1044 );
1045 }
1046
1047 #[test]
1048 fn multilinestring() {
1049 let line1: LineString<f32> = LineString::from(vec![(0., 0.), (1., 2.)]);
1050 let line2: LineString<f32> = LineString::from(vec![(-1., 0.), (0., 0.), (1., 2.)]);
1051 let mline = MultiLineString::new(vec![line1, line2]);
1052 let mline2 = mline.map_coords(|Coord { x, y }| (x + 10., y - 100.).into());
1053 assert_relative_eq!(
1054 mline2,
1055 MultiLineString::new(vec![
1056 LineString::from(vec![(10., -100.), (11., -98.)]),
1057 LineString::from(vec![(9., -100.), (10., -100.), (11., -98.)]),
1058 ]),
1059 epsilon = 1e-6
1060 );
1061 }
1062
1063 #[test]
1064 fn multipolygon() {
1065 let poly1 = polygon![
1066 (x: 0., y: 0.),
1067 (x: 10., y: 0.),
1068 (x: 10., y: 10.),
1069 (x: 0., y: 10.),
1070 (x: 0., y: 0.),
1071 ];
1072 let poly2 = polygon![
1073 exterior: [
1074 (x: 11., y: 11.),
1075 (x: 20., y: 11.),
1076 (x: 20., y: 20.),
1077 (x: 11., y: 20.),
1078 (x: 11., y: 11.),
1079 ],
1080 interiors: [
1081 [
1082 (x: 13., y: 13.),
1083 (x: 13., y: 17.),
1084 (x: 17., y: 17.),
1085 (x: 17., y: 13.),
1086 (x: 13., y: 13.),
1087 ]
1088 ],
1089 ];
1090
1091 let mp = MultiPolygon::new(vec![poly1, poly2]);
1092 let mp2 = mp.map_coords(|Coord { x, y }| (x * 2., y + 100.).into());
1093 assert_eq!(mp2.0.len(), 2);
1094 assert_relative_eq!(
1095 mp2.0[0],
1096 polygon![
1097 (x: 0., y: 100.),
1098 (x: 20., y: 100.),
1099 (x: 20., y: 110.),
1100 (x: 0., y: 110.),
1101 (x: 0., y: 100.),
1102 ],
1103 );
1104 assert_relative_eq!(
1105 mp2.0[1],
1106 polygon![
1107 exterior: [
1108 (x: 22., y: 111.),
1109 (x: 40., y: 111.),
1110 (x: 40., y: 120.),
1111 (x: 22., y: 120.),
1112 (x: 22., y: 111.),
1113 ],
1114 interiors: [
1115 [
1116 (x: 26., y: 113.),
1117 (x: 26., y: 117.),
1118 (x: 34., y: 117.),
1119 (x: 34., y: 113.),
1120 (x: 26., y: 113.),
1121 ],
1122 ],
1123 ],
1124 );
1125 }
1126
1127 #[test]
1128 fn geometrycollection() {
1129 let p1 = Geometry::Point(Point::new(10., 10.));
1130 let line1 = Geometry::LineString(LineString::from(vec![(0., 0.), (1., 2.)]));
1131
1132 let gc = GeometryCollection::new_from(vec![p1, line1]);
1133
1134 assert_eq!(
1135 gc.map_coords(|Coord { x, y }| (x + 10., y + 100.).into()),
1136 GeometryCollection::new_from(vec![
1137 Geometry::Point(Point::new(20., 110.)),
1138 Geometry::LineString(LineString::from(vec![(10., 100.), (11., 102.)])),
1139 ])
1140 );
1141 }
1142
1143 #[test]
1144 fn convert_type() {
1145 let p1: Point<f64> = Point::new(1., 2.);
1146 let p2: Point<f32> = p1.map_coords(|Coord { x, y }| (x as f32, y as f32).into());
1147 assert_relative_eq!(p2.x(), 1f32);
1148 assert_relative_eq!(p2.y(), 2f32);
1149 }
1150
1151 #[cfg(feature = "use-proj")]
1152 #[test]
1153 fn test_fallible_proj() {
1154 use proj::{Proj, ProjError};
1155 let from = "EPSG:4326";
1156 let to = "EPSG:2230";
1157 let to_feet = Proj::new_known_crs(from, to, None).unwrap();
1158
1159 let f = |c| -> Result<_, ProjError> {
1160 let shifted = to_feet.convert(c)?;
1161 Ok(shifted)
1162 };
1163 let usa_m = Point::new(-115.797615, 37.2647978);
1165 let usa_ft = usa_m.try_map_coords(f).unwrap();
1166 assert_relative_eq!(6693625.67217475, usa_ft.x(), epsilon = 1e-6);
1167 assert_relative_eq!(3497301.5918027186, usa_ft.y(), epsilon = 1e-6);
1168 }
1169
1170 #[test]
1171 fn test_fallible() {
1172 let f = |Coord { x, y }| -> Result<_, &'static str> {
1173 if relative_ne!(x, 2.0) {
1174 Ok((x * 2., y + 100.).into())
1175 } else {
1176 Err("Ugh")
1177 }
1178 };
1179 let bad_ls: LineString<_> = vec![
1181 Point::new(1.0, 1.0),
1182 Point::new(2.0, 2.0),
1183 Point::new(3.0, 3.0),
1184 ]
1185 .into();
1186 let good_ls: LineString<_> = vec![
1188 Point::new(1.0, 1.0),
1189 Point::new(2.1, 2.0),
1190 Point::new(3.0, 3.0),
1191 ]
1192 .into();
1193 let bad = bad_ls.try_map_coords(f);
1194 assert!(bad.is_err());
1195 let good = good_ls.try_map_coords(f);
1196 assert!(good.is_ok());
1197 assert_relative_eq!(
1198 good.unwrap(),
1199 vec![
1200 Point::new(2., 101.),
1201 Point::new(4.2, 102.),
1202 Point::new(6.0, 103.),
1203 ]
1204 .into()
1205 );
1206 }
1207
1208 #[test]
1209 fn rect_map_invert_coords() {
1210 let rect = Rect::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. });
1211
1212 rect.map_coords(|Coord { x, y }| (-x, -y).into());
1215 }
1216}