use crate::{TransBuild, TransParams};
use oxiproj_core::{Coord, IoUnits, Operation, ProjResult, M_HALFPI};
#[derive(Debug)]
struct Geoc {
one_es: f64,
rone_es: f64,
es: f64,
}
impl Operation for Geoc {
#[allow(clippy::float_cmp)]
fn forward_4d(&self, c: Coord) -> ProjResult<Coord> {
let v = c.v();
let limit = M_HALFPI - 1e-9;
if v[1] > limit || v[1] < -limit || self.es == 0.0 {
return Ok(c);
}
Ok(Coord::new(
v[0],
(self.one_es * v[1].tan()).atan(),
v[2],
v[3],
))
}
#[allow(clippy::float_cmp)]
fn inverse_4d(&self, c: Coord) -> ProjResult<Coord> {
let v = c.v();
let limit = M_HALFPI - 1e-9;
if v[1] > limit || v[1] < -limit || self.es == 0.0 {
return Ok(c);
}
Ok(Coord::new(
v[0],
(self.rone_es * v[1].tan()).atan(),
v[2],
v[3],
))
}
fn has_inverse(&self) -> bool {
true
}
}
pub fn new(p: &TransParams) -> ProjResult<TransBuild> {
let e = p.ellipsoid;
Ok(TransBuild::new(
Box::new(Geoc {
one_es: e.one_es,
rone_es: e.rone_es,
es: e.es,
}),
IoUnits::Radians,
IoUnits::Radians,
))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::TransParamLookup;
use oxiproj_core::{Ellipsoid, DEG_TO_RAD};
struct NoParams;
impl TransParamLookup for NoParams {
fn get_dms(&self, _key: &str) -> Option<f64> {
None
}
fn get_f64(&self, _key: &str) -> Option<f64> {
None
}
fn get_int(&self, _key: &str) -> Option<i64> {
None
}
fn get_str(&self, _key: &str) -> Option<&str> {
None
}
fn get_bool(&self, _key: &str) -> bool {
false
}
fn exists(&self, _key: &str) -> bool {
false
}
}
#[test]
fn geoc_forward_inverse_wgs84() {
let ell = Ellipsoid::named("WGS84").unwrap();
let b = new(&TransParams {
ellipsoid: &ell,
params: &NoParams,
registry: None,
})
.unwrap();
let op = b.operation;
let out = op
.forward_4d(Coord::new(12.0 * DEG_TO_RAD, 55.0 * DEG_TO_RAD, 0.0, 0.0))
.unwrap();
assert!((out.v()[1] - 54.818973309 * DEG_TO_RAD).abs() < 1e-9);
assert!((out.v()[0] - 12.0 * DEG_TO_RAD).abs() < 1e-15);
let back = op.inverse_4d(out).unwrap();
assert!((back.v()[1] - 55.0 * DEG_TO_RAD).abs() < 1e-9);
}
}