[Dokumentasi Kode Sumber] (5) : Menghitung Waktu Sholat

Menghitung Waktu Sholat dengan C

Menghitung Waktu Sholat dengan C adalah bagian Dari Koleksi Kode Sumber C

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/************************************************************************
* $Id: prayer.c 2186 2009-03-09 14:19:57Z thamer $
*
* ------------
* Description:
* ------------
* Copyright (c) 2003-2006, 2009, Arabeyes, Thamer Mahmoud
*
* A full featured Muslim Prayer Times calculator
*
*
* -----------------
* Revision Details: (Updated by Revision Control System)
* -----------------
* $Date: 2009-03-09 17:19:57 +0300 (Mon, 09 Mar 2009) $
* $Author: thamer $
* $Revision: 2186 $
* $Source$
*
* (www.arabeyes.org - under LGPL license - see COPYING file)
************************************************************************/
[/sourcecode]
[sourcecode language="cpp"]
#include "prayer.h"
#include "astro.h"
/* Defaults */
#define KAABA_LAT 21.423333
#define KAABA_LONG 39.823333
#define DEF_NEAREST_LATITUDE 48.5
#define DEF_IMSAAK_ANGLE 1.5
#define DEF_IMSAAK_INTERVAL 10
#define DEF_ROUND_SEC 30
#define AGGRESSIVE_ROUND_SEC 1
enum exmethods { NONE_EX,
LAT_ALL,
LAT_ALWAYS,
LAT_INVALID,
GOOD_ALL,
GOOD_INVALID,
SEVEN_NIGHT_ALWAYS,
SEVEN_NIGHT_INVALID,
SEVEN_DAY_ALWAYS,
SEVEN_DAY_INVALID,
HALF_ALWAYS,
HALF_INVALID,
MIN_ALWAYS,
MIN_INVALID,
GOOD_INVALID_SAME };
enum methods { NONE,
EGYPT_SURVEY,
KARACHI_SHAF,
KARACHI_HANAF,
NORTH_AMERICA,
MUSLIM_LEAGUE,
UMM_ALQURRA,
FIXED_ISHAA,
EGYPT_NEW };
enum salatType { FAJR,
SHUROOQ,
ZUHR,
ASSR,
MAGHRIB,
ISHAA,
IMSAAK,
NEXTFAJR };
static double getZuhr (double lon, const Astro* astro);
static double getFajIsh (double Lat, double dec, double Ang);
static double getAssr (double Lat, double dec, int mathhab);
static void base6hm(double bs, const Location* loc, const Method* conf,
Prayer* pt, int type);
static void getDayInfo( const Date* date, double gmt, int *lastDay, double *julianDay);
static void getPrayerTimesByDay ( const Location* loc, const Method* conf, int lastDay,
double julianDay, Prayer* pt, int type);
Astro astroCache; /* This global variable is used for caching values between
* multiple getPrayerTimesByDay() calls. You can disable this
* caching feature by moving this line to the start of the
* getPrayerTimesByDay() function. */
void getPrayerTimes ( const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
int lastDay;
double julianDay;
getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay);
getPrayerTimesByDay( loc, conf, lastDay, julianDay, pt, 0);
}
static void getPrayerTimesByDay ( const Location* loc, const Method* conf,
int lastDay, double julianDay, Prayer* pt,
int type)
{
int i, invalid;
double zu, sh, mg, fj, is, ar;
double lat, lon, dec;
double tempPrayer[6];
Astro tAstro;
lat = loc->degreeLat;
lon = loc->degreeLong;
invalid = 0;
/* Start by filling the tAstro structure with the appropriate astronomical
* values for this day. We also pass the cache structure to update and check
* if the actual values are already available. */
getAstroValuesByDay(julianDay, loc, &astroCache, &tAstro);
dec = DEG_TO_RAD(tAstro.dec[1]);
/* Get Prayer Times formulae results for this day of year and this
* location. The results are NOT the actual prayer times */
fj = getFajIsh (lat, dec, conf->fajrAng);
sh = getSunrise(loc, &tAstro);
zu = getZuhr (lon, &tAstro);
ar = getAssr (lat, dec, conf->mathhab);
mg = getSunset(loc, &tAstro);
is = getFajIsh (lat, dec, conf->ishaaAng);
/* Calculate all prayer times as Base-10 numbers in Normal circumstances */
/* Fajr */
if (fj == 99) {
tempPrayer[0] = 99;
invalid = 1;
}
else tempPrayer[0] = zu - fj;
if (sh == 99)
invalid = 1;
tempPrayer[1] = sh;
tempPrayer[2] = zu;
/* Assr */
if (ar == 99) {
tempPrayer[3] = 99;
invalid = 1;
}
else tempPrayer[3] = zu + ar;
if (mg == 99)
invalid = 1;
tempPrayer[4] = mg;
/* Ishaa */
if (is == 99) {
tempPrayer[5] = 99;
invalid = 1;
}
else tempPrayer[5] = zu + is;
/* Calculate all prayer times as Base-10 numbers in Extreme Latitudes (if
* needed) */
/* Reset status of extreme switches */
for (i=0; i<6; i++)
pt[i].isExtreme = 0;
if ((conf->extreme != NONE_EX) && !((conf->extreme == GOOD_INVALID ||
conf->extreme == LAT_INVALID ||
conf->extreme == SEVEN_NIGHT_INVALID ||
conf->extreme == SEVEN_DAY_INVALID ||
conf->extreme == HALF_INVALID) &&
(invalid == 0)))
{
double exdecPrev, exdecNext, degnLat;
double exZu=99, exFj=99, exIs=99, exAr=99, exIm=99, exSh=99, exMg=99;
double portion = 0;
double nGoodDay = 0;
int exinterval = 0;
Location exLoc = *loc;
Astro exAstroPrev;
Astro exAstroNext;
switch(conf->extreme)
{
/* Nearest Latitude (Method.nearestLat) */
case LAT_ALL:
case LAT_ALWAYS:
case LAT_INVALID:
/* FIXIT: we cannot compute this when interval is set because
* angle==0 . Only the if-invalid methods would work */
exLoc.degreeLat = conf->nearestLat;
exFj = getFajIsh(conf->nearestLat, dec, conf->fajrAng);
exIm = getFajIsh(conf->nearestLat, dec, conf->imsaakAng);
exSh = getSunrise(&exLoc, &tAstro);
exAr = getAssr(conf->nearestLat, dec, conf->mathhab);
exMg = getSunset(&exLoc, &tAstro);
exIs = getFajIsh(conf->nearestLat, dec, conf->ishaaAng);
switch(conf->extreme)
{
case LAT_ALL:
tempPrayer[0] = zu - exFj;
tempPrayer[1] = exSh;
tempPrayer[3] = zu + exAr;
tempPrayer[4] = exMg;
tempPrayer[5] = zu + exIs;
pt[0].isExtreme = 1;
pt[1].isExtreme = 1;
pt[2].isExtreme = 1;
pt[3].isExtreme = 1;
pt[4].isExtreme = 1;
pt[5].isExtreme = 1;
break;
case LAT_ALWAYS:
tempPrayer[0] = zu - exFj;
tempPrayer[5] = zu + exIs;
pt[0].isExtreme = 1;
pt[5].isExtreme = 1;
break;
case LAT_INVALID:
if (tempPrayer[0] == 99) {
tempPrayer[0] = zu - exFj;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
tempPrayer[5] = zu + exIs;
pt[5].isExtreme = 1;
}
break;
}
break;
/* Nearest Good Day */
case GOOD_ALL:
case GOOD_INVALID:
case GOOD_INVALID_SAME:
exAstroPrev = astroCache;
exAstroNext = astroCache;
/* Start by getting last or next nearest Good Day */
for(i=0; i <= lastDay; i++)
{
/* Last closest day */
nGoodDay = julianDay - i;
getAstroValuesByDay(nGoodDay, loc, &exAstroPrev, &tAstro);
exdecPrev = DEG_TO_RAD(tAstro.dec[1]);
exFj = getFajIsh(lat, exdecPrev, conf->fajrAng);
if (exFj != 99)
{
exIs = getFajIsh(lat, exdecPrev, conf->ishaaAng);
if (exIs != 99)
{
exZu = getZuhr (lon, &tAstro);
exSh = getSunrise (loc, &tAstro);
exAr = getAssr (lat, exdecPrev, conf->mathhab);
exMg = getSunset (loc, &tAstro);
break;
}
}
/* Next closest day */
nGoodDay = julianDay + i;
getAstroValuesByDay(nGoodDay, loc, &exAstroNext, &tAstro);
exdecNext = DEG_TO_RAD(tAstro.dec[1]);
exFj = getFajIsh(lat, exdecNext, conf->fajrAng);
if (exFj != 99)
{
exIs = getFajIsh(lat, exdecNext, conf->ishaaAng);
if (exIs != 99)
{
exZu = getZuhr (lon, &tAstro);
exSh = getSunrise (loc, &tAstro);
exAr = getAssr (lat, exdecNext, conf->mathhab);
exMg = getSunset (loc, &tAstro);
break;
}
}
}
switch(conf->extreme)
{
case GOOD_ALL:
tempPrayer[0] = exZu - exFj;
tempPrayer[1] = exSh;
tempPrayer[2] = exZu;
tempPrayer[3] = exZu + exAr;
tempPrayer[4] = exMg;
tempPrayer[5] = exZu + exIs;
for (i=0; i<6; i++)
pt[i].isExtreme = 1;
break;
case GOOD_INVALID:
if (tempPrayer[0] == 99) {
tempPrayer[0] = exZu - exFj;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
tempPrayer[5] = exZu + exIs;
pt[5].isExtreme = 1;
}
break;
case GOOD_INVALID_SAME:
if ((tempPrayer[0] == 99) || (tempPrayer[5] == 99))
{
tempPrayer[0] = exZu - exFj;
pt[0].isExtreme = 1;
tempPrayer[5] = exZu + exIs;
pt[5].isExtreme = 1;
}
break;
}
break;
case SEVEN_NIGHT_ALWAYS:
case SEVEN_NIGHT_INVALID:
case SEVEN_DAY_ALWAYS:
case SEVEN_DAY_INVALID:
case HALF_ALWAYS:
case HALF_INVALID:
/* FIXIT: For clarity, we may need to move the HALF_* methods
* into their own separate case statement. */
switch(conf->extreme)
{
case SEVEN_NIGHT_ALWAYS:
case SEVEN_NIGHT_INVALID:
portion = (24 - (tempPrayer[4] - tempPrayer[1])) * (1/7.0);
break;
case SEVEN_DAY_ALWAYS:
case SEVEN_DAY_INVALID:
portion = (tempPrayer[4] - tempPrayer[1]) * (1/7.0);
break;
case HALF_ALWAYS:
case HALF_INVALID:
portion = (24 - tempPrayer[4] - tempPrayer[1]) * (1/2.0);
break;
}
if (conf->extreme == SEVEN_NIGHT_INVALID ||
conf->extreme == SEVEN_DAY_INVALID ||
conf->extreme == HALF_INVALID)
{
if (tempPrayer[0] == 99) {
if (conf->extreme == HALF_INVALID)
tempPrayer[0] = portion - (conf->fajrInv / 60.0);
else tempPrayer[0] = tempPrayer[1] - portion;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
if (conf->extreme == HALF_INVALID)
tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ;
else tempPrayer[5] = tempPrayer[4] + portion;
pt[5].isExtreme = 1;
}
} else { /* for the always methods */
if (conf->extreme == HALF_ALWAYS) {
tempPrayer[0] = portion - (conf->fajrInv / 60.0);
tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ;
}
else {
tempPrayer[0] = tempPrayer[1] - portion;
tempPrayer[5] = tempPrayer[4] + portion;
}
pt[0].isExtreme = 1;
pt[5].isExtreme = 1;
}
break;
case MIN_ALWAYS:
/* Do nothing here because this is implemented through fajrInv and
* ishaaInv structure members */
tempPrayer[0] = tempPrayer[1];
tempPrayer[5] = tempPrayer[4];
pt[0].isExtreme = 1;
pt[5].isExtreme = 1;
break;
case MIN_INVALID:
if (tempPrayer[0] == 99) {
exinterval = conf->fajrInv / 60.0;
tempPrayer[0] = tempPrayer[1] - exinterval;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
exinterval = conf->ishaaInv / 60.0;
tempPrayer[5] = tempPrayer[4] + exinterval;
pt[5].isExtreme = 1;
}
break;
} /* end switch */
} /* end extreme */
/* Apply intervals if set */
if (conf->extreme != MIN_INVALID &&
conf->extreme != HALF_INVALID &&
conf->extreme != HALF_ALWAYS)
{
if (conf->fajrInv != 0) {
if (tempPrayer[1] != 99)
tempPrayer[0] = tempPrayer[1] - (conf->fajrInv / 60.0);
else tempPrayer[0] = 99;
}
if (conf->ishaaInv != 0) {
if (tempPrayer[4] != 99)
tempPrayer[5] = tempPrayer[4] + (conf->ishaaInv / 60.0);
else tempPrayer[5] = 99;
}
}
/* Final Step: Fill the Prayer array by doing decimal degree to
* Prayer structure conversion */
if (type == IMSAAK || type == NEXTFAJR)
base6hm(tempPrayer[0], loc, conf, &pt[0], type);
else {
for (i=0; i<6; i++)
base6hm(tempPrayer[i], loc, conf, &pt[i], i);
}
}
static void base6hm(double bs, const Location* loc, const Method* conf,
Prayer* pt, int type)
{
double min, sec;
/* Set to 99 and return if prayer is invalid */
if (bs == 99)
{
pt->hour = 99;
pt->minute = 99;
pt->second = 0;
return;
}
/* Add offsets */
if (conf->offset == 1) {
if (type == IMSAAK || type == NEXTFAJR)
bs += (conf->offList[0] / 60.0);
else bs += (conf->offList[type] / 60.0);
}
/* Fix after minus offsets before midnight */
if (bs < 0) {
while (bs < 0)
bs = 24 + bs;
}
min = (bs - floor(bs)) * 60;
sec = (min - floor(min)) * 60;
/* Add rounding minutes */
if (conf->round == 1)
{
if (sec >= DEF_ROUND_SEC)
bs += 1/60.0;
/* compute again */
min = (bs - floor(bs)) * 60;
sec = 0;
} else if (conf->round == 2 || conf->round == 3)
{
switch(type)
{
case FAJR:
case ZUHR:
case ASSR:
case MAGHRIB:
case ISHAA:
case NEXTFAJR:
if (conf->round == 2) {
if (sec >= DEF_ROUND_SEC) {
bs += 1/60.0;
min = (bs - floor(bs)) * 60;
}
} else if (conf->round == 3)
{
if (sec >= AGGRESSIVE_ROUND_SEC) {
bs += 1/60.0;
min = (bs - floor(bs)) * 60;
}
}
sec = 0;
break;
case SHUROOQ:
case IMSAAK:
sec = 0;
break;
}
}
/* Add daylight saving time and fix after midnight times */
bs += loc->dst;
if (bs >= 24)
bs = fmod(bs, 24);
pt->hour = (int)bs;
pt->minute = (int)min;
pt->second = (int)sec;
}
void getImsaak (const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
Method tmpConf;
int lastDay;
double julianDay;
Prayer temp[6];
tmpConf = *conf;
if (conf->fajrInv != 0) {
if (conf->imsaakInv == 0)
tmpConf.fajrInv += DEF_IMSAAK_INTERVAL;
else tmpConf.fajrInv += conf->imsaakInv;
} else if (conf->imsaakInv != 0) {
/* use an inv even if al-Fajr is computed (Indonesia?) */
tmpConf.offList[0] += (conf->imsaakInv * -1);
tmpConf.offset = 1;
} else {
tmpConf.fajrAng += conf->imsaakAng;
}
getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay);
getPrayerTimesByDay( loc, &tmpConf, lastDay, julianDay, temp, IMSAAK);
/* FIXIT: We probably need to check whether it's possible to compute
* Imsaak normally for some extreme methods first */
/* In case of an extreme Fajr time calculation use intervals for Imsaak and
* compute again */
if (temp[0].isExtreme != 0)
{
tmpConf = *conf;
if ( conf->imsaakInv == 0)
{
tmpConf.offList[0] -= DEF_IMSAAK_INTERVAL;
tmpConf.offset = 1;
} else
{
tmpConf.offList[0] -= conf->imsaakInv;
tmpConf.offset = 1;
}
getPrayerTimesByDay( loc, &tmpConf, lastDay, julianDay, temp, IMSAAK);
}
*pt = temp[0];
}
void getNextDayImsaak (const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
/* Copy the date structure and increment for next day.*/
Prayer temppt;
Date tempd = *date;
tempd.day++;
getImsaak (loc, conf, &tempd, &temppt);
*pt = temppt;
}
void getNextDayFajr (const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
Prayer temp[6];
int lastDay;
double julianDay;
getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay);
getPrayerTimesByDay( loc, conf, lastDay, julianDay+1, temp, NEXTFAJR);
*pt = temp[0];
}
static double getFajIsh(double lat, double dec, double Ang)
{
double rlat = DEG_TO_RAD(lat);
/* Compute the hour angle */
double part1 = sin(DEG_TO_RAD(-Ang)) - (sin (rlat) * sin (dec));
double part2 = cos (rlat) * cos (dec);
double part3 = part1 / part2;
if ( part3 < -INVALID_TRIGGER || part3 > INVALID_TRIGGER)
return 99;
return DEG_TO_10_BASE * RAD_TO_DEG (acos(part3) );
}
static double getZuhr(double lon, const Astro* astro)
{
return getTransit(lon, astro);
}
static double getAssr(double lat, double dec, int mathhab)
{
double part1, part2, part3, part4, ndec;
double rlat = DEG_TO_RAD(lat);
/* Reverse if at or near the southern hemisphere */
ndec = dec;
if (lat < 0.0)
ndec = -dec;
part1 = mathhab + tan(rlat - ndec);
if (part1 < 1.0)
part1 = mathhab - tan(rlat - ndec);
part2 = (PI/2.0) - atan(part1);
/* Compute the hour angle */
part3 = sin(part2) - (sin(rlat) * sin(ndec));
part4 = (part3 / (cos(rlat) * cos(ndec)));
if ( part4 < -INVALID_TRIGGER || part4 > INVALID_TRIGGER)
return 99;
return DEG_TO_10_BASE * RAD_TO_DEG (acos(part4));
}
int getDayofYear(int year, int month, int day)
{
int i;
int isLeap = ((year & 3) == 0) && ((year % 100) != 0
|| (year % 400) == 0);
static char dayList[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}
};
for (i=1; i<month; i++)
day += dayList[isLeap][i];
return day;
}
double dms2Decimal(int deg, int min, double sec, char dir)
{
double sum = deg + ((min/60.0)+(sec/3600.0));
if (dir == 'S' || dir == 'W' || dir == 's' || dir == 'w')
return sum * (-1.0);
return sum;
}
void decimal2Dms(double decimal, int *deg, int *min, double *sec)
{
double tempmin, tempsec, n1, n2;
tempmin = modf(decimal, &n1) * 60.0;
tempsec = modf(tempmin, &n2) * 60.0;
*deg = (int)n1;
*min = (int)n2;
*sec = tempsec;
}
static void getDayInfo ( const Date* date, double gmt, int *lastDay,
double *julianDay)
{
int ld;
double jd;
ld = getDayofYear(date->year, 12, 31);
jd = getJulianDay(date, gmt);
*lastDay = ld;
*julianDay = jd;
}
void getMethod(int n, Method* conf)
{
int i;
conf->fajrInv = 0;
conf->ishaaInv = 0;
conf->imsaakInv = 0;
conf->mathhab = 1;
conf->round = 2;
conf->nearestLat = DEF_NEAREST_LATITUDE;
conf->imsaakAng = DEF_IMSAAK_ANGLE;
conf->extreme = 5;
conf->offset = 0;
for (i = 0; i < 6; i++) {
conf->offList[i] = 0;
}
switch(n)
{
case NONE:
conf->fajrAng = 0.0;
conf->ishaaAng = 0.0;
break;
case EGYPT_SURVEY:
conf->fajrAng = 20;
conf->ishaaAng = 18;
break;
case KARACHI_SHAF:
conf->fajrAng = 18;
conf->ishaaAng = 18;
break;
case KARACHI_HANAF:
conf->fajrAng = 18;
conf->ishaaAng = 18;
conf->mathhab = 2;
break;
case NORTH_AMERICA:
conf->fajrAng = 15;
conf->ishaaAng = 15;
break;
case MUSLIM_LEAGUE:
conf->fajrAng = 18;
conf->ishaaAng = 17;
break;
case UMM_ALQURRA:
conf->fajrAng = 19;
conf->ishaaAng = 0.0;
conf->ishaaInv = 90;
break;
case FIXED_ISHAA:
conf->fajrAng = 19.5;
conf->ishaaAng = 0.0;
conf->ishaaInv = 90;
break;
case EGYPT_NEW:
conf->fajrAng = 19.5;
conf->ishaaAng = 17.5;
break;
}
}
/* Obtaining the direction of the shortest distance towards Qibla by using the
* great circle formula */
double getNorthQibla(const Location* loc)
{
/* FIXIT: reduce DEG_TO_RAD usage */
double num, denom;
num = sin (DEG_TO_RAD (loc->degreeLong) - DEG_TO_RAD (KAABA_LONG));
denom = (cos (DEG_TO_RAD (loc->degreeLat)) * tan (DEG_TO_RAD (KAABA_LAT))) -
(sin (DEG_TO_RAD (loc->degreeLat)) * ((cos ((DEG_TO_RAD (loc->degreeLong) -
DEG_TO_RAD(KAABA_LONG))))));
return RAD_TO_DEG (atan2 (num, denom));
}
[/sourcecode]
/************************************************************************ * $Id: prayer.c 2186 2009-03-09 14:19:57Z thamer $ * * ------------ * Description: * ------------ * Copyright (c) 2003-2006, 2009, Arabeyes, Thamer Mahmoud * * A full featured Muslim Prayer Times calculator * * * ----------------- * Revision Details: (Updated by Revision Control System) * ----------------- * $Date: 2009-03-09 17:19:57 +0300 (Mon, 09 Mar 2009) $ * $Author: thamer $ * $Revision: 2186 $ * $Source$ * * (www.arabeyes.org - under LGPL license - see COPYING file) ************************************************************************/ [/sourcecode] [sourcecode language="cpp"] #include "prayer.h" #include "astro.h" /* Defaults */ #define KAABA_LAT 21.423333 #define KAABA_LONG 39.823333 #define DEF_NEAREST_LATITUDE 48.5 #define DEF_IMSAAK_ANGLE 1.5 #define DEF_IMSAAK_INTERVAL 10 #define DEF_ROUND_SEC 30 #define AGGRESSIVE_ROUND_SEC 1 enum exmethods { NONE_EX, LAT_ALL, LAT_ALWAYS, LAT_INVALID, GOOD_ALL, GOOD_INVALID, SEVEN_NIGHT_ALWAYS, SEVEN_NIGHT_INVALID, SEVEN_DAY_ALWAYS, SEVEN_DAY_INVALID, HALF_ALWAYS, HALF_INVALID, MIN_ALWAYS, MIN_INVALID, GOOD_INVALID_SAME }; enum methods { NONE, EGYPT_SURVEY, KARACHI_SHAF, KARACHI_HANAF, NORTH_AMERICA, MUSLIM_LEAGUE, UMM_ALQURRA, FIXED_ISHAA, EGYPT_NEW }; enum salatType { FAJR, SHUROOQ, ZUHR, ASSR, MAGHRIB, ISHAA, IMSAAK, NEXTFAJR }; static double getZuhr (double lon, const Astro* astro); static double getFajIsh (double Lat, double dec, double Ang); static double getAssr (double Lat, double dec, int mathhab); static void base6hm(double bs, const Location* loc, const Method* conf, Prayer* pt, int type); static void getDayInfo( const Date* date, double gmt, int *lastDay, double *julianDay); static void getPrayerTimesByDay ( const Location* loc, const Method* conf, int lastDay, double julianDay, Prayer* pt, int type); Astro astroCache; /* This global variable is used for caching values between * multiple getPrayerTimesByDay() calls. You can disable this * caching feature by moving this line to the start of the * getPrayerTimesByDay() function. */ void getPrayerTimes ( const Location* loc, const Method* conf, const Date* date, Prayer* pt) { int lastDay; double julianDay; getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay); getPrayerTimesByDay( loc, conf, lastDay, julianDay, pt, 0); } static void getPrayerTimesByDay ( const Location* loc, const Method* conf, int lastDay, double julianDay, Prayer* pt, int type) { int i, invalid; double zu, sh, mg, fj, is, ar; double lat, lon, dec; double tempPrayer[6]; Astro tAstro; lat = loc->degreeLat; lon = loc->degreeLong; invalid = 0; /* Start by filling the tAstro structure with the appropriate astronomical * values for this day. We also pass the cache structure to update and check * if the actual values are already available. */ getAstroValuesByDay(julianDay, loc, &astroCache, &tAstro); dec = DEG_TO_RAD(tAstro.dec[1]); /* Get Prayer Times formulae results for this day of year and this * location. The results are NOT the actual prayer times */ fj = getFajIsh (lat, dec, conf->fajrAng); sh = getSunrise(loc, &tAstro); zu = getZuhr (lon, &tAstro); ar = getAssr (lat, dec, conf->mathhab); mg = getSunset(loc, &tAstro); is = getFajIsh (lat, dec, conf->ishaaAng); /* Calculate all prayer times as Base-10 numbers in Normal circumstances */ /* Fajr */ if (fj == 99) { tempPrayer[0] = 99; invalid = 1; } else tempPrayer[0] = zu - fj; if (sh == 99) invalid = 1; tempPrayer[1] = sh; tempPrayer[2] = zu; /* Assr */ if (ar == 99) { tempPrayer[3] = 99; invalid = 1; } else tempPrayer[3] = zu + ar; if (mg == 99) invalid = 1; tempPrayer[4] = mg; /* Ishaa */ if (is == 99) { tempPrayer[5] = 99; invalid = 1; } else tempPrayer[5] = zu + is; /* Calculate all prayer times as Base-10 numbers in Extreme Latitudes (if * needed) */ /* Reset status of extreme switches */ for (i=0; i<6; i++) pt[i].isExtreme = 0; if ((conf->extreme != NONE_EX) && !((conf->extreme == GOOD_INVALID || conf->extreme == LAT_INVALID || conf->extreme == SEVEN_NIGHT_INVALID || conf->extreme == SEVEN_DAY_INVALID || conf->extreme == HALF_INVALID) && (invalid == 0))) { double exdecPrev, exdecNext, degnLat; double exZu=99, exFj=99, exIs=99, exAr=99, exIm=99, exSh=99, exMg=99; double portion = 0; double nGoodDay = 0; int exinterval = 0; Location exLoc = *loc; Astro exAstroPrev; Astro exAstroNext; switch(conf->extreme) { /* Nearest Latitude (Method.nearestLat) */ case LAT_ALL: case LAT_ALWAYS: case LAT_INVALID: /* FIXIT: we cannot compute this when interval is set because * angle==0 . Only the if-invalid methods would work */ exLoc.degreeLat = conf->nearestLat; exFj = getFajIsh(conf->nearestLat, dec, conf->fajrAng); exIm = getFajIsh(conf->nearestLat, dec, conf->imsaakAng); exSh = getSunrise(&exLoc, &tAstro); exAr = getAssr(conf->nearestLat, dec, conf->mathhab); exMg = getSunset(&exLoc, &tAstro); exIs = getFajIsh(conf->nearestLat, dec, conf->ishaaAng); switch(conf->extreme) { case LAT_ALL: tempPrayer[0] = zu - exFj; tempPrayer[1] = exSh; tempPrayer[3] = zu + exAr; tempPrayer[4] = exMg; tempPrayer[5] = zu + exIs; pt[0].isExtreme = 1; pt[1].isExtreme = 1; pt[2].isExtreme = 1; pt[3].isExtreme = 1; pt[4].isExtreme = 1; pt[5].isExtreme = 1; break; case LAT_ALWAYS: tempPrayer[0] = zu - exFj; tempPrayer[5] = zu + exIs; pt[0].isExtreme = 1; pt[5].isExtreme = 1; break; case LAT_INVALID: if (tempPrayer[0] == 99) { tempPrayer[0] = zu - exFj; pt[0].isExtreme = 1; } if (tempPrayer[5] == 99) { tempPrayer[5] = zu + exIs; pt[5].isExtreme = 1; } break; } break; /* Nearest Good Day */ case GOOD_ALL: case GOOD_INVALID: case GOOD_INVALID_SAME: exAstroPrev = astroCache; exAstroNext = astroCache; /* Start by getting last or next nearest Good Day */ for(i=0; i <= lastDay; i++) { /* Last closest day */ nGoodDay = julianDay - i; getAstroValuesByDay(nGoodDay, loc, &exAstroPrev, &tAstro); exdecPrev = DEG_TO_RAD(tAstro.dec[1]); exFj = getFajIsh(lat, exdecPrev, conf->fajrAng); if (exFj != 99) { exIs = getFajIsh(lat, exdecPrev, conf->ishaaAng); if (exIs != 99) { exZu = getZuhr (lon, &tAstro); exSh = getSunrise (loc, &tAstro); exAr = getAssr (lat, exdecPrev, conf->mathhab); exMg = getSunset (loc, &tAstro); break; } } /* Next closest day */ nGoodDay = julianDay + i; getAstroValuesByDay(nGoodDay, loc, &exAstroNext, &tAstro); exdecNext = DEG_TO_RAD(tAstro.dec[1]); exFj = getFajIsh(lat, exdecNext, conf->fajrAng); if (exFj != 99) { exIs = getFajIsh(lat, exdecNext, conf->ishaaAng); if (exIs != 99) { exZu = getZuhr (lon, &tAstro); exSh = getSunrise (loc, &tAstro); exAr = getAssr (lat, exdecNext, conf->mathhab); exMg = getSunset (loc, &tAstro); break; } } } switch(conf->extreme) { case GOOD_ALL: tempPrayer[0] = exZu - exFj; tempPrayer[1] = exSh; tempPrayer[2] = exZu; tempPrayer[3] = exZu + exAr; tempPrayer[4] = exMg; tempPrayer[5] = exZu + exIs; for (i=0; i<6; i++) pt[i].isExtreme = 1; break; case GOOD_INVALID: if (tempPrayer[0] == 99) { tempPrayer[0] = exZu - exFj; pt[0].isExtreme = 1; } if (tempPrayer[5] == 99) { tempPrayer[5] = exZu + exIs; pt[5].isExtreme = 1; } break; case GOOD_INVALID_SAME: if ((tempPrayer[0] == 99) || (tempPrayer[5] == 99)) { tempPrayer[0] = exZu - exFj; pt[0].isExtreme = 1; tempPrayer[5] = exZu + exIs; pt[5].isExtreme = 1; } break; } break; case SEVEN_NIGHT_ALWAYS: case SEVEN_NIGHT_INVALID: case SEVEN_DAY_ALWAYS: case SEVEN_DAY_INVALID: case HALF_ALWAYS: case HALF_INVALID: /* FIXIT: For clarity, we may need to move the HALF_* methods * into their own separate case statement. */ switch(conf->extreme) { case SEVEN_NIGHT_ALWAYS: case SEVEN_NIGHT_INVALID: portion = (24 - (tempPrayer[4] - tempPrayer[1])) * (1/7.0); break; case SEVEN_DAY_ALWAYS: case SEVEN_DAY_INVALID: portion = (tempPrayer[4] - tempPrayer[1]) * (1/7.0); break; case HALF_ALWAYS: case HALF_INVALID: portion = (24 - tempPrayer[4] - tempPrayer[1]) * (1/2.0); break; } if (conf->extreme == SEVEN_NIGHT_INVALID || conf->extreme == SEVEN_DAY_INVALID || conf->extreme == HALF_INVALID) { if (tempPrayer[0] == 99) { if (conf->extreme == HALF_INVALID) tempPrayer[0] = portion - (conf->fajrInv / 60.0); else tempPrayer[0] = tempPrayer[1] - portion; pt[0].isExtreme = 1; } if (tempPrayer[5] == 99) { if (conf->extreme == HALF_INVALID) tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ; else tempPrayer[5] = tempPrayer[4] + portion; pt[5].isExtreme = 1; } } else { /* for the always methods */ if (conf->extreme == HALF_ALWAYS) { tempPrayer[0] = portion - (conf->fajrInv / 60.0); tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ; } else { tempPrayer[0] = tempPrayer[1] - portion; tempPrayer[5] = tempPrayer[4] + portion; } pt[0].isExtreme = 1; pt[5].isExtreme = 1; } break; case MIN_ALWAYS: /* Do nothing here because this is implemented through fajrInv and * ishaaInv structure members */ tempPrayer[0] = tempPrayer[1]; tempPrayer[5] = tempPrayer[4]; pt[0].isExtreme = 1; pt[5].isExtreme = 1; break; case MIN_INVALID: if (tempPrayer[0] == 99) { exinterval = conf->fajrInv / 60.0; tempPrayer[0] = tempPrayer[1] - exinterval; pt[0].isExtreme = 1; } if (tempPrayer[5] == 99) { exinterval = conf->ishaaInv / 60.0; tempPrayer[5] = tempPrayer[4] + exinterval; pt[5].isExtreme = 1; } break; } /* end switch */ } /* end extreme */ /* Apply intervals if set */ if (conf->extreme != MIN_INVALID && conf->extreme != HALF_INVALID && conf->extreme != HALF_ALWAYS) { if (conf->fajrInv != 0) { if (tempPrayer[1] != 99) tempPrayer[0] = tempPrayer[1] - (conf->fajrInv / 60.0); else tempPrayer[0] = 99; } if (conf->ishaaInv != 0) { if (tempPrayer[4] != 99) tempPrayer[5] = tempPrayer[4] + (conf->ishaaInv / 60.0); else tempPrayer[5] = 99; } } /* Final Step: Fill the Prayer array by doing decimal degree to * Prayer structure conversion */ if (type == IMSAAK || type == NEXTFAJR) base6hm(tempPrayer[0], loc, conf, &pt[0], type); else { for (i=0; i<6; i++) base6hm(tempPrayer[i], loc, conf, &pt[i], i); } } static void base6hm(double bs, const Location* loc, const Method* conf, Prayer* pt, int type) { double min, sec; /* Set to 99 and return if prayer is invalid */ if (bs == 99) { pt->hour = 99; pt->minute = 99; pt->second = 0; return; } /* Add offsets */ if (conf->offset == 1) { if (type == IMSAAK || type == NEXTFAJR) bs += (conf->offList[0] / 60.0); else bs += (conf->offList[type] / 60.0); } /* Fix after minus offsets before midnight */ if (bs < 0) { while (bs < 0) bs = 24 + bs; } min = (bs - floor(bs)) * 60; sec = (min - floor(min)) * 60; /* Add rounding minutes */ if (conf->round == 1) { if (sec >= DEF_ROUND_SEC) bs += 1/60.0; /* compute again */ min = (bs - floor(bs)) * 60; sec = 0; } else if (conf->round == 2 || conf->round == 3) { switch(type) { case FAJR: case ZUHR: case ASSR: case MAGHRIB: case ISHAA: case NEXTFAJR: if (conf->round == 2) { if (sec >= DEF_ROUND_SEC) { bs += 1/60.0; min = (bs - floor(bs)) * 60; } } else if (conf->round == 3) { if (sec >= AGGRESSIVE_ROUND_SEC) { bs += 1/60.0; min = (bs - floor(bs)) * 60; } } sec = 0; break; case SHUROOQ: case IMSAAK: sec = 0; break; } } /* Add daylight saving time and fix after midnight times */ bs += loc->dst; if (bs >= 24) bs = fmod(bs, 24); pt->hour = (int)bs; pt->minute = (int)min; pt->second = (int)sec; } void getImsaak (const Location* loc, const Method* conf, const Date* date, Prayer* pt) { Method tmpConf; int lastDay; double julianDay; Prayer temp[6]; tmpConf = *conf; if (conf->fajrInv != 0) { if (conf->imsaakInv == 0) tmpConf.fajrInv += DEF_IMSAAK_INTERVAL; else tmpConf.fajrInv += conf->imsaakInv; } else if (conf->imsaakInv != 0) { /* use an inv even if al-Fajr is computed (Indonesia?) */ tmpConf.offList[0] += (conf->imsaakInv * -1); tmpConf.offset = 1; } else { tmpConf.fajrAng += conf->imsaakAng; } getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay); getPrayerTimesByDay( loc, &tmpConf, lastDay, julianDay, temp, IMSAAK); /* FIXIT: We probably need to check whether it's possible to compute * Imsaak normally for some extreme methods first */ /* In case of an extreme Fajr time calculation use intervals for Imsaak and * compute again */ if (temp[0].isExtreme != 0) { tmpConf = *conf; if ( conf->imsaakInv == 0) { tmpConf.offList[0] -= DEF_IMSAAK_INTERVAL; tmpConf.offset = 1; } else { tmpConf.offList[0] -= conf->imsaakInv; tmpConf.offset = 1; } getPrayerTimesByDay( loc, &tmpConf, lastDay, julianDay, temp, IMSAAK); } *pt = temp[0]; } void getNextDayImsaak (const Location* loc, const Method* conf, const Date* date, Prayer* pt) { /* Copy the date structure and increment for next day.*/ Prayer temppt; Date tempd = *date; tempd.day++; getImsaak (loc, conf, &tempd, &temppt); *pt = temppt; } void getNextDayFajr (const Location* loc, const Method* conf, const Date* date, Prayer* pt) { Prayer temp[6]; int lastDay; double julianDay; getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay); getPrayerTimesByDay( loc, conf, lastDay, julianDay+1, temp, NEXTFAJR); *pt = temp[0]; } static double getFajIsh(double lat, double dec, double Ang) { double rlat = DEG_TO_RAD(lat); /* Compute the hour angle */ double part1 = sin(DEG_TO_RAD(-Ang)) - (sin (rlat) * sin (dec)); double part2 = cos (rlat) * cos (dec); double part3 = part1 / part2; if ( part3 < -INVALID_TRIGGER || part3 > INVALID_TRIGGER) return 99; return DEG_TO_10_BASE * RAD_TO_DEG (acos(part3) ); } static double getZuhr(double lon, const Astro* astro) { return getTransit(lon, astro); } static double getAssr(double lat, double dec, int mathhab) { double part1, part2, part3, part4, ndec; double rlat = DEG_TO_RAD(lat); /* Reverse if at or near the southern hemisphere */ ndec = dec; if (lat < 0.0) ndec = -dec; part1 = mathhab + tan(rlat - ndec); if (part1 < 1.0) part1 = mathhab - tan(rlat - ndec); part2 = (PI/2.0) - atan(part1); /* Compute the hour angle */ part3 = sin(part2) - (sin(rlat) * sin(ndec)); part4 = (part3 / (cos(rlat) * cos(ndec))); if ( part4 < -INVALID_TRIGGER || part4 > INVALID_TRIGGER) return 99; return DEG_TO_10_BASE * RAD_TO_DEG (acos(part4)); } int getDayofYear(int year, int month, int day) { int i; int isLeap = ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0); static char dayList[2][13] = { {0,31,28,31,30,31,30,31,31,30,31,30,31}, {0,31,29,31,30,31,30,31,31,30,31,30,31} }; for (i=1; i<month; i++) day += dayList[isLeap][i]; return day; } double dms2Decimal(int deg, int min, double sec, char dir) { double sum = deg + ((min/60.0)+(sec/3600.0)); if (dir == 'S' || dir == 'W' || dir == 's' || dir == 'w') return sum * (-1.0); return sum; } void decimal2Dms(double decimal, int *deg, int *min, double *sec) { double tempmin, tempsec, n1, n2; tempmin = modf(decimal, &n1) * 60.0; tempsec = modf(tempmin, &n2) * 60.0; *deg = (int)n1; *min = (int)n2; *sec = tempsec; } static void getDayInfo ( const Date* date, double gmt, int *lastDay, double *julianDay) { int ld; double jd; ld = getDayofYear(date->year, 12, 31); jd = getJulianDay(date, gmt); *lastDay = ld; *julianDay = jd; } void getMethod(int n, Method* conf) { int i; conf->fajrInv = 0; conf->ishaaInv = 0; conf->imsaakInv = 0; conf->mathhab = 1; conf->round = 2; conf->nearestLat = DEF_NEAREST_LATITUDE; conf->imsaakAng = DEF_IMSAAK_ANGLE; conf->extreme = 5; conf->offset = 0; for (i = 0; i < 6; i++) { conf->offList[i] = 0; } switch(n) { case NONE: conf->fajrAng = 0.0; conf->ishaaAng = 0.0; break; case EGYPT_SURVEY: conf->fajrAng = 20; conf->ishaaAng = 18; break; case KARACHI_SHAF: conf->fajrAng = 18; conf->ishaaAng = 18; break; case KARACHI_HANAF: conf->fajrAng = 18; conf->ishaaAng = 18; conf->mathhab = 2; break; case NORTH_AMERICA: conf->fajrAng = 15; conf->ishaaAng = 15; break; case MUSLIM_LEAGUE: conf->fajrAng = 18; conf->ishaaAng = 17; break; case UMM_ALQURRA: conf->fajrAng = 19; conf->ishaaAng = 0.0; conf->ishaaInv = 90; break; case FIXED_ISHAA: conf->fajrAng = 19.5; conf->ishaaAng = 0.0; conf->ishaaInv = 90; break; case EGYPT_NEW: conf->fajrAng = 19.5; conf->ishaaAng = 17.5; break; } } /* Obtaining the direction of the shortest distance towards Qibla by using the * great circle formula */ double getNorthQibla(const Location* loc) { /* FIXIT: reduce DEG_TO_RAD usage */ double num, denom; num = sin (DEG_TO_RAD (loc->degreeLong) - DEG_TO_RAD (KAABA_LONG)); denom = (cos (DEG_TO_RAD (loc->degreeLat)) * tan (DEG_TO_RAD (KAABA_LAT))) - (sin (DEG_TO_RAD (loc->degreeLat)) * ((cos ((DEG_TO_RAD (loc->degreeLong) - DEG_TO_RAD(KAABA_LONG)))))); return RAD_TO_DEG (atan2 (num, denom)); } [/sourcecode]
/************************************************************************
* $Id: prayer.c 2186 2009-03-09 14:19:57Z thamer $
*
* ------------
* Description:
* ------------
*  Copyright (c) 2003-2006, 2009, Arabeyes, Thamer Mahmoud
*
*  A full featured Muslim Prayer Times calculator
*
*
* -----------------
* Revision Details:    (Updated by Revision Control System)
* -----------------
*  $Date: 2009-03-09 17:19:57 +0300 (Mon, 09 Mar 2009) $
*  $Author: thamer $
*  $Revision: 2186 $
*  $Source$
*
* (www.arabeyes.org - under LGPL license - see COPYING file)
************************************************************************/
[/sourcecode]


