use super::hadec::HADec;
use super::xyz::XyzGeodetic;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[allow(clippy::upper_case_acronyms)]
pub struct UVW {
pub u: f64,
pub v: f64,
pub w: f64,
}
impl UVW {
pub fn from_xyz(xyz: XyzGeodetic, phase_centre: HADec) -> UVW {
let (s_ha, c_ha) = phase_centre.ha.sin_cos();
let (s_dec, c_dec) = phase_centre.dec.sin_cos();
Self::from_xyz_inner(xyz, s_ha, c_ha, s_dec, c_dec)
}
pub fn from_xyz_inner(xyz: XyzGeodetic, s_ha: f64, c_ha: f64, s_dec: f64, c_dec: f64) -> UVW {
Self {
u: s_ha * xyz.x + c_ha * xyz.y,
v: -s_dec * c_ha * xyz.x + s_dec * s_ha * xyz.y + c_dec * xyz.z,
w: c_dec * c_ha * xyz.x - c_dec * s_ha * xyz.y + s_dec * xyz.z,
}
}
}
impl std::ops::Sub<UVW> for UVW {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
UVW {
u: self.u - rhs.u,
v: self.v - rhs.v,
w: self.w - rhs.w,
}
}
}
impl std::ops::Mul<f64> for UVW {
type Output = Self;
fn mul(self, rhs: f64) -> Self {
UVW {
u: self.u * rhs,
v: self.v * rhs,
w: self.w * rhs,
}
}
}
impl std::ops::Div<f64> for UVW {
type Output = Self;
fn div(self, rhs: f64) -> Self {
UVW {
u: self.u / rhs,
v: self.v / rhs,
w: self.w / rhs,
}
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::AbsDiffEq for UVW {
type Epsilon = f64;
fn default_epsilon() -> f64 {
f64::EPSILON
}
fn abs_diff_eq(&self, other: &Self, epsilon: f64) -> bool {
f64::abs_diff_eq(&self.u, &other.u, epsilon)
&& f64::abs_diff_eq(&self.v, &other.v, epsilon)
&& f64::abs_diff_eq(&self.w, &other.w, epsilon)
}
}
#[cfg(any(test, feature = "approx"))]
impl approx::RelativeEq for UVW {
#[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.u, &other.u, epsilon, max_relative)
&& f64::relative_eq(&self.v, &other.v, epsilon, max_relative)
&& f64::relative_eq(&self.w, &other.w, 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 test_uvw_mul() {
let uvw = UVW {
u: 1.0,
v: 2.0,
w: 3.0,
} * 3.0;
assert_abs_diff_eq!(
uvw,
UVW {
u: 3.0,
v: 6.0,
w: 9.0
}
);
}
#[test]
fn test_uvw_div() {
let uvw = UVW {
u: 3.0,
v: 6.0,
w: 9.0,
} / 3.0;
assert_abs_diff_eq!(
uvw,
UVW {
u: 1.0,
v: 2.0,
w: 3.0
}
);
}
}