use crate::temporal::epoch::J2000EPOCH;
use sciforge::hub::prelude::constants::AU;
pub const EARTHAXIALTILTDEG: f64 = 23.4393;
pub struct SolarPosition {
pub azimuthdeg: f64,
pub elevationdeg: f64,
pub distanceau: f64,
pub direction: [f64; 3],
}
impl SolarPosition {
pub fn compute(juliandate: f64, latdeg: f64, londeg: f64) -> Self {
let d = juliandate - J2000EPOCH;
let meananomaly = (357.5291 + 0.98560028 * d) % 360.0;
let mrad = meananomaly.to_radians();
let equationofcenter =
1.9148 * mrad.sin() + 0.0200 * (2.0 * mrad).sin() + 0.0003 * (3.0 * mrad).sin();
let lvenus = (3.1761467 + 1021.3285544 * d / 36525.0) % (2.0 * std::f64::consts::PI);
let ljupiter = (0.599546 + 145.2702853 * d / 36525.0) % (2.0 * std::f64::consts::PI);
let perturbation = 0.00313 * (2.0 * lvenus - mrad).sin()
+ 0.00178 * (3.0 * mrad).sin()
+ 0.00077 * (ljupiter - mrad).sin();
let eclipticlon =
(meananomaly + equationofcenter + perturbation + 180.0 + 102.9372) % 360.0;
let eclrad = eclipticlon.to_radians();
let obliquityrad = EARTHAXIALTILTDEG.to_radians();
let declination = (obliquityrad.sin() * eclrad.sin()).asin();
let rightascension = (obliquityrad.cos() * eclrad.sin()).atan2(eclrad.cos());
let siderealtime = (280.16 + 360.9856235 * d + londeg) % 360.0;
let hourangle = siderealtime.to_radians() - rightascension;
let latrad = latdeg.to_radians();
let altitude = (latrad.sin() * declination.sin()
+ latrad.cos() * declination.cos() * hourangle.cos())
.asin();
let azimuth = (declination.sin() - altitude.sin() * latrad.sin())
.atan2(altitude.cos() * latrad.cos());
let dirx = altitude.cos() * azimuth.sin();
let diry = altitude.sin();
let dirz = altitude.cos() * azimuth.cos();
Self {
azimuthdeg: azimuth.to_degrees(),
elevationdeg: altitude.to_degrees(),
distanceau: 1.0 - 0.0167 * mrad.cos(),
direction: [dirx, diry, dirz],
}
}
pub fn distancem(&self) -> f64 {
self.distanceau * AU
}
pub fn isabovehorizon(&self) -> bool {
self.elevationdeg > 0.0
}
}