LTP GCOV extension - code coverage report
Current view: directory - ext/date/lib - astro.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 75
Code covered: 0.0 % Executed lines: 0
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2007 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Algorithms are taken from a public domain source by Paul             |
      16                 :    | Schlyter, who wrote this in December 1992                            |
      17                 :    +----------------------------------------------------------------------+
      18                 :    | Authors: Derick Rethans <derick@derickrethans.nl>                    |
      19                 :    +----------------------------------------------------------------------+
      20                 :  */
      21                 : 
      22                 : /* $Id: astro.c,v 1.1.2.4.2.1 2007/01/01 09:35:48 sebastian Exp $ */
      23                 : 
      24                 : #include <stdio.h>
      25                 : #include <math.h>
      26                 : #include "timelib.h"
      27                 : 
      28                 : #define days_since_2000_Jan_0(y,m,d) \
      29                 :         (367L*(y)-((7*((y)+(((m)+9)/12)))/4)+((275*(m))/9)+(d)-730530L)
      30                 : 
      31                 : #ifndef PI
      32                 :  #define PI        3.1415926535897932384
      33                 : #endif
      34                 : 
      35                 : #define RADEG     ( 180.0 / PI )
      36                 : #define DEGRAD    ( PI / 180.0 )
      37                 : 
      38                 : /* The trigonometric functions in degrees */
      39                 : 
      40                 : #define sind(x)  sin((x)*DEGRAD)
      41                 : #define cosd(x)  cos((x)*DEGRAD)
      42                 : #define tand(x)  tan((x)*DEGRAD)
      43                 : 
      44                 : #define atand(x)    (RADEG*atan(x))
      45                 : #define asind(x)    (RADEG*asin(x))
      46                 : #define acosd(x)    (RADEG*acos(x))
      47                 : #define atan2d(y,x) (RADEG*atan2(y,x))
      48                 : 
      49                 : 
      50                 : /* Following are some macros around the "workhorse" function __daylen__ */
      51                 : /* They mainly fill in the desired values for the reference altitude    */
      52                 : /* below the horizon, and also selects whether this altitude should     */
      53                 : /* refer to the Sun's center or its upper limb.                         */
      54                 : 
      55                 : 
      56                 : #include "astro.h"
      57                 : 
      58                 : /******************************************************************/
      59                 : /* This function reduces any angle to within the first revolution */
      60                 : /* by subtracting or adding even multiples of 360.0 until the     */
      61                 : /* result is >= 0.0 and < 360.0                                   */
      62                 : /******************************************************************/
      63                 : 
      64                 : #define INV360    (1.0 / 360.0)
      65                 : 
      66                 : /*****************************************/
      67                 : /* Reduce angle to within 0..360 degrees */
      68                 : /*****************************************/
      69                 : static double astro_revolution(double x)
      70               0 : {
      71               0 :         return (x - 360.0 * floor(x * INV360));
      72                 : }
      73                 : 
      74                 : /*********************************************/
      75                 : /* Reduce angle to within +180..+180 degrees */
      76                 : /*********************************************/
      77                 : static double astro_rev180( double x )
      78               0 : {
      79               0 :         return (x - 360.0 * floor(x * INV360 + 0.5));
      80                 : }
      81                 : 
      82                 : /*******************************************************************/
      83                 : /* This function computes GMST0, the Greenwich Mean Sidereal Time  */
      84                 : /* at 0h UT (i.e. the sidereal time at the Greenwhich meridian at  */
      85                 : /* 0h UT).  GMST is then the sidereal time at Greenwich at any     */
      86                 : /* time of the day.  I've generalized GMST0 as well, and define it */
      87                 : /* as:  GMST0 = GMST - UT  --  this allows GMST0 to be computed at */
      88                 : /* other times than 0h UT as well.  While this sounds somewhat     */
      89                 : /* contradictory, it is very practical:  instead of computing      */
      90                 : /* GMST like:                                                      */
      91                 : /*                                                                 */
      92                 : /*  GMST = (GMST0) + UT * (366.2422/365.2422)                      */
      93                 : /*                                                                 */
      94                 : /* where (GMST0) is the GMST last time UT was 0 hours, one simply  */
      95                 : /* computes:                                                       */
      96                 : /*                                                                 */
      97                 : /*  GMST = GMST0 + UT                                              */
      98                 : /*                                                                 */
      99                 : /* where GMST0 is the GMST "at 0h UT" but at the current moment!   */
     100                 : /* Defined in this way, GMST0 will increase with about 4 min a     */
     101                 : /* day.  It also happens that GMST0 (in degrees, 1 hr = 15 degr)   */
     102                 : /* is equal to the Sun's mean longitude plus/minus 180 degrees!    */
     103                 : /* (if we neglect aberration, which amounts to 20 seconds of arc   */
     104                 : /* or 1.33 seconds of time)                                        */
     105                 : /*                                                                 */
     106                 : /*******************************************************************/
     107                 : 
     108                 : static double astro_GMST0(double d)
     109               0 : {
     110                 :         double sidtim0;
     111                 :         /* Sidtime at 0h UT = L (Sun's mean longitude) + 180.0 degr  */
     112                 :         /* L = M + w, as defined in sunpos().  Since I'm too lazy to */
     113                 :         /* add these numbers, I'll let the C compiler do it for me.  */
     114                 :         /* Any decent C compiler will add the constants at compile   */
     115                 :         /* time, imposing no runtime or code overhead.               */
     116               0 :         sidtim0 = astro_revolution((180.0 + 356.0470 + 282.9404) + (0.9856002585 + 4.70935E-5) * d);
     117               0 :         return sidtim0;
     118                 : } 
     119                 : 
     120                 : /* This function computes the Sun's position at any instant */
     121                 : 
     122                 : /******************************************************/
     123                 : /* Computes the Sun's ecliptic longitude and distance */
     124                 : /* at an instant given in d, number of days since     */
     125                 : /* 2000 Jan 0.0.  The Sun's ecliptic latitude is not  */
     126                 : /* computed, since it's always very near 0.           */
     127                 : /******************************************************/
     128                 : static void astro_sunpos(double d, double *lon, double *r)
     129               0 : {
     130                 :         double M,         /* Mean anomaly of the Sun */
     131                 :                w,         /* Mean longitude of perihelion */
     132                 :                           /* Note: Sun's mean longitude = M + w */
     133                 :                e,         /* Eccentricity of Earth's orbit */
     134                 :                E,         /* Eccentric anomaly */
     135                 :                x, y,      /* x, y coordinates in orbit */
     136                 :                v;         /* True anomaly */
     137                 : 
     138                 :         /* Compute mean elements */
     139               0 :         M = astro_revolution(356.0470 + 0.9856002585 * d);
     140               0 :         w = 282.9404 + 4.70935E-5 * d;
     141               0 :         e = 0.016709 - 1.151E-9 * d;
     142                 : 
     143                 :         /* Compute true longitude and radius vector */
     144               0 :         E = M + e * RADEG * sind(M) * (1.0 + e * cosd(M));
     145               0 :         x = cosd(E) - e;
     146               0 :         y = sqrt(1.0 - e*e) * sind(E);
     147               0 :         *r = sqrt(x*x + y*y);              /* Solar distance */
     148               0 :         v = atan2d(y, x);                  /* True anomaly */
     149               0 :         *lon = v + w;                        /* True solar longitude */
     150               0 :         if (*lon >= 360.0) {
     151               0 :                 *lon -= 360.0;                   /* Make it 0..360 degrees */
     152                 :         }
     153               0 : }
     154                 : 
     155                 : static void astro_sun_RA_dec(double d, double *RA, double *dec, double *r)
     156               0 : {
     157                 :         double lon, obl_ecl, x, y, z;
     158                 : 
     159                 :         /* Compute Sun's ecliptical coordinates */
     160               0 :         astro_sunpos(d, &lon, r);
     161                 : 
     162                 :         /* Compute ecliptic rectangular coordinates (z=0) */
     163               0 :         x = *r * cosd(lon);
     164               0 :         y = *r * sind(lon);
     165                 : 
     166                 :         /* Compute obliquity of ecliptic (inclination of Earth's axis) */
     167               0 :         obl_ecl = 23.4393 - 3.563E-7 * d;
     168                 : 
     169                 :         /* Convert to equatorial rectangular coordinates - x is unchanged */
     170               0 :         z = y * sind(obl_ecl);
     171               0 :         y = y * cosd(obl_ecl);
     172                 : 
     173                 :         /* Convert to spherical coordinates */
     174               0 :         *RA = atan2d(y, x);
     175               0 :         *dec = atan2d(z, sqrt(x*x + y*y));
     176               0 : }
     177                 : 
     178                 : /**
     179                 :  * Note: timestamp = unixtimestamp (NEEDS to be 00:00:00 UT)
     180                 :  *       Eastern longitude positive, Western longitude negative       
     181                 :  *       Northern latitude positive, Southern latitude negative       
     182                 :  *       The longitude value IS critical in this function!            
     183                 :  *       altit = the altitude which the Sun should cross              
     184                 :  *               Set to -35/60 degrees for rise/set, -6 degrees       
     185                 :  *               for civil, -12 degrees for nautical and -18          
     186                 :  *               degrees for astronomical twilight.                   
     187                 :  *         upper_limb: non-zero -> upper limb, zero -> center         
     188                 :  *               Set to non-zero (e.g. 1) when computing rise/set     
     189                 :  *               times, and to zero when computing start/end of       
     190                 :  *               twilight.                                            
     191                 :  *        *rise = where to store the rise time                        
     192                 :  *        *set  = where to store the set  time                        
     193                 :  *                Both times are relative to the specified altitude,  
     194                 :  *                and thus this function can be used to compute       
     195                 :  *                various twilight times, as well as rise/set times   
     196                 :  * Return value:  0 = sun rises/sets this day, times stored at        
     197                 :  *                    *trise and *tset.                               
     198                 :  *               +1 = sun above the specified "horizon" 24 hours.     
     199                 :  *                    *trise set to time when the sun is at south,    
     200                 :  *                    minus 12 hours while *tset is set to the south  
     201                 :  *                    time plus 12 hours. "Day" length = 24 hours     
     202                 :  *               -1 = sun is below the specified "horizon" 24 hours   
     203                 :  *                    "Day" length = 0 hours, *trise and *tset are    
     204                 :  *                    both set to the time when the sun is at south.  
     205                 :  *                                                                    
     206                 :  */
     207                 : int timelib_astro_rise_set_altitude(timelib_time *t_loc, double lon, double lat, double altit, int upper_limb, double *h_rise, double *h_set, timelib_sll *ts_rise, timelib_sll *ts_set, timelib_sll *ts_transit)
     208               0 : {
     209                 :         double  d,  /* Days since 2000 Jan 0.0 (negative before) */
     210                 :         sr,         /* Solar distance, astronomical units */
     211                 :         sRA,        /* Sun's Right Ascension */
     212                 :         sdec,       /* Sun's declination */
     213                 :         sradius,    /* Sun's apparent radius */
     214                 :         t,          /* Diurnal arc */
     215                 :         tsouth,     /* Time when Sun is at south */
     216                 :         sidtime;    /* Local sidereal time */
     217                 :         timelib_time *t_utc;
     218                 :         timelib_sll   timestamp, old_sse;
     219                 : 
     220               0 :         int rc = 0; /* Return cde from function - usually 0 */
     221                 : 
     222                 :         /* Normalize time */
     223               0 :         old_sse = t_loc->sse;
     224               0 :         t_loc->h = 12;
     225               0 :         t_loc->i = t_loc->s = 0;
     226               0 :         timelib_update_ts(t_loc, NULL);
     227                 : 
     228                 :         /* Calculate TS belonging to UTC 00:00 of the current day */
     229               0 :         t_utc = timelib_time_ctor();
     230               0 :         t_utc->y = t_loc->y;
     231               0 :         t_utc->m = t_loc->m;
     232               0 :         t_utc->d = t_loc->d;
     233               0 :         t_utc->h = t_utc->i = t_utc->s = 0;
     234               0 :         timelib_update_ts(t_utc, NULL);
     235                 : 
     236                 :         /* Compute d of 12h local mean solar time */
     237               0 :         timestamp = t_loc->sse;
     238               0 :         d = timelib_ts_to_juliandate(timestamp) - lon/360.0;
     239                 : 
     240                 :         /* Compute local sidereal time of this moment */
     241               0 :         sidtime = astro_revolution(astro_GMST0(d) + 180.0 + lon);
     242                 : 
     243                 :         /* Compute Sun's RA + Decl at this moment */
     244               0 :         astro_sun_RA_dec( d, &sRA, &sdec, &sr );
     245                 : 
     246                 :         /* Compute time when Sun is at south - in hours UT */
     247               0 :         tsouth = 12.0 - astro_rev180(sidtime - sRA) / 15.0;
     248                 : 
     249                 :         /* Compute the Sun's apparent radius, degrees */
     250               0 :         sradius = 0.2666 / sr;
     251                 : 
     252                 :         /* Do correction to upper limb, if necessary */
     253               0 :         if (upper_limb) {
     254               0 :                 altit -= sradius;
     255                 :         }
     256                 : 
     257                 :         /* Compute the diurnal arc that the Sun traverses to reach */
     258                 :         /* the specified altitude altit: */
     259                 :         {
     260                 :                 double cost;
     261               0 :                 cost = (sind(altit) - sind(lat) * sind(sdec)) / (cosd(lat) * cosd(sdec));
     262               0 :                 *ts_transit = t_utc->sse + (tsouth * 3600);
     263               0 :                 if (cost >= 1.0) {
     264               0 :                         rc = -1;
     265               0 :                         t = 0.0;       /* Sun always below altit */
     266                 : 
     267               0 :                         *ts_rise = *ts_set = t_utc->sse + (tsouth * 3600);
     268               0 :                 } else if (cost <= -1.0) {
     269               0 :                         rc = +1;
     270               0 :                         t = 12.0;      /* Sun always above altit */
     271                 : 
     272               0 :                         *ts_rise = t_loc->sse - (12 * 3600);
     273               0 :                         *ts_set  = t_loc->sse + (12 * 3600);
     274                 :                 } else {
     275               0 :                         t = acosd(cost) / 15.0;   /* The diurnal arc, hours */
     276                 : 
     277                 :                         /* Store rise and set times - as Unix Timestamp */
     278               0 :                         *ts_rise = ((tsouth - t) * 3600) + t_utc->sse;
     279               0 :                         *ts_set  = ((tsouth + t) * 3600) + t_utc->sse;
     280                 : 
     281               0 :                         *h_rise = (tsouth - t);
     282               0 :                         *h_set  = (tsouth + t);
     283                 :                 }
     284                 :         }
     285                 : 
     286                 :         /* Kill temporary time and restore original sse */
     287               0 :         timelib_time_dtor(t_utc);
     288               0 :         t_loc->sse = old_sse;
     289                 : 
     290               0 :         return rc;
     291                 : }
     292                 : 
     293                 : double timelib_ts_to_juliandate(timelib_sll ts)
     294               0 : {
     295                 :         double tmp;
     296                 : 
     297               0 :         tmp = ts;
     298               0 :         tmp /= 86400;
     299               0 :         tmp += 2440587.5;
     300               0 :         tmp -= 2451543;
     301                 : 
     302               0 :         return tmp;
     303                 : }

Generated by: LTP GCOV extension version 1.5