pub mod gudermannian {
pub fn fwd(arg: f64) -> f64 {
arg.sinh().atan()
}
pub fn inv(arg: f64) -> f64 {
arg.tan().asinh()
}
}
pub fn ts(sincos: (f64, f64), e: f64) -> f64 {
let factor = if sincos.0 > 0. {
sincos.1 / (1. + sincos.0)
} else {
(1. - sincos.0) / sincos.1
};
(e * (e * sincos.0).atanh()).exp() * factor
}
pub fn pj_msfn(sincos: (f64, f64), es: f64) -> f64 {
sincos.1 / (1. - sincos.0 * sincos.0 * es).sqrt()
}
pub fn pj_phi2(ts0: f64, e: f64) -> f64 {
sinhpsi_to_tanphi((1. / ts0 - ts0) / 2., e).atan()
}
pub fn qs(sinphi: f64, e: f64) -> f64 {
let es = e * e;
let one_es = 1.0 - es;
if e < 1e-7 {
return 2.0 * sinphi;
}
let con = e * sinphi;
let div1 = 1.0 - con * con;
let div2 = 1.0 + con;
one_es * (sinphi / div1 - (0.5 / e) * ((1. - con) / div2).ln())
}
pub fn sinhpsi_to_tanphi(taup: f64, e: f64) -> f64 {
const MAX_ITER: usize = 5;
let rooteps: f64 = f64::EPSILON.sqrt();
let tol: f64 = rooteps / 10.; let tmax: f64 = 2. / rooteps;
let e2m = 1. - e * e;
let stol = tol * taup.abs().max(1.0);
let mut tau = if taup.abs() > 70. {
taup * (e * e.atanh()).exp()
} else {
taup / e2m
};
if (tau.abs() >= tmax) || tau.is_nan() {
return tau;
}
for _ in 0..MAX_ITER {
let tau1 = (1. + tau * tau).sqrt();
let sig = (e * (e * tau / tau1).atanh()).sinh();
let taupa = (1. + sig * sig).sqrt() * tau - sig * tau1;
let dtau =
(taup - taupa) * (1. + e2m * (tau * tau)) / (e2m * tau1 * (1. + taupa * taupa).sqrt());
tau += dtau;
if (dtau.abs() < stol) || tau.is_nan() {
return tau;
}
}
f64::NAN
}