geoconvert 1.0.2

A lightweight library to convert between geographic coordinate systems
Documentation
use crate::{ThisOrThat, constants::{WGS84_A, WGS84_F, UPS_K0}, utility::{GeoMath, dms}, latlon::LatLon};

const F: f64 = WGS84_F;
const E2: f64 = F * (2.0 - F);

pub(crate) struct PolarStereographic {
    a: f64,
    k0: f64,
    es: f64,
    c: f64,
}

impl PolarStereographic {
    pub fn ups() -> PolarStereographic {

        let es = (F < 0.0).ternary(-1.0, 1.0) * E2.abs().sqrt();
        let c = (1.0 - F) * 1_f64.eatanhe(es).exp();

        Self {
            a: WGS84_A,
            k0: UPS_K0,
            es,
            c,
        }
    }

    #[allow(clippy::wrong_self_convention)]
    pub fn from_latlon(&self, northp: bool, lat: f64, lon: f64) -> (f64, f64) {
        let lat = lat * northp.ternary(1.0, -1.0);

        let tau = lat.to_radians().tan();
        let taup = tau.taupf(self.es);
        let mut rho = 1_f64.hypot(taup) + taup.abs();
        rho = (taup >= 0.0).ternary_lazy(|| (!lat.eps_eq(f64::from(dms::QD))).ternary_lazy(|| 1.0 / rho, || 0.0), || rho);
        rho *= 2.0 * self.k0 * self.a / self.c;

        let (mut x, mut y) = {
            let (x, y) = lon.to_radians().sin_cos();
            (x, y)
        };

        x *= rho;
        y *= northp.ternary(-rho, rho);

        (x, y)
    }

    pub fn to_latlon(&self, northp: bool, x: f64, y: f64) -> LatLon {
        let rho = x.hypot(y);
        let t = (rho != 0.0)
            .ternary_lazy(
                || rho / (2.0 * self.k0 * self.a / self.c),
                || f64::EPSILON.powi(2)
            );
        let taup = (1.0 / t - t) / 2.;
        let tau = taup.tauf(self.es);

        let lat = northp.ternary(1.0, -1.0) * tau.atan().to_degrees();
        let lon = x.atan2(northp.ternary(-y, y)).to_degrees();

        LatLon {
            latitude: lat,
            longitude: lon,
        }
    }
}