| [649] | 1 | #include <stdio.h>
 | 
|---|
 | 2 | #include <math.h>
 | 
|---|
 | 3 | #include "aa_hadec.h"
 | 
|---|
 | 4 | #define GOODATAN2
 | 
|---|
 | 5 | #define PI M_PI
 | 
|---|
 | 6 | 
 | 
|---|
 | 7 | static void aaha_aux (double lat, double x, double y, double* p, double* q);
 | 
|---|
 | 8 | 
 | 
|---|
 | 9 | 
 | 
|---|
 | 10 | /* given latitude (n+, radians), lat, altitude (up+, radians), alt, and
 | 
|---|
 | 11 |  * azimuth (angle round to the east from north+, radians),
 | 
|---|
 | 12 |  * return hour angle (radians), ha, and declination (radians), dec.
 | 
|---|
 | 13 |  */
 | 
|---|
 | 14 | void aa_hadec (double lat, double alt, double az, double* ha, double* dec)
 | 
|---|
 | 15 | {
 | 
|---|
 | 16 |         aaha_aux (lat, az, alt, ha, dec);
 | 
|---|
 | 17 | }
 | 
|---|
 | 18 | 
 | 
|---|
 | 19 | /* given latitude (n+, radians), lat, hour angle (radians), ha, and declination
 | 
|---|
 | 20 |  * (radians), dec,
 | 
|---|
 | 21 |  * return altitude (up+, radians), alt, and
 | 
|---|
 | 22 |  * azimuth (angle round to the east from north+, radians),
 | 
|---|
 | 23 |  */
 | 
|---|
 | 24 | void hadec_aa (double lat, double ha, double dec, double* alt, double* az)
 | 
|---|
 | 25 | {
 | 
|---|
 | 26 |         aaha_aux (lat, ha, dec, az, alt);
 | 
|---|
 | 27 | }
 | 
|---|
 | 28 | 
 | 
|---|
 | 29 | /* the actual formula is the same for both transformation directions so
 | 
|---|
 | 30 |  * do it here once for each way.
 | 
|---|
 | 31 |  * N.B. all arguments are in radians.
 | 
|---|
 | 32 |  */
 | 
|---|
 | 33 | static void
 | 
|---|
 | 34 | aaha_aux (double lat, double x, double y, double* p, double* q)
 | 
|---|
 | 35 | {
 | 
|---|
 | 36 |         static double lastlat = -1000.;
 | 
|---|
 | 37 |         static double sinlastlat, coslastlat;
 | 
|---|
 | 38 |         double sy, cy;
 | 
|---|
 | 39 |         double sx, cx;
 | 
|---|
 | 40 | #ifndef GOODATAN2
 | 
|---|
 | 41 |         double sq, cq;
 | 
|---|
 | 42 |         double a;
 | 
|---|
 | 43 |         double cp;
 | 
|---|
 | 44 | #endif
 | 
|---|
 | 45 | 
 | 
|---|
 | 46 |         /* latitude doesn't change much, so try to reuse the sin and cos evals.
 | 
|---|
 | 47 |          */
 | 
|---|
 | 48 |         if (lat != lastlat) {
 | 
|---|
 | 49 |             sinlastlat = sin (lat);
 | 
|---|
 | 50 |             coslastlat = cos (lat);
 | 
|---|
 | 51 |             lastlat = lat;
 | 
|---|
 | 52 |         }
 | 
|---|
 | 53 | 
 | 
|---|
 | 54 |         sy = sin (y);
 | 
|---|
 | 55 |         cy = cos (y);
 | 
|---|
 | 56 |         sx = sin (x);
 | 
|---|
 | 57 |         cx = cos (x);
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 | /* define GOODATAN2 if atan2 returns full range -PI through +PI.
 | 
|---|
 | 60 |  */
 | 
|---|
 | 61 | #ifdef GOODATAN2
 | 
|---|
 | 62 |         *q = asin ((sy*sinlastlat) + (cy*coslastlat*cx));
 | 
|---|
 | 63 |         *p = atan2 (-cy*sx, -cy*cx*sinlastlat + sy*coslastlat);
 | 
|---|
 | 64 | #else
 | 
|---|
 | 65 | #define EPS     (1e-20)
 | 
|---|
 | 66 |         sq = (sy*sinlastlat) + (cy*coslastlat*cx);
 | 
|---|
 | 67 |         *q = asin (sq);
 | 
|---|
 | 68 |         cq = cos (*q);
 | 
|---|
 | 69 |         a = coslastlat*cq;
 | 
|---|
 | 70 |         if (a > -EPS && a < EPS)
 | 
|---|
 | 71 |             a = a < 0 ? -EPS : EPS; /* avoid / 0 */
 | 
|---|
 | 72 |         cp = (sy - (sinlastlat*sq))/a;
 | 
|---|
 | 73 |         if (cp >= 1.0)  /* the /a can be slightly > 1 */
 | 
|---|
 | 74 |             *p = 0.0;
 | 
|---|
 | 75 |         else if (cp <= -1.0)
 | 
|---|
 | 76 |             *p = PI;
 | 
|---|
 | 77 |         else
 | 
|---|
 | 78 |             *p = acos ((sy - (sinlastlat*sq))/a);
 | 
|---|
 | 79 |         if (sx>0) *p = 2.0*PI - *p;
 | 
|---|
 | 80 | #endif
 | 
|---|
 | 81 | }
 | 
|---|