1 // customrotation.cpp
2 //
3 // Custom rotation models for Solar System bodies.
4 //
5 // Copyright (C) 2008, the Celestia Development Team
6 // Initial version by Chris Laurel, claurel@gmail.com
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 
13 #include <map>
14 #include <string>
15 #include <celengine/customrotation.h>
16 #include <celengine/rotation.h>
17 #include <celengine/astro.h>
18 #include <celengine/precession.h>
19 
20 using namespace std;
21 
22 
23 static map<string, RotationModel*> CustomRotationModels;
24 static bool CustomRotationModelsInitialized = false;
25 
26 
27 // Clamp secular terms in IAU rotation models to this number of centuries
28 // from J2000. Extrapolating much further can lead to ridiculous results,
29 // such as planets 'tipping over' Periodic terms are not clamped; their
30 // validity over long time ranges is questionable, but extrapolating them
31 // doesn't produce obviously absurd results.
32 static const double IAU_SECULAR_TERM_VALID_CENTURIES = 50.0;
33 
34 // The P03 long period precession theory for Earth is valid for a one
35 // million year time span centered on J2000. For dates outside far outside
36 // that range, the polynomial terms produce absurd results.
37 static const double P03LP_VALID_CENTURIES = 5000.0;
38 
39 /*! Base class for IAU rotation models. All IAU rotation models are in the
40  *  J2000.0 Earth equatorial frame.
41  */
42 class IAURotationModel : public CachingRotationModel
43 {
44 public:
IAURotationModel(double _period)45     IAURotationModel(double _period) :
46         period(_period), flipped(false)
47     {
48     }
49 
~IAURotationModel()50     virtual ~IAURotationModel() {}
51 
isPeriodic() const52     bool isPeriodic() const { return true; }
getPeriod() const53     double getPeriod() const { return period; }
54 
computeSpin(double t) const55     virtual Quatd computeSpin(double t) const
56     {
57         // Time argument of IAU rotation models is actually day since J2000.0 TT, but
58         // Celestia uses TDB. The difference should be so minute as to be irrelevant.
59         t = t - astro::J2000;
60         if (flipped)
61             return Quatd::yrotation( degToRad(180.0 + meridian(t)));
62         else
63             return Quatd::yrotation(-degToRad(180.0 + meridian(t)));
64     }
65 
computeEquatorOrientation(double t) const66     virtual Quatd computeEquatorOrientation(double t) const
67     {
68         double poleRA = 0.0;
69         double poleDec = 0.0;
70 
71         t = t - astro::J2000;
72         pole(t, poleRA, poleDec);
73         double node = poleRA + 90.0;
74         double inclination = 90.0 - poleDec;
75 
76         if (flipped)
77             return Quatd::xrotation(PI) * Quatd::xrotation(degToRad(-inclination)) * Quatd::yrotation(degToRad(-node));
78         else
79             return Quatd::xrotation(degToRad(-inclination)) * Quatd::yrotation(degToRad(-node));
80     }
81 
82     // Return the RA and declination (in degrees) of the rotation axis
83     virtual void pole(double t, double& ra, double& dec) const = 0;
84 
85     virtual double meridian(double t) const = 0;
86 
87 protected:
clamp_centuries(double & T)88     static void clamp_centuries(double& T)
89     {
90         if (T < -IAU_SECULAR_TERM_VALID_CENTURIES)
91             T = -IAU_SECULAR_TERM_VALID_CENTURIES;
92         else if (T > IAU_SECULAR_TERM_VALID_CENTURIES)
93             T = IAU_SECULAR_TERM_VALID_CENTURIES;
94     }
95 
setFlipped(bool _flipped)96     void setFlipped(bool _flipped)
97     {
98         flipped = _flipped;
99     }
100 
101 private:
102     double period;
103     bool flipped;
104 };
105 
106 
107 
108 /******* Earth rotation model *******/
109 
110 class EarthRotationModel : public CachingRotationModel
111 {
112 public:
EarthRotationModel()113     EarthRotationModel()
114     {
115     }
116 
~EarthRotationModel()117     ~EarthRotationModel()
118     {
119     }
120 
computeSpin(double tjd) const121     Quatd computeSpin(double tjd) const
122     {
123         // TODO: Use a more accurate model for sidereal time
124         double t = tjd - astro::J2000;
125         double theta = 2 * PI * (t * 24.0 / 23.9344694 - 259.853 / 360.0);
126 
127         return Quatd::yrotation(-theta);
128     }
129 
computeEquatorOrientation(double tjd) const130     Quatd computeEquatorOrientation(double tjd) const
131     {
132         double T = (tjd - astro::J2000) / 36525.0;
133 
134         // Clamp T to the valid time range of the precession theory.
135         if (T < -P03LP_VALID_CENTURIES)
136             T = -P03LP_VALID_CENTURIES;
137         else if (T > P03LP_VALID_CENTURIES)
138             T = P03LP_VALID_CENTURIES;
139 
140         astro::PrecessionAngles prec = astro::PrecObliquity_P03LP(T);
141         astro::EclipticPole pole = astro::EclipticPrecession_P03LP(T);
142 
143         double obliquity = degToRad(prec.epsA / 3600);
144         double precession = degToRad(prec.pA / 3600);
145 
146         // Calculate the angles pi and Pi from the ecliptic pole coordinates
147         // P and Q:
148         //   P = sin(pi)*sin(Pi)
149         //   Q = sin(pi)*cos(Pi)
150         double P = pole.PA * 2.0 * PI / 1296000;
151         double Q = pole.QA * 2.0 * PI / 1296000;
152         double piA = asin(sqrt(P * P + Q * Q));
153         double PiA = atan2(P, Q);
154 
155         // Calculate the rotation from the J2000 ecliptic to the ecliptic
156         // of date.
157         Quatd RPi = Quatd::zrotation(PiA);
158         Quatd rpi = Quatd::xrotation(piA);
159         Quatd eclRotation = ~RPi * rpi * RPi;
160 
161         Quatd q = Quatd::xrotation(obliquity) * Quatd::zrotation(-precession) * ~eclRotation;
162 
163         // convert to Celestia's coordinate system
164         return Quatd::xrotation(PI / 2.0) * q * Quatd::xrotation(-PI / 2.0);
165     }
166 
getPeriod() const167     double getPeriod() const
168     {
169         return 23.9344694 / 24.0;
170     }
171 
isPeriodic() const172     bool isPeriodic() const
173     {
174         return true;
175     }
176 };
177 
178 
179 
180 /******* IAU rotation models for the planets *******/
181 
182 
183 /*! IAUPrecessingRotationModel is a rotation model with uniform rotation about
184  *  a pole that precesses linearly in RA and declination.
185  */
186 class IAUPrecessingRotationModel : public IAURotationModel
187 {
188 public:
189 
190     /*! rotationRate is in degrees per Julian day
191      *  pole precession is in degrees per Julian century
192      */
IAUPrecessingRotationModel(double _poleRA,double _poleRARate,double _poleDec,double _poleDecRate,double _meridianAtEpoch,double _rotationRate)193     IAUPrecessingRotationModel(double _poleRA,
194                                double _poleRARate,
195                                double _poleDec,
196                                double _poleDecRate,
197                                double _meridianAtEpoch,
198                                double _rotationRate) :
199     IAURotationModel(std::abs(360.0 / _rotationRate)),
200         poleRA(_poleRA),
201         poleRARate(_poleRARate),
202         poleDec(_poleDec),
203         poleDecRate(_poleDecRate),
204         meridianAtEpoch(_meridianAtEpoch),
205         rotationRate(_rotationRate)
206     {
207         if (rotationRate < 0.0)
208             setFlipped(true);
209     }
210 
pole(double d,double & ra,double & dec) const211     void pole(double d, double& ra, double &dec) const
212     {
213         double T = d / 36525.0;
214         clamp_centuries(T);
215         ra = poleRA + poleRARate * T;
216         dec = poleDec + poleDecRate * T;
217     }
218 
meridian(double d) const219     double meridian(double d) const
220     {
221         return meridianAtEpoch + rotationRate * d;
222     }
223 
224 private:
225     double poleRA;
226     double poleRARate;
227     double poleDec;
228     double poleDecRate;
229     double meridianAtEpoch;
230     double rotationRate;
231 };
232 
233 
234 class IAUNeptuneRotationModel : public IAURotationModel
235 {
236 public:
IAUNeptuneRotationModel()237     IAUNeptuneRotationModel() : IAURotationModel(360.0 / 536.3128492) {}
238 
pole(double d,double & ra,double & dec) const239     void pole(double d, double& ra, double &dec) const
240     {
241         double T = d / 36525.0;
242         double N = degToRad(357.85 + 52.316 * T);
243         ra = 299.36 + 0.70 * sin(N);
244         dec = 43.46 - 0.51 * cos(N);
245     }
246 
meridian(double d) const247     double meridian(double d) const
248     {
249         double T = d / 36525.0;
250         double N = degToRad(357.85 + 52.316 * T);
251         return 253.18 + 536.3128492 * d - 0.48 * sin(N);
252     }
253 };
254 
255 
256 /*! IAU rotation model for the Moon.
257  *  From the IAU/IAG Working Group on Cartographic Coordinates and Rotational Elements:
258  *  http://astrogeology.usgs.gov/Projects/WGCCRE/constants/iau2000_table2.html
259  */
260 class IAULunarRotationModel : public IAURotationModel
261 {
262 public:
IAULunarRotationModel()263     IAULunarRotationModel() : IAURotationModel(360.0 / 13.17635815) {}
264 
calcArgs(double d,double E[14]) const265     void calcArgs(double d, double E[14]) const
266     {
267         E[1]  = degToRad(125.045 -  0.0529921 * d);
268         E[2]  = degToRad(250.089 -  0.1059842 * d);
269         E[3]  = degToRad(260.008 + 13.012009 * d);
270         E[4]  = degToRad(176.625 + 13.3407154 * d);
271         E[5]  = degToRad(357.529 +  0.9856993 * d);
272         E[6]  = degToRad(311.589 + 26.4057084 * d);
273         E[7]  = degToRad(134.963 + 13.0649930 * d);
274         E[8]  = degToRad(276.617 +  0.3287146 * d);
275         E[9]  = degToRad( 34.226 +  1.7484877 * d);
276         E[10] = degToRad( 15.134 -  0.1589763 * d);
277         E[11] = degToRad(119.743 +  0.0036096 * d);
278         E[12] = degToRad(239.961 +  0.1643573 * d);
279         E[13] = degToRad( 25.053 + 12.9590088 * d);
280     }
281 
pole(double d,double & ra,double & dec) const282     void pole(double d, double& ra, double& dec) const
283     {
284         double T = d / 36525.0;
285         clamp_centuries(T);
286 
287         double E[14];
288         calcArgs(d, E);
289 
290         ra = 269.9949
291             + 0.0013*T
292             - 3.8787 * sin(E[1])
293             - 0.1204 * sin(E[2])
294             + 0.0700 * sin(E[3])
295             - 0.0172 * sin(E[4])
296             + 0.0072 * sin(E[6])
297             - 0.0052 * sin(E[10])
298             + 0.0043 * sin(E[13]);
299 
300         dec = 66.5392
301             + 0.0130 * T
302             + 1.5419 * cos(E[1])
303             + 0.0239 * cos(E[2])
304             - 0.0278 * cos(E[3])
305             + 0.0068 * cos(E[4])
306             - 0.0029 * cos(E[6])
307             + 0.0009 * cos(E[7])
308             + 0.0008 * cos(E[10])
309             - 0.0009 * cos(E[13]);
310 
311 
312     }
313 
meridian(double d) const314     double meridian(double d) const
315     {
316         double E[14];
317         calcArgs(d, E);
318 
319         // d^2 represents slowing of lunar rotation as the Moon recedes
320         // from the Earth. This may need to be clamped at some very large
321         // time range (1 Gy?)
322 
323         return (38.3213
324                 + 13.17635815 * d
325                 - 1.4e-12 * d * d
326                 + 3.5610 * sin(E[1])
327                 + 0.1208 * sin(E[2])
328                 - 0.0642 * sin(E[3])
329                 + 0.0158 * sin(E[4])
330                 + 0.0252 * sin(E[5])
331                 - 0.0066 * sin(E[6])
332                 - 0.0047 * sin(E[7])
333                 - 0.0046 * sin(E[8])
334                 + 0.0028 * sin(E[9])
335                 + 0.0052 * sin(E[10])
336                 + 0.0040 * sin(E[11])
337                 + 0.0019 * sin(E[12])
338                 - 0.0044 * sin(E[13]));
339     }
340 };
341 
342 
343 // Rotations of Martian, Jovian, and Uranian satellites from IAU/IAG Working group
344 // on Cartographic Coordinates and Rotational Elements (Corrected for known errata
345 // as of 17 Feb 2006)
346 // See: http://astrogeology.usgs.gov/Projects/WGCCRE/constants/iau2000_table2.html
347 
348 class IAUPhobosRotationModel : public IAURotationModel
349 {
350 public:
IAUPhobosRotationModel()351     IAUPhobosRotationModel() : IAURotationModel(360.0 / 1128.8445850) {}
352 
pole(double t,double & ra,double & dec) const353     void pole(double t, double& ra, double& dec) const
354     {
355         double T = t / 36525.0;
356         double M1 = degToRad(169.51 - 0.04357640 * t);
357         clamp_centuries(T);
358         ra  = 317.68 - 0.108 * T + 1.79 * sin(M1);
359         dec =  52.90 - 0.061 * T - 1.08 * cos(M1);
360     }
361 
meridian(double t) const362     double meridian(double t) const
363     {
364         // Note: negative coefficient of T^2 term for meridian angle indicates faster
365         // rotation as Phobos's orbit evolves inward toward Mars
366         double T = t / 36525.0;
367         double M1 = degToRad(169.51 - 0.04357640 * t);
368         double M2 = degToRad(192.93 + 1128.4096700 * t + 8.864 * T * T);
369         return 35.06 + 1128.8445850 * t + 8.864 * T * T - 1.42 * sin(M1) - 0.78 * sin(M2);
370     }
371 };
372 
373 
374 class IAUDeimosRotationModel : public IAURotationModel
375 {
376 public:
IAUDeimosRotationModel()377     IAUDeimosRotationModel() : IAURotationModel(360.0 / 285.1618970) {}
378 
pole(double t,double & ra,double & dec) const379     void pole(double t, double& ra, double& dec) const
380     {
381         double T = t / 36525.0;
382         double M3 = degToRad(53.47 - 0.0181510 * t);
383         clamp_centuries(T);
384         ra  = 316.65 - 0.108 * T + 2.98 * sin(M3);
385         dec =  53.52 - 0.061 * T - 1.78 * cos(M3);
386     }
387 
meridian(double t) const388     double meridian(double t) const
389     {
390         // Note: positive coefficient of T^2 term for meridian angle indicates slowing
391         // rotation as Deimos's orbit evolves outward from Mars
392         double T = t / 36525.0;
393         double M3 = degToRad(53.47 - 0.0181510 * t);
394         return 79.41 + 285.1618970 * t + 0.520 * T * T - 2.58 * sin(M3) + 0.19 * cos(M3);
395     }
396 };
397 
398 
399 /****** Satellites of Jupiter ******/
400 
401 class IAUAmaltheaRotationModel : public IAURotationModel
402 {
403 public:
IAUAmaltheaRotationModel()404     IAUAmaltheaRotationModel() : IAURotationModel(360.0 / 722.6314560) {}
405 
pole(double t,double & ra,double & dec) const406     void pole(double t, double& ra, double& dec) const
407     {
408         double T = t / 36525.0;
409         double J1 = degToRad(73.32 + 91472.9 * T);
410         clamp_centuries(T);
411         ra = 268.05 - 0.009 * T - 0.84 * sin(J1) + 0.01 * sin(2.0 * J1);
412         dec = 64.49 + 0.003 * T - 0.36 * cos(J1);
413     }
414 
meridian(double t) const415     double meridian(double t) const
416     {
417         double T = t / 36525.0;
418         double J1 = degToRad(73.32 + 91472.9 * T);
419         return 231.67 + 722.6314560 * t + 0.76 * sin(J1) - 0.01 * sin(2.0 * J1);
420     }
421 };
422 
423 
424 class IAUThebeRotationModel : public IAURotationModel
425 {
426 public:
IAUThebeRotationModel()427     IAUThebeRotationModel() : IAURotationModel(360.0 / 533.7004100) {}
428 
pole(double t,double & ra,double & dec) const429     void pole(double t, double& ra, double& dec) const
430     {
431         double T = t / 36525.0;
432         double J2 = degToRad(24.62 + 45137.2 * T);
433         clamp_centuries(T);
434         ra = 268.05 - 0.009 * T - 2.11 * sin(J2) + 0.04 * sin(2.0 * J2);
435         dec = 64.49 + 0.003 * T - 0.91 * cos(J2) + 0.01 * cos(2.0 * J2);
436     }
437 
meridian(double t) const438     double meridian(double t) const
439     {
440         double T = t / 36525.0;
441         double J2 = degToRad(24.62 + 45137.2 * T);
442         return 8.56 + 533.7004100 * t + 1.91 * sin(J2) - 0.04 * sin(2.0 * J2);
443     }
444 };
445 
446 
447 class IAUIoRotationModel : public IAURotationModel
448 {
449 public:
IAUIoRotationModel()450     IAUIoRotationModel() : IAURotationModel(360.0 / 203.4889538) {}
451 
pole(double t,double & ra,double & dec) const452     void pole(double t, double& ra, double& dec) const
453     {
454         double T = t / 36525.0;
455         double J3 = degToRad(283.90 + 4850.7 * T);
456         double J4 = degToRad(355.80 + 1191.3 * T);
457         clamp_centuries(T);
458         ra = 268.05 - 0.009 * T + 0.094 * sin(J3) + 0.024 * sin(J4);
459         dec = 64.49 + 0.003 * T + 0.040 * cos(J3) + 0.011 * cos(J4);
460     }
461 
meridian(double t) const462     double meridian(double t) const
463     {
464         double T = t / 36525.0;
465         double J3 = degToRad(283.90 + 4850.7 * T);
466         double J4 = degToRad(355.80 + 1191.3 * T);
467         return 200.39 + 203.4889538 * t - 0.085 * sin(J3) - 0.022 * sin(J4);
468     }
469 };
470 
471 
472 class IAUEuropaRotationModel : public IAURotationModel
473 {
474 public:
IAUEuropaRotationModel()475     IAUEuropaRotationModel() : IAURotationModel(360.0 / 101.3747235) {}
476 
pole(double t,double & ra,double & dec) const477     void pole(double t, double& ra, double& dec) const
478     {
479         double T = t / 36525.0;
480         double J4 = degToRad(355.80 + 1191.3 * T);
481         double J5 = degToRad(119.90 + 262.1 * T);
482         double J6 = degToRad(229.80 + 64.3 * T);
483         double J7 = degToRad(352.35 + 2382.6 * T);
484         clamp_centuries(T);
485         ra = 268.05 - 0.009 * T + 1.086 * sin(J4) + 0.060 * sin(J5) + 0.015 * sin(J6) + 0.009 * sin(J7);
486         dec = 64.49 + 0.003 * T + 0.486 * cos(J4) + 0.026 * cos(J5) + 0.007 * cos(J6) + 0.002 * cos(J7);
487     }
488 
meridian(double t) const489     double meridian(double t) const
490     {
491         double T = t / 36525.0;
492         double J4 = degToRad(355.80 + 1191.3 * T);
493         double J5 = degToRad(119.90 + 262.1 * T);
494         double J6 = degToRad(229.80 + 64.3 * T);
495         double J7 = degToRad(352.35 + 2382.6 * T);
496         return 36.022 + 101.3747235 * t - 0.980 * sin(J4) - 0.054 * sin(J5) - 0.014 * sin(J6) - 0.008 * sin(J7);
497     }
498 };
499 
500 
501 class IAUGanymedeRotationModel : public IAURotationModel
502 {
503 public:
IAUGanymedeRotationModel()504     IAUGanymedeRotationModel() : IAURotationModel(360.0 / 50.3176081) {}
505 
pole(double t,double & ra,double & dec) const506     void pole(double t, double& ra, double& dec) const
507     {
508         double T = t / 36525.0;
509         double J4 = degToRad(355.80 + 1191.3 * T);
510         double J5 = degToRad(119.90 + 262.1 * T);
511         double J6 = degToRad(229.80 + 64.3 * T);
512         clamp_centuries(T);
513         ra = 268.05 - 0.009 * T - 0.037 * sin(J4) + 0.431 * sin(J5) + 0.091 * sin(J6);
514         dec = 64.49 + 0.003 * T - 0.016 * cos(J4) + 0.186 * cos(J5) + 0.039 * cos(J6);
515     }
516 
meridian(double t) const517     double meridian(double t) const
518     {
519         double T = t / 36525.0;
520         double J4 = degToRad(355.80 + 1191.3 * T);
521         double J5 = degToRad(119.90 + 262.1 * T);
522         double J6 = degToRad(229.80 + 64.3 * T);
523         return 44.064 + 50.3176081 * t + 0.033 * sin(J4) - 0.389 * sin(J5) - 0.082 * sin(J6);
524     }
525 };
526 
527 
528 class IAUCallistoRotationModel : public IAURotationModel
529 {
530 public:
IAUCallistoRotationModel()531     IAUCallistoRotationModel() : IAURotationModel(360.0 / 21.5710715) {}
532 
pole(double t,double & ra,double & dec) const533     void pole(double t, double& ra, double& dec) const
534     {
535         double T = t / 36525.0;
536         double J5 = degToRad(119.90 + 262.1 * T);
537         double J6 = degToRad(229.80 + 64.3 * T);
538         double J8 = degToRad(113.35 + 6070.0 * T);
539         clamp_centuries(T);
540         ra = 268.05 - 0.009 * T - 0.068 * sin(J5) + 0.590 * sin(J6) + 0.010 * sin(J8);
541         dec = 64.49 + 0.003 * T - 0.029 * cos(J5) + 0.254 * cos(J6) - 0.004 * cos(J8);
542     }
543 
meridian(double t) const544     double meridian(double t) const
545     {
546         double T = t / 36525.0;
547         double J5 = degToRad(119.90 + 262.1 * T);
548         double J6 = degToRad(229.80 + 64.3 * T);
549         double J8 = degToRad(113.35 + 6070.0 * T);
550         return 259.51 + 21.5710715 * t + 0.061 * sin(J5) - 0.533 * sin(J6) - 0.009 * sin(J8);
551     }
552 };
553 
554 
555 /*
556 S1 = 353.32 + 75706.7 * T
557 S2 = 28.72 + 75706.7 * T
558 S3 = 177.40 - 36505.5 * T
559 S4 = 300.00 - 7225.9 * T
560 S5 = 53.59 - 8968.6 * T
561 S6 = 143.38 - 10553.5 * T
562 S7 = 345.20 - 1016.3 * T
563 S8 = 29.80 - 52.1 * T
564 S9 = 316.45 + 506.2 * T
565 */
566 
567 // Rotations of Saturnian satellites from Seidelmann, _Explanatory Supplement to the
568 // Astronomical Almanac_ (1992).
569 
570 class IAUMimasRotationModel : public IAURotationModel
571 {
572 public:
IAUMimasRotationModel()573     IAUMimasRotationModel() : IAURotationModel(360.0 / 381.9945550) {}
574 
pole(double t,double & ra,double & dec) const575     void pole(double t, double& ra, double& dec) const
576     {
577         double T = t / 36525.0;
578         double S3 = degToRad(177.40 - 36505.5 * T);
579         clamp_centuries(T);
580         ra = 40.66 - 0.036 * T + 13.56 * sin(S3);
581         dec = 83.52 - 0.004 * T - 1.53 * cos(S3);
582     }
583 
meridian(double t) const584     double meridian(double t) const
585     {
586         double T = t / 36525.0;
587         double S3 = degToRad(177.40 - 36505.5 * T);
588         double S9 = degToRad(316.45 + 506.2 * T);
589         return 337.46 + 381.9945550 * t - 13.48 * sin(S3) - 44.85 * sin(S9);
590     }
591 };
592 
593 
594 class IAUEnceladusRotationModel : public IAURotationModel
595 {
596 public:
IAUEnceladusRotationModel()597     IAUEnceladusRotationModel() : IAURotationModel(360.0 / 262.7318996) {}
598 
pole(double t,double & ra,double & dec) const599     void pole(double t, double& ra, double& dec) const
600     {
601         double T = t / 36525.0;
602         clamp_centuries(T);
603         ra = 40.66 - 0.036 * T;
604         dec = 83.52 - 0.004 * T;
605     }
606 
meridian(double t) const607     double meridian(double t) const
608     {
609         return 2.82 + 262.7318996 * t;
610     }
611 };
612 
613 
614 class IAUTethysRotationModel : public IAURotationModel
615 {
616 public:
IAUTethysRotationModel()617     IAUTethysRotationModel() : IAURotationModel(360.0 / 190.6979085) {}
618 
pole(double t,double & ra,double & dec) const619     void pole(double t, double& ra, double& dec) const
620     {
621         double T = t / 36525.0;
622         double S4 = degToRad(300.00 - 7225.9 * T);
623         clamp_centuries(T);
624         ra = 40.66 - 0.036 * T - 9.66 * sin(S4);
625         dec = 83.52 - 0.004 * T - 1.09 * cos(S4);
626     }
627 
meridian(double t) const628     double meridian(double t) const
629     {
630         double T = t / 36525.0;
631         double S4 = degToRad(300.00 - 7225.9 * T);
632         double S9 = degToRad(316.45 + 506.2 * T);
633         return 10.45 + 190.6979085 * t - 9.60 * sin(S4) + 2.23 * sin(S9);
634     }
635 };
636 
637 
638 class IAUTelestoRotationModel : public IAURotationModel
639 {
640 public:
IAUTelestoRotationModel()641     IAUTelestoRotationModel() : IAURotationModel(360.0 / 190.6979330) {}
642 
pole(double t,double & ra,double & dec) const643     void pole(double t, double& ra, double& dec) const
644     {
645         double T = t / 36525.0;
646         clamp_centuries(T);
647         ra = 50.50 - 0.036 * T;
648         dec = 84.06 - 0.004 * T;
649     }
650 
meridian(double t) const651     double meridian(double t) const
652     {
653         return 56.88 + 190.6979330 * t;
654     }
655 };
656 
657 
658 class IAUCalypsoRotationModel : public IAURotationModel
659 {
660 public:
IAUCalypsoRotationModel()661     IAUCalypsoRotationModel() : IAURotationModel(360.0 / 190.6742373) {}
662 
pole(double t,double & ra,double & dec) const663     void pole(double t, double& ra, double& dec) const
664     {
665         double T = t / 36525.0;
666         double S5 = degToRad(53.59 - 8968.6 * T);
667         clamp_centuries(T);
668         ra = 40.58 - 0.036 * T - 13.943 * sin(S5) - 1.686 * sin(2.0 * S5);
669         dec = 83.43 - 0.004 * T - 1.572 * cos(S5) + 0.095 * cos(2.0 * S5);
670     }
671 
meridian(double t) const672     double meridian(double t) const
673     {
674         double T = t / 36525.0;
675         double S5 = degToRad(53.59 - 8968.6 * T);
676         return 149.36 + 190.6742373 * t - 13.849 * sin(S5) + 1.685 * sin(2.0 * S5);
677     }
678 };
679 
680 
681 class IAUDioneRotationModel : public IAURotationModel
682 {
683 public:
IAUDioneRotationModel()684     IAUDioneRotationModel() : IAURotationModel(360.0 / 131.5349316) {}
685 
pole(double t,double & ra,double & dec) const686     void pole(double t, double& ra, double& dec) const
687     {
688         double T = t / 36525.0;
689         clamp_centuries(T);
690         ra = 40.66 - 0.036 * T;
691         dec = 83.52 - 0.004 * T;
692     }
693 
meridian(double t) const694     double meridian(double t) const
695     {
696         return 357.00 + 131.5349316 * t;
697     }
698 };
699 
700 
701 class IAUHeleneRotationModel : public IAURotationModel
702 {
703 public:
IAUHeleneRotationModel()704     IAUHeleneRotationModel() : IAURotationModel(360.0 / 131.6174056) {}
705 
pole(double t,double & ra,double & dec) const706     void pole(double t, double& ra, double& dec) const
707     {
708         double T = t / 36525.0;
709         double S6 = degToRad(143.38 - 10553.5 * T);
710         clamp_centuries(T);
711         ra = 40.58 - 0.036 * T + 1.662 * sin(S6) + 0.024 * sin(2.0 * S6);
712         dec = 83.52 - 0.004 * T - 0.187 * cos(S6) + 0.095 * cos(2.0 * S6);
713     }
714 
meridian(double t) const715     double meridian(double t) const
716     {
717         double T = t / 36525.0;
718         double S6 = degToRad(143.38 - 10553.5 * T);
719         return 245.39 + 131.6174056 * t - 1.651 * sin(S6) + 0.024 * sin(2.0 * S6);
720     }
721 };
722 
723 
724 class IAURheaRotationModel : public IAURotationModel
725 {
726 public:
IAURheaRotationModel()727     IAURheaRotationModel() : IAURotationModel(360.0 / 79.6900478) {}
728 
pole(double t,double & ra,double & dec) const729     void pole(double t, double& ra, double& dec) const
730     {
731         double T = t / 36525.0;
732         double S7 = degToRad(345.20 - 1016.3 * T);
733         clamp_centuries(T);
734         ra = 40.38 - 0.036 * T + 3.10 * sin(S7);
735         dec = 83.55 - 0.004 * T - 0.35 * cos(S7);
736     }
737 
meridian(double t) const738     double meridian(double t) const
739     {
740         double T = t / 36525.0;
741         double S7 = degToRad(345.20 - 1016.3 * T);
742         return 235.16 + 79.6900478 * t - 1.651 - 3.08 * sin(S7);
743     }
744 };
745 
746 
747 class IAUTitanRotationModel : public IAURotationModel
748 {
749 public:
IAUTitanRotationModel()750     IAUTitanRotationModel() : IAURotationModel(360.0 / 22.5769768) {}
751 
pole(double t,double & ra,double & dec) const752     void pole(double t, double& ra, double& dec) const
753     {
754         double T = t / 36525.0;
755         double S8 = degToRad(29.80 - 52.1 * T);
756         clamp_centuries(T);
757         ra = 36.41 - 0.036 * T + 2.66 * sin(S8);
758         dec = 83.94 - 0.004 * T - 0.30 * cos(S8);
759     }
760 
meridian(double t) const761     double meridian(double t) const
762     {
763         double T = t / 36525.0;
764         double S8 = degToRad(29.80 - 52.1 * T);
765         return 189.64 + 22.5769768 * t - 2.64 * sin(S8);
766     }
767 };
768 
769 
770 class IAUIapetusRotationModel : public IAURotationModel
771 {
772 public:
IAUIapetusRotationModel()773     IAUIapetusRotationModel() : IAURotationModel(360.0 / 4.5379572) {}
774 
pole(double t,double & ra,double & dec) const775     void pole(double t, double& ra, double& dec) const
776     {
777         double T = t / 36525.0;
778         clamp_centuries(T);
779         ra = 318.16 - 3.949 * T;
780         dec = 75.03 - 1.142 * T;
781     }
782 
meridian(double t) const783     double meridian(double t) const
784     {
785         return 350.20 + 4.5379572 * t;
786     }
787 };
788 
789 
790 class IAUPhoebeRotationModel : public IAURotationModel
791 {
792 public:
IAUPhoebeRotationModel()793     IAUPhoebeRotationModel() : IAURotationModel(360.0 / 22.5769768) {}
794 
pole(double t,double & ra,double & dec) const795     void pole(double t, double& ra, double& dec) const
796     {
797         double T = t / 36525.0;
798         clamp_centuries(T);
799         ra = 355.16;
800         dec = 68.70 - 1.143 * T;
801     }
802 
meridian(double t) const803     double meridian(double t) const
804     {
805         return 304.70 + 930.8338720 * t;
806     }
807 };
808 
809 
810 class IAUMirandaRotationModel : public IAURotationModel
811 {
812 public:
IAUMirandaRotationModel()813     IAUMirandaRotationModel() : IAURotationModel(360.0 / 254.6906892) { setFlipped(true); }
814 
pole(double t,double & ra,double & dec) const815     void pole(double t, double& ra, double& dec) const
816     {
817         double T = t / 36525.0;
818         double U11 = degToRad(102.23 - 2024.22 * T);
819         ra =  257.43 + 4.41 * sin(U11) - 0.04 * sin(2.0 * U11);
820         dec = -15.08 + 4.25 * cos(U11) - 0.02 * cos(2.0 * U11);
821     }
822 
meridian(double t) const823     double meridian(double t) const
824     {
825         double T = t / 36525.0;
826         double U11 = degToRad(102.23 - 2024.22 * T);
827         double U12 = degToRad(316.41 + 2863.96 * T);
828         return 30.70 - 254.6906892 * t
829                - 1.27 * sin(U12) + 0.15 * sin(2.0 * U12)
830                + 1.15 * sin(U11) - 0.09 * sin(2.0 * U11);
831     }
832 };
833 
834 
835 class IAUArielRotationModel : public IAURotationModel
836 {
837 public:
IAUArielRotationModel()838     IAUArielRotationModel() : IAURotationModel(360.0 / 142.8356681) { setFlipped(true); }
839 
pole(double t,double & ra,double & dec) const840     void pole(double t, double& ra, double& dec) const
841     {
842         double T = t / 36525.0;
843         double U13 = degToRad(304.01 - 51.94 * T);
844         ra =  257.43 + 0.29 * sin(U13);
845         dec = -15.10 + 0.28 * cos(U13);
846     }
847 
meridian(double t) const848     double meridian(double t) const
849     {
850         double T = t / 36525.0;
851         double U12 = degToRad(316.41 + 2863.96 * T);
852         double U13 = degToRad(304.01 - 51.94 * T);
853         return 156.22 - 142.8356681 * t + 0.05 * sin(U12) + 0.08 * sin(U13);
854     }
855 };
856 
857 
858 class IAUUmbrielRotationModel : public IAURotationModel
859 {
860 public:
IAUUmbrielRotationModel()861     IAUUmbrielRotationModel() : IAURotationModel(360.0 / 86.8688923) { setFlipped(true); }
862 
pole(double t,double & ra,double & dec) const863     void pole(double t, double& ra, double& dec) const
864     {
865         double T = t / 36525.0;
866         double U14 = degToRad(308.71 - 93.17 * T);
867         ra =  257.43 + 0.21 * sin(U14);
868         dec = -15.10 + 0.20 * cos(U14);
869     }
870 
meridian(double t) const871     double meridian(double t) const
872     {
873         double T = t / 36525.0;
874         double U12 = degToRad(316.41 + 2863.96 * T);
875         double U14 = degToRad(308.71 - 93.17 * T);
876         return 108.05 - 86.8688923 * t - 0.09 * sin(U12) + 0.06 * sin(U14);
877     }
878 };
879 
880 
881 class IAUTitaniaRotationModel : public IAURotationModel
882 {
883 public:
IAUTitaniaRotationModel()884     IAUTitaniaRotationModel() : IAURotationModel(360.0 / 41.351431) { setFlipped(true); }
885 
pole(double t,double & ra,double & dec) const886     void pole(double t, double& ra, double& dec) const
887     {
888         double T = t / 36525.0;
889         double U15 = degToRad(340.82 - 75.32 * T);
890         ra =  257.43 + 0.29 * sin(U15);
891         dec = -15.10 + 0.28 * cos(U15);
892     }
893 
meridian(double t) const894     double meridian(double t) const
895     {
896         double T = t / 36525.0;
897         double U15 = degToRad(340.82 - 75.32 * T);
898         return 77.74 - 41.351431 * t + 0.08 * sin(U15);
899     }
900 };
901 
902 
903 class IAUOberonRotationModel : public IAURotationModel
904 {
905 public:
IAUOberonRotationModel()906     IAUOberonRotationModel() : IAURotationModel(360.0 / 26.7394932) { setFlipped(true); }
907 
pole(double t,double & ra,double & dec) const908     void pole(double t, double& ra, double& dec) const
909     {
910         double T = t / 36525.0;
911         double U16 = degToRad(259.14 - 504.81 * T);
912         ra =  257.43 + 0.16 * sin(U16);
913         dec = -15.10 + 0.16 * cos(U16);
914     }
915 
meridian(double t) const916     double meridian(double t) const
917     {
918         double T = t / 36525.0;
919         double U16 = degToRad(259.14 - 504.81 * T);
920         return 6.77 - 26.7394932 * t + 0.04 * sin(U16);
921     }
922 };
923 
924 
925 
926 RotationModel*
GetCustomRotationModel(const std::string & name)927 GetCustomRotationModel(const std::string& name)
928 {
929     // Initialize the custom rotation model table.
930     if (!CustomRotationModelsInitialized)
931     {
932         CustomRotationModelsInitialized = true;
933 
934         CustomRotationModels["earth-p03lp"] = new EarthRotationModel();
935 
936         // IAU rotation elements for the planets
937         CustomRotationModels["iau-mercury"] = new IAUPrecessingRotationModel(281.01, -0.033,
938                                                                              61.45, -0.005,
939                                                                              329.548, 6.1385025);
940         CustomRotationModels["iau-venus"]   = new IAUPrecessingRotationModel(272.76, 0.0,
941                                                                              67.16, 0.0,
942                                                                              160.20, -1.4813688);
943         CustomRotationModels["iau-earth"]   = new IAUPrecessingRotationModel(0.0, -0.641,
944                                                                              90.0, -0.557,
945                                                                              190.147, 360.9856235);
946         CustomRotationModels["iau-mars"]    = new IAUPrecessingRotationModel(317.68143, -0.1061,
947                                                                              52.88650, -0.0609,
948                                                                              176.630, 350.89198226);
949         CustomRotationModels["iau-jupiter"] = new IAUPrecessingRotationModel(268.05, -0.009,
950                                                                              64.49, -0.003,
951                                                                              284.95, 870.5366420);
952         CustomRotationModels["iau-saturn"]  = new IAUPrecessingRotationModel(40.589, -0.036,
953                                                                              83.537, -0.004,
954                                                                              38.90, 810.7939024);
955         CustomRotationModels["iau-uranus"]  = new IAUPrecessingRotationModel(257.311, 0.0,
956                                                                              -15.175, 0.0,
957                                                                              203.81, -501.1600928);
958         CustomRotationModels["iau-neptune"] = new IAUNeptuneRotationModel();
959         CustomRotationModels["iau-pluto"]   = new IAUPrecessingRotationModel(313.02, 0.0,
960                                                                              9.09, 0.0,
961                                                                              236.77, -56.3623195);
962 
963         // IAU elements for satellite of Earth
964         CustomRotationModels["iau-moon"] = new IAULunarRotationModel();
965 
966         // IAU elements for satellites of Mars
967         CustomRotationModels["iau-phobos"] = new IAUPhobosRotationModel();
968         CustomRotationModels["iau-deimos"] = new IAUDeimosRotationModel();
969 
970         // IAU elements for satellites of Jupiter
971         CustomRotationModels["iau-metis"]    = new IAUPrecessingRotationModel(268.05, -0.009,
972                                                                               64.49, 0.003,
973                                                                               346.09, 1221.2547301);
974         CustomRotationModels["iau-adrastea"] = new IAUPrecessingRotationModel(268.05, -0.009,
975                                                                               64.49, 0.003,
976                                                                               33.29, 1206.9986602);
977         CustomRotationModels["iau-amalthea"] = new IAUAmaltheaRotationModel();
978         CustomRotationModels["iau-thebe"]    = new IAUThebeRotationModel();
979         CustomRotationModels["iau-io"]       = new IAUIoRotationModel();
980         CustomRotationModels["iau-europa"]   = new IAUEuropaRotationModel();
981         CustomRotationModels["iau-ganymede"] = new IAUGanymedeRotationModel();
982         CustomRotationModels["iau-callisto"] = new IAUCallistoRotationModel();
983 
984         // IAU elements for satellites of Saturn
985         CustomRotationModels["iau-pan"]        = new IAUPrecessingRotationModel(40.6, -0.036,
986                                                                                 83.5, -0.004,
987                                                                                 48.8, 626.0440000);
988         CustomRotationModels["iau-atlas"]      = new IAUPrecessingRotationModel(40.6, -0.036,
989                                                                                 83.5, -0.004,
990                                                                                 137.88, 598.3060000);
991         CustomRotationModels["iau-prometheus"] = new IAUPrecessingRotationModel(40.6, -0.036,
992                                                                                 83.5, -0.004,
993                                                                                 296.14, 587.289000);
994         CustomRotationModels["iau-pandora"]    = new IAUPrecessingRotationModel(40.6, -0.036,
995                                                                                 83.5, -0.004,
996                                                                                 162.92, 572.7891000);
997         CustomRotationModels["iau-mimas"]     = new IAUMimasRotationModel();
998         CustomRotationModels["iau-enceladus"] = new IAUEnceladusRotationModel();
999         CustomRotationModels["iau-tethys"]    = new IAUTethysRotationModel();
1000         CustomRotationModels["iau-telesto"]   = new IAUTelestoRotationModel();
1001         CustomRotationModels["iau-calypso"]   = new IAUCalypsoRotationModel();
1002         CustomRotationModels["iau-dione"]     = new IAUDioneRotationModel();
1003         CustomRotationModels["iau-helene"]    = new IAUHeleneRotationModel();
1004         CustomRotationModels["iau-rhea"]      = new IAURheaRotationModel();
1005         CustomRotationModels["iau-titan"]     = new IAUTitanRotationModel();
1006         CustomRotationModels["iau-iapetus"]   = new IAUIapetusRotationModel();
1007         CustomRotationModels["iau-phoebe"]    = new IAUPhoebeRotationModel();
1008 
1009         CustomRotationModels["iau-miranda"]   = new IAUMirandaRotationModel();
1010         CustomRotationModels["iau-ariel"]     = new IAUArielRotationModel();
1011         CustomRotationModels["iau-umbriel"]   = new IAUUmbrielRotationModel();
1012         CustomRotationModels["iau-titania"]   = new IAUTitaniaRotationModel();
1013         CustomRotationModels["iau-oberon"]    = new IAUOberonRotationModel();
1014     }
1015 
1016     if (CustomRotationModels.count(name) > 0)
1017         return CustomRotationModels[name];
1018     else
1019         return NULL;
1020 }
1021 
1022 
1023