use super::lunisolar_terms::LUNISOLAR_TERMS;
use super::types::NutationResult;
use crate::constants::{
ARCSEC_TO_RAD, CIRCULAR_ARCSECONDS, MICROARCSEC_TO_RAD, MILLIARCSEC_TO_RAD, TWOPI,
};
use crate::errors::AstroResult;
use crate::math::fmod;
pub struct NutationIAU2000B;
impl Default for NutationIAU2000B {
fn default() -> Self {
Self::new()
}
}
impl NutationIAU2000B {
pub fn new() -> Self {
Self
}
pub fn compute(&self, jd1: f64, jd2: f64) -> AstroResult<NutationResult> {
let t = crate::utils::jd_to_centuries(jd1, jd2);
let (delta_psi_ls, delta_eps_ls) = self.compute_lunisolar(t);
const PLANETARY_BIAS_LONGITUDE: f64 = -0.135 * MILLIARCSEC_TO_RAD;
const PLANETARY_BIAS_OBLIQUITY: f64 = 0.388 * MILLIARCSEC_TO_RAD;
let delta_psi = delta_psi_ls + PLANETARY_BIAS_LONGITUDE;
let delta_eps = delta_eps_ls + PLANETARY_BIAS_OBLIQUITY;
Ok(NutationResult {
delta_psi,
delta_eps,
})
}
fn compute_lunisolar(&self, t: f64) -> (f64, f64) {
let el = fmod(485868.249036 + 1717915923.2178 * t, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD;
let elp = fmod(1287104.79305 + 129596581.0481 * t, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD;
let f = fmod(335779.526232 + 1739527262.8478 * t, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD;
let d = fmod(1072260.70369 + 1602961601.2090 * t, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD;
let om = fmod(450160.398036 + -6962890.5431 * t, CIRCULAR_ARCSECONDS) * ARCSEC_TO_RAD;
let mut dpsi = 0.0;
let mut deps = 0.0;
for &(nl, nlp, nf, nd, nom, sp, spt, cp, ce, cet, se) in
LUNISOLAR_TERMS.iter().take(77).rev()
{
let arg = fmod(
(nl as f64) * el
+ (nlp as f64) * elp
+ (nf as f64) * f
+ (nd as f64) * d
+ (nom as f64) * om,
TWOPI,
);
let (sarg, carg) = libm::sincos(arg);
dpsi += (sp + spt * t) * sarg + cp * carg;
deps += (ce + cet * t) * carg + se * sarg;
}
(dpsi * MICROARCSEC_TO_RAD, deps * MICROARCSEC_TO_RAD)
}
}