lox_frames/transformations/
iau.rs

1/*
2 * Copyright (c) 2025. Helge Eichhorn and the LOX contributors
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 */
8
9use crate::transformations::rotations::Rotation;
10use glam::{DMat3, DVec3};
11use lox_bodies::RotationalElements;
12use lox_bodies::{TryRotationalElements, UndefinedOriginPropertyError};
13use lox_time::Time;
14use lox_time::time_scales::Tdb;
15use lox_time::time_scales::TryToScale;
16use lox_time::{julian_dates::JulianDate, time_scales::TimeScale};
17use std::f64::consts::{FRAC_PI_2, TAU};
18use thiserror::Error;
19
20use crate::frames::{Iau, Icrf};
21use crate::traits::TryRotateTo;
22
23#[derive(Debug, Error)]
24pub enum IauFrameTransformationError {
25    #[error(transparent)]
26    UndefinedRotationalElements(#[from] UndefinedOriginPropertyError),
27    #[error("TDB transformation error: {0}")]
28    Tdb(String),
29}
30
31pub fn icrf_to_iau<T, O, P>(
32    time: Time<T>,
33    body: O,
34    provider: Option<&P>,
35) -> Result<Rotation, IauFrameTransformationError>
36where
37    T: TimeScale + TryToScale<Tdb, P>,
38    O: TryRotationalElements,
39{
40    let seconds = time
41        .try_to_scale(Tdb, provider)
42        .map_err(|err| IauFrameTransformationError::Tdb(err.to_string()))?
43        .seconds_since_j2000();
44    let (right_ascension, declination, rotation_angle) = body.try_rotational_elements(seconds)?;
45    let (right_ascension_rate, declination_rate, rotation_rate) =
46        body.try_rotational_element_rates(seconds)?;
47
48    let m1 = DMat3::from_rotation_z(-(right_ascension + FRAC_PI_2));
49    let m2 = DMat3::from_rotation_x(-(FRAC_PI_2 - declination));
50    let m3 = DMat3::from_rotation_z(-(rotation_angle % TAU));
51    let m = m3 * m2 * m1;
52    let v = DVec3::new(right_ascension_rate, -declination_rate, rotation_rate);
53    Ok(Rotation::new(m).with_angular_velocity(v))
54}
55
56impl<T, O, P> TryRotateTo<T, Iau<O>, P> for Icrf
57where
58    T: TimeScale + TryToScale<Tdb, P>,
59    O: RotationalElements,
60{
61    type Error = IauFrameTransformationError;
62
63    fn try_rotation(
64        &self,
65        frame: Iau<O>,
66        time: Time<T>,
67        provider: Option<&P>,
68    ) -> Result<Rotation, Self::Error> {
69        icrf_to_iau(time, frame.0, provider)
70    }
71}
72
73impl<T, O, P> TryRotateTo<T, Icrf, P> for Iau<O>
74where
75    T: TimeScale + TryToScale<Tdb, P>,
76    O: RotationalElements + Clone,
77{
78    type Error = IauFrameTransformationError;
79
80    fn try_rotation(
81        &self,
82        _frame: Icrf,
83        time: Time<T>,
84        provider: Option<&P>,
85    ) -> Result<Rotation, Self::Error> {
86        Ok(icrf_to_iau(time, self.0.clone(), provider)?.transpose())
87    }
88}