[sourcecode language="cpp"]
#include "prayer.h"
#include "astro.h"
/* Defaults */
#define KAABA_LAT 21.423333
#define KAABA_LONG 39.823333
#define DEF_NEAREST_LATITUDE 48.5
#define DEF_IMSAAK_ANGLE 1.5
#define DEF_IMSAAK_INTERVAL 10
#define DEF_ROUND_SEC 30
#define AGGRESSIVE_ROUND_SEC 1
enum exmethods  { NONE_EX,
LAT_ALL,
LAT_ALWAYS,
LAT_INVALID,
GOOD_ALL,
GOOD_INVALID,
SEVEN_NIGHT_ALWAYS,
SEVEN_NIGHT_INVALID,
SEVEN_DAY_ALWAYS,
SEVEN_DAY_INVALID,
HALF_ALWAYS,
HALF_INVALID,
MIN_ALWAYS,
MIN_INVALID,
GOOD_INVALID_SAME };
enum methods    { NONE,
EGYPT_SURVEY,
KARACHI_SHAF,
KARACHI_HANAF,
NORTH_AMERICA,
MUSLIM_LEAGUE,
UMM_ALQURRA,
FIXED_ISHAA,
EGYPT_NEW };
enum salatType  { FAJR,
SHUROOQ,
ZUHR,
ASSR,
MAGHRIB,
ISHAA,
IMSAAK,
NEXTFAJR };
static double getZuhr (double lon, const Astro* astro);
static double getFajIsh (double Lat, double dec, double Ang);
static double getAssr (double Lat, double dec, int mathhab);
static void base6hm(double bs, const Location* loc, const Method* conf,
Prayer* pt, int type);
static void getDayInfo( const Date* date, double gmt, int *lastDay, double *julianDay);
static void getPrayerTimesByDay ( const Location* loc, const Method* conf, int lastDay,
double julianDay, Prayer* pt, int type);
Astro astroCache; /* This global variable is used for caching values between
* multiple getPrayerTimesByDay() calls. You can disable this
* caching feature by moving this line to the start of the
* getPrayerTimesByDay() function. */
void getPrayerTimes ( const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
int lastDay;
double julianDay;
getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay);
getPrayerTimesByDay( loc, conf, lastDay, julianDay, pt, 0);
}
static void getPrayerTimesByDay ( const Location* loc, const Method* conf,
int lastDay, double julianDay, Prayer* pt,
int type)
{
int i, invalid;
double zu, sh, mg, fj, is, ar;
double lat, lon, dec;
double tempPrayer[6];
Astro tAstro;
lat = loc->degreeLat;
lon = loc->degreeLong;
invalid = 0;
/* Start by filling the tAstro structure with the appropriate astronomical
* values for this day. We also pass the cache structure to update and check
* if the actual values are already available. */
getAstroValuesByDay(julianDay, loc, &astroCache, &tAstro);
dec = DEG_TO_RAD(tAstro.dec[1]);
/* Get Prayer Times formulae results for this day of year and this
* location. The results are NOT the actual prayer times */
fj   = getFajIsh (lat, dec, conf->fajrAng);
sh   = getSunrise(loc, &tAstro);
zu   = getZuhr (lon, &tAstro);
ar   = getAssr (lat, dec, conf->mathhab);
mg   = getSunset(loc, &tAstro);
is   = getFajIsh (lat, dec, conf->ishaaAng);
/* Calculate all prayer times as Base-10 numbers in Normal circumstances */
/* Fajr */
if (fj == 99) {
tempPrayer[0] = 99;
invalid = 1;
}
else tempPrayer[0] = zu - fj;
if (sh == 99)
invalid = 1;
tempPrayer[1] = sh;
tempPrayer[2] = zu;
/* Assr */
if (ar == 99) {
tempPrayer[3] = 99;
invalid = 1;
}
else tempPrayer[3] = zu + ar;
if (mg == 99)
invalid = 1;
tempPrayer[4] = mg;
/* Ishaa */
if (is == 99) {
tempPrayer[5] = 99;
invalid = 1;
}
else tempPrayer[5] = zu + is;
/* Calculate all prayer times as Base-10 numbers in Extreme Latitudes (if
* needed) */
/* Reset status of extreme switches */
for (i=0; i<6; i++)
pt[i].isExtreme = 0;
if ((conf->extreme != NONE_EX) && !((conf->extreme == GOOD_INVALID ||
conf->extreme == LAT_INVALID ||
conf->extreme == SEVEN_NIGHT_INVALID ||
conf->extreme == SEVEN_DAY_INVALID ||
conf->extreme == HALF_INVALID) &&
(invalid == 0)))
{
double exdecPrev, exdecNext, degnLat;
double exZu=99, exFj=99, exIs=99, exAr=99, exIm=99, exSh=99, exMg=99;
double portion = 0;
double nGoodDay = 0;
int exinterval = 0;
Location exLoc = *loc;
Astro exAstroPrev;
Astro exAstroNext;
switch(conf->extreme)
{
/* Nearest Latitude (Method.nearestLat) */
case LAT_ALL:
case LAT_ALWAYS:
case LAT_INVALID:
/* FIXIT: we cannot compute this when interval is set because
* angle==0 . Only the if-invalid methods would work */
exLoc.degreeLat = conf->nearestLat;
exFj = getFajIsh(conf->nearestLat, dec, conf->fajrAng);
exIm = getFajIsh(conf->nearestLat, dec, conf->imsaakAng);
exSh = getSunrise(&exLoc, &tAstro);
exAr = getAssr(conf->nearestLat, dec, conf->mathhab);
exMg = getSunset(&exLoc, &tAstro);
exIs = getFajIsh(conf->nearestLat, dec, conf->ishaaAng);
switch(conf->extreme)
{
case LAT_ALL:
tempPrayer[0] = zu - exFj;
tempPrayer[1] = exSh;
tempPrayer[3] = zu + exAr;
tempPrayer[4] = exMg;
tempPrayer[5] = zu + exIs;
pt[0].isExtreme = 1;
pt[1].isExtreme = 1;
pt[2].isExtreme = 1;
pt[3].isExtreme = 1;
pt[4].isExtreme = 1;
pt[5].isExtreme = 1;
break;
case LAT_ALWAYS:
tempPrayer[0] = zu - exFj;
tempPrayer[5] = zu + exIs;
pt[0].isExtreme = 1;
pt[5].isExtreme = 1;
break;
case LAT_INVALID:
if (tempPrayer[0] == 99) {
tempPrayer[0] = zu - exFj;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
tempPrayer[5] = zu + exIs;
pt[5].isExtreme = 1;
}
break;
}
break;
/* Nearest Good Day */
case GOOD_ALL:
case GOOD_INVALID:
case GOOD_INVALID_SAME:
exAstroPrev = astroCache;
exAstroNext = astroCache;
/* Start by getting last or next nearest Good Day */
for(i=0; i <= lastDay; i++)
{
/* Last closest day */
nGoodDay = julianDay - i;
getAstroValuesByDay(nGoodDay, loc, &exAstroPrev, &tAstro);
exdecPrev = DEG_TO_RAD(tAstro.dec[1]);
exFj = getFajIsh(lat, exdecPrev, conf->fajrAng);
if (exFj != 99)
{
exIs = getFajIsh(lat, exdecPrev, conf->ishaaAng);
if (exIs != 99)
{
exZu = getZuhr (lon, &tAstro);
exSh = getSunrise (loc, &tAstro);
exAr = getAssr (lat, exdecPrev, conf->mathhab);
exMg = getSunset (loc, &tAstro);
break;
}
}
/* Next closest day */
nGoodDay = julianDay + i;
getAstroValuesByDay(nGoodDay, loc, &exAstroNext, &tAstro);
exdecNext = DEG_TO_RAD(tAstro.dec[1]);
exFj = getFajIsh(lat, exdecNext, conf->fajrAng);
if (exFj != 99)
{
exIs = getFajIsh(lat, exdecNext, conf->ishaaAng);
if (exIs != 99)
{
exZu = getZuhr (lon, &tAstro);
exSh = getSunrise (loc, &tAstro);
exAr = getAssr (lat, exdecNext, conf->mathhab);
exMg = getSunset (loc, &tAstro);
break;
}
}
}
switch(conf->extreme)
{
case GOOD_ALL:
tempPrayer[0] = exZu - exFj;
tempPrayer[1] = exSh;
tempPrayer[2] = exZu;
tempPrayer[3] = exZu + exAr;
tempPrayer[4] = exMg;
tempPrayer[5] = exZu + exIs;
for (i=0; i<6; i++)
pt[i].isExtreme = 1;
break;
case GOOD_INVALID:
if (tempPrayer[0] == 99) {
tempPrayer[0] = exZu - exFj;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
tempPrayer[5] = exZu + exIs;
pt[5].isExtreme = 1;
}
break;
case GOOD_INVALID_SAME:
if ((tempPrayer[0] == 99) || (tempPrayer[5] == 99))
{
tempPrayer[0] = exZu - exFj;
pt[0].isExtreme = 1;
tempPrayer[5] = exZu + exIs;
pt[5].isExtreme = 1;
}
break;
}
break;
case SEVEN_NIGHT_ALWAYS:
case SEVEN_NIGHT_INVALID:
case SEVEN_DAY_ALWAYS:
case SEVEN_DAY_INVALID:
case HALF_ALWAYS:
case HALF_INVALID:
/* FIXIT: For clarity, we may need to move the HALF_* methods
* into their own separate case statement. */
switch(conf->extreme)
{
case SEVEN_NIGHT_ALWAYS:
case SEVEN_NIGHT_INVALID:
portion = (24 - (tempPrayer[4] - tempPrayer[1])) * (1/7.0);
break;
case SEVEN_DAY_ALWAYS:
case SEVEN_DAY_INVALID:
portion = (tempPrayer[4] - tempPrayer[1]) * (1/7.0);
break;
case HALF_ALWAYS:
case HALF_INVALID:
portion = (24 - tempPrayer[4] - tempPrayer[1]) * (1/2.0);
break;
}
if (conf->extreme == SEVEN_NIGHT_INVALID ||
conf->extreme == SEVEN_DAY_INVALID ||
conf->extreme == HALF_INVALID)
{
if (tempPrayer[0] == 99) {
if  (conf->extreme == HALF_INVALID)
tempPrayer[0] =  portion - (conf->fajrInv / 60.0);
else tempPrayer[0] = tempPrayer[1] - portion;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
if  (conf->extreme == HALF_INVALID)
tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ;
else tempPrayer[5] = tempPrayer[4] + portion;
pt[5].isExtreme = 1;
}
} else { /* for the always methods */
if  (conf->extreme == HALF_ALWAYS) {
tempPrayer[0] = portion - (conf->fajrInv / 60.0);
tempPrayer[5] = portion + (conf->ishaaInv / 60.0) ;
}
else {
tempPrayer[0] = tempPrayer[1] - portion;
tempPrayer[5] = tempPrayer[4] + portion;
}
pt[0].isExtreme = 1;
pt[5].isExtreme = 1;
}
break;
case MIN_ALWAYS:
/* Do nothing here because this is implemented through fajrInv and
* ishaaInv structure members */
tempPrayer[0] = tempPrayer[1];
tempPrayer[5] = tempPrayer[4];
pt[0].isExtreme = 1;
pt[5].isExtreme = 1;
break;
case MIN_INVALID:
if (tempPrayer[0] == 99) {
exinterval = conf->fajrInv / 60.0;
tempPrayer[0] = tempPrayer[1] - exinterval;
pt[0].isExtreme = 1;
}
if (tempPrayer[5] == 99) {
exinterval = conf->ishaaInv / 60.0;
tempPrayer[5] = tempPrayer[4] + exinterval;
pt[5].isExtreme = 1;
}
break;
} /* end switch */
} /* end extreme */
/* Apply intervals if set */
if (conf->extreme != MIN_INVALID &&
conf->extreme != HALF_INVALID &&
conf->extreme != HALF_ALWAYS)
{
if (conf->fajrInv != 0) {
if (tempPrayer[1] != 99)
tempPrayer[0] = tempPrayer[1] - (conf->fajrInv / 60.0);
else tempPrayer[0] = 99;
}
if (conf->ishaaInv != 0) {
if (tempPrayer[4] != 99)
tempPrayer[5] = tempPrayer[4] + (conf->ishaaInv / 60.0);
else tempPrayer[5] = 99;
}
}
/* Final Step: Fill the Prayer array by doing decimal degree to
* Prayer structure conversion */
if (type == IMSAAK || type == NEXTFAJR)
base6hm(tempPrayer[0], loc, conf, &pt[0], type);
else {
for (i=0; i<6; i++)
base6hm(tempPrayer[i], loc, conf, &pt[i], i);
}
}
static void base6hm(double bs, const Location* loc, const Method* conf,
Prayer* pt, int type)
{
double min, sec;
/* Set to 99 and return if prayer is invalid */
if (bs == 99)
{
pt->hour = 99;
pt->minute = 99;
pt->second = 0;
return;
}
/* Add offsets */
if (conf->offset == 1) {
if (type == IMSAAK || type == NEXTFAJR)
bs += (conf->offList[0] / 60.0);
else  bs += (conf->offList[type] / 60.0);
}
/* Fix after minus offsets before midnight */
if (bs < 0) {
while (bs < 0)
bs = 24 + bs;
}
min = (bs - floor(bs)) * 60;
sec = (min - floor(min)) * 60;
/* Add rounding minutes */
if (conf->round == 1)
{
if (sec >= DEF_ROUND_SEC)
bs += 1/60.0;
/* compute again */
min = (bs - floor(bs)) * 60;
sec = 0;
} else if (conf->round == 2 || conf->round == 3)
{
switch(type)
{
case FAJR:
case ZUHR:
case ASSR:
case MAGHRIB:
case ISHAA:
case NEXTFAJR:
if (conf->round == 2) {
if (sec >= DEF_ROUND_SEC) {
bs += 1/60.0;
min = (bs - floor(bs)) * 60;
}
} else if (conf->round == 3)
{
if (sec >= AGGRESSIVE_ROUND_SEC) {
bs += 1/60.0;
min = (bs - floor(bs)) * 60;
}
}
sec = 0;
break;
case SHUROOQ:
case IMSAAK:
sec = 0;
break;
}
}
/* Add daylight saving time and fix after midnight times */
bs += loc->dst;
if (bs >= 24)
bs = fmod(bs, 24);
pt->hour   = (int)bs;
pt->minute = (int)min;
pt->second = (int)sec;
}
void getImsaak (const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
Method tmpConf;
int lastDay;
double julianDay;
Prayer temp[6];
tmpConf = *conf;
if (conf->fajrInv != 0) {
if (conf->imsaakInv == 0)
tmpConf.fajrInv += DEF_IMSAAK_INTERVAL;
else tmpConf.fajrInv += conf->imsaakInv;
} else if (conf->imsaakInv != 0) {
/* use an inv even if al-Fajr is computed (Indonesia?) */
tmpConf.offList[0] += (conf->imsaakInv * -1);
tmpConf.offset = 1;
} else {
tmpConf.fajrAng += conf->imsaakAng;
}
getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay);
getPrayerTimesByDay( loc, &tmpConf, lastDay, julianDay, temp, IMSAAK);
/* FIXIT: We probably need to check whether it's possible to compute
* Imsaak normally for some extreme methods first */
/* In case of an extreme Fajr time calculation use intervals for Imsaak and
* compute again */
if (temp[0].isExtreme != 0)
{
tmpConf = *conf;
if ( conf->imsaakInv == 0)
{
tmpConf.offList[0] -= DEF_IMSAAK_INTERVAL;
tmpConf.offset = 1;
} else
{
tmpConf.offList[0] -= conf->imsaakInv;
tmpConf.offset = 1;
}
getPrayerTimesByDay( loc, &tmpConf, lastDay, julianDay, temp, IMSAAK);
}
*pt = temp[0];
}
void getNextDayImsaak (const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
/* Copy the date structure and increment for next day.*/
Prayer temppt;
Date tempd = *date;
tempd.day++;
getImsaak (loc, conf, &tempd, &temppt);
*pt = temppt;
}
void getNextDayFajr (const Location* loc, const Method* conf, const Date* date,
Prayer* pt)
{
Prayer temp[6];
int lastDay;
double julianDay;
getDayInfo ( date, loc->gmtDiff, &lastDay, &julianDay);
getPrayerTimesByDay( loc, conf, lastDay, julianDay+1, temp, NEXTFAJR);
*pt = temp[0];
}
static double getFajIsh(double lat, double dec, double Ang)
{
double rlat = DEG_TO_RAD(lat);
/* Compute the hour angle */
double part1 = sin(DEG_TO_RAD(-Ang)) - (sin (rlat) * sin (dec));
double part2 = cos (rlat) * cos (dec);
double part3 = part1 / part2;
if ( part3 < -INVALID_TRIGGER || part3 > INVALID_TRIGGER)
return 99;
return DEG_TO_10_BASE * RAD_TO_DEG (acos(part3) );
}
static double getZuhr(double lon, const Astro* astro)
{
return getTransit(lon, astro);
}
static double getAssr(double lat, double dec, int mathhab)
{
double part1, part2, part3, part4, ndec;
double rlat = DEG_TO_RAD(lat);
/* Reverse if at or near the southern hemisphere */
ndec = dec;
if (lat < 0.0)
ndec = -dec;
part1 = mathhab + tan(rlat - ndec);
if (part1 < 1.0)
part1 = mathhab - tan(rlat - ndec);
part2 = (PI/2.0) - atan(part1);
/* Compute the hour angle */
part3 = sin(part2) - (sin(rlat) * sin(ndec));
part4 = (part3 / (cos(rlat) * cos(ndec)));
if ( part4 < -INVALID_TRIGGER || part4 > INVALID_TRIGGER)
return 99;
return DEG_TO_10_BASE * RAD_TO_DEG (acos(part4));
}
int getDayofYear(int year, int month, int day)
{
int i;
int isLeap = ((year & 3) == 0) && ((year % 100) != 0
|| (year % 400) == 0);
static char dayList[2][13] = {
{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}
};
for (i=1; i<month; i++)
day += dayList[isLeap][i];
return day;
}
double dms2Decimal(int deg, int min, double sec, char dir)
{
double sum = deg + ((min/60.0)+(sec/3600.0));
if (dir == 'S' || dir == 'W' || dir == 's' || dir == 'w')
return sum * (-1.0);
return sum;
}
void decimal2Dms(double decimal, int *deg, int *min, double *sec)
{
double tempmin, tempsec, n1, n2;
tempmin = modf(decimal, &n1) * 60.0;
tempsec = modf(tempmin, &n2) * 60.0;
*deg = (int)n1;
*min = (int)n2;
*sec = tempsec;
}
static void getDayInfo ( const Date* date, double gmt, int *lastDay,
double *julianDay)
{
int ld;
double jd;
ld = getDayofYear(date->year, 12, 31);
jd = getJulianDay(date, gmt);
*lastDay = ld;
*julianDay = jd;
}
void getMethod(int n, Method* conf)
{
int i;
conf->fajrInv = 0;
conf->ishaaInv = 0;
conf->imsaakInv = 0;
conf->mathhab = 1;
conf->round = 2;
conf->nearestLat = DEF_NEAREST_LATITUDE;
conf->imsaakAng = DEF_IMSAAK_ANGLE;
conf->extreme = 5;
conf->offset = 0;
for (i = 0; i < 6; i++) {
conf->offList[i] = 0;
}
switch(n)
{
case NONE:
conf->fajrAng = 0.0;
conf->ishaaAng = 0.0;
break;
case EGYPT_SURVEY:
conf->fajrAng = 20;
conf->ishaaAng = 18;
break;
case KARACHI_SHAF:
conf->fajrAng = 18;
conf->ishaaAng = 18;
break;
case KARACHI_HANAF:
conf->fajrAng = 18;
conf->ishaaAng = 18;
conf->mathhab = 2;
break;
case NORTH_AMERICA:
conf->fajrAng = 15;
conf->ishaaAng = 15;
break;
case MUSLIM_LEAGUE:
conf->fajrAng = 18;
conf->ishaaAng = 17;
break;
case UMM_ALQURRA:
conf->fajrAng = 19;
conf->ishaaAng = 0.0;
conf->ishaaInv = 90;
break;
case FIXED_ISHAA:
conf->fajrAng = 19.5;
conf->ishaaAng = 0.0;
conf->ishaaInv = 90;
break;
case EGYPT_NEW:
conf->fajrAng = 19.5;
conf->ishaaAng = 17.5;
break;
}
}
/* Obtaining the direction of the shortest distance towards Qibla by using the
* great circle formula */
double getNorthQibla(const Location* loc)
{
/* FIXIT: reduce DEG_TO_RAD usage */
double num, denom;
num = sin (DEG_TO_RAD (loc->degreeLong) - DEG_TO_RAD (KAABA_LONG));
denom = (cos (DEG_TO_RAD (loc->degreeLat)) * tan (DEG_TO_RAD (KAABA_LAT))) -
(sin (DEG_TO_RAD (loc->degreeLat)) * ((cos ((DEG_TO_RAD (loc->degreeLong) -
DEG_TO_RAD(KAABA_LONG))))));
return RAD_TO_DEG (atan2 (num, denom));
}
[/sourcecode]

 

Be the first to comment

Leave a Reply

Your email address will not be published.


*