Skip to main content

lox_frames/
frames.rs

1// SPDX-FileCopyrightText: 2025 Helge Eichhorn <git@helgeeichhorn.de>
2//
3// SPDX-License-Identifier: MPL-2.0
4
5use lox_bodies::{Origin, RotationalElements, TryRotationalElements, UndefinedOriginPropertyError};
6
7use crate::{
8    iers::IersSystem,
9    traits::{BodyFixed, QuasiInertial, ReferenceFrame},
10};
11
12const ICRF_ID: usize = 0;
13const CIRF_ID: usize = 1;
14const TIRF_ID: usize = 2;
15const ITRF_ID: usize = 3;
16const J2000_ID: usize = 4;
17
18const MOD_ID: usize = 11;
19const TOD_ID: usize = 12;
20const PEF_ID: usize = 13;
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct Icrf;
25
26impl ReferenceFrame for Icrf {
27    fn name(&self) -> String {
28        "International Celestial Reference Frame".to_string()
29    }
30
31    fn abbreviation(&self) -> String {
32        "ICRF".to_string()
33    }
34
35    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
36        Some(ICRF_ID)
37    }
38}
39
40impl QuasiInertial for Icrf {}
41
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44pub struct J2000;
45
46impl ReferenceFrame for J2000 {
47    fn name(&self) -> String {
48        "J2000 Mean Equator and Equinox".to_string()
49    }
50
51    fn abbreviation(&self) -> String {
52        "J2000".to_string()
53    }
54
55    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
56        Some(J2000_ID)
57    }
58}
59
60impl QuasiInertial for J2000 {}
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
64pub struct Cirf;
65
66impl ReferenceFrame for Cirf {
67    fn name(&self) -> String {
68        "Celestial Intermediate Reference Frame".to_string()
69    }
70
71    fn abbreviation(&self) -> String {
72        "CIRF".to_string()
73    }
74
75    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
76        Some(CIRF_ID)
77    }
78}
79
80#[derive(Clone, Copy, Debug, PartialEq, Eq)]
81#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
82pub struct Tirf;
83
84impl ReferenceFrame for Tirf {
85    fn name(&self) -> String {
86        "Terrestrial Intermediate Reference Frame".to_string()
87    }
88
89    fn abbreviation(&self) -> String {
90        "TIRF".to_string()
91    }
92
93    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
94        Some(TIRF_ID)
95    }
96}
97
98#[derive(Clone, Copy, Debug, PartialEq, Eq)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100pub struct Itrf;
101
102impl ReferenceFrame for Itrf {
103    fn name(&self) -> String {
104        "International Terrestrial Reference Frame".to_string()
105    }
106
107    fn abbreviation(&self) -> String {
108        "ITRF".to_string()
109    }
110
111    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
112        Some(ITRF_ID)
113    }
114}
115
116#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
118pub struct Mod<T: IersSystem>(pub T);
119
120impl<T> ReferenceFrame for Mod<T>
121where
122    T: IersSystem,
123{
124    fn name(&self) -> String {
125        format!("{} Mean of Date Frame", self.0.name())
126    }
127
128    fn abbreviation(&self) -> String {
129        format!("MOD({})", self.0.name())
130    }
131
132    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
133        Some(MOD_ID * 10 + self.0.id())
134    }
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
139pub struct Tod<T: IersSystem>(pub T);
140
141impl<T> ReferenceFrame for Tod<T>
142where
143    T: IersSystem,
144{
145    fn name(&self) -> String {
146        format!("{} True of Date Frame", self.0.name())
147    }
148
149    fn abbreviation(&self) -> String {
150        format!("TOD({})", self.0.name())
151    }
152
153    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
154        Some(TOD_ID * 10 + self.0.id())
155    }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
159#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
160pub struct Pef<T: IersSystem>(pub T);
161
162impl<T> ReferenceFrame for Pef<T>
163where
164    T: IersSystem,
165{
166    fn name(&self) -> String {
167        format!("{} Pseudo-Earth Fixed Frame", self.0.name())
168    }
169
170    fn abbreviation(&self) -> String {
171        format!("PEF({})", self.0.name())
172    }
173
174    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
175        Some(PEF_ID * 10 + self.0.id())
176    }
177}
178
179#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
181pub struct Teme;
182
183impl ReferenceFrame for Teme {
184    fn name(&self) -> String {
185        "True Equator Mean Equinox".to_owned()
186    }
187
188    fn abbreviation(&self) -> String {
189        "TEME".to_owned()
190    }
191
192    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
193        Some(7)
194    }
195}
196
197impl BodyFixed for Itrf {}
198
199#[derive(Clone, Copy, Debug, PartialEq, Eq)]
200#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
201pub struct Iau<T: TryRotationalElements>(T);
202
203impl<T> Iau<T>
204where
205    T: RotationalElements,
206{
207    pub fn new(body: T) -> Self {
208        Self(body)
209    }
210}
211
212impl<T> Iau<T>
213where
214    T: TryRotationalElements,
215{
216    pub fn try_new(body: T) -> Result<Self, UndefinedOriginPropertyError> {
217        let _ = body.try_right_ascension(0.0)?;
218        Ok(Self(body))
219    }
220
221    pub fn body(&self) -> T
222    where
223        T: Copy,
224    {
225        self.0
226    }
227
228    pub fn rotational_elements(&self, j2000: f64) -> (f64, f64, f64) {
229        self.0.try_rotational_elements(j2000).unwrap()
230    }
231
232    pub fn rotational_element_rates(&self, j2000: f64) -> (f64, f64, f64) {
233        self.0.try_rotational_element_rates(j2000).unwrap()
234    }
235}
236
237impl<T: TryRotationalElements> BodyFixed for Iau<T> {}
238
239impl<T> ReferenceFrame for Iau<T>
240where
241    T: TryRotationalElements + Origin,
242{
243    fn name(&self) -> String {
244        let body = self.0.name();
245        match body {
246            "Sun" | "Moon" => format!("IAU Body-Fixed Reference Frame for the {body}"),
247            _ => format!("IAU Body-Fixed Reference Frame for {body}"),
248        }
249    }
250
251    fn abbreviation(&self) -> String {
252        let body = self.0.name().replace([' ', '-'], "_").to_uppercase();
253        format!("IAU_{body}")
254    }
255
256    fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
257        Some(1000 + self.0.id().0 as usize)
258    }
259}