use crate::error::ProjResult;
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EnFn {
pub data: [f64; 13],
}
pub fn pj_enfn(n: f64) -> ProjResult<EnFn> {
use crate::math::aux::{pj_auxlat_coeffs, pj_rectifying_radius, AuxLat};
let mut data = [0.0_f64; 13];
data[0] = pj_rectifying_radius(n);
pj_auxlat_coeffs(n, AuxLat::Geographic, AuxLat::Rectifying, &mut data[1..7])?;
pj_auxlat_coeffs(n, AuxLat::Rectifying, AuxLat::Geographic, &mut data[7..13])?;
Ok(EnFn { data })
}
pub fn pj_mlfn(phi: f64, sphi: f64, cphi: f64, en: &EnFn) -> f64 {
use crate::math::aux::pj_auxlat_convert_sc;
en.data[0] * pj_auxlat_convert_sc(phi, sphi, cphi, &en.data[1..7], 6)
}
pub fn pj_inv_mlfn(mu: f64, en: &EnFn) -> f64 {
use crate::math::aux::pj_auxlat_convert;
pj_auxlat_convert(mu / en.data[0], &en.data[7..13], 6)
}
#[cfg(test)]
mod tests {
use super::*;
fn wgs84_n() -> f64 {
let f = 1.0 / 298.257223563_f64;
f / (2.0 - f)
}
#[test]
fn round_trip_sample_latitudes() {
let n = wgs84_n();
let en = pj_enfn(n).expect("enfn");
for &phi in &[-1.4, -0.7, -0.1, 0.0, 0.1, 0.7, 1.4] {
let m = pj_mlfn(phi, phi.sin(), phi.cos(), &en);
let back = pj_inv_mlfn(m, &en);
assert!((back - phi).abs() < 1e-12, "phi={} back={}", phi, back);
}
}
#[test]
fn round_trip_dense_sweep() {
let n = wgs84_n();
let en = pj_enfn(n).expect("enfn");
let mut phi = -1.45_f64;
while phi <= 1.45 {
let m = pj_mlfn(phi, phi.sin(), phi.cos(), &en);
let back = pj_inv_mlfn(m, &en);
assert!((back - phi).abs() < 1e-11, "phi={} back={}", phi, back);
phi += 0.02;
}
}
#[test]
fn mlfn_at_equator_is_zero() {
let n = wgs84_n();
let en = pj_enfn(n).expect("enfn");
let m = pj_mlfn(0.0, 0.0, 1.0, &en);
assert!(m.abs() < 1e-15, "m={}", m);
}
#[test]
fn rectifying_radius_in_expected_range() {
let n = wgs84_n();
let en = pj_enfn(n).expect("enfn");
assert!(en.data[0] > 0.99, "radius={}", en.data[0]);
assert!(en.data[0] < 1.0, "radius={}", en.data[0]);
}
#[test]
fn enfn_layout_radius_then_fwd_then_inv() {
use crate::math::aux::{pj_auxlat_coeffs, pj_rectifying_radius, AuxLat};
let n = wgs84_n();
let en = pj_enfn(n).expect("enfn");
assert_eq!(en.data[0], pj_rectifying_radius(n));
let mut fwd = [0.0_f64; 6];
pj_auxlat_coeffs(n, AuxLat::Geographic, AuxLat::Rectifying, &mut fwd).expect("fwd coeffs");
assert_eq!(&en.data[1..7], &fwd[..]);
let mut inv = [0.0_f64; 6];
pj_auxlat_coeffs(n, AuxLat::Rectifying, AuxLat::Geographic, &mut inv).expect("inv coeffs");
assert_eq!(&en.data[7..13], &inv[..]);
}
}