#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DaylightState {
Day,
CivilTwilight,
NauticalTwilight,
AstronomicalTwilight,
Night,
}
pub struct DayNightCycle {
pub ls_deg: f64,
}
impl DayNightCycle {
pub fn new(ls_deg: f64) -> Self {
Self { ls_deg }
}
pub fn state_at(&self, lat_deg: f64, local_time_h: f64) -> DaylightState {
let sun =
super::solar_position::SolarPosition::compute(self.ls_deg, local_time_h, lat_deg, 0.0);
let elev = sun.elevation_deg;
if elev > 0.0 {
DaylightState::Day
} else if elev > -6.0 {
DaylightState::CivilTwilight
} else if elev > -12.0 {
DaylightState::NauticalTwilight
} else if elev > -18.0 {
DaylightState::AstronomicalTwilight
} else {
DaylightState::Night
}
}
pub fn ambient_light(&self, lat_deg: f64, local_time_h: f64) -> f64 {
let sun =
super::solar_position::SolarPosition::compute(self.ls_deg, local_time_h, lat_deg, 0.0);
let elev = sun.elevation_deg;
if elev > 10.0 {
1.0
} else if elev > 0.0 {
0.3 + 0.7 * (elev / 10.0)
} else if elev > -18.0 {
0.3 * ((elev + 18.0) / 18.0).max(0.0)
} else {
0.0
}
}
pub fn day_length_hours(&self, lat_deg: f64) -> f64 {
let decl = super::solar_position::solar_declination_deg(self.ls_deg).to_radians();
let lat = lat_deg.to_radians();
let cos_h = -(lat.tan() * decl.tan());
if cos_h <= -1.0 {
return 24.0;
}
if cos_h >= 1.0 {
return 0.0;
}
cos_h.acos().to_degrees() / 180.0 * 24.0
}
}