use crate::astronomy::eval_polynomial;
use crate::astronomy::julian::j2000_century;
pub fn nutation(date: f64) -> f64 {
let t = j2000_century(date);
let d = eval_polynomial(t, &[297.85036, 445267.11148, -0.0019142, 1.0 / 189474.0]).to_radians();
let m = eval_polynomial(t, &[357.52772, 35999.05034, -0.0001603, -1.0 / 300000.0]).to_radians();
let m1 = eval_polynomial(t, &[134.96298, 477198.867398, 0.0086972, 1.0 / 56250.0]).to_radians();
let f = eval_polynomial(t, &[93.27191, 483202.017538, -0.0036825, 1.0 / 327270.0]).to_radians();
let w = eval_polynomial(t, &[125.04452, -1934.136261, 0.0020708, 1.0 / 450000.0]).to_radians();
let mut long = 0.0;
for ([a0, a1, a2, a3, a4], sin, _) in TABLE.iter().rev() {
let a0 = *a0 as f64;
let a1 = *a1 as f64;
let a2 = *a2 as f64;
let a3 = *a3 as f64;
let a4 = *a4 as f64;
let arg = a4.mul_add(w, a3.mul_add(f, a2.mul_add(m1, a0.mul_add(d, a1 * m))));
long += arg.sin() * sin[1].mul_add(t, sin[0]);
}
(long * 0.0001 / 3600.0_f64).to_radians()
}
#[rustfmt::skip]
const TABLE: [([i8; 5], [f64; 2], [f64; 2]); 63] = [
([0, 0, 0, 0, 1], [-171996.0, -174.2], [92025.0, 8.9]),
([-2, 0, 0, 2, 2], [-13187.0, -1.6], [5736.0, -3.1]),
([0, 0, 0, 2, 2], [-2274.0, -0.2], [977.0, -0.5]),
([0, 0, 0, 0, 2], [2062.0, 0.2], [-895.0, 0.5]),
([0, 1, 0, 0, 0], [1426.0, -3.4], [54.0, -0.1]),
([0, 0, 1, 0, 0], [712.0, 0.1], [-7.0, 0.0]),
([-2, 1, 0, 2, 2], [-517.0, 1.2], [224.0, -0.6]),
([0, 0, 0, 2, 1], [-386.0, -0.4], [200.0, 0.0]),
([0, 0, 1, 2, 2], [-301.0, 0.0], [129.0, -0.1]),
([-2, -1, 0, 2, 2], [217.0, -0.5], [-95.0, 0.3]),
([-2, 0, 1, 0, 0], [-158.0, 0.0], [0.0, 0.0]),
([-2, 0, 0, 2, 1], [129.0, 0.1], [-70.0, 0.0]),
([0, 0, -1, 2, 2], [123.0, 0.0], [-53.0, 0.0]),
([2, 0, 0, 0, 0], [63.0, 0.0], [0.0, 0.0]),
([0, 0, 1, 0, 1], [63.0, 0.1], [-33.0, 0.0]),
([2, 0, -1, 2, 2], [-59.0, 0.0], [26.0, 0.0]),
([0, 0, -1, 0, 1], [-58.0, -0.1], [32.0, 0.0]),
([0, 0, 1, 2, 1], [-51.0, 0.0], [27.0, 0.0]),
([-2, 0, 2, 0, 0], [48.0, 0.0], [0.0, 0.0]),
([0, 0, -2, 2, 1], [46.0, 0.0], [-24.0, 0.0]),
([2, 0, 0, 2, 2], [-38.0, 0.0], [16.0, 0.0]),
([0, 0, 2, 2, 2], [-31.0, 0.0], [13.0, 0.0]),
([0, 0, 2, 0, 0], [29.0, 0.0], [0.0, 0.0]),
([-2, 0, 1, 2, 2], [29.0, 0.0], [-12.0, 0.0]),
([0, 0, 0, 2, 0], [26.0, 0.0], [0.0, 0.0]),
([-2, 0, 0, 2, 0], [-22.0, 0.0], [0.0, 0.0]),
([0, 0, -1, 2, 1], [21.0, 0.0], [-10.0, 0.0]),
([0, 2, 0, 0, 0], [17.0, -0.1], [0.0, 0.0]),
([2, 0, -1, 0, 1], [16.0, 0.0], [-8.0, 0.0]),
([-2, 2, 0, 2, 2], [-16.0, 0.1], [7.0, 0.0]),
([0, 1, 0, 0, 1], [-15.0, 0.0], [9.0, 0.0]),
([-2, 0, 1, 0, 1], [-13.0, 0.0], [7.0, 0.0]),
([0, -1, 0, 0, 1], [-12.0, 0.0], [6.0, 0.0]),
([0, 0, 2, -2, 0], [11.0, 0.0], [0.0, 0.0]),
([2, 0, -1, 2, 1], [-10.0, 0.0], [5.0, 0.0]),
([2, 0, 1, 2, 2], [-8.0, 0.0], [3.0, 0.0]),
([0, 1, 0, 2, 2], [7.0, 0.0], [-3.0, 0.0]),
([-2, 1, 1, 0, 0], [-7.0, 0.0], [0.0, 0.0]),
([0, -1, 0, 2, 2], [-7.0, 0.0], [3.0, 0.0]),
([2, 0, 0, 2, 1], [-7.0, 0.0], [3.0, 0.0]),
([2, 0, 1, 0, 0], [6.0, 0.0], [0.0, 0.0]),
([-2, 0, 2, 2, 2], [6.0, 0.0], [-3.0, 0.0]),
([-2, 0, 1, 2, 1], [6.0, 0.0], [-3.0, 0.0]),
([2, 0, -2, 0, 1], [-6.0, 0.0], [3.0, 0.0]),
([2, 0, 0, 0, 1], [-6.0, 0.0], [3.0, 0.0]),
([0, -1, 1, 0, 0], [5.0, 0.0], [0.0, 0.0]),
([-2, -1, 0, 2, 1], [-5.0, 0.0], [3.0, 0.0]),
([-2, 0, 0, 0, 1], [-5.0, 0.0], [3.0, 0.0]),
([0, 0, 2, 2, 1], [-5.0, 0.0], [3.0, 0.0]),
([-2, 0, 2, 0, 1], [4.0, 0.0], [0.0, 0.0]),
([-2, 1, 0, 2, 1], [4.0, 0.0], [0.0, 0.0]),
([0, 0, 1, -2, 0], [4.0, 0.0], [0.0, 0.0]),
([-1, 0, 1, 0, 0], [-4.0, 0.0], [0.0, 0.0]),
([-2, 1, 0, 0, 0], [-4.0, 0.0], [0.0, 0.0]),
([1, 0, 0, 0, 0], [-4.0, 0.0], [0.0, 0.0]),
([0, 0, 1, 2, 0], [3.0, 0.0], [0.0, 0.0]),
([0, 0, -2, 2, 2], [-3.0, 0.0], [0.0, 0.0]),
([-1, -1, 1, 0, 0], [-3.0, 0.0], [0.0, 0.0]),
([0, 1, 1, 0, 0], [-3.0, 0.0], [0.0, 0.0]),
([0, -1, 1, 2, 2], [-3.0, 0.0], [0.0, 0.0]),
([2, -1, -1, 2, 2], [-3.0, 0.0], [0.0, 0.0]),
([0, 0, 3, 2, 2], [-3.0, 0.0], [0.0, 0.0]),
([2, -1, 0, 2, 2], [-3.0, 0.0], [0.0, 0.0]),
];
#[cfg(test)]
mod tests {
use float_cmp::assert_approx_eq;
use test_case::test_case;
use super::nutation;
#[test_case(2460665.885255802, -0.0000020569363459503144)]
fn expect_nutation_longitude(date: f64, expected: f64) {
assert_approx_eq!(f64, nutation(date), expected);
}
}