1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.bodies;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24  import org.hipparchus.geometry.euclidean.threed.Vector3D;
25  import org.hipparchus.util.FastMath;
26  import org.hipparchus.util.FieldSinCos;
27  import org.hipparchus.util.SinCos;
28  import org.orekit.bodies.JPLEphemeridesLoader.EphemerisType;
29  import org.orekit.time.AbsoluteDate;
30  import org.orekit.time.FieldAbsoluteDate;
31  import org.orekit.time.TimeScales;
32  import org.orekit.utils.Constants;
33  
34  /** Enumerate for predefined IAU poles.
35   * <p>The pole models provided here come from the <a
36   * href="http://astropedia.astrogeology.usgs.gov/alfresco/d/d/workspace/SpacesStore/28fd9e81-1964-44d6-a58b-fbbf61e64e15/WGCCRE2009reprint.pdf">
37   * 2009 report</a> and the <a href="http://astropedia.astrogeology.usgs.gov/alfresco/d/d/workspace/SpacesStore/04d348b0-eb2b-46a2-abe9-6effacb37763/WGCCRE-Erratum-2011reprint.pdf">
38   * 2011 erratum</a> of the IAU/IAG Working Group on Cartographic Coordinates
39   * and Rotational Elements of the Planets and Satellites (WGCCRE). Note that these value
40   * differ from earliest reports (before 2005).
41   *</p>
42   * @author Luc Maisonobe
43   * @since 9.0
44   */
45  abstract class PredefinedIAUPoles implements IAUPole {
46  
47      /** Serializable UID. */
48      private static final long serialVersionUID = 20200130L;
49  
50      /** Time scales. */
51      private final TimeScales timeScales;
52  
53      /**
54       * Simple constructor.
55       *
56       * @param timeScales to use when computing the pole, including TDB and J2000.0.
57       */
58      PredefinedIAUPoles(final TimeScales timeScales) {
59          this.timeScales = timeScales;
60      }
61  
62      /** IAU pole and prime meridian model for Sun. */
63      private static class Sun extends PredefinedIAUPoles {
64  
65          /** Serializable UID. */
66          private static final long serialVersionUID = 20200130L;
67  
68          /** Constant term of the prime meridian. */
69          private static final double W0 = 84.176;
70  
71          /** Rate term of the prime meridian. */
72          private static final double W_DOT = 14.1844000;
73  
74          /** Fixed pole. */
75          private final Vector3D pole = new Vector3D(FastMath.toRadians(286.13),
76                                                     FastMath.toRadians(63.87));
77  
78          /**
79           * Simple constructor.
80           *
81           * @param timeScales to use when computing the pole, including TDB and J2000.0.
82           */
83          Sun(final TimeScales timeScales) {
84              super(timeScales);
85          }
86  
87          /** {@inheritDoc} */
88          public Vector3D getPole(final AbsoluteDate date) {
89              return pole;
90          }
91  
92          /** {@inheritDoc} */
93          public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
94              return new FieldVector3D<>(date.getField(), pole);
95          }
96  
97          /** {@inheritDoc} */
98          public double getPrimeMeridianAngle(final AbsoluteDate date) {
99              return FastMath.toRadians(d(date) * W_DOT + W0);
100         }
101 
102         /** {@inheritDoc} */
103         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
104             return FastMath.toRadians(d(date).multiply(W_DOT).add(W0));
105         }
106 
107     }
108 
109     /** IAU pole and prime meridian model for Mercury. */
110     private static class Mercury extends PredefinedIAUPoles {
111 
112         /** Serializable UID. */
113         private static final long serialVersionUID = 20200130L;
114 
115         /** Constant term of the right ascension of the pole. */
116         private static final double ALPHA_0 = 281.0097;
117 
118         /** Rate term of the right ascension of the pole. */
119         private static final double ALPHA_DOT = -0.0328;
120 
121         /** Constant term of the declination of the pole. */
122         private static final double DELTA_0 = 61.4143;
123 
124         /** Rate term of the declination of the pole. */
125         private static final double DELTA_DOT = -0.0049;
126 
127         /** Constant term of the prime meridian. */
128         private static final double W_0 = 329.5469;
129 
130         /** Rate term of the prime meridian. */
131         private static final double W_DOT = 6.1385025;
132 
133         /** M1 coefficient of the prime meridian. */
134         private static final double M1_COEFF = 0.00993822;
135 
136         /** M2 coefficient of the prime meridian. */
137         private static final double M2_COEFF = -0.00104581;
138 
139         /** M3 coefficient of the prime meridian. */
140         private static final double M3_COEFF = -0.00010280;
141 
142         /** M4 coefficient of the prime meridian. */
143         private static final double M4_COEFF = -0.00002364;
144 
145         /** M5 coefficient of the prime meridian. */
146         private static final double M5_COEFF = -0.00000532;
147 
148         /** Constant term of the M1 angle. */
149         private static final double M1_0   = 174.791086;
150 
151         /** Rate term of the M1 angle. */
152         private static final double M1_DOT = 4.092335;
153 
154         /** Constant term of the M2 angle. */
155         private static final double M2_0   = 349.582171;
156 
157         /** Rate term of the M1 angle. */
158         private static final double M2_DOT = 8.184670;
159 
160         /** Constant term of the M3 angle. */
161         private static final double M3_0   = 164.373257;
162 
163         /** Rate term of the M1 angle. */
164         private static final double M3_DOT = 12.277005;
165 
166         /** Constant term of the M4 angle. */
167         private static final double M4_0   = 339.164343;
168 
169         /** Rate term of the M1 angle. */
170         private static final double M4_DOT = 16.369340;
171 
172         /** Constant term of the M5 angle. */
173         private static final double M5_0   = 153.955429;
174 
175         /** Rate term of the M1 angle. */
176         private static final double M5_DOT = 20.461675;
177 
178         /**
179          * Simple constructor.
180          *
181          * @param timeScales to use when computing the pole, including TDB and J2000.0.
182          */
183         Mercury(final TimeScales timeScales) {
184             super(timeScales);
185         }
186 
187         /** {@inheritDoc} */
188         public Vector3D getPole(final AbsoluteDate date) {
189             final double t = t(date);
190             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
191                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
192         }
193 
194         /** {@inheritDoc} */
195         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
196             final T t = t(date);
197             return new FieldVector3D<>(FastMath.toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
198                                        FastMath.toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
199         }
200 
201         /** {@inheritDoc} */
202         public double getPrimeMeridianAngle(final AbsoluteDate date) {
203             final double d = d(date);
204             return FastMath.toRadians(d(date) * W_DOT + W_0 +
205                                       FastMath.sin(FastMath.toRadians(d * M1_DOT + M1_0)) * M1_COEFF +
206                                       FastMath.sin(FastMath.toRadians(d * M2_DOT + M2_0)) * M2_COEFF +
207                                       FastMath.sin(FastMath.toRadians(d * M3_DOT + M3_0)) * M3_COEFF +
208                                       FastMath.sin(FastMath.toRadians(d * M4_DOT + M4_0)) * M4_COEFF +
209                                       FastMath.sin(FastMath.toRadians(d * M5_DOT + M5_0)) * M5_COEFF);
210         }
211 
212         /** {@inheritDoc} */
213         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
214             final T d = d(date);
215             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0).
216                              add(FastMath.toRadians(d.multiply(M1_DOT).add(M1_0)).sin().multiply(M1_COEFF)).
217                              add(FastMath.toRadians(d.multiply(M2_DOT).add(M2_0)).sin().multiply(M2_COEFF)).
218                              add(FastMath.toRadians(d.multiply(M3_DOT).add(M3_0)).sin().multiply(M3_COEFF)).
219                              add(FastMath.toRadians(d.multiply(M4_DOT).add(M4_0)).sin().multiply(M4_COEFF)).
220                              add(FastMath.toRadians(d.multiply(M5_DOT).add(M5_0)).sin().multiply(M5_COEFF)));
221         }
222 
223     }
224 
225     /** IAU pole and prime meridian model for Venus. */
226     private static class Venus extends PredefinedIAUPoles {
227 
228         /** Serializable UID. */
229         private static final long serialVersionUID = 20200130L;
230 
231         /** Constant term of the prime meridian. */
232         private static final double W_0 = 160.20;
233 
234         /** Rate term of the prime meridian. */
235         private static final double W_DOT = -1.4813688;
236 
237         /** Fixed pole. */
238         private final Vector3D pole = new Vector3D(FastMath.toRadians(272.76),
239                                                    FastMath.toRadians(67.16));
240 
241         /**
242          * Simple constructor.
243          *
244          * @param timeScales to use when computing the pole, including TDB and J2000.0.
245          */
246         Venus(final TimeScales timeScales) {
247             super(timeScales);
248         }
249 
250         /** {@inheritDoc} */
251         public Vector3D getPole(final AbsoluteDate date) {
252             return pole;
253         }
254 
255         /** {@inheritDoc} */
256         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
257             return new FieldVector3D<>(date.getField(), pole);
258         }
259 
260         /** {@inheritDoc} */
261         public double getPrimeMeridianAngle(final AbsoluteDate date) {
262             return FastMath.toRadians(d(date) * W_DOT + W_0);
263         }
264 
265         /** {@inheritDoc} */
266         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
267             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0));
268         }
269 
270     }
271 
272     /** IAU pole and prime meridian model for Earth. */
273     private static class Earth extends PredefinedIAUPoles {
274 
275         /** Serializable UID. */
276         private static final long serialVersionUID = 20200130L;
277 
278         /** Constant term of the right ascension of the pole. */
279         private static final double ALPHA_0 =  0.00;
280 
281         /** Rate term of the right ascension of the pole. */
282         private static final double ALPHA_DOT = -0.641;
283 
284         /** Constant term of the declination of the pole. */
285         private static final double DELTA_0 = 90.00;
286 
287         /** Rate term of the declination of the pole. */
288         private static final double DELTA_DOT = -0.557;
289 
290         /** Constant term of the prime meridian. */
291         private static final double W_0 = 190.147;
292 
293         /** Rate term of the prime meridian. */
294         private static final double W_DOT = 360.9856235;
295 
296         /**
297          * Simple constructor.
298          *
299          * @param timeScales to use when computing the pole, including TDB and J2000.0.
300          */
301         Earth(final TimeScales timeScales) {
302             super(timeScales);
303         }
304 
305         /** {@inheritDoc} */
306         public Vector3D getPole(final AbsoluteDate date) {
307             final double t = t(date);
308             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
309                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
310         }
311 
312         /** {@inheritDoc} */
313         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
314             final T t = t(date);
315             return new FieldVector3D<>(FastMath.toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
316                                        FastMath.toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
317         }
318 
319         /** {@inheritDoc} */
320         @Override
321         public Vector3D getNode(final AbsoluteDate date) {
322             final double t = t(date);
323             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0 + 90.0),
324                                 0.0);
325         }
326 
327         /** {@inheritDoc} */
328         @Override
329         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getNode(final FieldAbsoluteDate<T> date) {
330             final T t = t(date);
331             return new FieldVector3D<>(FastMath.toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0 + 90.0)),
332                                        date.getField().getZero());
333         }
334 
335         /** {@inheritDoc} */
336         public double getPrimeMeridianAngle(final AbsoluteDate date) {
337             return FastMath.toRadians(d(date) * W_DOT + W_0);
338         }
339 
340         /** {@inheritDoc} */
341         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
342             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0));
343         }
344 
345     }
346 
347     /** IAU pole and prime meridian model for the Moon. */
348     private static class Moon extends PredefinedIAUPoles {
349 
350         /** Serializable UID. */
351         private static final long serialVersionUID = 20200130L;
352 
353         /** Constant term of the right ascension of the pole. */
354         private static final double ALPHA_0 = 269.9949;
355 
356         /** Rate term of the right ascension of the pole. */
357         private static final double ALPHA_DOT = 0.0031;
358 
359         /** Constant term of the declination of the pole. */
360         private static final double DELTA_0 = 66.5392;
361 
362         /** Rate term of the declination of the pole. */
363         private static final double DELTA_DOT =  0.0130;
364 
365         /** Constant term of the prime meridian. */
366         private static final double W_0 = 38.3213;
367 
368         /** Rate term of the prime meridian. */
369         private static final double W_DOT = 13.17635815;
370 
371         /** Rate term of the prime meridian. */
372         private static final double W_DOT_DOT = -1.4e-12;
373 
374         /** Constant term of the E1 angle. */
375         private static final double E01_0    = 125.045;
376 
377         /** Rate term of the E1 angle. */
378         private static final double E01_DOT  =  -0.0529921;
379 
380         /** Sine coefficient of the E1 angle. */
381         private static final double E01_SIN  = -3.8787;
382 
383         /** Cosine coefficient of the E1 angle. */
384         private static final double E01_COS  =  1.5419;
385 
386         /** Sine coefficient of the E1 angle, for the prime meridian. */
387         private static final double E01_W_SIN =  3.5610;
388 
389         /** Constant term of the E2 angle. */
390         private static final double E02_0    = 250.089;
391 
392         /** Rate term of the E2 angle. */
393         private static final double E02_DOT  =  -0.1059842;
394 
395         /** Sine coefficient of the E2 angle. */
396         private static final double E02_SIN  = -0.1204;
397 
398         /** Cosine coefficient of the E2 angle. */
399         private static final double E02_COS  =  0.0239;
400 
401         /** Sine coefficient of the E2 angle, for the prime meridian. */
402         private static final double E02_W_SIN =  0.1208;
403 
404         /** Constant term of the E3 angle. */
405         private static final double E03_0    = 260.008;
406 
407         /** Rate term of the E3 angle. */
408         private static final double E03_DOT  =  13.0120009;
409 
410         /** Sine coefficient of the E3 angle. */
411         private static final double E03_SIN  =  0.0700;
412 
413         /** Cosine coefficient of the E3 angle. */
414         private static final double E03_COS  = -0.0278;
415 
416         /** Sine coefficient of the E3 angle, for the prime meridian. */
417         private static final double E03_W_SIN = -0.0642;
418 
419         /** Constant term of the E4 angle. */
420         private static final double E04_0    = 176.625;
421 
422         /** Rate term of the E4 angle. */
423         private static final double E04_DOT  =  13.3407154;
424 
425         /** Sine coefficient of the E4 angle. */
426         private static final double E04_SIN  = -0.0172;
427 
428         /** Cosine coefficient of the E4 angle. */
429         private static final double E04_COS  =  0.0068;
430 
431         /** Sine coefficient of the E4 angle, for the prime meridian. */
432         private static final double E04_W_SIN =  0.0158;
433 
434         /** Constant term of the E5 angle. */
435         private static final double E05_0    = 357.529;
436 
437         /** Rate term of the E5 angle. */
438         private static final double E05_DOT  =   0.9856003;
439 
440         /** Sine coefficient of the E5 angle, for the prime meridian. */
441         private static final double E05_W_SIN =  0.0252;
442 
443         /** Constant term of the E6 angle. */
444         private static final double E06_0    = 311.589;
445 
446         /** Rate term of the E6 angle. */
447         private static final double E06_DOT  =  26.4057084;
448 
449         /** Sine coefficient of the E6 angle. */
450         private static final double E06_SIN  = 0.0072;
451 
452         /** Cosine coefficient of the E6 angle. */
453         private static final double E06_COS  = -0.0029;
454 
455         /** Sine coefficient of the E6 angle, for the prime meridian. */
456         private static final double E06_W_SIN = -0.0066;
457 
458         /** Constant term of the E7 angle. */
459         private static final double E07_0    = 134.963;
460 
461         /** Rate term of the E7 angle. */
462         private static final double E07_DOT  =  13.0649930;
463 
464         /** Cosine coefficient of the E7 angle. */
465         private static final double E07_COS  =  0.0009;
466 
467         /** Sine coefficient of the E7 angle, for the prime meridian. */
468         private static final double E07_W_SIN = -0.0047;
469 
470         /** Constant term of the E8 angle. */
471         private static final double E08_0    = 276.617;
472 
473         /** Rate term of the E8 angle. */
474         private static final double E08_DOT  =   0.3287146;
475 
476         /** Sine coefficient of the E8 angle, for the prime meridian. */
477         private static final double E08_W_SIN = -0.0046;
478 
479         /** Constant term of the E9 angle. */
480         private static final double E09_0    =  34.226;
481 
482         /** Rate term of the E9 angle. */
483         private static final double E09_DOT  =   1.7484877;
484 
485         /** Sine coefficient of the E9 angle, for the prime meridian. */
486         private static final double E09_W_SIN =  0.0028;
487 
488         /** Constant term of the E10 angle. */
489         private static final double E10_0    =  15.134;
490 
491         /** Rate term of the E10 angle. */
492         private static final double E10_DOT  =  -0.1589763;
493 
494         /** Sine coefficient of the E10 angle. */
495         private static final double E10_SIN  = -0.0052;
496 
497         /** Cosine coefficient of the E10 angle. */
498         private static final double E10_COS  = 0.0008;
499 
500         /** Sine coefficient of the E10 angle, for the prime meridian. */
501         private static final double E10_W_SIN =  0.0052;
502 
503         /** Constant term of the E11 angle. */
504         private static final double E11_0    = 119.743;
505 
506         /** Rate term of the E11 angle. */
507         private static final double E11_DOT  =   0.0036096;
508 
509         /** Sine coefficient of the E11 angle, for the prime meridian. */
510         private static final double E11_W_SIN =  0.0040;
511 
512         /** Constant term of the E12 angle. */
513         private static final double E12_0    = 239.961;
514 
515         /** Rate term of the E12 angle. */
516         private static final double E12_DOT  =   0.1643573;
517 
518         /** Sine coefficient of the E12 angle, for the prime meridian. */
519         private static final double E12_W_SIN =  0.0019;
520 
521         /** Constant term of the E13 angle. */
522         private static final double E13_0    =  25.053;
523 
524         /** Rate term of the E13 angle. */
525         private static final double E13_DOT  =  12.9590088;
526 
527         /** Sine coefficient of the E13 angle. */
528         private static final double E13_SIN  = 0.0043;
529 
530         /** Cosine coefficient of the E13 angle. */
531         private static final double E13_COS  = -0.0009;
532 
533         /** Sine coefficient of the E13 angle, for the prime meridian. */
534         private static final double E13_W_SIN = -0.0044;
535 
536         /**
537          * Simple constructor.
538          *
539          * @param timeScales to use when computing the pole, including TDB and J2000.0.
540          */
541         Moon(final TimeScales timeScales) {
542             super(timeScales);
543         }
544 
545         /** {@inheritDoc} */
546         public Vector3D getPole(final AbsoluteDate date) {
547             final double d = d(date);
548             final double t = t(date);
549 
550             final SinCos scE01 = FastMath.sinCos(FastMath.toRadians(d * E01_DOT + E01_0));
551             final SinCos scE02 = FastMath.sinCos(FastMath.toRadians(d * E02_DOT + E02_0));
552             final SinCos scE03 = FastMath.sinCos(FastMath.toRadians(d * E03_DOT + E03_0));
553             final SinCos scE04 = FastMath.sinCos(FastMath.toRadians(d * E04_DOT + E04_0));
554             final SinCos scE06 = FastMath.sinCos(FastMath.toRadians(d * E06_DOT + E06_0));
555             final SinCos scE10 = FastMath.sinCos(FastMath.toRadians(d * E10_DOT + E10_0));
556             final SinCos scE13 = FastMath.sinCos(FastMath.toRadians(d * E13_DOT + E13_0));
557 
558             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0 +
559                                                    scE01.sin() * E01_SIN +
560                                                    scE02.sin() * E02_SIN +
561                                                    scE03.sin() * E03_SIN +
562                                                    scE04.sin() * E04_SIN +
563                                                    scE06.sin() * E06_SIN +
564                                                    scE10.sin() * E10_SIN +
565                                                    scE13.sin() * E13_SIN),
566                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0 +
567                                                    scE01.cos() * E01_COS +
568                                                    scE02.cos() * E02_COS +
569                                                    scE03.cos() * E03_COS +
570                                                    scE04.cos() * E04_COS +
571                                                    scE06.cos() * E06_COS +
572                                                    FastMath.cos(FastMath.toRadians(d * E07_DOT + E07_0)) * E07_COS +  // only the cosine is needed
573                                                    scE10.cos() * E10_COS +
574                                                    scE13.cos() * E13_COS));
575         }
576 
577         /** {@inheritDoc} */
578         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
579             final T d = d(date);
580             final T t = t(date);
581 
582             final FieldSinCos<T> scE01 = FastMath.sinCos(FastMath.toRadians(d.multiply(E01_DOT).add(E01_0)));
583             final FieldSinCos<T> scE02 = FastMath.sinCos(FastMath.toRadians(d.multiply(E02_DOT).add(E02_0)));
584             final FieldSinCos<T> scE03 = FastMath.sinCos(FastMath.toRadians(d.multiply(E03_DOT).add(E03_0)));
585             final FieldSinCos<T> scE04 = FastMath.sinCos(FastMath.toRadians(d.multiply(E04_DOT).add(E04_0)));
586             final FieldSinCos<T> scE06 = FastMath.sinCos(FastMath.toRadians(d.multiply(E06_DOT).add(E06_0)));
587             final FieldSinCos<T> scE10 = FastMath.sinCos(FastMath.toRadians(d.multiply(E10_DOT).add(E10_0)));
588             final FieldSinCos<T> scE13 = FastMath.sinCos(FastMath.toRadians(d.multiply(E13_DOT).add(E13_0)));
589 
590             return new FieldVector3D<>(FastMath.toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0).
591                                                  add(scE01.sin().multiply(E01_SIN)).
592                                                  add(scE02.sin().multiply(E02_SIN)).
593                                                  add(scE03.sin().multiply(E03_SIN)).
594                                                  add(scE04.sin().multiply(E04_SIN)).
595                                                  add(scE06.sin().multiply(E06_SIN)).
596                                                  add(scE10.sin().multiply(E10_SIN)).
597                                                  add(scE13.sin().multiply(E13_SIN))),
598                                        FastMath.toRadians(t.multiply(DELTA_DOT).add(DELTA_0).
599                                                  add(scE01.cos().multiply(E01_COS)).
600                                                  add(scE02.cos().multiply(E02_COS)).
601                                                  add(scE03.cos().multiply(E03_COS)).
602                                                  add(scE04.cos().multiply(E04_COS)).
603                                                  add(scE06.cos().multiply(E06_COS)).
604                                                  add(FastMath.toRadians(d.multiply(E07_DOT).add(E07_0)).cos().multiply(E07_COS)).// only the cosine is needed
605                                                  add(scE10.cos().multiply(E10_COS)).
606                                                  add(scE13.cos().multiply(E13_COS))));
607         }
608 
609         /** {@inheritDoc} */
610         public double getPrimeMeridianAngle(final AbsoluteDate date) {
611             final double d = d(date);
612 
613             return FastMath.toRadians(d * (d * W_DOT_DOT + W_DOT) + W_0 +
614                                       FastMath.sin(FastMath.toRadians(d * E01_DOT + E01_0)) * E01_W_SIN +
615                                       FastMath.sin(FastMath.toRadians(d * E02_DOT + E02_0)) * E02_W_SIN +
616                                       FastMath.sin(FastMath.toRadians(d * E03_DOT + E03_0)) * E03_W_SIN +
617                                       FastMath.sin(FastMath.toRadians(d * E04_DOT + E04_0)) * E04_W_SIN +
618                                       FastMath.sin(FastMath.toRadians(d * E05_DOT + E05_0)) * E05_W_SIN +
619                                       FastMath.sin(FastMath.toRadians(d * E06_DOT + E06_0)) * E06_W_SIN +
620                                       FastMath.sin(FastMath.toRadians(d * E07_DOT + E07_0)) * E07_W_SIN +
621                                       FastMath.sin(FastMath.toRadians(d * E08_DOT + E08_0)) * E08_W_SIN +
622                                       FastMath.sin(FastMath.toRadians(d * E09_DOT + E09_0)) * E09_W_SIN +
623                                       FastMath.sin(FastMath.toRadians(d * E10_DOT + E10_0)) * E10_W_SIN +
624                                       FastMath.sin(FastMath.toRadians(d * E11_DOT + E11_0)) * E11_W_SIN +
625                                       FastMath.sin(FastMath.toRadians(d * E12_DOT + E12_0)) * E12_W_SIN +
626                                       FastMath.sin(FastMath.toRadians(d * E13_DOT + E13_0)) * E13_W_SIN);
627         }
628 
629         /** {@inheritDoc} */
630         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
631             final T d = d(date);
632             return FastMath.toRadians(d.multiply(d.multiply(W_DOT_DOT).add(W_DOT)).add(W_0).
633                                       add(FastMath.toRadians(d.multiply(E01_DOT).add(E01_0)).sin().multiply(E01_W_SIN)).
634                                       add(FastMath.toRadians(d.multiply(E02_DOT).add(E02_0)).sin().multiply(E02_W_SIN)).
635                                       add(FastMath.toRadians(d.multiply(E03_DOT).add(E03_0)).sin().multiply(E03_W_SIN)).
636                                       add(FastMath.toRadians(d.multiply(E04_DOT).add(E04_0)).sin().multiply(E04_W_SIN)).
637                                       add(FastMath.toRadians(d.multiply(E05_DOT).add(E05_0)).sin().multiply(E05_W_SIN)).
638                                       add(FastMath.toRadians(d.multiply(E06_DOT).add(E06_0)).sin().multiply(E06_W_SIN)).
639                                       add(FastMath.toRadians(d.multiply(E07_DOT).add(E07_0)).sin().multiply(E07_W_SIN)).
640                                       add(FastMath.toRadians(d.multiply(E08_DOT).add(E08_0)).sin().multiply(E08_W_SIN)).
641                                       add(FastMath.toRadians(d.multiply(E09_DOT).add(E09_0)).sin().multiply(E09_W_SIN)).
642                                       add(FastMath.toRadians(d.multiply(E10_DOT).add(E10_0)).sin().multiply(E10_W_SIN)).
643                                       add(FastMath.toRadians(d.multiply(E11_DOT).add(E11_0)).sin().multiply(E11_W_SIN)).
644                                       add(FastMath.toRadians(d.multiply(E12_DOT).add(E12_0)).sin().multiply(E12_W_SIN)).
645                                       add(FastMath.toRadians(d.multiply(E13_DOT).add(E13_0)).sin().multiply(E13_W_SIN)));
646         }
647 
648     }
649 
650     /** IAU pole and prime meridian model for Mars. */
651     private static class Mars extends PredefinedIAUPoles {
652 
653         /** Serializable UID. */
654         private static final long serialVersionUID = 20200130L;
655 
656         /** Constant term of the right ascension of the pole. */
657         private static final double ALPHA_0 = 317.68143;
658 
659         /** Rate term of the right ascension of the pole. */
660         private static final double ALPHA_DOT = -0.1061;
661 
662         /** Constant term of the declination of the pole. */
663         private static final double DELTA_0 =  52.88650;
664 
665         /** Rate term of the declination of the pole. */
666         private static final double DELTA_DOT = -0.0609;
667 
668         /** Constant term of the prime meridian. */
669         private static final double W_0 = 176.630;
670 
671         /** Rate term of the prime meridian. */
672         private static final double W_DOT = 350.89198226;
673 
674         /**
675          * Simple constructor.
676          *
677          * @param timeScales to use when computing the pole, including TDB and J2000.0.
678          */
679         Mars(final TimeScales timeScales) {
680             super(timeScales);
681         }
682 
683         /** {@inheritDoc} */
684         public Vector3D getPole(final AbsoluteDate date) {
685             final double t = t(date);
686             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
687                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
688         }
689 
690         /** {@inheritDoc} */
691         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
692             final T t = t(date);
693             return new FieldVector3D<>(FastMath.toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
694                                        FastMath.toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
695         }
696 
697         /** {@inheritDoc} */
698         public double getPrimeMeridianAngle(final AbsoluteDate date) {
699             return FastMath.toRadians(d(date) * W_DOT + W_0);
700         }
701 
702         /** {@inheritDoc} */
703         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
704             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0));
705         }
706 
707     }
708 
709     /** IAU pole and prime meridian model for Jupiter. */
710     private static class Jupiter extends PredefinedIAUPoles {
711 
712         /** Serializable UID. */
713         private static final long serialVersionUID = 20200130L;
714 
715         /** Constant term of the right ascension of the pole. */
716         private static final double ALPHA_0 = 268.056595;
717 
718         /** Rate term of the right ascension of the pole. */
719         private static final double ALPHA_DOT = -0.006499;
720 
721         /** Constant term of the declination of the pole. */
722         private static final double DELTA_0 = 64.495303;
723 
724         /** Rate term of the declination of the pole. */
725         private static final double DELTA_DOT = 0.002413;
726 
727         /** Constant term of the ja angle. */
728         private static final double JA_0 =  99.360714;
729 
730         /** Rate term of the ja angle. */
731         private static final double JA_DOT = 4850.4046;
732 
733         /** Sine coefficient of the ja angle. */
734         private static final double JA_SIN = 0.000117;
735 
736         /** Cosine coefficient of the ja angle. */
737         private static final double JA_COS = 0.000050;
738 
739         /** Constant term of the jb angle. */
740         private static final double JB_0 = 175.895369;
741 
742         /** Rate term of the jb angle. */
743         private static final double JB_DOT = 1191.9605;
744 
745         /** Sine coefficient of the jb angle. */
746         private static final double JB_SIN = 0.000938;
747 
748         /** Cosine coefficient of the jb angle. */
749         private static final double JB_COS = 0.000404;
750 
751         /** Constant term of the jc angle. */
752         private static final double JC_0 = 300.323162;
753 
754         /** Rate term of the jc angle. */
755         private static final double JC_DOT = 262.5475;
756 
757         /** Sine coefficient of the jc angle. */
758         private static final double JC_SIN = 0.001432;
759 
760         /** Cosine coefficient of the jc angle. */
761         private static final double JC_COS = 0.000617;
762 
763         /** Constant term of the jd angle. */
764         private static final double JD_0 = 114.012305;
765 
766         /** Rate term of the jd angle. */
767         private static final double JD_DOT = 6070.2476;
768 
769         /** Sine coefficient of the jd angle. */
770         private static final double JD_SIN = 0.000030;
771 
772         /** Cosine coefficient of the jd angle. */
773         private static final double JD_COS = -0.000013;
774 
775         /** Constant term of the je angle. */
776         private static final double JE_0 = 49.511251;
777 
778         /** Rate term of the je angle. */
779         private static final double JE_DOT = 64.3000;
780 
781         /** Sine coefficient of the je angle. */
782         private static final double JE_SIN = 0.002150;
783 
784         /** Cosine coefficient of the je angle. */
785         private static final double JE_COS = 0.000926;
786 
787         /** Constant term of the prime meridian. */
788         private static final double W_0 = 284.95;
789 
790         /** Rate term of the prime meridian. */
791         private static final double W_DOT = 870.5360000;
792 
793         /**
794          * Simple constructor.
795          *
796          * @param timeScales to use when computing the pole, including TDB and J2000.0.
797          */
798         Jupiter(final TimeScales timeScales) {
799             super(timeScales);
800         }
801 
802         /** {@inheritDoc} */
803         public Vector3D getPole(final AbsoluteDate date) {
804 
805             final double t = t(date);
806             final double ja = FastMath.toRadians(t * JA_DOT + JA_0);
807             final double jb = FastMath.toRadians(t * JB_DOT + JB_0);
808             final double jc = FastMath.toRadians(t * JC_DOT + JC_0);
809             final double jd = FastMath.toRadians(t * JD_DOT + JD_0);
810             final double je = FastMath.toRadians(t * JE_DOT + JE_0);
811 
812             final SinCos scJa = FastMath.sinCos(ja);
813             final SinCos scJb = FastMath.sinCos(jb);
814             final SinCos scJc = FastMath.sinCos(jc);
815             final SinCos scJd = FastMath.sinCos(jd);
816             final SinCos scJe = FastMath.sinCos(je);
817 
818             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0 +
819                                                    scJa.sin() * JA_SIN +
820                                                    scJb.sin() * JB_SIN +
821                                                    scJc.sin() * JC_SIN +
822                                                    scJd.sin() * JD_SIN +
823                                                    scJe.sin() * JE_SIN),
824                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0 +
825                                                    scJa.cos() * JA_COS +
826                                                    scJb.cos() * JB_COS +
827                                                    scJc.cos() * JC_COS +
828                                                    scJd.cos() * JD_COS +
829                                                    scJe.cos() * JE_COS));
830         }
831 
832         /** {@inheritDoc} */
833         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
834 
835             final T t = t(date);
836             final T ja = FastMath.toRadians(t.multiply(JA_DOT).add(JA_0));
837             final T jb = FastMath.toRadians(t.multiply(JB_DOT).add(JB_0));
838             final T jc = FastMath.toRadians(t.multiply(JC_DOT).add(JC_0));
839             final T jd = FastMath.toRadians(t.multiply(JD_DOT).add(JD_0));
840             final T je = FastMath.toRadians(t.multiply(JE_DOT).add(JE_0));
841 
842             final FieldSinCos<T> scJa = FastMath.sinCos(ja);
843             final FieldSinCos<T> scJb = FastMath.sinCos(jb);
844             final FieldSinCos<T> scJc = FastMath.sinCos(jc);
845             final FieldSinCos<T> scJd = FastMath.sinCos(jd);
846             final FieldSinCos<T> scJe = FastMath.sinCos(je);
847 
848             return new FieldVector3D<>(FastMath.toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0).
849                                                  add(scJa.sin().multiply(JA_SIN)).
850                                                  add(scJb.sin().multiply(JB_SIN)).
851                                                  add(scJc.sin().multiply(JC_SIN)).
852                                                  add(scJd.sin().multiply(JD_SIN)).
853                                                  add(scJe.sin().multiply(JE_SIN))),
854                                        FastMath.toRadians(t.multiply(DELTA_DOT).add(DELTA_0).
855                                                  add(scJa.cos().multiply(JA_COS)).
856                                                  add(scJb.cos().multiply(JB_COS)).
857                                                  add(scJc.cos().multiply(JC_COS)).
858                                                  add(scJd.cos().multiply(JD_COS)).
859                                                  add(scJe.cos().multiply(JE_COS))));
860 
861         }
862 
863         /** {@inheritDoc} */
864         public double getPrimeMeridianAngle(final AbsoluteDate date) {
865             return FastMath.toRadians(d(date) * W_DOT + W_0);
866         }
867 
868         /** {@inheritDoc} */
869         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
870             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0));
871         }
872 
873     }
874 
875     /** IAU pole and prime meridian model for Saturn. */
876     private static class Saturn extends PredefinedIAUPoles {
877 
878         /** Serializable UID. */
879         private static final long serialVersionUID = 20200130L;
880 
881         /** Constant term of the right ascension of the pole. */
882         private static final double ALPHA_0 = 40.589;
883 
884         /** Rate term of the right ascension of the pole. */
885         private static final double ALPHA_DOT = -0.036;
886 
887         /** Constant term of the declination of the pole. */
888         private static final double DELTA_0 = 83.537;
889 
890         /** Rate term of the declination of the pole. */
891         private static final double DELTA_DOT = -0.004;
892 
893         /** Constant term of the prime meridian. */
894         private static final double W_0 = 38.90;
895 
896         /** Rate term of the prime meridian. */
897         private static final double W_DOT = 810.7939024;
898 
899         /**
900          * Simple constructor.
901          *
902          * @param timeScales to use when computing the pole, including TDB and J2000.0.
903          */
904         Saturn(final TimeScales timeScales) {
905             super(timeScales);
906         }
907 
908         /** {@inheritDoc} */
909         public Vector3D getPole(final AbsoluteDate date) {
910             final double t = t(date);
911             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
912                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
913         }
914 
915         /** {@inheritDoc} */
916         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
917             final T t = t(date);
918             return new FieldVector3D<>(FastMath.toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
919                                        FastMath.toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
920         }
921 
922         /** {@inheritDoc} */
923         public double getPrimeMeridianAngle(final AbsoluteDate date) {
924             return FastMath.toRadians(d(date) * W_DOT + W_0);
925         }
926 
927         /** {@inheritDoc} */
928         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
929             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0));
930         }
931 
932     }
933 
934     /** IAU pole and prime meridian model for Uranus. */
935     private static class Uranus extends PredefinedIAUPoles {
936 
937         /** Serializable UID. */
938         private static final long serialVersionUID = 20200130L;
939 
940         /** Constant term of the prime meridian. */
941         private static final double W_0 = 203.81;
942 
943         /** Rate term of the prime meridian. */
944         private static final double W_DOT = -501.1600928;
945 
946         /** Fixed pole. */
947         private final Vector3D pole = new Vector3D(FastMath.toRadians(257.311),
948                                                    FastMath.toRadians(-15.175));
949 
950         /**
951          * Simple constructor.
952          *
953          * @param timeScales to use when computing the pole, including TDB and J2000.0.
954          */
955         Uranus(final TimeScales timeScales) {
956             super(timeScales);
957         }
958 
959         /** {@inheritDoc} */
960         public Vector3D getPole(final AbsoluteDate date) {
961             return pole;
962         }
963 
964         /** {@inheritDoc} */
965         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
966             return new FieldVector3D<>(date.getField(), pole);
967         }
968 
969         /** {@inheritDoc} */
970         public double getPrimeMeridianAngle(final AbsoluteDate date) {
971             return FastMath.toRadians(d(date) * W_DOT + W_0);
972         }
973 
974         /** {@inheritDoc} */
975         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
976             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0));
977         }
978 
979     }
980 
981     /** IAU pole and prime meridian model for Neptune. */
982     private static class Neptune extends PredefinedIAUPoles {
983 
984         /** Serializable UID. */
985         private static final long serialVersionUID = 20200130L;
986 
987         /** Constant term of the right ascension of the pole. */
988         private static final double ALPHA_0 = 299.36;
989 
990         /** Sine term of the right ascension of the pole. */
991         private static final double ALPHA_SIN = 0.70;
992 
993         /** Constant term of the declination of the pole. */
994         private static final double DELTA_0 = 43.46;
995 
996         /** Cosine term of the declination of the pole. */
997         private static final double DELTA_COS = -0.51;
998 
999         /** Constant term of the prime meridian. */
1000         private static final double W_0 = 253.18;
1001 
1002         /** Rate term of the prime meridian. */
1003         private static final double W_DOT = 536.3128492;
1004 
1005         /** Sine term of the prime meridian. */
1006         private static final double W_SIN = -0.48;
1007 
1008         /** Constant term of the N angle. */
1009         private static final double N_0   = 357.85;
1010 
1011         /** Rate term of the M1 angle. */
1012         private static final double N_DOT = 52.316;
1013 
1014         /**
1015          * Simple constructor.
1016          *
1017          * @param timeScales to use when computing the pole, including TDB and J2000.0.
1018          */
1019         Neptune(final TimeScales timeScales) {
1020             super(timeScales);
1021         }
1022 
1023         /** {@inheritDoc} */
1024         public Vector3D getPole(final AbsoluteDate date) {
1025             final double n  = FastMath.toRadians(t(date) * N_DOT + N_0);
1026             final SinCos sc = FastMath.sinCos(n);
1027             return new Vector3D(FastMath.toRadians(sc.sin() * ALPHA_SIN + ALPHA_0),
1028                                 FastMath.toRadians(sc.cos() * DELTA_COS + DELTA_0));
1029         }
1030 
1031         /** {@inheritDoc} */
1032         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
1033             final T n = FastMath.toRadians(t(date).multiply(N_DOT).add(N_0));
1034             final FieldSinCos<T> sc = FastMath.sinCos(n);
1035             return new FieldVector3D<>(FastMath.toRadians(sc.sin().multiply(ALPHA_SIN).add(ALPHA_0)),
1036                                        FastMath.toRadians(sc.cos().multiply(DELTA_COS).add(DELTA_0)));
1037         }
1038 
1039         /** {@inheritDoc} */
1040         public double getPrimeMeridianAngle(final AbsoluteDate date) {
1041             final double n = FastMath.toRadians(t(date) * N_DOT + N_0);
1042             return FastMath.toRadians(d(date) * W_DOT + FastMath.sin(n) * W_SIN + W_0);
1043         }
1044 
1045         /** {@inheritDoc} */
1046         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
1047             final T n = FastMath.toRadians(t(date).multiply(N_DOT).add(N_0));
1048             return FastMath.toRadians(d(date).multiply(W_DOT).add(n.sin().multiply(W_SIN)).add(W_0));
1049         }
1050 
1051     }
1052 
1053     /** IAU pole and prime meridian model for Pluto. */
1054     private static class Pluto extends PredefinedIAUPoles {
1055 
1056         /** Serializable UID. */
1057         private static final long serialVersionUID = 20200130L;
1058 
1059         /** Constant term of the prime meridian. */
1060         private static final double W_0 = 302.695;
1061 
1062         /** Rate term of the prime meridian. */
1063         private static final double W_DOT = 56.3625225;
1064 
1065         /** Fixed pole. */
1066         private final Vector3D pole = new Vector3D(FastMath.toRadians(132.993),
1067                                                    FastMath.toRadians(-6.163));
1068 
1069         /**
1070          * Simple constructor.
1071          *
1072          * @param timeScales to use when computing the pole, including TDB and J2000.0.
1073          */
1074         Pluto(final TimeScales timeScales) {
1075             super(timeScales);
1076         }
1077 
1078         /** {@inheritDoc} */
1079         public Vector3D getPole(final AbsoluteDate date) {
1080             return pole;
1081         }
1082 
1083         /** {@inheritDoc} */
1084         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
1085             return new FieldVector3D<>(date.getField(), pole);
1086         }
1087 
1088         /** {@inheritDoc} */
1089         public double getPrimeMeridianAngle(final AbsoluteDate date) {
1090             return FastMath.toRadians(d(date) * W_DOT + W_0);
1091         }
1092 
1093         /** {@inheritDoc} */
1094         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
1095             return FastMath.toRadians(d(date).multiply(W_DOT).add(W_0));
1096         }
1097 
1098     }
1099 
1100     /** Default IAUPole implementation for barycenters.
1101      * <p>
1102      * This implementation defines directions such that the inertially oriented and body
1103      * oriented frames are identical and aligned with GCRF. It is used for example
1104      * to define the ICRF.
1105      * </p>
1106      */
1107     private static class GcrfAligned extends PredefinedIAUPoles {
1108 
1109         /** Serializable UID. */
1110         private static final long serialVersionUID = 20200130L;
1111 
1112         /**
1113          * Simple constructor.
1114          *
1115          * @param timeScales to use when computing the pole, including TDB and J2000.0.
1116          */
1117         GcrfAligned(final TimeScales timeScales) {
1118             super(timeScales);
1119         }
1120 
1121         /** {@inheritDoc} */
1122         public Vector3D getPole(final AbsoluteDate date) {
1123             return Vector3D.PLUS_K;
1124         }
1125 
1126         /** {@inheritDoc} */
1127         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
1128             return FieldVector3D.getPlusK(date.getField());
1129         }
1130 
1131         /** {@inheritDoc} */
1132         @Override
1133         public Vector3D getNode(final AbsoluteDate date) {
1134             return Vector3D.PLUS_I;
1135         }
1136 
1137         /** {@inheritDoc} */
1138         @Override
1139         public <T extends CalculusFieldElement<T>> FieldVector3D<T> getNode(final FieldAbsoluteDate<T> date) {
1140             return FieldVector3D.getPlusI(date.getField());
1141         }
1142 
1143         /** {@inheritDoc} */
1144         public double getPrimeMeridianAngle(final AbsoluteDate date) {
1145             return 0;
1146         }
1147 
1148         /** {@inheritDoc} */
1149         public <T extends CalculusFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
1150             return date.getField().getZero();
1151         }
1152 
1153     }
1154 
1155 
1156     /** Get a predefined IAU pole.
1157      * @param body body identifier
1158      * @param timeScales to use when computing the pole, including TDB and J2000.0.
1159      * @return predefined IAU pole
1160      */
1161     public static PredefinedIAUPoles getIAUPole(final EphemerisType body,
1162                                                 final TimeScales timeScales) {
1163 
1164         switch (body) {
1165             case SUN :
1166                 return new Sun(timeScales);
1167             case MERCURY :
1168                 return new Mercury(timeScales);
1169             case VENUS :
1170                 return new Venus(timeScales);
1171             case EARTH :
1172                 return new Earth(timeScales);
1173             case MOON :
1174                 return new Moon(timeScales);
1175             case MARS :
1176                 return new Mars(timeScales);
1177             case JUPITER :
1178                 return new Jupiter(timeScales);
1179             case SATURN :
1180                 return new Saturn(timeScales);
1181             case URANUS :
1182                 return new Uranus(timeScales);
1183             case NEPTUNE :
1184                 return new Neptune(timeScales);
1185             case PLUTO :
1186                 return new Pluto(timeScales);
1187             default :
1188                 return new GcrfAligned(timeScales);
1189         }
1190     }
1191 
1192     /**
1193      * List of predefined IAU poles.
1194      *
1195      * @param timeScales to use when computing the pole, including TDB and J2000.0.
1196      * @return the poles.
1197      */
1198     static List<PredefinedIAUPoles> values(final TimeScales timeScales) {
1199         final List<PredefinedIAUPoles> values = new ArrayList<>(12);
1200         values.add(new Sun(timeScales));
1201         values.add(new Mercury(timeScales));
1202         values.add(new Venus(timeScales));
1203         values.add(new Earth(timeScales));
1204         values.add(new Moon(timeScales));
1205         values.add(new Mars(timeScales));
1206         values.add(new Jupiter(timeScales));
1207         values.add(new Saturn(timeScales));
1208         values.add(new Uranus(timeScales));
1209         values.add(new Neptune(timeScales));
1210         values.add(new Pluto(timeScales));
1211         values.add(new GcrfAligned(timeScales));
1212         return values;
1213     }
1214 
1215     /** Compute the interval in julian centuries from standard epoch.
1216      * @param date date
1217      * @return interval between date and standard epoch in julian centuries
1218      */
1219     protected double t(final AbsoluteDate date) {
1220         return date.offsetFrom(timeScales.getJ2000Epoch(), timeScales.getTDB()) /
1221                 Constants.JULIAN_CENTURY;
1222     }
1223 
1224     /** Compute the interval in julian centuries from standard epoch.
1225      * @param date date
1226      * @param <T> type of the filed elements
1227      * @return interval between date and standard epoch in julian centuries
1228      */
1229     protected <T extends CalculusFieldElement<T>> T t(final FieldAbsoluteDate<T> date) {
1230         final FieldAbsoluteDate<T> j2000Epoch =
1231                 new FieldAbsoluteDate<>(date.getField(), timeScales.getJ2000Epoch());
1232         return date.offsetFrom(j2000Epoch, timeScales.getTDB()).divide(Constants.JULIAN_CENTURY);
1233     }
1234 
1235     /** Compute the interval in julian days from standard epoch.
1236      * @param date date
1237      * @return interval between date and standard epoch in julian days
1238      */
1239     protected double d(final AbsoluteDate date) {
1240         return date.offsetFrom(timeScales.getJ2000Epoch(), timeScales.getTDB()) /
1241                 Constants.JULIAN_DAY;
1242     }
1243 
1244     /** Compute the interval in julian days from standard epoch.
1245      * @param date date
1246      * @param <T> type of the filed elements
1247      * @return interval between date and standard epoch in julian days
1248      */
1249     protected <T extends CalculusFieldElement<T>> T d(final FieldAbsoluteDate<T> date) {
1250         final FieldAbsoluteDate<T> j2000Epoch =
1251                 new FieldAbsoluteDate<>(date.getField(), timeScales.getJ2000Epoch());
1252         return date.offsetFrom(j2000Epoch, timeScales.getTDB()).divide(Constants.JULIAN_DAY);
1253     }
1254 
1255 }