use crate::lighting::solar_position::SolarPosition;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DaylightState {
Day,
CivilTwilight,
NauticalTwilight,
AstronomicalTwilight,
Night,
}
pub struct DayNightCycle {
pub juliandate: f64,
}
impl DayNightCycle {
pub fn new(juliandate: f64) -> Self {
Self { juliandate }
}
pub fn stateat(&self, latdeg: f64, londeg: f64) -> DaylightState {
let sun = SolarPosition::compute(self.juliandate, latdeg, londeg);
match sun.elevationdeg {
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,
e if e <= -18.0 => DaylightState::Night,
e => {
debug_assert!(e.is_nan());
DaylightState::Night
}
}
}
pub fn terminatorpoints(&self, numpoints: usize) -> Vec<[f64; 2]> {
let mut points = Vec::with_capacity(numpoints);
for i in 0..numpoints {
let lon = -180.0 + 360.0 * i as f64 / numpoints as f64;
let mut latlow = -90.0f64;
let mut lathigh = 90.0f64;
for iter in 0..30 {
let latmid = (latlow + lathigh) / 2.0;
let sun = SolarPosition::compute(self.juliandate, latmid, lon);
if sun.elevationdeg > 0.0 {
latlow = latmid;
} else {
lathigh = latmid;
}
if (lathigh - latlow).abs() < 1e-8 || iter == 29 {
break;
}
}
points.push([(latlow + lathigh) / 2.0, lon]);
}
points
}
pub fn ambientlight(&self, latdeg: f64, londeg: f64) -> f64 {
let sun = SolarPosition::compute(self.juliandate, latdeg, londeg);
let e = sun.elevationdeg;
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.0f64).powf(e / 6.0)
} else if e > -12.0 {
0.05 * (10.0f64).powf((e + 6.0) / 6.0)
} else if e > -18.0 {
0.005 * (10.0f64).powf((e + 12.0) / 6.0)
} else {
0.001
}
}
}