213 lines
4.2 KiB
C
213 lines
4.2 KiB
C
#include <math.h> /* for sin, cos, fabs, sqrt, atan, etc */
|
|
|
|
#define DegPerRad 57.29577951308232087680
|
|
#define RadPerDeg 0.01745329251994329576
|
|
|
|
extern double Glon, SinGlat, CosGlat, TimeZone;
|
|
|
|
double cosEPS = 0.91748;
|
|
double sinEPS = 0.39778;
|
|
double P2 = 6.283185307;
|
|
|
|
int Interp(double ym, double y0, double yp, double *xe, double *ye, double *z1, double *z2, int *nz){
|
|
|
|
double a, b, c, d;
|
|
|
|
*nz = 0;
|
|
a = 0.5*(ym+yp)-y0;
|
|
b = 0.5*(yp-ym);
|
|
c = y0;
|
|
*xe = -b/(2.0*a);
|
|
*ye = (a*(*xe) + b) * (*xe) + c;
|
|
d = b*b - 4.0*a*c;
|
|
|
|
if (d >= 0){
|
|
double dx;
|
|
|
|
dx = 0.5*sqrt(d)/fabs(a);
|
|
*z1 = *xe - dx;
|
|
*z2 = *xe+dx;
|
|
if (fabs(*z1) <= 1.0) *nz += 1;
|
|
if (fabs(*z2) <= 1.0) *nz += 1;
|
|
if (*z1 < -1.0) *z1 = *z2;
|
|
}
|
|
|
|
return(0);
|
|
|
|
|
|
}
|
|
|
|
void SunRise(int year, int month, int day, double LocalHour, double *UTRise, double *UTSet){
|
|
|
|
double UT, ym, SinH0;
|
|
double xe, ye, z1, z2, SinH(), hour24();
|
|
int Rise, Set, nz;
|
|
|
|
(void) LocalHour;
|
|
SinH0 = sin( -50.0/60.0 * RadPerDeg );
|
|
|
|
|
|
UT = 1.0+TimeZone;
|
|
*UTRise = -999.0;
|
|
*UTSet = -999.0;
|
|
Rise = Set = 0;
|
|
ym = SinH(year, month, day, UT-1.0) - SinH0;
|
|
|
|
while ( (UT <= 24.0+TimeZone) ) {
|
|
double y0, yp;
|
|
|
|
y0 = SinH(year, month, day, UT) - SinH0;
|
|
yp = SinH(year, month, day, UT+1.0) - SinH0;
|
|
|
|
Interp(ym, y0, yp, &xe, &ye, &z1, &z2, &nz);
|
|
|
|
switch(nz){
|
|
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
if (ym < 0.0){
|
|
*UTRise = UT + z1;
|
|
Rise = 1;
|
|
} else {
|
|
*UTSet = UT + z1;
|
|
Set = 1;
|
|
}
|
|
break;
|
|
case 2:
|
|
if (ye < 0.0){
|
|
*UTRise = UT + z2;
|
|
*UTSet = UT + z1;
|
|
} else {
|
|
*UTRise = UT + z1;
|
|
*UTSet = UT + z2;
|
|
}
|
|
Rise = 1;
|
|
Set = 1;
|
|
break;
|
|
}
|
|
ym = yp;
|
|
UT += 2.0;
|
|
|
|
}
|
|
|
|
if (Rise){
|
|
*UTRise -= TimeZone;
|
|
*UTRise = hour24(*UTRise);
|
|
} else {
|
|
*UTRise = -999.0;
|
|
}
|
|
|
|
if (Set){
|
|
*UTSet -= TimeZone;
|
|
*UTSet = hour24(*UTSet);
|
|
} else {
|
|
*UTSet = -999.0;
|
|
}
|
|
|
|
}
|
|
|
|
double SinH(int year, int month, int day, double UT){
|
|
|
|
double TU, frac(), jd();
|
|
double RA_Sun, DEC_Sun, gmst, lmst, Tau;
|
|
double M, DL, L, SL, X, Y, Z, RHO;
|
|
|
|
|
|
TU = (jd(year, month, day, UT+62.0/3600.0) - 2451545.0)/36525.0;
|
|
|
|
M = P2*frac(0.993133 + 99.997361*TU);
|
|
DL = 6893.0*sin(M) + 72.0*sin(2.0*M);
|
|
L = P2*frac(0.7859453 + M/P2 + (6191.2*TU+DL)/1296e3);
|
|
SL = sin(L);
|
|
X = cos(L); Y = cosEPS*SL; Z = sinEPS*SL; RHO = sqrt(1.0-Z*Z);
|
|
DEC_Sun = atan2(Z, RHO);
|
|
RA_Sun = (48.0/P2)*atan(Y/(X+RHO));
|
|
if (RA_Sun < 0) RA_Sun += 24.0;
|
|
|
|
RA_Sun = RA_Sun*15.0*RadPerDeg;
|
|
|
|
/*
|
|
* Compute Greenwich Mean Sidereal Time (gmst)
|
|
*/
|
|
UT = 24.0*frac( UT/24.0 );
|
|
|
|
gmst = 6.697374558 + 1.0*UT + (8640184.812866+(0.093104-6.2e-6*TU)*TU)*TU/3600.0;
|
|
lmst = 24.0*frac( (gmst-Glon/15.0) / 24.0 );
|
|
|
|
Tau = 15.0*lmst*RadPerDeg - RA_Sun;
|
|
return( SinGlat*sin(DEC_Sun) + CosGlat*cos(DEC_Sun)*cos(Tau) );
|
|
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Compute the Julian Day number for the given date.
|
|
* Julian Date is the number of days since noon of Jan 1 4713 B.C.
|
|
*/
|
|
double jd(ny, nm, nd, UT)
|
|
int ny, nm, nd;
|
|
double UT;
|
|
{
|
|
double B, C, D, JD, day;
|
|
|
|
day = nd + UT/24.0;
|
|
|
|
|
|
if ((nm == 1) || (nm == 2)){
|
|
ny = ny - 1;
|
|
nm = nm + 12;
|
|
}
|
|
|
|
if (((double)ny+nm/12.0+day/365.25)>=(1582.0+10.0/12.0+15.0/365.25)){
|
|
double A;
|
|
|
|
A = ((int)(ny / 100.0));
|
|
B = 2.0 - A + (int)(A/4.0);
|
|
}
|
|
else{
|
|
B = 0.0;
|
|
}
|
|
|
|
if (ny < 0.0){
|
|
C = (int)((365.25*(double)ny) - 0.75);
|
|
}
|
|
else{
|
|
C = (int)(365.25*(double)ny);
|
|
}
|
|
|
|
D = (int)(30.6001*(double)(nm+1));
|
|
|
|
|
|
JD = B + C + D + day + 1720994.5;
|
|
return(JD);
|
|
|
|
}
|
|
|
|
double hour24(hour)
|
|
double hour;
|
|
{
|
|
int n;
|
|
|
|
if (hour < 0.0){
|
|
n = (int)(hour/24.0) - 1;
|
|
return(hour-n*24.0);
|
|
}
|
|
else if (hour > 24.0){
|
|
n = (int)(hour/24.0);
|
|
return(hour-n*24.0);
|
|
}
|
|
else{
|
|
return(hour);
|
|
}
|
|
}
|
|
|
|
double frac(double x){
|
|
|
|
x -= (int)x;
|
|
return( (x<0) ? x+1.0 : x );
|
|
|
|
}
|
|
|