• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

marble

  • sources
  • kde-4.14
  • kdeedu
  • marble
  • src
  • lib
  • astro
eclsolar.cpp
Go to the documentation of this file.
1 //
2 // This file is part of the Marble Virtual Globe.
3 //
4 // This program is free software licensed under the GNU LGPL. You can
5 // find a copy of this license in LICENSE.txt in the top directory of
6 // the source code.
7 //
8 // Copyright 2012 Gerhard HOLTKAMP
9 //
10 
11 /***************************************************************************
12 * Calculate Solar Eclipses *
13 * *
14 * *
15 * The algorithm for the phases of the Moon and of the dates for the *
16 * equinoxes and solstices of the Sun as well as the dates of eclipses *
17 * are based on Jean Meeus "Astronomical Formulae for Calculators", *
18 * Willman-Bell, Inc., Richmond, Virginia, 1988 *
19 * *
20 * The algorithm for the Modified Julian Date and the calendar as well as *
21 * the detailed eclipse calculations are based on *
22 * O.Montebruck and T.Pfleger, "Astronomy with a PC", *
23 * Springer Verlag, Berlin, Heidelberg, New York, 1989 *
24 * and on the *
25 * "Explanatory Supplement to the Astronomical Almanac" *
26 * University Science Books, Mill Valley, CA, 1992 *
27 * *
28 * Open Source Code. License: GNU LGPL Version 2+ *
29 * *
30 * Author: Gerhard HOLTKAMP, 28-JAN-2013 *
31 ***************************************************************************/
32 
33 /*------------ include files and definitions -----------------------------*/
34 #include "eclsolar.h"
35 #include <cstdio>
36 #include <cstdlib>
37 #include <cstring>
38 #include <cmath>
39 #include <ctime>
40 using namespace std;
41 
42 #include "astrolib.h"
43 
44 /* const double PI = 3.14159265359; */
45 const double degrad = M_PI / 180.0;
46 
47 // ################ Solar Eclipse Class ####################
48 
49 EclSolar::EclSolar()
50 {
51  esinit();
52 }
53 
54 EclSolar::~EclSolar()
55 {
56 
57 }
58 
59 double EclSolar::atan23 (double y, double x)
60  {
61  /* redefine atan2 so that it does'nt crash when both x and y are 0 */
62  double result;
63 
64  if ((x == 0) && (y == 0)) result = 0;
65  else result = atan2 (y, x);
66 
67  return result;
68  }
69 
70 void EclSolar::esinit()
71 {
72  // initialize eclipse data
73  eb_start_called = false;
74  eb_moonph_called = false;
75  eb_lunecl = true;
76  eb_lunactive = false;
77  eb_local_called = false;
78 
79  eb_day = 1;
80  eb_month = 1;
81  eb_year = 2012;
82  eb_hour = 0;
83  eb_minute = 0;
84  eb_second = 0;
85  eb_tzone = 0;
86  eb_del_auto = 1;
87  DefTime();
88  eb_time = 0;
89  eb_del_tdut = DefTdUt(eb_year);
90  eb_geolat = 0;
91  eb_geolong = 0;
92  eb_geoheight = 0;
93  eb_lstcall = 0;
94  eb_locecl = 0;
95  eb_lastyear = -9999;
96  eb_numecl = 0;
97  eb_lasttz = eb_tzone;
98  eb_lastdlt = eb_del_tdut;
99  eb_cstep = 1.0;
100  eb_cmxlat = 0;
101  eb_cmxlng = 0;
102  eb_penangle = 1.0;
103  eb_penamode = 0;
104 }
105 
106 void EclSolar::DefTime () // Get System Time and Date
107  {
108  time_t tt;
109  int hh, mm, ss;
110  double jd, hr;
111 
112  tt = time(NULL);
113  jd = 40587.0 + tt/86400.0; // seconds since 1-JAN-1970
114 
115  caldat(jd, hh, mm, ss, hr);
116  eb_year = ss;
117  eb_month = mm;
118  eb_day = hh;
119 
120  dms(hr, hh, mm, jd);
121  eb_hour = hh;
122  eb_minute = mm;
123  eb_second = int(jd);
124  if (eb_del_auto) eb_del_tdut = DefTdUt(eb_year);
125  };
126 
127 int EclSolar::getYear() const
128 {
129  return eb_year;
130 }
131 
132 void EclSolar::putYear(int yr)
133 {
134  eb_start_called = false;
135  eb_moonph_called = false;
136  eb_local_called = false;
137  eb_lunactive = false;
138 
139  eb_year = yr;
140  if (eb_del_auto) eb_del_tdut = DefTdUt(eb_year);
141  moonph();
142 
143 }
144 
145 int EclSolar::getNumberEclYear()
146 {
147  // RETURN the number of eclipses of the currently selected year
148 
149  int j, k;
150 
151  if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
152 
153  if (eb_lunecl) return eb_numecl;
154 
155  k = 0;
156  for (j=0; j<eb_numecl; j++)
157  {
158  if (eb_phase[j] > 0) k++;
159  }
160 
161  return k;
162 }
163 void EclSolar::setLunarEcl(bool lecl)
164 {
165  // if lecl = true include lunar eclipses in addition to solar ones
166  if (lecl) eb_lunecl = true;
167  else eb_lunecl = false;
168  eb_start_called = false;
169  eb_local_called = false;
170 }
171 
172 void EclSolar::setStepWidth(double s)
173 {
174  // set the step width (in minutes) used for calculations
175  if (s < 0.01) eb_cstep = 0.01;
176  else eb_cstep = s;
177 }
178 
179 void EclSolar::setTimezone(double d)
180 {
181  // set the timezone to d (hours difference from UTC) for I/O
182  eb_tzone = d;
183 }
184 
185 void EclSolar::setDeltaTAI_UTC(double d)
186 {
187  // c is the difference between TAI and UTC according to the IERS
188  // we have to add 32.184 sec to get to the difference TT - UT
189  // which is used in the calculations here
190 
191  eb_del_tdut = d + 32.184;
192  eb_del_auto = 0;
193 }
194 
195 void EclSolar::setAutoTAI_UTC()
196 {
197  // set the difference between TAI and UTC according to the IERS
198  eb_del_auto = true;
199  eb_del_tdut = DefTdUt(eb_year);
200 }
201 
202 void EclSolar::setLocalPos(double lat, double lng, double hgt)
203 {
204  // set the geographic coordinates for the position of the local info
205  // latitude lat, longitude lng in decimal degrees
206  // height hgt in meters
207 
208  eb_geolat = lat;
209  eb_geolong = lng;
210  eb_geoheight = hgt;
211 
212  eb_local_called = false;
213 }
214 
215 int EclSolar::getLocalVisibility(double &mjd_start, double &mjd_stop)
216 {
217  // local start and stop times (MJD) for eclipse
218  // RETURN 0 if not locally visible
219 
220  char wbuf[700];
221 
222  if (!eb_local_called) getLocalDetails(wbuf);
223 
224  mjd_start = eb_lcb1;
225  mjd_stop = eb_lce1;
226 
227  return eb_lccnt;
228 }
229 
230 int EclSolar::getLocalTotal(double &mjd_start, double &mjd_stop)
231 {
232  // local start and stop times (MJD) for totality/annularity
233  // RETURN 0 if not locally visible
234 
235  int k, j;
236  char wbuf[700];
237 
238  if (!eb_local_called) getLocalDetails(wbuf);
239 
240  mjd_start = 0;
241  mjd_stop = 0;
242 
243  if(eb_lccnt == 0) return 0;
244 
245  k = 0;
246  if(eb_lunactive)
247  {
248  for (j=0; j<eb_nphase; j++)
249  {
250  if ((k==0) && (eb_spp[j] > 3))
251  {
252  mjd_start = eb_spt[j];
253  mjd_stop = eb_ept[j];
254  k = 1;
255  }
256  }
257 
258  if(mjd_start < eb_lcb1) mjd_start = eb_lcb1;
259  if(mjd_start > eb_lce1) k = 0;
260  if(mjd_stop > eb_lce1) mjd_stop = eb_lce1;
261  if(mjd_stop < eb_lcb1) k = 0;
262 
263  eb_ltotb = mjd_start;
264  eb_ltote = mjd_stop;
265 
266  }
267  else k = eb_lccnt;
268 
269  mjd_start = eb_ltotb;
270  mjd_stop = eb_ltote;
271 
272  return k;
273 }
274 
275 int EclSolar::getLocalMax(double &mjdmax, double &magmax, double &elmax)
276 {
277 // get local (solar) eclipse maximum
278 // mjdmax : Modified Julian Date of maximum eclipse
279 // magmax : maximum (local) magnitude of eclipse
280 // elmax : local Sun elevation at maximum
281 
282 // RETURN : 0 if eclipse not visible
283 
284 int k;
285 
286  mjdmax = 0;
287  magmax = 0;
288  elmax = 0;
289 
290  if (eb_lunactive) return 0;
291 
292  k = getLocalVisibility(mjdmax, magmax);
293 
294  if (k != 0)
295  {
296  mjdmax = eb_jdmaxps;
297  magmax = eb_maxps;
298  elmax = eb_maxelv;
299  }
300 
301  return k;
302 }
303 
304 int EclSolar::getPenumbra(double &mjd_start, double &mjd_stop)
305 {
306  // start and stop times (MJD) for penumbral eclipse of Moon
307  // RETURN 0 if no lunar eclipse
308 
309  int j, k;
310 
311  if (!eb_start_called) eclStart();
312 
313  mjd_start = 0;
314  mjd_stop = 0;
315 
316  if (!eb_lunactive) return 0;
317 
318  if (eb_nphase <= 0) return 0;
319 
320  k = 0 ;
321  for (j=0; j<eb_nphase; j++)
322  {
323  if (eb_spp[j] == 1)
324  {
325  mjd_start = eb_spt[j];
326  mjd_stop =eb_ept[j];
327  k = 1;
328  }
329  }
330 
331  return k;
332 }
333 
334 int EclSolar::getPartial(double &mjd_start, double &mjd_stop)
335 {
336  // (global) start and stop times (MJD) for partial phase
337  // RETURN 0 if no lunar eclipse
338 
339  int j, k;
340 
341  if (!eb_start_called) eclStart();
342 
343  mjd_start = 0;
344  mjd_stop = 0;
345 
346  if (eb_nphase <= 0) return 0;
347 
348  k = 0;
349 
350  if(eb_lunactive)
351  {
352  for (j=0; j<eb_nphase; j++)
353  {
354  if ((k==0) && (eb_spp[j] == 3))
355  {
356  mjd_start = eb_spt[j];
357  mjd_stop =eb_ept[j];
358  k = 1;
359  }
360  }
361  }
362  else
363  {
364  for (j=0; j<eb_nphase; j++)
365  {
366  if ((k==0) && (eb_spp[j] == 1))
367  {
368  mjd_start = eb_spt[j];
369  mjd_stop =eb_ept[j];
370  k = 1;
371  }
372  }
373  }
374 
375  return k;
376 
377 }
378 
379 int EclSolar::getTotal(double &mjd_start, double &mjd_stop)
380 {
381  // (global) start and stop times (MJD) for totality/annularity
382  // RETURN 0 if no lunar eclipse
383 
384  int j, k;
385 
386  if (!eb_start_called) eclStart();
387 
388  mjd_start = 0;
389  mjd_stop = 0;
390 
391  if (eb_nphase <= 0) return 0;
392 
393  k = 0;
394 
395  if(eb_lunactive)
396  {
397  for (j=0; j<eb_nphase; j++)
398  {
399  if ((k==0) && (eb_spp[j] > 3))
400  {
401  mjd_start = eb_spt[j];
402  mjd_stop =eb_ept[j];
403  k = 1;
404  }
405  }
406  }
407  else
408  {
409  for (j=0; j<eb_nphase; j++)
410  {
411  if ((k==0) && (eb_spp[j] > 1))
412  {
413  mjd_start = eb_spt[j];
414  mjd_stop =eb_ept[j];
415  k = 1;
416  }
417  }
418  }
419 
420  return k;
421 
422 }
423 
424 void EclSolar::setCurrentMJD(int year, int month, int day, int hour, int min, double sec)
425 {
426  // set the (MJD-) time currently used for calculations to year, month, day, hour, min, sec
427  // corrected for timezone
428 
429  double jd;
430 
431  jd = ddd(hour, min, sec) - eb_tzone;
432  jd = mjd(day, month, year, jd);
433 
434  eb_lastjd = jd;
435 
436 }
437 
438 void EclSolar::getDatefromMJD(double mjd, int &year, int &month, int &day, int &hour, int &min, double &sec) const
439 {
440  // convert times given in Modified Julian Date (MJD) into conventional date and time
441  // correct for timezone
442 
443  double magn;
444 
445  caldat((mjd + eb_tzone/24.0), day, month, year, magn);
446  dms (magn,hour,min,sec);
447  if (sec>30.0) min++;;
448  if (min>59)
449  {
450  hour++;
451  min=0;
452  };
453 
454 }
455 
456 //---------------------- getEclYearInfo--------------------------------
457 
458 void EclSolar::getEclYearInfo(char* wbuf)
459  {
460  // output the eclipse dates in buffer wbuf accurate to the minute.
461 
462  char dts[13];
463  char outbuf[127];
464  char magbuf[30];
465  int j, p, kecl;
466 
467  if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
468 
469  sprintf(wbuf,"Solar Eclipses for %4i UTC +%4.1f", eb_year, eb_tzone);
470 
471  kecl = 1;
472  for (j=0; j<eb_numecl; j++)
473  {
474  sprintf(dts,"%1i : ", kecl);
475  strcpy (outbuf,dts);
476  dtmstr((eb_eclmjd[j] + eb_tzone/24.0),dts);
477  dts[12] = '\0';
478  strcat (outbuf,dts);
479  p = eb_phase[j];
480 
481  switch (p)
482  {
483  case 1: strcat(outbuf,"\t Partial Sun");
484  sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
485  strcat(outbuf,magbuf);
486  break;
487 
488  case 2: strcat(outbuf,"\t non-central Annular Sun");
489  break;
490  case 4: strcat(outbuf,"\t Annular Sun");
491  break;
492 
493  case 3: strcat(outbuf, "\t non-central Total Sun");
494  break;
495  case 5: strcat(outbuf, "\t Total Sun");
496  break;
497 
498  case 6: strcat(outbuf, "\t Annular/Total Sun");
499  break;
500 
501  case -1:
502  case -2: strcat(outbuf, "\t Penumbral Moon");
503  sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
504  strcat(outbuf,magbuf);
505  break;
506 
507  case -3: strcat(outbuf, "\t Partial Moon");
508  sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
509  strcat(outbuf,magbuf);
510  break;
511 
512  case -4: strcat(outbuf, "\t Total Moon");
513  sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
514  strcat(outbuf,magbuf);
515  break;
516  };
517 
518  if ((p > 0) || eb_lunecl) // solar eclipse only or also lunar eclipses
519  {
520  strcat (wbuf, "\n");
521  strcat (wbuf, outbuf);
522  kecl++;
523  };
524  }
525  }
526 
527 int EclSolar::getEclYearInfo(int k, int &yr, int &month, int &day,
528  int &hour, int &min, double &sec, double &tzone, double &magn)
529 {
530  /* output the eclipse info for k-th eclipse
531 
532  year, month, day, hour, minutes, seconds and timezone
533  magn = magnitude of eclipse
534 
535  RETURN: phase of eclipse. 0 if no k-th eclipse
536 
537  1: Partial Sun
538  2: non-central Annular Sun
539  3: non-central Total Sun
540  4: Annular Sun
541  5: Total Sun
542  6: Annular/Total Sun
543 
544  -1, -2: Penumbral Moon
545  -3: Partial Moon
546  -4: Total Moon
547 
548  */
549  bool nls;
550  int j, p, kecl;
551 
552  nls = true;
553 
554  if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
555 
556  if (k < 1)
557  {
558  k = eb_eclselect; // select current eclipse as default
559  nls = false;
560  };
561  if ((k < 1) && (k > eb_numecl)) return 0;
562 
563  p = k - 1;
564  if (nls && (!eb_lunecl))
565  {
566  kecl = 0;
567  p = -1;
568  for(j=0; j<eb_numecl; j++)
569  {
570  if (eb_phase[j] > 0)
571  {
572  kecl++;
573  if (kecl == k) p = j;
574  };
575  };
576  };
577 
578  if (p < 0) return 0;
579 
580  j = p;
581 
582  // convert MJD into corresponding date and time
583  caldat((eb_eclmjd[j] + eb_tzone/24.0), day, month, yr, magn);
584  dms (magn,hour,min,sec);
585  if (sec>30.0) min++;;
586  if (min>59)
587  {
588  hour++;
589  min=0;
590  };
591 
592  magn = eb_magnitude[j];
593  tzone = eb_tzone;
594 
595  return eb_phase[j];
596 }
597 
598 int EclSolar::getEclTxt (int k, char* jtxt)
599  {
600  // get the data / kind of eclipse info for the j-th eclipse
601  // and place it into jtxt
602 
603  // RETURN : the phase of the eclipse. 0 if no j-th eclipse
604 
605  int p, j;
606  char dts[13];
607 
608  if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
609 
610  if (k < 1) k = eb_eclselect; // select current eclipse as default
611  if ((k < 1) && (k > eb_numecl)) return 0;
612 
613  j = k-1;
614 
615  sprintf(jtxt, "%2i :", (j+1));
616  sprintf(dts, "%5i ", eb_year);
617  strcat (jtxt, dts);
618  dtmstr((eb_eclmjd[j]+eb_tzone/24.0),dts);
619  dts[6] = '\0';
620  strcat (jtxt,dts);
621 
622  p = eb_phase[j];
623  switch (p)
624  {
625  case 1: strcat(jtxt," Par.Sun");
626  break;
627  case 2: strcat(jtxt, " non-centr.Ann.Sun");
628  break;
629  case 4: strcat(jtxt," Ann.Sun");
630  break;
631  case 3: strcat(jtxt," non-centr.Tot.Sun");
632  break;
633  case 5: strcat(jtxt," Tot.Sun");
634  break;
635  case 6: strcat(jtxt," Ann/Tot.");
636  break;
637 
638  case -1:
639  case -2: strcat(jtxt," Pen.Moon");
640  break;
641  case -3: strcat(jtxt," Par.Moon");
642  break;
643  case -4: strcat(jtxt," Tot.Moon");
644  break;
645  };
646 
647  return p;
648  }
649 
650 // ----------------------------- Select Eclipse -------------------------
651 
652 void EclSolar::putEclSelect(int es)
653 {
654  // store the number of the eclipse selected for detailed calculations
655  int k, j;
656 
657  if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
658 
659  k = 0;
660 
661  eb_lunactive = false;
662  eb_eclselect = 1;
663  for (j=0; j<eb_numecl; j++)
664  {
665  if ((eb_phase[j] > 0) || eb_lunecl) // only solar eclipses if set
666  {
667  k++;
668  if (k == es)
669  {
670  eb_eclselect = j + 1;
671  if (eb_phase[j] < 0) eb_lunactive = true;
672  };
673  };
674  };
675  eb_start_called = false;
676 }
677 
678 void EclSolar::nextEcl()
679 {
680  // select the next eclipse for detailed calculations
681  int k, j, es;
682 
683  if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
684  eb_start_called = false;
685 
686  k = eb_eclselect + 1;
687  if (k > eb_numecl)
688  {
689  k = eb_year + 1;
690  putYear (k);
691  k = 1;
692  putEclSelect(k);
693 
694  return;
695  };
696 
697  if (eb_lunecl) // easier when lunar eclipses are included
698  {
699  putEclSelect(k);
700 
701  return;
702  };
703 
704  eb_lunactive = false;
705 
706  es = eb_eclselect;
707  k = 0;
708  for (j=es; j<eb_numecl; j++)
709  {
710  if ((k == 0) && (eb_phase[j] > 0)) k = j + 1;
711  };
712 
713  if(k > 0)
714  {
715  eb_eclselect = k;
716  return;
717  }
718 
719  k = eb_year + 1;
720  putYear (k);
721  es = 1;
722  putEclSelect(es);
723 
724 }
725 
726 void EclSolar::previousEcl()
727 {
728  // select the prevoius eclipse for detailed calculations
729  int k, j, es;
730 
731  if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
732  eb_start_called = false;
733 
734  k = eb_eclselect - 1;
735 
736  if (k <= 0)
737  {
738  k = eb_year - 1;
739  putYear (k);
740  k = eb_numecl;
741  };
742 
743  if (eb_lunecl) // easier when lunar eclipses are included
744  {
745  putEclSelect(k);
746 
747  return;
748  };
749 
750  eb_lunactive = false;
751 
752  es = 0;
753  k--;
754  for (j=k; j>=0; j--)
755  {
756  if ((es == 0) && (eb_phase[j] > 0)) es = j + 1;
757  };
758 
759  if(es > 0) eb_eclselect = es;
760  else putEclSelect(0); // this case should never happen!
761 
762 }
763 
764 double EclSolar::getLastMJD() const
765 {
766  // RETURN the MJD last used in calculations
767 
768  return eb_lastjd;
769 }
770 
771 void EclSolar::setPenumbraAngle(double pa, int mode)
772 {
773  /* set the Penumbra Angle
774  if mode == 0 the angle will be set to pa-times the maximum angle
775  (pa < 1.0). Set pa = 1 for the normal penumbra boundaries
776 
777  if mode == 1 the angle will be set such that the penumbra line
778  markes magnitude pa. pa == 0 will mark normal penumbra boudaries
779 
780  if mode == 2 the angle will be set such that the penumbra line
781  markes the obscuration pa. pa == 0.5 will mean that 50% of the Sun's
782  disk is covered by the Moon etc.
783  */
784 
785  double mjd, dpn1, dpn2, pan1, pan2;
786  double mag, m1, m2, s, ps;
787  int j;
788  Vec3 ubm, ube;
789  Eclipse eclp;
790 
791  if (mode == 0)
792  {
793  eb_penangle = pa;
794  eb_penamode = 0;
795  if (pa > 1.0) eb_penangle = 1.0;
796  if (pa < 0) eb_penangle = 1.0;
797 
798  return;
799  }
800 
801  if (!eb_start_called) eclStart();
802 
803  if (mode == 1)
804  {
805  eb_penamode = 1;
806  mjd = eb_eclmjd[eb_eclselect-1];
807  eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1);
808  eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn2, pan2);
809 
810  if(dpn2 > 0)
811  {
812  eb_penangle = fabs(pa);
813  if(eb_penangle > 1.0) eb_penangle = 1.0;
814  eb_penangle = 1.0 - eb_penangle * (1.0 + dpn1 / dpn2);
815  }
816  else eb_penangle = 1.0;
817 
818  return;
819  }
820 
821  if (mode == 2)
822  {
823  eb_penamode = 2;
824  mjd = eb_eclmjd[eb_eclselect-1];
825  eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1);
826  eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn2, pan2);
827 
828  ps = pa; // find the magnitude that corresponds to the obscuration
829  if (ps > 1.0) ps = 1.0;
830  if (ps < 0) ps = 0;
831  for (j=1; j<11; j++)
832  {
833  mag = double(j) * 0.1;
834  s = sunObscure(dpn2, dpn1, mag);
835  if (s >= ps) break;
836  }
837 
838  m1 = mag - 0.1;
839  m2 = mag;
840  for (j=0; j<8; j++) // 8 iterations should be plenty
841  {
842  mag = (m2 + m1) * 0.5;
843  s = sunObscure(dpn2, dpn1, mag);
844  if (s > ps) m2 = mag;
845  else m1 = mag;
846  }
847 
848  if(dpn2 > 0)
849  {
850  eb_penangle = fabs(mag);
851  if(eb_penangle > 1.0) eb_penangle = 1.0;
852  eb_penangle = 1.0 - eb_penangle * (1.0 + dpn1 / dpn2);
853  }
854  else eb_penangle = 1.0;
855 
856  return;
857  }
858 
859  eb_penamode = 0;
860  eb_penangle = 1.0;
861 
862 }
863 
864 // -------- auxilliary functions --------------------------------
865 void EclSolar::GetMonth (int mm, char* mchr)
866  {
867  // get three letter designation of month
868  // mm is the number of the month
869  // mchr is a char[4] array to receive the three letters of the month
870 
871  switch (mm)
872  {
873  case 1 : strcpy(mchr,"JAN"); break;
874  case 2 : strcpy(mchr,"FEB"); break;
875  case 3 : strcpy(mchr,"MAR"); break;
876  case 4 : strcpy(mchr,"APR"); break;
877  case 5 : strcpy(mchr,"MAY"); break;
878  case 6 : strcpy(mchr,"JUN"); break;
879  case 7 : strcpy(mchr,"JUL"); break;
880  case 8 : strcpy(mchr,"AUG"); break;
881  case 9 : strcpy(mchr,"SEP"); break;
882  case 10 : strcpy(mchr,"OCT"); break;
883  case 11 : strcpy(mchr,"NOV"); break;
884  case 12 : strcpy(mchr,"DEC"); break;
885  default: strcpy(mchr,"ERR");
886  };
887 }
888 
889 double EclSolar::phmjd (double yearf, double phase, double tdut,
890  int& eph, double& ejd, double& emag)
891  /*
892  Calculate the Modified Julian Date of the occurrence of the specified
893  phase of the Moon and check for possible eclipses.
894  yearf : year.fraction of date close to the Moon phase
895  phase : 0 for New Moon,
896  0.25 for First Quarter,
897  0.5 for Full Moon,
898  0.75 for Last Quarter.
899  tdut = TDT - UT in sec
900 
901  RETURN: the MJD of the lunar phase event
902 
903  OUTPUT:
904  eph : phase of the eclipse on that date
905  0 = no eclipse, 1 = partial solar eclipse,
906  2 = non-central annular, 3 = non-central total
907  4 = annular solar, 5 = total solar,
908  6 = annular/total solar, -1 =partial penumbral lunar,
909  -2 = total penumbral lunar, -3 = partial umbral lunar,
910  -4 = total umbral lunar
911  ejd : Modified Julian Date of the maximum of the eclipse (if any)
912  emag : magnitude of the eclipse (if any)
913  */
914  {
915  double tt, jd, k, m, p, f;
916  double s, c, gam, u;
917  int tst;
918  Eclipse eclp;
919 
920  // preliminary (modified) Julian Date
921  k = floor ((yearf - 1900.0) * 12.3685) + phase;
922  tt = k / 1236.85;
923  jd = 166.56 + (132.87 - 0.009173*tt)*tt;
924  jd = 15020.25933 + 29.53058868*k
925  + (0.0001178 - 0.000000155*tt)*tt*tt
926  + 0.00033 * sin (degrad*jd);
927 
928  eph = 0; // assume no eclipse
929 
930  // Sun's mean anomaly
931  m = degrad * (359.2242 + 29.10535608*k
932  - (0.0000333 - 0.00000347*tt)*tt*tt);
933  // Moon's mean anomaly
934  p = degrad * (306.0253 + 385.81691808*k
935  + (0.0107306 + 0.00001236*tt)*tt*tt);
936  // 2* Moon's argument of latitude
937  f = 2.0 * degrad * (21.2964 + 390.67050646*k
938  - (0.0016528 - 0.00000239*tt)*tt*tt);
939 
940  if ((phase == 0) || (phase == 0.5)) // for Full and New Moon
941  {
942  k = (0.1734 - 0.000393*tt) * sin (m)
943  + 0.0021 * sin (2.0 * m)
944  - 0.4068 * sin (p)
945  + 0.0161 * sin (2.0 * p)
946  - 0.0004 * sin (3.0 * p)
947  + 0.0104 * sin (f)
948  - 0.0051 * sin (m + p)
949  - 0.0074 * sin (m - p)
950  + 0.0004 * sin (f + m)
951  - 0.0004 * sin (f - m)
952  - 0.0006 * sin (f + p)
953  + 0.0010 * sin (f - p)
954  + 0.0005 * sin (m + 2.0*p);
955 
956  // check for possible eclipses.
957  f = f / 2.0;
958  if (fabs(sin(f)) <= 0.36) // eclipses are possible
959  {
960  ejd = (0.1734 - 0.000393*tt) * sin(m)
961  + 0.0021 * sin(2.0*m)
962  - 0.4068 * sin(p)
963  + 0.0161 * sin(2.0*p)
964  - 0.0051 * sin(m+p)
965  - 0.0074 * sin(m-p)
966  - 0.0104 * sin(2.0*f);
967  ejd += jd;
968 
969  s = 5.19595 - 0.0048*cos(m) + 0.0020*cos(2.0*m) - 0.3283*cos(p)
970  - 0.0060*cos(m+p) + 0.0041*cos(m-p);
971 
972  c = 0.2070*sin(m) + 0.0024*sin(2.0*m) - 0.0390*sin(p)
973  + 0.0115*sin(2.0*p) - 0.0073*sin(m+p)
974  - 0.0067*sin(m-p) + 0.0117*sin(2.0*f);
975 
976  gam = s*sin(f) + c*cos(f);
977  u = 0.0059 + 0.0046*cos(m) - 0.0182*cos(p)
978  + 0.0004*cos(2.0*p) - 0.0005*cos(m+p);
979 
980  if (phase == 0) // check for solar eclipse
981  {
982  if (fabs(gam) <= (1.5432+u))
983  {
984  if (fabs(gam) < 0.9972) // central eclipse
985  {
986  emag = 1.0;
987  if (u < 0) eph = 5; // total eclipse
988  else
989  {
990  if (u > 0.0047) eph = 4; // annular eclipse
991  else
992  {
993  if (u < (0.00464*cos(asin(gam)))) eph = 6; // annular/total
994  else eph = 4; // annular
995  }; // end if u>0.0047
996  }; // end if u<0
997  } // end if fabs(gam) if
998  else // non-central eclipse
999  {
1000  eph = 1; // assume partial eclipse
1001  if (fabs(gam) < (0.9972+fabs(u))) // non-central annular or total
1002  {
1003  eph = eclp.solar(ejd,tdut,s,c);
1004  emag = 1.0;
1005  };
1006  if (eph == 1) // get magnitude of partial eclipse
1007  emag = (1.5432 + u - fabs(gam)) / (0.5460 + 2.0*u);
1008  if (emag < 0.025) // check if low mag eclipse is OK
1009  {
1010  eph = 0;
1011  u = 1.0 / 720; // 2 min steps
1012  for (int j=0; j < 288; j++)
1013  {
1014  tt = ejd - 0.2 + double(j)*u;
1015  tst = eclp.solar(tt,tdut,s,c);
1016  if (tst > 0) eph = tst;
1017  };
1018  };
1019  }
1020  }
1021  } // end of solar eclipse check
1022 
1023  if (phase == 0.5) // check for lunar eclipse
1024  {
1025  c = (1.5572 + u - fabs(gam)) / 0.5450;
1026  if (c > 0)
1027  {
1028  s = (1.0129 - u - fabs(gam)) / 0.5450;
1029  if (s < 0) // penumbral eclipse
1030  {
1031  emag = c;
1032  if (emag > 1) eph = -2;
1033  else eph = -1;
1034  }
1035  else // umbral eclipse
1036  {
1037  emag = s;
1038  if (emag > 1) eph = -4;
1039  else eph = -3;
1040  }
1041  }
1042  }
1043  }
1044  };
1045 
1046  if ((phase == 0.25) || (phase == 0.75)) // for first and last quarter
1047  {
1048  k = (0.1721 - 0.0004*tt) * sin (m)
1049  + 0.0021 * sin (2.0 * m)
1050  - 0.6280 * sin (p)
1051  + 0.0089 * sin (2.0 * p)
1052  - 0.0004 * sin (3.0 * p)
1053  + 0.0079 * sin (f)
1054  - 0.0119 * sin (m + p)
1055  - 0.0047 * sin (m - p)
1056  + 0.0003 * sin (f + m)
1057  - 0.0004 * sin (f - m)
1058  - 0.0006 * sin (f + p)
1059  + 0.0021 * sin (f - p)
1060  + 0.0003 * sin (m + 2.0*p)
1061  + 0.0004 * sin (m - 2.0*p)
1062  - 0.0003 * sin (2.0*m + p);
1063  if (phase == 0.25)
1064  {
1065  k += 0.0028 - 0.0004*cos(m) + 0.0003*cos(p);
1066  };
1067  if (phase == 0.75)
1068  {
1069  k += -0.0028 + 0.0004*cos(m) - 0.0003*cos(p);
1070  };
1071  };
1072 
1073  jd = jd + k;
1074 
1075  return jd;
1076  }
1077 
1078 void EclSolar::ckphase (double minmjd, double maxmjd, double yr,
1079  double deltdut, int &mp, PMJD p, double phase)
1080  /* calculate the respective phase for one (MJD-) date and check whether
1081  this date is within the limits given by minmjd and maxmjd.
1082  Use yr as the year.fraction close to the desired date.
1083  If the date is within the limits store the result in the
1084  respective array.
1085  Also check for possible occurences of eclipses and store the
1086  respective data in an array
1087  */
1088  {
1089  double td, ejd, emag;
1090  int j, eph;
1091 
1092  td = phmjd (yr, phase, deltdut*86400.0, eph, ejd, emag);
1093  // correct difference between UT and TDT
1094  td = td - deltdut; // correct for difference between TDT and UT.
1095 
1096  // check whether the date is within the respective year
1097 
1098  if ((td >= minmjd) && (td <= maxmjd) && (mp < MAXLUN))
1099  {
1100  if (mp==0)
1101  {
1102  p[0]=td;
1103  mp=1;
1104  }
1105  else
1106  {
1107  if (p[mp-1] < (td - 0.1))
1108  {
1109  p[mp]=td;
1110  mp=mp+1;
1111  };
1112  };
1113  };
1114 
1115  // now the eclipses
1116  if (eph != 0)
1117  {
1118  td = ejd;
1119  td = td - deltdut; // correct for difference between TDT and UT.
1120 
1121  // check whether the date is within the respective year
1122  if ((td >= minmjd)&&(td <= maxmjd)&&(eb_numecl<GBL_ECLBUF))
1123  {
1124  if (eb_numecl == 0)
1125  {
1126  eb_eclmjd[0] = td;
1127  eb_magnitude[0] = emag;
1128  eb_phase[0] = eph;
1129  eb_numecl = 1;
1130  }
1131  else
1132  {
1133  for (j=0; j<eb_numecl; j++)
1134  { // check whether the date is already stored
1135  if (fabs(eb_eclmjd[j]- td) < 0.01) eph = 0;
1136  };
1137  if (eph != 0)
1138  {
1139  j = eb_numecl;
1140  eb_eclmjd[j] = td;
1141  eb_magnitude[j] = emag;
1142  eb_phase[j] = eph;
1143  eb_numecl += 1;
1144  };
1145  }
1146  }
1147  }
1148  }
1149 
1150 void EclSolar::dtmstr(double jdmoon, char *dts)
1151 // Convert the Modified Julian Date jdmoon into a corresponding string
1152 // *dts which has the format "MMM DD HH:MM"
1153 {
1154  int dd, mm, yy, deg, mnt;
1155  double hh, sec;
1156  char mchr[4];
1157 
1158  // convert MJD into corresponding date and time
1159  caldat(jdmoon, dd, mm, yy, hh);
1160  dms (hh,deg,mnt,sec);
1161  if (sec>30.0) {mnt++;};
1162  if (mnt>59)
1163  {
1164  deg++;
1165  mnt=0;
1166  };
1167 
1168  // store data in their positions
1169  GetMonth (mm, mchr);
1170  dts[0]=mchr[0];
1171  dts[1]=mchr[1];
1172  dts[2]=mchr[2];
1173  dts[3]=' ';
1174  sprintf(&dts[4],"%2i %2i:%02i", dd, deg, mnt);
1175  dts[12]=' ';
1176 }
1177 
1178 //------------------------- moonph ---------------------------------
1179 
1180 void EclSolar::moonph()
1181 {
1182  int mp0, mp25, mp5, mp75; // counter of respective phase entries
1183  PMJD p0, p25, p5, p75;
1184  int day, month, year, j;
1185  double yr, yx, hour, deltdut;
1186  double minmjd, maxmjd;
1187  double glatsv, glongsv, gheightsv, lat, lng;
1188  char wbuf[700];
1189 
1190  eb_moonph_called = true;
1191 
1192 // assign input data from Window Input Structure
1193  year = eb_year;
1194  deltdut = eb_del_tdut / 86400.0; // difference TDT - UT in days
1195  eb_lastyear = year;
1196  eb_lasttz = eb_tzone;
1197  eb_lastdlt = eb_del_tdut;
1198 
1199 // initializing counters
1200  eb_numecl = 0;
1201  mp0 = 0;
1202  mp25 = 0;
1203  mp5 = 0;
1204  mp75 = 0;
1205 
1206  yr = year - 0.2;
1207  yx = year + 1.2;
1208  day = 1;
1209  month = 1;
1210  hour = 0;
1211  minmjd = mjd(day, month, year, hour);
1212  day = 31;
1213  month = 12;
1214  hour = 24.0;
1215  maxmjd = mjd(day, month, year, hour);
1216 
1217  /* As the function phmjd finds the respective phases of the Moon
1218  only to within a few weeks of the time given by the input
1219  parameter (year.faction) the following loop starts well ahead of
1220  the beginning of the year in question and ends well after.
1221  The time step of two weeks utilized to increment the year.fraction
1222  parameter assures that we catch all the different lunations */
1223 
1224  while (yr < yx)
1225  { // calculate and check the phases
1226  ckphase(minmjd,maxmjd,yr,deltdut, mp0, p0, 0.0);
1227  ckphase(minmjd,maxmjd,yr,deltdut, mp25, p25, 0.25);
1228  ckphase(minmjd,maxmjd,yr,deltdut, mp5, p5, 0.5);
1229  ckphase(minmjd,maxmjd,yr,deltdut, mp75, p75, 0.75);
1230  yr+=0.02; // incease by 1/50th of a year (about two weeks)
1231  };
1232 
1233  for (j=0; j<eb_numecl; j++)
1234  {
1235  if( (eb_phase[j] == 1) && (eb_magnitude[j] > 0.98)) // check for possible non-central eclipse
1236  {
1237  glatsv = eb_geolat;
1238  glongsv = eb_geolong;
1239  gheightsv = eb_geoheight;
1240  eb_eclselect = j+1;
1241  eb_start_called = false;
1242  eb_local_called = false;
1243 
1244  getMaxPos (lat, lng);
1245  eb_geolat = lat;
1246  eb_geolong = lng;
1247  eb_geoheight = 0;
1248 
1249  getLocalDetails(wbuf);
1250 
1251  if ((eb_spp[0] == 2) || (eb_spp[1] == 2)) eb_phase[j] = 2;
1252  if ((eb_spp[0] == 3) || (eb_spp[1] == 3)) eb_phase[j] = 3;
1253 
1254  eb_geolat = glatsv;
1255  eb_geolong = glongsv;
1256  eb_geoheight = gheightsv;
1257  eb_start_called = false;
1258  eb_local_called = false;
1259 
1260  }
1261 
1262  };
1263 
1264  eb_eclselect = 0;
1265 }
1266 
1267 double EclSolar::getlocmag(double jd, double ep2, double phi, double lamda,
1268  double height, Vec3 rs, Vec3 rm, int& totflg)
1269  {
1270  /* get magnitude of solar eclipse at local position.
1271  jd : MJD (UT) of event
1272  ep2 : correction for apparent sidereal time (in sec)
1273  phi, lamda : latitude and longitude of observer in radians
1274  height : height of observer in m
1275  rs, rm : geocentric position vector of the sun and the moon
1276  totflg : 1 if total or annular, 0 otherwise
1277 
1278  RETURN: The magnitude of the eclipse (0 if no eclipse)
1279  */
1280 
1281  const double ds = 218.245445; // diameter of Sun in Earth radii
1282  const double dm = 0.544986; // diameter of Moon in Earth radii
1283  Vec3 gm, gs, s;
1284  double dsun, dmoon, asep;
1285  double elev;
1286 
1287  gm = GeoPos(jd, ep2, phi, lamda, height);
1288  gs = rs - gm;
1289  gm = rm - gm;
1290 
1291  // correct for refraction
1292  s = EquHor(jd, ep2, phi, lamda, gs);
1293  s = carpol(s);
1294  elev = s[2];
1295 
1296  if (elev > -3.5e-2) // cutoff of -2 deg for calculating refraction
1297  {
1298  elev = Refract(elev);
1299  s[2] = s[2] + elev;
1300  s = polcar (s);
1301  gs = HorEqu(jd, ep2, phi, lamda, s);
1302  };
1303 
1304  s = EquHor(jd, ep2, phi, lamda, gm);
1305  s = carpol(s);
1306  elev = s[2];
1307  if (elev > -3.5e-2) // cutoff of -2 deg for calculating refraction
1308  {
1309  elev = Refract(elev);
1310  s[2] = s[2] + elev;
1311  s = polcar (s);
1312  gm = HorEqu(jd, ep2, phi, lamda, s);
1313  };
1314 
1315  dsun = atan(0.5*ds/abs(gs)); // apparent radius of the Sun
1316  dmoon = atan(0.5*dm/abs(gm)); // apparent radius of the Moon
1317 
1318  gs = vnorm(gs);
1319  gm = vnorm(gm);
1320  asep = fabs(dot(gs, gm));
1321  if (asep > 1.0) asep = 1.0;
1322  asep = acos(asep); // apparent distance between Sun and Moon
1323 
1324  totflg = 0;
1325  if ((dsun+dmoon) > asep) // we have an eclipse
1326  {
1327  if (fabs(dsun-dmoon) > asep) totflg = 1;
1328  asep = fabs(dsun + dmoon - asep) / (2.0 * dsun);
1329  }
1330  else asep = 0;
1331 
1332  return asep;
1333  }
1334 
1335 //------------------------- eclStart ---------------------------------
1336 
1337 void EclSolar::eclStart()
1338 {
1339  /* get start and end times of the various phases of the eclipse
1340  j = index of the eclipse
1341  eb_spt[i] = start time in MJD for phase i
1342  eb_ept[i] = end time in MJD for phase i
1343  eb_spp[i] = kind of phase i
1344 
1345  Also set the global eb_jdstart and eb_jdstop
1346  to the (global jd times) of eclipse start and end.
1347 
1348  */
1349  int nump, eflg, pcur, pold, maxp, i, j, npflg, p;
1350  double jd, step, jd2, jdf, d1, d2;
1351  double azim, elev, dist, phi, lamda;
1352  bool eclstarted;
1353  Vec3 gx;
1354  Eclipse eclp;
1355 
1356  if (!eb_moonph_called) // just in case - this should never happen!
1357  {
1358  moonph();
1359  putEclSelect(1);
1360  };
1361 
1362  eb_local_called = false;
1363  eb_start_called = true;
1364 
1365  j = eb_eclselect-1;
1366 
1367  eclstarted = false;
1368  nump = 0;
1369  maxp = 0;
1370  eflg = 0; // end flag
1371  pold = 0;
1372  elev = 0;
1373  eb_maxps = -1.0;
1374  eb_maxelv = -1.0;
1375  p = eb_phase[j];
1376  jd = eb_eclmjd[j] - 0.5; // start 12 hours before maximum
1377  jdf = jd + 1.5; // emergency stop if something goes wrong with the loop
1378  step = eb_cstep / (24.0*60.0); // stepwidth (best set to 1 minute)
1379 
1380  do
1381  {
1382  if (eb_lunactive) pcur = eclp.lunar(jd, eb_del_tdut);
1383  else pcur = eclp.solar (jd, eb_del_tdut,d1, d2);
1384  // now check the start and stop times for the phases
1385  if (pcur > pold)
1386  {
1387  eclstarted = true;
1388  if(nump < 4)
1389  {
1390  eb_spt[nump] = jd;
1391  eb_spp[nump] = pcur;
1392  nump++;
1393  maxp++;
1394  pold = pcur;
1395  // get time accurate to the second
1396  jd2 = jd - 1.0/86400.0; // go in seconds steps
1397  for (i=0; i<60; i++)
1398  {
1399  if (eb_lunactive) pcur = eclp.lunar(jd, eb_del_tdut);
1400  else pcur = eclp.solar (jd2, eb_del_tdut,d1, d2);
1401 
1402  if (pcur == pold) eb_spt[nump] = jd2;
1403  else break;
1404  jd2 = jd2 - 1.0/86400.0; // go in seconds steps
1405  };
1406  pcur = pold;
1407 
1408  }
1409  }
1410  else if (eclstarted && (pcur < pold))
1411  {
1412  pold = pcur;
1413  // get time accurate to the second
1414  jd2 = jd - 1.0/86400.0; // go in seconds steps
1415  for (i=0; i<60; i++)
1416  {
1417  if (eb_lunactive) pcur = eclp.lunar(jd, eb_del_tdut);
1418  else pcur = eclp.solar (jd2, eb_del_tdut,d1, d2);
1419  if (pcur == pold) jd = jd2;
1420  else break;
1421  jd2 = jd2 - 1.0/86400.0; // go in seconds steps
1422  };
1423  pcur = pold;
1424 
1425  npflg = 1;
1426  if (nump > 1)
1427  {
1428  if (pcur > eb_spp[nump-2]) npflg = 0;
1429  }
1430  if (npflg)
1431  {
1432  nump--;
1433  if (nump >= 0) eb_ept[nump] = jd;
1434  if (nump > 1)
1435  {
1436  if (pcur < eb_spp[nump-1])
1437  {
1438  nump--;
1439  eb_ept[nump] = jd;
1440  }
1441  }
1442  if (nump <= 0) eflg = 1;
1443  }
1444  };
1445 
1446  jd += step;
1447  if (jd > jdf) eflg = 1;
1448 
1449  } while (eflg != 1);
1450 
1451  // now check for maximum eclipse conditions
1452 
1453  calcMaxPos(phi, lamda);
1454 
1455  if ((eb_lunactive == false) && (p > 3)) // central solar eclipse
1456  {
1457  eb_jdmaxps = eb_eclmjd[j];
1458  jd = eb_eclmjd[j] - 600.0/86400.0; // start 10 min before approximate max time
1459  phi = eb_cmxlat * degrad;
1460  lamda = eb_cmxlng * degrad;
1461  for (i=0; i<1200; i++)
1462  {
1463  jd += 1.0/86400.0; // go in seconds steps
1464  pcur = eclp.solar (jd, eb_del_tdut,d1, d2);
1465  if (pcur > 3)
1466  {
1467  gx = eclp.GetRSun();
1468  AppPos (jd, eclp.GetEp2(), d1, d2, 0.0, 1, gx, azim, elev, dist);
1469 
1470  if (elev > eb_maxelv)
1471  {
1472  eb_maxelv = elev;
1473  eb_jdmaxps = jd;
1474  phi = d1;
1475  lamda = d2;
1476  };
1477  }
1478  }
1479  jd = eb_jdmaxps;
1480  eb_maxelv = elev / degrad;
1481  eb_cmxlat = phi / degrad;
1482  eb_cmxlng = lamda / degrad;
1483  if (eb_cmxlng < 0) eb_cmxlng += 360.0;
1484  };
1485 
1486  eb_jdstart = eb_spt[0];
1487  eb_jdstop = eb_ept[0];
1488  eb_nphase = maxp;
1489 
1490  }
1491 
1492 void EclSolar::calcMaxPos(double &lat, double &lng)
1493  {
1494  // Get the geographic position of the maximum eclipse
1495  // in case of a central eclipse the position is approximate
1496  // lat and lng are in decimal degrees
1497 
1498  int j, p;
1499  double t, mp2;
1500  Vec3 rm;
1501  Vec3 s2;
1502  Eclipse eclp;
1503 
1504  mp2 = 2.0 * M_PI;
1505 
1506  j = eb_eclselect-1;
1507 
1508  t = eb_eclmjd[j];
1509 
1510  if (eb_lunactive)
1511  {
1512  p = eclp.lunar(t, eb_del_tdut);
1513  rm = eclp.GetRMoon();
1514 
1515  // get sub lunar point at maximum
1516  s2 = carpol(rm);
1517  lat = s2[2]; // just preliminary
1518  lng = s2[1] - lsidtim (t, 0, eclp.GetEp2())*M_PI/12.0;
1519  if (lng > mp2) lng -= mp2;
1520  if (lng < -M_PI) lng += mp2;
1521  if (lng > M_PI) lng -= mp2;
1522  if (fabs(lat) < 1.53589) lat = atan(1.00674*tan(lat));
1523  lat /= degrad;
1524  lng /= degrad;
1525  if (lng < 0) lng += 360.0;
1526  eb_cmxlat = lat;
1527  eb_cmxlng = lng;
1528  return;
1529  }
1530  else p = eclp.solar(t,eb_del_tdut,lat,lng);
1531 
1532  if (p > 3)
1533  {
1534  eb_cmxlat = lat;
1535  eb_cmxlng = lng;
1536  eb_cmxlat /= degrad;
1537  eb_cmxlng /= degrad;
1538  }
1539  else
1540  {
1541  eclp.maxpos(t,eb_del_tdut,eb_cmxlat,eb_cmxlng);
1542  eb_cmxlat /= degrad;
1543  eb_cmxlng /= degrad;
1544  };
1545 
1546  if (eb_cmxlng < 0) eb_cmxlng += 360.0;
1547  lat = eb_cmxlat;
1548  lng = eb_cmxlng;
1549  }
1550 
1551 void EclSolar::getMaxPos(double &lat, double &lng)
1552  {
1553  // Get the geographic position of the maximum eclipse
1554 
1555  if (!eb_start_called) eclStart();
1556 
1557  lat = eb_cmxlat;
1558  lng = eb_cmxlng;
1559  }
1560 
1561 double EclSolar::sunObscure(double l1, double l2, double mag)
1562 {
1563  // get the Obscuration of the Sun from penumbra l1, umbra l2 and
1564  // magnitude mag
1565 
1566  double s, a, b, c, m;
1567 
1568  m = l1 - mag * (l1 + l2);
1569  s = (l1 - l2) / (l1 + l2);
1570  c = (l1*l1 + l2*l2 - 2*m*m) / (l1*l1 - l2*l2);
1571  c = acos(c);
1572  b = (l1*l2 + m*m) / (m*(l1+l2));
1573  b = acos(b);
1574  a = M_PI - (b + c);
1575  s = (s*s*a + b) - s * sin(c);
1576 
1577  return s / M_PI;
1578 }
1579 
1580 /*------------------------- EclCentral ---------------------------------*/
1581 
1582 int EclSolar::eclPltCentral(bool firstc, double &lat, double &lng)
1583  {
1584  /* get next coordinates for central eclipse position
1585  first = 1 for first call (first point will be found)
1586  lat, lng : latitude and longitude in decimal degrees
1587 
1588  RETURN: phase (= 4 annular, = 5 total, = 6 annular/total
1589  0 if there was no central eclipse)
1590  */
1591  double phi, lamda, d1, d2, jd, jd2;
1592  int kp, kp2, i;
1593  Eclipse eclp;
1594 
1595  if (!eb_start_called) eclStart();
1596 
1597  if (eb_lunactive) // just in case
1598  {
1599  eb_finished2 = true;
1600  lat = 0.0;
1601  lng = 0.0;
1602  return 0;
1603  };
1604 
1605  eb_cphs = 0;
1606 
1607  if (firstc) // find the first occurence compliant with the step width
1608  {
1609  jd = eb_jdstart;
1610  kp = eclp.solar(jd, eb_del_tdut, phi, lamda);
1611 
1612  while ((kp < 4) && (jd < eb_jdstop))
1613  {
1614  jd += double(eb_cstep) / (24.0*60.0);
1615  eb_lastjd = jd;
1616  kp = eclp.solar(jd, eb_del_tdut, phi, lamda);
1617  };
1618 
1619  jd2 = jd;
1620  for (i=0; i<60; i++) // get it right to the second
1621  {
1622  jd2 = jd2 - 1.0/86400.0; // go in seconds steps
1623  kp2 = eclp.solar (jd2, eb_del_tdut,d1, d2);
1624  if (kp2 == kp)
1625  {
1626  jd = jd2;
1627  phi = d1;
1628  lamda = d2;
1629  }
1630  else break;
1631  };
1632  eb_finished2 = false;
1633 
1634  } // end of firstc
1635  else
1636  {
1637  if (eb_finished2) return 0;
1638 
1639  jd = eb_lastjd + double(eb_cstep) / (24.0*60.0);
1640  eb_lastjd = jd;
1641  if (jd > eb_jdstop)
1642  {
1643  eb_finished2 = true;
1644  return 0;
1645  };
1646 
1647  kp = eclp.solar(jd, eb_del_tdut, phi, lamda);
1648 
1649  if (kp <= 3) // end of central eclipse.
1650  {
1651  eb_finished = true;
1652  for (i=0; i<60; i++) // get it right to the second
1653  {
1654  jd-= 1.0/86400.0; // go in seconds steps
1655  kp = eclp.solar (jd, eb_del_tdut, phi, lamda);
1656  if (kp > 3) break;
1657  };
1658  };
1659  };
1660 
1661  if (kp > 3) // central eclipse
1662  {
1663  eb_cphs = kp;
1664 
1665  phi /= degrad;
1666  lamda /= degrad;
1667  if (lamda < 0.0) lamda += 360.0;
1668  if (lamda > 360.0) lamda -= 360.0;
1669  eb_clat = phi;
1670  eb_clng = lamda;
1671  lat = eb_clat;
1672  lng = eb_clng;
1673 
1674  // djd = eclp.duration(jd, indata->del_tdut, width);
1675  }
1676  return kp;
1677  }
1678 
1679 //--------------------Northern and Southern Boundaries -------------------------
1680 
1681 void EclSolar::InitBound()
1682  {
1683  /* Initialize the calculation for the northern and southern boundaries
1684  of solar eclipses (umbra or penumbra).
1685  The function EclStart must have been called first to enable InitBound
1686  to get the right eclipse.
1687  The calculation is done in Earth radii.
1688 
1689  OUTPUT:
1690  eb_ubm : Penumbra base vector
1691  eb_ube : Shadod base vector for upper boundary
1692  eb_udm : Penumbra base delta vector
1693  eb_ude : Shadow delta vector for upper boundary
1694  eb_lbe : Shadod base vector for lower boundary
1695  eb_lde : Shadow delta vector for lower boundary
1696  */
1697 
1698 // const double dm = 0.272493; // radius of Moon in Earth radii
1699  double dpn1, dpn2, pan1, pan2, s0;
1700  Vec3 shmv, u2m, u2e;
1701  Vec3 ax1, ax2;
1702  Eclipse eclp;
1703 
1704  if (!eb_start_called) eclStart();
1705  if (eb_lunactive) return; // only for solar eclipses
1706 
1707  // beginning of the eclipse
1708  eclp.penumd (eb_jdstart, eb_del_tdut, eb_ubm, eb_ube, dpn1, pan1);
1709 
1710  // end of the eclipse
1711  eclp.penumd (eb_jdstop, eb_del_tdut, u2m, u2e, dpn2, pan2);
1712 
1713  dpn1 *= 0.5;
1714  dpn2 *= 0.5;
1715 
1716  if (eb_penamode == 0)
1717  {
1718  dpn1 *= eb_penangle;
1719  pan1 *= eb_penangle;
1720  dpn2 *= eb_penangle;
1721  pan2 *= eb_penangle;
1722  }
1723 
1724  if (eb_penamode > 0)
1725  {
1726  s0 = eb_penangle * tan(pan1);
1727  s0 = atan(s0);
1728  if (pan1 > 0)
1729  {
1730  dpn1 = dpn1 * s0 / pan1;
1731  pan1 = s0;
1732  }
1733  s0 = eb_penangle * tan(pan2);
1734  s0 = atan(s0);
1735  if (pan2 > 0)
1736  {
1737  dpn2 = dpn2 * s0 / pan2;
1738  pan2 = s0;
1739  }
1740  }
1741 
1742  // get apex of penumbra cone
1743  pan1 = tan(pan1);
1744  if (pan1 != 0) dpn1 = dpn1 / pan1;
1745  else dpn1 = 1.2 * abs(eb_ubm); // avoid a crash
1746  pan2 = tan(pan2);
1747  if (pan2 != 0) dpn2 = dpn2 / pan2;
1748  else dpn2 = dpn1; // avoid a crash
1749 
1750  // get vector perpendicular to movement of shadow
1751  s0 = - dot(eb_ubm, eb_ube);
1752  ax1 = eb_ubm + s0 * eb_ube;
1753  eb_ubm = eb_ubm + (s0 - dpn1) * eb_ube;
1754  s0 = - dot(u2m, u2e);
1755  ax2 = u2m + s0 * u2e;
1756  u2m = u2m + (s0 - dpn2) * u2e;
1757  shmv = ax1 - ax2;
1758  ax2 = ax1 * ax2;
1759  shmv = shmv * ax2;
1760  shmv = vnorm(shmv);
1761 
1762  // now get the delta vectors
1763  eb_udm = u2m - eb_ubm;
1764  eb_lbe = eb_ube - pan1 * shmv;
1765  eb_ube = eb_ube + pan1 * shmv;
1766  eb_ude = u2e + pan2 * shmv;
1767  eb_lde = u2e - pan2 * shmv;
1768  eb_ube = vnorm(eb_ube);
1769  eb_lbe = vnorm(eb_lbe);
1770  eb_ude = vnorm(eb_ude);
1771  eb_lde = vnorm(eb_lde);
1772  eb_lde = eb_lde - eb_lbe;
1773  eb_ude = eb_ude - eb_ube;
1774 
1775  // scale the delta vectors
1776  dpn1 = eb_jdstop - eb_jdstart;
1777  if (dpn1 == 0) dpn1 = 1.0;
1778  else dpn1 = 1.0 / dpn1;
1779  eb_udm *= dpn1;
1780  eb_ude *= dpn1;
1781  eb_lde *= dpn1;
1782  }
1783 
1784 int EclSolar::GNSBound(bool firstc, bool north, double& lat, double& lng)
1785  {
1786  /* Get the geographic coordinates of the northern or southern boundaries
1787  at time t.
1788  INPUT: firstc :true for first call
1789  north : true for southern boundary
1790  see also InitBound
1791  OUTPUT:
1792  lat, lng : latitude and longitude of penumbra boundary.
1793  If lat > 90 no northern boundary exists.
1794 
1795  RETURN: 1 if time within eclipse, 0 if end of eclipse
1796  */
1797  const double flat = 0.996633; // flatting of the Earth
1798 
1799  double s0, s, r0, r2, dlt, t;
1800  Vec3 vrm, vre;
1801 
1802  if (eb_lunactive) // only solar eclipses
1803  {
1804  lng = 0.0;
1805  lat = 100.0;
1806  return 0;
1807  };
1808 
1809  if (firstc)
1810  {
1811  InitBound();
1812  t = eb_jdstart;
1813  eb_lastjd = t;
1814  }
1815  else
1816  {
1817  t = eb_lastjd + double(eb_cstep) / (24.0*60.0);
1818  eb_lastjd = t;
1819  };
1820 
1821  if (t >= eb_jdstop)
1822  {
1823  lng = 0.0;
1824  lat = 100.0;
1825  return 0;
1826  };
1827 
1828  // get shadow vector at time t
1829  vrm = eb_ubm + (t - eb_jdstart) * eb_udm;
1830  if (north) vre = eb_ube + (t - eb_jdstart) * eb_ude;
1831  else vre = eb_lbe + (t - eb_jdstart) * eb_lde;
1832  vre = vnorm (vre); // direction of penumbra boundary
1833 
1834  s0 = - dot(vrm, vre); // distance Moon - fundamental plane
1835  r2 = dot (vrm,vrm);
1836  dlt = s0*s0 + 1.0 - r2;
1837  r0 = 1.0 - dlt;
1838 
1839  if (r0 > 0) r0 = sqrt (r0);
1840  else r0 = 0; // distance center of Earth - shadow axis
1841 
1842  // calculate the coordinates if there is an intersecton
1843  if (r0 < 1.0) // there should be an intersection
1844  {
1845  if (dlt > 0) dlt = sqrt(dlt);
1846  else dlt = 0;
1847  s = s0 - dlt; // distance Moon - fundamental plane
1848  vrm = vrm + s * vre;
1849  vrm = vnorm(vrm);
1850  vrm[2] *= flat; // vector to intersection
1851  vre = carpol(vrm);
1852  lng = vre[1] - lsidtim(t,0,0)*0.261799387799; // geographic coordinates
1853  if (lng > 2*M_PI) lng -= 2.0*M_PI;
1854  if (lng < 0.0) lng += 2.0*M_PI;
1855  lat = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615;
1856  lat = atan23(vrm[2],lat);
1857  lat /= degrad;
1858  lng /= degrad;
1859 
1860  if (lng < 0.0) lng += 360.0;
1861  if (lng > 360.0) lng -= 360.0;
1862  }
1863  else
1864  {
1865  lat = 100.0;
1866  lng = 0;
1867  };
1868 
1869  return 1;
1870  }
1871 
1872 //------------------ Sunrise / Sunset Boundaries ---------------------------
1873 
1874 void EclSolar::InRSBound()
1875  {
1876  /* Initialize the calculation for the sunrise and sunset boundaries
1877  of solar eclipses.
1878  The function EclStart must have been called first to enable InRSBound
1879  to get the right eclipse.
1880  The calculation is done in Earth radii.
1881 
1882  OUTPUT:
1883  eb_ubm : Moon base vector
1884  eb_ube : Shadod base vector
1885  eb_udm : Moon delta vector
1886  eb_ude : Shadow delta vector for
1887  eb_dpb : Base value for diameter of penumbra
1888  eb_dpd : delta value for diameter of penumbra
1889  */
1890 
1891  double pan;
1892  Vec3 u2m, u2e;
1893  Eclipse eclp;
1894 
1895  if (!eb_start_called) eclStart();
1896 
1897  // beginning of the eclipse
1898  eclp.penumd (eb_jdstart, eb_del_tdut, eb_ubm, eb_ube, eb_dpb, pan);
1899 
1900  // end of the eclipse
1901  eclp.penumd (eb_jdstop, eb_del_tdut, u2m, u2e, eb_dpd, pan);
1902 
1903  // get the delta vectors
1904  eb_udm = u2m - eb_ubm;
1905  eb_ude = u2e - eb_ube;
1906  eb_dpd = eb_dpd - eb_dpb;
1907 
1908  // scale the delta vectors
1909 
1910  pan = eb_jdstop - eb_jdstart;
1911  if (pan == 0) pan = 1.0;
1912  else pan = 1.0 / pan;
1913  eb_udm *= pan;
1914  eb_ude *= pan;
1915  eb_dpd *= pan;
1916  }
1917 
1918 int EclSolar::iscrs(double vrc0, double vrc1, double dpn,
1919  double& vrx0, double& vrx1, double& vrx20, double& vrx21)
1920  {
1921  /* calculate intersection vectors of the penumbral cone with the
1922  Earth in the fundamental plane to find the locations of rise
1923  and set.
1924 
1925  INPUT : components of vectors vrc (pointing to the center of the
1926  penumbra), vre (unit vector perpendicular to the
1927  fundamental plane).
1928  dpn : half diameter of penumbra in Earth radii
1929 
1930  OUTPUT: components of the intersection vectors vrx and vrx2 if
1931  successful.
1932 
1933  RETURN: 1 if intersection successful, 0 otherwise.
1934  */
1935  int rtn;
1936  double a, b, c, f1, f2, f3, f4;
1937 
1938  rtn = 1;
1939  f1 = vrc0*vrc0;
1940 
1941  if (f1 < 1.0e-60) rtn = 0;
1942  else
1943  {
1944  f2 = 1.0 - dpn*dpn + f1 + vrc1*vrc1;
1945  f3 = f2 / (2.0*vrc0);
1946  f4 = vrc1 / vrc0;
1947  a = 1.0 + vrc1*vrc1 / f1;
1948  b = f2*vrc1 / f1;
1949  c = f2*f2 / (4.0*f1) - 1.0;
1950  if (fabs(a) < 1.0e-60) rtn = 0;
1951  else
1952  {
1953  vrx21 = -0.5 * b / a; ;
1954  vrx0 = vrx21*vrx21 - c / a;
1955  if (vrx0 < 0) rtn = 0;
1956  else
1957  {
1958  vrx0 = sqrt(vrx0);
1959  vrx1 = vrx21 + vrx0;
1960  vrx21 = vrx21 - vrx0;
1961  vrx0 = f3 + f4*vrx1;
1962  vrx20 = f3 + f4*vrx21;
1963  vrx1 = -vrx1;
1964  vrx21 = -vrx21;
1965  };
1966  };
1967  };
1968 
1969  return rtn;
1970  }
1971 
1972 int EclSolar::GRSBound(bool firstc, double& lat1, double& lng1, double& lat2, double& lng2)
1973  {
1974  /* Get the geographic coordinates of the boundaries for rise/set
1975  at time t.
1976 
1977  INPUT: firstc : true for first call
1978 
1979  OUTPUT:
1980  lat1, lng1; lat2, lng2 : latitude and longitude of first
1981  and second point ofboundary.
1982  If lat > 90 no respective point exists.
1983 
1984  RETURN: 0 if end of eclipse, 1 otherwise
1985  */
1986  const double flat = 0.996633; // flatting of the Earth
1987 
1988  double s0, r0, dpn, t;
1989  Vec3 vrm, vre, vrc, vrx, vrx2;
1990  Mat3 m1, m2;
1991 
1992  if (eb_lunactive) // only solar eclipses
1993  {
1994  lng1 = 0.0;
1995  lat1 = 100.0;
1996  lng2 = 0.0;
1997  lat2 = 100.0;
1998  eb_finished = true;
1999  return 0;
2000  };
2001 
2002  if (firstc)
2003  {
2004  InRSBound();
2005  t = eb_jdstart + 1.0/86400.0; // just add a second to be beyond the limit
2006  eb_lastjd = t;
2007  eb_finished = false;
2008  }
2009  else
2010  {
2011  t = eb_lastjd + double(eb_cstep) / (24.0*60.0);
2012  eb_lastjd = t;
2013  };
2014 
2015  if (t >= eb_jdstop)
2016  {
2017  if (eb_finished)
2018  {
2019  lng1 = 0.0;
2020  lat1 = 100.0;
2021  lng2 = 0.0;
2022  lat2 = 100.0;
2023  return 0;
2024  };
2025  t = eb_jdstop - 1.0/86400.0; // just to go to the very end and then stop
2026  eb_lastjd = t;
2027  eb_finished = true;
2028  };
2029 
2030  // get position of penumbra and shadow cone
2031  vrm = eb_ubm + (t - eb_jdstart) * eb_udm;
2032  vre = eb_ube + (t - eb_jdstart) * eb_ude;
2033  vre = vnorm (vre); // direction of penumbra boundary
2034  dpn = eb_dpb + (t - eb_jdstart) * eb_dpd;
2035  dpn *= 0.5; // half cone diameter
2036  vrx = carpol(vre);
2037 
2038  m1 = zrot(vrx[1] + M_PI/2.0);
2039  m2 = xrot(M_PI/2.0 - vrx[2]);
2040  m1 = m2 * m1; // rotation from equatorial into fundamental plane
2041  m2 = mxtrn(m1); // rotation from fundamental plane into equatorial
2042 
2043  // get vector to center of shadow in the fundamental plane
2044  s0 = - dot(vrm, vre);
2045  vrc = vrm + s0 * vre;
2046 
2047  r0 = abs(vrc); // distance between center of Earth and center of shadow
2048  vrc = mxvct(m1, vrc);
2049 
2050  lng1 = 0;
2051  lat1 = 100.0;
2052  lng2 = 0;
2053  lat2 = 100.0;
2054  // check whether intersection of Earth and shadow cone are possible
2055  // in fundamental plane
2056  if ((r0 > fabs(1.0 - dpn)) && (r0 < fabs(1.0 + dpn)))
2057  {
2058  // now find the intersections
2059  if (iscrs(vrc[0],vrc[1], dpn, vrx[0],vrx[1], vrx2[0],vrx2[1])) lat1 = 0;
2060  else
2061  {
2062  if (iscrs(vrc[1],vrc[0], dpn, vrx[1],vrx[0], vrx2[1],vrx2[0])) lat1 = 0;
2063  };
2064  };
2065 
2066  // calculate the coordinates if there is an intersecton
2067  if (lat1 < 100.0) // there should be an intersection
2068  {
2069  vrx[2] = 0;
2070  vrx = mxvct(m2, vrx);
2071  vrx = vnorm(vrx);
2072  vrx[2] *= flat; // vector to intersection
2073  vre = carpol(vrx);
2074  lng1 = vre[1] - lsidtim(t,0,0)*0.261799387799; // geographic coordinates
2075 
2076  if (lng1 > M_PI) lng1 -= 2.0*M_PI;
2077  if (lng1 < (-M_PI)) lng1 += 2.0*M_PI;
2078  lat1 = sqrt(vrx[0]*vrx[0] + vrx[1]*vrx[1])*0.993305615;
2079  lat1 = atan23(vrx[2],lat1);
2080  lat1 /= degrad;
2081  lng1 /= degrad;
2082  };
2083  if (lat1 < 100.0) // intersection #2
2084  {
2085  vrx2[2] = 0;
2086  vrx2 = mxvct(m2, vrx2);
2087  vrx2 = vnorm(vrx2);
2088  vrx2[2] *= flat; // vector to intersection
2089  vre = carpol(vrx2);
2090  lng2 = vre[1] - lsidtim(t,0,0)*0.261799387799; // geographic coordinates
2091  if (lng2 > M_PI) lng2 -= 2.0*M_PI;
2092  if (lng2 < (-M_PI)) lng2 += 2.0*M_PI;
2093  lat2 = sqrt(vrx2[0]*vrx2[0] + vrx2[1]*vrx2[1])*0.993305615;
2094  lat2 = atan23(vrx2[2],lat2);
2095  lat2 /= degrad;
2096  lng2 /= degrad;
2097  };
2098 
2099  return 1;
2100  }
2101 
2102 /*------------------------- EclDetails ---------------------------------*/
2103 
2104 double EclSolar::DegFDms (double h)
2105  {
2106  /* convert degrees from d.fff -> d.mmsss where .mm are the minutes
2107  and sss are seconds (and fractions of seconds).
2108  */
2109  int mm, deg;
2110  double hh, t, sec;
2111 
2112  hh = fabs(h);
2113  dms (hh,deg,mm,sec);
2114  if (sec>=59.5)
2115  {
2116  mm++;
2117  sec = 0;
2118  };
2119  if (mm>59)
2120  {
2121  deg++;
2122  mm=0;
2123  };
2124  hh = double(deg);
2125  t = double(mm)/100.0;
2126  hh += t;
2127  t = sec/10000.0;
2128  hh += t;
2129  if (h < 0) hh = -hh;
2130 
2131  return hh;
2132  }
2133 
2134 int EclSolar::localStart(int j, double *spt, double *ept, int *spp,
2135  int p, char *otxt)
2136  {
2137  /* get start and end times of the various phases of the eclipse
2138  j = index of the eclipse
2139  spt[i] = start time in MJD for phase i
2140  ept[i] = end time in MJD for phase i
2141  spp[i] = kind of phase i
2142  p = phase
2143 
2144  RETURN: the number of different phases of this eclipse.
2145 
2146  The step width will be 1 min
2147  */
2148  int nump, eflg, pcur, pold, maxp, i, npflg;
2149  double magecl; // local magnitude of eclipse at jd
2150  double jd, step, jdf, d1, d2, elrise;
2151  double azim, elev, dist, phi, lamda;
2152  char dts[13];
2153  char outb[127];
2154  Vec3 gx;
2155  Eclipse eclp;
2156 
2157  nump = 0;
2158  maxp = 0;
2159  eflg = 0; // end flag
2160  pold = 0;
2161  elev = 0;
2162  eb_lccnt = 0;
2163  eb_maxps = -1.0;
2164  eb_maxelv = -1.0;
2165  phi = eb_geolat * M_PI / 180.0;
2166  lamda = eb_geolong * M_PI / 180.0;
2167  jd = eb_eclmjd[j] - 0.5; // start 12 hours before maximum
2168  jdf = jd + 1.5; // emergency stop if something goes wrong with the loop
2169  step = 1.0/(24.0*60.0); // stepwidth 1 minute
2170  eb_ltotb = jd;
2171  eb_ltote = jd - 1.0;
2172 
2173  do
2174  {
2175  if(p < 0)
2176  {
2177  pcur = eclp.lunar (jd, eb_del_tdut);
2178  gx = eclp.GetRMoon();
2179  magecl = 1.0; // just set it 1. It's not needed for lunar eclipses.
2180  elrise = -9.89e-3; // allow for refraction during rise/set
2181  }
2182  else
2183  {
2184  pcur = eclp.solar (jd, eb_del_tdut,d1, d2);
2185  gx = eclp.GetRSun();
2186  magecl = 0;
2187  elrise = -1.45e-2; // allow for refraction during rise/set
2188  };
2189 
2190  // check whether body is visible from local position.
2191  if (pcur > 0)
2192  {
2193  AppPos (jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 1, gx,
2194  azim, elev, dist);
2195  if ((p > 0) && (elev >= elrise))
2196  {
2197  magecl = getlocmag(jd, eclp.GetEp2(), phi, lamda, eb_geoheight,
2198  eclp.GetRSun(),eclp.GetRMoon(), i);
2199  if (magecl > eb_maxps)
2200  {
2201  eb_maxps = magecl;
2202  eb_maxelv = elev;
2203  eb_jdmaxps = jd;
2204  }
2205  }
2206  }
2207 
2208  if ((eb_lccnt == 0) && (pcur != 0))
2209  {
2210  if ((elev >= elrise) && (magecl > 0))
2211  {
2212  eb_lcb1 = jd;
2213  eb_lccnt = 1;
2214  }
2215  }
2216  if (eb_lccnt == 1)
2217  {
2218  if ((elev < elrise) || (pcur == 0) || (magecl == 0))
2219  {
2220  eb_lce1 = jd;
2221  eb_lccnt = 2;
2222  }
2223  }
2224  if ((eb_lccnt == 2) && (pcur != 0))
2225  {
2226  if ((elev >= elrise) && (magecl > 0))
2227  {
2228  eb_lcb2 = jd;
2229  eb_lccnt = 3;
2230  }
2231  }
2232  if (eb_lccnt == 3)
2233  {
2234  if ((elev < elrise) || (pcur == 0) || (magecl == 0))
2235  {
2236  eb_lce2 = jd;
2237  eb_lccnt = 4;
2238  }
2239  }
2240 
2241  // now check the start and stop times for the phases
2242  if (pcur > pold)
2243  {
2244  if(nump < 4)
2245  {
2246  spt[nump] = jd;
2247  spp[nump] = pcur;
2248  nump++;
2249  maxp++;
2250  pold = pcur;
2251  }
2252  }
2253  else if (pcur < pold)
2254  {
2255  npflg = 1;
2256  if (nump > 1)
2257  {
2258  if (pcur > spp[nump-2]) npflg = 0;
2259  }
2260  if (npflg)
2261  {
2262  nump--;
2263  if (nump >= 0) ept[nump] = jd;
2264  if (nump > 1)
2265  {
2266  if (pcur < spp[nump-1])
2267  {
2268  nump--;
2269  ept[nump] = jd;
2270  }
2271  }
2272  if (nump <= 0) eflg = 1;
2273  }
2274  pold = pcur;
2275  };
2276 
2277  jd += step;
2278  if (jd > jdf) eflg = 1;
2279 
2280  } while (eflg != 1);
2281 
2282  // put the respective info into textfile otxt
2283  if(maxp > 0)
2284  {
2285  for (i=0; i<maxp; i++)
2286  {
2287  if (p < 0)
2288  {
2289  switch (spp[i])
2290  {
2291  case 1: strcpy(outb,"penumbral ");
2292  break;
2293  case 2: strcpy(outb,"tot.penumb ");
2294  break;
2295  case 3: strcpy(outb,"partial ");
2296  break;
2297  case 4: strcpy(outb,"totality ");
2298  break;
2299  }
2300  }
2301  else
2302  {
2303  switch (spp[i])
2304  {
2305  case 1: strcpy(outb,"partial ");
2306  break;
2307  case 2: strcpy(outb,"n-centr.Ann ");
2308  break;
2309  case 3: strcpy(outb,"n-centr.Tot ");
2310  break;
2311  case 4: strcpy(outb,"annularity ");
2312  break;
2313  case 5: strcpy(outb,"totality ");
2314  break;
2315  }
2316  }
2317 
2318  strcat(otxt,"\n ");
2319  strcat(otxt, outb);
2320  strcat(otxt,"\tbegins ");
2321  dtmstr((spt[i]+eb_tzone/24.0),dts);
2322  dts[12] = '\0';
2323  strcat(otxt,dts);
2324  strcat(otxt, "\tends ");
2325  dtmstr((ept[i]+eb_tzone/24.0),dts);
2326  dts[12] = '\0';
2327  strcat(otxt,dts);
2328  }
2329  }
2330  if (maxp > 0)
2331  {
2332  if (eb_lccnt == 1) eb_lce1 = ept[0];
2333  if (eb_lccnt == 3) eb_lce2 = ept[0];
2334  }
2335 
2336  if (eb_maxps > 0.8) // check for local central phase
2337  {
2338  jd = eb_jdmaxps - 16.0/(24.0*60.0);
2339  eb_ltote = jd + 32.0/(24.0*60.0);
2340  eflg = 0;
2341  do
2342  {
2343  jd += 1.0/86400.0; // go in seconds steps
2344  eclp.solar (jd, eb_del_tdut,d1, d2);
2345  gx = eclp.GetRSun();
2346  AppPos (jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 1, gx,
2347  azim, elev, dist);
2348  if (elev >= elrise)
2349  {
2350  magecl = getlocmag(jd, eclp.GetEp2(), phi, lamda, eb_geoheight,
2351  eclp.GetRSun(),eclp.GetRMoon(), i);
2352  if (magecl > eb_maxps)
2353  {
2354  eb_maxelv = elev;
2355  eb_maxps = magecl;
2356  eb_jdmaxps = jd;
2357  }
2358  if (i > 0)
2359  {
2360  eb_ltotb = jd;
2361  eflg = 1;
2362  }
2363  }
2364  if (jd > eb_ltote) eflg = 1;
2365 
2366  } while (!eflg);
2367 
2368  if (jd < eb_ltote)
2369  {
2370  eflg = 0;
2371  do
2372  {
2373  jd += 1.0/86400.0; // go in seconds steps
2374  eclp.solar (jd, eb_del_tdut,d1, d2);
2375  gx = eclp.GetRSun();
2376  AppPos (jd, eclp.GetEp2(), phi, lamda, eb_geoheight, 1, gx,
2377  azim, elev, dist);
2378  if (elev < elrise) eflg = 1;
2379  magecl = getlocmag(jd, eclp.GetEp2(), phi, lamda, eb_geoheight,
2380  eclp.GetRSun(),eclp.GetRMoon(), i);
2381  if (magecl > eb_maxps)
2382  {
2383  eb_maxelv = elev;
2384  eb_maxps = magecl;
2385  eb_jdmaxps = jd;
2386  }
2387  if (i == 0) eflg = 1;
2388  if (jd > eb_ltote) eflg = 1;
2389 
2390  } while (!eflg);
2391  eb_ltote = jd;
2392  }
2393  else eb_ltote = eb_ltotb - 1.0;
2394  }
2395 
2396  return maxp;
2397  }
2398 
2399 
2400 void EclSolar::getLocalDetails(char *otxt)
2401  {
2402  /* get the details of the eclipse selected in eclbuf.select
2403  and place the output into otxt
2404  */
2405  int j, p, i, ecloutbn;
2406  int dd, mm, yy, deg, mnt;
2407  double sec, hh;
2408 
2409  int spp[4], nump;
2410  double spt[4], ept[4];
2411  double jd, jdf;
2412  char dts[13];
2413  char outb[127];
2414 
2415  if (!eb_start_called) eclStart();
2416  eb_local_called = true;
2417 
2418  j = eb_eclselect-1;
2419  p = eb_phase[j];
2420 
2421  ecloutbn = 3;
2422  sprintf(otxt,"+++ Timezone: %g +++ TT - UTC: %g (sec) +++ Year: %5i +++\n\n", eb_tzone, eb_del_tdut, eb_year);
2423  switch (p)
2424  {
2425  case 1: strcpy(outb,"\t\tPartial Eclipse of the Sun");
2426  break;
2427  case 2: strcpy(outb,"\t\tNon-Central Annular Eclipse of the Sun");
2428  break;
2429  case 3: strcpy(outb,"\t\tNon-Central Total Eclipse of the Sun");
2430  break;
2431  case 4: strcpy(outb,"\t\tAnnular Eclipse of the Sun");
2432  break;
2433  case 5: strcpy(outb, "\t\tTotal Eclipse of the Sun");
2434  break;
2435  case 6: strcpy(outb, "\t\tAnnular/Total Solar Eclipse");
2436  break;
2437 
2438  case -1:
2439  case -2: strcpy(outb, "\t\tPenumbral Eclipse of the Moon");
2440  break;
2441  case -3: strcpy(outb, "\t\tPartial eclipse of the Moon");
2442  break;
2443  case -4: strcpy(outb, "\t\tTotal eclipse of the Moon");
2444  break;
2445  };
2446 
2447  strcat(otxt,outb);
2448  sprintf(outb,"\n\nMaximum Eclipse at ");
2449  strcat(otxt,outb);
2450  dtmstr((eb_eclmjd[j]+eb_tzone/24.0),dts);
2451  dts[12] = '\0';
2452  strcat(otxt,dts);
2453  if (p < 4)
2454  {
2455  sprintf(outb," with magnitude:%5.2f",eb_magnitude[j]);
2456  strcat(otxt, outb);
2457  }
2458 
2459  strcat(otxt,"\n");
2460  nump = localStart(j, spt, ept, spp, p, otxt);
2461  if ((p < 4) || (nump < 1)) ecloutbn = 5;
2462 
2463  if (ecloutbn == 3)
2464  {
2465  // get start and stop dates for central phase
2466  jd = spt[nump-1];
2467  for (i=0; i<nump; i++)
2468  if ((spt[i] < jd) && (spp[i] > 3)) jd = spt[i]; // start of central phase
2469  caldat(jd, dd, mm, yy, hh);
2470  dms (hh,deg,mnt,sec);
2471  sec = 0;
2472  i = mnt / eb_cstep;
2473  mnt = i* int(eb_cstep); // cut to proper time step
2474  hh = ddd (deg, mnt, sec);
2475  jd = mjd (dd, mm, yy, hh);
2476  jdf = ept[nump-1];
2477  for (i=0; i<nump; i++)
2478  if ((ept[i] > jdf) && (spp[i] > 3)) jdf = ept[i]; // end of central phase
2479 
2480  jd += eb_cstep / (24.0*60.0);
2481  }
2482 
2483  // local circumstances
2484  strcat(otxt, "\n\n\nLocal Circumstances for ");
2485  jd = eb_geolat;
2486  jdf = eb_geolong;
2487  sprintf(outb,"\nLat: %g Long: %g height: %g m\n\n",
2488  jd, jdf, eb_geoheight);
2489  strcat(otxt,outb);
2490  if (p != 0)
2491  {
2492  if (eb_lccnt > 0)
2493  {
2494  sprintf(outb,"Eclipse visible from ");
2495  dtmstr((eb_lcb1+eb_tzone/24.0),dts);
2496  dts[12] = '\0';
2497  strcat(outb," ");
2498  strcat(outb,dts);
2499  strcat(outb," to ");
2500  dtmstr((eb_lce1+eb_tzone/24.0),dts);
2501  dts[12] = '\0';
2502  strcat(outb,dts);
2503  if (eb_lccnt > 2) // this case almost never happens
2504  {
2505  strcat(otxt,outb);
2506  strcpy(outb,"\n\tand from ");
2507  dtmstr((eb_lcb2+eb_tzone/24.0),dts);
2508  dts[12] = '\0';
2509  strcat(outb," ");
2510  strcat(outb,dts);
2511  strcat(outb," to ");
2512  dtmstr((eb_lce2+eb_tzone/24.0),dts);
2513  dts[12] = '\0';
2514  strcat(outb,dts);
2515  }
2516  }
2517  else sprintf(outb,"Eclipse not visible");
2518  strcat(otxt,outb);
2519  }
2520 
2521  // local solar eclipse magnitude
2522  if ((p > 0) && (eb_lccnt > 0))
2523  {
2524  sprintf(outb,"\nMaximum Eclipse at ");
2525  strcat(otxt,outb);
2526  dtmstr((eb_jdmaxps+eb_tzone/24.0),dts);
2527  dts[12] = '\0';
2528  strcat(otxt,dts);
2529  sprintf(outb," with magnitude %6.3f", eb_maxps);
2530  strcat(otxt,outb);
2531  sprintf(outb," elev:%4.1f", 180.0*eb_maxelv/M_PI);
2532  strcat(otxt,outb);
2533  if (eb_ltotb <= eb_ltote)
2534  { // local central eclipse
2535  if ((p % 2) == 0) strcpy(outb, "\nannularity from");
2536  else strcpy(outb, "\ntotality from");
2537  if ((p == 1) || (p == 6))
2538  strcpy(outb, "\ntotality/annularity from");
2539  strcat(otxt,outb);
2540  caldat((eb_ltotb+eb_tzone/24.0), dd, mm, yy, hh);
2541  caldat((eb_ltote+eb_tzone/24.0), dd, mm, yy, jd);
2542  hh = DegFDms(hh);
2543  jd = DegFDms(jd);
2544  jdf = (eb_ltote - eb_ltotb) * 86400.0;
2545  sprintf(outb,"%8.4f to%8.4f del.t:%3.0f sec \n",hh,jd, jdf);
2546  strcat(otxt,outb);
2547  }
2548  }
2549 
2550  eb_maxelv /= degrad;
2551  }
2552 
2553 //---------Northern and Southern Umbra Boundaries ---------------------
2554 
2555 double EclSolar::navCourse (double lat1, double lng1, double lat2, double lng2)
2556 {
2557  // get course (in radians) from (lat1, lng1) to (lat2, lng2) over the Earth surface
2558  // the geographic coordinates are in decimal degrees
2559 
2560  double lt1, ln1, lt2, ln2, cd, an;
2561 
2562  lt1 = lat1 * degrad;
2563  ln1 = lng1 * degrad;
2564  lt2 = lat2 * degrad;
2565  ln2 = lng2 * degrad;
2566 
2567  cd = sin(lt1)*sin(lt2) + cos(lt1)*cos(lt2)*cos(ln2 - ln1);
2568  an = acos(cd);
2569  an = cos(lt1) * sin(an);
2570 
2571  if (an == 0) return 0; // same spot. didn't move
2572 
2573  cd = (sin(lt2) - sin(lt1)*cd) / an;
2574  an = acos (cd);
2575 
2576  if (sin(ln2 - ln1) < 0) an = -an;
2577 
2578  return an;
2579 }
2580 
2581 void EclSolar::navNewPos (double d, double an, double lat1, double lng1, double &lat2, double &lng2)
2582 {
2583  /*
2584  starting from (lat1, lng1) along the great circle for d (radians) with course an (in radians)
2585  get the new position (lat2, lng2) (in decimal degrees) at the Earth surface
2586  */
2587 
2588  double cd, sd, lt1, ag;
2589 
2590  ag = an;
2591  if (ag > M_PI) ag -= 2*M_PI;
2592  if (ag < -M_PI) ag += 2*M_PI;
2593 
2594  cd = cos(d);
2595  lt1 = lat1 * degrad;
2596 
2597  sd = cd * sin(lt1) + sin(d) * cos(lt1) * cos(ag);
2598  lat2 = asin(sd);
2599 
2600  lng2 = cos(lt1) * cos(lat2);
2601 
2602  if (lng2 == 0) // just in case to avoid a crash
2603  {
2604  lat2 = lat1;
2605  lng2 = lng1;
2606  return;
2607  }
2608 
2609  lng2 = (cd - sin(lt1) * sd) / lng2;
2610  lng2 = acos(lng2);
2611  lng2 /= degrad;
2612  if (ag > 0) lng2 = lng1 + lng2;
2613  else lng2 = lng1 -lng2;
2614  if(lng2 > 360.0) lng2 -= 360.0;
2615  if(lng2 < 0) lng2 += 360.0;
2616 
2617  lat2 /= degrad;
2618 
2619 }
2620 
2621 int EclSolar::centralBound(bool firstc, double& lat1, double& lng1, double& lat2, double& lng2)
2622 {
2623  /* Get the geographic coordinates of the northern or southern boundaries
2624  of the umbra at time t.
2625  INPUT: firstc :true for first call
2626 
2627  OUTPUT:
2628  lat, lng : latitude and longitude of umbra boundary in decimal degrees.
2629  If lat > 90 no boundary exists.
2630 
2631  RETURN: current phase if time within eclipse, <=3 if no central eclipse
2632  */
2633 
2634  bool lastp;
2635  int k;
2636  double dpn1, t;
2637  double lt1, ln1, lt2, ln2, an;
2638  Eclipse eclp;
2639 
2640  if (!eb_start_called) eclStart();
2641 
2642  lng1 = 0.0;
2643  lat1 = 100.0;
2644  lng2 = 0.0;
2645  lat2 = 100.0;
2646 
2647  lastp = false;
2648 
2649  if (eb_lunactive) return 0; // only solar eclipses
2650 
2651 
2652  if (firstc)
2653  {
2654  k = eclPltCentral(true, lt1, ln1);
2655  firstc = false;
2656  }
2657  else k = eclPltCentral(false, lt1, ln1);
2658  t = eb_lastjd;
2659 
2660  if (k <= 3) return k; // no central eclipse
2661 
2662  k = eclPltCentral(false, lt2, ln2); // next step
2663  eb_lastjd = t; // go back to the original step
2664 
2665  if (k <= 3) // try the last step instead at the end
2666  {
2667  eb_lastjd -= 2.0 * eb_cstep / (24.0*60.0);
2668  k = eclPltCentral(false, lt2, ln2);
2669  eb_lastjd = t;
2670  lastp = true;
2671  };
2672 
2673  if (k <= 3) return k; // no central eclipse
2674 
2675  eclp.solar(t, eb_del_tdut, lat1, lng1);
2676  lat1 = 100.0;
2677  lng1 = 0;
2678 
2679  an = navCourse (lt1, ln1, lt2, ln2); // direction of shadow along Earth surface
2680  an += 0.5*M_PI; // direction perpendicular to shadow movement (right boundary)
2681 
2682  eclp.duration(t, eb_del_tdut, dpn1); // dpn1 is width of umbra in km
2683  dpn1 = (dpn1 / 111.1) * 0.0174533; // radians of umbra width
2684  dpn1 /= 2.0;
2685  navNewPos(dpn1, an, lt1, ln1, lat1, lng1);
2686 
2687  an -= M_PI; // find opposite boundary
2688 
2689  navNewPos(dpn1, an, lt1, ln1, lat2, lng2);
2690 
2691  if (lastp) // we went the opposite way at the end
2692  {
2693  lt1 = lat2;
2694  ln1 = lng2;
2695  lat2 = lat1;
2696  lng2 = lng1;
2697  lat1 = lt1;
2698  lng1 = ln1;
2699  return 0; // end of eclipse
2700  }
2701  else return k;
2702  }
2703 
2704 //-------------------- Shadow Cone -------------------------
2705 
2706 void EclSolar::getShadowCone(double mjd, bool umbra, int numpts, double* lat, double* lng)
2707 {
2708  /* Get the geographic coordinates of the shadow cone at MJD-time mjd.
2709  if umbra is true the umbra cone will be returned
2710  if umbra is false the penumbra will be returned
2711 
2712  OUTPUT:
2713  lat and lng must be arrays of length numpts into which the numpts points will be placed
2714  if there is no (total) eclipse at the time, lat will be set 100.0, lng 0.
2715  */
2716 
2717  const double flat = 0.996633; // flatting of the Earth
2718 
2719  int j, k1, k2, kmiss;
2720  double dpn1, pan1, s0, dlt, dta, ag;
2721  double s, r0, r2, dt1, dt2;
2722  Vec3 vrm, vre;
2723  Vec3 ubm, ube;
2724  Vec3 ax1, ax2;
2725  Mat3 mx1, mx2;
2726  Eclipse eclp;
2727 
2728  if (numpts < 2) return;
2729 
2730  for (j=0; j<numpts; j++) // just in case you got to return empty-handed
2731  {
2732  lat[j] = 100.0;
2733  lng[j] = 0;
2734  }
2735 
2736  if (!eb_start_called) eclStart();
2737  if (eb_lunactive) return; // only for solar eclipses
2738 
2739  if (umbra && (eb_phase[eb_eclselect-1] < 1)) return;
2740 
2741  // get the shadow details
2742  if(umbra) eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1);
2743  else eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn1, pan1);
2744 
2745  dpn1 *= 0.5;
2746 
2747  if (!umbra)
2748  {
2749  if (eb_penamode == 0)
2750  {
2751  dpn1 *= eb_penangle;
2752  pan1 *= eb_penangle;
2753  }
2754 
2755  if (eb_penamode > 0)
2756  {
2757  s0 = eb_penangle * tan(pan1);
2758  s0 = atan(s0);
2759  if (pan1 > 0)
2760  {
2761  dpn1 = dpn1 * s0 / pan1;
2762  pan1 = s0;
2763  }
2764  }
2765  };
2766 
2767  // get apex of umbra/penumbra cone
2768  pan1 = tan(pan1);
2769  if (pan1 < 0.0000174533) return; // if cone is smaller that 0.001°
2770  dpn1 = dpn1 / pan1;
2771 
2772  s0 = - dot(ubm, ube);
2773  ubm = ubm + (s0 - dpn1) * ube;
2774 
2775  // get any vector perpendicular to the shadow
2776  ax1[0] = 0;
2777  ax1[1] = 0;
2778  ax1[2] = 1.0;
2779  ax2 = ax1 * ube;
2780  ax1 = vnorm(ax2) * pan1;
2781 
2782  ax2 = carpol(ube);
2783  mx1 = zrot(ax2[1]);
2784  mx2 = yrot(ax2[2]) * mx1; // transform to a system where x points into the direction of the shadow
2785  mx1 = mxtrn(mx1); // to get back to equatorial system after rotation
2786 
2787  ax2 = mxvct(mx2,ax1); // vector which we will rotate numpts times
2788 
2789  // now loop for numpts points
2790  dta = 2.0*M_PI / double(numpts);
2791 
2792  for (j=0; j<numpts; j++)
2793  {
2794  ag = double(j) * dta; // rotation angle of the cone vector
2795  mx2 = xrot(ag);
2796  ax1 = mxvct(mx2,ax2);
2797  ax1 = mxvct(mx1, ax1);
2798 
2799  vre = ube + ax1;
2800  vre = vnorm(vre); // direction in which to find an intersection
2801  vrm[0] = ubm[0];
2802  vrm[1] = ubm[1];
2803  vrm[2] = ubm[2];
2804 
2805  s0 = - dot(vrm, vre); // distance Apex - fundamental plane
2806  r2 = dot (vrm,vrm);
2807  dlt = s0*s0 + 1.0 - r2;
2808  r0 = 1.0 - dlt;
2809 
2810  if (r0 > 0) r0 = sqrt (r0);
2811  else r0 = 0; // distance center of Earth - shadow axis
2812 
2813  // calculate the coordinates if there is an intersecton
2814  if (r0 < 1.0) // there should be an intersection
2815  {
2816  if (dlt > 0) dlt = sqrt(dlt);
2817  else dlt = 0;
2818  s = s0 - dlt; // distance Apex - fundamental plane
2819  vrm = vrm + s * vre;
2820  vrm = vnorm(vrm);
2821  vrm[2] *= flat; // vector to intersection
2822  vre = carpol(vrm);
2823  lng[j] = vre[1] - lsidtim(mjd,0,0)*0.261799387799; // geographic coordinates
2824  if (lng[j] > 2*M_PI) lng[j] -= 2.0*M_PI;
2825  if (lng[j] < 0.0) lng[j] += 2.0*M_PI;
2826  lat[j] = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615;
2827  lat[j] = atan23(vrm[2],lat[j]);
2828  lat[j] /= degrad;
2829  lng[j] /= degrad;
2830 
2831  if (lng[j] < 0.0) lng[j] += 360.0;
2832  if (lng[j] > 360.0) lng[j] -= 360.0;
2833  }
2834  else // no intersection.
2835  {
2836  lat[j] = 100.0;
2837  lng[j] = 0;
2838  };
2839  }
2840 
2841  k1 = -1;
2842  k2 = -1;
2843  kmiss = 0;
2844  for (j=0; j<numpts; j++) // check for missing points
2845  {
2846  if (lat[j] < 100.0)
2847  {
2848  if (k1 < 0) k1 = j; // first valid point
2849  k2 = j; // last valid point
2850  }
2851  else kmiss++;
2852  }
2853 
2854  if ((kmiss < 2) || (kmiss >= (numpts -1))) return; // cone completely on Earth surface or not at all
2855 
2856  dt1 = double(k1) * dta;
2857  dt2 = double(k2) * dta;
2858  k1--;
2859  k2++;
2860  if (k1 < 0) k1 = numpts - 1; // wrap around
2861  if (k2 >= (numpts-1)) k2 = 0;
2862  dta = 2.0*M_PI / double(numpts*20);
2863 
2864  for (j=1; j<20; j++) // go in smaller steps to get closer to the borderline
2865  {
2866  ag = dt1 - double(j) * dta; // rotation angle of the cone vector
2867  mx2 = xrot(ag);
2868  ax1 = mxvct(mx2,ax2);
2869  ax1 = mxvct(mx1, ax1);
2870 
2871  vre = ube + ax1;
2872  vre = vnorm(vre); // direction in which to find an intersection
2873  vrm[0] = ubm[0];
2874  vrm[1] = ubm[1];
2875  vrm[2] = ubm[2];
2876 
2877  s0 = - dot(vrm, vre); // distance Apex - fundamental plane
2878  r2 = dot (vrm,vrm);
2879  dlt = s0*s0 + 1.0 - r2;
2880  r0 = 1.0 - dlt;
2881 
2882  if (r0 > 0) r0 = sqrt (r0);
2883  else r0 = 0; // distance center of Earth - shadow axis
2884 
2885  // calculate the coordinates if there is an intersecton
2886  if (r0 < 1.0) // there should be an intersection
2887  {
2888  if (dlt > 0) dlt = sqrt(dlt);
2889  else dlt = 0;
2890  s = s0 - dlt; // distance Apex - fundamental plane
2891  vrm = vrm + s * vre;
2892  vrm = vnorm(vrm);
2893  vrm[2] *= flat; // vector to intersection
2894  vre = carpol(vrm);
2895  lng[k1] = vre[1] - lsidtim(mjd,0,0)*0.261799387799; // geographic coordinates
2896  if (lng[k1] > 2*M_PI) lng[k1] -= 2.0*M_PI;
2897  if (lng[k1] < 0.0) lng[k1] += 2.0*M_PI;
2898  lat[k1] = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615;
2899  lat[k1] = atan23(vrm[2],lat[k1]);
2900  lat[k1] /= degrad;
2901  lng[k1] /= degrad;
2902 
2903  if (lng[k1] < 0.0) lng[k1] += 360.0;
2904  if (lng[k1] > 360.0) lng[k1] -= 360.0;
2905  }
2906  else break;
2907  }
2908 
2909  for (j=1; j<20; j++) // go in smaller steps to get closer to the borderline
2910  {
2911  ag = dt2 + double(j) * dta; // rotation angle of the cone vector
2912  mx2 = xrot(ag);
2913  ax1 = mxvct(mx2,ax2);
2914  ax1 = mxvct(mx1, ax1);
2915 
2916  vre = ube + ax1;
2917  vre = vnorm(vre); // direction in which to find an intersection
2918  vrm[0] = ubm[0];
2919  vrm[1] = ubm[1];
2920  vrm[2] = ubm[2];
2921 
2922  s0 = - dot(vrm, vre); // distance Apex - fundamental plane
2923  r2 = dot (vrm,vrm);
2924  dlt = s0*s0 + 1.0 - r2;
2925  r0 = 1.0 - dlt;
2926 
2927  if (r0 > 0) r0 = sqrt (r0);
2928  else r0 = 0; // distance center of Earth - shadow axis
2929 
2930  // calculate the coordinates if there is an intersecton
2931  if (r0 < 1.0) // there should be an intersection
2932  {
2933  if (dlt > 0) dlt = sqrt(dlt);
2934  else dlt = 0;
2935  s = s0 - dlt; // distance Apex - fundamental plane
2936  vrm = vrm + s * vre;
2937  vrm = vnorm(vrm);
2938  vrm[2] *= flat; // vector to intersection
2939  vre = carpol(vrm);
2940  lng[k2] = vre[1] - lsidtim(mjd,0,0)*0.261799387799; // geographic coordinates
2941  if (lng[k2] > 2*M_PI) lng[k2] -= 2.0*M_PI;
2942  if (lng[k2] < 0.0) lng[k2] += 2.0*M_PI;
2943  lat[k2] = sqrt(vrm[0]*vrm[0] + vrm[1]*vrm[1])*0.993305615;
2944  lat[k2] = atan23(vrm[2],lat[k2]);
2945  lat[k2] /= degrad;
2946  lng[k2] /= degrad;
2947 
2948  if (lng[k2] < 0.0) lng[k2] += 360.0;
2949  if (lng[k2] > 360.0) lng[k2] -= 360.0;
2950  }
2951  else break;
2952  }
2953 
2954 }
2955 
Refract
double Refract(double h, double p, double t)
Definition: astrolib.cpp:893
Mat3
Definition: attlib.h:63
EclSolar::putEclSelect
void putEclSelect(int es)
Definition: eclsolar.cpp:652
GeoPos
Vec3 GeoPos(double jd, double ep2, double lat, double lng, double ht)
Definition: astrolib.cpp:718
Eclipse::duration
double duration(double jd, double tdut, double &width)
Definition: astrolib.cpp:2157
degrad
const double degrad
Definition: eclsolar.cpp:45
Eclipse::GetRSun
Vec3 GetRSun() const
Definition: astrolib.cpp:2215
EclSolar::setLunarEcl
void setLunarEcl(bool lecl)
Definition: eclsolar.cpp:163
EclSolar::setDeltaTAI_UTC
void setDeltaTAI_UTC(double d)
Definition: eclsolar.cpp:185
EclSolar::getLocalTotal
int getLocalTotal(double &mjd_start, double &mjd_stop)
Definition: eclsolar.cpp:230
Vec3
Definition: attlib.h:27
EclSolar::getShadowCone
void getShadowCone(double mjd, bool umbra, int numpts, double *lat, double *lng)
Definition: eclsolar.cpp:2706
EclSolar::getEclYearInfo
void getEclYearInfo(char *wbuf)
Definition: eclsolar.cpp:458
GBL_ECLBUF
const int GBL_ECLBUF
Definition: eclsolar.h:17
EclSolar::getYear
int getYear() const
Definition: eclsolar.cpp:127
EclSolar::setLocalPos
void setLocalPos(double lat, double lng, double hgt)
Definition: eclsolar.cpp:202
EclSolar::setAutoTAI_UTC
void setAutoTAI_UTC()
Definition: eclsolar.cpp:195
EclSolar::GRSBound
int GRSBound(bool firstc, double &lat1, double &lng1, double &lat2, double &lng2)
Definition: eclsolar.cpp:1972
Eclipse::solar
int solar(double jd, double tdut, double &phi, double &lamda)
Definition: astrolib.cpp:1893
yrot
Mat3 yrot(double a)
Definition: attlib.cpp:509
eclsolar.h
ddd
double ddd(int d, int m, double s)
Definition: astrolib.cpp:35
astrolib.h
EclSolar::setCurrentMJD
void setCurrentMJD(int year, int month, int day, int hour, int min, double sec)
Definition: eclsolar.cpp:424
lsidtim
double lsidtim(double jd, double lambda, double ep2)
Definition: astrolib.cpp:302
HorEqu
Vec3 HorEqu(double jd, double ep2, double lat, double lng, Vec3 r)
Definition: astrolib.cpp:813
Eclipse::GetEp2
double GetEp2() const
Definition: astrolib.cpp:2225
EclSolar::getLocalDetails
void getLocalDetails(char *otxt)
Definition: eclsolar.cpp:2400
Eclipse::lunar
int lunar(double jd, double tdut)
Definition: astrolib.cpp:2230
DefTdUt
double DefTdUt(int yi)
Definition: astrolib.cpp:223
EclSolar::getTotal
int getTotal(double &mjd_start, double &mjd_stop)
Definition: eclsolar.cpp:379
EclSolar::eclPltCentral
int eclPltCentral(bool firstc, double &lat, double &lng)
Definition: eclsolar.cpp:1582
Eclipse::GetRMoon
Vec3 GetRMoon() const
Definition: astrolib.cpp:2220
EclSolar::setPenumbraAngle
void setPenumbraAngle(double pa, int mode)
Definition: eclsolar.cpp:771
carpol
Vec3 carpol(const Vec3 &c)
Definition: attlib.cpp:184
vnorm
Vec3 vnorm(const Vec3 &c)
Definition: attlib.cpp:170
EclSolar::getNumberEclYear
int getNumberEclYear()
Definition: eclsolar.cpp:145
Eclipse::maxpos
void maxpos(double jd, double tdut, double &phi, double &lamda)
Definition: astrolib.cpp:1983
Eclipse
Definition: astrolib.h:125
zrot
Mat3 zrot(double a)
Definition: attlib.cpp:530
EclSolar::centralBound
int centralBound(bool firstc, double &lat1, double &lng1, double &lat2, double &lng2)
Definition: eclsolar.cpp:2621
EclSolar::getDatefromMJD
void getDatefromMJD(double mjd, int &year, int &month, int &day, int &hour, int &min, double &sec) const
Definition: eclsolar.cpp:438
EclSolar::GNSBound
int GNSBound(bool firstc, bool north, double &lat, double &lng)
Definition: eclsolar.cpp:1784
EclSolar::getLocalVisibility
int getLocalVisibility(double &mjd_start, double &mjd_stop)
Definition: eclsolar.cpp:215
EclSolar::getMaxPos
void getMaxPos(double &lat, double &lng)
Definition: eclsolar.cpp:1551
caldat
void caldat(double mjd, int &day, int &month, int &year, double &hour)
Definition: astrolib.cpp:145
EclSolar::nextEcl
void nextEcl()
Definition: eclsolar.cpp:678
EclSolar::putYear
void putYear(int yr)
Definition: eclsolar.cpp:132
MAXLUN
const int MAXLUN
Definition: eclsolar.h:18
EclSolar::EclSolar
EclSolar()
Definition: eclsolar.cpp:49
abs
double abs(const Vec3 &c)
Definition: attlib.cpp:100
EclSolar::previousEcl
void previousEcl()
Definition: eclsolar.cpp:726
EclSolar::getPenumbra
int getPenumbra(double &mjd_start, double &mjd_stop)
Definition: eclsolar.cpp:304
mxtrn
Mat3 mxtrn(const Mat3 &m1)
Definition: attlib.cpp:379
EclSolar::getEclTxt
int getEclTxt(int j, char *jtxt)
Definition: eclsolar.cpp:598
AppPos
void AppPos(double jd, double ep2, double lat, double lng, double ht, int solsys, Vec3 r, double &azim, double &elev, double &dist)
Definition: astrolib.cpp:835
EclSolar::setStepWidth
void setStepWidth(double s)
Definition: eclsolar.cpp:172
dms
void dms(double dd, int &d, int &m, double &s)
Definition: astrolib.cpp:59
EclSolar::~EclSolar
~EclSolar()
Definition: eclsolar.cpp:54
mjd
double mjd(int day, int month, int year, double hour)
Definition: astrolib.cpp:94
EclSolar::setTimezone
void setTimezone(double d)
Definition: eclsolar.cpp:179
Eclipse::penumd
void penumd(double jd, double tdut, Vec3 &vrm, Vec3 &ves, double &dpn, double &pang)
Definition: astrolib.cpp:2035
M_PI
#define M_PI
Definition: GeoDataCoordinates.h:26
xrot
Mat3 xrot(double a)
Definition: attlib.cpp:488
mag
double mag(double x[3])
Definition: sgp4ext.cpp:68
EclSolar::getPartial
int getPartial(double &mjd_start, double &mjd_stop)
Definition: eclsolar.cpp:334
EclSolar::getLocalMax
int getLocalMax(double &mjdmax, double &magmax, double &elmax)
Definition: eclsolar.cpp:275
EquHor
Vec3 EquHor(double jd, double ep2, double lat, double lng, Vec3 r)
Definition: astrolib.cpp:790
EclSolar::getLastMJD
double getLastMJD() const
Definition: eclsolar.cpp:764
dot
double dot(const Vec3 &c1, const Vec3 &c2)
Definition: attlib.cpp:108
Eclipse::umbra
void umbra(double jd, double tdut, Vec3 &vrm, Vec3 &ves, double &dpn, double &pang)
Definition: astrolib.cpp:2081
polcar
Vec3 polcar(const Vec3 &c)
Definition: attlib.cpp:207
mxvct
Vec3 mxvct(const Mat3 &m1, Vec3 &v1)
Definition: attlib.cpp:473
PMJD
double PMJD[MAXLUN]
Definition: eclsolar.h:20
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:13:39 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

marble

Skip menu "marble"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal