#![cfg_attr(feature = "use-proj", doc = "```")]
#![cfg_attr(not(feature = "use-proj"), doc = "```ignore")]
pub(crate) use crate::geometry::*;
pub(crate) use crate::CoordNum;
pub trait MapCoords<T, NT> {
type Output;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output
where
T: CoordNum,
NT: CoordNum;
#[cfg_attr(feature = "use-proj", doc = "```")]
#[cfg_attr(not(feature = "use-proj"), doc = "```ignore")]
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E>
where
T: CoordNum,
NT: CoordNum;
}
pub trait MapCoordsInPlace<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy)
where
T: CoordNum;
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E>
where
T: CoordNum;
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Point<T> {
type Output = Point<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
Point(func(self.0))
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E>,
) -> Result<Self::Output, E> {
Ok(Point(func(self.0)?))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for Point<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
self.0 = func(self.0);
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
self.0 = func(self.0)?;
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Line<T> {
type Output = Line<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
Line::new(
self.start_point().map_coords(func).0,
self.end_point().map_coords(func).0,
)
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
Ok(Line::new(
self.start_point().try_map_coords(func)?.0,
self.end_point().try_map_coords(func)?.0,
))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for Line<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
self.start = func(self.start);
self.end = func(self.end);
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
self.start = func(self.start)?;
self.end = func(self.end)?;
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for LineString<T> {
type Output = LineString<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
LineString::from(
self.points()
.map(|p| p.map_coords(func))
.collect::<Vec<_>>(),
)
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
Ok(LineString::from(
self.points()
.map(|p| p.try_map_coords(func))
.collect::<Result<Vec<_>, E>>()?,
))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for LineString<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
for p in &mut self.0 {
*p = func(*p);
}
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
for p in &mut self.0 {
*p = func(*p)?;
}
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Polygon<T> {
type Output = Polygon<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
Polygon::new(
self.exterior().map_coords(func),
self.interiors()
.iter()
.map(|l| l.map_coords(func))
.collect(),
)
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
Ok(Polygon::new(
self.exterior().try_map_coords(func)?,
self.interiors()
.iter()
.map(|l| l.try_map_coords(func))
.collect::<Result<Vec<_>, E>>()?,
))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for Polygon<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
self.exterior_mut(|line_string| {
line_string.map_coords_in_place(func);
});
self.interiors_mut(|line_strings| {
for line_string in line_strings {
line_string.map_coords_in_place(func);
}
});
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
let mut result = Ok(());
self.exterior_mut(|line_string| {
if let Err(e) = line_string.try_map_coords_in_place(&func) {
result = Err(e);
}
});
if result.is_ok() {
self.interiors_mut(|line_strings| {
for line_string in line_strings {
if let Err(e) = line_string.try_map_coords_in_place(&func) {
result = Err(e);
break;
}
}
});
}
result
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for MultiPoint<T> {
type Output = MultiPoint<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
MultiPoint::new(self.iter().map(|p| p.map_coords(func)).collect())
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
Ok(MultiPoint::new(
self.0
.iter()
.map(|p| p.try_map_coords(func))
.collect::<Result<Vec<_>, E>>()?,
))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for MultiPoint<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
for p in &mut self.0 {
p.map_coords_in_place(func);
}
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
for p in &mut self.0 {
p.try_map_coords_in_place(&func)?;
}
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for MultiLineString<T> {
type Output = MultiLineString<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
MultiLineString::new(self.iter().map(|l| l.map_coords(func)).collect())
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
Ok(MultiLineString::new(
self.0
.iter()
.map(|l| l.try_map_coords(func))
.collect::<Result<Vec<_>, E>>()?,
))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for MultiLineString<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
for p in &mut self.0 {
p.map_coords_in_place(func);
}
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
for p in &mut self.0 {
p.try_map_coords_in_place(&func)?;
}
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for MultiPolygon<T> {
type Output = MultiPolygon<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
MultiPolygon::new(self.iter().map(|p| p.map_coords(func)).collect())
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
Ok(MultiPolygon::new(
self.0
.iter()
.map(|p| p.try_map_coords(func))
.collect::<Result<Vec<_>, E>>()?,
))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for MultiPolygon<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
for p in &mut self.0 {
p.map_coords_in_place(func);
}
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
for p in &mut self.0 {
p.try_map_coords_in_place(&func)?;
}
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Geometry<T> {
type Output = Geometry<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
match *self {
Geometry::Point(ref x) => Geometry::Point(x.map_coords(func)),
Geometry::Line(ref x) => Geometry::Line(x.map_coords(func)),
Geometry::LineString(ref x) => Geometry::LineString(x.map_coords(func)),
Geometry::Polygon(ref x) => Geometry::Polygon(x.map_coords(func)),
Geometry::MultiPoint(ref x) => Geometry::MultiPoint(x.map_coords(func)),
Geometry::MultiLineString(ref x) => Geometry::MultiLineString(x.map_coords(func)),
Geometry::MultiPolygon(ref x) => Geometry::MultiPolygon(x.map_coords(func)),
Geometry::GeometryCollection(ref x) => Geometry::GeometryCollection(x.map_coords(func)),
Geometry::Rect(ref x) => Geometry::Rect(x.map_coords(func)),
Geometry::Triangle(ref x) => Geometry::Triangle(x.map_coords(func)),
}
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
match *self {
Geometry::Point(ref x) => Ok(Geometry::Point(x.try_map_coords(func)?)),
Geometry::Line(ref x) => Ok(Geometry::Line(x.try_map_coords(func)?)),
Geometry::LineString(ref x) => Ok(Geometry::LineString(x.try_map_coords(func)?)),
Geometry::Polygon(ref x) => Ok(Geometry::Polygon(x.try_map_coords(func)?)),
Geometry::MultiPoint(ref x) => Ok(Geometry::MultiPoint(x.try_map_coords(func)?)),
Geometry::MultiLineString(ref x) => {
Ok(Geometry::MultiLineString(x.try_map_coords(func)?))
}
Geometry::MultiPolygon(ref x) => Ok(Geometry::MultiPolygon(x.try_map_coords(func)?)),
Geometry::GeometryCollection(ref x) => {
Ok(Geometry::GeometryCollection(x.try_map_coords(func)?))
}
Geometry::Rect(ref x) => Ok(Geometry::Rect(x.try_map_coords(func)?)),
Geometry::Triangle(ref x) => Ok(Geometry::Triangle(x.try_map_coords(func)?)),
}
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for Geometry<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
match *self {
Geometry::Point(ref mut x) => x.map_coords_in_place(func),
Geometry::Line(ref mut x) => x.map_coords_in_place(func),
Geometry::LineString(ref mut x) => x.map_coords_in_place(func),
Geometry::Polygon(ref mut x) => x.map_coords_in_place(func),
Geometry::MultiPoint(ref mut x) => x.map_coords_in_place(func),
Geometry::MultiLineString(ref mut x) => x.map_coords_in_place(func),
Geometry::MultiPolygon(ref mut x) => x.map_coords_in_place(func),
Geometry::GeometryCollection(ref mut x) => x.map_coords_in_place(func),
Geometry::Rect(ref mut x) => x.map_coords_in_place(func),
Geometry::Triangle(ref mut x) => x.map_coords_in_place(func),
}
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
match *self {
Geometry::Point(ref mut x) => x.try_map_coords_in_place(func),
Geometry::Line(ref mut x) => x.try_map_coords_in_place(func),
Geometry::LineString(ref mut x) => x.try_map_coords_in_place(func),
Geometry::Polygon(ref mut x) => x.try_map_coords_in_place(func),
Geometry::MultiPoint(ref mut x) => x.try_map_coords_in_place(func),
Geometry::MultiLineString(ref mut x) => x.try_map_coords_in_place(func),
Geometry::MultiPolygon(ref mut x) => x.try_map_coords_in_place(func),
Geometry::GeometryCollection(ref mut x) => x.try_map_coords_in_place(func),
Geometry::Rect(ref mut x) => x.try_map_coords_in_place(func),
Geometry::Triangle(ref mut x) => x.try_map_coords_in_place(func),
}
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for GeometryCollection<T> {
type Output = GeometryCollection<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
GeometryCollection::new_from(self.iter().map(|g| g.map_coords(func)).collect())
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E> + Copy,
) -> Result<Self::Output, E> {
Ok(GeometryCollection::new_from(
self.0
.iter()
.map(|g| g.try_map_coords(func))
.collect::<Result<Vec<_>, E>>()?,
))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for GeometryCollection<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T> + Copy) {
for p in &mut self.0 {
p.map_coords_in_place(func);
}
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
for p in &mut self.0 {
p.try_map_coords_in_place(&func)?;
}
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Rect<T> {
type Output = Rect<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
Rect::new(func(self.min()), func(self.max()))
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E>,
) -> Result<Self::Output, E> {
Ok(Rect::new(func(self.min())?, func(self.max())?))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for Rect<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
let mut new_rect = Rect::new(func(self.min()), func(self.max()));
::std::mem::swap(self, &mut new_rect);
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
let mut new_rect = Rect::new(func(self.min())?, func(self.max())?);
::std::mem::swap(self, &mut new_rect);
Ok(())
}
}
impl<T: CoordNum, NT: CoordNum> MapCoords<T, NT> for Triangle<T> {
type Output = Triangle<NT>;
fn map_coords(&self, func: impl Fn(Coord<T>) -> Coord<NT> + Copy) -> Self::Output {
Triangle::new(func(self.0), func(self.1), func(self.2))
}
fn try_map_coords<E>(
&self,
func: impl Fn(Coord<T>) -> Result<Coord<NT>, E>,
) -> Result<Self::Output, E> {
Ok(Triangle::new(func(self.0)?, func(self.1)?, func(self.2)?))
}
}
impl<T: CoordNum> MapCoordsInPlace<T> for Triangle<T> {
fn map_coords_in_place(&mut self, func: impl Fn(Coord<T>) -> Coord<T>) {
let mut new_triangle = Triangle::new(func(self.0), func(self.1), func(self.2));
::std::mem::swap(self, &mut new_triangle);
}
fn try_map_coords_in_place<E>(
&mut self,
func: impl Fn(Coord<T>) -> Result<Coord<T>, E>,
) -> Result<(), E> {
let mut new_triangle = Triangle::new(func(self.0)?, func(self.1)?, func(self.2)?);
::std::mem::swap(self, &mut new_triangle);
Ok(())
}
}
#[cfg(test)]
mod test {
use super::{MapCoords, MapCoordsInPlace};
use crate::{
coord, polygon, Coord, Geometry, GeometryCollection, Line, LineString, MultiLineString,
MultiPoint, MultiPolygon, Point, Polygon, Rect,
};
#[test]
fn point() {
let p = Point::new(10., 10.);
let new_p = p.map_coords(|Coord { x, y }| (x + 10., y + 100.).into());
assert_relative_eq!(new_p.x(), 20.);
assert_relative_eq!(new_p.y(), 110.);
}
#[test]
fn point_inplace() {
let mut p2 = Point::new(10f32, 10f32);
p2.map_coords_in_place(|Coord { x, y }| (x + 10., y + 100.).into());
assert_relative_eq!(p2.x(), 20.);
assert_relative_eq!(p2.y(), 110.);
}
#[test]
fn rect_inplace() {
let mut rect = Rect::new((10, 10), (20, 20));
rect.map_coords_in_place(|Coord { x, y }| (x + 10, y + 20).into());
assert_eq!(rect.min(), coord! { x: 20, y: 30 });
assert_eq!(rect.max(), coord! { x: 30, y: 40 });
}
#[test]
fn rect_inplace_normalized() {
let mut rect = Rect::new((2, 2), (3, 3));
rect.map_coords_in_place(|pt| {
match pt.x_y() {
(2, 2) => (4, 4).into(),
(3, 3) => (1, 1).into(),
_ => panic!("unexpected point"),
}
});
assert_eq!(rect.min(), coord! { x: 1, y: 1 });
assert_eq!(rect.max(), coord! { x: 4, y: 4 });
}
#[test]
fn rect_map_coords() {
let rect = Rect::new((10, 10), (20, 20));
let another_rect = rect.map_coords(|Coord { x, y }| (x + 10, y + 20).into());
assert_eq!(another_rect.min(), coord! { x: 20, y: 30 });
assert_eq!(another_rect.max(), coord! { x: 30, y: 40 });
}
#[test]
fn rect_try_map_coords() {
let rect = Rect::new((10i32, 10), (20, 20));
let result = rect.try_map_coords(|Coord { x, y }| -> Result<_, &'static str> {
Ok((
x.checked_add(10).ok_or("overflow")?,
y.checked_add(20).ok_or("overflow")?,
)
.into())
});
assert!(result.is_ok());
}
#[test]
fn rect_try_map_coords_normalized() {
let rect = Rect::new((2, 2), (3, 3));
let result: Result<_, std::convert::Infallible> = rect.try_map_coords(|pt| {
match pt.x_y() {
(2, 2) => Ok((4, 4).into()),
(3, 3) => Ok((1, 1).into()),
_ => panic!("unexpected point"),
}
});
let new_rect = result.unwrap();
assert_eq!(new_rect.min(), coord! { x: 1, y: 1 });
assert_eq!(new_rect.max(), coord! { x: 4, y: 4 });
}
#[test]
fn line() {
let line = Line::from([(0., 0.), (1., 2.)]);
assert_relative_eq!(
line.map_coords(|Coord { x, y }| (x * 2., y).into()),
Line::from([(0., 0.), (2., 2.)]),
epsilon = 1e-6
);
}
#[test]
fn linestring() {
let line1: LineString<f32> = LineString::from(vec![(0., 0.), (1., 2.)]);
let line2 = line1.map_coords(|Coord { x, y }| (x + 10., y - 100.).into());
assert_relative_eq!(line2.0[0], Coord::from((10., -100.)), epsilon = 1e-6);
assert_relative_eq!(line2.0[1], Coord::from((11., -98.)), epsilon = 1e-6);
}
#[test]
fn polygon() {
let exterior = LineString::from(vec![(0., 0.), (1., 1.), (1., 0.), (0., 0.)]);
let interiors = vec![LineString::from(vec![
(0.1, 0.1),
(0.9, 0.9),
(0.9, 0.1),
(0.1, 0.1),
])];
let p = Polygon::new(exterior, interiors);
let p2 = p.map_coords(|Coord { x, y }| (x + 10., y - 100.).into());
let exterior2 =
LineString::from(vec![(10., -100.), (11., -99.), (11., -100.), (10., -100.)]);
let interiors2 = vec![LineString::from(vec![
(10.1, -99.9),
(10.9, -99.1),
(10.9, -99.9),
(10.1, -99.9),
])];
let expected_p2 = Polygon::new(exterior2, interiors2);
assert_relative_eq!(p2, expected_p2, epsilon = 1e-6);
}
#[test]
fn multipoint() {
let p1 = Point::new(10., 10.);
let p2 = Point::new(0., -100.);
let mp = MultiPoint::new(vec![p1, p2]);
assert_eq!(
mp.map_coords(|Coord { x, y }| (x + 10., y + 100.).into()),
MultiPoint::new(vec![Point::new(20., 110.), Point::new(10., 0.)])
);
}
#[test]
fn multilinestring() {
let line1: LineString<f32> = LineString::from(vec![(0., 0.), (1., 2.)]);
let line2: LineString<f32> = LineString::from(vec![(-1., 0.), (0., 0.), (1., 2.)]);
let mline = MultiLineString::new(vec![line1, line2]);
let mline2 = mline.map_coords(|Coord { x, y }| (x + 10., y - 100.).into());
assert_relative_eq!(
mline2,
MultiLineString::new(vec![
LineString::from(vec![(10., -100.), (11., -98.)]),
LineString::from(vec![(9., -100.), (10., -100.), (11., -98.)]),
]),
epsilon = 1e-6
);
}
#[test]
fn multipolygon() {
let poly1 = polygon![
(x: 0., y: 0.),
(x: 10., y: 0.),
(x: 10., y: 10.),
(x: 0., y: 10.),
(x: 0., y: 0.),
];
let poly2 = polygon![
exterior: [
(x: 11., y: 11.),
(x: 20., y: 11.),
(x: 20., y: 20.),
(x: 11., y: 20.),
(x: 11., y: 11.),
],
interiors: [
[
(x: 13., y: 13.),
(x: 13., y: 17.),
(x: 17., y: 17.),
(x: 17., y: 13.),
(x: 13., y: 13.),
]
],
];
let mp = MultiPolygon::new(vec![poly1, poly2]);
let mp2 = mp.map_coords(|Coord { x, y }| (x * 2., y + 100.).into());
assert_eq!(mp2.0.len(), 2);
assert_relative_eq!(
mp2.0[0],
polygon![
(x: 0., y: 100.),
(x: 20., y: 100.),
(x: 20., y: 110.),
(x: 0., y: 110.),
(x: 0., y: 100.),
],
);
assert_relative_eq!(
mp2.0[1],
polygon![
exterior: [
(x: 22., y: 111.),
(x: 40., y: 111.),
(x: 40., y: 120.),
(x: 22., y: 120.),
(x: 22., y: 111.),
],
interiors: [
[
(x: 26., y: 113.),
(x: 26., y: 117.),
(x: 34., y: 117.),
(x: 34., y: 113.),
(x: 26., y: 113.),
],
],
],
);
}
#[test]
fn geometrycollection() {
let p1 = Geometry::Point(Point::new(10., 10.));
let line1 = Geometry::LineString(LineString::from(vec![(0., 0.), (1., 2.)]));
let gc = GeometryCollection::new_from(vec![p1, line1]);
assert_eq!(
gc.map_coords(|Coord { x, y }| (x + 10., y + 100.).into()),
GeometryCollection::new_from(vec![
Geometry::Point(Point::new(20., 110.)),
Geometry::LineString(LineString::from(vec![(10., 100.), (11., 102.)])),
])
);
}
#[test]
fn convert_type() {
let p1: Point<f64> = Point::new(1., 2.);
let p2: Point<f32> = p1.map_coords(|Coord { x, y }| (x as f32, y as f32).into());
assert_relative_eq!(p2.x(), 1f32);
assert_relative_eq!(p2.y(), 2f32);
}
#[cfg(feature = "use-proj")]
#[test]
fn test_fallible_proj() {
use proj::{Proj, ProjError};
let from = "EPSG:4326";
let to = "EPSG:2230";
let to_feet = Proj::new_known_crs(from, to, None).unwrap();
let f = |c| -> Result<_, ProjError> {
let shifted = to_feet.convert(c)?;
Ok(shifted)
};
let usa_m = Point::new(-115.797615, 37.2647978);
let usa_ft = usa_m.try_map_coords(f).unwrap();
assert_relative_eq!(6693625.67217475, usa_ft.x(), epsilon = 1e-6);
assert_relative_eq!(3497301.5918027186, usa_ft.y(), epsilon = 1e-6);
}
#[test]
fn test_fallible() {
let f = |Coord { x, y }| -> Result<_, &'static str> {
if relative_ne!(x, 2.0) {
Ok((x * 2., y + 100.).into())
} else {
Err("Ugh")
}
};
let bad_ls: LineString<_> = vec![
Point::new(1.0, 1.0),
Point::new(2.0, 2.0),
Point::new(3.0, 3.0),
]
.into();
let good_ls: LineString<_> = vec![
Point::new(1.0, 1.0),
Point::new(2.1, 2.0),
Point::new(3.0, 3.0),
]
.into();
let bad = bad_ls.try_map_coords(f);
assert!(bad.is_err());
let good = good_ls.try_map_coords(f);
assert!(good.is_ok());
assert_relative_eq!(
good.unwrap(),
vec![
Point::new(2., 101.),
Point::new(4.2, 102.),
Point::new(6.0, 103.),
]
.into()
);
}
#[test]
fn rect_map_invert_coords() {
let rect = Rect::new(coord! { x: 0., y: 0. }, coord! { x: 1., y: 1. });
rect.map_coords(|Coord { x, y }| (-x, -y).into());
}
}