use crate::coordinates::cartesian::Direction;
use crate::coordinates::frames::{self, MutableFrame};
use crate::coordinates::transform::frames::bias;
use crate::coordinates::transform::TransformFrame;
use affn::Rotation3;
impl<F: MutableFrame> TransformFrame<Direction<F>> for Direction<F> {
fn to_frame(&self) -> Direction<F> {
Direction::<F>::from_array(self.as_array())
}
}
impl TransformFrame<Direction<frames::EquatorialMeanJ2000>>
for Direction<frames::EclipticMeanJ2000>
{
fn to_frame(&self) -> Direction<frames::EquatorialMeanJ2000> {
let rot = bias::obliquity_ecl_to_eq();
let [x, y, z] = rot.apply_array([self.x(), self.y(), self.z()]);
Direction::<frames::EquatorialMeanJ2000>::from_array([x, y, z])
}
}
impl TransformFrame<Direction<frames::EclipticMeanJ2000>>
for Direction<frames::EquatorialMeanJ2000>
{
fn to_frame(&self) -> Direction<frames::EclipticMeanJ2000> {
let rot = bias::obliquity_eq_to_ecl();
let [x, y, z] = rot.apply_array([self.x(), self.y(), self.z()]);
Direction::<frames::EclipticMeanJ2000>::from_array([x, y, z])
}
}
impl TransformFrame<Direction<frames::EquatorialMeanJ2000>> for Direction<frames::ICRS> {
fn to_frame(&self) -> Direction<frames::EquatorialMeanJ2000> {
let rot: Rotation3 = bias::frame_bias_icrs_to_j2000();
let [x, y, z] = rot.apply_array([self.x(), self.y(), self.z()]);
Direction::<frames::EquatorialMeanJ2000>::from_array([x, y, z])
}
}
impl TransformFrame<Direction<frames::ICRS>> for Direction<frames::EquatorialMeanJ2000> {
fn to_frame(&self) -> Direction<frames::ICRS> {
let rot: Rotation3 = bias::frame_bias_j2000_to_icrs();
let [x, y, z] = rot.apply_array([self.x(), self.y(), self.z()]);
Direction::<frames::ICRS>::from_array([x, y, z])
}
}
impl TransformFrame<Direction<frames::ICRS>> for Direction<frames::EclipticMeanJ2000> {
fn to_frame(&self) -> Direction<frames::ICRS> {
let eq: Direction<frames::EquatorialMeanJ2000> = self.to_frame();
eq.to_frame()
}
}
impl TransformFrame<Direction<frames::EclipticMeanJ2000>> for Direction<frames::ICRS> {
fn to_frame(&self) -> Direction<frames::EclipticMeanJ2000> {
let eq: Direction<frames::EquatorialMeanJ2000> = self.to_frame();
eq.to_frame()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn assert_arr3_close(a: [f64; 3], b: [f64; 3], eps: f64) {
assert!((a[0] - b[0]).abs() < eps);
assert!((a[1] - b[1]).abs() < eps);
assert!((a[2] - b[2]).abs() < eps);
}
#[test]
fn identity_direction_transform_is_noop() {
let dir = Direction::<frames::EclipticMeanJ2000>::from_array([0.0, 0.6, 0.8]);
let same: Direction<frames::EclipticMeanJ2000> = dir.to_frame();
assert_arr3_close(dir.as_array(), same.as_array(), 1e-15);
}
#[test]
fn ecliptic_to_icrs_roundtrip_matches_original() {
let dir_ecl = Direction::<frames::EclipticMeanJ2000>::from_array([0.1, 0.2, 0.3]);
let icrs: Direction<frames::ICRS> = dir_ecl.to_frame();
let back: Direction<frames::EclipticMeanJ2000> = icrs.to_frame();
assert_arr3_close(dir_ecl.as_array(), back.as_array(), 1e-12);
}
#[test]
fn icrs_to_equatorial_bias_and_back_is_stable() {
let icrs = Direction::<frames::ICRS>::from_array([-0.3, 0.4, -0.5]);
let eq: Direction<frames::EquatorialMeanJ2000> = icrs.to_frame();
let back: Direction<frames::ICRS> = eq.to_frame();
assert_arr3_close(icrs.as_array(), back.as_array(), 1e-12);
}
}