|
| 1 | +// SPDX-FileCopyrightText: 2025 Helge Eichhorn <[email protected]> |
| 2 | +// |
| 3 | +// SPDX-License-Identifier: MPL-2.0 |
| 4 | + |
| 5 | +use glam::DVec3; |
| 6 | +use lox_core::{f64::consts::ROTATION_RATE_EARTH, units::Angle}; |
| 7 | +use lox_frames::transformations::Rotation; |
| 8 | +use lox_time::{ |
| 9 | + Time, |
| 10 | + time_scales::{Tdb, Tt, Ut1}, |
| 11 | +}; |
| 12 | + |
| 13 | +use crate::{ |
| 14 | + cip::CipCoords, ecliptic::MeanObliquity, nutation::Nutation, precession::BiasPrecessionIau2000, |
| 15 | + rotation::GreenwichApparentSiderealTime, |
| 16 | +}; |
| 17 | + |
| 18 | +pub fn icrf_to_mod(time: Time<Tt>) -> Rotation { |
| 19 | + let bp = BiasPrecessionIau2000::new(time); |
| 20 | + Rotation::new(bp.rpb) |
| 21 | +} |
| 22 | + |
| 23 | +pub fn mod_to_icrf(time: Time<Tt>) -> Rotation { |
| 24 | + icrf_to_mod(time).transpose() |
| 25 | +} |
| 26 | + |
| 27 | +pub fn mod_to_tod_iau2000a(time: Time<Tt>, corrections: Option<CipCoords>) -> Rotation { |
| 28 | + let CipCoords { x: dx, y: dy } = corrections.unwrap_or_default(); |
| 29 | + let nut = Nutation::iau2000a(time.with_scale(Tdb)); |
| 30 | + let epsa = MeanObliquity::iau1980(time); |
| 31 | + let numat = nut.nutation_matrix(epsa); |
| 32 | + |
| 33 | + let BiasPrecessionIau2000 { rpb, .. } = BiasPrecessionIau2000::new(time); |
| 34 | + let rnpb = numat * rpb; |
| 35 | + let v1 = DVec3::new(dx.as_f64(), dy.as_f64(), 0.0); |
| 36 | + let v2 = rnpb * v1; |
| 37 | + let corrections = Nutation { |
| 38 | + longitude: Angle::new(v2.x / epsa.0.sin()), |
| 39 | + obliquity: Angle::new(v2.y), |
| 40 | + }; |
| 41 | + |
| 42 | + Rotation::new((nut + corrections).nutation_matrix(epsa)) |
| 43 | +} |
| 44 | + |
| 45 | +pub fn tod_to_mod_iau2000a(time: Time<Tt>, corrections: Option<CipCoords>) -> Rotation { |
| 46 | + mod_to_tod_iau2000a(time, corrections).transpose() |
| 47 | +} |
| 48 | + |
| 49 | +pub fn mod_to_tod_iau2000b(time: Time<Tt>, corrections: Option<CipCoords>) -> Rotation { |
| 50 | + let CipCoords { x: dx, y: dy } = corrections.unwrap_or_default(); |
| 51 | + let nut = Nutation::iau2000b(time.with_scale(Tdb)); |
| 52 | + let epsa = MeanObliquity::iau1980(time); |
| 53 | + let numat = nut.nutation_matrix(epsa); |
| 54 | + |
| 55 | + let BiasPrecessionIau2000 { rpb, .. } = BiasPrecessionIau2000::new(time); |
| 56 | + let rnpb = numat * rpb; |
| 57 | + let v1 = DVec3::new(dx.as_f64(), dy.as_f64(), 0.0); |
| 58 | + let v2 = rnpb * v1; |
| 59 | + let corrections = Nutation { |
| 60 | + longitude: Angle::new(v2.x / epsa.0.sin()), |
| 61 | + obliquity: Angle::new(v2.y), |
| 62 | + }; |
| 63 | + |
| 64 | + Rotation::new((nut + corrections).nutation_matrix(epsa)) |
| 65 | +} |
| 66 | + |
| 67 | +pub fn tod_to_mod_iau2000b(time: Time<Tt>, corrections: Option<CipCoords>) -> Rotation { |
| 68 | + mod_to_tod_iau2000b(time, corrections).transpose() |
| 69 | +} |
| 70 | + |
| 71 | +pub fn tod_to_pef_iau2000a(tt: Time<Tt>, ut1: Time<Ut1>) -> Rotation { |
| 72 | + let gst = GreenwichApparentSiderealTime::iau2000a(tt, ut1); |
| 73 | + Rotation::new(gst.0.rotation_z()).with_angular_velocity(DVec3::new( |
| 74 | + 0.0, |
| 75 | + 0.0, |
| 76 | + ROTATION_RATE_EARTH, |
| 77 | + )) |
| 78 | +} |
| 79 | + |
| 80 | +pub fn pef_to_tod_iau2000a(tt: Time<Tt>, ut1: Time<Ut1>) -> Rotation { |
| 81 | + tod_to_pef_iau2000a(tt, ut1).transpose() |
| 82 | +} |
| 83 | + |
| 84 | +pub fn tod_to_pef_iau2000b(tt: Time<Tt>, ut1: Time<Ut1>) -> Rotation { |
| 85 | + let gst = GreenwichApparentSiderealTime::iau2000b(tt, ut1); |
| 86 | + Rotation::new(gst.0.rotation_z()).with_angular_velocity(DVec3::new( |
| 87 | + 0.0, |
| 88 | + 0.0, |
| 89 | + ROTATION_RATE_EARTH, |
| 90 | + )) |
| 91 | +} |
| 92 | + |
| 93 | +pub fn pef_to_tod_iau2000b(tt: Time<Tt>, ut1: Time<Ut1>) -> Rotation { |
| 94 | + tod_to_pef_iau2000b(tt, ut1).transpose() |
| 95 | +} |
0 commit comments