1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2012 Gerhard HOLTKAMP
4 //
5
6 /***************************************************************************
7 * Calculate Solar Eclipses *
8 * *
9 * *
10 * The algorithm for the phases of the Moon and of the dates for the *
11 * equinoxes and solstices of the Sun as well as the dates of eclipses *
12 * are based on Jean Meeus "Astronomical Formulae for Calculators", *
13 * Willman-Bell, Inc., Richmond, Virginia, 1988 *
14 * *
15 * The algorithm for the Modified Julian Date and the calendar as well as *
16 * the detailed eclipse calculations are based on *
17 * O.Montebruck and T.Pfleger, "Astronomy with a PC", *
18 * Springer Verlag, Berlin, Heidelberg, New York, 1989 *
19 * and on the *
20 * "Explanatory Supplement to the Astronomical Almanac" *
21 * University Science Books, Mill Valley, CA, 1992 *
22 * *
23 * Open Source Code. License: GNU LGPL Version 2+ *
24 * *
25 * Author: Gerhard HOLTKAMP, 28-JAN-2013 *
26 ***************************************************************************/
27
28 /*------------ include files and definitions -----------------------------*/
29 #include "eclsolar.h"
30 #include <cstdio>
31 #include <cstdlib>
32 #include <cstring>
33 #include <cmath>
34 #include <ctime>
35 using namespace std;
36
37 #include "astrolib.h"
38
39 /* const double PI = 3.14159265359; */
40 const double degrad = M_PI / 180.0;
41
42 // ################ Solar Eclipse Class ####################
43
EclSolar()44 EclSolar::EclSolar()
45 {
46 esinit();
47 }
48
~EclSolar()49 EclSolar::~EclSolar()
50 {
51
52 }
53
atan23(double y,double x)54 double EclSolar::atan23 (double y, double x)
55 {
56 /* redefine atan2 so that it doesn't crash when both x and y are 0 */
57 double result;
58
59 if ((x == 0) && (y == 0)) result = 0;
60 else result = atan2 (y, x);
61
62 return result;
63 }
64
esinit()65 void EclSolar::esinit()
66 {
67 // initialize eclipse data
68 eb_start_called = false;
69 eb_moonph_called = false;
70 eb_lunecl = true;
71 eb_lunactive = false;
72 eb_local_called = false;
73
74 eb_day = 1;
75 eb_month = 1;
76 eb_year = 2012;
77 eb_hour = 0;
78 eb_minute = 0;
79 eb_second = 0;
80 eb_tzone = 0;
81 eb_del_auto = 1;
82 DefTime();
83 eb_time = 0;
84 eb_del_tdut = DefTdUt(eb_year);
85 eb_geolat = 0;
86 eb_geolong = 0;
87 eb_geoheight = 0;
88 eb_lstcall = 0;
89 eb_locecl = 0;
90 eb_lastyear = -9999;
91 eb_numecl = 0;
92 eb_lasttz = eb_tzone;
93 eb_lastdlt = eb_del_tdut;
94 eb_cstep = 1.0;
95 eb_cmxlat = 0;
96 eb_cmxlng = 0;
97 eb_penangle = 1.0;
98 eb_penamode = 0;
99 }
100
DefTime()101 void EclSolar::DefTime () // Get System Time and Date
102 {
103 time_t tt;
104 int hh, mm, ss;
105 double jd, hr;
106
107 tt = time(NULL);
108 jd = 40587.0 + tt/86400.0; // seconds since 1-JAN-1970
109
110 caldat(jd, hh, mm, ss, hr);
111 eb_year = ss;
112 eb_month = mm;
113 eb_day = hh;
114
115 dms(hr, hh, mm, jd);
116 eb_hour = hh;
117 eb_minute = mm;
118 eb_second = int(jd);
119 if (eb_del_auto) eb_del_tdut = DefTdUt(eb_year);
120 };
121
getYear() const122 int EclSolar::getYear() const
123 {
124 return eb_year;
125 }
126
putYear(int yr)127 void EclSolar::putYear(int yr)
128 {
129 eb_start_called = false;
130 eb_moonph_called = false;
131 eb_local_called = false;
132 eb_lunactive = false;
133
134 eb_year = yr;
135 if (eb_del_auto) eb_del_tdut = DefTdUt(eb_year);
136 moonph();
137
138 }
139
getNumberEclYear()140 int EclSolar::getNumberEclYear()
141 {
142 // RETURN the number of eclipses of the currently selected year
143
144 int j, k;
145
146 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
147
148 if (eb_lunecl) return eb_numecl;
149
150 k = 0;
151 for (j=0; j<eb_numecl; j++)
152 {
153 if (eb_phase[j] > 0) k++;
154 }
155
156 return k;
157 }
setLunarEcl(bool lecl)158 void EclSolar::setLunarEcl(bool lecl)
159 {
160 // if lecl = true include lunar eclipses in addition to solar ones
161 if (lecl) eb_lunecl = true;
162 else eb_lunecl = false;
163 eb_start_called = false;
164 eb_local_called = false;
165 }
166
setStepWidth(double s)167 void EclSolar::setStepWidth(double s)
168 {
169 // set the step width (in minutes) used for calculations
170 if (s < 0.01) eb_cstep = 0.01;
171 else eb_cstep = s;
172 }
173
setTimezone(double d)174 void EclSolar::setTimezone(double d)
175 {
176 // set the timezone to d (hours difference from UTC) for I/O
177 eb_tzone = d;
178 }
179
setDeltaTAI_UTC(double d)180 void EclSolar::setDeltaTAI_UTC(double d)
181 {
182 // c is the difference between TAI and UTC according to the IERS
183 // we have to add 32.184 sec to get to the difference TT - UT
184 // which is used in the calculations here
185
186 eb_del_tdut = d + 32.184;
187 eb_del_auto = 0;
188 }
189
setAutoTAI_UTC()190 void EclSolar::setAutoTAI_UTC()
191 {
192 // set the difference between TAI and UTC according to the IERS
193 eb_del_auto = true;
194 eb_del_tdut = DefTdUt(eb_year);
195 }
196
setLocalPos(double lat,double lng,double hgt)197 void EclSolar::setLocalPos(double lat, double lng, double hgt)
198 {
199 // set the geographic coordinates for the position of the local info
200 // latitude lat, longitude lng in decimal degrees
201 // height hgt in meters
202
203 eb_geolat = lat;
204 eb_geolong = lng;
205 eb_geoheight = hgt;
206
207 eb_local_called = false;
208 }
209
getLocalVisibility(double & mjd_start,double & mjd_stop)210 int EclSolar::getLocalVisibility(double &mjd_start, double &mjd_stop)
211 {
212 // local start and stop times (MJD) for eclipse
213 // RETURN 0 if not locally visible
214
215 char wbuf[700];
216
217 if (!eb_local_called) getLocalDetails(wbuf);
218
219 mjd_start = eb_lcb1;
220 mjd_stop = eb_lce1;
221
222 return eb_lccnt;
223 }
224
getLocalTotal(double & mjd_start,double & mjd_stop)225 int EclSolar::getLocalTotal(double &mjd_start, double &mjd_stop)
226 {
227 // local start and stop times (MJD) for totality/annularity
228 // RETURN 0 if not locally visible
229
230 int k, j;
231 char wbuf[700];
232
233 if (!eb_local_called) getLocalDetails(wbuf);
234
235 mjd_start = 0;
236 mjd_stop = 0;
237
238 if(eb_lccnt == 0) return 0;
239
240 k = 0;
241 if(eb_lunactive)
242 {
243 for (j=0; j<eb_nphase; j++)
244 {
245 if ((k==0) && (eb_spp[j] > 3))
246 {
247 mjd_start = eb_spt[j];
248 mjd_stop = eb_ept[j];
249 k = 1;
250 }
251 }
252
253 if(mjd_start < eb_lcb1) mjd_start = eb_lcb1;
254 if(mjd_start > eb_lce1) k = 0;
255 if(mjd_stop > eb_lce1) mjd_stop = eb_lce1;
256 if(mjd_stop < eb_lcb1) k = 0;
257
258 eb_ltotb = mjd_start;
259 eb_ltote = mjd_stop;
260
261 }
262 else k = eb_lccnt;
263
264 mjd_start = eb_ltotb;
265 mjd_stop = eb_ltote;
266
267 return k;
268 }
269
getLocalMax(double & mjdmax,double & magmax,double & elmax)270 int EclSolar::getLocalMax(double &mjdmax, double &magmax, double &elmax)
271 {
272 // get local (solar) eclipse maximum
273 // mjdmax : Modified Julian Date of maximum eclipse
274 // magmax : maximum (local) magnitude of eclipse
275 // elmax : local Sun elevation at maximum
276
277 // RETURN : 0 if eclipse not visible
278
279 int k;
280
281 mjdmax = 0;
282 magmax = 0;
283 elmax = 0;
284
285 if (eb_lunactive) return 0;
286
287 k = getLocalVisibility(mjdmax, magmax);
288
289 if (k != 0)
290 {
291 mjdmax = eb_jdmaxps;
292 magmax = eb_maxps;
293 elmax = eb_maxelv;
294 }
295
296 return k;
297 }
298
getPenumbra(double & mjd_start,double & mjd_stop)299 int EclSolar::getPenumbra(double &mjd_start, double &mjd_stop)
300 {
301 // start and stop times (MJD) for penumbral eclipse of Moon
302 // RETURN 0 if no lunar eclipse
303
304 int j, k;
305
306 if (!eb_start_called) eclStart();
307
308 mjd_start = 0;
309 mjd_stop = 0;
310
311 if (!eb_lunactive) return 0;
312
313 if (eb_nphase <= 0) return 0;
314
315 k = 0 ;
316 for (j=0; j<eb_nphase; j++)
317 {
318 if (eb_spp[j] == 1)
319 {
320 mjd_start = eb_spt[j];
321 mjd_stop =eb_ept[j];
322 k = 1;
323 }
324 }
325
326 return k;
327 }
328
getPartial(double & mjd_start,double & mjd_stop)329 int EclSolar::getPartial(double &mjd_start, double &mjd_stop)
330 {
331 // (global) start and stop times (MJD) for partial phase
332 // RETURN 0 if no lunar eclipse
333
334 int j, k;
335
336 if (!eb_start_called) eclStart();
337
338 mjd_start = 0;
339 mjd_stop = 0;
340
341 if (eb_nphase <= 0) return 0;
342
343 k = 0;
344
345 if(eb_lunactive)
346 {
347 for (j=0; j<eb_nphase; j++)
348 {
349 if ((k==0) && (eb_spp[j] == 3))
350 {
351 mjd_start = eb_spt[j];
352 mjd_stop =eb_ept[j];
353 k = 1;
354 }
355 }
356 }
357 else
358 {
359 for (j=0; j<eb_nphase; j++)
360 {
361 if ((k==0) && (eb_spp[j] == 1))
362 {
363 mjd_start = eb_spt[j];
364 mjd_stop =eb_ept[j];
365 k = 1;
366 }
367 }
368 }
369
370 return k;
371
372 }
373
getTotal(double & mjd_start,double & mjd_stop)374 int EclSolar::getTotal(double &mjd_start, double &mjd_stop)
375 {
376 // (global) start and stop times (MJD) for totality/annularity
377 // RETURN 0 if no lunar eclipse
378
379 int j, k;
380
381 if (!eb_start_called) eclStart();
382
383 mjd_start = 0;
384 mjd_stop = 0;
385
386 if (eb_nphase <= 0) return 0;
387
388 k = 0;
389
390 if(eb_lunactive)
391 {
392 for (j=0; j<eb_nphase; j++)
393 {
394 if ((k==0) && (eb_spp[j] > 3))
395 {
396 mjd_start = eb_spt[j];
397 mjd_stop =eb_ept[j];
398 k = 1;
399 }
400 }
401 }
402 else
403 {
404 for (j=0; j<eb_nphase; j++)
405 {
406 if ((k==0) && (eb_spp[j] > 1))
407 {
408 mjd_start = eb_spt[j];
409 mjd_stop =eb_ept[j];
410 k = 1;
411 }
412 }
413 }
414
415 return k;
416
417 }
418
setCurrentMJD(int year,int month,int day,int hour,int min,double sec)419 void EclSolar::setCurrentMJD(int year, int month, int day, int hour, int min, double sec)
420 {
421 // set the (MJD-) time currently used for calculations to year, month, day, hour, min, sec
422 // corrected for timezone
423
424 double jd;
425
426 jd = ddd(hour, min, sec) - eb_tzone;
427 jd = mjd(day, month, year, jd);
428
429 eb_lastjd = jd;
430
431 }
432
getDatefromMJD(double mjd,int & year,int & month,int & day,int & hour,int & min,double & sec) const433 void EclSolar::getDatefromMJD(double mjd, int &year, int &month, int &day, int &hour, int &min, double &sec) const
434 {
435 // convert times given in Modified Julian Date (MJD) into conventional date and time
436 // correct for timezone
437
438 double magn;
439
440 caldat((mjd + eb_tzone/24.0), day, month, year, magn);
441 dms (magn,hour,min,sec);
442 if (sec>30.0) min++;
443 if (min>59)
444 {
445 hour++;
446 min=0;
447 };
448
449 }
450
451 //---------------------- getEclYearInfo--------------------------------
452
getEclYearInfo(char * wbuf)453 void EclSolar::getEclYearInfo(char* wbuf)
454 {
455 // output the eclipse dates in buffer wbuf accurate to the minute.
456
457 char dts[13];
458 char outbuf[127];
459 char magbuf[30];
460 int j, p, kecl;
461
462 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
463
464 sprintf(wbuf,"Solar Eclipses for %4i UTC +%4.1f", eb_year, eb_tzone);
465
466 kecl = 1;
467 for (j=0; j<eb_numecl; j++)
468 {
469 sprintf(dts,"%1i : ", kecl);
470 strcpy (outbuf,dts);
471 dtmstr((eb_eclmjd[j] + eb_tzone/24.0),dts);
472 dts[12] = '\0';
473 strcat (outbuf,dts);
474 p = eb_phase[j];
475
476 switch (p)
477 {
478 case 1: strcat(outbuf,"\t Partial Sun");
479 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
480 strcat(outbuf,magbuf);
481 break;
482
483 case 2: strcat(outbuf,"\t non-central Annular Sun");
484 break;
485 case 4: strcat(outbuf,"\t Annular Sun");
486 break;
487
488 case 3: strcat(outbuf, "\t non-central Total Sun");
489 break;
490 case 5: strcat(outbuf, "\t Total Sun");
491 break;
492
493 case 6: strcat(outbuf, "\t Annular/Total Sun");
494 break;
495
496 case -1:
497 case -2: strcat(outbuf, "\t Penumbral Moon");
498 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
499 strcat(outbuf,magbuf);
500 break;
501
502 case -3: strcat(outbuf, "\t Partial Moon");
503 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
504 strcat(outbuf,magbuf);
505 break;
506
507 case -4: strcat(outbuf, "\t Total Moon");
508 sprintf(magbuf," (magnitude:%5.2f)",eb_magnitude[j]);
509 strcat(outbuf,magbuf);
510 break;
511 };
512
513 if ((p > 0) || eb_lunecl) // solar eclipse only or also lunar eclipses
514 {
515 strcat (wbuf, "\n");
516 strcat (wbuf, outbuf);
517 kecl++;
518 };
519 }
520 }
521
getEclYearInfo(int k,int & yr,int & month,int & day,int & hour,int & min,double & sec,double & tzone,double & magn)522 int EclSolar::getEclYearInfo(int k, int &yr, int &month, int &day,
523 int &hour, int &min, double &sec, double &tzone, double &magn)
524 {
525 /* output the eclipse info for k-th eclipse
526
527 year, month, day, hour, minutes, seconds and timezone
528 magn = magnitude of eclipse
529
530 RETURN: phase of eclipse. 0 if no k-th eclipse
531
532 1: Partial Sun
533 2: non-central Annular Sun
534 3: non-central Total Sun
535 4: Annular Sun
536 5: Total Sun
537 6: Annular/Total Sun
538
539 -1, -2: Penumbral Moon
540 -3: Partial Moon
541 -4: Total Moon
542
543 */
544 bool nls;
545 int j, p, kecl;
546
547 nls = true;
548
549 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
550
551 if (k < 1)
552 {
553 k = eb_eclselect; // select current eclipse as default
554 nls = false;
555 };
556 if ((k < 1) && (k > eb_numecl)) return 0;
557
558 p = k - 1;
559 if (nls && (!eb_lunecl))
560 {
561 kecl = 0;
562 p = -1;
563 for(j=0; j<eb_numecl; j++)
564 {
565 if (eb_phase[j] > 0)
566 {
567 kecl++;
568 if (kecl == k) p = j;
569 };
570 };
571 };
572
573 if (p < 0) return 0;
574
575 j = p;
576
577 // convert MJD into corresponding date and time
578 caldat((eb_eclmjd[j] + eb_tzone/24.0), day, month, yr, magn);
579 dms (magn,hour,min,sec);
580 if (sec>30.0) min++;
581 if (min>59)
582 {
583 hour++;
584 min=0;
585 };
586
587 magn = eb_magnitude[j];
588 tzone = eb_tzone;
589
590 return eb_phase[j];
591 }
592
getEclTxt(int k,char * jtxt)593 int EclSolar::getEclTxt (int k, char* jtxt)
594 {
595 // get the data / kind of eclipse info for the j-th eclipse
596 // and place it into jtxt
597
598 // RETURN : the phase of the eclipse. 0 if no j-th eclipse
599
600 int p, j;
601 char dts[13];
602
603 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
604
605 if (k < 1) k = eb_eclselect; // select current eclipse as default
606 if ((k < 1) && (k > eb_numecl)) return 0;
607
608 j = k-1;
609
610 sprintf(jtxt, "%2i :", (j+1));
611 sprintf(dts, "%5i ", eb_year);
612 strcat (jtxt, dts);
613 dtmstr((eb_eclmjd[j]+eb_tzone/24.0),dts);
614 dts[6] = '\0';
615 strcat (jtxt,dts);
616
617 p = eb_phase[j];
618 switch (p)
619 {
620 case 1: strcat(jtxt," Par.Sun");
621 break;
622 case 2: strcat(jtxt, " non-centr.Ann.Sun");
623 break;
624 case 4: strcat(jtxt," Ann.Sun");
625 break;
626 case 3: strcat(jtxt," non-centr.Tot.Sun");
627 break;
628 case 5: strcat(jtxt," Tot.Sun");
629 break;
630 case 6: strcat(jtxt," Ann/Tot.");
631 break;
632
633 case -1:
634 case -2: strcat(jtxt," Pen.Moon");
635 break;
636 case -3: strcat(jtxt," Par.Moon");
637 break;
638 case -4: strcat(jtxt," Tot.Moon");
639 break;
640 };
641
642 return p;
643 }
644
645 // ----------------------------- Select Eclipse -------------------------
646
putEclSelect(int es)647 void EclSolar::putEclSelect(int es)
648 {
649 // store the number of the eclipse selected for detailed calculations
650 int k, j;
651
652 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
653
654 k = 0;
655
656 eb_lunactive = false;
657 eb_eclselect = 1;
658 for (j=0; j<eb_numecl; j++)
659 {
660 if ((eb_phase[j] > 0) || eb_lunecl) // only solar eclipses if set
661 {
662 k++;
663 if (k == es)
664 {
665 eb_eclselect = j + 1;
666 if (eb_phase[j] < 0) eb_lunactive = true;
667 };
668 };
669 };
670 eb_start_called = false;
671 }
672
nextEcl()673 void EclSolar::nextEcl()
674 {
675 // select the next eclipse for detailed calculations
676 int k, j, es;
677
678 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
679 eb_start_called = false;
680
681 k = eb_eclselect + 1;
682 if (k > eb_numecl)
683 {
684 k = eb_year + 1;
685 putYear (k);
686 k = 1;
687 putEclSelect(k);
688
689 return;
690 };
691
692 if (eb_lunecl) // easier when lunar eclipses are included
693 {
694 putEclSelect(k);
695
696 return;
697 };
698
699 eb_lunactive = false;
700
701 es = eb_eclselect;
702 k = 0;
703 for (j=es; j<eb_numecl; j++)
704 {
705 if ((k == 0) && (eb_phase[j] > 0)) k = j + 1;
706 };
707
708 if(k > 0)
709 {
710 eb_eclselect = k;
711 return;
712 }
713
714 k = eb_year + 1;
715 putYear (k);
716 es = 1;
717 putEclSelect(es);
718
719 }
720
previousEcl()721 void EclSolar::previousEcl()
722 {
723 // select the previous eclipse for detailed calculations
724 int k, j, es;
725
726 if (!eb_moonph_called) moonph(); // calculate the eclipses of the year
727 eb_start_called = false;
728
729 k = eb_eclselect - 1;
730
731 if (k <= 0)
732 {
733 k = eb_year - 1;
734 putYear (k);
735 k = eb_numecl;
736 };
737
738 if (eb_lunecl) // easier when lunar eclipses are included
739 {
740 putEclSelect(k);
741
742 return;
743 };
744
745 eb_lunactive = false;
746
747 es = 0;
748 k--;
749 for (j=k; j>=0; j--)
750 {
751 if ((es == 0) && (eb_phase[j] > 0)) es = j + 1;
752 };
753
754 if(es > 0) eb_eclselect = es;
755 else putEclSelect(0); // this case should never happen!
756
757 }
758
getLastMJD() const759 double EclSolar::getLastMJD() const
760 {
761 // RETURN the MJD last used in calculations
762
763 return eb_lastjd;
764 }
765
setPenumbraAngle(double pa,int mode)766 void EclSolar::setPenumbraAngle(double pa, int mode)
767 {
768 /* set the Penumbra Angle
769 if mode == 0 the angle will be set to pa-times the maximum angle
770 (pa < 1.0). Set pa = 1 for the normal penumbra boundaries
771
772 if mode == 1 the angle will be set such that the penumbra line
773 markes magnitude pa. pa == 0 will mark normal penumbra boundaries
774
775 if mode == 2 the angle will be set such that the penumbra line
776 markes the obscuration pa. pa == 0.5 will mean that 50% of the Sun's
777 disk is covered by the Moon etc.
778 */
779
780 double mjd, dpn1, dpn2, pan1, pan2;
781 double mag, m1, m2, s, ps;
782 int j;
783 Vec3 ubm, ube;
784 Eclipse eclp;
785
786 if (mode == 0)
787 {
788 eb_penangle = pa;
789 eb_penamode = 0;
790 if (pa > 1.0) eb_penangle = 1.0;
791 if (pa < 0) eb_penangle = 1.0;
792
793 return;
794 }
795
796 if (!eb_start_called) eclStart();
797
798 if (mode == 1)
799 {
800 eb_penamode = 1;
801 mjd = eb_eclmjd[eb_eclselect-1];
802 eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1);
803 eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn2, pan2);
804
805 if(dpn2 > 0)
806 {
807 eb_penangle = fabs(pa);
808 if(eb_penangle > 1.0) eb_penangle = 1.0;
809 eb_penangle = 1.0 - eb_penangle * (1.0 + dpn1 / dpn2);
810 }
811 else eb_penangle = 1.0;
812
813 return;
814 }
815
816 if (mode == 2)
817 {
818 eb_penamode = 2;
819 mjd = eb_eclmjd[eb_eclselect-1];
820 eclp.umbra (mjd, eb_del_tdut, ubm, ube, dpn1, pan1);
821 eclp.penumd (mjd, eb_del_tdut, ubm, ube, dpn2, pan2);
822
823 ps = pa; // find the magnitude that corresponds to the obscuration
824 if (ps > 1.0) ps = 1.0;
825 if (ps < 0) ps = 0;
826 for (j=1; j<11; j++)
827 {
828 mag = double(j) * 0.1;
829 s = sunObscure(dpn2, dpn1, mag);
830 if (s >= ps) break;
831 }
832
833 m1 = mag - 0.1;
834 m2 = mag;
835 for (j=0; j<8; j++) // 8 iterations should be plenty
836 {
837 mag = (m2 + m1) * 0.5;
838 s = sunObscure(dpn2, dpn1, mag);
839 if (s > ps) m2 = mag;
840 else m1 = mag;
841 }
842
843 if(dpn2 > 0)
844 {
845 eb_penangle = fabs(mag);
846 if(eb_penangle > 1.0) eb_penangle = 1.0;
847 eb_penangle = 1.0 - eb_penangle * (1.0 + dpn1 / dpn2);
848 }
849 else eb_penangle = 1.0;
850
851 return;
852 }
853
854 eb_penamode = 0;
855 eb_penangle = 1.0;
856
857 }
858
859 // -------- auxiliary functions --------------------------------
GetMonth(int mm,char * mchr)860 void EclSolar::GetMonth (int mm, char* mchr)
861 {
862 // get three letter designation of month
863 // mm is the number of the month
864 // mchr is a char[4] array to receive the three letters of the month
865
866 switch (mm)
867 {
868 case 1 : strcpy(mchr,"JAN"); break;
869 case 2 : strcpy(mchr,"FEB"); break;
870 case 3 : strcpy(mchr,"MAR"); break;
871 case 4 : strcpy(mchr,"APR"); break;
872 case 5 : strcpy(mchr,"MAY"); break;
873 case 6 : strcpy(mchr,"JUN"); break;
874 case 7 : strcpy(mchr,"JUL"); break;
875 case 8 : strcpy(mchr,"AUG"); break;
876 case 9 : strcpy(mchr,"SEP"); break;
877 case 10 : strcpy(mchr,"OCT"); break;
878 case 11 : strcpy(mchr,"NOV"); break;
879 case 12 : strcpy(mchr,"DEC"); break;
880 default: strcpy(mchr,"ERR");
881 };
882 }
883
phmjd(double yearf,double phase,double tdut,int & eph,double & ejd,double & emag)884 double EclSolar::phmjd (double yearf, double phase, double tdut,
885 int& eph, double& ejd, double& emag)
886 /*
887 Calculate the Modified Julian Date of the occurrence of the specified
888 phase of the Moon and check for possible eclipses.
889 yearf : year.fraction of date close to the Moon phase
890 phase : 0 for New Moon,
891 0.25 for First Quarter,
892 0.5 for Full Moon,
893 0.75 for Last Quarter.
894 tdut = TDT - UT in sec
895
896 RETURN: the MJD of the lunar phase event
897
898 OUTPUT:
899 eph : phase of the eclipse on that date
900 0 = no eclipse, 1 = partial solar eclipse,
901 2 = non-central annular, 3 = non-central total
902 4 = annular solar, 5 = total solar,
903 6 = annular/total solar, -1 =partial penumbral lunar,
904 -2 = total penumbral lunar, -3 = partial umbral lunar,
905 -4 = total umbral lunar
906 ejd : Modified Julian Date of the maximum of the eclipse (if any)
907 emag : magnitude of the eclipse (if any)
908 */
909 {
910 double tt, jd, k, m, p, f;
911 double s, c, gam, u;
912 int tst;
913 Eclipse eclp;
914
915 // preliminary (modified) Julian Date
916 k = floor ((yearf - 1900.0) * 12.3685) + phase;
917 tt = k / 1236.85;
918 jd = 166.56 + (132.87 - 0.009173*tt)*tt;
919 jd = 15020.25933 + 29.53058868*k
920 + (0.0001178 - 0.000000155*tt)*tt*tt
921 + 0.00033 * sin (degrad*jd);
922
923 eph = 0; // assume no eclipse
924
925 // Sun's mean anomaly
926 m = degrad * (359.2242 + 29.10535608*k
927 - (0.0000333 - 0.00000347*tt)*tt*tt);
928 // Moon's mean anomaly
929 p = degrad * (306.0253 + 385.81691808*k
930 + (0.0107306 + 0.00001236*tt)*tt*tt);
931 // 2* Moon's argument of latitude
932 f = 2.0 * degrad * (21.2964 + 390.67050646*k
933 - (0.0016528 - 0.00000239*tt)*tt*tt);
934
935 if ((phase == 0) || (phase == 0.5)) // for Full and New Moon
936 {
937 k = (0.1734 - 0.000393*tt) * sin (m)
938 + 0.0021 * sin (2.0 * m)
939 - 0.4068 * sin (p)
940 + 0.0161 * sin (2.0 * p)
941 - 0.0004 * sin (3.0 * p)
942 + 0.0104 * sin (f)
943 - 0.0051 * sin (m + p)
944 - 0.0074 * sin (m - p)
945 + 0.0004 * sin (f + m)
946 - 0.0004 * sin (f - m)
947 - 0.0006 * sin (f + p)
948 + 0.0010 * sin (f - p)
949 + 0.0005 * sin (m + 2.0*p);
950
951 // check for possible eclipses.
952 f = f / 2.0;
953 if (fabs(sin(f)) <= 0.36) // eclipses are possible
954 {
955 ejd = (0.1734 - 0.000393*tt) * sin(m)
956 + 0.0021 * sin(2.0*m)
957 - 0.4068 * sin(p)
958 + 0.0161 * sin(2.0*p)
959 - 0.0051 * sin(m+p)
960 - 0.0074 * sin(m-p)
961 - 0.0104 * sin(2.0*f);
962 ejd += jd;
963
964 s = 5.19595 - 0.0048*cos(m) + 0.0020*cos(2.0*m) - 0.3283*cos(p)
965 - 0.0060*cos(m+p) + 0.0041*cos(m-p);
966
967 c = 0.2070*sin(m) + 0.0024*sin(2.0*m) - 0.0390*sin(p)
968 + 0.0115*sin(2.0*p) - 0.0073*sin(m+p)
969 - 0.0067*sin(m-p) + 0.0117*sin(2.0*f);
970
971 gam = s*sin(f) + c*cos(f);
972 u = 0.0059 + 0.0046*cos(m) - 0.0182*cos(p)
973 + 0.0004*cos(2.0*p) - 0.0005*cos(m+p);
974
975 if (phase == 0) // check for solar eclipse
976 {
977 if (fabs(gam) <= (1.5432+u))
978 {
979 if (fabs(gam) < 0.9972) // central eclipse
980 {
981 emag = 1.0;
982 if (u < 0) eph = 5; // total eclipse
983 else
984 {
985 if (u > 0.0047) eph = 4; // annular eclipse
986 else
987 {
988 if (u < (0.00464*cos(asin(gam)))) eph = 6; // annular/total
989 else eph = 4; // annular
990 }; // end if u>0.0047
991 }; // end if u<0
992 } // end if fabs(gam) if
993 else // non-central eclipse
994 {
995 eph = 1; // assume partial eclipse
996 if (fabs(gam) < (0.9972+fabs(u))) // non-central annular or total
997 {
998 eph = eclp.solar(ejd,tdut,s,c);
999 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
ckphase(double minmjd,double maxmjd,double yr,double deltdut,int & mp,PMJD p,double phase)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
dtmstr(double jdmoon,char * dts)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
moonph()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
getlocmag(double jd,double ep2,double phi,double lamda,double height,const Vec3 & rs,const Vec3 & rm,int & totflg)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
eclStart()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
calcMaxPos(double & lat,double & lng)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
getMaxPos(double & lat,double & lng)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
sunObscure(double l1,double l2,double mag)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
eclPltCentral(bool firstc,double & lat,double & lng)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
InitBound()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
GNSBound(bool firstc,bool north,double & lat,double & lng)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
InRSBound()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
iscrs(double vrc0,double vrc1,double dpn,double & vrx0,double & vrx1,double & vrx20,double & vrx21)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
GRSBound(bool firstc,double & lat1,double & lng1,double & lat2,double & lng2)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
DegFDms(double h)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
localStart(int j,double * spt,double * ept,int * spp,int p,char * otxt)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
getLocalDetails(char * otxt)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
navCourse(double lat1,double lng1,double lat2,double lng2)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
navNewPos(double d,double an,double lat1,double lng1,double & lat2,double & lng2)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
centralBound(bool firstc,double & lat1,double & lng1,double & lat2,double & lng2)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
getShadowCone(double mjd,bool umbra,int numpts,double * lat,double * lng)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
2943