use crate::event::SolarEvent;
use crate::math::{acos, cos, sin, sqrt};
pub(crate) fn hour_angle(
latitude_deg: f64,
declination: f64,
altitude: f64,
event: SolarEvent,
) -> f64 {
let latitude = latitude_deg.to_radians();
let denominator = cos(latitude) * cos(declination);
let numerator =
-sin(event.angle()
+ (f64::to_radians(2.076) * altitude.signum() * sqrt(altitude.abs()) / 60.))
- sin(latitude) * sin(declination);
let sign = if event.is_morning() { -1. } else { 1. };
sign * acos(numerator / denominator)
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_relative_eq;
#[test]
fn test_oposites() {
assert_relative_eq!(
hour_angle(32., -22., 0., SolarEvent::Sunrise),
-hour_angle(32., -22., 0., SolarEvent::Sunset),
);
}
#[test]
fn test_prime_meridian() {
assert_relative_eq!(
hour_angle(0., f64::to_radians(-22.97753), 0., SolarEvent::Sunset),
f64::to_radians(90.90516),
epsilon = 0.00001
);
}
#[test]
fn test_altitude() {
assert_relative_eq!(
hour_angle(0., f64::to_radians(-22.97753), 100., SolarEvent::Sunset),
f64::to_radians(91.28098),
epsilon = 0.00001
);
assert_relative_eq!(
hour_angle(0., f64::to_radians(-22.97753), -100., SolarEvent::Sunset),
f64::to_radians(90.52933),
epsilon = 0.00001
);
}
}