#![forbid(unsafe_code)]
mod nutation_data;
mod vsop87d_earth;
use core::f64::consts::{PI, TAU};
use nutation_data::NUT_COEFFS;
use vsop87d_earth::{EARTH_L, EARTH_R};
const ARCSEC_TO_RAD: f64 = PI / 180.0 / 3600.0;
const RAD_TO_DEG: f64 = 180.0 / PI;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SolarState {
pub true_longitude_degrees: f64,
pub apparent_longitude_degrees: f64,
pub radius_au: f64,
}
pub fn solar_ecliptic_state(jde_tt: f64) -> SolarState {
let tau = (jde_tt - 2451545.0) / 365250.0; let t = (jde_tt - 2451545.0) / 36525.0;
let mut lon = eval_vsop_series(EARTH_L, tau);
let r = eval_vsop_series(EARTH_R, tau);
let tau2 = tau * tau;
lon += (-0.106674 - 0.616597 * tau2 + 0.315446 * tau2 * tau2 - 0.050315 * tau2 * tau2 * tau2)
/ 206264.806;
let geo_true = lon + PI;
let (dl, dlp, df, dd, dom) = delaunay_args(t);
let dpsi = nutation_dpsi(dl, dlp, df, dd, dom, t);
let apparent = geo_true + dpsi * ARCSEC_TO_RAD + (-20.4898 / r) * ARCSEC_TO_RAD;
SolarState {
true_longitude_degrees: normalize_radians(geo_true) * RAD_TO_DEG,
apparent_longitude_degrees: normalize_radians(apparent) * RAD_TO_DEG,
radius_au: r,
}
}
fn eval_vsop_series(series: &[&[[f64; 3]]], tau: f64) -> f64 {
let mut result = 0.0;
let mut tau_pow = 1.0;
for terms in series {
let mut sum = 0.0;
for term in *terms {
sum += term[0] * (term[1] + term[2] * tau).cos();
}
result += sum * tau_pow;
tau_pow *= tau;
}
result
}
fn delaunay_args(t: f64) -> (f64, f64, f64, f64, f64) {
let t2 = t * t;
let t3 = t2 * t;
let t4 = t3 * t;
let l = ((485868.249036 + 1717915923.2178 * t + 31.8792 * t2 + 0.051635 * t3
- 0.00024470 * t4)
% 1296000.0)
* ARCSEC_TO_RAD;
let lp = ((1287104.79305 + 129596581.0481 * t - 0.5532 * t2 + 0.000136 * t3 - 0.00001149 * t4)
% 1296000.0)
* ARCSEC_TO_RAD;
let f = ((335779.526232 + 1739527262.8478 * t - 12.7512 * t2 - 0.001037 * t3
+ 0.00000417 * t4)
% 1296000.0)
* ARCSEC_TO_RAD;
let d = ((1072260.70369 + 1602961601.2090 * t - 6.3706 * t2 + 0.006593 * t3 - 0.00003169 * t4)
% 1296000.0)
* ARCSEC_TO_RAD;
let om = ((450160.398036 - 6962890.5431 * t + 7.4722 * t2 + 0.007702 * t3 - 0.00005939 * t4)
% 1296000.0)
* ARCSEC_TO_RAD;
(l, lp, f, d, om)
}
fn nutation_dpsi(l: f64, lp: f64, f: f64, d: f64, om: f64, t: f64) -> f64 {
let mut dpsi = 0.0;
for row in NUT_COEFFS {
let arg = row[0] * l + row[1] * lp + row[2] * f + row[3] * d + row[4] * om;
dpsi += (row[5] + row[6] * t) * arg.sin();
}
dpsi / 1e7
}
fn normalize_radians(rad: f64) -> f64 {
((rad % TAU) + TAU) % TAU
}