use crate::astronomical::core::{JulianDay, constants::*};
pub struct SolarCalculator;
impl SolarCalculator {
pub fn mean_longitude(jd: JulianDay) -> f64 {
let t = jd.centuries_since_j2000();
let l0 = 280.46646 + 36000.76983 * t + 0.0003032 * t * t;
normalize_degrees(l0)
}
pub fn mean_anomaly(jd: JulianDay) -> f64 {
let t = jd.centuries_since_j2000();
let m = 357.52911 + 35999.05029 * t - 0.0001537 * t * t;
normalize_degrees(m)
}
pub fn equation_of_center(jd: JulianDay) -> f64 {
let t = jd.centuries_since_j2000();
let m = Self::mean_anomaly(jd) * DEG_TO_RAD;
(1.914602 - 0.004817 * t - 0.000014 * t * t) * m.sin()
+ (0.019993 - 0.000101 * t) * (2.0 * m).sin()
+ 0.000289 * (3.0 * m).sin()
}
pub fn true_longitude(jd: JulianDay) -> f64 {
let l0 = Self::mean_longitude(jd);
let c = Self::equation_of_center(jd);
normalize_degrees(l0 + c)
}
pub fn apparent_longitude(jd: JulianDay) -> f64 {
let true_long = Self::true_longitude(jd);
let t = jd.centuries_since_j2000();
let omega = 125.04 - 1934.136 * t;
let nutation = -0.00569 - 0.00478 * (omega * DEG_TO_RAD).sin();
normalize_degrees(true_long + nutation)
}
}
fn normalize_degrees(angle: f64) -> f64 {
angle.rem_euclid(360.0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sun_longitude_j2000() {
let jd = JulianDay(J2000_0);
let longitude = SolarCalculator::true_longitude(jd);
assert!((longitude - 280.0).abs() < 5.0);
}
}