From 85568fa7a4b511975c88074a77add2d2e7794ce3 Mon Sep 17 00:00:00 2001 From: David Marteau Date: Tue, 15 Oct 2024 00:59:07 +0200 Subject: [PATCH] Add Equidistant Cylindrical 'eqc' projection --- proj4rs/src/projections/eqc.rs | 89 ++++++++++++++++++++++++++++++++++ proj4rs/src/projections/mod.rs | 4 +- projections.md | 3 +- 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 proj4rs/src/projections/eqc.rs diff --git a/proj4rs/src/projections/eqc.rs b/proj4rs/src/projections/eqc.rs new file mode 100644 index 0000000..4b66530 --- /dev/null +++ b/proj4rs/src/projections/eqc.rs @@ -0,0 +1,89 @@ +//! +//! From proj/eqc.cpp +//! +//! See also +//! +//! Simplest of all projections +//! +//! eqc: "Equidistant Cylindrical (Plate Carree)" +//! + +use crate::ellps::Ellipsoid; +use crate::errors::{Error, Result}; +use crate::parameters::ParamList; +use crate::proj::ProjData; + +// Projection stub +super::projection! { eqc } + +#[derive(Debug, Clone)] +pub(crate) struct Projection { + rc: f64, + phi0: f64, +} + +impl Projection { + pub fn eqc(p: &mut ProjData, params: &ParamList) -> Result { + let rc = params.try_angular_value("lat_ts")?.unwrap_or(0.).cos(); + if rc <= 0. { + return Err(Error::InvalidParameterValue("lat_ts should be <= 90°")); + } + p.ellps = Ellipsoid::sphere(p.ellps.a)?; + Ok(Self { rc, phi0: p.phi0 }) + } + + #[inline(always)] + pub fn forward(&self, lam: f64, phi: f64, z: f64) -> Result<(f64, f64, f64)> { + Ok((lam * self.rc, phi - self.phi0, z)) + } + + #[inline(always)] + pub fn inverse(&self, x: f64, y: f64, z: f64) -> Result<(f64, f64, f64)> { + Ok((x / self.rc, y + self.phi0, z)) + } + + pub const fn has_inverse() -> bool { + true + } + + pub const fn has_forward() -> bool { + true + } +} + + +#[cfg(test)] +mod tests { + use crate::math::consts::EPS_10; + use crate::proj::Proj; + use crate::tests::utils::{test_proj_forward, test_proj_inverse}; + + #[test] + fn proj_eqc_wgs84() { + let p = Proj::from_proj_string("+proj=eqc +ellps=WGS84").unwrap(); + + println!("{:#?}", p.projection()); + + let inputs = [ + ((2., 47., 0.), (222638.98158654713, 5232016.06728385761, 0.)), + ]; + + test_proj_forward(&p, &inputs, EPS_10); + test_proj_inverse(&p, &inputs, EPS_10); + } + + #[test] + fn proj_eqc_lat_ts() { + let p = Proj::from_proj_string("+proj=eqc +lat_ts=30 +lon_0=-90").unwrap(); + + println!("{:#?}", p.projection()); + + let inputs = [ + ((-88., 30., 0.), (192811.01392664597, 3339584.72379820701, 0.)), + ]; + + test_proj_forward(&p, &inputs, EPS_10); + test_proj_inverse(&p, &inputs, EPS_10); + } + +} diff --git a/proj4rs/src/projections/mod.rs b/proj4rs/src/projections/mod.rs index 00cd8fc..2f789a2 100644 --- a/proj4rs/src/projections/mod.rs +++ b/proj4rs/src/projections/mod.rs @@ -134,7 +134,7 @@ macro_rules! projection { use downcast; use projection; -const NUM_PROJECTIONS: usize = 21; +const NUM_PROJECTIONS: usize = 22; macro_rules! declare_projections { ($(($name:ident $(,)? $($init:ident),*)),+ $(,)?) => { @@ -161,6 +161,7 @@ macro_rules! declare_projections { // --------------------------- pub mod aea; +pub mod eqc; pub mod estmerc; pub mod etmerc; pub mod geocent; @@ -190,6 +191,7 @@ declare_projections! [ (laea), (moll, wag4, wag5), (geos), + (eqc), ]; /// diff --git a/projections.md b/projections.md index 4e4331a..c1266ca 100644 --- a/projections.md +++ b/projections.md @@ -15,6 +15,7 @@ (laea), (moll, wag4, wag5), (geos), + (eqc), ] ``` @@ -25,7 +26,7 @@ - [-] bonne - [-] cass - [-] cea -- [-] eqc +- [+] eqc - [-] eqdc - [-] eqearth - [-] equi