use core::f64::consts::PI;
use std::f64::consts::TAU;
use crate::astronomy::julian::j2000_century;
use crate::astronomy::nutation::nutation;
use crate::astronomy::{SphericalCoords, earth, eval_polynomial};
fn position_true(date: f64) -> SphericalCoords {
let coords = earth::position(date);
let s = coords.longitude + PI;
let (sp, cp) = eval_polynomial(j2000_century(date), &[
s,
-1.397_f64.to_radians(),
-0.00031_f64.to_radians(),
])
.sin_cos();
let b = (0.03916 / 3600.0_f64).to_radians() * (cp - sp);
let long = (s - (0.09033 / 3600.0_f64).to_radians()).rem_euclid(TAU);
let lat = b - coords.latitude;
SphericalCoords {
latitude: lat,
longitude: long,
..coords
}
}
pub fn position_apparent(date: f64) -> SphericalCoords {
let coords = position_true(date);
let nutation = nutation(date);
let aberration = (-20.4898 / 3600.0_f64).to_radians() / coords.distance;
SphericalCoords {
longitude: coords.longitude + nutation + aberration,
..coords
}
}
#[cfg(test)]
mod tests {
use float_cmp::assert_approx_eq;
use test_case::test_case;
use super::{position_apparent, position_true};
#[rustfmt::skip]
#[test_case(2460665.885255802, 7.442085486363556e-7, 4.712406431570293, 0.9837312104362747)]
fn expect_solar_position_true(date: f64, b: f64, l: f64, r: f64) {
let coords = position_true(date);
assert_approx_eq!(f64, coords.longitude, l);
assert_approx_eq!(f64, coords.latitude, b);
assert_approx_eq!(f64, coords.distance, r);
}
#[rustfmt::skip]
#[test_case(2460665.885255802, 7.442085486363556e-7, 4.712303394455034, 0.9837312104362747)]
fn expect_solar_position_apparent(date: f64, b: f64, l: f64, r: f64) {
let coords = position_apparent(date);
assert_approx_eq!(f64, coords.longitude, l);
assert_approx_eq!(f64, coords.latitude, b);
assert_approx_eq!(f64, coords.distance, r);
}
}