use std::f64::consts::FRAC_PI_2;
use erfa::aliases::eraAe2hd;
use super::hadec::HADec;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct AzEl {
pub az: f64,
pub el: f64,
}
impl AzEl {
pub fn from_radians(az_rad: f64, el_rad: f64) -> AzEl {
Self {
az: az_rad,
el: el_rad,
}
}
pub fn from_degrees(az_deg: f64, el_deg: f64) -> AzEl {
Self {
az: az_deg.to_radians(),
el: el_deg.to_radians(),
}
}
#[deprecated = "use `AzEl::from_radians` instead"]
pub fn new(az_rad: f64, el_rad: f64) -> AzEl {
Self {
az: az_rad,
el: el_rad,
}
}
#[deprecated = "use `AzEl::from_degrees` instead"]
pub fn new_degrees(az_deg: f64, el_deg: f64) -> AzEl {
Self::from_degrees(az_deg, el_deg)
}
pub fn za(self) -> f64 {
FRAC_PI_2 - self.el
}
pub fn to_hadec(self, latitude_rad: f64) -> HADec {
let (ha, dec) = eraAe2hd(self.az, self.el, latitude_rad);
HADec::from_radians(ha, dec)
}
pub fn to_hadec_mwa(self) -> HADec {
self.to_hadec(crate::constants::MWA_LAT_RAD)
}
}
impl std::fmt::Display for AzEl {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"({:.4}°, {:.4}°)",
self.az.to_degrees(),
self.el.to_degrees()
)
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::AbsDiffEq for AzEl {
type Epsilon = f64;
fn default_epsilon() -> f64 {
f64::EPSILON
}
fn abs_diff_eq(&self, other: &Self, epsilon: f64) -> bool {
f64::abs_diff_eq(&self.az, &other.az, epsilon)
&& f64::abs_diff_eq(&self.el, &other.el, epsilon)
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::RelativeEq for AzEl {
#[inline]
fn default_max_relative() -> f64 {
f64::EPSILON
}
#[inline]
fn relative_eq(&self, other: &Self, epsilon: f64, max_relative: f64) -> bool {
f64::relative_eq(&self.az, &other.az, epsilon, max_relative)
&& f64::relative_eq(&self.el, &other.el, epsilon, max_relative)
}
#[inline]
fn relative_ne(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool {
!Self::relative_eq(self, other, epsilon, max_relative)
}
}
#[cfg(test)]
mod tests {
use super::*;
use approx::assert_abs_diff_eq;
#[test]
fn to_hadec() {
let ae = AzEl::from_degrees(45.0, 30.0);
let result = ae.to_hadec(-0.497600);
let expected = HADec::from_radians(-0.6968754873551053, 0.3041176697804004);
assert_abs_diff_eq!(result, expected, epsilon = 1e-10);
}
#[test]
fn to_hadec2() {
let ae = AzEl::from_radians(0.261700, 0.785400);
let result = ae.to_hadec(-0.897600);
let expected = HADec::from_radians(-0.185499449332533, -0.12732312479328656);
assert_abs_diff_eq!(result, expected, epsilon = 1e-10);
}
#[test]
fn test_za() {
let ae = AzEl::from_radians(0.261700, 0.785400);
let za = ae.za();
assert_abs_diff_eq!(za, 0.7853963268, epsilon = 1e-10);
}
}