File indexing completed on 2024-04-21 03:48: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