Skip to content

Commit

Permalink
Merge georust#718
Browse files Browse the repository at this point in the history
718: Add new `Transform` algorithm for transforming a geometry with PROJ. r=lnicola a=frewsxcv

- [x] I agree to follow the project's [code of conduct](https://github.com/georust/geo/blob/master/CODE_OF_CONDUCT.md).
- [x] I added an entry to `CHANGES.md` if knowledge of this change could be valuable to users.
  - I will do this if we decide we want this
- [x] Add entry to table of contents in `lib.rs`

Co-authored-by: Corey Farwell <coreyf@rwell.org>
  • Loading branch information
bors[bot] and frewsxcv authored Feb 6, 2022
2 parents aa81502 + 323717a commit 73af924
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 5 deletions.
12 changes: 9 additions & 3 deletions geo/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@

## Unreleased

* Bump proj crate to 0.23.0, using PROJ 8.1.0
* Bump `proj` crate to 0.25.0, using PROJ 8.1.0
* <https://github.com/georust/geo/pull/661>
* <https://github.com/georust/geo/pull/718>
* Add `ChaikinSmoothing` algorithm
* <https://github.com/georust/geo/pull/648>
* Fix `rotate` for multipolygons to rotate around the collection's centroid, instead of rotating each individual polygon around its own centroid.
* <https://github.com/georust/geo/pull/651>
* Add KNearestConcaveHull algorithm
* Add `KNearestConcaveHull` algorithm
* <https://github.com/georust/geo/pull/635>
* remove cargo-tarpaulin due to instability (#676, #677)
* Remove cargo-tarpaulin due to instability (#676, #677)
* Fix: `ClosestPoint` for Polygon's handling of internal points
* <https://github.com/georust/geo/pull/679>
* Implemented `ClosestPoint` method for types Triangle, Rect, GeometryCollection, Coordinate and the Geometry enum.
* <https://github.com/georust/geo/pull/675>
* BREAKING: `TryMapCoords` Result is now generic rather than a Box<dyn Error>.
* <https://github.com/georust/geo/issues/722>
* Add `Transform` algorithm
* <https://github.com/georust/geo/pull/718>

## 0.18.0

Expand Down
2 changes: 1 addition & 1 deletion geo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rstar = { version = "0.8" }
geographiclib-rs = { version = "0.2" }
log = "0.4.11"

proj = { version = "0.23.1", optional = true }
proj = { version = "0.25", optional = true }

geo-types = { version = "0.7.2", features = ["approx", "use-rstar"] }

Expand Down
3 changes: 3 additions & 0 deletions geo/src/algorithm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ pub mod rotate;
pub mod simplify;
/// Simplify `Geometries` using the Visvalingam-Whyatt algorithm. Includes a topology-preserving variant.
pub mod simplifyvw;
/// Transform a geometry using PROJ.
#[cfg(feature = "use-proj")]
pub mod transform;
/// Translate a `Geometry` along the given offsets.
pub mod translate;
/// Calculate the Vincenty distance between two `Point`s.
Expand Down
117 changes: 117 additions & 0 deletions geo/src/algorithm/transform.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use std::{convert::TryInto, error::Error, fmt};

/// Transform a geometry using PROJ.
pub trait Transform<T> {
type Output;

/// Transform a geometry.
///
/// # Examples
///
/// Transform a geometry using a PROJ string definition:
///
/// ```
/// use geo::{self, prelude::*};
///
/// let point = geo::point!(x: -36.508f32, y: -54.2815f32);
///
/// assert_eq!(
/// point.transform("+proj=axisswap +order=2,1,3,4").unwrap(),
/// geo::point!(x: -54.2815f32, y: -36.508f32)
/// );
/// ```
///
/// Transform a geometry from one CRS to another CRS:
///
/// ```
/// use geo::{self, prelude::*};
///
/// let point = geo::point!(x: -36.508f32, y: -54.2815f32);
///
/// assert_eq!(
/// point.transform(("EPSG:4326", "EPSG:3857")).unwrap(),
/// geo::point!(x: -4064052.0f32, y: -7223650.5f32)
/// );
/// ```
fn transform(
&self,
proj: impl TryInto<proj::Proj, Error = proj::ProjCreateError>,
) -> Result<Self::Output, TransformError>;

/// Transform a geometry from one CRS to another CRS.
///
/// # Examples
///
/// ```
/// use geo::{self, prelude::*};
///
/// let point: geo::Point<f32> = geo::point!(x: -36.508f32, y: -54.2815f32);
///
/// assert_eq!(
/// point.transform_crs_to_crs("EPSG:4326", "EPSG:3857").unwrap(),
/// geo::point!(x: -4064052.0f32, y: -7223650.5f32)
/// );
/// ```
fn transform_crs_to_crs(
&self,
source_crs: &str,
target_crs: &str,
) -> Result<Self::Output, TransformError>;
}

impl<T, G> Transform<T> for G
where
T: crate::CoordFloat,
G: crate::algorithm::map_coords::TryMapCoords<T, T, proj::ProjError>,
{
type Output = G::Output;

fn transform(
&self,
proj: impl TryInto<proj::Proj, Error = proj::ProjCreateError>,
) -> Result<Self::Output, TransformError> {
let transformer: proj::Proj = proj.try_into()?;
let result: Result<G::Output, proj::ProjError> =
self.try_map_coords(|&(x, y)| transformer.convert((x, y)));
Ok(result?)
}

fn transform_crs_to_crs(
&self,
source_crs: &str,
target_crs: &str,
) -> Result<Self::Output, TransformError> {
self.transform((source_crs, target_crs))
}
}

#[derive(Debug)]
pub enum TransformError {
UnknownCrs,
ProjCreateError(proj::ProjCreateError),
ProjError(proj::ProjError),
}

impl From<proj::ProjError> for TransformError {
fn from(e: proj::ProjError) -> Self {
TransformError::ProjError(e)
}
}

impl From<proj::ProjCreateError> for TransformError {
fn from(e: proj::ProjCreateError) -> Self {
TransformError::ProjCreateError(e)
}
}

impl fmt::Display for TransformError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TransformError::UnknownCrs => write!(f, "Unknown CRS"),
TransformError::ProjCreateError(err) => err.fmt(f),
TransformError::ProjError(err) => err.fmt(f),
}
}
}

