mod anomaly;
mod center;
mod declination;
mod hourangle;
mod longitude;
mod perihelion;
mod transit;
use core::f64::consts::PI;
use chrono::{DateTime, NaiveDate, Utc};
use crate::Coordinates;
use crate::event::SolarEvent;
use crate::julian::{julian_to_unix, mean_solar_noon};
use self::anomaly::solar_mean_anomaly;
use self::center::equation_of_center;
use self::declination::declination;
use self::hourangle::hour_angle;
use self::longitude::ecliptic_longitude;
use self::transit::solar_transit;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct SolarDay {
lat: f64,
altitude: f64,
solar_transit: f64,
declination: f64,
}
impl SolarDay {
pub fn new(coord: Coordinates, date: NaiveDate) -> Self {
let day = mean_solar_noon(coord.lon(), date);
let solar_anomaly = solar_mean_anomaly(day);
let equation_of_center = equation_of_center(solar_anomaly);
let ecliptic_longitude = ecliptic_longitude(solar_anomaly, equation_of_center, day);
let solar_transit = solar_transit(day, solar_anomaly, ecliptic_longitude);
let declination = declination(ecliptic_longitude);
Self {
lat: coord.lat(),
altitude: 0.,
solar_transit,
declination,
}
}
pub fn with_altitude(mut self, altitude: f64) -> Self {
self.altitude = altitude;
self
}
pub fn event_time(&self, event: SolarEvent) -> Option<DateTime<Utc>> {
let hour_angle = hour_angle(self.lat, self.declination, self.altitude, event);
if hour_angle.is_nan() {
return None;
}
let frac = hour_angle / (2. * PI);
let timestamp = julian_to_unix(self.solar_transit + frac);
Some(DateTime::from_timestamp(timestamp, 0).expect("invalid result"))
}
}