1use 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)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[cfg_attr(feature = "serde", serde(into = "&'static str", try_from = "String"))]
26pub struct Icrf;
27
28impl ReferenceFrame for Icrf {
29 fn name(&self) -> String {
30 "International Celestial Reference Frame".to_string()
31 }
32
33 fn abbreviation(&self) -> String {
34 "ICRF".to_string()
35 }
36
37 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
38 Some(ICRF_ID)
39 }
40}
41
42impl QuasiInertial for Icrf {}
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47#[cfg_attr(feature = "serde", serde(into = "&'static str", try_from = "String"))]
48pub struct J2000;
49
50impl ReferenceFrame for J2000 {
51 fn name(&self) -> String {
52 "J2000 Mean Equator and Equinox".to_string()
53 }
54
55 fn abbreviation(&self) -> String {
56 "J2000".to_string()
57 }
58
59 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
60 Some(J2000_ID)
61 }
62}
63
64impl QuasiInertial for J2000 {}
65
66#[derive(Clone, Copy, Debug, PartialEq, Eq)]
68#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
69#[cfg_attr(feature = "serde", serde(into = "&'static str", try_from = "String"))]
70pub struct Cirf;
71
72impl ReferenceFrame for Cirf {
73 fn name(&self) -> String {
74 "Celestial Intermediate Reference Frame".to_string()
75 }
76
77 fn abbreviation(&self) -> String {
78 "CIRF".to_string()
79 }
80
81 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
82 Some(CIRF_ID)
83 }
84}
85
86#[derive(Clone, Copy, Debug, PartialEq, Eq)]
88#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
89#[cfg_attr(feature = "serde", serde(into = "&'static str", try_from = "String"))]
90pub struct Tirf;
91
92impl ReferenceFrame for Tirf {
93 fn name(&self) -> String {
94 "Terrestrial Intermediate Reference Frame".to_string()
95 }
96
97 fn abbreviation(&self) -> String {
98 "TIRF".to_string()
99 }
100
101 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
102 Some(TIRF_ID)
103 }
104}
105
106#[derive(Clone, Copy, Debug, PartialEq, Eq)]
108#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
109#[cfg_attr(feature = "serde", serde(into = "&'static str", try_from = "String"))]
110pub struct Itrf;
111
112impl ReferenceFrame for Itrf {
113 fn name(&self) -> String {
114 "International Terrestrial Reference Frame".to_string()
115 }
116
117 fn abbreviation(&self) -> String {
118 "ITRF".to_string()
119 }
120
121 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
122 Some(ITRF_ID)
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
129pub struct Mod<T: IersSystem>(pub T);
130
131impl<T> ReferenceFrame for Mod<T>
132where
133 T: IersSystem,
134{
135 fn name(&self) -> String {
136 format!("{} Mean of Date Frame", self.0.name())
137 }
138
139 fn abbreviation(&self) -> String {
140 format!("MOD({})", self.0.name())
141 }
142
143 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
144 Some(MOD_ID * 10 + self.0.id())
145 }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
150#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
151pub struct Tod<T: IersSystem>(pub T);
152
153impl<T> ReferenceFrame for Tod<T>
154where
155 T: IersSystem,
156{
157 fn name(&self) -> String {
158 format!("{} True of Date Frame", self.0.name())
159 }
160
161 fn abbreviation(&self) -> String {
162 format!("TOD({})", self.0.name())
163 }
164
165 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
166 Some(TOD_ID * 10 + self.0.id())
167 }
168}
169
170#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
173pub struct Pef<T: IersSystem>(pub T);
174
175impl<T> ReferenceFrame for Pef<T>
176where
177 T: IersSystem,
178{
179 fn name(&self) -> String {
180 format!("{} Pseudo-Earth Fixed Frame", self.0.name())
181 }
182
183 fn abbreviation(&self) -> String {
184 format!("PEF({})", self.0.name())
185 }
186
187 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
188 Some(PEF_ID * 10 + self.0.id())
189 }
190}
191
192#[derive(Debug, Clone, Copy, PartialEq, Eq)]
194#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
195#[cfg_attr(feature = "serde", serde(into = "&'static str", try_from = "String"))]
196pub struct Teme;
197
198impl ReferenceFrame for Teme {
199 fn name(&self) -> String {
200 "True Equator Mean Equinox".to_owned()
201 }
202
203 fn abbreviation(&self) -> String {
204 "TEME".to_owned()
205 }
206
207 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
208 Some(7)
209 }
210}
211
212impl BodyFixed for Itrf {}
213
214macro_rules! impl_frame_serde {
217 ($ty:ident, $abbrev:literal) => {
218 #[cfg(feature = "serde")]
219 impl From<$ty> for &'static str {
220 fn from(_: $ty) -> Self {
221 $abbrev
222 }
223 }
224
225 #[cfg(feature = "serde")]
226 impl TryFrom<String> for $ty {
227 type Error = String;
228 fn try_from(s: String) -> Result<Self, Self::Error> {
229 if s == $abbrev {
230 Ok($ty)
231 } else {
232 Err(format!("expected \"{}\", got \"{}\"", $abbrev, s))
233 }
234 }
235 }
236 };
237}
238
239impl_frame_serde!(Icrf, "ICRF");
240impl_frame_serde!(J2000, "J2000");
241impl_frame_serde!(Cirf, "CIRF");
242impl_frame_serde!(Tirf, "TIRF");
243impl_frame_serde!(Itrf, "ITRF");
244impl_frame_serde!(Teme, "TEME");
245
246#[derive(Clone, Copy, Debug, PartialEq, Eq)]
248#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
249pub struct Iau<T: TryRotationalElements>(T);
250
251impl<T> Iau<T>
252where
253 T: RotationalElements,
254{
255 pub fn new(body: T) -> Self {
257 Self(body)
258 }
259}
260
261impl<T> Iau<T>
262where
263 T: TryRotationalElements,
264{
265 pub fn try_new(body: T) -> Result<Self, UndefinedOriginPropertyError> {
267 let _ = body.try_right_ascension(0.0)?;
268 Ok(Self(body))
269 }
270
271 pub fn body(&self) -> T
273 where
274 T: Copy,
275 {
276 self.0
277 }
278
279 pub fn rotational_elements(&self, j2000: f64) -> (f64, f64, f64) {
282 self.0.try_rotational_elements(j2000).unwrap()
283 }
284
285 pub fn rotational_element_rates(&self, j2000: f64) -> (f64, f64, f64) {
287 self.0.try_rotational_element_rates(j2000).unwrap()
288 }
289}
290
291impl<T: TryRotationalElements> BodyFixed for Iau<T> {}
292
293impl<T> ReferenceFrame for Iau<T>
294where
295 T: TryRotationalElements + Origin,
296{
297 fn name(&self) -> String {
298 let body = self.0.name();
299 match body {
300 "Sun" | "Moon" => format!("IAU Body-Fixed Reference Frame for the {body}"),
301 _ => format!("IAU Body-Fixed Reference Frame for {body}"),
302 }
303 }
304
305 fn abbreviation(&self) -> String {
306 let body = self.0.name().replace([' ', '-'], "_").to_uppercase();
307 format!("IAU_{body}")
308 }
309
310 fn frame_id(&self, _: crate::traits::private::Internal) -> Option<usize> {
311 Some(1000 + self.0.id().0 as usize)
312 }
313}