1 /************************************************************************
2  *  Copyright (c) 2003-2006, 2009, Arabeyes, Thamer Mahmoud
3  *
4  *  A full featured Muslim Prayer Times calculator
5  *
6  * (www.arabeyes.org - under LGPL license - see COPYING file)
7  ************************************************************************/
8 
9 
10 #include "prayer.h"
11 #include "astro.h"
12 
13 /* Defaults */
14 #define KAABA_LAT 21.423333
15 #define KAABA_LONG 39.823333
16 #define DEF_NEAREST_LATITUDE 48.5
17 #define DEF_EXTREME_LATITUDE 55.0
18 #define DEF_IMSAAK_ANGLE 1.5
19 #define DEF_IMSAAK_INTERVAL 10
20 #define DEF_ROUND_SEC 30
21 #define AGGRESSIVE_ROUND_SEC 1
22 
23 
24 
25 enum exmethods  { NONE_EX,
26                   LAT_ALL,
27                   LAT_ALWAYS,
28                   LAT_INVALID,
29                   GOOD_ALL,
30                   GOOD_INVALID,
31                   SEVEN_NIGHT_ALWAYS,
32                   SEVEN_NIGHT_INVALID,
33                   SEVEN_DAY_ALWAYS,
34                   SEVEN_DAY_INVALID,
35                   HALF_ALWAYS,
36                   HALF_INVALID,
37                   MIN_ALWAYS,
38                   MIN_INVALID,
39                   GOOD_INVALID_SAME,
40                   ANGLE_BASED };
41 
42 enum methods    { NONE,
43                   EGYPT_SURVEY,
44                   KARACHI_SHAF,
45                   KARACHI_HANAF,
46                   NORTH_AMERICA,
47                   MUSLIM_LEAGUE,
48                   UMM_ALQURRA,
49                   FIXED_ISHAA,
50                   EGYPT_NEW,
51                   UMM_ALQURRA_RAMADAN,
52                   MOONSIGHTING_COMMITTEE,
53                   MOROCCO_AWQAF };
54 
55 enum salatType  { FAJR,
56                   SHUROOQ,
57                   ZUHR,
58                   ASSR,
59                   MAGHRIB,
60                   ISHAA,
61                   IMSAAK,
62                   NEXTFAJR };
63 
64 static double getZuhr (double lon, const Astro* astro);
65 static double getFajIsh (double Lat, double dec, double Ang);
66 static double getAssr (double Lat, double dec, int mathhab);
67 static double getSeasonalFajr(double lat, int day, double fajr, double sunrise);
68 static double getSeasonalIsha(double lat, int day, double isha, double sunset);
69 static void base6hm(double bs, const Location* loc, const Method* conf,
70                     Prayer* pt, int type);
71 static int getSeasonDay(int dayOfYear, double lat);
72 static void getDayInfo( const Date* date, double gmt, int *lastDay, int *dayOfYear, double *julianDay);
73 static void getPrayerTimesByDay ( const Location* loc, const Method* conf, int lastDay,
74                                   int dayOfYear, double julianDay, Prayer* pt, int type);
75 
76 /* Astro astroCache;  This global variable is used for caching values between
77                    * multiple getPrayerTimesByDay() calls. You can disable this
78                    * caching feature by moving this line to the start of the
79                    * getPrayerTimesByDay() function. */
80 
getPrayerTimes(const Location * loc,const Method * conf,const Date * date,Prayer * pt)81 void getPrayerTimes ( const Location* loc, const Method* conf, const Date* date,
82                       Prayer* pt)
83 {
84     int lastDay;
85     int dayOfYear;
86     double julianDay;
87     getDayInfo ( date, loc->gmtDiff, &lastDay, &dayOfYear, &julianDay);
88     getPrayerTimesByDay( loc, conf, lastDay, dayOfYear, julianDay, pt, 0);
89 }
90 
getPrayerTimesByDay(const Location * loc,const Method * conf,int lastDay,int dayOfYear,double julianDay,Prayer * pt,int type)91 static void getPrayerTimesByDay ( const Location* loc, const Method* conf,
92                                   int lastDay, int dayOfYear, double julianDay,
93                                   Prayer* pt, int type)
94 {
95 
96     int i, invalid;
97     double zu, sh, mg, fj, is, ar;
98     double lat, lon, dec;
99     double tempPrayer[6];
100     /* made as a local variable to avoid race condition between threads */
101     Astro astroCache;
102     Astro tAstro;
103 
104     lat = loc->degreeLat;
105     lon = loc->degreeLong;
106     invalid = 0;
107 
108     /* Start by filling the tAstro structure with the appropriate astronomical
109      * values for this day. We also pass the cache structure to update and check
110      * if the actual values are already available. */
111     getAstroValuesByDay(julianDay, loc, &astroCache, &tAstro);
112     dec = DEG_TO_RAD(tAstro.dec[1]);
113 
114     /* Get Prayer Times formulae results for this day of year and this
115      * location. The results are NOT the actual prayer times */
116     fj   = getFajIsh (lat, dec, conf->fajrAng);
117     sh   = getSunrise(loc, &tAstro);
118     zu   = getZuhr (lon, &tAstro);
119     ar   = getAssr (lat, dec, conf->mathhab);
120     mg   = getSunset(loc, &tAstro);
121     is   = getFajIsh (lat, dec, conf->ishaaAng);
122 
123     /* Calculate all prayer times as Base-10 numbers in Normal circumstances */
124     /* Fajr */
125     if (fj == 99) {
126         tempPrayer[0] = 99;
127         if (conf->method != MOONSIGHTING_COMMITTEE) {
128             invalid = 1;
129         }
130     }
131     else tempPrayer[0] = zu - fj;
132 
133     if (sh == 99)
134         invalid = 1;
135     tempPrayer[1] = sh;
136 
137     tempPrayer[2] = zu;
138 
139     /* Assr */
140     if (ar == 99) {
141         tempPrayer[3] = 99;
142         invalid = 1;
143     }
144     else tempPrayer[3] = zu + ar;
145 
146 
147     if (mg == 99)
148         invalid = 1;
149     tempPrayer[4] = mg;
150 
151 
152     /* Ishaa */
153     if (is == 99) {
154         tempPrayer[5] = 99;
155         if (conf->method != MOONSIGHTING_COMMITTEE) {
156             invalid = 1;
157         }
158     }
159     else tempPrayer[5] = zu + is;
160 
161 
162     if (conf->method == MOONSIGHTING_COMMITTEE) {
163         tempPrayer[0] = getSeasonalFajr(lat, dayOfYear, tempPrayer[0], tempPrayer[1]);
164         tempPrayer[5] = getSeasonalIsha(lat, dayOfYear, tempPrayer[5], tempPrayer[4]);
165 
166         if (tempPrayer[0] == 99 || tempPrayer[5] == 99) {
167             invalid = 1;
168         }
169 
170         if (tempPrayer[2] != 99) {
171             tempPrayer[2] += (5.0 / 60.0);
172         }
173 
174         if (tempPrayer[4] != 99) {
175             tempPrayer[4] += (3.0 / 60.0);
176         }
177     }
178 
179     /* Re-calculate Fajr and Ishaa in Extreme Latitudes */
180     if (lat > conf->extremeLat) {
181         tempPrayer[0] = 99;
182         tempPrayer[5] = 99;
183         invalid = 1;
184     }
185 
186     /* Reset status of extreme switches */
187     for (i=0; i<6; i++)
188         pt[i].isExtreme = 0;
189 
190     if ((conf->extreme != NONE_EX) && ((invalid == 1) ||
191                                          (conf->extreme == LAT_ALL ||
192                                           conf->extreme == LAT_ALWAYS ||
193                                           conf->extreme == GOOD_ALL ||
194                                           conf->extreme == SEVEN_NIGHT_ALWAYS ||
195                                           conf->extreme == SEVEN_DAY_ALWAYS ||
196                                           conf->extreme == HALF_ALWAYS ||
197                                           conf->extreme == MIN_ALWAYS)
198                                        ))
199     {
200         double exdecPrev, exdecNext;
201         double exZu=99, exFj=99, exIs=99, exAr=99, exSh=99, exMg=99;
202         double portion = 0;
203         double nGoodDay = 0;
204         int exinterval = 0;
205         Location exLoc = *loc;
206         Astro exAstroPrev;
207         Astro exAstroNext;
208         double fajrDiff, ishaDiff;
209 
210         switch(conf->extreme)
211         {
212         /* Angle Based */
213         case ANGLE_BASED:
214                 portion = ((24 - tempPrayer[4]) + tempPrayer[1]);
215                 fajrDiff = (1/60.0 * conf->fajrAng) * portion;
216                 ishaDiff = (1/60.0 * conf->ishaaAng) * portion;
217 
218                 tempPrayer[0] = tempPrayer[1] - fajrDiff;
219                 tempPrayer[5] = tempPrayer[4] + ishaDiff;
220                 pt[0].isExtreme = 1;
221                 pt[5].isExtreme = 1;
222                 break;
223 
224         /* Nearest Latitude (Method.nearestLat) */
225         case LAT_ALL:
226         case LAT_ALWAYS:
227         case LAT_INVALID:
228 
229             /* FIXIT: we cannot compute this when interval is set because
230              * angle==0 . Only the if-invalid methods would work */
231             exLoc.degreeLat = conf->nearestLat;
232             exFj = getFajIsh(conf->nearestLat, dec, conf->fajrAng);
233             /*exIm = getFajIsh(conf->nearestLat, dec, conf->imsaakAng);*/
234             exSh = getSunrise(&exLoc, &tAstro);
235             exAr = getAssr(conf->nearestLat, dec, conf->mathhab);
236             exMg = getSunset(&exLoc, &tAstro);
237             exIs = getFajIsh(conf->nearestLat, dec, conf->ishaaAng);
238 
239 
240             switch(conf->extreme)
241             {
242             case LAT_ALL:
243                 tempPrayer[0] = zu - exFj;
244                 tempPrayer[1] = exSh;
245                 tempPrayer[3] = zu + exAr;
246                 tempPrayer[4] = exMg;
247                 tempPrayer[5] = zu + exIs;
248                 pt[0].isExtreme = 1;
249                 pt[1].isExtreme = 1;
250                 pt[2].isExtreme = 1;
251                 pt[3].isExtreme = 1;
252                 pt[4].isExtreme = 1;
253                 pt[5].isExtreme = 1;
254                 break;
255 
256             case LAT_ALWAYS:
257                 tempPrayer[0] = zu - exFj;
258                 tempPrayer[5] = zu + exIs;
259                 pt[0].isExtreme = 1;
260                 pt[5].isExtreme = 1;
261                 break;
262 
263             case LAT_INVALID:
264                 if (tempPrayer[0] == 99) {
265                     tempPrayer[0] = zu - exFj;
266                     pt[0].isExtreme = 1;
267                 }
268                 if (tempPrayer[5] == 99) {
269                     tempPrayer[5] = zu + exIs;
270                     pt[5].isExtreme = 1;
271                 }
272                 break;
273             }
274             break;
275 
276 
277         /* Nearest Good Day */
278         case GOOD_ALL:
279         case GOOD_INVALID:
280         case GOOD_INVALID_SAME:
281 
282             exAstroPrev = astroCache;
283             exAstroNext = astroCache;
284 
285             /* Start by getting last or next nearest Good Day */
286             for(i=0; i <= lastDay; i++)
287             {
288 
289                 /* Last closest day */
290                 nGoodDay = julianDay - i;
291                 getAstroValuesByDay(nGoodDay, loc, &exAstroPrev, &tAstro);
292                 exdecPrev = DEG_TO_RAD(tAstro.dec[1]);
293                 exFj = getFajIsh(lat, exdecPrev, conf->fajrAng);
294                 if (exFj != 99)
295                 {
296                     exIs = getFajIsh(lat, exdecPrev, conf->ishaaAng);
297                     if (exIs != 99)
298                     {
299                         exZu = getZuhr (lon, &tAstro);
300                         exSh = getSunrise (loc, &tAstro);
301                         exAr = getAssr (lat, exdecPrev, conf->mathhab);
302                         exMg = getSunset (loc, &tAstro);
303                         break;
304                     }
305                 }
306 
307                 /* Next closest day */
308                 nGoodDay = julianDay + i;
309                 getAstroValuesByDay(nGoodDay, loc, &exAstroNext, &tAstro);
310                 exdecNext = DEG_TO_RAD(tAstro.dec[1]);
311                 exFj = getFajIsh(lat, exdecNext, conf->fajrAng);
312                 if (exFj != 99)
313                 {
314                     exIs = getFajIsh(lat, exdecNext, conf->ishaaAng);
315                     if (exIs != 99)
316                     {
317                         exZu = getZuhr (lon, &tAstro);
318                         exSh = getSunrise (loc, &tAstro);
319                         exAr = getAssr (lat, exdecNext, conf->mathhab);
320                         exMg = getSunset (loc, &tAstro);
321                         break;
322                     }
323                 }
324             }
325 
326             switch(conf->extreme)
327             {
328             case GOOD_ALL:
329                 tempPrayer[0] = exZu - exFj;
330                 tempPrayer[1] = exSh;
331                 tempPrayer[2] = exZu;
332                 tempPrayer[3] = exZu + exAr;
333                 tempPrayer[4] = exMg;
334                 tempPrayer[5] = exZu + exIs;
335                 for (i=0; i<6; i++)
336                     pt[i].isExtreme = 1;
337                 break;
338             case GOOD_INVALID:
339                 if (tempPrayer[0] == 99) {
340                     tempPrayer[0] = exZu - exFj;
341                     pt[0].isExtreme = 1;
342                 }
343                 if (tempPrayer[5] == 99) {
344                     tempPrayer[5] = exZu + exIs;
345                     pt[5].isExtreme = 1;
346                 }
347                 break;
348             case GOOD_INVALID_SAME:
349                 if ((tempPrayer[0] == 99) || (tempPrayer[5] == 99))
350                 {
351                     tempPrayer[0] = exZu - exFj;
352                     pt[0].isExtreme = 1;
353                     tempPrayer[5] = exZu + exIs;
354                     pt[5].isExtreme = 1;
355                 }
356                 break;
357             }
358             break;
359 
360         case SEVEN_NIGHT_ALWAYS:
361         case SEVEN_NIGHT_INVALID:
362         case SEVEN_DAY_ALWAYS:
363         case SEVEN_DAY_INVALID:
364         case HALF_ALWAYS:
365         case HALF_INVALID:
366 
367             /* FIXIT: For clarity, we may need to move the HALF_* methods
368              * into their own separate case statement. */
369             switch(conf->extreme)
370             {
371             case SEVEN_NIGHT_ALWAYS:
372             case SEVEN_NIGHT_INVALID:
373                 portion = (24 - (tempPrayer[4] - tempPrayer[1])) * (1/7.0);
374                 break;
375             case SEVEN_DAY_ALWAYS:
376             case SEVEN_DAY_INVALID:
377                 portion = (tempPrayer[4] - tempPrayer[1]) * (1/7.0);
378                 break;
379             case HALF_ALWAYS:
380             case HALF_INVALID:
381                 portion = (24 - tempPrayer[4] - tempPrayer[1]) * (1/2.0);
382                 break;
383             }
384 
385 
386             if (conf->extreme == SEVEN_NIGHT_INVALID ||
387                 conf->extreme == SEVEN_DAY_INVALID ||
388                 conf->extreme == HALF_INVALID)
389             {
390                 if (tempPrayer[0] == 99) {
391                     if  (conf->extreme == HALF_INVALID)
392                         tempPrayer[0] =  portion - (conf->fajrInv / 60.0);
393                     else tempPrayer[0] = tempPrayer[1] - portion;
394                     pt[0].isExtreme = 1;
395                 }
396                 if (tempPrayer[5] == 99) {
397                     if  (conf->extreme == HALF_INVALID)
398                         tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ;
399                     else tempPrayer[5] = tempPrayer[4] + portion;
400                     pt[5].isExtreme = 1;
401                 }
402             } else { /* for the always methods */
403 
404                 if  (conf->extreme == HALF_ALWAYS) {
405                     tempPrayer[0] = portion - (conf->fajrInv / 60.0);
406                     tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ;
407                 }
408 
409                 else {
410                     tempPrayer[0] = tempPrayer[1] - portion;
411                     tempPrayer[5] = tempPrayer[4] + portion;
412                 }
413                 pt[0].isExtreme = 1;
414                 pt[5].isExtreme = 1;
415             }
416             break;
417 
418         case MIN_ALWAYS:
419             /* Do nothing here because this is implemented through fajrInv and
420              * ishaaInv structure members */
421             tempPrayer[0] = tempPrayer[1];
422             tempPrayer[5] = tempPrayer[4];
423             pt[0].isExtreme = 1;
424             pt[5].isExtreme = 1;
425             break;
426 
427         case MIN_INVALID:
428             if (tempPrayer[0] == 99) {
429                 exinterval = conf->fajrInv / 60.0;
430                 tempPrayer[0] = tempPrayer[1] - exinterval;
431                 pt[0].isExtreme = 1;
432             }
433             if (tempPrayer[5] == 99) {
434                 exinterval = conf->ishaaInv / 60.0;
435                 tempPrayer[5] = tempPrayer[4] + exinterval;
436                 pt[5].isExtreme = 1;
437             }
438             break;
439         } /* end switch */
440     } /* end extreme */
441 
442     /* Apply intervals if set */
443     if (conf->extreme != MIN_INVALID &&
444         conf->extreme != HALF_INVALID &&
445         conf->extreme != HALF_ALWAYS)
446     {
447         if (conf->fajrInv != 0) {
448             if (tempPrayer[1] != 99)
449                 tempPrayer[0] = tempPrayer[1] - (conf->fajrInv / 60.0);
450             else tempPrayer[0] = 99;
451         }
452 
453         if (conf->ishaaInv != 0) {
454             if (tempPrayer[4] != 99)
455                 tempPrayer[5] = tempPrayer[4] + (conf->ishaaInv / 60.0);
456             else tempPrayer[5] = 99;
457         }
458     }
459 
460     /* Final Step: Fill the Prayer array by doing decimal degree to
461      * Prayer structure conversion */
462     if (type == IMSAAK || type == NEXTFAJR)
463         base6hm(tempPrayer[0], loc, conf, &pt[0], type);
464     else {
465         for (i=0; i<6; i++)
466             base6hm(tempPrayer[i], loc, conf, &pt[i], i);
467     }
468 }
469 
base6hm(double bs,const Location * loc,const Method * conf,Prayer * pt,int type)470 static void base6hm(double bs, const Location* loc, const Method* conf,
471                     Prayer* pt, int type)
472 {
473     double min, sec;
474 
475     /* Set to 99 and return if prayer is invalid */
476     if (bs == 99)
477     {
478         pt->hour = 99;
479         pt->minute = 99;
480         pt->second = 0;
481         return;
482     }
483 
484     /* Add offsets */
485     if (conf->offset == 1) {
486         if (type == IMSAAK || type == NEXTFAJR)
487             bs += (conf->offList[0] / 60.0);
488         else  bs += (conf->offList[type] / 60.0);
489     }
490 
491     /* Fix after minus offsets before midnight */
492     if (bs < 0) {
493         while (bs < 0)
494             bs = 24 + bs;
495     }
496 
497     min = (bs - floor(bs)) * 60;
498     sec = (min - floor(min)) * 60;
499 
500     /* Add rounding minutes */
501     if (conf->round == 1)
502     {
503         if (sec >= DEF_ROUND_SEC)
504             bs += 1/60.0;
505         /* compute again */
506         min = (bs - floor(bs)) * 60;
507         sec = 0;
508 
509     } else if (conf->round == 2 || conf->round == 3)
510     {
511         switch(type)
512         {
513         case FAJR:
514         case ZUHR:
515         case ASSR:
516         case MAGHRIB:
517         case ISHAA:
518         case NEXTFAJR:
519 
520             if (conf->round == 2) {
521                 if (sec >= DEF_ROUND_SEC) {
522                     bs += 1/60.0;
523                     min = (bs - floor(bs)) * 60;
524                 }
525             } else if (conf->round == 3)
526             {
527                 if (sec >= AGGRESSIVE_ROUND_SEC) {
528                     bs += 1/60.0;
529                     min = (bs - floor(bs)) * 60;
530                 }
531             }
532             sec = 0;
533             break;
534 
535         case SHUROOQ:
536         case IMSAAK:
537             sec = 0;
538             break;
539         }
540     }
541 
542     /* Add daylight saving time and fix after midnight times */
543     bs += loc->dst;
544     if (bs >= 24)
545         bs = fmod(bs, 24);
546 
547     pt->hour   = (int)bs;
548     pt->minute = (int)min;
549     pt->second = (int)sec;
550 }
551 
getImsaak(const Location * loc,const Method * conf,const Date * date,Prayer * pt)552 void getImsaak (const Location* loc, const Method* conf, const Date* date,
553                 Prayer* pt)
554 {
555 
556     Method tmpConf;
557     int lastDay;
558     int dayOfYear;
559     double julianDay;
560     Prayer temp[6];
561 
562     tmpConf = *conf;
563 
564     if (conf->fajrInv != 0) {
565         if (conf->imsaakInv == 0)
566             tmpConf.fajrInv += DEF_IMSAAK_INTERVAL;
567         else tmpConf.fajrInv += conf->imsaakInv;
568 
569     } else if (conf->imsaakInv != 0) {
570         /* use an inv even if al-Fajr is computed (Indonesia?) */
571         tmpConf.offList[0] += (conf->imsaakInv * -1);
572         tmpConf.offset = 1;
573     } else {
574         tmpConf.fajrAng += conf->imsaakAng;
575     }
576 
577     getDayInfo ( date, loc->gmtDiff, &lastDay, &dayOfYear, &julianDay);
578     getPrayerTimesByDay( loc, &tmpConf, lastDay, dayOfYear, julianDay, temp, IMSAAK);
579 
580     /* FIXIT: We probably need to check whether it's possible to compute
581      * Imsaak normally for some extreme methods first */
582     /* In case of an extreme Fajr time calculation use intervals for Imsaak and
583      * compute again */
584     if (temp[0].isExtreme != 0)
585     {
586         tmpConf = *conf;
587         if ( conf->imsaakInv == 0)
588         {
589             tmpConf.offList[0] -= DEF_IMSAAK_INTERVAL;
590             tmpConf.offset = 1;
591         } else
592         {
593             tmpConf.offList[0] -= conf->imsaakInv;
594             tmpConf.offset = 1;
595         }
596         getPrayerTimesByDay( loc, &tmpConf, lastDay, dayOfYear, julianDay, temp, IMSAAK);
597     }
598 
599     *pt = temp[0];
600 
601 }
602 
getNextDayImsaak(const Location * loc,const Method * conf,const Date * date,Prayer * pt)603 void getNextDayImsaak (const Location* loc, const Method* conf, const Date* date,
604                        Prayer* pt)
605 {
606     /* Copy the date structure and increment for next day.*/
607     Prayer temppt;
608     Date tempd = *date;
609     tempd.day++;
610 
611     getImsaak (loc, conf, &tempd, &temppt);
612 
613     *pt = temppt;
614 }
615 
getNextDayFajr(const Location * loc,const Method * conf,const Date * date,Prayer * pt)616 void getNextDayFajr (const Location* loc, const Method* conf, const Date* date,
617                      Prayer* pt)
618 {
619     Prayer temp[6];
620     int lastDay;
621     int dayOfYear;
622     double julianDay;
623     getDayInfo ( date, loc->gmtDiff, &lastDay, &dayOfYear, &julianDay);
624     getPrayerTimesByDay( loc, conf, lastDay, dayOfYear+1, julianDay+1, temp, NEXTFAJR);
625 
626     *pt = temp[0];
627 }
628 
getFajIsh(double lat,double dec,double Ang)629 static double getFajIsh(double lat, double dec, double Ang)
630 {
631     double rlat = DEG_TO_RAD(lat);
632 
633     /* Compute the hour angle */
634     double part1 = sin(DEG_TO_RAD(-Ang)) - (sin (rlat) * sin (dec));
635     double part2 = cos (rlat) * cos (dec);
636     double part3 = part1 / part2;
637 
638     if ( part3 < -INVALID_TRIGGER || part3 > INVALID_TRIGGER)
639         return 99;
640 
641     return DEG_TO_10_BASE * RAD_TO_DEG (acos(part3) );
642 }
643 
getZuhr(double lon,const Astro * astro)644 static double getZuhr(double lon, const Astro* astro)
645 {
646     return getTransit(lon, astro);
647 }
648 
getAssr(double lat,double dec,int mathhab)649 static double getAssr(double lat, double dec, int mathhab)
650 {
651     double part1, part2, part3, part4;
652     double rlat = DEG_TO_RAD(lat);
653 
654     part1 = mathhab + tan(fabs(rlat - dec));
655     part2 = atan(1.0 / part1);
656 
657     /* Compute the hour angle */
658     part3 = sin(part2) - (sin(rlat) * sin(dec));
659     part4 = (part3 / (cos(rlat) * cos(dec)));
660 
661     if ( part4 < -INVALID_TRIGGER || part4 > INVALID_TRIGGER) {
662         return 99;
663     }
664 
665     return DEG_TO_10_BASE * RAD_TO_DEG (acos(part4));
666 }
667 
getSeasonalFajr(double lat,int day,double fajr,double sunrise)668 static double getSeasonalFajr(double lat, int day, double fajr, double sunrise)
669 {
670     float A, B, C, D;
671     int DYY;
672     double adjustedFajr;
673 
674     DYY = getSeasonDay(day, lat);
675 
676     A = 75 + 28.65 / 55.0 * fabs(lat);
677     B = 75 + 19.44 / 55.0 * fabs(lat);
678     C = 75 + 32.74 / 55.0 * fabs(lat);
679     D = 75 + 48.1 / 55.0 * fabs(lat);
680 
681     if ( DYY < 91) {
682         A = A + ( B - A )/ 91.0 * DYY;
683     } else if ( DYY < 137) {
684         A = B + ( C - B ) / 46.0 * ( DYY - 91 );
685     } else if ( DYY< 183 ) {
686         A = C + ( D - C ) / 46.0 * ( DYY - 137 );
687     } else if ( DYY < 229 ) {
688         A = D + ( C - D ) / 46.0 * ( DYY - 183 );
689     } else if ( DYY < 275 ) {
690         A = C + ( B - C ) / 46.0 * ( DYY - 229 );
691     } else if ( DYY >= 275 ) {
692         A = B + ( A - B ) / 91.0 * ( DYY - 275 );
693     }
694 
695     adjustedFajr = sunrise - (floor(A) / 60.0);
696     if (adjustedFajr > fajr || fajr == 99) {
697         fajr = adjustedFajr;
698     }
699 
700     return fajr;
701 }
702 
getSeasonalIsha(double lat,int day,double isha,double sunset)703 static double getSeasonalIsha(double lat, int day, double isha, double sunset)
704 {
705     float A, B, C, D;
706     int DYY;
707     double adjustedIsha;
708 
709     DYY = getSeasonDay(day, lat);
710 
711     A = 75 + 25.6 / 55.0 * fabs(lat);
712     B = 75 + 2.05 / 55.0 * fabs(lat);
713     C = 75 - 9.21 / 55.0 * fabs(lat);
714     D = 75 + 6.14 / 55.0 * fabs(lat);
715 
716     if ( DYY < 91) {
717         A = A + ( B - A )/ 91.0 * DYY;
718     } else if ( DYY < 137) {
719         A = B + ( C - B ) / 46.0 * ( DYY - 91 );
720     } else if ( DYY< 183 ) {
721         A = C + ( D - C ) / 46.0 * ( DYY - 137 );
722     } else if ( DYY < 229 ) {
723         A = D + ( C - D ) / 46.0 * ( DYY - 183 );
724     } else if ( DYY < 275 ) {
725         A = C + ( B - C ) / 46.0 * ( DYY - 229 );
726     } else if ( DYY >= 275 ) {
727         A = B + ( A - B ) / 91.0 * ( DYY - 275 );
728     }
729 
730     adjustedIsha = sunset + (ceil(A) / 60.0);
731     if (adjustedIsha < isha || isha == 99) {
732         isha = adjustedIsha;
733     }
734 
735     return isha;
736 }
737 
getSeasonDay(int dayOfYear,double lat)738 static int getSeasonDay(int dayOfYear, double lat)
739 {
740     int seasonDay;
741 
742     if (lat >= 0) {
743         seasonDay = dayOfYear + 10;
744         if (seasonDay > 365) {
745             seasonDay = seasonDay - 365;
746         }
747     } else {
748         seasonDay = dayOfYear - 172;
749         if (seasonDay < 0) {
750             seasonDay = seasonDay + 365;
751         }
752     }
753 
754     return seasonDay;
755 }
756 
getDayofYear(int year,int month,int day)757 int getDayofYear(int year, int month, int day)
758 {
759     int i;
760     int isLeap = ((year & 3) == 0) && ((year % 100) != 0
761                                        || (year % 400) == 0);
762 
763     static char dayList[2][13] = {
764         {0,31,28,31,30,31,30,31,31,30,31,30,31},
765         {0,31,29,31,30,31,30,31,31,30,31,30,31}
766     };
767 
768     for (i=1; i<month; i++)
769         day += dayList[isLeap][i];
770 
771     return day;
772 }
773 
dms2Decimal(int deg,int min,double sec,char dir)774 double dms2Decimal(int deg, int min, double sec, char dir)
775 {
776     double sum = deg + ((min/60.0)+(sec/3600.0));
777     if (dir == 'S' || dir == 'W' || dir == 's' || dir == 'w')
778         return sum * (-1.0);
779     return sum;
780 }
781 
decimal2Dms(double decimal,int * deg,int * min,double * sec)782 void decimal2Dms(double decimal, int *deg, int *min, double *sec)
783 {
784     double tempmin, tempsec, n1, n2;
785 
786     tempmin = modf(decimal, &n1) * 60.0;
787     tempsec = modf(tempmin, &n2) * 60.0;
788 
789     *deg = (int)n1;
790     *min = (int)n2;
791     *sec = tempsec;
792 
793 }
794 
getDayInfo(const Date * date,double gmt,int * lastDay,int * dayOfYear,double * julianDay)795 static void getDayInfo ( const Date* date, double gmt, int *lastDay,
796                          int *dayOfYear, double *julianDay)
797 {
798     int ld;
799     int dy;
800     double jd;
801     ld = getDayofYear(date->year, 12, 31);
802     dy = getDayofYear(date->year, date->month, date->day);
803     jd = getJulianDay(date, gmt);
804     *lastDay = ld;
805     *dayOfYear = dy;
806     *julianDay = jd;
807 }
808 
getMethod(int n,Method * conf)809 void getMethod(int n, Method* conf)
810 {
811     int i;
812     conf->method = n;
813     conf->fajrInv = 0;
814     conf->ishaaInv = 0;
815     conf->imsaakInv = 0;
816     conf->mathhab = 1;
817     conf->round = 2;
818     conf->nearestLat = DEF_NEAREST_LATITUDE;
819     conf->imsaakAng = DEF_IMSAAK_ANGLE;
820     conf->extreme = 5;
821     conf->extremeLat = DEF_EXTREME_LATITUDE;
822     conf->offset = 0;
823     for (i = 0; i < 6; i++) {
824         conf->offList[i] = 0;
825     }
826 
827     switch(n)
828     {
829     case NONE:
830         conf->fajrAng = 0.0;
831         conf->ishaaAng = 0.0;
832         break;
833 
834     case EGYPT_SURVEY:
835         conf->fajrAng = 20;
836         conf->ishaaAng = 18;
837         break;
838 
839     case KARACHI_SHAF:
840         conf->fajrAng = 18;
841         conf->ishaaAng = 18;
842         break;
843 
844     case KARACHI_HANAF:
845         conf->fajrAng = 18;
846         conf->ishaaAng = 18;
847         conf->mathhab = 2;
848         break;
849 
850     case NORTH_AMERICA:
851         conf->fajrAng = 15;
852         conf->ishaaAng = 15;
853         break;
854 
855     case MUSLIM_LEAGUE:
856         conf->fajrAng = 18;
857         conf->ishaaAng = 17;
858         break;
859 
860     case UMM_ALQURRA:
861         conf->fajrAng = 18;
862         conf->ishaaAng = 0.0;
863         conf->ishaaInv = 90;
864         break;
865 
866     case FIXED_ISHAA:
867         conf->fajrAng = 19.5;
868         conf->ishaaAng = 0.0;
869         conf->ishaaInv = 90;
870         break;
871 
872     case EGYPT_NEW:
873         conf->fajrAng = 19.5;
874         conf->ishaaAng = 17.5;
875         break;
876 
877     case UMM_ALQURRA_RAMADAN:
878         conf->fajrAng = 18;
879         conf->ishaaAng = 0.0;
880         conf->ishaaInv = 120;
881         break;
882 
883     case MOONSIGHTING_COMMITTEE:
884         conf->fajrAng = 18;
885         conf->ishaaAng = 18;
886         break;
887 
888     case MOROCCO_AWQAF:
889         conf->fajrAng = 19;
890         conf->ishaaAng = 17;
891         conf->offset = 1;
892         conf->offList[2] = 5;
893         conf->offList[4] = 5;
894         break;
895     }
896 }
897 
898 /* Obtaining the direction of the shortest distance towards Qibla by using the
899  * great circle formula */
getNorthQibla(const Location * loc)900 double getNorthQibla(const Location* loc)
901 {
902     /* FIXIT: reduce DEG_TO_RAD usage */
903     double num, denom;
904     num = sin (DEG_TO_RAD (loc->degreeLong) - DEG_TO_RAD (KAABA_LONG));
905     denom = (cos (DEG_TO_RAD (loc->degreeLat)) * tan (DEG_TO_RAD (KAABA_LAT))) -
906         (sin (DEG_TO_RAD (loc->degreeLat)) * ((cos ((DEG_TO_RAD (loc->degreeLong) -
907                                                      DEG_TO_RAD(KAABA_LONG))))));
908     return RAD_TO_DEG (atan2 (num, denom));
909 
910 }
911