use crate::calendar::julian_centuries;
use crate::coords::{deg_to_rad, normalize_degrees};
use crate::planet::{Planet, PlanetaryPosition};
pub fn solar_longitude(jd: f64) -> f64 {
let (e_lon, _e_lat, _e_r) = crate::vsop87::earth_heliocentric(jd);
normalize_degrees(e_lon + 180.0)
}
pub fn solar_distance_au(jd: f64) -> f64 {
let (_lon, _lat, r) = crate::vsop87::earth_heliocentric(jd);
r
}
pub fn solar_latitude(jd: f64) -> f64 {
let (_lon, lat, _r) = crate::vsop87::earth_heliocentric(jd);
-lat
}
pub fn solar_position(jd: f64) -> PlanetaryPosition {
PlanetaryPosition::new(
Planet::Sun,
solar_longitude(jd),
solar_latitude(jd),
solar_distance_au(jd),
crate::calendar::jd_to_unix(jd),
)
}
pub fn equation_of_time(jd: f64) -> f64 {
let t = julian_centuries(jd);
let l0 = deg_to_rad(mean_longitude_meeus(t));
let m = deg_to_rad(mean_anomaly_meeus(t));
let e = 0.016_708_634 - 0.000_042_037 * t;
let eps = deg_to_rad(crate::coords::mean_obliquity(t));
let y = (eps / 2.0).tan().powi(2);
let eot = y * (2.0 * l0).sin() - 2.0 * e * m.sin() + 4.0 * e * y * m.sin() * (2.0 * l0).cos()
- 0.5 * y * y * (4.0 * l0).sin()
- 1.25 * e * e * (2.0 * m).sin();
crate::coords::rad_to_deg(eot) * 4.0
}
fn mean_longitude_meeus(t: f64) -> f64 {
normalize_degrees((0.000_303_2 * t + 36_000.769_83) * t + 280.466_46)
}
fn mean_anomaly_meeus(t: f64) -> f64 {
normalize_degrees((-0.000_153_7 * t + 35_999.050_29) * t + 357.529_11)
}
#[cfg(feature = "meeus")]
fn equation_of_center_meeus(t: f64, m_deg: f64) -> f64 {
let m = deg_to_rad(m_deg);
((-0.000_014 * t - 0.004_817) * t + 1.914_602) * m.sin()
+ (-0.000_101 * t + 0.019_993) * (2.0 * m).sin()
+ 0.000_289 * (3.0 * m).sin()
}
#[cfg(feature = "meeus")]
pub fn solar_longitude_meeus(jd: f64) -> f64 {
let t = julian_centuries(jd);
let l0 = mean_longitude_meeus(t);
let m = mean_anomaly_meeus(t);
let c = equation_of_center_meeus(t, m);
let sun_lon = l0 + c;
let omega = 125.04 - 1934.136 * t;
let correction = -0.005_69 - 0.004_78 * deg_to_rad(omega).sin();
normalize_degrees(sun_lon + correction)
}
#[cfg(feature = "meeus")]
pub fn solar_distance_au_meeus(jd: f64) -> f64 {
let t = julian_centuries(jd);
let m = mean_anomaly_meeus(t);
let m_rad = deg_to_rad(m);
let e = (-0.000_000_126_7 * t - 0.000_042_037) * t + 0.016_708_634;
let v_rad = m_rad + deg_to_rad(equation_of_center_meeus(t, m));
1.000_001_018 * (1.0 - e * e) / (1.0 + e * v_rad.cos())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn solar_longitude_j2000() {
let lon = solar_longitude(2_451_545.0);
assert!((lon - 280.47).abs() < 0.2, "got {lon}");
}
#[test]
fn solar_longitude_meeus_25a_epoch() {
let lon = solar_longitude(2_448_908.5);
assert!((lon - 199.91).abs() < 0.1, "got {lon}");
}
#[test]
fn solar_distance_meeus_25a() {
let dist = solar_distance_au(2_448_908.5);
assert!((dist - 0.9977).abs() < 0.001, "got {dist}");
}
#[test]
fn solar_latitude_nonzero() {
let lat = solar_latitude(2_451_545.0);
assert!(lat.abs() < 0.01, "lat = {lat}");
}
#[test]
fn solar_position_struct() {
let pos = solar_position(2_451_545.0);
assert_eq!(pos.planet, Planet::Sun);
assert!(pos.longitude_deg >= 0.0 && pos.longitude_deg < 360.0);
assert!(pos.distance_au > 0.98 && pos.distance_au < 1.02);
}
#[test]
fn solar_longitude_range() {
for day in 0..365 {
let jd = 2_451_545.0 + day as f64;
let lon = solar_longitude(jd);
assert!(
(0.0..360.0).contains(&lon),
"longitude {lon} out of range at day {day}"
);
}
}
#[test]
fn equation_of_time_range() {
for day in 0..365 {
let jd = 2_451_545.0 + day as f64;
let eot = equation_of_time(jd);
assert!(
eot.abs() < 20.0,
"EoT {eot} min out of expected range at day {day}"
);
}
}
}