File indexing completed on 2025-01-05 03:58:41
0001 // SPDX-License-Identifier: LGPL-2.1-or-later 0002 // 0003 // SPDX-FileCopyrightText: 2012 Gerhard HOLTKAMP 0004 // 0005 0006 /*************************************************************************** 0007 * Calculate Solar Eclipses * 0008 * * 0009 * * 0010 * The algorithm for the phases of the Moon and of the dates for the * 0011 * equinoxes and solstices of the Sun as well as the dates of eclipses * 0012 * are based on Jean Meeus "Astronomical Formulae for Calculators", * 0013 * Willman-Bell, Inc., Richmond, Virginia, 1988 * 0014 * * 0015 * The algorithm for the Modified Julian Date and the calendar as well as * 0016 * the detailed eclipse calculations are based on * 0017 * O.Montebruck and T.Pfleger, "Astronomy with a PC", * 0018 * Springer Verlag, Berlin, Heidelberg, New York, 1989 * 0019 * and on the * 0020 * "Explanatory Supplement to the Astronomical Almanac" * 0021 * University Science Books, Mill Valley, CA, 1992 * 0022 * * 0023 * Open Source Code. License: GNU LGPL Version 2+ * 0024 * * 0025 * Author: Gerhard HOLTKAMP, 28-JAN-2013 * 0026 ***************************************************************************/ 0027 0028 /*------------ include files and definitions -----------------------------*/ 0029 #include "eclsolar.h" 0030 #include <cstdio> 0031 #include <cstdlib> 0032 #include <cstring> 0033 #include <cmath> 0034 #include <ctime> 0035 using namespace std; 0036 0037 #include "astrolib.h" 0038 0039 /* const double PI = 3.14159265359; */ 0040 const double degrad = M_PI / 180.0; 0041 0042 // ################ Solar Eclipse Class #################### 0043 0044 EclSolar::EclSolar() 0045 { 0046 esinit(); 0047 } 0048 0049 EclSolar::~EclSolar() 0050 { 0051 0052 } 0053 0054 double EclSolar::atan23 (double y, double x) 0055 { 0056 /* redefine atan2 so that it doesn't crash when both x and y are 0 */ 0057 double result; 0058 0059 if ((x == 0) && (y == 0)) result = 0; 0060 else result = atan2 (y, x); 0061 0062 return result; 0063 } 0064 0065 void EclSolar::esinit() 0066 { 0067 // initialize eclipse data 0068 eb_start_called = false; 0069 eb_moonph_called = false; 0070 eb_lunecl = true; 0071 eb_lunactive = false; 0072 eb_local_called = false; 0073 0074 eb_day = 1; 0075 eb_month = 1; 0076 eb_year = 2012; 0077 eb_hour = 0; 0078 eb_minute = 0; 0079 eb_second = 0; 0080 eb_tzone = 0; 0081 eb_del_auto = 1; 0082 DefTime(); 0083 eb_time = 0; 0084 eb_del_tdut = DefTdUt(eb_year); 0085 eb_geolat = 0; 0086 eb_geolong = 0; 0087 eb_geoheight = 0; 0088 eb_lstcall = 0; 0089 eb_locecl = 0; 0090 eb_lastyear = -9999; 0091 eb_numecl = 0; 0092 eb_lasttz = eb_tzone; 0093 eb_lastdlt = eb_del_tdut; 0094 eb_cstep = 1.0; 0095 eb_cmxlat = 0; 0096 eb_cmxlng = 0; 0097 eb_penangle = 1.0; 0098 eb_penamode = 0; 0099 } 0100 0101 void EclSolar::DefTime () // Get System Time and Date 0102 { 0103 time_t tt; 0104 int hh, mm, ss; 0105 double jd, hr; 0106 0107 tt = time(NULL); 0108 jd = 40587.0 + tt/86400.0; // seconds since 1-JAN-1970 0109 0110 caldat(jd, hh, mm, ss, hr); 0111 eb_year = ss; 0112 eb_month = mm; 0113 eb_day = hh; 0114 0115 dms(hr, hh, mm, jd); 0116 eb_hour = hh; 0117 eb_minute = mm; 0118 eb_second = int(jd); 0119 if (eb_del_auto) eb_del_tdut = DefTdUt(eb_year); 0120 }; 0121 0122 int EclSolar::getYear() const 0123 { 0124 return eb_year; 0125 } 0126 0127 void EclSolar::putYear(int yr) 0128 { 0129 eb_start_called = false; 0130 eb_moonph_called = false; 0131 eb_local_called = false; 0132 eb_lunactive = false; 0133 0134 eb_year = yr; 0135 if (eb_del_auto) eb_del_tdut = DefTdUt(eb_year); 0136 moonph(); 0137 0138 } 0139 0140 int EclSolar::getNumberEclYear() 0141 { 0142 // RETURN the number of eclipses of the currently selected year 0143 0144 int j, k; 0145 0146 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year 0147 0148 if (eb_lunecl) return eb_numecl; 0149 0150 k = 0; 0151 for (j=0; j<eb_numecl; j++) 0152 { 0153 if (eb_phase[j] > 0) k++; 0154 } 0155 0156 return k; 0157 } 0158 void EclSolar::setLunarEcl(bool lecl) 0159 { 0160 // if lecl = true include lunar eclipses in addition to solar ones 0161 if (lecl) eb_lunecl = true; 0162 else eb_lunecl = false; 0163 eb_start_called = false; 0164 eb_local_called = false; 0165 } 0166 0167 void EclSolar::setStepWidth(double s) 0168 { 0169 // set the step width (in minutes) used for calculations 0170 if (s < 0.01) eb_cstep = 0.01; 0171 else eb_cstep = s; 0172 } 0173 0174 void EclSolar::setTimezone(double d) 0175 { 0176 // set the timezone to d (hours difference from UTC) for I/O 0177 eb_tzone = d; 0178 } 0179 0180 void EclSolar::setDeltaTAI_UTC(double d) 0181 { 0182 // c is the difference between TAI and UTC according to the IERS 0183 // we have to add 32.184 sec to get to the difference TT - UT 0184 // which is used in the calculations here 0185 0186 eb_del_tdut = d + 32.184; 0187 eb_del_auto = 0; 0188 } 0189 0190 void EclSolar::setAutoTAI_UTC() 0191 { 0192 // set the difference between TAI and UTC according to the IERS 0193 eb_del_auto = true; 0194 eb_del_tdut = DefTdUt(eb_year); 0195 } 0196 0197 void EclSolar::setLocalPos(double lat, double lng, double hgt) 0198 { 0199 // set the geographic coordinates for the position of the local info 0200 // latitude lat, longitude lng in decimal degrees 0201 // height hgt in meters 0202 0203 eb_geolat = lat; 0204 eb_geolong = lng; 0205 eb_geoheight = hgt; 0206 0207 eb_local_called = false; 0208 } 0209 0210 int EclSolar::getLocalVisibility(double &mjd_start, double &mjd_stop) 0211 { 0212 // local start and stop times (MJD) for eclipse 0213 // RETURN 0 if not locally visible 0214 0215 char wbuf[700]; 0216 0217 if (!eb_local_called) getLocalDetails(wbuf); 0218 0219 mjd_start = eb_lcb1; 0220 mjd_stop = eb_lce1; 0221 0222 return eb_lccnt; 0223 } 0224 0225 int EclSolar::getLocalTotal(double &mjd_start, double &mjd_stop) 0226 { 0227 // local start and stop times (MJD) for totality/annularity 0228 // RETURN 0 if not locally visible 0229 0230 int k, j; 0231 char wbuf[700]; 0232 0233 if (!eb_local_called) getLocalDetails(wbuf); 0234 0235 mjd_start = 0; 0236 mjd_stop = 0; 0237 0238 if(eb_lccnt == 0) return 0; 0239 0240 k = 0; 0241 if(eb_lunactive) 0242 { 0243 for (j=0; j<eb_nphase; j++) 0244 { 0245 if ((k==0) && (eb_spp[j] > 3)) 0246 { 0247 mjd_start = eb_spt[j]; 0248 mjd_stop = eb_ept[j]; 0249 k = 1; 0250 } 0251 } 0252 0253 if(mjd_start < eb_lcb1) mjd_start = eb_lcb1; 0254 if(mjd_start > eb_lce1) k = 0; 0255 if(mjd_stop > eb_lce1) mjd_stop = eb_lce1; 0256 if(mjd_stop < eb_lcb1) k = 0; 0257 0258 eb_ltotb = mjd_start; 0259 eb_ltote = mjd_stop; 0260 0261 } 0262 else k = eb_lccnt; 0263 0264 mjd_start = eb_ltotb; 0265 mjd_stop = eb_ltote; 0266 0267 return k; 0268 } 0269 0270 int EclSolar::getLocalMax(double &mjdmax, double &magmax, double &elmax) 0271 { 0272 // get local (solar) eclipse maximum 0273 // mjdmax : Modified Julian Date of maximum eclipse 0274 // magmax : maximum (local) magnitude of eclipse 0275 // elmax : local Sun elevation at maximum 0276 0277 // RETURN : 0 if eclipse not visible 0278 0279 int k; 0280 0281 mjdmax = 0; 0282 magmax = 0; 0283 elmax = 0; 0284 0285 if (eb_lunactive) return 0; 0286 0287 k = getLocalVisibility(mjdmax, magmax); 0288 0289 if (k != 0) 0290 { 0291 mjdmax = eb_jdmaxps; 0292 magmax = eb_maxps; 0293 elmax = eb_maxelv; 0294 } 0295 0296 return k; 0297 } 0298 0299 int EclSolar::getPenumbra(double &mjd_start, double &mjd_stop) 0300 { 0301 // start and stop times (MJD) for penumbral eclipse of Moon 0302 // RETURN 0 if no lunar eclipse 0303 0304 int j, k; 0305 0306 if (!eb_start_called) eclStart(); 0307 0308 mjd_start = 0; 0309 mjd_stop = 0; 0310 0311 if (!eb_lunactive) return 0; 0312 0313 if (eb_nphase <= 0) return 0; 0314 0315 k = 0 ; 0316 for (j=0; j<eb_nphase; j++) 0317 { 0318 if (eb_spp[j] == 1) 0319 { 0320 mjd_start = eb_spt[j]; 0321 mjd_stop =eb_ept[j]; 0322 k = 1; 0323 } 0324 } 0325 0326 return k; 0327 } 0328 0329 int EclSolar::getPartial(double &mjd_start, double &mjd_stop) 0330 { 0331 // (global) start and stop times (MJD) for partial phase 0332 // RETURN 0 if no lunar eclipse 0333 0334 int j, k; 0335 0336 if (!eb_start_called) eclStart(); 0337 0338 mjd_start = 0; 0339 mjd_stop = 0; 0340 0341 if (eb_nphase <= 0) return 0; 0342 0343 k = 0; 0344 0345 if(eb_lunactive) 0346 { 0347 for (j=0; j<eb_nphase; j++) 0348 { 0349 if ((k==0) && (eb_spp[j] == 3)) 0350 { 0351 mjd_start = eb_spt[j]; 0352 mjd_stop =eb_ept[j]; 0353 k = 1; 0354 } 0355 } 0356 } 0357 else 0358 { 0359 for (j=0; j<eb_nphase; j++) 0360 { 0361 if ((k==0) && (eb_spp[j] == 1)) 0362 { 0363 mjd_start = eb_spt[j]; 0364 mjd_stop =eb_ept[j]; 0365 k = 1; 0366 } 0367 } 0368 } 0369 0370 return k; 0371 0372 } 0373 0374 int EclSolar::getTotal(double &mjd_start, double &mjd_stop) 0375 { 0376 // (global) start and stop times (MJD) for totality/annularity 0377 // RETURN 0 if no lunar eclipse 0378 0379 int j, k; 0380 0381 if (!eb_start_called) eclStart(); 0382 0383 mjd_start = 0; 0384 mjd_stop = 0; 0385 0386 if (eb_nphase <= 0) return 0; 0387 0388 k = 0; 0389 0390 if(eb_lunactive) 0391 { 0392 for (j=0; j<eb_nphase; j++) 0393 { 0394 if ((k==0) && (eb_spp[j] > 3)) 0395 { 0396 mjd_start = eb_spt[j]; 0397 mjd_stop =eb_ept[j]; 0398 k = 1; 0399 } 0400 } 0401 } 0402 else 0403 { 0404 for (j=0; j<eb_nphase; j++) 0405 { 0406 if ((k==0) && (eb_spp[j] > 1)) 0407 { 0408 mjd_start = eb_spt[j]; 0409 mjd_stop =eb_ept[j]; 0410 k = 1; 0411 } 0412 } 0413 } 0414 0415 return k; 0416 0417 } 0418 0419 void EclSolar::setCurrentMJD(int year, int month, int day, int hour, int min, double sec) 0420 { 0421 // set the (MJD-) time currently used for calculations to year, month, day, hour, min, sec 0422 // corrected for timezone 0423 0424 double jd; 0425 0426 jd = ddd(hour, min, sec) - eb_tzone; 0427 jd = mjd(day, month, year, jd); 0428 0429 eb_lastjd = jd; 0430 0431 } 0432 0433 void EclSolar::getDatefromMJD(double mjd, int &year, int &month, int &day, int &hour, int &min, double &sec) const 0434 { 0435 // convert times given in Modified Julian Date (MJD) into conventional date and time 0436 // correct for timezone 0437 0438 double magn; 0439 0440 caldat((mjd + eb_tzone/24.0), day, month, year, magn); 0441 dms (magn,hour,min,sec); 0442 if (sec>30.0) min++; 0443 if (min>59) 0444 { 0445 hour++; 0446 min=0; 0447 }; 0448 0449 } 0450 0451 //---------------------- getEclYearInfo-------------------------------- 0452 0453 void EclSolar::getEclYearInfo(char* wbuf) 0454 { 0455 // output the eclipse dates in buffer wbuf accurate to the minute. 0456 0457 char dts[15]; 0458 char outbuf[127]; 0459 char magbuf[30]; 0460 int j, p, kecl; 0461 0462 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year 0463 0464 sprintf(wbuf,"Solar Eclipses for %4i UTC +%4.1f", eb_year, eb_tzone); 0465 0466 kecl = 1; 0467 for (j=0; j<eb_numecl; j++) 0468 { 0469 sprintf(dts,"%1i : ", kecl); 0470 strcpy (outbuf,dts); 0471 dtmstr((eb_eclmjd[j] + eb_tzone/24.0),dts); 0472 dts[12] = '\0'; 0473 strcat (outbuf,dts); 0474 p = eb_phase[j]; 0475 0476 switch (p) 0477 { 0478 case 1: strcat(outbuf,"\t Partial Sun"); 0479 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]); 0480 strcat(outbuf,magbuf); 0481 break; 0482 0483 case 2: strcat(outbuf,"\t non-central Annular Sun"); 0484 break; 0485 case 4: strcat(outbuf,"\t Annular Sun"); 0486 break; 0487 0488 case 3: strcat(outbuf, "\t non-central Total Sun"); 0489 break; 0490 case 5: strcat(outbuf, "\t Total Sun"); 0491 break; 0492 0493 case 6: strcat(outbuf, "\t Annular/Total Sun"); 0494 break; 0495 0496 case -1: 0497 case -2: strcat(outbuf, "\t Penumbral Moon"); 0498 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]); 0499 strcat(outbuf,magbuf); 0500 break; 0501 0502 case -3: strcat(outbuf, "\t Partial Moon"); 0503 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]); 0504 strcat(outbuf,magbuf); 0505 break; 0506 0507 case -4: strcat(outbuf, "\t Total Moon"); 0508 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]); 0509 strcat(outbuf,magbuf); 0510 break; 0511 }; 0512 0513 if ((p > 0) || eb_lunecl) // solar eclipse only or also lunar eclipses 0514 { 0515 strcat (wbuf, "\n"); 0516 strcat (wbuf, outbuf); 0517 kecl++; 0518 }; 0519 } 0520 } 0521 0522 int EclSolar::getEclYearInfo(int k, int &yr, int &month, int &day, 0523 int &hour, int &min, double &sec, double &tzone, double &magn) 0524 { 0525 /* output the eclipse info for k-th eclipse 0526 0527 year, month, day, hour, minutes, seconds and timezone 0528 magn = magnitude of eclipse 0529 0530 RETURN: phase of eclipse. 0 if no k-th eclipse 0531 0532 1: Partial Sun 0533 2: non-central Annular Sun 0534 3: non-central Total Sun 0535 4: Annular Sun 0536 5: Total Sun 0537 6: Annular/Total Sun 0538 0539 -1, -2: Penumbral Moon 0540 -3: Partial Moon 0541 -4: Total Moon 0542 0543 */ 0544 bool nls; 0545 int j, p, kecl; 0546 0547 nls = true; 0548 0549 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year 0550 0551 if (k < 1) 0552 { 0553 k = eb_eclselect; // select current eclipse as default 0554 nls = false; 0555 }; 0556 if ((k < 1) && (k > eb_numecl)) return 0; 0557 0558 p = k - 1; 0559 if (nls && (!eb_lunecl)) 0560 { 0561 kecl = 0; 0562 p = -1; 0563 for(j=0; j<eb_numecl; j++) 0564 { 0565 if (eb_phase[j] > 0) 0566 { 0567 kecl++; 0568 if (kecl == k) p = j; 0569 }; 0570 }; 0571 }; 0572 0573 if (p < 0) return 0; 0574 0575 j = p; 0576 0577 // convert MJD into corresponding date and time 0578 caldat((eb_eclmjd[j] + eb_tzone/24.0), day, month, yr, magn); 0579 dms (magn,hour,min,sec); 0580 if (sec>30.0) min++; 0581 if (min>59) 0582 { 0583 hour++; 0584 min=0; 0585 }; 0586 0587 magn = eb_magnitude[j]; 0588 tzone = eb_tzone; 0589 0590 return eb_phase[j]; 0591 } 0592 0593 int EclSolar::getEclTxt (int k, char* jtxt) 0594 { 0595 // get the data / kind of eclipse info for the j-th eclipse 0596 // and place it into jtxt 0597 0598 // RETURN : the phase of the eclipse. 0 if no j-th eclipse 0599 0600 int p, j; 0601 char dts[13]; 0602 0603 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year 0604 0605 if (k < 1) k = eb_eclselect; // select current eclipse as default 0606 if ((k < 1) && (k > eb_numecl)) return 0; 0607 0608 j = k-1; 0609 0610 sprintf(jtxt, "%2i :", (j+1)); 0611 sprintf(dts, "%5i ", eb_year); 0612 strcat (jtxt, dts); 0613 dtmstr((eb_eclmjd[j]+eb_tzone/24.0),dts); 0614 dts[6] = '\0'; 0615 strcat (jtxt,dts); 0616 0617 p = eb_phase[j]; 0618 switch (p) 0619 { 0620 case 1: strcat(jtxt," Par.Sun"); 0621 break; 0622 case 2: strcat(jtxt, " non-centr.Ann.Sun"); 0623 break; 0624 case 4: strcat(jtxt," Ann.Sun"); 0625 break; 0626 case 3: strcat(jtxt," non-centr.Tot.Sun"); 0627 break; 0628 case 5: strcat(jtxt," Tot.Sun"); 0629 break; 0630 case 6: strcat(jtxt," Ann/Tot."); 0631 break; 0632 0633 case -1: 0634 case -2: strcat(jtxt," Pen.Moon"); 0635 break; 0636 case -3: strcat(jtxt," Par.Moon"); 0637 break; 0638 case -4: strcat(jtxt," Tot.Moon"); 0639 break; 0640 }; 0641 0642 return p; 0643 } 0644 0645 // ----------------------------- Select Eclipse ------------------------- 0646 0647 void EclSolar::putEclSelect(int es) 0648 { 0649 // store the number of the eclipse selected for detailed calculations 0650 int k, j; 0651 0652 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year 0653 0654 k = 0; 0655 0656 eb_lunactive = false; 0657 eb_eclselect = 1; 0658 for (j=0; j<eb_numecl; j++) 0659 { 0660 if ((eb_phase[j] > 0) || eb_lunecl) // only solar eclipses if set 0661 { 0662 k++; 0663 if (k == es) 0664 { 0665 eb_eclselect = j + 1; 0666 if (eb_phase[j] < 0) eb_lunactive = true; 0667 }; 0668 }; 0669 }; 0670 eb_start_called = false; 0671 } 0672 0673 void EclSolar::nextEcl() 0674 { 0675 // select the next eclipse for detailed calculations 0676 int k, j, es; 0677 0678 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year 0679 eb_start_called = false; 0680 0681 k = eb_eclselect + 1; 0682 if (k > eb_numecl) 0683 { 0684 k = eb_year + 1; 0685 putYear (k); 0686 k = 1; 0687 putEclSelect(k); 0688 0689 return; 0690 }; 0691 0692 if (eb_lunecl) // easier when lunar eclipses are included 0693 { 0694 putEclSelect(k); 0695 0696 return; 0697 }; 0698 0699 eb_lunactive = false; 0700 0701 es = eb_eclselect; 0702 k = 0; 0703 for (j=es; j<eb_numecl; j++) 0704 { 0705 if ((k == 0) && (eb_phase[j] > 0)) k = j + 1; 0706 }; 0707 0708 if(k > 0) 0709 { 0710 eb_eclselect = k; 0711 return; 0712 } 0713 0714 k = eb_year + 1; 0715 putYear (k); 0716 es = 1; 0717 putEclSelect(es); 0718 0719 } 0720 0721 void EclSolar::previousEcl() 0722 { 0723 // select the previous eclipse for detailed calculations 0724 int k, j, es; 0725 0726 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year 0727 eb_start_called = false; 0728 0729 k = eb_eclselect - 1; 0730 0731 if (k <= 0) 0732 { 0733 k = eb_year - 1; 0734 putYear (k); 0735 k = eb_numecl; 0736 }; 0737 0738 if (eb_lunecl) // easier when lunar eclipses are included 0739 { 0740 putEclSelect(k); 0741 0742 return; 0743 }; 0744 0745 eb_lunactive = false; 0746 0747 es = 0; 0748 k--; 0749 for (j=k; j>=0; j--) 0750 { 0751 if ((es == 0) && (eb_phase[j] > 0)) es = j + 1; 0752 }; 0753 0754 if(es > 0) eb_eclselect = es; 0755 else putEclSelect(0); // this case should never happen! 0756 0757 } 0758 0759 double EclSolar::getLastMJD() const 0760 { 0761 // RETURN the MJD last used in calculations 0762 0763 return eb_lastjd; 0764 } 0765 0766 void EclSolar::setPenumbraAngle(double pa, int mode) 0767 { 0768 /* set the Penumbra Angle 0769 if mode == 0 the angle will be set to pa-times the maximum angle 0770 (pa < 1.0). Set pa = 1 for the normal penumbra boundaries 0771 0772 if mode == 1 the angle will be set such that the penumbra line 0773 markes magnitude pa. pa == 0 will mark normal penumbra boundaries 0774 0775 if mode == 2 the angle will be set such that the penumbra line 0776 markes the obscuration pa. pa == 0.5 will mean that 50% of the Sun's 0777 disk is covered by the Moon etc. 0778 */ 0779 0780 double mjd, dpn1, dpn2, pan1, pan2; 0781 double mag, m1, m2, s, ps; 0782 int j; 0783 Vec3 ubm, ube; 0784 Eclipse eclp; 0785 0786 if (mode == 0) 0787 { 0788 eb_penangle = pa; 0789 eb_penamode = 0; 0790 if (pa > 1.0) eb_penangle = 1.0; 0791 if (pa < 0) eb_penangle = 1.0; 0792 0793 return; 0794 } 0795 0796 if (!eb_start_called) eclStart(); 0797 0798 if (mode == 1) 0799 { 0800 eb_penamode = 1; 0801 mjd = eb_eclmjd[eb_eclselect-1]; 0802 eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1); 0803 eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn2, pan2); 0804 0805 if(dpn2 > 0) 0806 { 0807 eb_penangle = fabs(pa); 0808 if(eb_penangle > 1.0) eb_penangle = 1.0; 0809 eb_penangle = 1.0 - eb_penangle * (1.0 + dpn1 / dpn2); 0810 } 0811 else eb_penangle = 1.0; 0812 0813 return; 0814 } 0815 0816 if (mode == 2) 0817 { 0818 eb_penamode = 2; 0819 mjd = eb_eclmjd[eb_eclselect-1]; 0820 eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1); 0821 eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn2, pan2); 0822 0823 ps = pa; // find the magnitude that corresponds to the obscuration 0824 if (ps > 1.0) ps = 1.0; 0825 if (ps < 0) ps = 0; 0826 for (j=1; j<11; j++) 0827 { 0828 mag = double(j) * 0.1; 0829 s = sunObscure(dpn2, dpn1, mag); 0830 if (s >= ps) break; 0831 } 0832 0833 m1 = mag - 0.1; 0834 m2 = mag; 0835 for (j=0; j<8; j++) // 8 iterations should be plenty 0836 { 0837 mag = (m2 + m1) * 0.5; 0838 s = sunObscure(dpn2, dpn1, mag); 0839 if (s > ps) m2 = mag; 0840 else m1 = mag; 0841 } 0842 0843 if(dpn2 > 0) 0844 { 0845 eb_penangle = fabs(mag); 0846 if(eb_penangle > 1.0) eb_penangle = 1.0; 0847 eb_penangle = 1.0 - eb_penangle * (1.0 + dpn1 / dpn2); 0848 } 0849 else eb_penangle = 1.0; 0850 0851 return; 0852 } 0853 0854 eb_penamode = 0; 0855 eb_penangle = 1.0; 0856 0857 } 0858 0859 // -------- auxiliary functions -------------------------------- 0860 void EclSolar::GetMonth (int mm, char* mchr) 0861 { 0862 // get three letter designation of month 0863 // mm is the number of the month 0864 // mchr is a char[4] array to receive the three letters of the month 0865 0866 switch (mm) 0867 { 0868 case 1 : strcpy(mchr,"JAN"); break; 0869 case 2 : strcpy(mchr,"FEB"); break; 0870 case 3 : strcpy(mchr,"MAR"); break; 0871 case 4 : strcpy(mchr,"APR"); break; 0872 case 5 : strcpy(mchr,"MAY"); break; 0873 case 6 : strcpy(mchr,"JUN"); break; 0874 case 7 : strcpy(mchr,"JUL"); break; 0875 case 8 : strcpy(mchr,"AUG"); break; 0876 case 9 : strcpy(mchr,"SEP"); break; 0877 case 10 : strcpy(mchr,"OCT"); break; 0878 case 11 : strcpy(mchr,"NOV"); break; 0879 case 12 : strcpy(mchr,"DEC"); break; 0880 default: strcpy(mchr,"ERR"); 0881 }; 0882 } 0883 0884 double EclSolar::phmjd (double yearf, double phase, double tdut, 0885 int& eph, double& ejd, double& emag) 0886 /* 0887 Calculate the Modified Julian Date of the occurrence of the specified 0888 phase of the Moon and check for possible eclipses. 0889 yearf : year.fraction of date close to the Moon phase 0890 phase : 0 for New Moon, 0891 0.25 for First Quarter, 0892 0.5 for Full Moon, 0893 0.75 for Last Quarter. 0894 tdut = TDT - UT in sec 0895 0896 RETURN: the MJD of the lunar phase event 0897 0898 OUTPUT: 0899 eph : phase of the eclipse on that date 0900 0 = no eclipse, 1 = partial solar eclipse, 0901 2 = non-central annular, 3 = non-central total 0902 4 = annular solar, 5 = total solar, 0903 6 = annular/total solar, -1 =partial penumbral lunar, 0904 -2 = total penumbral lunar, -3 = partial umbral lunar, 0905 -4 = total umbral lunar 0906 ejd : Modified Julian Date of the maximum of the eclipse (if any) 0907 emag : magnitude of the eclipse (if any) 0908 */ 0909 { 0910 double tt, jd, k, m, p, f; 0911 double s, c, gam, u; 0912 int tst; 0913 Eclipse eclp; 0914 0915 // preliminary (modified) Julian Date 0916 k = floor ((yearf - 1900.0) * 12.3685) + phase; 0917 tt = k / 1236.85; 0918 jd = 166.56 + (132.87 - 0.009173*tt)*tt; 0919 jd = 15020.25933 + 29.53058868*k 0920 + (0.0001178 - 0.000000155*tt)*tt*tt 0921 + 0.00033 * sin (degrad*jd); 0922 0923 eph = 0; // assume no eclipse 0924 0925 // Sun's mean anomaly 0926 m = degrad * (359.2242 + 29.10535608*k 0927 - (0.0000333 - 0.00000347*tt)*tt*tt); 0928 // Moon's mean anomaly 0929 p = degrad * (306.0253 + 385.81691808*k 0930 + (0.0107306 + 0.00001236*tt)*tt*tt); 0931 // 2* Moon's argument of latitude 0932 f = 2.0 * degrad * (21.2964 + 390.67050646*k 0933 - (0.0016528 - 0.00000239*tt)*tt*tt); 0934 0935 if ((phase == 0) || (phase == 0.5)) // for Full and New Moon 0936 { 0937 k = (0.1734 - 0.000393*tt) * sin (m) 0938 + 0.0021 * sin (2.0 * m) 0939 - 0.4068 * sin (p) 0940 + 0.0161 * sin (2.0 * p) 0941 - 0.0004 * sin (3.0 * p) 0942 + 0.0104 * sin (f) 0943 - 0.0051 * sin (m + p) 0944 - 0.0074 * sin (m - p) 0945 + 0.0004 * sin (f + m) 0946 - 0.0004 * sin (f - m) 0947 - 0.0006 * sin (f + p) 0948 + 0.0010 * sin (f - p) 0949 + 0.0005 * sin (m + 2.0*p); 0950 0951 // check for possible eclipses. 0952 f = f / 2.0; 0953 if (fabs(sin(f)) <= 0.36) // eclipses are possible 0954 { 0955 ejd = (0.1734 - 0.000393*tt) * sin(m) 0956 + 0.0021 * sin(2.0*m) 0957 - 0.4068 * sin(p) 0958 + 0.0161 * sin(2.0*p) 0959 - 0.0051 * sin(m+p) 0960 - 0.0074 * sin(m-p) 0961 - 0.0104 * sin(2.0*f); 0962 ejd += jd; 0963 0964 s = 5.19595 - 0.0048*cos(m) + 0.0020*cos(2.0*m) - 0.3283*cos(p) 0965 - 0.0060*cos(m+p) + 0.0041*cos(m-p); 0966 0967 c = 0.2070*sin(m) + 0.0024*sin(2.0*m) - 0.0390*sin(p) 0968 + 0.0115*sin(2.0*p) - 0.0073*sin(m+p) 0969 - 0.0067*sin(m-p) + 0.0117*sin(2.0*f); 0970 0971 gam = s*sin(f) + c*cos(f); 0972 u = 0.0059 + 0.0046*cos(m) - 0.0182*cos(p) 0973 + 0.0004*cos(2.0*p) - 0.0005*cos(m+p); 0974 0975 if (phase == 0) // check for solar eclipse 0976 { 0977 if (fabs(gam) <= (1.5432+u)) 0978 { 0979 if (fabs(gam) < 0.9972) // central eclipse 0980 { 0981 emag = 1.0; 0982 if (u < 0) eph = 5; // total eclipse 0983 else 0984 { 0985 if (u > 0.0047) eph = 4; // annular eclipse 0986 else 0987 { 0988 if (u < (0.00464*cos(asin(gam)))) eph = 6; // annular/total 0989 else eph = 4; // annular 0990 }; // end if u>0.0047 0991 }; // end if u<0 0992 } // end if fabs(gam) if 0993 else // non-central eclipse 0994 { 0995 eph = 1; // assume partial eclipse 0996 if (fabs(gam) < (0.9972+fabs(u))) // non-central annular or total 0997 { 0998 eph = eclp.solar(ejd,tdut,s,c); 0999 emag = 1.0; 1000 }; 1001 if (eph == 1) // get magnitude of partial eclipse 1002 emag = (1.5432 + u - fabs(gam)) / (0.5460 + 2.0*u); 1003 if (emag < 0.025) // check if low mag eclipse is OK 1004 { 1005 eph = 0; 1006 u = 1.0 / 720; // 2 min steps 1007 for (int j=0; j < 288; j++) 1008 { 1009 tt = ejd - 0.2 + double(j)*u; 1010 tst = eclp.solar(tt,tdut,s,c); 1011 if (tst > 0) eph = tst; 1012 }; 1013 }; 1014 } 1015 } 1016 } // end of solar eclipse check 1017 1018 if (phase == 0.5) // check for lunar eclipse 1019 { 1020 c = (1.5572 + u - fabs(gam)) / 0.5450; 1021 if (c > 0) 1022 { 1023 s = (1.0129 - u - fabs(gam)) / 0.5450; 1024 if (s < 0) // penumbral eclipse 1025 { 1026 emag = c; 1027 if (emag > 1) eph = -2; 1028 else eph = -1; 1029 } 1030 else // umbral eclipse 1031 { 1032 emag = s; 1033 if (emag > 1) eph = -4; 1034 else eph = -3; 1035 } 1036 } 1037 } 1038 } 1039 }; 1040 1041 if ((phase == 0.25) || (phase == 0.75)) // for first and last quarter 1042 { 1043 k = (0.1721 - 0.0004*tt) * sin (m) 1044 + 0.0021 * sin (2.0 * m) 1045 - 0.6280 * sin (p) 1046 + 0.0089 * sin (2.0 * p) 1047 - 0.0004 * sin (3.0 * p) 1048 + 0.0079 * sin (f) 1049 - 0.0119 * sin (m + p) 1050 - 0.0047 * sin (m - p) 1051 + 0.0003 * sin (f + m) 1052 - 0.0004 * sin (f - m) 1053 - 0.0006 * sin (f + p) 1054 + 0.0021 * sin (f - p) 1055 + 0.0003 * sin (m + 2.0*p) 1056 + 0.0004 * sin (m - 2.0*p) 1057 - 0.0003 * sin (2.0*m + p); 1058 if (phase == 0.25) 1059 { 1060 k += 0.0028 - 0.0004*cos(m) + 0.0003*cos(p); 1061 }; 1062 if (phase == 0.75) 1063 { 1064 k += -0.0028 + 0.0004*cos(m) - 0.0003*cos(p); 1065 }; 1066 }; 1067 1068 jd = jd + k; 1069 1070 return jd; 1071 } 1072 1073 void EclSolar::ckphase (double minmjd, double maxmjd, double yr, 1074 double deltdut, int &mp, PMJD p, double phase) 1075 /* calculate the respective phase for one (MJD-) date and check whether 1076 this date is within the limits given by minmjd and maxmjd. 1077 Use yr as the year.fraction close to the desired date. 1078 If the date is within the limits store the result in the 1079 respective array. 1080 Also check for possible occurrences of eclipses and store the 1081 respective data in an array 1082 */ 1083 { 1084 double td, ejd, emag; 1085 int j, eph; 1086 1087 td = phmjd (yr, phase, deltdut*86400.0, eph, ejd, emag); 1088 // correct difference between UT and TDT 1089 td = td - deltdut; // correct for difference between TDT and UT. 1090 1091 // check whether the date is within the respective year 1092 1093 if ((td >= minmjd) && (td <= maxmjd) && (mp < MAXLUN)) 1094 { 1095 if (mp==0) 1096 { 1097 p[0]=td; 1098 mp=1; 1099 } 1100 else 1101 { 1102 if (p[mp-1] < (td - 0.1)) 1103 { 1104 p[mp]=td; 1105 mp=mp+1; 1106 }; 1107 }; 1108 }; 1109 1110 // now the eclipses 1111 if (eph != 0) 1112 { 1113 td = ejd; 1114 td = td - deltdut; // correct for difference between TDT and UT. 1115 1116 // check whether the date is within the respective year 1117 if ((td >= minmjd)&&(td <= maxmjd)&&(eb_numecl<GBL_ECLBUF)) 1118 { 1119 if (eb_numecl == 0) 1120 { 1121 eb_eclmjd[0] = td; 1122 eb_magnitude[0] = emag; 1123 eb_phase[0] = eph; 1124 eb_numecl = 1; 1125 } 1126 else 1127 { 1128 for (j=0; j<eb_numecl; j++) 1129 { // check whether the date is already stored 1130 if (fabs(eb_eclmjd[j]- td) < 0.01) eph = 0; 1131 }; 1132 if (eph != 0) 1133 { 1134 j = eb_numecl; 1135 eb_eclmjd[j] = td; 1136 eb_magnitude[j] = emag; 1137 eb_phase[j] = eph; 1138 eb_numecl += 1; 1139 }; 1140 } 1141 } 1142 } 1143 } 1144 1145 void EclSolar::dtmstr(double jdmoon, char *dts) 1146 // Convert the Modified Julian Date jdmoon into a corresponding string 1147 // *dts which has the format "MMM DD HH:MM" 1148 { 1149 int dd, mm, yy, deg, mnt; 1150 double hh, sec; 1151 char mchr[4]; 1152 1153 // convert MJD into corresponding date and time 1154 caldat(jdmoon, dd, mm, yy, hh); 1155 dms (hh,deg,mnt,sec); 1156 if (sec>30.0) {mnt++;}; 1157 if (mnt>59) 1158 { 1159 deg++; 1160 mnt=0; 1161 }; 1162 1163 // store data in their positions 1164 GetMonth (mm, mchr); 1165 dts[0]=mchr[0]; 1166 dts[1]=mchr[1]; 1167 dts[2]=mchr[2]; 1168 dts[3]=' '; 1169 sprintf(&dts[4],"%2i %2i:%02i", dd, deg, mnt); 1170 dts[12]=' '; 1171 } 1172 1173 //------------------------- moonph --------------------------------- 1174 1175 void EclSolar::moonph() 1176 { 1177 int mp0, mp25, mp5, mp75; // counter of respective phase entries 1178 PMJD p0, p25, p5, p75; 1179 int day, month, year, j; 1180 double yr, yx, hour, deltdut; 1181 double minmjd, maxmjd; 1182 double glatsv, glongsv, gheightsv, lat, lng; 1183 char wbuf[700]; 1184 1185 eb_moonph_called = true; 1186 1187 // assign input data from Window Input Structure 1188 year = eb_year; 1189 deltdut = eb_del_tdut / 86400.0; // difference TDT - UT in days 1190 eb_lastyear = year; 1191 eb_lasttz = eb_tzone; 1192 eb_lastdlt = eb_del_tdut; 1193 1194 // initializing counters 1195 eb_numecl = 0; 1196 mp0 = 0; 1197 mp25 = 0; 1198 mp5 = 0; 1199 mp75 = 0; 1200 1201 yr = year - 0.2; 1202 yx = year + 1.2; 1203 day = 1; 1204 month = 1; 1205 hour = 0; 1206 minmjd = mjd(day, month, year, hour); 1207 day = 31; 1208 month = 12; 1209 hour = 24.0; 1210 maxmjd = mjd(day, month, year, hour); 1211 1212 /* As the function phmjd finds the respective phases of the Moon 1213 only to within a few weeks of the time given by the input 1214 parameter (year.faction) the following loop starts well ahead of 1215 the beginning of the year in question and ends well after. 1216 The time step of two weeks utilized to increment the year.fraction 1217 parameter assures that we catch all the different lunations */ 1218 1219 while (yr < yx) 1220 { // calculate and check the phases 1221 ckphase(minmjd,maxmjd,yr,deltdut, mp0, p0, 0.0); 1222 ckphase(minmjd,maxmjd,yr,deltdut, mp25, p25, 0.25); 1223 ckphase(minmjd,maxmjd,yr,deltdut, mp5, p5, 0.5); 1224 ckphase(minmjd,maxmjd,yr,deltdut, mp75, p75, 0.75); 1225 yr+=0.02; // increase by 1/50th of a year (about two weeks) 1226 }; 1227 1228 for (j=0; j<eb_numecl; j++) 1229 { 1230 if( (eb_phase[j] == 1) && (eb_magnitude[j] > 0.98)) // check for possible non-central eclipse 1231 { 1232 glatsv = eb_geolat; 1233 glongsv = eb_geolong; 1234 gheightsv = eb_geoheight; 1235 eb_eclselect = j+1; 1236 eb_start_called = false; 1237 eb_local_called = false; 1238 1239 getMaxPos (lat, lng); 1240 eb_geolat = lat; 1241 eb_geolong = lng; 1242 eb_geoheight = 0; 1243 1244 getLocalDetails(wbuf); 1245 1246 if ((eb_spp[0] == 2) || (eb_spp[1] == 2)) eb_phase[j] = 2; 1247 if ((eb_spp[0] == 3) || (eb_spp[1] == 3)) eb_phase[j] = 3; 1248 1249 eb_geolat = glatsv; 1250 eb_geolong = glongsv; 1251 eb_geoheight = gheightsv; 1252 eb_start_called = false; 1253 eb_local_called = false; 1254 1255 } 1256 1257 }; 1258 1259 eb_eclselect = 0; 1260 } 1261 1262 double EclSolar::getlocmag(double jd, double ep2, double phi, double lamda, 1263 double height, const Vec3& rs, const Vec3& rm, int& totflg) 1264 { 1265 /* get magnitude of solar eclipse at local position. 1266 jd : MJD (UT) of event 1267 ep2 : correction for apparent sidereal time (in sec) 1268 phi, lamda : latitude and longitude of observer in radians 1269 height : height of observer in m 1270 rs, rm : geocentric position vector of the sun and the moon 1271 totflg : 1 if total or annular, 0 otherwise 1272 1273 RETURN: The magnitude of the eclipse (0 if no eclipse) 1274 */ 1275 1276 const double ds = 218.245445; // diameter of Sun in Earth radii 1277 const double dm = 0.544986; // diameter of Moon in Earth radii 1278 Vec3 gm, gs, s; 1279 double dsun, dmoon, asep; 1280 double elev; 1281 1282 gm = GeoPos(jd, ep2, phi, lamda, height); 1283 gs = rs - gm; 1284 gm = rm - gm; 1285 1286 // correct for refraction 1287 s = EquHor(jd, ep2, phi, lamda, gs); 1288 s = carpol(s); 1289 elev = s[2]; 1290 1291 if (elev > -3.5e-2) // cutoff of -2 deg for calculating refraction 1292 { 1293 elev = Refract(elev); 1294 s[2] = s[2] + elev; 1295 s = polcar (s); 1296 gs = HorEqu(jd, ep2, phi, lamda, s); 1297 }; 1298 1299 s = EquHor(jd, ep2, phi, lamda, gm); 1300 s = carpol(s); 1301 elev = s[2]; 1302 if (elev > -3.5e-2) // cutoff of -2 deg for calculating refraction 1303 { 1304 elev = Refract(elev); 1305 s[2] = s[2] + elev; 1306 s = polcar (s); 1307 gm = HorEqu(jd, ep2, phi, lamda, s); 1308 }; 1309 1310 dsun = atan(0.5*ds/abs(gs)); // apparent radius of the Sun 1311 dmoon = atan(0.5*dm/abs(gm)); // apparent radius of the Moon 1312 1313 gs = vnorm(gs); 1314 gm = vnorm(gm); 1315 asep = fabs(dot(gs, gm)); 1316 if (asep > 1.0) asep = 1.0; 1317 asep = acos(asep); // apparent distance between Sun and Moon 1318 1319 totflg = 0; 1320 if ((dsun+dmoon) > asep) // we have an eclipse 1321 { 1322 if (fabs(dsun-dmoon) > asep) totflg = 1; 1323 asep = fabs(dsun + dmoon - asep) / (2.0 * dsun); 1324 } 1325 else asep = 0; 1326 1327 return asep; 1328 } 1329 1330 //------------------------- eclStart --------------------------------- 1331 1332 void EclSolar::eclStart() 1333 { 1334 /* get start and end times of the various phases of the eclipse 1335 j = index of the eclipse 1336 eb_spt[i] = start time in MJD for phase i 1337 eb_ept[i] = end time in MJD for phase i 1338 eb_spp[i] = kind of phase i 1339 1340 Also set the global eb_jdstart and eb_jdstop 1341 to the (global jd times) of eclipse start and end. 1342 1343 */ 1344 int nump, eflg, pcur, pold, maxp, i, j, npflg, p; 1345 double jd, step, jd2, jdf, d1, d2; 1346 double azim, elev, dist, phi, lamda; 1347 bool eclstarted; 1348 Vec3 gx; 1349 Eclipse eclp; 1350 1351 if (!eb_moonph_called) // just in case - this should never happen! 1352 { 1353 moonph(); 1354 putEclSelect(1); 1355 }; 1356 1357 eb_local_called = false; 1358 eb_start_called = true; 1359 1360 j = eb_eclselect-1; 1361 1362 eclstarted = false; 1363 nump = 0; 1364 maxp = 0; 1365 eflg = 0; // end flag 1366 pold = 0; 1367 elev = 0; 1368 eb_maxps = -1.0; 1369 eb_maxelv = -1.0; 1370 p = eb_phase[j]; 1371 jd = eb_eclmjd[j] - 0.5; // start 12 hours before maximum 1372 jdf = jd + 1.5; // emergency stop if something goes wrong with the loop 1373 step = eb_cstep / (24.0*60.0); // stepwidth (best set to 1 minute) 1374 1375 do 1376 { 1377 if (eb_lunactive) pcur = eclp.lunar(jd, eb_del_tdut); 1378 else pcur = eclp.solar (jd, eb_del_tdut,d1, d2); 1379 // now check the start and stop times for the phases 1380 if (pcur > pold) 1381 { 1382 eclstarted = true; 1383 if(nump < 4) 1384 { 1385 eb_spt[nump] = jd; 1386 eb_spp[nump] = pcur; 1387 nump++; 1388 maxp++; 1389 pold = pcur; 1390 // get time accurate to the second 1391 jd2 = jd - 1.0/86400.0; // go in seconds steps 1392 for (i=0; i<60; i++) 1393 { 1394 if (eb_lunactive) pcur = eclp.lunar(jd, eb_del_tdut); 1395 else pcur = eclp.solar (jd2, eb_del_tdut,d1, d2); 1396 1397 if (pcur == pold) eb_spt[nump] = jd2; 1398 else break; 1399 jd2 = jd2 - 1.0/86400.0; // go in seconds steps 1400 }; 1401 } 1402 } 1403 else if (eclstarted && (pcur < pold)) 1404 { 1405 pold = pcur; 1406 // get time accurate to the second 1407 jd2 = jd - 1.0/86400.0; // go in seconds steps 1408 for (i=0; i<60; i++) 1409 { 1410 if (eb_lunactive) pcur = eclp.lunar(jd, eb_del_tdut); 1411 else pcur = eclp.solar (jd2, eb_del_tdut,d1, d2); 1412 if (pcur == pold) jd = jd2; 1413 else break; 1414 jd2 = jd2 - 1.0/86400.0; // go in seconds steps 1415 }; 1416 pcur = pold; 1417 1418 npflg = 1; 1419 if (nump > 1) 1420 { 1421 if (pcur > eb_spp[nump-2]) npflg = 0; 1422 } 1423 if (npflg) 1424 { 1425 nump--; 1426 if (nump >= 0) eb_ept[nump] = jd; 1427 if (nump > 1) 1428 { 1429 if (pcur < eb_spp[nump-1]) 1430 { 1431 nump--; 1432 eb_ept[nump] = jd; 1433 } 1434 } 1435 if (nump <= 0) eflg = 1; 1436 } 1437 }; 1438 1439 jd += step; 1440 if (jd > jdf) eflg = 1; 1441 1442 } while (eflg != 1); 1443 1444 // now check for maximum eclipse conditions 1445 1446 calcMaxPos(phi, lamda); 1447 1448 if ((eb_lunactive == false) && (p > 3)) // central solar eclipse 1449 { 1450 eb_jdmaxps = eb_eclmjd[j]; 1451 jd = eb_eclmjd[j] - 600.0/86400.0; // start 10 min before approximate max time 1452 phi = eb_cmxlat * degrad; 1453 lamda = eb_cmxlng * degrad; 1454 for (i=0; i<1200; i++) 1455 { 1456 jd += 1.0/86400.0; // go in seconds steps 1457 pcur = eclp.solar (jd, eb_del_tdut,d1, d2); 1458 if (pcur > 3) 1459 { 1460 gx = eclp.GetRSun(); 1461 AppPos (jd, eclp.GetEp2(), d1, d2, 0.0, 1, gx, azim, elev, dist); 1462 1463 if (elev > eb_maxelv) 1464 { 1465 eb_maxelv = elev; 1466 eb_jdmaxps = jd; 1467 phi = d1; 1468 lamda = d2; 1469 }; 1470 } 1471 } 1472 eb_maxelv = elev / degrad; 1473 eb_cmxlat = phi / degrad; 1474 eb_cmxlng = lamda / degrad; 1475 if (eb_cmxlng < 0) eb_cmxlng += 360.0; 1476 }; 1477 1478 eb_jdstart = eb_spt[0]; 1479 eb_jdstop = eb_ept[0]; 1480 eb_nphase = maxp; 1481 1482 } 1483 1484 void EclSolar::calcMaxPos(double &lat, double &lng) 1485 { 1486 // Get the geographic position of the maximum eclipse 1487 // in case of a central eclipse the position is approximate 1488 // lat and lng are in decimal degrees 1489 1490 int j, p; 1491 double t, mp2; 1492 Vec3 rm; 1493 Vec3 s2; 1494 Eclipse eclp; 1495 1496 mp2 = 2.0 * M_PI; 1497 1498 j = eb_eclselect-1; 1499 1500 t = eb_eclmjd[j]; 1501 1502 if (eb_lunactive) 1503 { 1504 eclp.lunar(t, eb_del_tdut); 1505 rm = eclp.GetRMoon(); 1506 1507 // get sub lunar point at maximum 1508 s2 = carpol(rm); 1509 lat = s2[2]; // just preliminary 1510 lng = s2[1] - lsidtim (t, 0, eclp.GetEp2())*M_PI/12.0; 1511 if (lng > mp2) lng -= mp2; 1512 if (lng < -M_PI) lng += mp2; 1513 if (lng > M_PI) lng -= mp2; 1514 if (fabs(lat) < 1.53589) lat = atan(1.00674*tan(lat)); 1515 lat /= degrad; 1516 lng /= degrad; 1517 if (lng < 0) lng += 360.0; 1518 eb_cmxlat = lat; 1519 eb_cmxlng = lng; 1520 return; 1521 } 1522 else p = eclp.solar(t,eb_del_tdut,lat,lng); 1523 1524 if (p > 3) 1525 { 1526 eb_cmxlat = lat; 1527 eb_cmxlng = lng; 1528 eb_cmxlat /= degrad; 1529 eb_cmxlng /= degrad; 1530 } 1531 else 1532 { 1533 eclp.maxpos(t,eb_del_tdut,eb_cmxlat,eb_cmxlng); 1534 eb_cmxlat /= degrad; 1535 eb_cmxlng /= degrad; 1536 }; 1537 1538 if (eb_cmxlng < 0) eb_cmxlng += 360.0; 1539 lat = eb_cmxlat; 1540 lng = eb_cmxlng; 1541 } 1542 1543 void EclSolar::getMaxPos(double &lat, double &lng) 1544 { 1545 // Get the geographic position of the maximum eclipse 1546 1547 if (!eb_start_called) eclStart(); 1548 1549 lat = eb_cmxlat; 1550 lng = eb_cmxlng; 1551 } 1552 1553 double EclSolar::sunObscure(double l1, double l2, double mag) 1554 { 1555 // get the Obscuration of the Sun from penumbra l1, umbra l2 and 1556 // magnitude mag 1557 1558 double s, a, b, c, m; 1559 1560 m = l1 - mag * (l1 + l2); 1561 s = (l1 - l2) / (l1 + l2); 1562 c = (l1*l1 + l2*l2 - 2*m*m) / (l1*l1 - l2*l2); 1563 c = acos(c); 1564 b = (l1*l2 + m*m) / (m*(l1+l2)); 1565 b = acos(b); 1566 a = M_PI - (b + c); 1567 s = (s*s*a + b) - s * sin(c); 1568 1569 return s / M_PI; 1570 } 1571 1572 /*------------------------- EclCentral ---------------------------------*/ 1573 1574 int EclSolar::eclPltCentral(bool firstc, double &lat, double &lng) 1575 { 1576 /* get next coordinates for central eclipse position 1577 first = 1 for first call (first point will be found) 1578 lat, lng : latitude and longitude in decimal degrees 1579 1580 RETURN: phase (= 4 annular, = 5 total, = 6 annular/total 1581 0 if there was no central eclipse) 1582 */ 1583 double phi, lamda, d1, d2, jd, jd2; 1584 int kp, kp2, i; 1585 Eclipse eclp; 1586 1587 if (!eb_start_called) eclStart(); 1588 1589 if (eb_lunactive) // just in case 1590 { 1591 eb_finished2 = true; 1592 lat = 0.0; 1593 lng = 0.0; 1594 return 0; 1595 }; 1596 1597 eb_cphs = 0; 1598 1599 if (firstc) // find the first occurrence compliant with the step width 1600 { 1601 jd = eb_jdstart; 1602 kp = eclp.solar(jd, eb_del_tdut, phi, lamda); 1603 1604 while ((kp < 4) && (jd < eb_jdstop)) 1605 { 1606 jd += double(eb_cstep) / (24.0*60.0); 1607 eb_lastjd = jd; 1608 kp = eclp.solar(jd, eb_del_tdut, phi, lamda); 1609 }; 1610 1611 jd2 = jd; 1612 for (i=0; i<60; i++) // get it right to the second 1613 { 1614 jd2 = jd2 - 1.0/86400.0; // go in seconds steps 1615 kp2 = eclp.solar (jd2, eb_del_tdut,d1, d2); 1616 if (kp2 == kp) 1617 { 1618 phi = d1; 1619 lamda = d2; 1620 } 1621 else break; 1622 }; 1623 eb_finished2 = false; 1624 1625 } // end of firstc 1626 else 1627 { 1628 if (eb_finished2) return 0; 1629 1630 jd = eb_lastjd + double(eb_cstep) / (24.0*60.0); 1631 eb_lastjd = jd; 1632 if (jd > eb_jdstop) 1633 { 1634 eb_finished2 = true; 1635 return 0; 1636 }; 1637 1638 kp = eclp.solar(jd, eb_del_tdut, phi, lamda); 1639 1640 if (kp <= 3) // end of central eclipse. 1641 { 1642 eb_finished = true; 1643 for (i=0; i<60; i++) // get it right to the second 1644 { 1645 jd-= 1.0/86400.0; // go in seconds steps 1646 kp = eclp.solar (jd, eb_del_tdut, phi, lamda); 1647 if (kp > 3) break; 1648 }; 1649 }; 1650 }; 1651 1652 if (kp > 3) // central eclipse 1653 { 1654 eb_cphs = kp; 1655 1656 phi /= degrad; 1657 lamda /= degrad; 1658 if (lamda < 0.0) lamda += 360.0; 1659 if (lamda > 360.0) lamda -= 360.0; 1660 eb_clat = phi; 1661 eb_clng = lamda; 1662 lat = eb_clat; 1663 lng = eb_clng; 1664 1665 // djd = eclp.duration(jd, indata->del_tdut, width); 1666 } 1667 return kp; 1668 } 1669 1670 //--------------------Northern and Southern Boundaries ------------------------- 1671 1672 void EclSolar::InitBound() 1673 { 1674 /* Initialize the calculation for the northern and southern boundaries 1675 of solar eclipses (umbra or penumbra). 1676 The function EclStart must have been called first to enable InitBound 1677 to get the right eclipse. 1678 The calculation is done in Earth radii. 1679 1680 OUTPUT: 1681 eb_ubm : Penumbra base vector 1682 eb_ube : Shadod base vector for upper boundary 1683 eb_udm : Penumbra base delta vector 1684 eb_ude : Shadow delta vector for upper boundary 1685 eb_lbe : Shadod base vector for lower boundary 1686 eb_lde : Shadow delta vector for lower boundary 1687 */ 1688 1689 // const double dm = 0.272493; // radius of Moon in Earth radii 1690 double dpn1, dpn2, pan1, pan2, s0; 1691 Vec3 shmv, u2m, u2e; 1692 Vec3 ax1, ax2; 1693 Eclipse eclp; 1694 1695 if (!eb_start_called) eclStart(); 1696 if (eb_lunactive) return; // only for solar eclipses 1697 1698 // beginning of the eclipse 1699 eclp.penumd (eb_jdstart, eb_del_tdut, eb_ubm, eb_ube, dpn1, pan1); 1700 1701 // end of the eclipse 1702 eclp.penumd (eb_jdstop, eb_del_tdut, u2m, u2e, dpn2, pan2); 1703 1704 dpn1 *= 0.5; 1705 dpn2 *= 0.5; 1706 1707 if (eb_penamode == 0) 1708 { 1709 dpn1 *= eb_penangle; 1710 pan1 *= eb_penangle; 1711 dpn2 *= eb_penangle; 1712 pan2 *= eb_penangle; 1713 } 1714 1715 if (eb_penamode > 0) 1716 { 1717 s0 = eb_penangle * tan(pan1); 1718 s0 = atan(s0); 1719 if (pan1 > 0) 1720 { 1721 dpn1 = dpn1 * s0 / pan1; 1722 pan1 = s0; 1723 } 1724 s0 = eb_penangle * tan(pan2); 1725 s0 = atan(s0); 1726 if (pan2 > 0) 1727 { 1728 dpn2 = dpn2 * s0 / pan2; 1729 pan2 = s0; 1730 } 1731 } 1732 1733 // get apex of penumbra cone 1734 pan1 = tan(pan1); 1735 if (pan1 != 0) dpn1 = dpn1 / pan1; 1736 else dpn1 = 1.2 * abs(eb_ubm); // avoid a crash 1737 pan2 = tan(pan2); 1738 if (pan2 != 0) dpn2 = dpn2 / pan2; 1739 else dpn2 = dpn1; // avoid a crash 1740 1741 // get vector perpendicular to movement of shadow 1742 s0 = - dot(eb_ubm, eb_ube); 1743 ax1 = eb_ubm + s0 * eb_ube; 1744 eb_ubm = eb_ubm + (s0 - dpn1) * eb_ube; 1745 s0 = - dot(u2m, u2e); 1746 ax2 = u2m + s0 * u2e; 1747 u2m = u2m + (s0 - dpn2) * u2e; 1748 shmv = ax1 - ax2; 1749 ax2 = ax1 * ax2; 1750 shmv = shmv * ax2; 1751 shmv = vnorm(shmv); 1752 1753 // now get the delta vectors 1754 eb_udm = u2m - eb_ubm; 1755 eb_lbe = eb_ube - pan1 * shmv; 1756 eb_ube = eb_ube + pan1 * shmv; 1757 eb_ude = u2e + pan2 * shmv; 1758 eb_lde = u2e - pan2 * shmv; 1759 eb_ube = vnorm(eb_ube); 1760 eb_lbe = vnorm(eb_lbe); 1761 eb_ude = vnorm(eb_ude); 1762 eb_lde = vnorm(eb_lde); 1763 eb_lde = eb_lde - eb_lbe; 1764 eb_ude = eb_ude - eb_ube; 1765 1766 // scale the delta vectors 1767 dpn1 = eb_jdstop - eb_jdstart; 1768 if (dpn1 == 0) dpn1 = 1.0; 1769 else dpn1 = 1.0 / dpn1; 1770 eb_udm *= dpn1; 1771 eb_ude *= dpn1; 1772 eb_lde *= dpn1; 1773 } 1774 1775 int EclSolar::GNSBound(bool firstc, bool north, double& lat, double& lng) 1776 { 1777 /* Get the geographic coordinates of the northern or southern boundaries 1778 at time t. 1779 INPUT: firstc :true for first call 1780 north : true for southern boundary 1781 see also InitBound 1782 OUTPUT: 1783 lat, lng : latitude and longitude of penumbra boundary. 1784 If lat > 90 no northern boundary exists. 1785 1786 RETURN: 1 if time within eclipse, 0 if end of eclipse 1787 */ 1788 const double flat = 0.996633; // flatting of the Earth 1789 1790 double s0, s, r0, r2, dlt, t; 1791 Vec3 vrm, vre; 1792 1793 if (eb_lunactive) // only solar eclipses 1794 { 1795 lng = 0.0; 1796 lat = 100.0; 1797 return 0; 1798 }; 1799 1800 if (firstc) 1801 { 1802 InitBound(); 1803 t = eb_jdstart; 1804 eb_lastjd = t; 1805 } 1806 else 1807 { 1808 t = eb_lastjd + double(eb_cstep) / (24.0*60.0); 1809 eb_lastjd = t; 1810 }; 1811 1812 if (t >= eb_jdstop) 1813 { 1814 lng = 0.0; 1815 lat = 100.0; 1816 return 0; 1817 }; 1818 1819 // get shadow vector at time t 1820 vrm = eb_ubm + (t - eb_jdstart) * eb_udm; 1821 if (north) vre = eb_ube + (t - eb_jdstart) * eb_ude; 1822 else vre = eb_lbe + (t - eb_jdstart) * eb_lde; 1823 vre = vnorm (vre); // direction of penumbra boundary 1824 1825 s0 = - dot(vrm, vre); // distance Moon - fundamental plane 1826 r2 = dot (vrm,vrm); 1827 dlt = s0*s0 + 1.0 - r2; 1828 r0 = 1.0 - dlt; 1829 1830 if (r0 > 0) r0 = sqrt (r0); 1831 else r0 = 0; // distance center of Earth - shadow axis 1832 1833 // calculate the coordinates if there is an intersecton 1834 if (r0 < 1.0) // there should be an intersection 1835 { 1836 if (dlt > 0) dlt = sqrt(dlt); 1837 else dlt = 0; 1838 s = s0 - dlt; // distance Moon - fundamental plane 1839 vrm = vrm + s * vre; 1840 vrm = vnorm(vrm); 1841 vrm[2] *= flat; // vector to intersection 1842 vre = carpol(vrm); 1843 lng = vre[1] - lsidtim(t,0,0)*0.261799387799; // geographic coordinates 1844 if (lng > 2*M_PI) lng -= 2.0*M_PI; 1845 if (lng < 0.0) lng += 2.0*M_PI; 1846 lat = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615; 1847 lat = atan23(vrm[2],lat); 1848 lat /= degrad; 1849 lng /= degrad; 1850 1851 if (lng < 0.0) lng += 360.0; 1852 if (lng > 360.0) lng -= 360.0; 1853 } 1854 else 1855 { 1856 lat = 100.0; 1857 lng = 0; 1858 }; 1859 1860 return 1; 1861 } 1862 1863 //------------------ Sunrise / Sunset Boundaries --------------------------- 1864 1865 void EclSolar::InRSBound() 1866 { 1867 /* Initialize the calculation for the sunrise and sunset boundaries 1868 of solar eclipses. 1869 The function EclStart must have been called first to enable InRSBound 1870 to get the right eclipse. 1871 The calculation is done in Earth radii. 1872 1873 OUTPUT: 1874 eb_ubm : Moon base vector 1875 eb_ube : Shadod base vector 1876 eb_udm : Moon delta vector 1877 eb_ude : Shadow delta vector for 1878 eb_dpb : Base value for diameter of penumbra 1879 eb_dpd : delta value for diameter of penumbra 1880 */ 1881 1882 double pan; 1883 Vec3 u2m, u2e; 1884 Eclipse eclp; 1885 1886 if (!eb_start_called) eclStart(); 1887 1888 // beginning of the eclipse 1889 eclp.penumd (eb_jdstart, eb_del_tdut, eb_ubm, eb_ube, eb_dpb, pan); 1890 1891 // end of the eclipse 1892 eclp.penumd (eb_jdstop, eb_del_tdut, u2m, u2e, eb_dpd, pan); 1893 1894 // get the delta vectors 1895 eb_udm = u2m - eb_ubm; 1896 eb_ude = u2e - eb_ube; 1897 eb_dpd = eb_dpd - eb_dpb; 1898 1899 // scale the delta vectors 1900 1901 pan = eb_jdstop - eb_jdstart; 1902 if (pan == 0) pan = 1.0; 1903 else pan = 1.0 / pan; 1904 eb_udm *= pan; 1905 eb_ude *= pan; 1906 eb_dpd *= pan; 1907 } 1908 1909 int EclSolar::iscrs(double vrc0, double vrc1, double dpn, 1910 double& vrx0, double& vrx1, double& vrx20, double& vrx21) 1911 { 1912 /* calculate intersection vectors of the penumbral cone with the 1913 Earth in the fundamental plane to find the locations of rise 1914 and set. 1915 1916 INPUT : components of vectors vrc (pointing to the center of the 1917 penumbra), vre (unit vector perpendicular to the 1918 fundamental plane). 1919 dpn : half diameter of penumbra in Earth radii 1920 1921 OUTPUT: components of the intersection vectors vrx and vrx2 if 1922 successful. 1923 1924 RETURN: 1 if intersection successful, 0 otherwise. 1925 */ 1926 int rtn; 1927 double a, b, c, f1, f2, f3, f4; 1928 1929 rtn = 1; 1930 f1 = vrc0*vrc0; 1931 1932 if (f1 < 1.0e-60) rtn = 0; 1933 else 1934 { 1935 f2 = 1.0 - dpn*dpn + f1 + vrc1*vrc1; 1936 f3 = f2 / (2.0*vrc0); 1937 f4 = vrc1 / vrc0; 1938 a = 1.0 + vrc1*vrc1 / f1; 1939 b = f2*vrc1 / f1; 1940 c = f2*f2 / (4.0*f1) - 1.0; 1941 if (fabs(a) < 1.0e-60) rtn = 0; 1942 else 1943 { 1944 vrx21 = -0.5 * b / a; ; 1945 vrx0 = vrx21*vrx21 - c / a; 1946 if (vrx0 < 0) rtn = 0; 1947 else 1948 { 1949 vrx0 = sqrt(vrx0); 1950 vrx1 = vrx21 + vrx0; 1951 vrx21 = vrx21 - vrx0; 1952 vrx0 = f3 + f4*vrx1; 1953 vrx20 = f3 + f4*vrx21; 1954 vrx1 = -vrx1; 1955 vrx21 = -vrx21; 1956 }; 1957 }; 1958 }; 1959 1960 return rtn; 1961 } 1962 1963 int EclSolar::GRSBound(bool firstc, double& lat1, double& lng1, double& lat2, double& lng2) 1964 { 1965 /* Get the geographic coordinates of the boundaries for rise/set 1966 at time t. 1967 1968 INPUT: firstc : true for first call 1969 1970 OUTPUT: 1971 lat1, lng1; lat2, lng2 : latitude and longitude of first 1972 and second point ofboundary. 1973 If lat > 90 no respective point exists. 1974 1975 RETURN: 0 if end of eclipse, 1 otherwise 1976 */ 1977 const double flat = 0.996633; // flatting of the Earth 1978 1979 double s0, r0, dpn, t; 1980 Vec3 vrm, vre, vrc, vrx, vrx2; 1981 Mat3 m1, m2; 1982 1983 if (eb_lunactive) // only solar eclipses 1984 { 1985 lng1 = 0.0; 1986 lat1 = 100.0; 1987 lng2 = 0.0; 1988 lat2 = 100.0; 1989 eb_finished = true; 1990 return 0; 1991 }; 1992 1993 if (firstc) 1994 { 1995 InRSBound(); 1996 t = eb_jdstart + 1.0/86400.0; // just add a second to be beyond the limit 1997 eb_lastjd = t; 1998 eb_finished = false; 1999 } 2000 else 2001 { 2002 t = eb_lastjd + double(eb_cstep) / (24.0*60.0); 2003 eb_lastjd = t; 2004 }; 2005 2006 if (t >= eb_jdstop) 2007 { 2008 if (eb_finished) 2009 { 2010 lng1 = 0.0; 2011 lat1 = 100.0; 2012 lng2 = 0.0; 2013 lat2 = 100.0; 2014 return 0; 2015 }; 2016 t = eb_jdstop - 1.0/86400.0; // just to go to the very end and then stop 2017 eb_lastjd = t; 2018 eb_finished = true; 2019 }; 2020 2021 // get position of penumbra and shadow cone 2022 vrm = eb_ubm + (t - eb_jdstart) * eb_udm; 2023 vre = eb_ube + (t - eb_jdstart) * eb_ude; 2024 vre = vnorm (vre); // direction of penumbra boundary 2025 dpn = eb_dpb + (t - eb_jdstart) * eb_dpd; 2026 dpn *= 0.5; // half cone diameter 2027 vrx = carpol(vre); 2028 2029 m1 = zrot(vrx[1] + M_PI/2.0); 2030 m2 = xrot(M_PI/2.0 - vrx[2]); 2031 m1 = m2 * m1; // rotation from equatorial into fundamental plane 2032 m2 = mxtrn(m1); // rotation from fundamental plane into equatorial 2033 2034 // get vector to center of shadow in the fundamental plane 2035 s0 = - dot(vrm, vre); 2036 vrc = vrm + s0 * vre; 2037 2038 r0 = abs(vrc); // distance between center of Earth and center of shadow 2039 vrc = mxvct(m1, vrc); 2040 2041 lng1 = 0; 2042 lat1 = 100.0; 2043 lng2 = 0; 2044 lat2 = 100.0; 2045 // check whether intersection of Earth and shadow cone are possible 2046 // in fundamental plane 2047 if ((r0 > fabs(1.0 - dpn)) && (r0 < fabs(1.0 + dpn))) 2048 { 2049 // now find the intersections 2050 if (iscrs(vrc[0],vrc[1], dpn, vrx[0],vrx[1], vrx2[0],vrx2[1])) lat1 = 0; 2051 else 2052 { 2053 if (iscrs(vrc[1],vrc[0], dpn, vrx[1],vrx[0], vrx2[1],vrx2[0])) lat1 = 0; 2054 }; 2055 }; 2056 2057 // calculate the coordinates if there is an intersecton 2058 if (lat1 < 100.0) // there should be an intersection 2059 { 2060 vrx[2] = 0; 2061 vrx = mxvct(m2, vrx); 2062 vrx = vnorm(vrx); 2063 vrx[2] *= flat; // vector to intersection 2064 vre = carpol(vrx); 2065 lng1 = vre[1] - lsidtim(t,0,0)*0.261799387799; // geographic coordinates 2066 2067 if (lng1 > M_PI) lng1 -= 2.0*M_PI; 2068 if (lng1 < (-M_PI)) lng1 += 2.0*M_PI; 2069 lat1 = sqrt(vrx[0]*vrx[0] + vrx[1]*vrx[1])*0.993305615; 2070 lat1 = atan23(vrx[2],lat1); 2071 lat1 /= degrad; 2072 lng1 /= degrad; 2073 }; 2074 if (lat1 < 100.0) // intersection #2 2075 { 2076 vrx2[2] = 0; 2077 vrx2 = mxvct(m2, vrx2); 2078 vrx2 = vnorm(vrx2); 2079 vrx2[2] *= flat; // vector to intersection 2080 vre = carpol(vrx2); 2081 lng2 = vre[1] - lsidtim(t,0,0)*0.261799387799; // geographic coordinates 2082 if (lng2 > M_PI) lng2 -= 2.0*M_PI; 2083 if (lng2 < (-M_PI)) lng2 += 2.0*M_PI; 2084 lat2 = sqrt(vrx2[0]*vrx2[0] + vrx2[1]*vrx2[1])*0.993305615; 2085 lat2 = atan23(vrx2[2],lat2); 2086 lat2 /= degrad; 2087 lng2 /= degrad; 2088 }; 2089 2090 return 1; 2091 } 2092 2093 /*------------------------- EclDetails ---------------------------------*/ 2094 2095 double EclSolar::DegFDms (double h) 2096 { 2097 /* convert degrees from d.fff -> d.mmsss where .mm are the minutes 2098 and sss are seconds (and fractions of seconds). 2099 */ 2100 int mm, deg; 2101 double hh, t, sec; 2102 2103 hh = fabs(h); 2104 dms (hh,deg,mm,sec); 2105 if (sec>=59.5) 2106 { 2107 mm++; 2108 sec = 0; 2109 }; 2110 if (mm>59) 2111 { 2112 deg++; 2113 mm=0; 2114 }; 2115 hh = double(deg); 2116 t = double(mm)/100.0; 2117 hh += t; 2118 t = sec/10000.0; 2119 hh += t; 2120 if (h < 0) hh = -hh; 2121 2122 return hh; 2123 } 2124 2125 int EclSolar::localStart(int j, double *spt, double *ept, int *spp, 2126 int p, char *otxt) 2127 { 2128 /* get start and end times of the various phases of the eclipse 2129 j = index of the eclipse 2130 spt[i] = start time in MJD for phase i 2131 ept[i] = end time in MJD for phase i 2132 spp[i] = kind of phase i 2133 p = phase 2134 2135 RETURN: the number of different phases of this eclipse. 2136 2137 The step width will be 1 min 2138 */ 2139 int nump, eflg, pcur, pold, maxp, i, npflg; 2140 double magecl; // local magnitude of eclipse at jd 2141 double jd, step, jdf, d1, d2, elrise; 2142 double azim, elev, dist, phi, lamda; 2143 char dts[13]; 2144 char outb[127]; 2145 Vec3 gx; 2146 Eclipse eclp; 2147 2148 nump = 0; 2149 maxp = 0; 2150 eflg = 0; // end flag 2151 pold = 0; 2152 elev = 0; 2153 eb_lccnt = 0; 2154 eb_maxps = -1.0; 2155 eb_maxelv = -1.0; 2156 phi = eb_geolat * M_PI / 180.0; 2157 lamda = eb_geolong * M_PI / 180.0; 2158 jd = eb_eclmjd[j] - 0.5; // start 12 hours before maximum 2159 jdf = jd + 1.5; // emergency stop if something goes wrong with the loop 2160 step = 1.0/(24.0*60.0); // stepwidth 1 minute 2161 eb_ltotb = jd; 2162 eb_ltote = jd - 1.0; 2163 2164 do 2165 { 2166 if(p < 0) 2167 { 2168 pcur = eclp.lunar (jd, eb_del_tdut); 2169 gx = eclp.GetRMoon(); 2170 magecl = 1.0; // just set it 1. It's not needed for lunar eclipses. 2171 elrise = -9.89e-3; // allow for refraction during rise/set 2172 } 2173 else 2174 { 2175 pcur = eclp.solar (jd, eb_del_tdut,d1, d2); 2176 gx = eclp.GetRSun(); 2177 magecl = 0; 2178 elrise = -1.45e-2; // allow for refraction during rise/set 2179 }; 2180 2181 // check whether body is visible from local position. 2182 if (pcur > 0) 2183 { 2184 AppPos (jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 1, gx, 2185 azim, elev, dist); 2186 if ((p > 0) && (elev >= elrise)) 2187 { 2188 magecl = getlocmag(jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 2189 eclp.GetRSun(),eclp.GetRMoon(), i); 2190 if (magecl > eb_maxps) 2191 { 2192 eb_maxps = magecl; 2193 eb_maxelv = elev; 2194 eb_jdmaxps = jd; 2195 } 2196 } 2197 } 2198 2199 if ((eb_lccnt == 0) && (pcur != 0)) 2200 { 2201 if ((elev >= elrise) && (magecl > 0)) 2202 { 2203 eb_lcb1 = jd; 2204 eb_lccnt = 1; 2205 } 2206 } 2207 if (eb_lccnt == 1) 2208 { 2209 if ((elev < elrise) || (pcur == 0) || (magecl == 0)) 2210 { 2211 eb_lce1 = jd; 2212 eb_lccnt = 2; 2213 } 2214 } 2215 if ((eb_lccnt == 2) && (pcur != 0)) 2216 { 2217 if ((elev >= elrise) && (magecl > 0)) 2218 { 2219 eb_lcb2 = jd; 2220 eb_lccnt = 3; 2221 } 2222 } 2223 if (eb_lccnt == 3) 2224 { 2225 if ((elev < elrise) || (pcur == 0) || (magecl == 0)) 2226 { 2227 eb_lce2 = jd; 2228 eb_lccnt = 4; 2229 } 2230 } 2231 2232 // now check the start and stop times for the phases 2233 if (pcur > pold) 2234 { 2235 if(nump < 4) 2236 { 2237 spt[nump] = jd; 2238 spp[nump] = pcur; 2239 nump++; 2240 maxp++; 2241 pold = pcur; 2242 } 2243 } 2244 else if (pcur < pold) 2245 { 2246 npflg = 1; 2247 if (nump > 1) 2248 { 2249 if (pcur > spp[nump-2]) npflg = 0; 2250 } 2251 if (npflg) 2252 { 2253 nump--; 2254 if (nump >= 0) ept[nump] = jd; 2255 if (nump > 1) 2256 { 2257 if (pcur < spp[nump-1]) 2258 { 2259 nump--; 2260 ept[nump] = jd; 2261 } 2262 } 2263 if (nump <= 0) eflg = 1; 2264 } 2265 pold = pcur; 2266 }; 2267 2268 jd += step; 2269 if (jd > jdf) eflg = 1; 2270 2271 } while (eflg != 1); 2272 2273 // put the respective info into textfile otxt 2274 if(maxp > 0) 2275 { 2276 for (i=0; i<maxp; i++) 2277 { 2278 if (p < 0) 2279 { 2280 switch (spp[i]) 2281 { 2282 case 1: strcpy(outb,"penumbral "); 2283 break; 2284 case 2: strcpy(outb,"tot.penumb "); 2285 break; 2286 case 3: strcpy(outb,"partial "); 2287 break; 2288 case 4: strcpy(outb,"totality "); 2289 break; 2290 } 2291 } 2292 else 2293 { 2294 switch (spp[i]) 2295 { 2296 case 1: strcpy(outb,"partial "); 2297 break; 2298 case 2: strcpy(outb,"n-centr.Ann "); 2299 break; 2300 case 3: strcpy(outb,"n-centr.Tot "); 2301 break; 2302 case 4: strcpy(outb,"annularity "); 2303 break; 2304 case 5: strcpy(outb,"totality "); 2305 break; 2306 } 2307 } 2308 2309 strcat(otxt,"\n "); 2310 strcat(otxt, outb); 2311 strcat(otxt,"\tbegins "); 2312 dtmstr((spt[i]+eb_tzone/24.0),dts); 2313 dts[12] = '\0'; 2314 strcat(otxt,dts); 2315 strcat(otxt, "\tends "); 2316 dtmstr((ept[i]+eb_tzone/24.0),dts); 2317 dts[12] = '\0'; 2318 strcat(otxt,dts); 2319 } 2320 } 2321 if (maxp > 0) 2322 { 2323 if (eb_lccnt == 1) eb_lce1 = ept[0]; 2324 if (eb_lccnt == 3) eb_lce2 = ept[0]; 2325 } 2326 2327 if (eb_maxps > 0.8) // check for local central phase 2328 { 2329 jd = eb_jdmaxps - 16.0/(24.0*60.0); 2330 eb_ltote = jd + 32.0/(24.0*60.0); 2331 eflg = 0; 2332 do 2333 { 2334 jd += 1.0/86400.0; // go in seconds steps 2335 eclp.solar (jd, eb_del_tdut,d1, d2); 2336 gx = eclp.GetRSun(); 2337 AppPos (jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 1, gx, 2338 azim, elev, dist); 2339 if (elev >= elrise) 2340 { 2341 magecl = getlocmag(jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 2342 eclp.GetRSun(),eclp.GetRMoon(), i); 2343 if (magecl > eb_maxps) 2344 { 2345 eb_maxelv = elev; 2346 eb_maxps = magecl; 2347 eb_jdmaxps = jd; 2348 } 2349 if (i > 0) 2350 { 2351 eb_ltotb = jd; 2352 eflg = 1; 2353 } 2354 } 2355 if (jd > eb_ltote) eflg = 1; 2356 2357 } while (!eflg); 2358 2359 if (jd < eb_ltote) 2360 { 2361 eflg = 0; 2362 do 2363 { 2364 jd += 1.0/86400.0; // go in seconds steps 2365 eclp.solar (jd, eb_del_tdut,d1, d2); 2366 gx = eclp.GetRSun(); 2367 AppPos (jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 1, gx, 2368 azim, elev, dist); 2369 if (elev < elrise) eflg = 1; 2370 magecl = getlocmag(jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 2371 eclp.GetRSun(),eclp.GetRMoon(), i); 2372 if (magecl > eb_maxps) 2373 { 2374 eb_maxelv = elev; 2375 eb_maxps = magecl; 2376 eb_jdmaxps = jd; 2377 } 2378 if (i == 0) eflg = 1; 2379 if (jd > eb_ltote) eflg = 1; 2380 2381 } while (!eflg); 2382 eb_ltote = jd; 2383 } 2384 else eb_ltote = eb_ltotb - 1.0; 2385 } 2386 2387 return maxp; 2388 } 2389 2390 2391 void EclSolar::getLocalDetails(char *otxt) 2392 { 2393 /* get the details of the eclipse selected in eclbuf.select 2394 and place the output into otxt 2395 */ 2396 int j, p, i, ecloutbn; 2397 int dd, mm, yy, deg, mnt; 2398 double sec, hh; 2399 2400 int spp[4], nump; 2401 double spt[4], ept[4]; 2402 double jd, jdf; 2403 char dts[13]; 2404 char outb[127]; 2405 2406 if (!eb_start_called) eclStart(); 2407 eb_local_called = true; 2408 2409 j = eb_eclselect-1; 2410 p = eb_phase[j]; 2411 2412 ecloutbn = 3; 2413 sprintf(otxt,"+++ Timezone: %g +++ TT - UTC: %g (sec) +++ Year: %5i +++\n\n", eb_tzone, eb_del_tdut, eb_year); 2414 switch (p) 2415 { 2416 case 1: strcpy(outb,"\t\tPartial Eclipse of the Sun"); 2417 break; 2418 case 2: strcpy(outb,"\t\tNon-Central Annular Eclipse of the Sun"); 2419 break; 2420 case 3: strcpy(outb,"\t\tNon-Central Total Eclipse of the Sun"); 2421 break; 2422 case 4: strcpy(outb,"\t\tAnnular Eclipse of the Sun"); 2423 break; 2424 case 5: strcpy(outb, "\t\tTotal Eclipse of the Sun"); 2425 break; 2426 case 6: strcpy(outb, "\t\tAnnular/Total Solar Eclipse"); 2427 break; 2428 2429 case -1: 2430 case -2: strcpy(outb, "\t\tPenumbral Eclipse of the Moon"); 2431 break; 2432 case -3: strcpy(outb, "\t\tPartial eclipse of the Moon"); 2433 break; 2434 case -4: strcpy(outb, "\t\tTotal eclipse of the Moon"); 2435 break; 2436 }; 2437 2438 strcat(otxt,outb); 2439 sprintf(outb,"\n\nMaximum Eclipse at "); 2440 strcat(otxt,outb); 2441 dtmstr((eb_eclmjd[j]+eb_tzone/24.0),dts); 2442 dts[12] = '\0'; 2443 strcat(otxt,dts); 2444 if (p < 4) 2445 { 2446 sprintf(outb," with magnitude:%5.2f",eb_magnitude[j]); 2447 strcat(otxt, outb); 2448 } 2449 2450 strcat(otxt,"\n"); 2451 nump = localStart(j, spt, ept, spp, p, otxt); 2452 if ((p < 4) || (nump < 1)) ecloutbn = 5; 2453 2454 if (ecloutbn == 3) 2455 { 2456 // get start and stop dates for central phase 2457 jd = spt[nump-1]; 2458 for (i=0; i<nump; i++) 2459 if ((spt[i] < jd) && (spp[i] > 3)) jd = spt[i]; // start of central phase 2460 caldat(jd, dd, mm, yy, hh); 2461 dms (hh,deg,mnt,sec); 2462 sec = 0; 2463 i = mnt / eb_cstep; 2464 mnt = i* int(eb_cstep); // cut to proper time step 2465 hh = ddd (deg, mnt, sec); 2466 jdf = ept[nump-1]; 2467 for (i=0; i<nump; i++) 2468 if ((ept[i] > jdf) && (spp[i] > 3)) jdf = ept[i]; // end of central phase 2469 } 2470 2471 // local circumstances 2472 strcat(otxt, "\n\n\nLocal Circumstances for "); 2473 jd = eb_geolat; 2474 jdf = eb_geolong; 2475 sprintf(outb,"\nLat: %g Long: %g height: %g m\n\n", 2476 jd, jdf, eb_geoheight); 2477 strcat(otxt,outb); 2478 if (p != 0) 2479 { 2480 if (eb_lccnt > 0) 2481 { 2482 sprintf(outb,"Eclipse visible from "); 2483 dtmstr((eb_lcb1+eb_tzone/24.0),dts); 2484 dts[12] = '\0'; 2485 strcat(outb," "); 2486 strcat(outb,dts); 2487 strcat(outb," to "); 2488 dtmstr((eb_lce1+eb_tzone/24.0),dts); 2489 dts[12] = '\0'; 2490 strcat(outb,dts); 2491 if (eb_lccnt > 2) // this case almost never happens 2492 { 2493 strcat(otxt,outb); 2494 strcpy(outb,"\n\tand from "); 2495 dtmstr((eb_lcb2+eb_tzone/24.0),dts); 2496 dts[12] = '\0'; 2497 strcat(outb," "); 2498 strcat(outb,dts); 2499 strcat(outb," to "); 2500 dtmstr((eb_lce2+eb_tzone/24.0),dts); 2501 dts[12] = '\0'; 2502 strcat(outb,dts); 2503 } 2504 } 2505 else sprintf(outb,"Eclipse not visible"); 2506 strcat(otxt,outb); 2507 } 2508 2509 // local solar eclipse magnitude 2510 if ((p > 0) && (eb_lccnt > 0)) 2511 { 2512 sprintf(outb,"\nMaximum Eclipse at "); 2513 strcat(otxt,outb); 2514 dtmstr((eb_jdmaxps+eb_tzone/24.0),dts); 2515 dts[12] = '\0'; 2516 strcat(otxt,dts); 2517 sprintf(outb," with magnitude %6.3f", eb_maxps); 2518 strcat(otxt,outb); 2519 sprintf(outb," elev:%4.1f", 180.0*eb_maxelv/M_PI); 2520 strcat(otxt,outb); 2521 if (eb_ltotb <= eb_ltote) 2522 { // local central eclipse 2523 if ((p % 2) == 0) strcpy(outb, "\nannularity from"); 2524 else strcpy(outb, "\ntotality from"); 2525 if ((p == 1) || (p == 6)) 2526 strcpy(outb, "\ntotality/annularity from"); 2527 strcat(otxt,outb); 2528 caldat((eb_ltotb+eb_tzone/24.0), dd, mm, yy, hh); 2529 caldat((eb_ltote+eb_tzone/24.0), dd, mm, yy, jd); 2530 hh = DegFDms(hh); 2531 jd = DegFDms(jd); 2532 jdf = (eb_ltote - eb_ltotb) * 86400.0; 2533 sprintf(outb,"%8.4f to%8.4f del.t:%3.0f sec \n",hh,jd, jdf); 2534 strcat(otxt,outb); 2535 } 2536 } 2537 2538 eb_maxelv /= degrad; 2539 } 2540 2541 //---------Northern and Southern Umbra Boundaries --------------------- 2542 2543 double EclSolar::navCourse (double lat1, double lng1, double lat2, double lng2) 2544 { 2545 // get course (in radians) from (lat1, lng1) to (lat2, lng2) over the Earth surface 2546 // the geographic coordinates are in decimal degrees 2547 2548 double lt1, ln1, lt2, ln2, cd, an; 2549 2550 lt1 = lat1 * degrad; 2551 ln1 = lng1 * degrad; 2552 lt2 = lat2 * degrad; 2553 ln2 = lng2 * degrad; 2554 2555 cd = sin(lt1)*sin(lt2) + cos(lt1)*cos(lt2)*cos(ln2 - ln1); 2556 an = acos(cd); 2557 an = cos(lt1) * sin(an); 2558 2559 if (an == 0) return 0; // same spot. didn't move 2560 2561 cd = (sin(lt2) - sin(lt1)*cd) / an; 2562 an = acos (cd); 2563 2564 if (sin(ln2 - ln1) < 0) an = -an; 2565 2566 return an; 2567 } 2568 2569 void EclSolar::navNewPos (double d, double an, double lat1, double lng1, double &lat2, double &lng2) 2570 { 2571 /* 2572 starting from (lat1, lng1) along the great circle for d (radians) with course an (in radians) 2573 get the new position (lat2, lng2) (in decimal degrees) at the Earth surface 2574 */ 2575 2576 double cd, sd, lt1, ag; 2577 2578 ag = an; 2579 if (ag > M_PI) ag -= 2*M_PI; 2580 if (ag < -M_PI) ag += 2*M_PI; 2581 2582 cd = cos(d); 2583 lt1 = lat1 * degrad; 2584 2585 sd = cd * sin(lt1) + sin(d) * cos(lt1) * cos(ag); 2586 lat2 = asin(sd); 2587 2588 lng2 = cos(lt1) * cos(lat2); 2589 2590 if (lng2 == 0) // just in case to avoid a crash 2591 { 2592 lat2 = lat1; 2593 lng2 = lng1; 2594 return; 2595 } 2596 2597 lng2 = (cd - sin(lt1) * sd) / lng2; 2598 lng2 = acos(lng2); 2599 lng2 /= degrad; 2600 if (ag > 0) lng2 = lng1 + lng2; 2601 else lng2 = lng1 -lng2; 2602 if(lng2 > 360.0) lng2 -= 360.0; 2603 if(lng2 < 0) lng2 += 360.0; 2604 2605 lat2 /= degrad; 2606 2607 } 2608 2609 int EclSolar::centralBound(bool firstc, double& lat1, double& lng1, double& lat2, double& lng2) 2610 { 2611 /* Get the geographic coordinates of the northern or southern boundaries 2612 of the umbra at time t. 2613 INPUT: firstc :true for first call 2614 2615 OUTPUT: 2616 lat, lng : latitude and longitude of umbra boundary in decimal degrees. 2617 If lat > 90 no boundary exists. 2618 2619 RETURN: current phase if time within eclipse, <=3 if no central eclipse 2620 */ 2621 2622 bool lastp; 2623 int k; 2624 double dpn1, t; 2625 double lt1, ln1, lt2, ln2, an; 2626 Eclipse eclp; 2627 2628 if (!eb_start_called) eclStart(); 2629 2630 lng1 = 0.0; 2631 lat1 = 100.0; 2632 lng2 = 0.0; 2633 lat2 = 100.0; 2634 2635 lastp = false; 2636 2637 if (eb_lunactive) return 0; // only solar eclipses 2638 2639 2640 if (firstc) 2641 { 2642 k = eclPltCentral(true, lt1, ln1); 2643 } 2644 else k = eclPltCentral(false, lt1, ln1); 2645 t = eb_lastjd; 2646 2647 if (k <= 3) return k; // no central eclipse 2648 2649 k = eclPltCentral(false, lt2, ln2); // next step 2650 eb_lastjd = t; // go back to the original step 2651 2652 if (k <= 3) // try the last step instead at the end 2653 { 2654 eb_lastjd -= 2.0 * eb_cstep / (24.0*60.0); 2655 k = eclPltCentral(false, lt2, ln2); 2656 eb_lastjd = t; 2657 lastp = true; 2658 }; 2659 2660 if (k <= 3) return k; // no central eclipse 2661 2662 eclp.solar(t, eb_del_tdut, lat1, lng1); 2663 lat1 = 100.0; 2664 lng1 = 0; 2665 2666 an = navCourse (lt1, ln1, lt2, ln2); // direction of shadow along Earth surface 2667 an += 0.5*M_PI; // direction perpendicular to shadow movement (right boundary) 2668 2669 eclp.duration(t, eb_del_tdut, dpn1); // dpn1 is width of umbra in km 2670 dpn1 = (dpn1 / 111.1) * 0.0174533; // radians of umbra width 2671 dpn1 /= 2.0; 2672 navNewPos(dpn1, an, lt1, ln1, lat1, lng1); 2673 2674 an -= M_PI; // find opposite boundary 2675 2676 navNewPos(dpn1, an, lt1, ln1, lat2, lng2); 2677 2678 if (lastp) // we went the opposite way at the end 2679 { 2680 lt1 = lat2; 2681 ln1 = lng2; 2682 lat2 = lat1; 2683 lng2 = lng1; 2684 lat1 = lt1; 2685 lng1 = ln1; 2686 return 0; // end of eclipse 2687 } 2688 else return k; 2689 } 2690 2691 //-------------------- Shadow Cone ------------------------- 2692 2693 void EclSolar::getShadowCone(double mjd, bool umbra, int numpts, double* lat, double* lng) 2694 { 2695 /* Get the geographic coordinates of the shadow cone at MJD-time mjd. 2696 if umbra is true the umbra cone will be returned 2697 if umbra is false the penumbra will be returned 2698 2699 OUTPUT: 2700 lat and lng must be arrays of length numpts into which the numpts points will be placed 2701 if there is no (total) eclipse at the time, lat will be set 100.0, lng 0. 2702 */ 2703 2704 const double flat = 0.996633; // flatting of the Earth 2705 2706 int j, k1, k2, kmiss; 2707 double dpn1, pan1, s0, dlt, dta, ag; 2708 double s, r0, r2, dt1, dt2; 2709 Vec3 vrm, vre; 2710 Vec3 ubm, ube; 2711 Vec3 ax1, ax2; 2712 Mat3 mx1, mx2; 2713 Eclipse eclp; 2714 2715 if (numpts < 2) return; 2716 2717 for (j=0; j<numpts; j++) // just in case you got to return empty-handed 2718 { 2719 lat[j] = 100.0; 2720 lng[j] = 0; 2721 } 2722 2723 if (!eb_start_called) eclStart(); 2724 if (eb_lunactive) return; // only for solar eclipses 2725 2726 if (umbra && (eb_phase[eb_eclselect-1] < 1)) return; 2727 2728 // get the shadow details 2729 if(umbra) eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1); 2730 else eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn1, pan1); 2731 2732 dpn1 *= 0.5; 2733 2734 if (!umbra) 2735 { 2736 if (eb_penamode == 0) 2737 { 2738 dpn1 *= eb_penangle; 2739 pan1 *= eb_penangle; 2740 } 2741 2742 if (eb_penamode > 0) 2743 { 2744 s0 = eb_penangle * tan(pan1); 2745 s0 = atan(s0); 2746 if (pan1 > 0) 2747 { 2748 dpn1 = dpn1 * s0 / pan1; 2749 pan1 = s0; 2750 } 2751 } 2752 }; 2753 2754 // get apex of umbra/penumbra cone 2755 pan1 = tan(pan1); 2756 if (pan1 < 0.0000174533) return; // if cone is smaller that 0.001° 2757 dpn1 = dpn1 / pan1; 2758 2759 s0 = - dot(ubm, ube); 2760 ubm = ubm + (s0 - dpn1) * ube; 2761 2762 // get any vector perpendicular to the shadow 2763 ax1[0] = 0; 2764 ax1[1] = 0; 2765 ax1[2] = 1.0; 2766 ax2 = ax1 * ube; 2767 ax1 = vnorm(ax2) * pan1; 2768 2769 ax2 = carpol(ube); 2770 mx1 = zrot(ax2[1]); 2771 mx2 = yrot(ax2[2]) * mx1; // transform to a system where x points into the direction of the shadow 2772 mx1 = mxtrn(mx1); // to get back to equatorial system after rotation 2773 2774 ax2 = mxvct(mx2,ax1); // vector which we will rotate numpts times 2775 2776 // now loop for numpts points 2777 dta = 2.0*M_PI / double(numpts); 2778 2779 for (j=0; j<numpts; j++) 2780 { 2781 ag = double(j) * dta; // rotation angle of the cone vector 2782 mx2 = xrot(ag); 2783 ax1 = mxvct(mx2,ax2); 2784 ax1 = mxvct(mx1, ax1); 2785 2786 vre = ube + ax1; 2787 vre = vnorm(vre); // direction in which to find an intersection 2788 vrm[0] = ubm[0]; 2789 vrm[1] = ubm[1]; 2790 vrm[2] = ubm[2]; 2791 2792 s0 = - dot(vrm, vre); // distance Apex - fundamental plane 2793 r2 = dot (vrm,vrm); 2794 dlt = s0*s0 + 1.0 - r2; 2795 r0 = 1.0 - dlt; 2796 2797 if (r0 > 0) r0 = sqrt (r0); 2798 else r0 = 0; // distance center of Earth - shadow axis 2799 2800 // calculate the coordinates if there is an intersecton 2801 if (r0 < 1.0) // there should be an intersection 2802 { 2803 if (dlt > 0) dlt = sqrt(dlt); 2804 else dlt = 0; 2805 s = s0 - dlt; // distance Apex - fundamental plane 2806 vrm = vrm + s * vre; 2807 vrm = vnorm(vrm); 2808 vrm[2] *= flat; // vector to intersection 2809 vre = carpol(vrm); 2810 lng[j] = vre[1] - lsidtim(mjd,0,0)*0.261799387799; // geographic coordinates 2811 if (lng[j] > 2*M_PI) lng[j] -= 2.0*M_PI; 2812 if (lng[j] < 0.0) lng[j] += 2.0*M_PI; 2813 lat[j] = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615; 2814 lat[j] = atan23(vrm[2],lat[j]); 2815 lat[j] /= degrad; 2816 lng[j] /= degrad; 2817 2818 if (lng[j] < 0.0) lng[j] += 360.0; 2819 if (lng[j] > 360.0) lng[j] -= 360.0; 2820 } 2821 else // no intersection. 2822 { 2823 lat[j] = 100.0; 2824 lng[j] = 0; 2825 }; 2826 } 2827 2828 k1 = -1; 2829 k2 = -1; 2830 kmiss = 0; 2831 for (j=0; j<numpts; j++) // check for missing points 2832 { 2833 if (lat[j] < 100.0) 2834 { 2835 if (k1 < 0) k1 = j; // first valid point 2836 k2 = j; // last valid point 2837 } 2838 else kmiss++; 2839 } 2840 2841 if ((kmiss < 2) || (kmiss >= (numpts -1))) return; // cone completely on Earth surface or not at all 2842 2843 dt1 = double(k1) * dta; 2844 dt2 = double(k2) * dta; 2845 k1--; 2846 k2++; 2847 if (k1 < 0) k1 = numpts - 1; // wrap around 2848 if (k2 >= (numpts-1)) k2 = 0; 2849 dta = 2.0*M_PI / double(numpts*20); 2850 2851 for (j=1; j<20; j++) // go in smaller steps to get closer to the borderline 2852 { 2853 ag = dt1 - double(j) * dta; // rotation angle of the cone vector 2854 mx2 = xrot(ag); 2855 ax1 = mxvct(mx2,ax2); 2856 ax1 = mxvct(mx1, ax1); 2857 2858 vre = ube + ax1; 2859 vre = vnorm(vre); // direction in which to find an intersection 2860 vrm[0] = ubm[0]; 2861 vrm[1] = ubm[1]; 2862 vrm[2] = ubm[2]; 2863 2864 s0 = - dot(vrm, vre); // distance Apex - fundamental plane 2865 r2 = dot (vrm,vrm); 2866 dlt = s0*s0 + 1.0 - r2; 2867 r0 = 1.0 - dlt; 2868 2869 if (r0 > 0) r0 = sqrt (r0); 2870 else r0 = 0; // distance center of Earth - shadow axis 2871 2872 // calculate the coordinates if there is an intersecton 2873 if (r0 < 1.0) // there should be an intersection 2874 { 2875 if (dlt > 0) dlt = sqrt(dlt); 2876 else dlt = 0; 2877 s = s0 - dlt; // distance Apex - fundamental plane 2878 vrm = vrm + s * vre; 2879 vrm = vnorm(vrm); 2880 vrm[2] *= flat; // vector to intersection 2881 vre = carpol(vrm); 2882 lng[k1] = vre[1] - lsidtim(mjd,0,0)*0.261799387799; // geographic coordinates 2883 if (lng[k1] > 2*M_PI) lng[k1] -= 2.0*M_PI; 2884 if (lng[k1] < 0.0) lng[k1] += 2.0*M_PI; 2885 lat[k1] = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615; 2886 lat[k1] = atan23(vrm[2],lat[k1]); 2887 lat[k1] /= degrad; 2888 lng[k1] /= degrad; 2889 2890 if (lng[k1] < 0.0) lng[k1] += 360.0; 2891 if (lng[k1] > 360.0) lng[k1] -= 360.0; 2892 } 2893 else break; 2894 } 2895 2896 for (j=1; j<20; j++) // go in smaller steps to get closer to the borderline 2897 { 2898 ag = dt2 + double(j) * dta; // rotation angle of the cone vector 2899 mx2 = xrot(ag); 2900 ax1 = mxvct(mx2,ax2); 2901 ax1 = mxvct(mx1, ax1); 2902 2903 vre = ube + ax1; 2904 vre = vnorm(vre); // direction in which to find an intersection 2905 vrm[0] = ubm[0]; 2906 vrm[1] = ubm[1]; 2907 vrm[2] = ubm[2]; 2908 2909 s0 = - dot(vrm, vre); // distance Apex - fundamental plane 2910 r2 = dot (vrm,vrm); 2911 dlt = s0*s0 + 1.0 - r2; 2912 r0 = 1.0 - dlt; 2913 2914 if (r0 > 0) r0 = sqrt (r0); 2915 else r0 = 0; // distance center of Earth - shadow axis 2916 2917 // calculate the coordinates if there is an intersecton 2918 if (r0 < 1.0) // there should be an intersection 2919 { 2920 if (dlt > 0) dlt = sqrt(dlt); 2921 else dlt = 0; 2922 s = s0 - dlt; // distance Apex - fundamental plane 2923 vrm = vrm + s * vre; 2924 vrm = vnorm(vrm); 2925 vrm[2] *= flat; // vector to intersection 2926 vre = carpol(vrm); 2927 lng[k2] = vre[1] - lsidtim(mjd,0,0)*0.261799387799; // geographic coordinates 2928 if (lng[k2] > 2*M_PI) lng[k2] -= 2.0*M_PI; 2929 if (lng[k2] < 0.0) lng[k2] += 2.0*M_PI; 2930 lat[k2] = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615; 2931 lat[k2] = atan23(vrm[2],lat[k2]); 2932 lat[k2] /= degrad; 2933 lng[k2] /= degrad; 2934 2935 if (lng[k2] < 0.0) lng[k2] += 360.0; 2936 if (lng[k2] > 360.0) lng[k2] -= 360.0; 2937 } 2938 else break; 2939 } 2940 2941 } 2942