File indexing completed on 2025-01-05 03:58:39
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2014 Gerhard Holtkamp 0004 // 0005 0006 /* ========================================================================= 0007 Procedures needed for standard astronomy programs. 0008 The majority of procedures in this unit are taken from Montenbruck, 0009 Pfleger "Astronomie mit dem Personal Computer", Springer Verlag, 1989 0010 as well as from the "Explanatory Supplement to the Astronomical Almanac" 0011 University Science Books, Mill Valley, California, 1992 0012 and modified correspondingly. 0013 0014 License: GNU LGPL Version 2+ 0015 Copyright : Gerhard HOLTKAMP 15-APR-2015 0016 ========================================================================= */ 0017 0018 #include <cmath> 0019 using namespace std; 0020 0021 #include "astrolib.h" 0022 0023 double frac (double f) 0024 { return fmod(f,1.0); } 0025 0026 /*--------------- Function ddd ------------------------------------------*/ 0027 0028 double ddd (int d, int m, double s) 0029 { 0030 /* 0031 Conversion from Degrees, Minutes, Seconds into decimal degrees 0032 0033 INPUT : 0034 d : degrees 0035 m : minutes 0036 s : seconds (and fractions) 0037 0038 OUTPUT : 0039 dd : decimal degrees 0040 */ 0041 double dd; 0042 0043 if ( (d < 0) || (m < 0) || (s < 0)) dd = -1.0; 0044 else dd = 1.0; 0045 dd = dd * (fabs(double(d)) + fabs(double(m))/60.0 + fabs(s)/3600.0); 0046 0047 return dd; 0048 } 0049 0050 /*--------------- Function dms ------------------------------------------*/ 0051 0052 void dms (double dd, int &d, int &m, double &s) 0053 /* 0054 Conversion from decimal degrees into Degrees, Minutes, Seconds 0055 0056 INPUT : 0057 dd : decimal degrees 0058 0059 OUTPUT : 0060 d : degrees 0061 m : minutes 0062 s : seconds (and fractions) 0063 */ 0064 { 0065 double d1; 0066 0067 d1 = fabs(dd); 0068 // d = int(floor(d1)); 0069 d = int(d1); 0070 d1 = (d1 - d) * 60.0; 0071 // m = int(floor(d1)); 0072 m = int(d1); 0073 s = (d1 - m) * 60.0; 0074 if (dd < 0) 0075 { 0076 if (d != 0) d = -d; 0077 else 0078 { 0079 if (m != 0) m = -m; 0080 else s = -s; 0081 }; 0082 }; 0083 } 0084 0085 /*------------ FUNCTION mjd ----------------------------------------------*/ 0086 0087 double mjd (int day, int month, int year, double hour) 0088 /* 0089 Modified Julian Date ( MJD = Julian Date - 2400000.5) 0090 valid for every date 0091 Julian Calendar up to 4-OCT-1582, 0092 Gregorian Calendar from 15-OCT-1582. 0093 */ 0094 { 0095 double a; 0096 long int b, c; 0097 0098 a = 10000.0 * year + 100.0 * month + day; 0099 if (month <= 2) 0100 { 0101 month = month + 12; 0102 year = year - 1; 0103 }; 0104 if (a <= 15821004.1) 0105 { 0106 b = ((year+4716)/4) - 1181; 0107 if (year < -4716) 0108 { 0109 c = year + 4717; 0110 c = -c; 0111 c = c / 4; 0112 c = -c; 0113 b = c - 1182; 0114 }; 0115 } 0116 else b = (year/400) - (year/100) + (year/4); 0117 // { b = -2 + floor((year+4716)/4) - 1179;} 0118 // else {b = floor(year/400) - floor(year/100) + floor(year/4);}; 0119 0120 a = 365.0 * year - 679004.0; 0121 a = a + b + int(30.6001 * (month + 1)) + day + hour / 24.0; 0122 0123 return a; 0124 } 0125 0126 /*---------------- Function julcent ---------------------------------------*/ 0127 0128 double julcent (double mjuld) 0129 { 0130 /* 0131 Julian Centuries since J2000.0 of Modified Julian Date mjuld. 0132 */ 0133 return (mjuld - 51544.5) / 36525.0; 0134 } 0135 0136 /*---------------- Function caldat -----------------------------------------*/ 0137 0138 void caldat (double mjd, int &day, int &month, int &year, double &hour) 0139 /* 0140 Calculate the calendar date from the Modified Julian Date 0141 0142 INPUT : 0143 mjd : Modified Julian Date (Julian Date - 2400000.5) 0144 0145 OUTPUT : 0146 day, month, year : corresponding date 0147 hour : corresponding hours of the above date 0148 */ 0149 { 0150 long int b, c, d, e, f, jd0; 0151 0152 jd0 = long(mjd + 2400001.0); 0153 if (jd0 < 2299161) c = jd0 + 1524; /* Julian calendar */ 0154 else 0155 { /* Gregorian calendar */ 0156 b = long (( jd0 - 1867216.25) / 36524.25); 0157 c = jd0 + b - (b/4) + 1525; 0158 }; 0159 0160 if (mjd < -2400001.0) // special case for year < -4712 0161 { 0162 if (mjd == floor(mjd)) jd0 = jd0 + 1; 0163 c = long((-jd0 - 0.1)/ 365.25); 0164 c = c + 1; 0165 year = -4712 - c; 0166 d = c / 4; 0167 d = c * 365 + d; // number of days from JAN 1, -4712 0168 f = d + jd0; // day of the year 0169 if ((c % 4) == 0) e = 61; 0170 else e = 60; 0171 if (f == 0) 0172 { 0173 year = year - 1; 0174 month = 12; 0175 day = 31; 0176 f = 500; // set as a marker 0177 }; 0178 if (f < e) 0179 { 0180 if (f < 32) 0181 { 0182 month = 1; 0183 day = f; 0184 } 0185 else 0186 { 0187 month = 2; 0188 day = f - 31; 0189 }; 0190 } 0191 else 0192 { 0193 if (f < 500) 0194 { 0195 f = f - e; 0196 month = long((f + 123.0) / 30.6001); 0197 day = f - long(month * 30.6001) + 123; 0198 month = month - 1; 0199 }; 0200 }; 0201 } 0202 else // normal case 0203 { 0204 d = long ((c - 122.1) / 365.25); 0205 e = 365 * d + (d/4); 0206 f = long ((c - e) / 30.6001); 0207 day = c - e - long(30.6001 * f); 0208 month = f - 1 - 12 * (f / 14); 0209 year = d - 4715 - ((7 + month) / 10); 0210 }; 0211 0212 hour = 24.0 * (mjd - floor(mjd)); 0213 } 0214 0215 /*---------------- Function DefTdUt --------------------------------------*/ 0216 double DefTdUt (int yi) 0217 { 0218 /* 0219 Get a suitable default for value of TDT - UT in year yi in seconds. 0220 */ 0221 0222 const int td[9] = {55,55,56,56,57,58,58,59,60}; 0223 double t, result; 0224 int yy, yr; 0225 0226 yr = yi; 0227 0228 if (yr > 1899) 0229 { 0230 if (yr >= 2000) // this corrects for observations until 2013 0231 { 0232 if (yr > 2006) yr -= 1; 0233 if (yr > 2006) yr -= 1; // no leap second at the end of 2007 0234 if (yr > 2007) yr -= 1; // no leap second at the end of 2009 0235 if (yr > 2007) yr -= 1; // no leap second at the end of 2010 0236 if (yr > 2008) yr -= 1; // no leap second at the end of 2012 0237 yr -= 6; 0238 if (yr < 1999) yr = 1999; 0239 }; 0240 t = yr - 2000; 0241 t = t / 100.0; 0242 result = (((-339.84*t - 516.12)*t -160.22)*t + 92.23)*t + 71.28; 0243 if (yr > 2013) 0244 { 0245 t = yr - 2013; 0246 t = t / 100.0; 0247 result = (27.5*t + 75.0)*t + 73.0; 0248 } 0249 else if (yr > 1994) 0250 { 0251 result -= 6.28; 0252 } 0253 else if (yr > 1985) 0254 { 0255 yy = yr - 1986; 0256 result = td[yy]; 0257 }; 0258 }; 0259 0260 if (yr < 1900) 0261 { 0262 t = yr - 1800; 0263 t = t / 100; 0264 if (yr > 1649) 0265 { 0266 t = t - 0.19; 0267 result = 5.156 + 13.3066 * t * t; 0268 if (yr > 1864) result = -0.6*(yr - 1865) + 6; 0269 if (yr > 1884) result = -0.2*(yr - 1885) - 6; 0270 } 0271 else 0272 { 0273 if (yr > 947) result = 25.5 * t*t; 0274 else result = 1360 + (44.3*t + 320.0) * t; 0275 }; 0276 }; 0277 0278 // round to full seconds 0279 0280 if (result < 0) 0281 { 0282 t = -result; 0283 t += 0.5; 0284 result = - floor(t); 0285 } 0286 else result = floor(result + 0.5); 0287 0288 result += 0.184; // because of TT = TAI + 32.184; 0289 0290 return result; 0291 } 0292 0293 /*---------------- Function lsidtim -------------------------------------*/ 0294 0295 double lsidtim (double jd, double lambda, double ep2) 0296 { 0297 /* Calculate the Apparent Local Mean Sidereal Time (in decimal hours) for 0298 the Modified Julian Date jd and geographic longitude lambda (in degrees) 0299 and with the correction (AST - MST) eps (given in seconds) 0300 */ 0301 double lmst; 0302 double t, ut, gmst; 0303 int mjd0; 0304 0305 mjd0 = int(jd); 0306 ut = (jd - mjd0)*24.0; 0307 t = (mjd0 - 51544.5) / 36525.0; 0308 gmst = 6.697374558 + 1.0027379093*ut 0309 + (8640184.812866 + (0.093104 - 6.2e-6*t)*t)*t/3600.0; 0310 lmst = 24.0 * frac((gmst + lambda/15.0) / 24.0); 0311 lmst = lmst + ep2 / 3600.0; 0312 0313 return lmst; 0314 } 0315 0316 /*---------------- Function eps -----------------------------------------*/ 0317 0318 double eps (double t) // obliquity of ecliptic 0319 { 0320 /* 0321 Obliquety of ecliptic eps (in radians) 0322 at time t (in Julian Centuries from J2000.0) 0323 */ 0324 double tp; 0325 0326 tp = 23.43929111 - (46.815+(0.00059-0.001813*t)*t)*t/3600.0; 0327 tp = 1.74532925199e-2 * tp; 0328 0329 return tp; 0330 } 0331 0332 /*---------------- Function eclequ -----------------------------------------*/ 0333 0334 Vec3 eclequ (double t, Vec3& r1) // ecliptic -> equatorial 0335 { 0336 /* 0337 Convert position vector r1 from ecliptic into equatorial coordinates 0338 at t (in Julian Centuries from J2000.0 ) 0339 */ 0340 0341 Mat3 m; 0342 Vec3 r2; 0343 0344 m = xrot (-eps(t)); 0345 r2 = mxvct (m, r1); 0346 return r2; 0347 } 0348 0349 /*---------------- Function equecl -----------------------------------------*/ 0350 0351 Vec3 equecl (double t, Vec3& r1) // equatorial -> ecliptic 0352 { 0353 /* 0354 Convert position vector r1 from equatorial into ecliptic coordinates 0355 at t (in Julian Centuries from J2000.0) 0356 */ 0357 0358 Mat3 m; 0359 Vec3 r2; 0360 0361 m = xrot (eps(t)); 0362 r2 = mxvct (m, r1); 0363 return r2; 0364 } 0365 0366 /*---------------- Function pmatecl -----------------------------------------*/ 0367 0368 Mat3 pmatecl (double t1, double t2) // ecl. precession 0369 { 0370 /* 0371 Calculate ecliptic precession matrix a from t1 to t2 0372 (times in Julian Centuries from J2000.0) 0373 */ 0374 0375 const double secrad = 4.8481368111e-6; // arcsec -> radians 0376 0377 double ppi, pii, pa, dt; 0378 Mat3 m1, m2, a; 0379 0380 dt = t2 - t1; 0381 ppi = 174.876383889 + (((3289.4789+0.60622*t1)*t1) + 0382 ((-869.8089-0.50491*t1) + 0.03536*dt)*dt) / 3600.0; 0383 ppi = ppi * 1.74532925199e-2; 0384 pii = ((47.0029-(0.06603-0.000598*t1)*t1) + 0385 ((-0.03302+0.000598*t1)+0.00006*dt)*dt)*dt * secrad; 0386 pa = ((5029.0966+(2.22226-0.000042*t1)*t1) + 0387 ((1.11113-0.000042*t1)-0.000006*dt)*dt)*dt * secrad; 0388 0389 pa = ppi + pa; 0390 m1 = zrot (-pa); 0391 m2 = xrot (pii); 0392 m1 = m1 * m2; 0393 m2 = zrot (ppi); 0394 a = m1 * m2; 0395 0396 return a; 0397 } 0398 0399 /*---------------- Function pmatequ --------------------------------------*/ 0400 0401 Mat3 pmatequ (double t1, double t2) // equ. precession 0402 { 0403 /* 0404 Calculate equatorial precession matrix a from t1 to t2 0405 (times in Julian Centuries from J2000.0) 0406 */ 0407 const double secrad = 4.8481368111e-6; // arcsec -> radians 0408 0409 double dt, zeta, z, theta; 0410 Mat3 m1, m2, a; 0411 0412 dt = t2 - t1; 0413 zeta = ((2306.2181+(1.39656-0.000139*t1)*t1) + 0414 ((0.30188-0.000345*t1)+0.017998*dt)*dt)*dt * secrad; 0415 z = zeta + ((0.7928+0.000411*t1)+0.000205*dt)*dt*dt * secrad; 0416 theta = ((2004.3109-(0.8533+0.000217*t1)*t1) - 0417 ((0.42665+0.000217*t1)+0.041833*dt)*dt)*dt * secrad; 0418 0419 m1 = zrot (-z); 0420 m2 = yrot (theta); 0421 m1 = m1 * m2; 0422 m2 = zrot (-zeta); 0423 a = m1 * m2; 0424 0425 return a; 0426 } 0427 0428 /*---------------- Function nutmat --------------------------------------*/ 0429 0430 Mat3 nutmat (double t, double& ep2, bool hpr) 0431 { 0432 /* 0433 Calculate nutation matrix a from mean to true equatorial coordinates 0434 at time t (in Julian Centuries from J2000.0) 0435 Also calculates the correction ep2 for apparent sidereal time in sec 0436 0437 if hpr is true a high precision is used, otherwise a low precision 0438 (only the first 50 terms of the nutation theory are used) 0439 */ 0440 const int ntb1 = 15; 0441 const int tb1[ntb1][5] = 0442 { 0443 { 0, 0, 0, 0, 1}, // 1 0444 { 0, 0, 0, 0, 2}, // 2 0445 { 0, 0, 2,-2, 2}, // 9 0446 { 0, 1, 0, 0, 0}, // 10 0447 { 0, 1, 2,-2, 2}, // 11 0448 { 0,-1, 2,-2, 2}, // 12 0449 { 0, 0, 2,-2, 1}, // 13 0450 { 0, 2, 0, 0, 0}, // 16 0451 { 0, 2, 2,-2, 2}, // 18 0452 { 0, 0, 2, 0, 2}, // 31 0453 { 1, 0, 0, 0, 0}, // 32 0454 { 0, 0, 2, 0, 1}, // 33 0455 { 1, 0, 2, 0, 2}, // 34 0456 { 1, 0, 0, 0, 1}, // 38 0457 { -1, 0, 0, 0, 1}, // 39 0458 }; 0459 0460 const int ntb2 = 35; 0461 const int tb2[ntb2][5] = 0462 { 0463 { -2, 0, 2, 0, 1}, // 3 0464 { 2, 0,-2, 0, 0}, // 4 0465 { -2, 0, 2, 0, 2}, // 5 0466 { 1,-1, 0,-1, 0}, // 6 0467 { 0,-2, 2,-2, 1}, // 7 0468 { 2, 0,-2, 0, 1}, // 8 0469 { 2, 0, 0,-2, 0}, // 14 0470 { 0, 0, 2,-2, 0}, // 15 0471 { 0, 1, 0, 0, 1}, // 17 0472 { 0,-1, 0, 0, 1}, // 19 0473 { -2, 0, 0, 2, 1}, // 20 0474 { 0,-1, 2,-2, 1}, // 21 0475 { 2, 0, 0,-2, 1}, // 22 0476 { 0, 1, 2,-2, 1}, // 23 0477 { 1, 0, 0,-1, 0}, // 24 0478 { 2, 1, 0,-2, 0}, // 25 0479 { 0, 0,-2, 2, 1}, // 26 0480 { 0, 1,-2, 2, 0}, // 27 0481 { 0, 1, 0, 0, 2}, // 28 0482 { -1, 0, 0, 1, 1}, // 29 0483 { 0, 1, 2,-2, 0}, // 30 0484 { 1, 0, 0,-2, 0}, // 35 0485 { -1, 0, 2, 0, 2}, // 36 0486 { 0, 0, 0, 2, 0}, // 37 0487 { -1, 0, 2, 2, 2}, // 40 0488 { 1, 0, 2, 0, 1}, // 41 0489 { 0, 0, 2, 2, 2}, // 42 0490 { 2, 0, 0, 0, 0}, // 43 0491 { 1, 0, 2,-2, 2}, // 44 0492 { 2, 0, 2, 0, 2}, // 45 0493 { 0, 0, 2, 0, 0}, // 46 0494 { -1, 0, 2, 0, 1}, // 47 0495 { -1, 0, 0, 2, 1}, // 48 0496 { 1, 0, 0,-2, 1}, // 49 0497 { -1, 0, 2, 2, 1}, // 50 0498 }; 0499 0500 const double tb3[ntb1][4] = 0501 { 0502 {-171996.0,-174.2, 92025.0, 8.9 }, // 1 0503 { 2062.0, 0.2, -895.0, 0.5 }, // 2 0504 { -13187.0, -1.6, 5736.0, -3.1 }, // 9 0505 { 1426.0, -3.4, 54.0, -0.1 }, // 10 0506 { -517.0, 1.2, 224.0, -0.6 }, // 11 0507 { 217.0, -0.5, -95.0, 0.3 }, // 12 0508 { 129.0, 0.1, -70.0, 0.0 }, // 13 0509 { 17.0, -0.1, 0.0, 0.0 }, // 16 0510 { -16.0, 0.1, 7.0, 0.0 }, // 18 0511 { -2274.0, -0.2, 977.0, -0.5 }, // 31 0512 { 712.0, 0.1, -7.0, 0.0 }, // 32 0513 { -386.0, -0.4, 200.0, 0.0 }, // 33 0514 { -301.0, 0.0, 129.0, -0.1 }, // 34 0515 { 63.0, 0.1, -33.0, 0.0 }, // 38 0516 { -58.0, -0.1, 32.0, 0.0 }, // 39 0517 }; 0518 0519 const double tb4[ntb2][2] = 0520 { 0521 { 46.0, -24.0}, // 3 0522 { 11.0, 0.0 }, // 4 0523 { -3.0, 1.0 }, // 5 0524 { -3.0, 0.0 }, // 6 0525 { -2.0, 1.0 }, // 7 0526 { 1.0, 0.0 }, // 8 0527 { 48.0, 1.0 }, // 14 0528 {-22.0, 0.0 }, // 15 0529 {-15.0, 9.0 }, // 17 0530 {-12.0, 6.0 }, // 19 0531 { -6.0, 3.0 }, // 20 0532 { -5.0, 3.0 }, // 21 0533 { 4.0, -2.0 }, // 22 0534 { 4.0, -2.0 }, // 23 0535 { -4.0, 0.0 }, // 24 0536 { 1.0, 0.0 }, // 25 0537 { 1.0, 0.0 }, // 26 0538 { -1.0, 0.0 }, // 27 0539 { 1.0, 0.0 }, // 28 0540 { 1.0, 0.0 }, // 29 0541 { -1.0, 0.0 }, // 30 0542 {-158.0,-1.0 }, // 35 0543 {123.0,-53.0 }, // 36 0544 { 63.0, -2.0 }, // 37 0545 {-59.0, 26.0 }, // 40 0546 {-51.0, 27.0 }, // 41 0547 {-38.0, 16.0 }, // 42 0548 { 29.0, -1.0 }, // 43 0549 { 29.0,-12.0 }, // 44 0550 {-31.0, 13.0 }, // 45 0551 { 26.0, -1.0 }, // 46 0552 { 21.0,-10.0 }, // 47 0553 { 16.0, -8.0 }, // 48 0554 {-13.0, 7.0 }, // 49 0555 {-10.0, 5.0 }, // 50 0556 }; 0557 0558 const double secrad = 4.8481368111e-6; // arcsec -> radians 0559 const double p2 = 2.0 * M_PI; 0560 0561 double ls, lm, d, f, n, dpsi, deps, ep0; 0562 int j; 0563 Mat3 m1, m2, a; 0564 0565 if (hpr) 0566 { 0567 lm = 2.355548393544 + 0568 (8328.691422883903 + (0.000151795164 + 0.000000310281*t)*t)*t; 0569 ls = 6.240035939326 + 0570 (628.301956024185 + (-0.000002797375 - 0.000000058178*t)*t)*t; 0571 f = 1.627901933972 + 0572 (8433.466158318464 + (-0.000064271750 + 0.000000053330*t)*t)*t; 0573 d = 5.198469513580 + 0574 (7771.377146170650 + (-0.000033408511 + 0.000000092115*t)*t)*t; 0575 n = 2.182438624361 + 0576 (-33.757045933754 + (0.000036142860 + 0.000000038785*t)*t)*t; 0577 0578 lm = fmod(lm,p2); 0579 ls = fmod(ls,p2); 0580 f = fmod(f,p2); 0581 d = fmod(d,p2); 0582 n = fmod(n,p2); 0583 0584 dpsi = 0.0; 0585 deps = 0.0; 0586 for(j=0; j<ntb1; j++) 0587 { 0588 ep0 = tb1[j][0]*lm + tb1[j][1]*ls + tb1[j][2]*f + tb1[j][3]*d + tb1[j][4]*n; 0589 dpsi = dpsi + (tb3[j][0]+tb3[j][1]*t) * sin(ep0); 0590 deps = deps + (tb3[j][2]+tb3[j][3]*t) * cos(ep0); 0591 }; 0592 for(j=0; j<ntb2; j++) 0593 { 0594 ep0 = tb2[j][0]*lm + tb2[j][1]*ls + tb2[j][2]*f + tb2[j][3]*d + tb2[j][4]*n; 0595 dpsi = dpsi + tb4[j][0] * sin(ep0); 0596 deps = deps + tb4[j][1] * cos(ep0); 0597 }; 0598 dpsi = 1.0e-4 * dpsi * secrad; 0599 deps = 1.0e-4 * deps * secrad; 0600 } 0601 0602 else // low precision 0603 { 0604 ls = p2 * frac (0.993133+99.997306*t); // mean anomaly sun 0605 d = p2 * frac (0.827362+1236.853087*t); // diff long. moon-sun 0606 f = p2 * frac (0.259089+1342.227826*t); // dist. node 0607 n = p2 * frac (0.347346 - 5.372447*t); // long. node 0608 0609 dpsi = (-17.2*sin(n) - 1.319*sin(2*(f-d+n)) - 0.227*sin(2*(f+n)) 0610 + 0.206*sin(2*n) + 0.143*sin(ls)) * secrad; 0611 deps = (+9.203*cos(n) + 0.574*cos(2*(f-d+n)) + 0.098*cos(2*(f+n)) 0612 -0.09*cos(2*n) ) * secrad; 0613 }; 0614 0615 ep0 = eps (t); 0616 ep2 = ep0 + deps; 0617 m1 = xrot (ep0); 0618 m2 = zrot (-dpsi); 0619 m1 *= m2; 0620 m2 = xrot (-ep2); 0621 a = m2 * m1; 0622 ep2 = dpsi * cos (ep2); 0623 ep2 *= 13750.9870831; // convert radians into time-seconds 0624 0625 return a; 0626 } 0627 0628 /*---------------- Function nutecl --------------------------------------*/ 0629 0630 Mat3 nutecl (double t, double& ep2) // nutation matrix (ecliptic) 0631 { 0632 /* 0633 Calculate nutation matrix a from mean to true ecliptic coordinates 0634 at time t (in Julian Centuries from J2000.0) 0635 Also calculates the correction ep2 for apparent sidereal time in sec 0636 */ 0637 0638 const double secrad = 4.8481368111e-6; // arcsec -> radians 0639 const double p2 = 2.0 * M_PI; 0640 0641 double ls, d, f, n, dpsi, deps, ep0; 0642 Mat3 m1, m2, a; 0643 0644 ls = p2 * frac (0.993133+99.997306*t); // mean anomaly sun 0645 d = p2 * frac (0.827362+1236.853087*t); // diff long. moon-sun 0646 f = p2 * frac (0.259089+1342.227826*t); // dist. node 0647 n = p2 * frac (0.347346 - 5.372447*t); // long. node 0648 0649 dpsi = (-17.2*sin(n) - 1.319*sin(2*(f-d+n)) - 0.227*sin(2*(f+n)) 0650 + 0.206*sin(2*n) + 0.143*sin(ls)) * secrad; 0651 0652 deps = (+9.203*cos(n) + 0.574*cos(2*(f-d+n)) + 0.098*cos(2*(f+n)) 0653 -0.09*cos(2*n) ) * secrad; 0654 0655 ep0 = eps (t); 0656 ep2 = ep0 + deps; 0657 m1 = xrot (-deps); 0658 m2 = zrot (-dpsi); 0659 a = m1 * m2; 0660 ep2 = dpsi * cos (ep2); 0661 ep2 *= 13750.9870831; // convert radians into time-seconds 0662 0663 return a; 0664 } 0665 0666 /*---------------- Function pmatequ --------------------------------------*/ 0667 0668 Mat3 PoleMx (double xp, double yp) 0669 { 0670 /* Returns Polar Motion matrix. 0671 xp and yp are the coordinates of the Celestial Ephemeris Pole 0672 with respect to the IERS Reference Pole in arcsec as published 0673 in the IERS Bulletin B. 0674 */ 0675 const double arctrd = M_PI / (180.0*3600.0); 0676 Mat3 res; 0677 double xr, yr; 0678 0679 xr = xp * arctrd; 0680 yr = yp * arctrd; 0681 res.assign(1.0,0.0,xr,0.0,1.0,-yr,-xr,yr,1.0); 0682 0683 return res; 0684 } 0685 0686 /*---------------- Function aberrat --------------------------------------*/ 0687 0688 Vec3 aberrat (double t, Vec3& ve) // aberration 0689 { 0690 /* 0691 Correct position vector ve for aberration into new position va 0692 at time t (in Julian Centuries from J2000.0) 0693 */ 0694 const double p2 = 2.0 * M_PI; 0695 0696 double l, cl, d0; 0697 Vec3 va; 0698 0699 d0 = abs(ve); 0700 l = p2 * frac(0.27908+100.00214*t); 0701 cl = cos(l)*d0; 0702 va[0] = ve[0] - 9.934e-5 * sin(l) * d0; 0703 va[1] = ve[1] + 9.125e-5 * cl; 0704 va[2] = ve[2] + 3.927e-5 * cl; 0705 0706 return va; 0707 } 0708 0709 /*--------------------- Function GeoPos ----------------------------------*/ 0710 0711 Vec3 GeoPos (double jd, double ep2, double lat, double lng, double ht) 0712 { 0713 /* Return the geocentric vector (in the equatorial system) of the 0714 geographic position given by the latitude lat and longitude lng 0715 (in radians) and height ht (in m) at the MJD-time jd (UT). 0716 ep2 : correction for apparent sidereal time in sec 0717 0718 The length unit of the vector is in terms of the equatorial 0719 Earth radius (6378.137 km) 0720 */ 0721 double const e2 = 6.69438499959e-3; 0722 double np, h, sp; 0723 0724 Vec3 r; 0725 0726 sp = sin(lat); 0727 h = ht / 6378.137e3; 0728 np = 1.0 / (sqrt(1.0 - e2*sp*sp)); 0729 r[2] = ((1.0 - e2)*np + h)*sp; 0730 0731 sp = (np + h) * cos(lat); 0732 np = lsidtim(jd, (lng*180.0/M_PI), ep2) * M_PI/12.0; 0733 0734 r[0] = sp * cos(np); 0735 r[1] = sp * sin(np); 0736 0737 return r; 0738 } 0739 0740 Vec3 GeoPos (double jd, double ep2, double lat, double lng, double ht, 0741 double xp, double yp) 0742 { 0743 /* Return the geocentric vector (in the equatorial system) of the 0744 geographic position given by the latitude lat and longitude lng 0745 (in radians) and height ht (in m) at the MJD-time jd (UT). 0746 0747 ep2 : correction for apparent sidereal time in sec 0748 xp, yp: coordinates of polar motion in arcsec. 0749 0750 The length unit of the vector is in terms of the equatorial 0751 Earth radius (6378.137 km) 0752 */ 0753 double const e2 = 6.69438499959e-3; 0754 double np, h, sp; 0755 Mat3 prx; 0756 Vec3 r; 0757 0758 sp = sin(lat); 0759 h = ht / 6378.137e3; 0760 np = 1.0 / (sqrt(1.0 - e2*sp*sp)); 0761 r[2] = ((1.0 - e2)*np + h)*sp; 0762 sp = (np + h) * cos(lat); 0763 r[0] = sp * cos(lng); 0764 r[1] = sp * sin(lng); 0765 0766 // correct for polar motion 0767 if ((xp != 0) || (yp != 0)) 0768 { 0769 prx = mxtrn(PoleMx(xp, yp)); 0770 r = mxvct(prx, r); 0771 }; 0772 0773 // convert into equatorial 0774 np = lsidtim(jd, 0.0, ep2) * M_PI/12.0; 0775 prx = zrot(-np); 0776 r = mxvct(prx, r); 0777 0778 return r; 0779 } 0780 0781 /*--------------------- Function EquHor ----------------------------------*/ 0782 0783 Vec3 EquHor (double jd, double ep2, double lat, double lng, Vec3 r) 0784 { 0785 /* convert vector r from the equatorial system into the horizontal system. 0786 jd = MJD-time (UT) 0787 ep2 : correction for apparent sidereal time in sec 0788 lat, lng : geographic latitude and longitude (in radians) 0789 */ 0790 double lst; 0791 Vec3 s; 0792 Mat3 mx; 0793 0794 lst = lsidtim(jd, (lng*180.0/M_PI), ep2) * M_PI/12.0; 0795 mx = zrot(lst); 0796 s = mxvct(mx, r); 0797 mx = yrot(M_PI/2.0 - lat); 0798 s = mxvct(mx, s); 0799 0800 return s; 0801 } 0802 0803 /*--------------------- Function HorEqu ----------------------------------*/ 0804 0805 0806 Vec3 HorEqu (double jd, double ep2, double lat, double lng, Vec3 r) 0807 { 0808 /* convert vector r from the horizontal system into the equatorial system. 0809 jd = MJD-time (UT) 0810 ep2 : correction for apparent sidereal time in sec 0811 lat, lng : geographic latitude and longitude (in radians) 0812 */ 0813 double lst; 0814 Vec3 s; 0815 Mat3 mx; 0816 0817 mx = yrot(lat - M_PI/2.0); 0818 s = mxvct(mx, r); 0819 lst = -lsidtim(jd, (lng*180.0/M_PI), ep2) * M_PI/12.0; 0820 mx = zrot(lst); 0821 s = mxvct(mx, s); 0822 0823 return s; 0824 } 0825 0826 /*--------------------- Function AppPos ----------------------------------*/ 0827 0828 void AppPos (double jd, double ep2, double lat, double lng, double ht, 0829 int solsys, const Vec3& r, double& azim, double& elev, double& dist) 0830 { 0831 /* get apparent position in the horizontal system 0832 jd = MJD-time (UT) 0833 ep2 : correction for apparent sidereal time in sec 0834 lat, lng : geographic latitude and longitude (in radians) 0835 ht : height above normal in meters. 0836 solsys : = 1 if object is in solar system and parallax has to be 0837 taken into account, 0 otherwise. 0838 r = vector of celestial object. The unit of length of this vector 0839 has to be in terms of the equatorial Earth radius (6378.14 km) 0840 if solsys = 1, otherwise it's arbitrary. 0841 azim : azimuth in radians (0 is to the North). 0842 elev : elevation in radians 0843 dist : distance (if solsys = 1; otherwise abs(r)) 0844 */ 0845 Vec3 s; 0846 0847 // correct for topocentric position (parallax) 0848 if (solsys) s = r - GeoPos(jd, ep2, lat, lng, ht); 0849 else s = r; 0850 0851 s = EquHor(jd, ep2, lat, lng, s); 0852 s = carpol(s); 0853 dist = s[0]; 0854 elev = s[2]; 0855 azim = M_PI - s[1]; 0856 } 0857 0858 /*--------------------- Function AppRADec ----------------------------------*/ 0859 0860 void AppRADec (double jd, double ep2, double lat, double lng, 0861 double azim, double elev, double& ra, double& dec) 0862 { 0863 /* get apparent position in the horizontal system 0864 jd = MJD-time (UT) 0865 ep2 : correction for apparent sidereal time in sec 0866 lat, lng : geographic latitude and longitude (in radians) 0867 azim : azimuth in radians (0 is to the North). 0868 elev : elevation in radians 0869 ra : Right Ascension (in radians) 0870 dec : Declination (in radians) 0871 */ 0872 Vec3 s; 0873 0874 s[0] = 1.0; 0875 s[1] = M_PI - azim; 0876 s[2] = elev; 0877 s = polcar(s); 0878 s = HorEqu(jd, ep2, lat, lng, s); 0879 s = carpol(s); 0880 dec = s[2]; 0881 ra = s[1]; 0882 } 0883 0884 /*------------------------- Refract ---------------------------------*/ 0885 0886 double Refract (double h, double p, double t) 0887 { 0888 /* Calculate atmospheric refraction with low precision 0889 h = height (in radians) of object 0890 p = presure (in millibars) 0891 t = temperature (in degrees Celsius) 0892 0893 RETURN: refraction angle in radians 0894 */ 0895 double const raddeg = 180.0 / M_PI; 0896 double r; 0897 0898 r = h * raddeg; 0899 r = (r + 7.31 / (r + 4.4)) / raddeg; 0900 r = (0.28*p/(t+273.0)) * 0.0167 / tan(r); 0901 r = r / raddeg; 0902 0903 return r; 0904 } 0905 0906 /*---------------- Function eccanom --------------------------------------*/ 0907 0908 double eccanom (double man, double ecc) 0909 { 0910 /* 0911 Solve Kepler equation for eccentric anomaly of elliptical orbits. 0912 man : Mean Anomaly (in radians) 0913 ecc : eccentricity 0914 */ 0915 const double p2 = 2.0*M_PI; 0916 const double eps = 1E-11; 0917 const int maxit = 15; 0918 0919 double m, e, f; 0920 int i, mi; 0921 0922 m=man/p2; 0923 mi = int(m); 0924 m=p2*(m-mi); 0925 if (m < 0) m=m+p2; 0926 if (ecc < 0.8) e=m; 0927 else e=M_PI; 0928 f = e - ecc*sin(e) - m; 0929 i=0; 0930 0931 while ((fabs(f) > eps) && (i < maxit)) 0932 { 0933 e = e - f / (1.0 - ecc*cos(e)); 0934 f = e - ecc*sin(e) - m; 0935 i = i + 1; 0936 } 0937 0938 return e; 0939 } 0940 0941 0942 /*---------------- Function hypanom --------------------------------------*/ 0943 0944 double hypanom (double mh, double ecc) 0945 { 0946 /* 0947 Solve Kepler equation for eccentric anomaly of hyperbolic orbits. 0948 mh : Mean Anomaly 0949 ecc : eccentricity 0950 */ 0951 const double eps = 1E-11; 0952 const int maxit = 15; 0953 0954 double h, f; 0955 int i; 0956 0957 h = log (2.0*fabs(mh)/ecc+1.8); 0958 if (mh < 0.0) h = -h; 0959 f = ecc * sinh(h) - h - mh; 0960 i = 0; 0961 0962 while ((fabs(f) > eps*(1.0+fabs(h+mh))) && (i < maxit)) 0963 { 0964 h = h - f / (ecc*cosh(h) - 1.0); 0965 f = ecc*sinh(h) - h - mh; 0966 i = i + 1; 0967 } 0968 0969 return h; 0970 } 0971 0972 0973 /*------------------ Function ellip ------------------------------------*/ 0974 0975 void ellip (double gm, double t0, double t, double a, double ecc, 0976 double m0, Vec3& r1, Vec3& v1) 0977 { 0978 /* 0979 Calculate position r1 and velocity v1 of for elliptic orbit at time t. 0980 gm : Gravitational Constant 0981 t0 : epoch 0982 a : semim-ajor axis 0983 ecc : eccentricity 0984 m0 : Mean Anomaly at epoch (in radians). 0985 The units must be consistent with each other. 0986 */ 0987 double m, e, fac, k, c, s; 0988 0989 if (fabs(a) < 1e-60) a = 1e-60; 0990 k = gm / a; 0991 if (k >= 0) k = sqrt(k); 0992 else k = 0; // just in case 0993 0994 m = k * (t - t0) / a + m0; 0995 e = eccanom(m, ecc); 0996 fac = sqrt(1.0 - ecc*ecc); 0997 c = cos(e); 0998 s = sin(e); 0999 r1.assign (a*(c - ecc), a*fac*s, 0.0); 1000 m = 1.0 - ecc*c; 1001 v1.assign (-k*s/m, k*fac*c/m, 0.0); 1002 } 1003 1004 /*---------------- Function hyperb --------------------------------------*/ 1005 1006 void hyperb (double gm, double t0, double t, double a, double ecc, 1007 Vec3& r1, Vec3& v1) 1008 { 1009 /* 1010 Calculate position r1 and velocity v1 of for hyperbolic orbit at time t. 1011 gm : Gravitational Constant 1012 t0 : time of perihelion passage 1013 a : semi-major axis 1014 ecc : eccentricity 1015 The units must be consistent with each other. 1016 */ 1017 double mh, h, fac, k, c, s; 1018 1019 a = fabs(a); 1020 if (a < 1e-60) a = 1e-60; 1021 k = gm / a; 1022 if (k >= 0) k = sqrt(k); 1023 else k = 0; // just in case 1024 1025 mh = k * (t - t0) / a; 1026 h = hypanom (mh, ecc); 1027 fac = sqrt(ecc*ecc-1.0); 1028 c = cosh(h); 1029 s = sinh(h); 1030 r1.assign (a*(ecc-c), a*fac*s, 0.0); 1031 mh = ecc*c - 1.0; 1032 v1.assign (-k*s/mh, k*fac*c/mh, 0.0); 1033 } 1034 1035 /*---------------- Function parab --------------------------------------*/ 1036 1037 void stumpff (double e2, double& c1, double& c2, double& c3) 1038 { 1039 /* 1040 Calculation of Stumpff functions c1=sin(e)/c, 1041 c2=(1-cos(e))/e^2 and c3=(e-sin(e))/e^3 for the 1042 argument e2=e^2 (e: eccentric anomaly) 1043 */ 1044 const double eps=1E-12; 1045 double n, add; 1046 1047 c1=0.0; c2=0.0; c3=0.0; add=1.0; n=1.0; 1048 do 1049 { 1050 c1=c1+add; add=add/(2.0*n); 1051 c2=c2+add; add=add/(2.0*n+1); 1052 c3=c3+add; add=-e2*add; 1053 n=n+1.0; 1054 } while (abs(add)>eps); 1055 } 1056 1057 void parab (double gm, double t0, double t, double q, double ecc, 1058 Vec3& r1, Vec3& v1) 1059 { 1060 /* 1061 Calculate position r1 and velocity v1 of for parabolic 1062 (or near parabolic) orbit at time t using Stumpff's method. 1063 gm : Gravitational Constant 1064 t0 : time of perihelion passage 1065 q : perihelion distance 1066 ecc : eccentricity 1067 The units must be consistent with each other. 1068 */ 1069 const double eps = 1E-9; 1070 const int maxit = 15; 1071 1072 double e2, e20, fac, c1, c2, c3, k, tau, a, u, u2; 1073 double x, y; 1074 int i, fle; 1075 1076 ecc = fabs(ecc); 1077 e2=0.0; fac=0.5*ecc; i=0; 1078 1079 q = fabs(q); 1080 if (q < 1e-40) q = 1e-40; 1081 k = gm / (q*(1+ecc)); 1082 1083 if (k >= 0) k = sqrt(k); 1084 else k = 0; // just in case 1085 1086 tau = gm / (q*q*q); 1087 if (tau >= 0) tau= 1.5*sqrt(tau)*(t-t0); 1088 else tau = 0; 1089 1090 do 1091 { 1092 i = i + 1; 1093 e20 = e2; 1094 if (fac < 0.0) a = -1.0; 1095 else a = tau * sqrt(fac); 1096 a = sqrt(a*a+1.0)+a; 1097 if (a > 0.0) a = exp(log(a)/3.0); 1098 if (a == 0.0) u = 0.0; 1099 else u = a - 1.0/a; 1100 u2 = u*u; 1101 if (fac != 0) e2 = u2*(1.0-ecc)/fac; 1102 else e2 = 1; 1103 stumpff (e2, c1, c2, c3); 1104 fac = 3.0*ecc*c3; 1105 fle = (abs(e2-e20) < eps) || (i > maxit); 1106 } while (!fle); 1107 1108 if (fac != 0) 1109 { 1110 tau = q*(1.0+u2*c2*ecc/fac); 1111 x = q*(1.0-u2*c2/fac); 1112 y = (1.0+ecc)/fac; 1113 if (y >= 0) y = q*sqrt(y)*u*c1; 1114 else y = 0; 1115 r1.assign (x, y, 0.0); 1116 v1.assign (-k*y/tau, k*(x/tau+ecc), 0.0); 1117 } 1118 else // just in case 1119 { 1120 r1.assign (0, 0, 0); 1121 v1.assign (0, 0, 0); 1122 }; 1123 } 1124 1125 /*---------------- Function kepler --------------------------------------*/ 1126 1127 void kepler (double gm, double t0, double t, double m0, double a, double ecc, 1128 double ran, double aper, double inc, Vec3& r1, Vec3& v1) 1129 { 1130 /* 1131 Calculate position r1 and velocity v1 of body at time t as an 1132 undisturbed 2-body Kepler problem. 1133 1134 gm : Gravitational Constant 1135 t0 : time of perihelion passage (hyperbolic or near-parabolic) 1136 epoch of m0 for elliptical orbits. 1137 m0 : Mean Anomaly at epoch for elliptical orbits in degrees in the 1138 range 0 to 360. If m0 < 0 the calculations will be done as 1139 near-parabolic. Set m0 = 0 for hyperbolic orbits. 1140 a : semi-major axis for elliptical (positive) or hyperbolic orbits 1141 (negative). If m0 < 0, a signifies perihelion distance q instead 1142 ecc : eccentricity 1143 ran : Right Ascension of Ascending Node (in degrees) 1144 aper : Argument of Perihelion (in degrees) 1145 inc : Inclination (in degrees) 1146 1147 The units must be consistent with each other. 1148 1149 NOTE : If ecc = 1 the orbit will always be calculated as a parabolic one. 1150 If ecc < 1 (elliptical orbits) two possibilities exist: 1151 If m0 >= 0 the calculation will be done in the classical 1152 way with m0 signifying the mean anomaly at time t0 and 1153 a the semi-major axis. 1154 If m0 < 0 the orbit will be calculated as a near-parabolic 1155 orbit with a signifying the perihelion distance at time t0. 1156 (This latter method will be useful for high eccentricity 1157 comet orbits for which typically q is given instead of a) 1158 If ecc > 1 (hyperbolic orbits) two possibilities exist: 1159 If m0 >= 0 (the value is ignored for hyperbolic orbits) 1160 a classical hyperbolic calculation is performed with a 1161 signifying the semi-major axis (negative for hyperbolas). 1162 If m0 < 0 the orbit will be calculated as a near-parabolic 1163 orbit with a signifying the perihelion distance. (This can 1164 be useful for comet orbits which would rarely have an 1165 eccentricity >> 1) 1166 In either case t0 signifies the time of perihelion passage. 1167 */ 1168 const double dgrd = M_PI / 180.0; 1169 enum {ell, par, hyp} kepc; 1170 Mat3 m1,m2; 1171 1172 kepc = ell; // just to keep the compiler happy 1173 1174 // convert into radians 1175 m0 *= dgrd; 1176 ran *= dgrd; 1177 aper *= dgrd; 1178 inc *= dgrd; 1179 1180 // calculate the position and velocity within the orbit plane 1181 if (ecc == 1.0) kepc = par; 1182 if (ecc < 1.0) 1183 { 1184 if (m0 < 0.0) kepc = par; 1185 else kepc = ell; 1186 } 1187 if (ecc > 1.0) 1188 { 1189 if (m0 < 0.0) kepc = par; 1190 else kepc = hyp; 1191 } 1192 1193 switch (kepc) 1194 { 1195 case ell : ellip (gm, t0, t, a, ecc, m0, r1, v1); break; 1196 case par : parab (gm, t0, t, a, ecc, r1, v1); break; 1197 case hyp : hyperb (gm, t0, t, a, ecc, r1, v1); break; 1198 } 1199 1200 // convert into reference plane 1201 m1 = zrot (-aper); 1202 m2 = xrot (-inc); 1203 m1 *= m2; 1204 m2 = zrot (-ran); 1205 m2 = m2 * m1; 1206 1207 r1 = mxvct (m2, r1); 1208 v1 = mxvct (m2, v1); 1209 } 1210 1211 /*---------------- Function oscelm --------------------------------------*/ 1212 1213 void oscelm (double gm, double t, Vec3& r1, Vec3& v1, 1214 double& t0, double& m0, double& a, double& ecc, 1215 double& ran, double& aper, double& inc) 1216 { 1217 /* 1218 Get the osculating Kepler elements at epoch t from position r1 and 1219 velocity v1 of body. 1220 1221 gm : Gravitational Constant. If set negative, its absolute value will 1222 be taken as gm and the perihelion distance will be returned 1223 instead of the semimajor axis. 1224 t0 : time of perihelion passage 1225 m0 : Mean Anomaly at epoch for elliptical orbits in degrees in the 1226 range 0 to 360. Set m0 = 0 for hyperbolic orbits. 1227 m0 will be set to -1 if perihelion distance is to be returned 1228 instead of a. 1229 a : semi-major axis for elliptical (positive) or hyperbolic orbits 1230 (negative). If m0 < 0, a signifies perihelion distance q instead. 1231 If gm is negative, the perihelion distance q will be returned 1232 ecc : eccentricity 1233 ran : Right Ascension of Ascending Node (in degrees) 1234 aper : Argument of Perihelion (in degrees) 1235 inc : Inclination (in degrees) 1236 1237 The units must be consistent with each other. 1238 */ 1239 const double rddg = 180.0/M_PI; 1240 const double p2 = 2.0*M_PI; 1241 1242 Vec3 c; 1243 double cabs, u, cu, su, p, r; 1244 int pflg; // 1, if perihelion distance to be returned 1245 1246 pflg = 0; 1247 if (gm < 0.0) 1248 { 1249 gm = -gm; 1250 pflg = 1; 1251 }; 1252 1253 if (gm < 1e-60) gm = 1e-60; 1254 c = r1 * v1; 1255 cabs = abs(c); 1256 if (fabs(cabs) < 1e-40) cabs = 1e-40; 1257 ran = atan20 (c[0], -c[1]); 1258 inc = c[2]/cabs; 1259 if (fabs(inc) <= 1.0) inc = acos (inc); 1260 else inc = 0; 1261 1262 r = abs(r1); 1263 if (fabs(r) < 1e-40) r = 1e-40; 1264 su = sin(inc); 1265 if (su != 0.0) su = r1[2]/su; 1266 cu = r1[0]*cos(ran)+r1[1]*sin(ran); 1267 u = atan20 (su, cu); // argument of latitude 1268 1269 a = abs(v1); 1270 a = 2.0/r - a*a/gm; 1271 if (fabs(a) < 1.0E-30) ecc = 1.0; // parabolic 1272 else 1273 { 1274 a = 1.0/a; // semimajor axis 1275 ecc = 0; 1276 }; 1277 1278 p = cabs*cabs/gm; // semilatum rectum 1279 1280 if (ecc == 1.0) 1281 { 1282 p = p / 2.0; // perihelion distance 1283 a = 2*p; 1284 } 1285 else 1286 { 1287 ecc = 1.0 - p/a; 1288 if (ecc >= 0) ecc = sqrt(ecc); 1289 else ecc = 0; 1290 p = p / (1.0 + ecc); // perihelion distance 1291 } 1292 1293 if (fabs(a) > 1e-60) cu = (1.0 - r/a); 1294 else cu = 0; // just in case 1295 su = dot(r1,v1) / sqrt(fabs(a)*gm); 1296 if (ecc < 1.0) 1297 { 1298 m0 = atan20(su,cu); // eccentric anomaly 1299 su = sin(m0); 1300 cu = cos(m0); 1301 aper = 1.0-ecc*ecc; 1302 if (aper >= 0) aper = atan20(sqrt(aper)*su,(cu-ecc)); // true anomaly 1303 m0 = m0 - ecc*su; // mean anomaly 1304 } 1305 else if (ecc > 1.0) 1306 { 1307 su = su / ecc; 1308 m0 = su + sqrt(su*su + 1.0); 1309 if (m0 >= 0) m0 = log(m0); // = asinh (su); hyperbolic anomaly 1310 aper = (ecc+1.0)/(ecc-1.0); 1311 if (aper >= 0) aper = 2.0 * atan(sqrt(aper)*tanh(m0/2.0)); 1312 m0 = ecc*su-m0; 1313 } 1314 1315 if (ecc != 1.0) 1316 { 1317 aper = u - aper; // argument of perihelion 1318 u = fabs(a); 1319 t0 = u/gm; 1320 if (t0 >= 0) t0 = t - u*sqrt(t0)*m0; // time of perihelion transit 1321 else t0 = t; 1322 } 1323 else // parabolic 1324 { 1325 pflg = 1; 1326 1327 aper = 2.0 * atan(su); // true anomaly 1328 aper = u - aper; // argument of perihelion 1329 t0 = 2.0*p*p*p/gm; 1330 if (t0 >= 0) t0 = t - sqrt(t0) * (su*su*su/3.0 + su); 1331 else t0 = t; 1332 } 1333 1334 if (m0 < 0.0) m0 = m0 + p2; 1335 if (ran < 0.0) ran = ran + p2; 1336 if (aper < 0.0) aper = aper + p2; 1337 m0 = rddg * m0; 1338 ran = rddg * ran; 1339 aper = rddg * aper; 1340 inc = rddg * inc; 1341 1342 if (ecc > 1.0) m0 = 0.0; 1343 if (pflg) 1344 { 1345 a = p; 1346 m0 = -1.0; 1347 } 1348 } 1349 1350 /*-------------------- QuickSun --------------------------------------*/ 1351 1352 Vec3 QuickSun (double t) // low precision position of the Sun at time t 1353 { 1354 /* Low precision position of the Sun at time t given in 1355 Julian centuries since J2000. 1356 Valid only between 1950 and 2050. 1357 1358 Returns the position vector (in A.U.) in ecliptic coordinates 1359 1360 */ 1361 double n, g, l; 1362 Vec3 rs; 1363 1364 n = 36525.0 * t; 1365 l = 280.460 + 0.9856474*n; // mean longitude 1366 g = 357.528 + 0.9856003*n; // mean anomaly 1367 l = 2.0*M_PI * frac(l/360.0); 1368 g = 2.0*M_PI * frac(g/360.0); 1369 l = l + (1.915*sin(g) + 0.020*sin(2.0*g)) * 1.74532925199e-2; // ecl.long. 1370 g = 1.00014 - 0.01671*cos(g) - 0.00014*cos(2.0*g); // radius 1371 rs[0] = g * cos(l); 1372 rs[1] = g * sin(l); 1373 rs[2] = 0; 1374 1375 return rs; 1376 } 1377 1378 /*-------------------- Class Sun200 --------------------------------------*/ 1379 /* 1380 Ecliptic coordinates (in A.U.) and velocity (in A.U./day) 1381 of the sun for Equinox of Date given in Julian centuries since J2000. 1382 ====================================================================== 1383 */ 1384 Sun200::Sun200 () 1385 { } 1386 1387 Vec3 Sun200::position (double t) // position of the Sun at time t 1388 { 1389 Vec3 rs, vs; 1390 1391 state (t, rs, vs); 1392 1393 return rs; 1394 } 1395 1396 void Sun200::state (double t, Vec3& rs, Vec3& vs) 1397 { 1398 /* State vector rs (position) and vs (velocity) of the Sun in 1399 ecliptic of date coordinates at time t (in Julian Centuries 1400 since J2000). 1401 */ 1402 const double p2 = 2.0 * M_PI; 1403 1404 double l, b, r; 1405 int i; 1406 1407 tt = t; 1408 1409 dl = 0.0; dr = 0.0; db = 0.0; 1410 m2 = p2 * frac(0.1387306 + 162.5485917*t); 1411 m3 = p2 * frac(0.9931266 + 99.9973604*t); 1412 m4 = p2 * frac(0.0543250 + 53.1666028*t); 1413 m5 = p2 * frac(0.0551750 + 8.4293972*t); 1414 m6 = p2 * frac(0.8816500 + 3.3938722*t); 1415 d = p2 * frac(0.8274 + 1236.8531*t); 1416 a= p2 * frac(0.3749 + 1325.5524*t); 1417 uu = p2 * frac(0.2591 + 1342.2278*t); 1418 1419 c3[1] = 1.0; s3[1] = 0.0; 1420 c3[2] = cos(m3); s3[2] = sin(m3); 1421 c3[0] = c3[2]; s3[0] = -s3[2]; 1422 1423 for (i=3; i<9; i++) 1424 addthe(c3[i-1],s3[i-1],c3[2],s3[2],c3[i],s3[i]); 1425 pertven(); pertmar(); pertjup(); pertsat(); pertmoo(); 1426 1427 dl = dl + 6.4 * sin(p2*(0.6983 + 0.0561*t)) 1428 + 1.87 * sin(p2*(0.5764 + 0.4174*t)) 1429 + 0.27 * sin(p2*(0.4189 + 0.3306*t)) 1430 + 0.20 * sin(p2*(0.3581 + 2.4814*t)); 1431 l = p2 * frac(0.7859453 + m3/p2 +((6191.2+1.1*t)*t+dl)/1296.0E3); 1432 r = 1.0001398 - 0.0000007*t + dr*1E-6; 1433 b = db * 4.8481368111E-6; 1434 1435 cl= cos(l); sl=sin(l); cb=cos(b); sb=sin(b); 1436 rs[0]=r*cl*cb; rs[1]=r*sl*cb; rs[2]=r*sb; 1437 1438 /* velocity calculation 1439 gms=2.9591202986e-4 AU^3/d^2 1440 e=0.0167086 1441 sqrt(gms/a)=1.7202085e-2 AU/d 1442 sqrt(gms/a)*sqrt(1-e^2)=1.71996836e-2 AU/d 1443 nu=M + 2e*sin(M) = M + 0.0334172 * sin(M) */ 1444 1445 uu = m3 + 0.0334172*sin(m3); // eccentric Anomaly E 1446 d = cos(uu); 1447 uu = sin(uu); 1448 a = 1.0 - 0.0167086*d; 1449 vs[0] = -1.7202085e-2*uu/a; // velocity in orbit plane 1450 vs[1] = 1.71996836e-2*d/a; 1451 uu = atan2 (0.9998604*uu, (d-0.0167086)); // true anomaly 1452 d = cos(uu); 1453 uu = sin(uu); 1454 dr = d*vs[0]+uu*vs[1]; 1455 dl = (d*vs[1]-uu*vs[0]) / r; 1456 1457 vs[0] = dr*cl*cb - dl*r*sl*cb; 1458 vs[1] = dr*sl*cb + dl*r*cl*cb; 1459 vs[2] = dr*sb; 1460 } 1461 1462 void Sun200::addthe (double c1, double s1, double c2, double s2, 1463 double& cc, double& ss) 1464 { 1465 cc=c1*c2-s1*s2; 1466 ss=s1*c2+c1*s2; 1467 } 1468 1469 void Sun200::term (int i1, int i, int it, double dlc, double dls, double drc, 1470 double drs, double dbc, double dbs) 1471 { 1472 if (it == 0) addthe (c3[i1+1],s3[i1+1],c[i+8],s[i+8],u,v); 1473 else 1474 { 1475 u=u*tt; 1476 v=v*tt; 1477 } 1478 dl = dl + dlc*u + dls*v; 1479 dr = dr + drc*u + drs*v; 1480 db = db + dbc*u + dbs*v; 1481 } 1482 1483 void Sun200::pertven() // Kepler terms and perturbations by Venus 1484 { 1485 int i; 1486 1487 c[8]=1.0; s[8]=0.0; c[7]=cos(m2); s[7]=-sin(m2); 1488 for (i=7; i>2; i--) 1489 addthe(c[i],s[i],c[7],s[7],c[i-1],s[i-1]); 1490 1491 term (1, 0, 0, -0.22, 6892.76, -16707.37, -0.54, 0.0, 0.0); 1492 term (1, 0, 1, -0.06, -17.35, 42.04, -0.15, 0.0, 0.0); 1493 term (1, 0, 2, -0.01, -0.05, 0.13, -0.02, 0.0, 0.0); 1494 term (2, 0, 0, 0.0, 71.98, -139.57, 0.0, 0.0, 0.0); 1495 term (2, 0, 1, 0.0, -0.36, 0.7, 0.0, 0.0, 0.0); 1496 term (3, 0, 0, 0.0, 1.04, -1.75, 0.0, 0.0, 0.0); 1497 term (0, -1, 0, 0.03, -0.07, -0.16, -0.07, 0.02, -0.02); 1498 term (1, -1, 0, 2.35, -4.23, -4.75, -2.64, 0.0, 0.0); 1499 term (1, -2, 0, -0.1, 0.06, 0.12, 0.2, 0.02, 0.0); 1500 term (2, -1, 0, -0.06, -0.03, 0.2, -0.01, 0.01, -0.09); 1501 term (2, -2, 0, -4.7, 2.9, 8.28, 13.42, 0.01, -0.01); 1502 term (3, -2, 0, 1.8, -1.74, -1.44, -1.57, 0.04, -0.06); 1503 term (3, -3, 0, -0.67, 0.03, 0.11, 2.43, 0.01, 0.0); 1504 term (4, -2, 0, 0.03, -0.03, 0.1, 0.09, 0.01, -0.01); 1505 term (4, -3, 0, 1.51, -0.4, -0.88, -3.36, 0.18, -0.1); 1506 term (4, -4, 0, -0.19, -0.09, -0.38, 0.77, 0.0, 0.0); 1507 term (5, -3, 0, 0.76, -0.68, 0.3, 0.37, 0.01, 0.0); 1508 term (5, -4, 0, -0.14, -0.04, -0.11, 0.43, -0.03, 0.0); 1509 term (5, -5, 0, -0.05, -0.07, -0.31, 0.21, 0.0, 0.0); 1510 term (6, -4, 0, 0.15, -0.04, -0.06, -0.21, 0.01, 0.0); 1511 term (6, -5, 0, -0.03, -0.03, -0.09, 0.09, -0.01, 0.0); 1512 term (6, -6, 0, 0.0, -0.04, -0.18, 0.02, 0.0, 0.0); 1513 term (7, -5, 0, -0.12, -0.03, -0.08, 0.31, -0.02, -0.01); 1514 } 1515 1516 void Sun200::pertmar() // Kepler terms and perturbations by Mars 1517 { 1518 int i; 1519 1520 c[7] = cos(m4); s[7] = -sin(m4); 1521 for (i=7; i>0; i--) 1522 addthe(c[i],s[i],c[7],s[7],c[i-1],s[i-1]); 1523 term (1, -1, 0, -0.22, 0.17, -0.21, -0.27, 0.0, 0.0); 1524 term (1, -2, 0, -1.66, 0.62, 0.16, 0.28, 0.0, 0.0); 1525 term (2, -2, 0, 1.96, 0.57, -1.32, 4.55, 0.0, 0.01); 1526 term (2, -3, 0, 0.4, 0.15, -0.17, 0.46, 0.0, 0.0); 1527 term (2, -4, 0, 0.53, 0.26, 0.09, -0.22, 0.0, 0.0); 1528 term (3, -3, 0, 0.05, 0.12, -0.35, 0.15, 0.0, 0.0); 1529 term (3, -4, 0, -0.13, -0.48, 1.06, -0.29, 0.01, 0.0); 1530 term (3, -5, 0, -0.04, -0.2, 0.2, -0.04, 0.0, 0.0); 1531 term (4, -4, 0, 0.0, -0.03, 0.1, 0.04, 0.0, 0.0); 1532 term (4, -5, 0, 0.05, -0.07, 0.2, 0.14, 0.0, 00); 1533 term (4, -6, 0, -0.1, 0.11, -0.23, -0.22, 0.0, 0.0); 1534 term (5, -7, 0, -0.05, 0.0, 0.01, -0.14, 0.0, 0.0); 1535 term (5, -8, 0, 0.05, 0.01, -0.02, 0.1, 0.0, 0.0); 1536 } 1537 1538 void Sun200::pertjup() // Kepler terms and perturbations by Jupiter 1539 { 1540 int i; 1541 1542 c[7] = cos(m5); s[7] = -sin(m5); 1543 for (i=7; i>4; i--) 1544 addthe(c[i],s[i],c[7],s[7],c[i-1],s[i-1]); 1545 term (1, -1, 0, 0.01, 0.07, 0.18, -0.02, 0.0, -0.02); 1546 term (0, -1, 0, -0.31, 2.58, 0.52, 0.34, 0.02, 0.0); 1547 term (1, -1, 0, -7.21, -0.06, 0.13, -16.27, 0.0, -0.02); 1548 term (1, -2, 0, -0.54, -1.52, 3.09, -1.12, 0.01, -0.17); 1549 term (1, -3, 0, -0.03, -0.21, 0.38, -0.06, 0.0, -0.02); 1550 term (2, -1, 0, -0.16, 0.05, -0.18, -0.31, 0.01, 0.0); 1551 term (2, -2, 0, 0.14, -2.73, 9.23, 0.48, 0.0, 0.0); 1552 term (2, -3, 0, 0.07, -0.55, 1.83, 0.25, 0.01, 0.0); 1553 term (2, -4, 0, 0.02, -0.08, 0.25, 0.06, 0.0, 0.0); 1554 term (3, -2, 0, 0.01, -0.07, 0.16, 0.04, 0.0, 0.0); 1555 term (3, -3, 0, -0.16, -0.03, 0.08, -0.64, 0.0, 0.0); 1556 term (3, -4, 0, -0.04, -0.01, 0.03, -0.17, 0.0, 0.0); 1557 } 1558 1559 void Sun200::pertsat() // Kepler terms and perturbations by Saturn 1560 { 1561 c[7] = cos(m6); s[7] = -sin(m6); 1562 addthe(c[7],s[7],c[7],s[7],c[6],s[6]); 1563 term (0, -1, 0, 0.0, 0.32, 0.01, 0.0, 0.0, 0.0); 1564 term (1, -1, 0, -0.08, -0.41, 0.97, -0.18, 0.0, -0.01); 1565 term (1, -2, 0, 0.04, 0.1, -0.23, 0.1, 0.0, 0.0); 1566 term (2, -2, 0, 0.04, 0.1, -0.35, 0.13, 0.0, 0.0); 1567 } 1568 1569 void Sun200::pertmoo() // corrections for Earth-Moon center of gravity 1570 { 1571 dl = dl + 6.45*sin(d) - 0.42*sin(d-a) + 0.18*sin(d+a) + 0.17*sin(d-m3) - 0.06*sin(d+m3); 1572 dr = dr + 30.76*cos(d) - 3.06*cos(d-a) + 0.85*cos(d+a) - 0.58*cos(d+m3) + 0.57*cos(d-m3); 1573 db = db + 0.576*sin(uu); 1574 } 1575 1576 /*--------------------- Class moon200 ----------------------------------*/ 1577 1578 /* 1579 Position vector (in Earth radii) of the Moon referred to Ecliptic 1580 for Equinox of Date. 1581 t is the time in Julian centuries since J2000. 1582 */ 1583 1584 Moon200::Moon200 () 1585 { } 1586 1587 Vec3 Moon200::position (double t) // position of the Moon at time t 1588 { 1589 Vec3 rm; 1590 1591 const double arc = 206264.81; // 3600*180/pi = ''/r 1592 const double pi2 = M_PI * 2.0; 1593 1594 double lambda, beta, r, fac; 1595 1596 minit(t); 1597 solar1(); solar2(); solar3(); solarn(n); planetary(t); 1598 1599 lambda = pi2 * frac ((l0+dlam/arc) / pi2); 1600 if (lambda < 0) lambda = lambda + pi2; 1601 s = f + ds / arc; 1602 1603 fac = 1.000002708 + 139.978 * dgam; 1604 beta = (fac*(18518.511+1.189+gam1c)*sin(s)-6.24*sin(3*s)+n); 1605 beta = beta * 4.8481368111e-6; 1606 sinpi = sinpi * 0.999953253; 1607 r = arc / sinpi; 1608 1609 rm.assign (r, lambda, beta); 1610 rm = polcar(rm); 1611 1612 return rm; 1613 } 1614 1615 1616 void Moon200::addthe (double c1, double s1, double c2, double s2, 1617 double& c, double& s) 1618 { 1619 c=c1*c2-s1*s2; 1620 s=s1*c2+c1*s2; 1621 } 1622 1623 double Moon200::sinus (double phi) 1624 { 1625 /* sin(phi) in units of 1r = 360ø */ 1626 return sin (2.0*M_PI * frac(phi)); 1627 } 1628 1629 void Moon200::long_periodic (double t) 1630 { 1631 /* long periodic changes of mean elements */ 1632 1633 double s1, s2, s3, s4, s5, s6, s7; 1634 1635 s1 = sinus (0.19833 + 0.05611*t); 1636 s2 = sinus (0.27869 + 0.04508*t); 1637 s3 = sinus (0.16827 - 0.36903*t); 1638 s4 = sinus (0.34734 - 5.37261*t); 1639 s5 = sinus (0.10498 - 5.37899*t); 1640 s6 = sinus (0.42681 - 0.41855*t); 1641 s7 = sinus (0.14943 - 5.37511*t); 1642 dl0 = 0.84*s1 + 0.31*s2 + 14.27*s3 + 7.26*s4 + 0.28*s5 + 0.24*s6; 1643 dl = 2.94*s1 + 0.31*s2 + 14.27*s3 + 9.34*s4 + 1.12*s5 + 0.83*s6; 1644 dls = -6.4*s1 - 1.89*s6; 1645 df = 0.21*s1+0.31*s2+14.27*s3-88.7*s4-15.3*s5+0.24*s6-1.86*s7; 1646 dd = dl0 - dls; 1647 dgam = -3332E-9 * sinus (0.59734 - 5.37261*t) 1648 -539E-9 * sinus (0.35498 - 5.37899*t) 1649 -64E-9 * sinus (0.39943 - 5.37511*t); 1650 } 1651 1652 void Moon200::minit(double t) 1653 { 1654 /* calculate mean elements l (moon), F (node distance) 1655 l' (sun) and D (moon's elongation) */ 1656 1657 const double arc = 206264.81; // 3600*180/pi = ''/r 1658 const double pi2 = M_PI * 2.0; 1659 1660 int i, j, max; 1661 double t2, arg, fac; 1662 1663 max = 0; // just to keep the compiler happy 1664 arg = 0; 1665 fac = 0; 1666 1667 t2 = t * t; 1668 dlam = 0; ds = 0; gam1c = 0; sinpi = 3422.7; 1669 long_periodic (t); 1670 l0 = pi2*frac(0.60643382+1336.85522467*t-0.00000313*t2) + dl0/arc; 1671 l = pi2*frac(0.37489701+1325.55240982*t+0.00002565*t2) + dl/arc; 1672 ls = pi2*frac(0.99312619+99.99735956*t-0.00000044*t2) + dls/arc; 1673 f = pi2*frac(0.25909118+1342.22782980*t-0.00000892*t2) + df/arc; 1674 d = pi2*frac(0.82736186+1236.85308708*t-0.00000397*t2) + dd/arc; 1675 for (i=0; i<4; i++) 1676 { 1677 switch (i) 1678 { 1679 case 0: arg=l; max=4; fac=1.000002208; break; 1680 case 1: arg=ls; max=3; fac=0.997504612-0.002495388*t; break; 1681 case 2: arg=f; max=4; fac=1.000002708+139.978*dgam; break; 1682 case 3: arg=d; max=6; fac=1.0; break; 1683 } 1684 co[6][i] = 1.0; co[7][i] = cos (arg) * fac; 1685 si[6][i] = 0.0; si[7][i] = sin (arg) * fac; 1686 for (j = 2; j <= max; j++) 1687 addthe(co[j+5][i],si[j+5][i],co[7][i],si[7][i],co[j+6][i],si[j+6][i]); 1688 for (j = 1; j <= max; j++) 1689 { 1690 co[6-j][i]=co[j+6][i]; 1691 si[6-j][i]=-si[j+6][i]; 1692 } 1693 } 1694 } 1695 1696 void Moon200::term (int p, int q, int r, int s, double& x, double& y) 1697 { 1698 // calculate x=cos(p*arg1+q*arg2...); y=sin(p*arg1+q*arg2...) 1699 int i[4]; 1700 int k; 1701 1702 i[0]=p; i[1]=q; i[2]=r; i[3]=s; x=1.0; y=0.0; 1703 for (k=0; k<4; k++) 1704 if (i[k]!=0) addthe(x,y,co[i[k]+6][k],si[i[k]+6][k],x,y); 1705 } 1706 1707 void Moon200::addsol(double coeffl, double coeffs, double coeffg, 1708 double coeffp, int p, int q, int r, int s) 1709 { 1710 double x, y; 1711 term (p,q,r,s,x,y); 1712 dlam = dlam + coeffl*y; ds = ds + coeffs*y; 1713 gam1c = gam1c + coeffg*x; sinpi = sinpi + coeffp*x; 1714 } 1715 1716 void Moon200::solar1() 1717 { 1718 addsol ( 13.902, 14.06, -0.001, 0.2607, 0, 0, 0, 4); 1719 addsol ( 0.403, -4.01, 0.394, 0.0023, 0, 0, 0, 3); 1720 addsol ( 2369.912, 2373.36, 0.601, 28.2333, 0, 0, 0, 2); 1721 addsol ( -125.154, -112.79, -0.725, -0.9781, 0, 0, 0, 1); 1722 addsol ( 1.979, 6.98, -0.445, 0.0433, 1, 0, 0, 4); 1723 addsol (191.953, 192.72, 0.029, 3.0861, 1, 0, 0, 2); 1724 addsol (-8.466, -13.51, 0.455, -0.1093, 1, 0, 0, 1); 1725 addsol (22639.5, 22609.07, 0.079, 186.5398, 1, 0, 0, 0); 1726 addsol (18.609, 3.59, -0.094, 0.0118, 1, 0, 0, -1); 1727 addsol (-4586.465, -4578.13, -0.077, 34.3117, 1, 0, 0, -2); 1728 addsol (3.215, 5.44, 0.192, -0.0386, 1, 0, 0, -3); 1729 addsol (-38.428, -38.64, 0.001, 0.6008, 1, 0, 0, -4); 1730 addsol (-0.393, -1.43, -0.092, 0.0086, 1, 0, 0, -6); 1731 addsol (-0.289, -1.59, 0.123, -0.0053, 0, 1, 0, 4); 1732 addsol (-24.420, -25.1, 0.04, -0.3, 0, 1, 0, 2); 1733 addsol (18.023, 17.93, 0.007, 0.1494, 0, 1, 0, 1); 1734 addsol (-668.146, -126.98, -1.302, -0.3997, 0, 1, 0, 0); 1735 addsol (0.56, 0.32, -0.001, -0.0037, 0, 1, 0, -1); 1736 addsol (-165.145, -165.06, 0.054, 1.9178, 0, 1, 0, -2); 1737 addsol (-1.877, -6.46, -0.416, 0.0339, 0, 1, 0, -4); 1738 addsol (0.213, 1.02, -0.074, 0.0054, 2, 0, 0, 4); 1739 addsol (14.387, 14.78, -0.017, 0.2833, 2, 0, 0, 2); 1740 addsol (-0.586, -1.2, 0.054, -0.01, 2, 0, 0, 1); 1741 addsol (769.016, 767.96, 0.107, 10.1657, 2, 0, 0, 0); 1742 addsol (1.75, 2.01, -0.018, 0.0155, 2, 0, 0, -1); 1743 addsol (-211.656, -152.53, 5.679, -0.3039, 2, 0, 0, -2); 1744 addsol (1.225, 0.91, -0.03, -0.0088, 2, 0, 0, -3); 1745 addsol (-30.773, -34.07, -0.308, 0.3722, 2, 0, 0, -4); 1746 addsol (-0.57, -1.4, -0.074, 0.0109, 2, 0, 0, -6); 1747 addsol (-2.921, -11.75, 0.787, -0.0484, 1, 1, 0, 2); 1748 addsol (1.267, 1.52, -0.022, 0.0164, 1, 1, 0, 1); 1749 addsol (-109.673, -115.18, 0.461, -0.949, 1, 1, 0, 0); 1750 addsol (-205.962, -182.36, 2.056, 1.4437, 1, 1, 0, -2); 1751 addsol (0.233, 0.36, 0.012, -0.0025, 1, 1, 0, -3); 1752 addsol (-4.391, -9.66, -0.471, 0.0673, 1, 1, 0, -4); 1753 } 1754 1755 void Moon200::solar2() 1756 { 1757 addsol (0.283, 1.53, -0.111, 0.006, 1, -1, 0, 4); 1758 addsol (14.577, 31.7, -1.54, 0.2302, 1, -1, 0, 2); 1759 addsol (147.687, 138.76, 0.679, 1.1528, 1, -1, 0, 0); 1760 addsol (-1.089, 0.55, 0.021, 0.0, 1, -1, 0, -1); 1761 addsol (28.475, 23.59, -0.443, -0.2257, 1, -1, 0, -2); 1762 addsol (-0.276, -0.38, -0.006, -0.0036, 1, -1, 0, -3); 1763 addsol (0.636, 2.27, 0.146, -0.0102, 1, -1, 0, -4); 1764 addsol (-0.189, -1.68, 0.131, -0.0028, 0, 2, 0, 2); 1765 addsol (-7.486, -0.66, -0.037, -0.0086, 0, 2, 0, 0); 1766 addsol (-8.096, -16.35, -0.74, 0.0918, 0, 2, 0, -2); 1767 addsol (-5.741, -0.04, 0.0, -0.0009, 0, 0, 2, 2); 1768 addsol (0.255, 0.0, 0.0, 0.0, 0, 0, 2, 1); 1769 addsol (-411.608, -0.2, 0.0, -0.0124, 0, 0, 2, 0); 1770 addsol (0.584, 0.84, 0.0, 0.0071, 0, 0, 2, -1); 1771 addsol (-55.173, -52.14, 0.0, -0.1052, 0, 0, 2, -2); 1772 addsol (0.254, 0.25, 0.0, -0.0017, 0, 0, 2, -3); 1773 addsol (0.025, -1.67, 0.0, 0.0031, 0, 0, 2, -4); 1774 addsol (1.06, 2.96, -0.166, 0.0243, 3, 0, 0, 2); 1775 addsol (36.124, 50.64, -1.3, 0.6215, 3, 0, 0, 0); 1776 addsol (-13.193, -16.4, 0.258, -0.1187, 3, 0, 0, -2); 1777 addsol (-1.187, -0.74, 0.042, 0.0074, 3, 0, 0, -4); 1778 addsol (-0.293, -0.31, -0.002, 0.0046, 3, 0, 0, -6); 1779 addsol (-0.29, -1.45, 0.116, -0.0051, 2, 1, 0, 2); 1780 addsol (-7.649, -10.56, 0.259, -0.1038, 2, 1, 0, 0); 1781 addsol (-8.627, -7.59, 0.078, -0.0192, 2, 1, 0, -2); 1782 addsol (-2.74, -2.54, 0.022, 0.0324, 2, 1, 0, -4); 1783 addsol (1.181, 3.32, -0.212, 0.0213, 2, -1, 0, 2); 1784 addsol (9.703, 11.67, -0.151, 0.1268, 2, -1, 0, 0); 1785 addsol (-0.352, -0.37, 0.001, -0.0028, 2, -1, 0, -1); 1786 addsol (-2.494, -1.17, -0.003, -0.0017, 2, -1, 0, -2); 1787 addsol (0.36, 0.2, -0.012, -0.0043, 2, -1, 0, -4); 1788 addsol (-1.167, -1.25, 0.008, -0.0106, 1, 2, 0, 0); 1789 addsol (-7.412, -6.12, 0.117, 0.0484, 1, 2, 0, -2); 1790 addsol (-0.311, -0.65, -0.032, 0.0044, 1, 2, 0, -4); 1791 addsol (0.757, 1.82, -0.105, 0.0112, 1, -2, 0, 2); 1792 addsol (2.58, 2.32, 0.027, 0.0196, 1, -2, 0, 0); 1793 addsol (2.533, 2.4, -0.014, -0.0212, 1, -2, 0, -2); 1794 addsol (-0.344, -0.57, -0.025, 0.0036, 0, 3, 0, -2); 1795 addsol (-0.992, -0.02, 0.0, 0.0, 1, 0, 2, 2); 1796 addsol (-45.099, -0.02, 0.0, -0.0010, 1, 0, 2, 0); 1797 addsol (-0.179, -9.52, 0.0, -0.0833, 1, 0, 2, -2); 1798 addsol (-0.301, -0.33, 0.0, 0.0014, 1, 0, 2, -4); 1799 addsol (-6.382, -3.37, 0.0, -0.0481, 1, 0, -2, 2); 1800 addsol (39.528, 85.13, 0.0, -0.7136, 1, 0, -2, 0); 1801 addsol (9.366, 0.71, 0.0, -0.0112, 1, 0, -2, -2); 1802 addsol (0.202, 0.02, 0.0, 0.0, 1, 0, -2, -4); 1803 } 1804 1805 void Moon200::solar3() 1806 { 1807 addsol (0.415, 0.1, 0.0, 0.0013, 0, 1, 2, 0); 1808 addsol (-2.152, -2.26, 0.0, -0.0066, 0, 1, 2, -2); 1809 addsol (-1.44, -1.3, 0.0, 0.0014, 0, 1, -2, 2); 1810 addsol (0.384, -0.04, 0.0, 0.0, 0, 1, -2, -2); 1811 addsol (1.938, 3.6, -0.145, 0.0401, 4, 0, 0, 0); 1812 addsol (-0.952, -1.58, 0.052, -0.0130, 4, 0, 0, -2); 1813 addsol (-0.551, -0.94, 0.032, -0.0097, 3, 1, 0, 0); 1814 addsol (-0.482, -0.57, 0.005, -0.0045, 3, 1, 0, -2); 1815 addsol (0.681, 0.96, -0.026, 0.0115, 3, -1, 0, 0); 1816 addsol (-0.297, -0.27, 0.002, -0.0009, 2, 2, 0, -2); 1817 addsol (0.254, 0.21, -0.003, 0.0, 2, -2, 0, -2); 1818 addsol (-0.25, -0.22, 0.004, 0.0014, 1, 3, 0, -2); 1819 addsol (-3.996, 0.0, 0.0, 0.0004, 2, 0, 2, 0); 1820 addsol (0.557, -0.75, 0.0, -0.009, 2, 0, 2, -2); 1821 addsol (-0.459, -0.38, 0.0, -0.0053, 2, 0, -2, 2); 1822 addsol (-1.298, 0.74, 0.0, 0.0004, 2, 0, -2, 0); 1823 addsol (0.538, 1.14, 0.0, -0.0141, 2, 0, -2, -2); 1824 addsol (0.263, 0.02, 0.0, 0.0, 1, 1, 2, 0); 1825 addsol (0.426, 0.07, 0.0, -0.0006, 1, 1, -2, -2); 1826 addsol (-0.304, 0.03, 0.0, 0.0003, 1, -1, 2, 0); 1827 addsol (-0.372, -0.19, 0.0, -0.0027, 1, -1, -2, 2); 1828 addsol (0.418, 0.0, 0.0, 0.0, 0, 0, 4, 0); 1829 addsol (-0.330, -0.04, 0.0, 0.0, 3, 0, 2, 0); 1830 } 1831 1832 void Moon200::addn (double coeffn, int p, int q, int r, int s, 1833 double& n, double&x, double& y) 1834 { 1835 term (p,q,r,s,x,y); 1836 n=n+coeffn*y; 1837 } 1838 1839 void Moon200::solarn (double& n) 1840 { 1841 // perturbation N of ecliptic latitude 1842 double x, y; 1843 1844 n = 0.0; 1845 addn (-526.069, 0, 0, 1, -2, n, x, y); 1846 addn (-3.352, 0, 0, 1, -4, n, x, y); 1847 addn (44.297, 1, 0, 1, -2, n, x, y); 1848 addn (-6.0, 1, 0, 1, -4, n, x, y); 1849 addn (20.599, -1, 0, 1, 0, n, x, y); 1850 addn (-30.598, -1, 0, 1, -2, n, x, y); 1851 addn (-24.649, -2, 0, 1, 0, n, x, y); 1852 addn (-2.0, -2, 0, 1, -2, n, x, y); 1853 addn (-22.571, 0, 1, 1, -2, n, x, y); 1854 addn (10.985, 0, -1, 1, -2, n, x, y); 1855 } 1856 1857 void Moon200::planetary (double t) 1858 { 1859 // perturbations of the ecliptic longitude by Venus and Jupiter 1860 1861 dlam = dlam 1862 + 0.82*sinus(0.7736 -62.5512*t)+0.31*sinus(0.0466-125.1025*t) 1863 + 0.35*sinus(0.5785-25.1042*t)+0.66*sinus(0.4591+1335.8075*t) 1864 + 0.64*sinus(0.313-91.568*t)+1.14*sinus(0.148+1331.2898*t) 1865 + 0.21*sinus(0.5918+1056.5859*t)+0.44*sinus(0.5784+1322.8595*t) 1866 + 0.24*sinus(0.2275-5.7374*t)+0.28*sinus(0.2965+2.6929*t) 1867 + 0.33*sinus(0.3132+6.3368*t); 1868 } 1869 1870 /*-------------------- Class Eclipse --------------------------------------*/ 1871 /* 1872 Calculalations for Solar and Lunar Eclipses 1873 */ 1874 1875 Eclipse::Eclipse() 1876 { 1877 // some assignments just in case 1878 rs.assign(1,0,0); 1879 rm.assign(1,0,0); 1880 eshadow.assign (1,0,0); 1881 rint.assign (1,0,0); 1882 d_umbra = 0; 1883 ep2 = 0; 1884 } 1885 1886 int Eclipse::solar (double jd, double tdut, double& phi, double& lamda) 1887 { 1888 /* Calculates various items about a solar eclipse. 1889 INPUT: 1890 jd = Modified Julian Date (UT) 1891 tdut = TDT - UT in sec 1892 1893 OUTPUT: 1894 phi, lamda: Geographic latitude and longitude (in radians) 1895 of center of shadow if central eclipse 1896 1897 RETURN: 1898 0 : No eclipse 1899 1 : Partial eclipse 1900 2 : Non-central annular eclipse 1901 3 : Non-central total eclipse 1902 4 : Annular eclipse 1903 5 : Total eclipse 1904 */ 1905 1906 const double flat = 0.996633; // flatting of the Earth 1907 const double ds = 218.245445; // diameter of Sun in Earth radii 1908 const double dm = 0.544986; // diameter of Moon in Earth radii 1909 double s0, s, dlt, r2, r0; 1910 int phase; 1911 Vec3 ve; 1912 1913 // get the apparent equatorial coordinates of the sun and the moon 1914 equ_sun_moon(jd, tdut); 1915 1916 rs[2]/=flat; // adjust for flatting of the Earth 1917 rm[2]/=flat; 1918 rint.assign (); 1919 lamda = 0; 1920 phi = 0; 1921 1922 // intersect shadow axis with Earth 1923 eshadow = rm - rs; 1924 eshadow = vnorm(eshadow); // direction vector of shadow 1925 1926 s0 = - dot(rm, eshadow); // distance Moon - fundamental plane 1927 r2 = dot (rm,rm); 1928 dlt = s0*s0 + 1.0 - r2; 1929 r0 = 1.0 - dlt; 1930 if (r0 > 0) r0 = sqrt (r0); 1931 else r0 = 0; // distance center of Earth - shadow axis 1932 1933 r2 = abs(rs - rm); 1934 d_umbra = (ds - dm) * s0 / r2 - dm;// diameter of umbra at fundamental plane 1935 d_penumbra = (ds + dm) * s0 / r2 + dm; 1936 1937 // get phase of eclipse 1938 if (r0 < 1.0) 1939 { 1940 if (dlt > 0) dlt = sqrt(dlt); 1941 else dlt = 0; 1942 s = s0 - dlt; // distance Moon - fundamental plane 1943 d_umbra = (ds - dm) * s / r2 - dm; // diameter of umbra at surface 1944 rint = rm + s * eshadow; 1945 rint[2] *= flat; // vector to intersection 1946 ve = carpol(rint); 1947 lamda = ve[1] - lsidtim(jd,0,ep2)*0.261799387799; // geographic coordinates 1948 if (lamda > M_PI) lamda -= 2.0*M_PI; 1949 if (lamda < (-M_PI)) lamda += 2.0*M_PI; 1950 phi = sqrt(rint[0]*rint[0] + rint[1]*rint[1])*0.993305615; 1951 phi = atan2(rint[2],phi); 1952 1953 if (d_umbra > 0) phase = 4; // central annular eclipse 1954 else phase = 5; // central total eclipse 1955 } 1956 else 1957 { 1958 if (r0 < (1.0 + 0.5 * fabs(d_umbra))) 1959 { 1960 if (d_umbra > 0) phase = 2; // non-central annular eclipse 1961 else phase = 3; // non-central total eclipse 1962 } 1963 else 1964 { 1965 if (r0 < (1.0 + 0.5*d_penumbra)) phase = 1; // partial eclipse 1966 else phase = 0; // no eclipse 1967 } 1968 } 1969 1970 rs[2]*=flat; // restore from flatting of the Earth 1971 rm[2]*=flat; 1972 1973 return phase; 1974 } 1975 1976 void Eclipse::maxpos (double jd, double tdut, double& phi, double& lamda) 1977 { 1978 /* Calculates the geographic position of the place of maximum eclipse 1979 at the time jd for a non-central eclipse. (NOTE that in case of 1980 a central eclipse the maximum position will be calculated by 1981 function solar. Do not use this function in that case as the 1982 result would be incorrect! No check is being done in this routine 1983 whether an eclipse is visible at all. Use maxpos only in case of a 1984 confirmed partial or non-central eclipse. 1985 1986 INPUT: 1987 jd = Modified Julian Date (UT) 1988 tdut = TDT - UT in sec 1989 1990 OUTPUT: 1991 phi, lamda: Geographic latitude and longitude (in radians) 1992 of maximum eclipse at the time 1993 */ 1994 1995 const double flat = 0.996633; // flatting of the Earth 1996 double s0; 1997 Vec3 ve; 1998 1999 // get the apparent equatorial coordinates of the sun and the moon 2000 equ_sun_moon(jd, tdut); 2001 2002 rs[2]/=flat; // adjust for flatting of the Earth 2003 rm[2]/=flat; 2004 rint.assign (); 2005 lamda = 0; 2006 phi = 0; 2007 2008 // intersect shadow axis with Earth 2009 eshadow = rm - rs; 2010 eshadow = vnorm(eshadow); // direction vector of shadow 2011 2012 s0 = - dot(rm, eshadow); // distance Moon - fundamental plane 2013 rint = rm + s0 * eshadow; 2014 rint = vnorm(rint); // normalize to 1 Earth radius 2015 rint[2] *= flat; // vector to position of maximum eclipse 2016 ve = carpol(rint); 2017 2018 lamda = ve[1] - lsidtim(jd,0,ep2)*0.261799387799; // geographic coordinates 2019 if (lamda > M_PI) lamda -= 2.0*M_PI; 2020 if (lamda < (-M_PI)) lamda += 2.0*M_PI; 2021 phi = sqrt(rint[0]*rint[0] + rint[1]*rint[1])*0.993305615; 2022 phi = atan2(rint[2],phi); 2023 2024 rs[2]*=flat; // restore from flatting of the Earth 2025 rm[2]*=flat; 2026 } 2027 2028 void Eclipse::penumd (double jd, double tdut, Vec3& vrm, Vec3& ves, 2029 double& dpn, double& pang) 2030 { 2031 /* Calculates various items needed for finding out the northern and 2032 southern border of the penumbra during a solar eclipse. 2033 2034 INPUT: 2035 jd = Modified Julian Date (UT) 2036 tdut = TDT - UT in sec 2037 2038 OUTPUT: 2039 vrm = position vector of Moon adjusted for flattening 2040 ves = unit vector pointing into the direction of the center of the shadow 2041 dpn = diameter of the penumbra at the fundamental plane 2042 pang = angle of penumbral half-cone in radians 2043 */ 2044 2045 const double flat = 0.996633; // flatting of the Earth 2046 const double ds = 218.245445; // diameter of Sun in Earth radii 2047 const double dm = 0.544986; // diameter of Moon in Earth radii 2048 double s0, r2; 2049 2050 // get the apparent equatorial coordinates of the sun and the moon 2051 equ_sun_moon(jd, tdut); 2052 rs[2]/=flat; // adjust for flatting of the Earth 2053 rm[2]/=flat; 2054 2055 // intersect shadow axis with Earth 2056 eshadow = rm - rs; 2057 pang = abs(eshadow); 2058 eshadow = vnorm(eshadow); // direction vector of shadow 2059 ves = eshadow; 2060 vrm = rm; 2061 2062 s0 = - dot(rm, eshadow); // distance Moon - fundamental plane 2063 2064 r2 = abs(rs - rm); 2065 dpn = (ds + dm) * s0 / r2 + dm; 2066 2067 // penumbral angle 2068 pang = asin((dm + ds) / (2.0 * pang)); 2069 2070 rs[2]*=flat; // restore from flatting of the Earth 2071 rm[2]*=flat; 2072 } 2073 2074 void Eclipse::umbra (double jd, double tdut, Vec3& vrm, Vec3& ves, 2075 double& dpn, double& pang) 2076 { 2077 /* Calculates various items needed for finding out the northern and 2078 southern border of the umbra during a solar eclipse. 2079 2080 INPUT: 2081 jd = Modified Julian Date (UT) 2082 tdut = TDT - UT in sec 2083 2084 OUTPUT: 2085 vrm = position vector of Moon adjusted for flattening 2086 ves = unit vector pointing into the direction of the center of the shadow 2087 dpn = diameter of the umbra at the fundamental plane 2088 pang = angle of umbral half-cone in radians 2089 */ 2090 2091 const double flat = 0.996633; // flatting of the Earth 2092 const double ds = 218.245445; // diameter of Sun in Earth radii 2093 const double dm = 0.544986; // diameter of Moon in Earth radii 2094 double s0, r2; 2095 2096 // get the apparent equatorial coordinates of the sun and the moon 2097 equ_sun_moon(jd, tdut); 2098 rs[2]/=flat; // adjust for flatting of the Earth 2099 rm[2]/=flat; 2100 2101 // intersect shadow axis with Earth 2102 eshadow = rm - rs; 2103 pang = abs(eshadow); 2104 eshadow = vnorm(eshadow); // direction vector of shadow 2105 ves = eshadow; 2106 vrm = rm; 2107 2108 s0 = - dot(rm, eshadow); // distance Moon - fundamental plane 2109 2110 r2 = abs(rs - rm); 2111 dpn = (ds - dm) * s0 / r2 - dm; 2112 2113 // umbral angle 2114 pang = asin((ds - dm) / (2.0 * pang)); 2115 2116 rs[2]*=flat; // restore from flatting of the Earth 2117 rm[2]*=flat; 2118 } 2119 2120 void Eclipse::equ_sun_moon(double jd, double tdut) 2121 { 2122 /* Get the equatorial coordinates of the Sun and the Moon and 2123 store them in rs and rm. 2124 Also store the time t in Julian Centuries and the correction 2125 ep2 for the Apparent Sidereal Time. 2126 jd = Modified Julian Date (UT) 2127 tdut = TDT - UT in sec 2128 */ 2129 double ae = 23454.77992; // 149597870.0/6378.14 = 1AE -> Earth Radii 2130 Mat3 mx; 2131 2132 t = julcent (jd) + tdut / 3.15576e9; // =(86400.0 * 36525.0); 2133 rs = sun.position(t); 2134 rm = moon.position(t); 2135 rs = eclequ(t,rs); 2136 rm = eclequ(t,rm); 2137 2138 // correct Moon coordinates for center of figure 2139 mx = zrot(-2.4240684e-6); // +0.5" in longitude 2140 rm = mxvct(mx,rm); 2141 mx = yrot(-1.2120342e-6); // -0.25" in latitude 2142 rm = mxvct(mx,rm); 2143 mx = nutmat(t,ep2); // nutation 2144 rs = mxvct(mx,rs); // apparent coordinates 2145 rs = aberrat(t,rs); 2146 rs *= ae; 2147 rm = mxvct(mx,rm); 2148 } 2149 2150 double Eclipse::duration (double jd, double tdut, double& width) 2151 { 2152 /* Get the duration of a central eclipse at the center point 2153 for MJD jd and TDT-UT tdut in seconds. 2154 Also return the width of the umbra in km. 2155 A call to solar with the respective jd must have been done 2156 prior to calling this function !!! 2157 */ 2158 const double omega = 4.3755e-3; // radial velocity of Earth in rad/min. 2159 2160 double dur, lm, pa, umbold; 2161 Vec3 rold, eold, rsold, rmold; 2162 Mat3 mx; 2163 2164 // save old values for jd 2165 rold = rint; 2166 eold = eshadow; 2167 umbold = d_umbra; 2168 rsold = rs; 2169 rmold = rm; 2170 2171 dur = 0.1; // 0.1 min 2172 if (solar(jd+dur/1440.0,tdut, lm, pa) > 3) 2173 { 2174 mx = zrot(dur*omega); 2175 rint = mxvct(mx,rint); 2176 rint -= rold; 2177 pa = dot (rint, eold); 2178 lm = dot (rint, rint) - pa*pa; 2179 if (lm > 0) lm = sqrt(lm); 2180 else lm = 0; 2181 if (lm > 0) dur = fabs(umbold) / lm * dur * 60.0; 2182 else dur = 0; 2183 } 2184 2185 else dur = -1; 2186 2187 // restore old values for jd 2188 d_umbra = umbold; 2189 eshadow = eold; 2190 eold = rold*rint; // direction perpendicular of apparent shadow movement 2191 rint = rold; 2192 rs = rsold; 2193 rm = rmold; 2194 2195 // get width of umbra at center location 2196 rold = vnorm (rint); 2197 pa = dot(rold,eshadow); 2198 if (pa > 1.0) pa = 1.0; 2199 if (pa < -1.0) pa = -1.0; 2200 if (fabs(pa) < 1.0e-15) lm = fabs(d_umbra); // just in case 2201 else lm = fabs(d_umbra / pa); // projection along shadow vector 2202 2203 rsold = vnorm(rint*eshadow); 2204 rmold = vnorm(eold); 2205 pa = dot(rsold,rmold); // cos of projection shadow - perperndicular 2206 if (pa > 1.0) pa = 1.0; 2207 if (pa < -1.0) pa = -1.0; 2208 umbold = fabs(sin(acos(pa))); 2209 2210 // this is for very slant shadow angles respective to movement 2211 lm = lm * umbold; 2212 umbold = fabs(pa * d_umbra); 2213 if (umbold > lm) width = umbold; 2214 else width = lm; 2215 2216 // this is the normal case 2217 rold = vnorm (eold); 2218 pa = dot(rold,eshadow); 2219 if (pa > 1.0) pa = 1.0; 2220 if (pa < -1.0) pa = -1.0; 2221 pa = fabs(sin(acos(pa))); 2222 if (pa < 0.00001) pa = 0.00001; 2223 lm = d_umbra / pa; // allow for projection 2224 lm = fabs(lm); 2225 2226 if (lm > width) width = lm; 2227 width = width * 6378.14; 2228 2229 return dur; 2230 } 2231 2232 Vec3 Eclipse::GetRSun () // get Earth - Sun vector in Earth radii 2233 { 2234 return rs; 2235 } 2236 2237 Vec3 Eclipse::GetRMoon () // get Earth - Moon vector in Earth radii 2238 { 2239 return rm; 2240 } 2241 2242 double Eclipse::GetEp2 () // get the ep2 value 2243 { 2244 return ep2; 2245 } 2246 2247 int Eclipse::lunar (double jd, double tdut) 2248 { 2249 /* check whether lunar eclipse is in progress at 2250 Modified Julian Date jd (UT). 2251 tdut = TDT - UT in sec 2252 2253 RETURN: 2254 0 : No eclipse 2255 1 : Partial Penumbral Eclipse 2256 2 : Total Penumbral Eclipse 2257 3 : Partial Umbral Eclipse 2258 4 : Total Umbral Eclipse 2259 */ 2260 2261 const double dm = 0.544986; // diameter of Moon in Earth radii 2262 const double ds = 218.245445; // diameter of Sun in Earth radii 2263 2264 double umbra, penumbra; 2265 double r2, s0, sep; 2266 int phase; 2267 Vec3 v1, v2; 2268 2269 // get position of Sun and Moon 2270 equ_sun_moon(jd, tdut); 2271 2272 // get radius of umbra and penumbra 2273 r2 = abs(rs); 2274 s0 = abs (rm); 2275 umbra = 1.02*fabs((ds - 2.0) * s0 / r2 - 2.0)*0.5; // radius of umbra 2276 penumbra = 1.02*fabs((ds + 2.0) * s0 / r2 + 2.0)*0.5;//radius of penumbra 2277 /* (the factor 1.02 allows for enlargment of shadow due to 2278 Earth's atmosphere) */ 2279 2280 // get angular separation of center of shadow and Moon 2281 r2 = abs(rm); 2282 sep = dot(rs,rm)/(abs(rs)*r2); 2283 if (fabs(sep) > 1.0) sep = 1.0; 2284 sep = acos(sep); // in radians 2285 sep = fabs(tan(sep)*r2); // distance of Moon and shadow in Earth radii 2286 2287 // Now check the kind of eclipse 2288 if (sep < (umbra - dm/2.0)) phase = 4; 2289 else if (sep < (umbra + dm/2.0)) phase = 3; 2290 else if (sep < (penumbra - dm/2.0)) phase = 2; 2291 else if (sep < (penumbra + dm/2.0)) phase = 1; 2292 else phase = 0; 2293 2294 return phase; 2295 } 2296 2297