impl Error for TransformError {}
4 changes: 3 additions & 1 deletion geo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
//! - **[`Centroid`](algorithm::centroid::Centroid)**: Calculate the centroid of a geometry
//! - **[`HaversineDestination`](algorithm::haversine_destination::HaversineDestination)**:
//! - **[`HaversineIntermediate`](algorithm::haversine_intermediate::HaversineIntermediate)**:
//! - **`Proj`**: Project geometries with the `proj` crate
//! - **[`Proj`](algorithm::proj::Proj)**: Project geometries with the `proj` crate (requires the `use-proj` feature)
//! - **[`ChaikinSmoothing`](algorithm::chaikin_smoothing::ChaikinSmoothing)**: Smoothen `LineString`, `Polygon`, `MultiLineString` and `MultiPolygon` using Chaikins algorithm.
//!
//! # Features
Expand Down Expand Up @@ -252,6 +252,8 @@ pub mod prelude {
pub use crate::algorithm::rotate::{Rotate, RotatePoint};
pub use crate::algorithm::simplify::Simplify;
pub use crate::algorithm::simplifyvw::SimplifyVW;
#[cfg(feature = "use-proj")]
pub use crate::algorithm::transform::Transform;
pub use crate::algorithm::translate::Translate;
pub use crate::algorithm::vincenty_distance::VincentyDistance;
pub use crate::algorithm::vincenty_length::VincentyLength;
Expand Down

0 comments on commit 73af924

Please sign in to comment.