[Dokumentasi Kode Sumber] (5) : prayer.c

[sourcecode language=”cpp”]
/************************************************************************
* $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.


*