proj-core 0.8.0

Pure-Rust coordinate transformation library with no C dependencies
Documentation
use super::{Transform, TransformableGeometry};
use crate::coord::Bounds;
use crate::error::Result;

#[cfg(feature = "geo-types")]
pub(super) const DEFAULT_GEO_TYPES_RECT_DENSIFY_POINTS: usize = 21;

#[cfg(feature = "geo-types")]
fn transform_geo_coord(
    transform: &Transform,
    coord: geo_types::Coord<f64>,
) -> Result<geo_types::Coord<f64>> {
    transform.convert(coord)
}

#[cfg(feature = "geo-types")]
fn transform_geo_coords(
    transform: &Transform,
    coords: Vec<geo_types::Coord<f64>>,
) -> Result<Vec<geo_types::Coord<f64>>> {
    coords
        .into_iter()
        .map(|coord| transform_geo_coord(transform, coord))
        .collect()
}

#[cfg(feature = "geo-types")]
pub(super) fn transform_geo_rect_with_densification(
    transform: &Transform,
    rect: geo_types::Rect<f64>,
    densify_points: usize,
) -> Result<geo_types::Rect<f64>> {
    let min = rect.min();
    let max = rect.max();
    let transformed =
        transform.transform_bounds(Bounds::new(min.x, min.y, max.x, max.y), densify_points)?;

    Ok(geo_types::Rect::new(
        geo_types::Coord {
            x: transformed.min_x,
            y: transformed.min_y,
        },
        geo_types::Coord {
            x: transformed.max_x,
            y: transformed.max_y,
        },
    ))
}

#[cfg(feature = "geo-types")]
fn transform_geo_rect(
    transform: &Transform,
    rect: geo_types::Rect<f64>,
) -> Result<geo_types::Rect<f64>> {
    transform_geo_rect_with_densification(transform, rect, DEFAULT_GEO_TYPES_RECT_DENSIFY_POINTS)
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::Coord<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        transform_geo_coord(transform, self)
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::Point<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(geo_types::Point::from(transform_geo_coord(
            transform, self.0,
        )?))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::Line<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(geo_types::Line::new(
            transform_geo_coord(transform, self.start)?,
            transform_geo_coord(transform, self.end)?,
        ))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::LineString<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(geo_types::LineString::new(transform_geo_coords(
            transform,
            self.into_inner(),
        )?))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::Polygon<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        let (exterior, interiors) = self.into_inner();
        let exterior = exterior.transform_geometry(transform)?;
        let interiors = interiors
            .into_iter()
            .map(|ring| ring.transform_geometry(transform))
            .collect::<Result<Vec<_>>>()?;
        Ok(geo_types::Polygon::new(exterior, interiors))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::MultiPoint<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(geo_types::MultiPoint(
            self.0
                .into_iter()
                .map(|point| point.transform_geometry(transform))
                .collect::<Result<Vec<_>>>()?,
        ))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::MultiLineString<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(geo_types::MultiLineString(
            self.0
                .into_iter()
                .map(|line| line.transform_geometry(transform))
                .collect::<Result<Vec<_>>>()?,
        ))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::MultiPolygon<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(geo_types::MultiPolygon(
            self.0
                .into_iter()
                .map(|polygon| polygon.transform_geometry(transform))
                .collect::<Result<Vec<_>>>()?,
        ))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::GeometryCollection<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(geo_types::GeometryCollection(
            self.0
                .into_iter()
                .map(|geometry| geometry.transform_geometry(transform))
                .collect::<Result<Vec<_>>>()?,
        ))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::Rect<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        transform_geo_rect(transform, self)
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::Triangle<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        let [v1, v2, v3] = self.to_array();
        Ok(geo_types::Triangle(
            transform_geo_coord(transform, v1)?,
            transform_geo_coord(transform, v2)?,
            transform_geo_coord(transform, v3)?,
        ))
    }
}

#[cfg(feature = "geo-types")]
impl TransformableGeometry for geo_types::Geometry<f64> {
    fn transform_geometry(self, transform: &Transform) -> Result<Self> {
        Ok(match self {
            geo_types::Geometry::Point(geometry) => {
                geo_types::Geometry::Point(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::Line(geometry) => {
                geo_types::Geometry::Line(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::LineString(geometry) => {
                geo_types::Geometry::LineString(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::Polygon(geometry) => {
                geo_types::Geometry::Polygon(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::MultiPoint(geometry) => {
                geo_types::Geometry::MultiPoint(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::MultiLineString(geometry) => {
                geo_types::Geometry::MultiLineString(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::MultiPolygon(geometry) => {
                geo_types::Geometry::MultiPolygon(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::GeometryCollection(geometry) => {
                geo_types::Geometry::GeometryCollection(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::Rect(geometry) => {
                geo_types::Geometry::Rect(geometry.transform_geometry(transform)?)
            }
            geo_types::Geometry::Triangle(geometry) => {
                geo_types::Geometry::Triangle(geometry.transform_geometry(transform)?)
            }
        })
    }
}