use crate::lighting::solar_position::SolarPosition;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DaylightState {
Day,
CivilTwilight,
NauticalTwilight,
AstronomicalTwilight,
Night,
}
pub struct DayNightCycle {
pub julian_date: f64,
}
impl DayNightCycle {
pub fn new(julian_date: f64) -> Self {
Self { julian_date }
}
pub fn state_at(&self, lat_deg: f64, lon_deg: f64) -> DaylightState {
let sun = SolarPosition::compute(self.julian_date, lat_deg, lon_deg);
match sun.elevation_deg {
e if e > 0.0 => DaylightState::Day,
e if e > -6.0 => DaylightState::CivilTwilight,
e if e > -12.0 => DaylightState::NauticalTwilight,
e if e > -18.0 => DaylightState::AstronomicalTwilight,
_ => DaylightState::Night,
}
}
pub fn terminator_points(&self, num_points: usize) -> Vec<[f64; 2]> {
let mut points = Vec::with_capacity(num_points);
for i in 0..num_points {
let lon = -180.0 + 360.0 * i as f64 / num_points as f64;
let mut lat_low = -90.0_f64;
let mut lat_high = 90.0_f64;
for _ in 0..30 {
let lat_mid = (lat_low + lat_high) / 2.0;
let sun = SolarPosition::compute(self.julian_date, lat_mid, lon);
if sun.elevation_deg > 0.0 {
lat_low = lat_mid;
} else {
lat_high = lat_mid;
}
}
points.push([(lat_low + lat_high) / 2.0, lon]);
}
points
}
pub fn ambient_light(&self, lat_deg: f64, lon_deg: f64) -> f64 {
let sun = SolarPosition::compute(self.julian_date, lat_deg, lon_deg);
let e = sun.elevation_deg;
if e > 10.0 {
1.0
} else if e > 0.0 {
0.5 + 0.5 * (e / 10.0) * (e / 10.0)
} else if e > -6.0 {
0.5 * (10.0_f64).powf(e / 6.0)
} else if e > -12.0 {
0.05 * (10.0_f64).powf((e + 6.0) / 6.0)
} else if e > -18.0 {
0.005 * (10.0_f64).powf((e + 12.0) / 6.0)
} else {
0.001
}
}
}