Skip to main content

lox_frames/rotations/
impls.rs

1// SPDX-FileCopyrightText: 2025 Helge Eichhorn <git@helgeeichhorn.de>
2//
3// SPDX-License-Identifier: MPL-2.0
4
5use lox_bodies::{DynOrigin, TryRotationalElements};
6use lox_time::{
7    Time,
8    offsets::TryOffset,
9    time_scales::{Tdb, TimeScale, Tt, Ut1},
10};
11
12use crate::{
13    Cirf, DynFrame, Iau, Icrf, Itrf, Tirf,
14    frames::{J2000, Mod, Pef, Teme, Tod},
15    iers::{Iers1996, Iers2003, Iers2010, ReferenceSystem},
16    rotations::{
17        DynRotationError, Rotation, RotationError, RotationProvider, TryComposedRotation,
18        TryRotation,
19    },
20};
21
22// ICRF <-> IAU
23
24impl<T, R, U> TryRotation<Icrf, Iau<R>, T> for U
25where
26    T: TimeScale + Copy,
27    R: TryRotationalElements + Copy,
28    U: RotationProvider<T> + TryOffset<T, Tdb>,
29{
30    type Error = RotationError;
31
32    fn try_rotation(
33        &self,
34        _origin: Icrf,
35        target: Iau<R>,
36        time: Time<T>,
37    ) -> Result<Rotation, Self::Error> {
38        self.icrf_to_iau(time, target)
39    }
40}
41
42impl<T, R, U> TryRotation<Iau<R>, Icrf, T> for U
43where
44    T: TimeScale + Copy,
45    R: TryRotationalElements + Copy,
46    U: RotationProvider<T> + TryOffset<T, Tdb>,
47{
48    type Error = RotationError;
49
50    fn try_rotation(
51        &self,
52        origin: Iau<R>,
53        _target: Icrf,
54        time: Time<T>,
55    ) -> Result<Rotation, Self::Error> {
56        self.iau_to_icrf(time, origin)
57    }
58}
59
60// ICRF <-> J2000
61
62impl<T, U> TryRotation<Icrf, J2000, T> for U
63where
64    T: TimeScale + Copy,
65    U: RotationProvider<T>,
66{
67    type Error = RotationError;
68
69    fn try_rotation(
70        &self,
71        _origin: Icrf,
72        _target: J2000,
73        _time: Time<T>,
74    ) -> Result<Rotation, Self::Error> {
75        Ok(self.icrf_to_j2000())
76    }
77}
78
79impl<T, U> TryRotation<J2000, Icrf, T> for U
80where
81    T: TimeScale + Copy,
82    U: RotationProvider<T>,
83{
84    type Error = RotationError;
85
86    fn try_rotation(
87        &self,
88        _origin: J2000,
89        _target: Icrf,
90        _time: Time<T>,
91    ) -> Result<Rotation, Self::Error> {
92        Ok(self.j2000_to_icrf())
93    }
94}
95
96// J2000 <-> MOD
97
98impl<T, U> TryRotation<J2000, Mod<Iers1996>, T> for U
99where
100    T: TimeScale + Copy,
101    U: RotationProvider<T> + TryOffset<T, Tt>,
102{
103    type Error = RotationError;
104
105    fn try_rotation(
106        &self,
107        _origin: J2000,
108        _target: Mod<Iers1996>,
109        time: Time<T>,
110    ) -> Result<Rotation, Self::Error> {
111        self.j2000_to_mod(time, ReferenceSystem::Iers1996)
112    }
113}
114
115impl<T, U> TryRotation<Mod<Iers1996>, J2000, T> for U
116where
117    T: TimeScale + Copy,
118    U: RotationProvider<T> + TryOffset<T, Tt>,
119{
120    type Error = RotationError;
121
122    fn try_rotation(
123        &self,
124        _origin: Mod<Iers1996>,
125        _target: J2000,
126        time: Time<T>,
127    ) -> Result<Rotation, Self::Error> {
128        self.mod_to_j2000(time, ReferenceSystem::Iers1996)
129    }
130}
131
132impl<T, U> TryRotation<J2000, Mod<Iers2003>, T> for U
133where
134    T: TimeScale + Copy,
135    U: RotationProvider<T> + TryOffset<T, Tt>,
136{
137    type Error = RotationError;
138
139    fn try_rotation(
140        &self,
141        _origin: J2000,
142        target: Mod<Iers2003>,
143        time: Time<T>,
144    ) -> Result<Rotation, Self::Error> {
145        self.j2000_to_mod(time, ReferenceSystem::Iers2003(target.0.0))
146    }
147}
148
149impl<T, U> TryRotation<Mod<Iers2003>, J2000, T> for U
150where
151    T: TimeScale + Copy,
152    U: RotationProvider<T> + TryOffset<T, Tt>,
153{
154    type Error = RotationError;
155
156    fn try_rotation(
157        &self,
158        origin: Mod<Iers2003>,
159        _target: J2000,
160        time: Time<T>,
161    ) -> Result<Rotation, Self::Error> {
162        self.mod_to_j2000(time, ReferenceSystem::Iers2003(origin.0.0))
163    }
164}
165
166impl<T, U> TryRotation<J2000, Mod<Iers2010>, T> for U
167where
168    T: TimeScale + Copy,
169    U: RotationProvider<T> + TryOffset<T, Tt>,
170{
171    type Error = RotationError;
172
173    fn try_rotation(
174        &self,
175        _origin: J2000,
176        _target: Mod<Iers2010>,
177        time: Time<T>,
178    ) -> Result<Rotation, Self::Error> {
179        self.j2000_to_mod(time, ReferenceSystem::Iers2010)
180    }
181}
182
183impl<T, U> TryRotation<Mod<Iers2010>, J2000, T> for U
184where
185    T: TimeScale + Copy,
186    U: RotationProvider<T> + TryOffset<T, Tt>,
187{
188    type Error = RotationError;
189
190    fn try_rotation(
191        &self,
192        _origin: Mod<Iers2010>,
193        _target: J2000,
194        time: Time<T>,
195    ) -> Result<Rotation, Self::Error> {
196        self.mod_to_j2000(time, ReferenceSystem::Iers2010)
197    }
198}
199
200// ICRF <-> ITRF
201
202impl<T, U> TryRotation<Icrf, Itrf, T> for U
203where
204    T: TimeScale + Copy,
205    U: RotationProvider<T> + TryOffset<T, Tdb> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
206{
207    type Error = RotationError;
208
209    fn try_rotation(
210        &self,
211        _origin: Icrf,
212        _target: Itrf,
213        time: Time<T>,
214    ) -> Result<Rotation, Self::Error> {
215        self.icrf_to_itrf(time)
216    }
217}
218
219impl<T, U> TryRotation<Itrf, Icrf, T> for U
220where
221    T: TimeScale + Copy,
222    U: RotationProvider<T> + TryOffset<T, Tdb> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
223{
224    type Error = RotationError;
225
226    fn try_rotation(
227        &self,
228        _origin: Itrf,
229        _target: Icrf,
230        time: Time<T>,
231    ) -> Result<Rotation, Self::Error> {
232        self.itrf_to_icrf(time)
233    }
234}
235
236// ICRF <-> CIRF
237
238impl<T, U> TryRotation<Icrf, Cirf, T> for U
239where
240    T: TimeScale + Copy,
241    U: RotationProvider<T> + TryOffset<T, Tdb>,
242{
243    type Error = RotationError;
244
245    fn try_rotation(
246        &self,
247        _origin: Icrf,
248        _target: Cirf,
249        time: Time<T>,
250    ) -> Result<Rotation, Self::Error> {
251        self.icrf_to_cirf(time)
252    }
253}
254
255impl<T, U> TryRotation<Cirf, Icrf, T> for U
256where
257    T: TimeScale + Copy,
258    U: RotationProvider<T> + TryOffset<T, Tdb>,
259{
260    type Error = RotationError;
261
262    fn try_rotation(
263        &self,
264        _origin: Cirf,
265        _target: Icrf,
266        time: Time<T>,
267    ) -> Result<Rotation, Self::Error> {
268        self.cirf_to_icrf(time)
269    }
270}
271
272// CIRF <-> TIRF
273
274impl<T, U> TryRotation<Cirf, Tirf, T> for U
275where
276    T: TimeScale + Copy,
277    U: RotationProvider<T> + TryOffset<T, Ut1>,
278{
279    type Error = RotationError;
280
281    fn try_rotation(
282        &self,
283        _origin: Cirf,
284        _target: Tirf,
285        time: Time<T>,
286    ) -> Result<Rotation, Self::Error> {
287        self.cirf_to_tirf(time)
288    }
289}
290
291impl<T, U> TryRotation<Tirf, Cirf, T> for U
292where
293    T: TimeScale + Copy,
294    U: RotationProvider<T> + TryOffset<T, Ut1>,
295{
296    type Error = RotationError;
297
298    fn try_rotation(
299        &self,
300        _origin: Tirf,
301        _target: Cirf,
302        time: Time<T>,
303    ) -> Result<Rotation, Self::Error> {
304        self.tirf_to_cirf(time)
305    }
306}
307
308// TIRF <-> ITRF
309
310impl<T, U> TryRotation<Tirf, Itrf, T> for U
311where
312    T: TimeScale + Copy,
313    U: RotationProvider<T> + TryOffset<T, Tt>,
314{
315    type Error = RotationError;
316
317    fn try_rotation(
318        &self,
319        _origin: Tirf,
320        _target: Itrf,
321        time: Time<T>,
322    ) -> Result<Rotation, Self::Error> {
323        self.tirf_to_itrf(time)
324    }
325}
326
327impl<T, U> TryRotation<Itrf, Tirf, T> for U
328where
329    T: TimeScale + Copy,
330    U: RotationProvider<T> + TryOffset<T, Tt>,
331{
332    type Error = RotationError;
333
334    fn try_rotation(
335        &self,
336        _origin: Itrf,
337        _target: Tirf,
338        time: Time<T>,
339    ) -> Result<Rotation, Self::Error> {
340        self.itrf_to_tirf(time)
341    }
342}
343
344// ICRF <-> MOD
345
346impl<T, U> TryRotation<Icrf, Mod<Iers1996>, T> for U
347where
348    T: TimeScale + Copy,
349    U: RotationProvider<T> + TryOffset<T, Tt>,
350{
351    type Error = RotationError;
352
353    fn try_rotation(
354        &self,
355        _origin: Icrf,
356        _target: Mod<Iers1996>,
357        time: Time<T>,
358    ) -> Result<Rotation, Self::Error> {
359        self.icrf_to_mod(time, ReferenceSystem::Iers1996)
360    }
361}
362
363impl<T, U> TryRotation<Mod<Iers1996>, Icrf, T> for U
364where
365    T: TimeScale + Copy,
366    U: RotationProvider<T> + TryOffset<T, Tt>,
367{
368    type Error = RotationError;
369
370    fn try_rotation(
371        &self,
372        _origin: Mod<Iers1996>,
373        _target: Icrf,
374        time: Time<T>,
375    ) -> Result<Rotation, Self::Error> {
376        self.mod_to_icrf(time, ReferenceSystem::Iers1996)
377    }
378}
379
380impl<T, U> TryRotation<Icrf, Mod<Iers2003>, T> for U
381where
382    T: TimeScale + Copy,
383    U: RotationProvider<T> + TryOffset<T, Tt>,
384{
385    type Error = RotationError;
386
387    fn try_rotation(
388        &self,
389        _origin: Icrf,
390        target: Mod<Iers2003>,
391        time: Time<T>,
392    ) -> Result<Rotation, Self::Error> {
393        self.icrf_to_mod(time, ReferenceSystem::Iers2003(target.0.0))
394    }
395}
396
397impl<T, U> TryRotation<Mod<Iers2003>, Icrf, T> for U
398where
399    T: TimeScale + Copy,
400    U: RotationProvider<T> + TryOffset<T, Tt>,
401{
402    type Error = RotationError;
403
404    fn try_rotation(
405        &self,
406        origin: Mod<Iers2003>,
407        _target: Icrf,
408        time: Time<T>,
409    ) -> Result<Rotation, Self::Error> {
410        self.mod_to_icrf(time, ReferenceSystem::Iers2003(origin.0.0))
411    }
412}
413
414impl<T, U> TryRotation<Icrf, Mod<Iers2010>, T> for U
415where
416    T: TimeScale + Copy,
417    U: RotationProvider<T> + TryOffset<T, Tt>,
418{
419    type Error = RotationError;
420
421    fn try_rotation(
422        &self,
423        _origin: Icrf,
424        _target: Mod<Iers2010>,
425        time: Time<T>,
426    ) -> Result<Rotation, Self::Error> {
427        self.icrf_to_mod(time, ReferenceSystem::Iers2010)
428    }
429}
430
431impl<T, U> TryRotation<Mod<Iers2010>, Icrf, T> for U
432where
433    T: TimeScale + Copy,
434    U: RotationProvider<T> + TryOffset<T, Tt>,
435{
436    type Error = RotationError;
437
438    fn try_rotation(
439        &self,
440        _origin: Mod<Iers2010>,
441        _target: Icrf,
442        time: Time<T>,
443    ) -> Result<Rotation, Self::Error> {
444        self.mod_to_icrf(time, ReferenceSystem::Iers2010)
445    }
446}
447
448// MOD <-> TOD
449
450impl<T, U> TryRotation<Mod<Iers1996>, Tod<Iers1996>, T> for U
451where
452    T: TimeScale + Copy,
453    U: RotationProvider<T> + TryOffset<T, Tdb>,
454{
455    type Error = RotationError;
456
457    fn try_rotation(
458        &self,
459        _origin: Mod<Iers1996>,
460        _target: Tod<Iers1996>,
461        time: Time<T>,
462    ) -> Result<Rotation, Self::Error> {
463        self.mod_to_tod(time, ReferenceSystem::Iers1996)
464    }
465}
466
467impl<T, U> TryRotation<Tod<Iers1996>, Mod<Iers1996>, T> for U
468where
469    T: TimeScale + Copy,
470    U: RotationProvider<T> + TryOffset<T, Tdb>,
471{
472    type Error = RotationError;
473
474    fn try_rotation(
475        &self,
476        _origin: Tod<Iers1996>,
477        _target: Mod<Iers1996>,
478        time: Time<T>,
479    ) -> Result<Rotation, Self::Error> {
480        self.tod_to_mod(time, ReferenceSystem::Iers1996)
481    }
482}
483
484impl<T, U> TryRotation<Mod<Iers2003>, Tod<Iers2003>, T> for U
485where
486    T: TimeScale + Copy,
487    U: RotationProvider<T> + TryOffset<T, Tdb>,
488{
489    type Error = RotationError;
490
491    fn try_rotation(
492        &self,
493        origin: Mod<Iers2003>,
494        _target: Tod<Iers2003>,
495        time: Time<T>,
496    ) -> Result<Rotation, Self::Error> {
497        self.mod_to_tod(time, ReferenceSystem::Iers2003(origin.0.0))
498    }
499}
500
501impl<T, U> TryRotation<Tod<Iers2003>, Mod<Iers2003>, T> for U
502where
503    T: TimeScale + Copy,
504    U: RotationProvider<T> + TryOffset<T, Tdb>,
505{
506    type Error = RotationError;
507
508    fn try_rotation(
509        &self,
510        origin: Tod<Iers2003>,
511        _target: Mod<Iers2003>,
512        time: Time<T>,
513    ) -> Result<Rotation, Self::Error> {
514        self.tod_to_mod(time, ReferenceSystem::Iers2003(origin.0.0))
515    }
516}
517
518impl<T, U> TryRotation<Mod<Iers2010>, Tod<Iers2010>, T> for U
519where
520    T: TimeScale + Copy,
521    U: RotationProvider<T> + TryOffset<T, Tdb>,
522{
523    type Error = RotationError;
524
525    fn try_rotation(
526        &self,
527        _origin: Mod<Iers2010>,
528        _target: Tod<Iers2010>,
529        time: Time<T>,
530    ) -> Result<Rotation, Self::Error> {
531        self.mod_to_tod(time, ReferenceSystem::Iers2010)
532    }
533}
534
535impl<T, U> TryRotation<Tod<Iers2010>, Mod<Iers2010>, T> for U
536where
537    T: TimeScale + Copy,
538    U: RotationProvider<T> + TryOffset<T, Tdb>,
539{
540    type Error = RotationError;
541
542    fn try_rotation(
543        &self,
544        _origin: Tod<Iers2010>,
545        _target: Mod<Iers2010>,
546        time: Time<T>,
547    ) -> Result<Rotation, Self::Error> {
548        self.tod_to_mod(time, ReferenceSystem::Iers2010)
549    }
550}
551
552// TOD <-> PEF
553
554impl<T, U> TryRotation<Tod<Iers1996>, Pef<Iers1996>, T> for U
555where
556    T: TimeScale + Copy,
557    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
558{
559    type Error = RotationError;
560
561    fn try_rotation(
562        &self,
563        _origin: Tod<Iers1996>,
564        _target: Pef<Iers1996>,
565        time: Time<T>,
566    ) -> Result<Rotation, Self::Error> {
567        self.tod_to_pef(time, ReferenceSystem::Iers1996)
568    }
569}
570
571impl<T, U> TryRotation<Pef<Iers1996>, Tod<Iers1996>, T> for U
572where
573    T: TimeScale + Copy,
574    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
575{
576    type Error = RotationError;
577
578    fn try_rotation(
579        &self,
580        _origin: Pef<Iers1996>,
581        _target: Tod<Iers1996>,
582        time: Time<T>,
583    ) -> Result<Rotation, Self::Error> {
584        self.pef_to_tod(time, ReferenceSystem::Iers1996)
585    }
586}
587
588impl<T, U> TryRotation<Tod<Iers2003>, Pef<Iers2003>, T> for U
589where
590    T: TimeScale + Copy,
591    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
592{
593    type Error = RotationError;
594
595    fn try_rotation(
596        &self,
597        origin: Tod<Iers2003>,
598        _target: Pef<Iers2003>,
599        time: Time<T>,
600    ) -> Result<Rotation, Self::Error> {
601        self.tod_to_pef(time, ReferenceSystem::Iers2003(origin.0.0))
602    }
603}
604
605impl<T, U> TryRotation<Pef<Iers2003>, Tod<Iers2003>, T> for U
606where
607    T: TimeScale + Copy,
608    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
609{
610    type Error = RotationError;
611
612    fn try_rotation(
613        &self,
614        origin: Pef<Iers2003>,
615        _target: Tod<Iers2003>,
616        time: Time<T>,
617    ) -> Result<Rotation, Self::Error> {
618        self.pef_to_tod(time, ReferenceSystem::Iers2003(origin.0.0))
619    }
620}
621
622impl<T, U> TryRotation<Tod<Iers2010>, Pef<Iers2010>, T> for U
623where
624    T: TimeScale + Copy,
625    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
626{
627    type Error = RotationError;
628
629    fn try_rotation(
630        &self,
631        _origin: Tod<Iers2010>,
632        _target: Pef<Iers2010>,
633        time: Time<T>,
634    ) -> Result<Rotation, Self::Error> {
635        self.tod_to_pef(time, ReferenceSystem::Iers2010)
636    }
637}
638
639impl<T, U> TryRotation<Pef<Iers2010>, Tod<Iers2010>, T> for U
640where
641    T: TimeScale + Copy,
642    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Ut1>,
643{
644    type Error = RotationError;
645
646    fn try_rotation(
647        &self,
648        _origin: Pef<Iers2010>,
649        _target: Tod<Iers2010>,
650        time: Time<T>,
651    ) -> Result<Rotation, Self::Error> {
652        self.pef_to_tod(time, ReferenceSystem::Iers2010)
653    }
654}
655
656// PEF <-> ITRF
657
658impl<T, U> TryRotation<Pef<Iers1996>, Itrf, T> for U
659where
660    T: TimeScale + Copy,
661    U: RotationProvider<T> + TryOffset<T, Tt>,
662{
663    type Error = RotationError;
664
665    fn try_rotation(
666        &self,
667        _origin: Pef<Iers1996>,
668        _target: Itrf,
669        time: Time<T>,
670    ) -> Result<Rotation, Self::Error> {
671        self.pef_to_itrf(time, ReferenceSystem::Iers1996)
672    }
673}
674
675impl<T, U> TryRotation<Itrf, Pef<Iers1996>, T> for U
676where
677    T: TimeScale + Copy,
678    U: RotationProvider<T> + TryOffset<T, Tt>,
679{
680    type Error = RotationError;
681
682    fn try_rotation(
683        &self,
684        _origin: Itrf,
685        _target: Pef<Iers1996>,
686        time: Time<T>,
687    ) -> Result<Rotation, Self::Error> {
688        self.itrf_to_pef(time, ReferenceSystem::Iers1996)
689    }
690}
691
692impl<T, U> TryRotation<Pef<Iers2003>, Itrf, T> for U
693where
694    T: TimeScale + Copy,
695    U: RotationProvider<T> + TryOffset<T, Tt>,
696{
697    type Error = RotationError;
698
699    fn try_rotation(
700        &self,
701        origin: Pef<Iers2003>,
702        _target: Itrf,
703        time: Time<T>,
704    ) -> Result<Rotation, Self::Error> {
705        self.pef_to_itrf(time, ReferenceSystem::Iers2003(origin.0.0))
706    }
707}
708
709impl<T, U> TryRotation<Itrf, Pef<Iers2003>, T> for U
710where
711    T: TimeScale + Copy,
712    U: RotationProvider<T> + TryOffset<T, Tt>,
713{
714    type Error = RotationError;
715
716    fn try_rotation(
717        &self,
718        _origin: Itrf,
719        target: Pef<Iers2003>,
720        time: Time<T>,
721    ) -> Result<Rotation, Self::Error> {
722        self.itrf_to_pef(time, ReferenceSystem::Iers2003(target.0.0))
723    }
724}
725
726impl<T, U> TryRotation<Pef<Iers2010>, Itrf, T> for U
727where
728    T: TimeScale + Copy,
729    U: RotationProvider<T> + TryOffset<T, Tt>,
730{
731    type Error = RotationError;
732
733    fn try_rotation(
734        &self,
735        _origin: Pef<Iers2010>,
736        _target: Itrf,
737        time: Time<T>,
738    ) -> Result<Rotation, Self::Error> {
739        self.pef_to_itrf(time, ReferenceSystem::Iers2010)
740    }
741}
742
743impl<T, U> TryRotation<Itrf, Pef<Iers2010>, T> for U
744where
745    T: TimeScale + Copy,
746    U: RotationProvider<T> + TryOffset<T, Tt>,
747{
748    type Error = RotationError;
749
750    fn try_rotation(
751        &self,
752        _origin: Itrf,
753        _target: Pef<Iers2010>,
754        time: Time<T>,
755    ) -> Result<Rotation, Self::Error> {
756        self.itrf_to_pef(time, ReferenceSystem::Iers2010)
757    }
758}
759
760// TOD <-> TEME
761
762impl<T, U> TryRotation<Tod<Iers1996>, Teme, T> for U
763where
764    T: TimeScale + Copy,
765    U: RotationProvider<T> + TryOffset<T, Tdb>,
766{
767    type Error = RotationError;
768
769    fn try_rotation(
770        &self,
771        _origin: Tod<Iers1996>,
772        _target: Teme,
773        time: Time<T>,
774    ) -> Result<Rotation, Self::Error> {
775        self.tod_to_teme(time)
776    }
777}
778
779impl<T, U> TryRotation<Teme, Tod<Iers1996>, T> for U
780where
781    T: TimeScale + Copy,
782    U: RotationProvider<T> + TryOffset<T, Tdb>,
783{
784    type Error = RotationError;
785
786    fn try_rotation(
787        &self,
788        _origin: Teme,
789        _target: Tod<Iers1996>,
790        time: Time<T>,
791    ) -> Result<Rotation, Self::Error> {
792        self.teme_to_tod(time)
793    }
794}
795
796impl<T, U> TryRotation<Tod<Iers2003>, Teme, T> for U
797where
798    T: TimeScale + Copy,
799    U: RotationProvider<T> + TryOffset<T, Tdb>,
800{
801    type Error = RotationError;
802
803    fn try_rotation(
804        &self,
805        _origin: Tod<Iers2003>,
806        _target: Teme,
807        time: Time<T>,
808    ) -> Result<Rotation, Self::Error> {
809        self.tod_to_teme(time)
810    }
811}
812
813impl<T, U> TryRotation<Teme, Tod<Iers2003>, T> for U
814where
815    T: TimeScale + Copy,
816    U: RotationProvider<T> + TryOffset<T, Tdb>,
817{
818    type Error = RotationError;
819
820    fn try_rotation(
821        &self,
822        _origin: Teme,
823        _target: Tod<Iers2003>,
824        time: Time<T>,
825    ) -> Result<Rotation, Self::Error> {
826        self.teme_to_tod(time)
827    }
828}
829
830impl<T, U> TryRotation<Tod<Iers2010>, Teme, T> for U
831where
832    T: TimeScale + Copy,
833    U: RotationProvider<T> + TryOffset<T, Tdb>,
834{
835    type Error = RotationError;
836
837    fn try_rotation(
838        &self,
839        _origin: Tod<Iers2010>,
840        _target: Teme,
841        time: Time<T>,
842    ) -> Result<Rotation, Self::Error> {
843        self.tod_to_teme(time)
844    }
845}
846
847impl<T, U> TryRotation<Teme, Tod<Iers2010>, T> for U
848where
849    T: TimeScale + Copy,
850    U: RotationProvider<T> + TryOffset<T, Tdb>,
851{
852    type Error = RotationError;
853
854    fn try_rotation(
855        &self,
856        _origin: Teme,
857        _target: Tod<Iers2010>,
858        time: Time<T>,
859    ) -> Result<Rotation, Self::Error> {
860        self.teme_to_tod(time)
861    }
862}
863
864// Composed Rotations
865
866macro_rules! impl_composed {
867    ($($origin:ty => $target:ty: [$($via:expr),+]),* $(,)?) => {
868        $(
869            impl<T, U> TryRotation<$origin, $target, T> for U
870            where
871                T: TimeScale + Copy,
872                U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Tdb> + TryOffset<T, Ut1>,
873            {
874                type Error = RotationError;
875
876                fn try_rotation(
877                    &self,
878                    origin: $origin,
879                    target: $target,
880                    time: Time<T>,
881                ) -> Result<Rotation, Self::Error> {
882                    (origin, $($via),+, target).try_composed_rotation(self, time)
883                }
884            }
885        )*
886    };
887}
888
889impl_composed!(
890    // J2000 composed rotations
891    J2000 => Cirf: [Icrf],
892    J2000 => Tirf: [Icrf, Cirf],
893    J2000 => Itrf: [Icrf, Cirf, Tirf],
894    J2000 => Iau<DynOrigin>: [Icrf],
895    J2000 => Tod<Iers1996>: [Mod(Iers1996)],
896    J2000 => Tod<Iers2003>: [Mod(Iers2003::default())],
897    J2000 => Tod<Iers2010>: [Mod(Iers2010)],
898    J2000 => Pef<Iers1996>: [Mod(Iers1996), Tod(Iers1996)],
899    J2000 => Pef<Iers2003>: [Mod(Iers2003::default()), Tod(Iers2003::default())],
900    J2000 => Pef<Iers2010>: [Mod(Iers2010), Tod(Iers2010)],
901    J2000 => Teme: [Mod(Iers1996), Tod(Iers1996)],
902    Cirf => J2000: [Icrf],
903    Tirf => J2000: [Cirf, Icrf],
904    Itrf => J2000: [Tirf, Cirf, Icrf],
905    Iau<DynOrigin> => J2000: [Icrf],
906    Tod<Iers1996> => J2000: [Mod(Iers1996)],
907    Tod<Iers2003> => J2000: [Mod(Iers2003::default())],
908    Tod<Iers2010> => J2000: [Mod(Iers2010)],
909    Pef<Iers1996> => J2000: [Tod(Iers1996), Mod(Iers1996)],
910    Pef<Iers2003> => J2000: [Tod(Iers2003::default()), Mod(Iers2003::default())],
911    Pef<Iers2010> => J2000: [Tod(Iers2010), Mod(Iers2010)],
912    Teme => J2000: [Tod(Iers1996), Mod(Iers1996)],
913
914    Cirf => Iau<DynOrigin>: [Icrf],
915    Cirf => Itrf: [Tirf],
916    Cirf => Mod<Iers1996>: [Icrf],
917    Cirf => Mod<Iers2003>: [Icrf],
918    Cirf => Mod<Iers2010>: [Icrf],
919    Cirf => Pef<Iers1996>: [Icrf, Mod(Iers1996), Tod(Iers1996)],
920    Cirf => Pef<Iers2003>: [Icrf, Mod(Iers2003::default()), Tod(Iers2003::default())],
921    Cirf => Pef<Iers2010>: [Icrf, Mod(Iers2010), Tod(Iers2010)],
922    Cirf => Teme: [Icrf, Mod(Iers1996), Tod(Iers1996)],
923    Cirf => Tod<Iers1996>: [Icrf, Mod(Iers1996)],
924    Cirf => Tod<Iers2003>: [Icrf, Mod(Iers2003::default())],
925    Cirf => Tod<Iers2010>: [Icrf, Mod(Iers2010)],
926    Iau<DynOrigin> => Cirf: [Icrf],
927    Iau<DynOrigin> => Itrf: [Icrf, Cirf, Tirf],
928    Iau<DynOrigin> => Tirf: [Icrf, Cirf],
929    Iau<DynOrigin> => Mod<Iers1996>: [Icrf],
930    Iau<DynOrigin> => Mod<Iers2003>: [Icrf],
931    Iau<DynOrigin> => Mod<Iers2010>: [Icrf],
932    Iau<DynOrigin> => Tod<Iers1996>: [Icrf, Mod(Iers1996)],
933    Iau<DynOrigin> => Tod<Iers2003>: [Icrf, Mod(Iers2003::default())],
934    Iau<DynOrigin> => Tod<Iers2010>: [Icrf, Mod(Iers2010)],
935    Iau<DynOrigin> => Pef<Iers1996>: [Icrf, Mod(Iers1996), Tod(Iers1996)],
936    Iau<DynOrigin> => Pef<Iers2003>: [Icrf, Mod(Iers2003::default()), Tod(Iers2003::default())],
937    Iau<DynOrigin> => Pef<Iers2010>: [Icrf, Mod(Iers2010), Tod(Iers2010)],
938    Iau<DynOrigin> => Teme: [Icrf, Mod(Iers1996), Tod(Iers1996)],
939    Icrf => Pef<Iers1996>: [Mod(Iers1996), Tod(Iers1996)],
940    Icrf => Pef<Iers2003>: [Mod(Iers2003::default()), Tod(Iers2003::default())],
941    Icrf => Pef<Iers2010>: [Mod(Iers2010), Tod(Iers2010)],
942    Icrf => Teme: [Mod(Iers1996), Tod(Iers1996)],
943    Icrf => Tirf: [Cirf],
944    Icrf => Tod<Iers1996>: [Mod(Iers1996)],
945    Icrf => Tod<Iers2003>: [Mod(Iers2003::default())],
946    Icrf => Tod<Iers2010>: [Mod(Iers2010)],
947    Itrf => Cirf: [Tirf],
948    Itrf => Iau<DynOrigin>: [Tirf, Cirf, Icrf],
949    Itrf => Mod<Iers1996>: [Pef(Iers1996), Tod(Iers1996)],
950    Itrf => Mod<Iers2003>: [Pef(Iers2003::default()), Tod(Iers2003::default())],
951    Itrf => Mod<Iers2010>: [Pef(Iers2010), Tod(Iers2010)],
952    Itrf => Tod<Iers1996>: [Pef(Iers1996)],
953    Itrf => Tod<Iers2003>: [Pef(Iers2003::default())],
954    Itrf => Tod<Iers2010>: [Pef(Iers2010)],
955    Itrf => Teme: [Pef(Iers1996), Tod(Iers1996)],
956    Mod<Iers1996> => Cirf: [Icrf],
957    Mod<Iers2003> => Cirf: [Icrf],
958    Mod<Iers2010> => Cirf: [Icrf],
959    Mod<Iers1996> => Tirf: [Icrf, Cirf],
960    Mod<Iers2003> => Tirf: [Icrf, Cirf],
961    Mod<Iers2010> => Tirf: [Icrf, Cirf],
962    Mod<Iers1996> => Itrf: [Tod(Iers1996), Pef(Iers1996)],
963    Mod<Iers2003> => Itrf: [Tod(Iers2003::default()), Pef(Iers2003::default())],
964    Mod<Iers2010> => Itrf: [Tod(Iers2010), Pef(Iers2010)],
965    Mod<Iers1996> => Iau<DynOrigin>: [Icrf],
966    Mod<Iers2003> => Iau<DynOrigin>: [Icrf],
967    Mod<Iers2010> => Iau<DynOrigin>: [Icrf],
968    Mod<Iers1996> => Pef<Iers1996>: [Tod(Iers1996)],
969    Mod<Iers2003> => Pef<Iers2003>: [Tod(Iers2003::default())],
970    Mod<Iers2010> => Pef<Iers2010>: [Tod(Iers2010)],
971    Mod<Iers1996> => Teme: [Tod(Iers1996)],
972    Mod<Iers2003> => Teme: [Tod(Iers2003::default())],
973    Mod<Iers2010> => Teme: [Tod(Iers2010)],
974    Pef<Iers1996> => Cirf: [Tod(Iers1996), Mod(Iers1996), Icrf],
975    Pef<Iers2003> => Cirf: [Tod(Iers2003::default()), Mod(Iers2003::default()), Icrf],
976    Pef<Iers2010> => Cirf: [Tod(Iers2010), Mod(Iers2010), Icrf],
977    Pef<Iers1996> => Icrf: [Tod(Iers1996), Mod(Iers1996)],
978    Pef<Iers2003> => Icrf: [Tod(Iers2003::default()), Mod(Iers2003::default())],
979    Pef<Iers2010> => Icrf: [Tod(Iers2010), Mod(Iers2010)],
980    Pef<Iers1996> => Tirf: [Itrf],
981    Pef<Iers2003> => Tirf: [Itrf],
982    Pef<Iers2010> => Tirf: [Itrf],
983    Pef<Iers1996> => Iau<DynOrigin>: [Tod(Iers1996), Mod(Iers1996), Icrf],
984    Pef<Iers2003> => Iau<DynOrigin>: [Tod(Iers2003::default()), Mod(Iers2003::default()), Icrf],
985    Pef<Iers2010> => Iau<DynOrigin>: [Tod(Iers2010), Mod(Iers2010), Icrf],
986    Pef<Iers1996> => Mod<Iers1996>: [Tod(Iers1996)],
987    Pef<Iers2003> => Mod<Iers2003>: [Tod(Iers2003::default())],
988    Pef<Iers2010> => Mod<Iers2010>: [Tod(Iers2010)],
989    Teme => Cirf: [Tod(Iers1996), Mod(Iers1996), Icrf],
990    Teme => Icrf: [Tod(Iers1996), Mod(Iers1996)],
991    Teme => Tirf: [Tod(Iers1996), Mod(Iers1996), Icrf, Cirf],
992    Teme => Itrf: [Tod(Iers1996), Pef(Iers1996)],
993    Teme => Iau<DynOrigin>: [Tod(Iers1996), Mod(Iers1996), Icrf],
994    Teme => Mod<Iers1996>: [Tod(Iers1996)],
995    Teme => Mod<Iers2003>: [Tod(Iers2003::default())],
996    Teme => Mod<Iers2010>: [Tod(Iers2010)],
997    Teme => Pef<Iers1996>: [Tod(Iers1996)],
998    Teme => Pef<Iers2003>: [Tod(Iers2003::default())],
999    Teme => Pef<Iers2010>: [Tod(Iers2010)],
1000    Tirf => Iau<DynOrigin>: [Cirf, Icrf],
1001    Tirf => Icrf: [Cirf],
1002    Tirf => Mod<Iers1996>: [Cirf, Icrf],
1003    Tirf => Mod<Iers2003>: [Cirf, Icrf],
1004    Tirf => Mod<Iers2010>: [Cirf, Icrf],
1005    Tirf => Pef<Iers1996>: [Itrf],
1006    Tirf => Pef<Iers2003>: [Itrf],
1007    Tirf => Pef<Iers2010>: [Itrf],
1008    Tirf => Teme: [Cirf, Icrf, Mod(Iers1996), Tod(Iers1996)],
1009    Tirf => Tod<Iers1996>: [Cirf, Icrf, Mod(Iers1996)],
1010    Tirf => Tod<Iers2003>: [Cirf, Icrf, Mod(Iers2003::default())],
1011    Tirf => Tod<Iers2010>: [Cirf, Icrf, Mod(Iers2010)],
1012    Tod<Iers1996> => Cirf: [Mod(Iers1996), Icrf],
1013    Tod<Iers2003> => Cirf: [Mod(Iers2003::default()), Icrf],
1014    Tod<Iers2010> => Cirf: [Mod(Iers2010), Icrf],
1015    Tod<Iers1996> => Icrf: [Mod(Iers1996)],
1016    Tod<Iers2003> => Icrf: [Mod(Iers2003::default())],
1017    Tod<Iers2010> => Icrf: [Mod(Iers2010)],
1018    Tod<Iers1996> => Tirf: [Mod(Iers1996), Icrf, Cirf],
1019    Tod<Iers2003> => Tirf: [Mod(Iers2003::default()), Icrf, Cirf],
1020    Tod<Iers2010> => Tirf: [Mod(Iers2010), Icrf, Cirf],
1021    Tod<Iers1996> => Itrf: [Pef(Iers1996)],
1022    Tod<Iers2003> => Itrf: [Pef(Iers2003::default())],
1023    Tod<Iers2010> => Itrf: [Pef(Iers2010)],
1024    Tod<Iers1996> => Iau<DynOrigin>: [Mod(Iers1996), Icrf],
1025    Tod<Iers2003> => Iau<DynOrigin>: [Mod(Iers2003::default()), Icrf],
1026    Tod<Iers2010> => Iau<DynOrigin>: [Mod(Iers2010), Icrf],
1027    Pef<Iers1996> => Teme: [Tod(Iers1996)],
1028    Pef<Iers2003> => Teme: [Tod(Iers2003::default())],
1029    Pef<Iers2010> => Teme: [Tod(Iers2010)],
1030);
1031
1032// Dynamic
1033
1034impl<T, U> TryRotation<DynFrame, DynFrame, T> for U
1035where
1036    T: TimeScale + Copy,
1037    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Tdb> + TryOffset<T, Ut1>,
1038{
1039    type Error = DynRotationError;
1040
1041    fn try_rotation(
1042        &self,
1043        origin: DynFrame,
1044        target: DynFrame,
1045        time: Time<T>,
1046    ) -> Result<Rotation, Self::Error> {
1047        if origin == target {
1048            return Ok(Rotation::IDENTITY);
1049        }
1050        match (origin, target) {
1051            (DynFrame::Icrf, DynFrame::Cirf) => Ok(self.try_rotation(Icrf, Cirf, time)?),
1052            (DynFrame::Icrf, DynFrame::Tirf) => Ok(self.try_rotation(Icrf, Tirf, time)?),
1053            (DynFrame::Icrf, DynFrame::Itrf) => Ok(self.try_rotation(Icrf, Itrf, time)?),
1054            (DynFrame::Icrf, DynFrame::Iau(body)) => {
1055                Ok(self.try_rotation(Icrf, Iau::try_new(body)?, time)?)
1056            }
1057            (DynFrame::Icrf, DynFrame::Mod(sys)) => match sys {
1058                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Icrf, Mod(Iers1996), time)?),
1059                ReferenceSystem::Iers2003(iau2000_model) => {
1060                    Ok(self.try_rotation(Icrf, Mod(Iers2003(iau2000_model)), time)?)
1061                }
1062                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Icrf, Mod(Iers2010), time)?),
1063            },
1064            (DynFrame::Icrf, DynFrame::Tod(sys)) => match sys {
1065                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Icrf, Tod(Iers1996), time)?),
1066                ReferenceSystem::Iers2003(iau2000_model) => {
1067                    Ok(self.try_rotation(Icrf, Tod(Iers2003(iau2000_model)), time)?)
1068                }
1069                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Icrf, Tod(Iers2010), time)?),
1070            },
1071            (DynFrame::Icrf, DynFrame::Pef(sys)) => match sys {
1072                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Icrf, Pef(Iers1996), time)?),
1073                ReferenceSystem::Iers2003(iau2000_model) => {
1074                    Ok(self.try_rotation(Icrf, Pef(Iers2003(iau2000_model)), time)?)
1075                }
1076                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Icrf, Pef(Iers2010), time)?),
1077            },
1078            (DynFrame::Icrf, DynFrame::Teme) => Ok(self.try_rotation(Icrf, Teme, time)?),
1079            (DynFrame::Icrf, DynFrame::J2000) => Ok(self.try_rotation(Icrf, J2000, time)?),
1080            (DynFrame::J2000, DynFrame::Icrf) => Ok(self.try_rotation(J2000, Icrf, time)?),
1081            (DynFrame::J2000, DynFrame::Cirf) => Ok(self.try_rotation(J2000, Cirf, time)?),
1082            (DynFrame::J2000, DynFrame::Tirf) => Ok(self.try_rotation(J2000, Tirf, time)?),
1083            (DynFrame::J2000, DynFrame::Itrf) => Ok(self.try_rotation(J2000, Itrf, time)?),
1084            (DynFrame::J2000, DynFrame::Iau(body)) => {
1085                Ok(self.try_rotation(J2000, Iau::try_new(body)?, time)?)
1086            }
1087            (DynFrame::J2000, DynFrame::Mod(sys)) => match sys {
1088                ReferenceSystem::Iers1996 => Ok(self.try_rotation(J2000, Mod(Iers1996), time)?),
1089                ReferenceSystem::Iers2003(iau2000_model) => {
1090                    Ok(self.try_rotation(J2000, Mod(Iers2003(iau2000_model)), time)?)
1091                }
1092                ReferenceSystem::Iers2010 => Ok(self.try_rotation(J2000, Mod(Iers2010), time)?),
1093            },
1094            (DynFrame::J2000, DynFrame::Tod(sys)) => match sys {
1095                ReferenceSystem::Iers1996 => Ok(self.try_rotation(J2000, Tod(Iers1996), time)?),
1096                ReferenceSystem::Iers2003(iau2000_model) => {
1097                    Ok(self.try_rotation(J2000, Tod(Iers2003(iau2000_model)), time)?)
1098                }
1099                ReferenceSystem::Iers2010 => Ok(self.try_rotation(J2000, Tod(Iers2010), time)?),
1100            },
1101            (DynFrame::J2000, DynFrame::Pef(sys)) => match sys {
1102                ReferenceSystem::Iers1996 => Ok(self.try_rotation(J2000, Pef(Iers1996), time)?),
1103                ReferenceSystem::Iers2003(iau2000_model) => {
1104                    Ok(self.try_rotation(J2000, Pef(Iers2003(iau2000_model)), time)?)
1105                }
1106                ReferenceSystem::Iers2010 => Ok(self.try_rotation(J2000, Pef(Iers2010), time)?),
1107            },
1108            (DynFrame::J2000, DynFrame::Teme) => Ok(self.try_rotation(J2000, Teme, time)?),
1109            (DynFrame::Cirf, DynFrame::Icrf) => Ok(self.try_rotation(Cirf, Icrf, time)?),
1110            (DynFrame::Cirf, DynFrame::Tirf) => Ok(self.try_rotation(Cirf, Tirf, time)?),
1111            (DynFrame::Cirf, DynFrame::Itrf) => Ok(self.try_rotation(Cirf, Itrf, time)?),
1112            (DynFrame::Cirf, DynFrame::Iau(body)) => {
1113                Ok(self.try_rotation(Cirf, Iau::try_new(body)?, time)?)
1114            }
1115            (DynFrame::Cirf, DynFrame::Mod(sys)) => match sys {
1116                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Cirf, Mod(Iers1996), time)?),
1117                ReferenceSystem::Iers2003(iau2000_model) => {
1118                    Ok(self.try_rotation(Cirf, Mod(Iers2003(iau2000_model)), time)?)
1119                }
1120                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Cirf, Mod(Iers2010), time)?),
1121            },
1122            (DynFrame::Cirf, DynFrame::Tod(sys)) => match sys {
1123                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Cirf, Tod(Iers1996), time)?),
1124                ReferenceSystem::Iers2003(iau2000_model) => {
1125                    Ok(self.try_rotation(Cirf, Tod(Iers2003(iau2000_model)), time)?)
1126                }
1127                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Cirf, Tod(Iers2010), time)?),
1128            },
1129            (DynFrame::Cirf, DynFrame::Pef(sys)) => match sys {
1130                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Cirf, Pef(Iers1996), time)?),
1131                ReferenceSystem::Iers2003(iau2000_model) => {
1132                    Ok(self.try_rotation(Cirf, Pef(Iers2003(iau2000_model)), time)?)
1133                }
1134                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Cirf, Pef(Iers2010), time)?),
1135            },
1136            (DynFrame::Cirf, DynFrame::Teme) => Ok(self.try_rotation(Cirf, Teme, time)?),
1137            (DynFrame::Cirf, DynFrame::J2000) => Ok(self.try_rotation(Cirf, J2000, time)?),
1138            (DynFrame::Tirf, DynFrame::Icrf) => Ok(self.try_rotation(Tirf, Icrf, time)?),
1139            (DynFrame::Tirf, DynFrame::Cirf) => Ok(self.try_rotation(Tirf, Cirf, time)?),
1140            (DynFrame::Tirf, DynFrame::Itrf) => Ok(self.try_rotation(Tirf, Itrf, time)?),
1141            (DynFrame::Tirf, DynFrame::Iau(body)) => {
1142                Ok(self.try_rotation(Tirf, Iau::try_new(body)?, time)?)
1143            }
1144            (DynFrame::Tirf, DynFrame::Mod(sys)) => match sys {
1145                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tirf, Mod(Iers1996), time)?),
1146                ReferenceSystem::Iers2003(iau2000_model) => {
1147                    Ok(self.try_rotation(Tirf, Mod(Iers2003(iau2000_model)), time)?)
1148                }
1149                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tirf, Mod(Iers2010), time)?),
1150            },
1151            (DynFrame::Tirf, DynFrame::Tod(sys)) => match sys {
1152                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tirf, Tod(Iers1996), time)?),
1153                ReferenceSystem::Iers2003(iau2000_model) => {
1154                    Ok(self.try_rotation(Tirf, Tod(Iers2003(iau2000_model)), time)?)
1155                }
1156                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tirf, Tod(Iers2010), time)?),
1157            },
1158            (DynFrame::Tirf, DynFrame::Pef(sys)) => match sys {
1159                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tirf, Pef(Iers1996), time)?),
1160                ReferenceSystem::Iers2003(iau2000_model) => {
1161                    Ok(self.try_rotation(Tirf, Pef(Iers2003(iau2000_model)), time)?)
1162                }
1163                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tirf, Pef(Iers2010), time)?),
1164            },
1165            (DynFrame::Tirf, DynFrame::Teme) => Ok(self.try_rotation(Tirf, Teme, time)?),
1166            (DynFrame::Tirf, DynFrame::J2000) => Ok(self.try_rotation(Tirf, J2000, time)?),
1167            (DynFrame::Itrf, DynFrame::Icrf) => Ok(self.try_rotation(Itrf, Icrf, time)?),
1168            (DynFrame::Itrf, DynFrame::Cirf) => Ok(self.try_rotation(Itrf, Cirf, time)?),
1169            (DynFrame::Itrf, DynFrame::Tirf) => Ok(self.try_rotation(Itrf, Tirf, time)?),
1170            (DynFrame::Itrf, DynFrame::Iau(body)) => {
1171                Ok(self.try_rotation(Itrf, Iau::try_new(body)?, time)?)
1172            }
1173            (DynFrame::Itrf, DynFrame::Mod(sys)) => match sys {
1174                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Itrf, Mod(Iers1996), time)?),
1175                ReferenceSystem::Iers2003(iau2000_model) => {
1176                    Ok(self.try_rotation(Itrf, Mod(Iers2003(iau2000_model)), time)?)
1177                }
1178                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Itrf, Mod(Iers2010), time)?),
1179            },
1180            (DynFrame::Itrf, DynFrame::Tod(sys)) => match sys {
1181                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Itrf, Tod(Iers1996), time)?),
1182                ReferenceSystem::Iers2003(iau2000_model) => {
1183                    Ok(self.try_rotation(Itrf, Tod(Iers2003(iau2000_model)), time)?)
1184                }
1185                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Itrf, Tod(Iers2010), time)?),
1186            },
1187            (DynFrame::Itrf, DynFrame::Pef(sys)) => match sys {
1188                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Itrf, Pef(Iers1996), time)?),
1189                ReferenceSystem::Iers2003(iau2000_model) => {
1190                    Ok(self.try_rotation(Itrf, Pef(Iers2003(iau2000_model)), time)?)
1191                }
1192                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Itrf, Pef(Iers2010), time)?),
1193            },
1194            (DynFrame::Itrf, DynFrame::Teme) => Ok(self.try_rotation(Itrf, Teme, time)?),
1195            (DynFrame::Itrf, DynFrame::J2000) => Ok(self.try_rotation(Itrf, J2000, time)?),
1196            (DynFrame::Iau(body), DynFrame::Icrf) => {
1197                Ok(self.try_rotation(Iau::try_new(body)?, Icrf, time)?)
1198            }
1199            (DynFrame::Iau(body), DynFrame::Cirf) => {
1200                Ok(self.try_rotation(Iau::try_new(body)?, Cirf, time)?)
1201            }
1202            (DynFrame::Iau(body), DynFrame::Tirf) => {
1203                Ok(self.try_rotation(Iau::try_new(body)?, Tirf, time)?)
1204            }
1205            (DynFrame::Iau(body), DynFrame::Itrf) => {
1206                Ok(self.try_rotation(Iau::try_new(body)?, Itrf, time)?)
1207            }
1208            (DynFrame::Iau(body), DynFrame::Mod(sys)) => match sys {
1209                ReferenceSystem::Iers1996 => {
1210                    Ok(self.try_rotation(Iau::try_new(body)?, Mod(Iers1996), time)?)
1211                }
1212                ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1213                    Iau::try_new(body)?,
1214                    Mod(Iers2003(iau2000_model)),
1215                    time,
1216                )?),
1217                ReferenceSystem::Iers2010 => {
1218                    Ok(self.try_rotation(Iau::try_new(body)?, Mod(Iers2010), time)?)
1219                }
1220            },
1221            (DynFrame::Iau(body), DynFrame::Tod(sys)) => match sys {
1222                ReferenceSystem::Iers1996 => {
1223                    Ok(self.try_rotation(Iau::try_new(body)?, Tod(Iers1996), time)?)
1224                }
1225                ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1226                    Iau::try_new(body)?,
1227                    Tod(Iers2003(iau2000_model)),
1228                    time,
1229                )?),
1230                ReferenceSystem::Iers2010 => {
1231                    Ok(self.try_rotation(Iau::try_new(body)?, Tod(Iers2010), time)?)
1232                }
1233            },
1234            (DynFrame::Iau(body), DynFrame::Pef(sys)) => match sys {
1235                ReferenceSystem::Iers1996 => {
1236                    Ok(self.try_rotation(Iau::try_new(body)?, Pef(Iers1996), time)?)
1237                }
1238                ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1239                    Iau::try_new(body)?,
1240                    Pef(Iers2003(iau2000_model)),
1241                    time,
1242                )?),
1243                ReferenceSystem::Iers2010 => {
1244                    Ok(self.try_rotation(Iau::try_new(body)?, Pef(Iers2010), time)?)
1245                }
1246            },
1247            (DynFrame::Iau(body), DynFrame::Teme) => {
1248                Ok(self.try_rotation(Iau::try_new(body)?, Teme, time)?)
1249            }
1250            (DynFrame::Iau(body), DynFrame::J2000) => {
1251                Ok(self.try_rotation(Iau::try_new(body)?, J2000, time)?)
1252            }
1253            (DynFrame::Mod(sys), DynFrame::Icrf) => match sys {
1254                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Mod(Iers1996), Icrf, time)?),
1255                ReferenceSystem::Iers2003(iau2000_model) => {
1256                    Ok(self.try_rotation(Mod(Iers2003(iau2000_model)), Icrf, time)?)
1257                }
1258                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Mod(Iers2010), Icrf, time)?),
1259            },
1260            (DynFrame::Mod(sys), DynFrame::Cirf) => match sys {
1261                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Mod(Iers1996), Cirf, time)?),
1262                ReferenceSystem::Iers2003(iau2000_model) => {
1263                    Ok(self.try_rotation(Mod(Iers2003(iau2000_model)), Cirf, time)?)
1264                }
1265                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Mod(Iers2010), Cirf, time)?),
1266            },
1267            (DynFrame::Mod(sys), DynFrame::Tirf) => match sys {
1268                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Mod(Iers1996), Tirf, time)?),
1269                ReferenceSystem::Iers2003(iau2000_model) => {
1270                    Ok(self.try_rotation(Mod(Iers2003(iau2000_model)), Tirf, time)?)
1271                }
1272                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Mod(Iers2010), Tirf, time)?),
1273            },
1274            (DynFrame::Mod(sys), DynFrame::Itrf) => match sys {
1275                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Mod(Iers1996), Itrf, time)?),
1276                ReferenceSystem::Iers2003(iau2000_model) => {
1277                    Ok(self.try_rotation(Mod(Iers2003(iau2000_model)), Itrf, time)?)
1278                }
1279                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Mod(Iers2010), Itrf, time)?),
1280            },
1281            (DynFrame::Mod(sys), DynFrame::Iau(body)) => match sys {
1282                ReferenceSystem::Iers1996 => {
1283                    Ok(self.try_rotation(Mod(Iers1996), Iau::try_new(body)?, time)?)
1284                }
1285                ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1286                    Mod(Iers2003(iau2000_model)),
1287                    Iau::try_new(body)?,
1288                    time,
1289                )?),
1290                ReferenceSystem::Iers2010 => {
1291                    Ok(self.try_rotation(Mod(Iers2010), Iau::try_new(body)?, time)?)
1292                }
1293            },
1294            (DynFrame::Mod(sys1), DynFrame::Tod(sys2)) => {
1295                if sys1 != sys2 {
1296                    return Err(DynRotationError::IncompatibleReferenceSystems);
1297                }
1298                match sys1 {
1299                    ReferenceSystem::Iers1996 => {
1300                        Ok(self.try_rotation(Mod(Iers1996), Tod(Iers1996), time)?)
1301                    }
1302                    ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1303                        Mod(Iers2003(iau2000_model)),
1304                        Tod(Iers2003(iau2000_model)),
1305                        time,
1306                    )?),
1307                    ReferenceSystem::Iers2010 => {
1308                        Ok(self.try_rotation(Mod(Iers2010), Tod(Iers2010), time)?)
1309                    }
1310                }
1311            }
1312            (DynFrame::Mod(sys1), DynFrame::Pef(sys2)) => {
1313                if sys1 != sys2 {
1314                    return Err(DynRotationError::IncompatibleReferenceSystems);
1315                }
1316                match sys1 {
1317                    ReferenceSystem::Iers1996 => {
1318                        Ok(self.try_rotation(Mod(Iers1996), Pef(Iers1996), time)?)
1319                    }
1320                    ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1321                        Mod(Iers2003(iau2000_model)),
1322                        Pef(Iers2003(iau2000_model)),
1323                        time,
1324                    )?),
1325                    ReferenceSystem::Iers2010 => {
1326                        Ok(self.try_rotation(Mod(Iers2010), Pef(Iers2010), time)?)
1327                    }
1328                }
1329            }
1330            (DynFrame::Mod(sys), DynFrame::Teme) => match sys {
1331                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Mod(Iers1996), Teme, time)?),
1332                ReferenceSystem::Iers2003(iau2000_model) => {
1333                    Ok(self.try_rotation(Mod(Iers2003(iau2000_model)), Teme, time)?)
1334                }
1335                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Mod(Iers2010), Teme, time)?),
1336            },
1337            (DynFrame::Mod(sys), DynFrame::J2000) => match sys {
1338                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Mod(Iers1996), J2000, time)?),
1339                ReferenceSystem::Iers2003(iau2000_model) => {
1340                    Ok(self.try_rotation(Mod(Iers2003(iau2000_model)), J2000, time)?)
1341                }
1342                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Mod(Iers2010), J2000, time)?),
1343            },
1344            (DynFrame::Tod(sys), DynFrame::Icrf) => match sys {
1345                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tod(Iers1996), Icrf, time)?),
1346                ReferenceSystem::Iers2003(iau2000_model) => {
1347                    Ok(self.try_rotation(Tod(Iers2003(iau2000_model)), Icrf, time)?)
1348                }
1349                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tod(Iers2010), Icrf, time)?),
1350            },
1351            (DynFrame::Tod(sys), DynFrame::Cirf) => match sys {
1352                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tod(Iers1996), Cirf, time)?),
1353                ReferenceSystem::Iers2003(iau2000_model) => {
1354                    Ok(self.try_rotation(Tod(Iers2003(iau2000_model)), Cirf, time)?)
1355                }
1356                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tod(Iers2010), Cirf, time)?),
1357            },
1358            (DynFrame::Tod(sys), DynFrame::Tirf) => match sys {
1359                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tod(Iers1996), Tirf, time)?),
1360                ReferenceSystem::Iers2003(iau2000_model) => {
1361                    Ok(self.try_rotation(Tod(Iers2003(iau2000_model)), Tirf, time)?)
1362                }
1363                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tod(Iers2010), Tirf, time)?),
1364            },
1365            (DynFrame::Tod(sys), DynFrame::Itrf) => match sys {
1366                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tod(Iers1996), Itrf, time)?),
1367                ReferenceSystem::Iers2003(iau2000_model) => {
1368                    Ok(self.try_rotation(Tod(Iers2003(iau2000_model)), Itrf, time)?)
1369                }
1370                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tod(Iers2010), Itrf, time)?),
1371            },
1372            (DynFrame::Tod(sys), DynFrame::Iau(body)) => match sys {
1373                ReferenceSystem::Iers1996 => {
1374                    Ok(self.try_rotation(Tod(Iers1996), Iau::try_new(body)?, time)?)
1375                }
1376                ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1377                    Tod(Iers2003(iau2000_model)),
1378                    Iau::try_new(body)?,
1379                    time,
1380                )?),
1381                ReferenceSystem::Iers2010 => {
1382                    Ok(self.try_rotation(Tod(Iers2010), Iau::try_new(body)?, time)?)
1383                }
1384            },
1385            (DynFrame::Tod(sys1), DynFrame::Mod(sys2)) => {
1386                if sys1 != sys2 {
1387                    return Err(DynRotationError::IncompatibleReferenceSystems);
1388                }
1389                match sys1 {
1390                    ReferenceSystem::Iers1996 => {
1391                        Ok(self.try_rotation(Tod(Iers1996), Mod(Iers1996), time)?)
1392                    }
1393                    ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1394                        Tod(Iers2003(iau2000_model)),
1395                        Mod(Iers2003(iau2000_model)),
1396                        time,
1397                    )?),
1398                    ReferenceSystem::Iers2010 => {
1399                        Ok(self.try_rotation(Tod(Iers2010), Mod(Iers2010), time)?)
1400                    }
1401                }
1402            }
1403            (DynFrame::Tod(sys1), DynFrame::Pef(sys2)) => {
1404                if sys1 != sys2 {
1405                    return Err(DynRotationError::IncompatibleReferenceSystems);
1406                }
1407                match sys1 {
1408                    ReferenceSystem::Iers1996 => {
1409                        Ok(self.try_rotation(Tod(Iers1996), Pef(Iers1996), time)?)
1410                    }
1411                    ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1412                        Tod(Iers2003(iau2000_model)),
1413                        Pef(Iers2003(iau2000_model)),
1414                        time,
1415                    )?),
1416                    ReferenceSystem::Iers2010 => {
1417                        Ok(self.try_rotation(Tod(Iers2010), Pef(Iers2010), time)?)
1418                    }
1419                }
1420            }
1421            (DynFrame::Tod(sys), DynFrame::Teme) => match sys {
1422                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tod(Iers1996), Teme, time)?),
1423                ReferenceSystem::Iers2003(iau2000_model) => {
1424                    Ok(self.try_rotation(Tod(Iers2003(iau2000_model)), Teme, time)?)
1425                }
1426                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tod(Iers2010), Teme, time)?),
1427            },
1428            (DynFrame::Tod(sys), DynFrame::J2000) => match sys {
1429                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Tod(Iers1996), J2000, time)?),
1430                ReferenceSystem::Iers2003(iau2000_model) => {
1431                    Ok(self.try_rotation(Tod(Iers2003(iau2000_model)), J2000, time)?)
1432                }
1433                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Tod(Iers2010), J2000, time)?),
1434            },
1435            (DynFrame::Pef(sys), DynFrame::Icrf) => match sys {
1436                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Pef(Iers1996), Icrf, time)?),
1437                ReferenceSystem::Iers2003(iau2000_model) => {
1438                    Ok(self.try_rotation(Pef(Iers2003(iau2000_model)), Icrf, time)?)
1439                }
1440                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Pef(Iers2010), Icrf, time)?),
1441            },
1442            (DynFrame::Pef(sys), DynFrame::Cirf) => match sys {
1443                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Pef(Iers1996), Cirf, time)?),
1444                ReferenceSystem::Iers2003(iau2000_model) => {
1445                    Ok(self.try_rotation(Pef(Iers2003(iau2000_model)), Cirf, time)?)
1446                }
1447                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Pef(Iers2010), Cirf, time)?),
1448            },
1449            (DynFrame::Pef(sys), DynFrame::Tirf) => match sys {
1450                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Pef(Iers1996), Tirf, time)?),
1451                ReferenceSystem::Iers2003(iau2000_model) => {
1452                    Ok(self.try_rotation(Pef(Iers2003(iau2000_model)), Tirf, time)?)
1453                }
1454                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Pef(Iers2010), Tirf, time)?),
1455            },
1456            (DynFrame::Pef(sys), DynFrame::Itrf) => match sys {
1457                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Pef(Iers1996), Itrf, time)?),
1458                ReferenceSystem::Iers2003(iau2000_model) => {
1459                    Ok(self.try_rotation(Pef(Iers2003(iau2000_model)), Itrf, time)?)
1460                }
1461                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Pef(Iers2010), Itrf, time)?),
1462            },
1463            (DynFrame::Pef(sys), DynFrame::Iau(body)) => match sys {
1464                ReferenceSystem::Iers1996 => {
1465                    Ok(self.try_rotation(Pef(Iers1996), Iau::try_new(body)?, time)?)
1466                }
1467                ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1468                    Pef(Iers2003(iau2000_model)),
1469                    Iau::try_new(body)?,
1470                    time,
1471                )?),
1472                ReferenceSystem::Iers2010 => {
1473                    Ok(self.try_rotation(Pef(Iers2010), Iau::try_new(body)?, time)?)
1474                }
1475            },
1476            (DynFrame::Pef(sys1), DynFrame::Mod(sys2)) => {
1477                if sys1 != sys2 {
1478                    return Err(DynRotationError::IncompatibleReferenceSystems);
1479                }
1480                match sys1 {
1481                    ReferenceSystem::Iers1996 => {
1482                        Ok(self.try_rotation(Pef(Iers1996), Mod(Iers1996), time)?)
1483                    }
1484                    ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1485                        Pef(Iers2003(iau2000_model)),
1486                        Mod(Iers2003(iau2000_model)),
1487                        time,
1488                    )?),
1489                    ReferenceSystem::Iers2010 => {
1490                        Ok(self.try_rotation(Pef(Iers2010), Mod(Iers2010), time)?)
1491                    }
1492                }
1493            }
1494            (DynFrame::Pef(sys1), DynFrame::Tod(sys2)) => {
1495                if sys1 != sys2 {
1496                    return Err(DynRotationError::IncompatibleReferenceSystems);
1497                }
1498                match sys1 {
1499                    ReferenceSystem::Iers1996 => {
1500                        Ok(self.try_rotation(Pef(Iers1996), Tod(Iers1996), time)?)
1501                    }
1502                    ReferenceSystem::Iers2003(iau2000_model) => Ok(self.try_rotation(
1503                        Pef(Iers2003(iau2000_model)),
1504                        Tod(Iers2003(iau2000_model)),
1505                        time,
1506                    )?),
1507                    ReferenceSystem::Iers2010 => {
1508                        Ok(self.try_rotation(Pef(Iers2010), Tod(Iers2010), time)?)
1509                    }
1510                }
1511            }
1512            (DynFrame::Pef(sys), DynFrame::Teme) => match sys {
1513                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Pef(Iers1996), Teme, time)?),
1514                ReferenceSystem::Iers2003(iau2000_model) => {
1515                    Ok(self.try_rotation(Pef(Iers2003(iau2000_model)), Teme, time)?)
1516                }
1517                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Pef(Iers2010), Teme, time)?),
1518            },
1519            (DynFrame::Pef(sys), DynFrame::J2000) => match sys {
1520                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Pef(Iers1996), J2000, time)?),
1521                ReferenceSystem::Iers2003(iau2000_model) => {
1522                    Ok(self.try_rotation(Pef(Iers2003(iau2000_model)), J2000, time)?)
1523                }
1524                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Pef(Iers2010), J2000, time)?),
1525            },
1526            (DynFrame::Teme, DynFrame::Icrf) => Ok(self.try_rotation(Teme, Icrf, time)?),
1527            (DynFrame::Teme, DynFrame::Cirf) => Ok(self.try_rotation(Teme, Cirf, time)?),
1528            (DynFrame::Teme, DynFrame::Tirf) => Ok(self.try_rotation(Teme, Tirf, time)?),
1529            (DynFrame::Teme, DynFrame::Itrf) => Ok(self.try_rotation(Teme, Itrf, time)?),
1530            (DynFrame::Teme, DynFrame::Iau(body)) => {
1531                Ok(self.try_rotation(Teme, Iau::try_new(body)?, time)?)
1532            }
1533            (DynFrame::Teme, DynFrame::Mod(sys)) => match sys {
1534                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Teme, Mod(Iers1996), time)?),
1535                ReferenceSystem::Iers2003(iau2000_model) => {
1536                    Ok(self.try_rotation(Teme, Mod(Iers2003(iau2000_model)), time)?)
1537                }
1538                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Teme, Mod(Iers2010), time)?),
1539            },
1540            (DynFrame::Teme, DynFrame::Tod(sys)) => match sys {
1541                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Teme, Tod(Iers1996), time)?),
1542                ReferenceSystem::Iers2003(iau2000_model) => {
1543                    Ok(self.try_rotation(Teme, Tod(Iers2003(iau2000_model)), time)?)
1544                }
1545                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Teme, Tod(Iers2010), time)?),
1546            },
1547            (DynFrame::Teme, DynFrame::Pef(sys)) => match sys {
1548                ReferenceSystem::Iers1996 => Ok(self.try_rotation(Teme, Pef(Iers1996), time)?),
1549                ReferenceSystem::Iers2003(iau2000_model) => {
1550                    Ok(self.try_rotation(Teme, Pef(Iers2003(iau2000_model)), time)?)
1551                }
1552                ReferenceSystem::Iers2010 => Ok(self.try_rotation(Teme, Pef(Iers2010), time)?),
1553            },
1554            (DynFrame::Teme, DynFrame::J2000) => Ok(self.try_rotation(Teme, J2000, time)?),
1555            (_, _) => Ok(Rotation::IDENTITY),
1556        }
1557    }
1558}
1559
1560// Mixed DynFrame <-> ConcreteFrame rotations
1561//
1562// These impls allow rotation providers to handle `DynFrame → R` and `R → DynFrame`
1563// for concrete frame types. They delegate to the existing `DynFrame → DynFrame` impl
1564// by converting the concrete frame via `Into<DynFrame>`.
1565
1566macro_rules! impl_mixed_dyn_rotation {
1567    ($($frame:ty),* $(,)?) => {
1568        $(
1569            impl<T, U> TryRotation<DynFrame, $frame, T> for U
1570            where
1571                T: TimeScale + Copy,
1572                U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Tdb> + TryOffset<T, Ut1>,
1573            {
1574                type Error = DynRotationError;
1575
1576                fn try_rotation(
1577                    &self,
1578                    origin: DynFrame,
1579                    target: $frame,
1580                    time: Time<T>,
1581                ) -> Result<Rotation, Self::Error> {
1582                    let target_dyn: DynFrame = target.into();
1583                    <Self as TryRotation<DynFrame, DynFrame, T>>::try_rotation(
1584                        self, origin, target_dyn, time,
1585                    )
1586                }
1587            }
1588
1589            impl<T, U> TryRotation<$frame, DynFrame, T> for U
1590            where
1591                T: TimeScale + Copy,
1592                U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Tdb> + TryOffset<T, Ut1>,
1593            {
1594                type Error = DynRotationError;
1595
1596                fn try_rotation(
1597                    &self,
1598                    origin: $frame,
1599                    target: DynFrame,
1600                    time: Time<T>,
1601                ) -> Result<Rotation, Self::Error> {
1602                    let origin_dyn: DynFrame = origin.into();
1603                    <Self as TryRotation<DynFrame, DynFrame, T>>::try_rotation(
1604                        self, origin_dyn, target, time,
1605                    )
1606                }
1607            }
1608        )*
1609    };
1610}
1611
1612impl_mixed_dyn_rotation!(
1613    Icrf,
1614    J2000,
1615    Cirf,
1616    Tirf,
1617    Itrf,
1618    Teme,
1619    Mod<Iers1996>,
1620    Mod<Iers2003>,
1621    Mod<Iers2010>,
1622    Tod<Iers1996>,
1623    Tod<Iers2003>,
1624    Tod<Iers2010>,
1625    Pef<Iers1996>,
1626    Pef<Iers2003>,
1627    Pef<Iers2010>,
1628);
1629
1630// Iau<DynOrigin> mixed impls — used by the Dyn path for body-fixed frames.
1631impl<T, U> TryRotation<DynFrame, Iau<DynOrigin>, T> for U
1632where
1633    T: TimeScale + Copy,
1634    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Tdb> + TryOffset<T, Ut1>,
1635{
1636    type Error = DynRotationError;
1637
1638    fn try_rotation(
1639        &self,
1640        origin: DynFrame,
1641        target: Iau<DynOrigin>,
1642        time: Time<T>,
1643    ) -> Result<Rotation, Self::Error> {
1644        let target_dyn: DynFrame = target.into();
1645        <Self as TryRotation<DynFrame, DynFrame, T>>::try_rotation(self, origin, target_dyn, time)
1646    }
1647}
1648
1649impl<T, U> TryRotation<Iau<DynOrigin>, DynFrame, T> for U
1650where
1651    T: TimeScale + Copy,
1652    U: RotationProvider<T> + TryOffset<T, Tt> + TryOffset<T, Tdb> + TryOffset<T, Ut1>,
1653{
1654    type Error = DynRotationError;
1655
1656    fn try_rotation(
1657        &self,
1658        origin: Iau<DynOrigin>,
1659        target: DynFrame,
1660        time: Time<T>,
1661    ) -> Result<Rotation, Self::Error> {
1662        let origin_dyn: DynFrame = origin.into();
1663        <Self as TryRotation<DynFrame, DynFrame, T>>::try_rotation(self, origin_dyn, target, time)
1664    }
1665}
1666
1667#[cfg(test)]
1668mod tests {
1669    use super::*;
1670    use crate::providers::DefaultRotationProvider;
1671    use lox_time::time_scales::Tai;
1672
1673    fn tai_j2000() -> Time<Tai> {
1674        Time::j2000(Tai)
1675    }
1676
1677    #[test]
1678    fn test_mixed_icrf_to_dynframe() {
1679        let time = tai_j2000();
1680        let rot: Rotation = DefaultRotationProvider
1681            .try_rotation(Icrf, DynFrame::Icrf, time)
1682            .unwrap();
1683        assert!(
1684            rot.position_matrix()
1685                .abs_diff_eq(glam::DMat3::IDENTITY, 1e-14)
1686        );
1687    }
1688
1689    #[test]
1690    fn test_mixed_dynframe_to_icrf() {
1691        let time = tai_j2000();
1692        let rot: Rotation = DefaultRotationProvider
1693            .try_rotation(DynFrame::Icrf, Icrf, time)
1694            .unwrap();
1695        assert!(
1696            rot.position_matrix()
1697                .abs_diff_eq(glam::DMat3::IDENTITY, 1e-14)
1698        );
1699    }
1700
1701    #[test]
1702    fn test_mixed_iau_dynorigin_to_dynframe() {
1703        let time = tai_j2000();
1704        let iau_earth = Iau::try_new(DynOrigin::Earth).unwrap();
1705        let rot: Rotation = DefaultRotationProvider
1706            .try_rotation(iau_earth, DynFrame::Icrf, time)
1707            .unwrap();
1708        assert!(
1709            !rot.position_matrix()
1710                .abs_diff_eq(glam::DMat3::IDENTITY, 1e-6)
1711        );
1712    }
1713
1714    #[test]
1715    fn test_mixed_dynframe_to_iau_dynorigin() {
1716        let time = tai_j2000();
1717        let iau_earth = Iau::try_new(DynOrigin::Earth).unwrap();
1718        let rot: Rotation = DefaultRotationProvider
1719            .try_rotation(DynFrame::Icrf, iau_earth, time)
1720            .unwrap();
1721        assert!(
1722            !rot.position_matrix()
1723                .abs_diff_eq(glam::DMat3::IDENTITY, 1e-6)
1724        );
1725    }
1726
1727    #[test]
1728    fn test_mixed_roundtrip_icrf_iau_earth() {
1729        let time = tai_j2000();
1730        let iau_earth = Iau::try_new(DynOrigin::Earth).unwrap();
1731        let rot_fwd: Rotation = DefaultRotationProvider
1732            .try_rotation(Icrf, DynFrame::Iau(DynOrigin::Earth), time)
1733            .unwrap();
1734        let rot_bwd: Rotation = DefaultRotationProvider
1735            .try_rotation(iau_earth, DynFrame::Icrf, time)
1736            .unwrap();
1737        let product = rot_fwd.position_matrix() * rot_bwd.position_matrix();
1738        assert!(product.abs_diff_eq(glam::DMat3::IDENTITY, 1e-14));
1739    }
1740}