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