/* **********************************************************************
 * *	                                                                *
 * *                   Sun position routine                             * 
 * *                                                                    *
 * ********************************************************************** 
 * File: utils/antennax/sun_position.c
 *
 *            COPYRIGHT (c) 1992, 1998, 2001, 2004, 2006 BY
 *             VAISALA INC., WESTFORD MASSACHUSETTS, U.S.A. 
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED. 
 */

#include <math.h>

#include "sigtypes.h"
#include "user_lib.h"
#include "antenna_lib.h"

static void sas
( double s1,
  double *ps2,
  double s3,
  double *pa1,   /* All angles in radians */
  double a2,
  double *pa3 );

/* ------------------------------
 */
void sun_position
  (SINT4  iyear_a,             /* year */
   SINT4  iyday_a,             /* Day of year, origin 1 */
   SINT4  idsec_a,             /* Seconds of day */
   double fposition_a[2],      /* Position on earth in long/lat degrees */
   double *fAzimuth_a,         /* Azimuth in radians */
   double *fElevation_a )      /* Elevation in radians */
{
  /* Calculate the sun's position by the method presented by
   * Jean Meeus in Astronomical Formulae for Calculators
   * chapters--
   *   18  Solar Coordinates
   *    7  Sidereal Time
   *   15  Nutation
   *   21  Equation of Time
   * are used
   * -- Input --
   *  tgmt : time of GMT observation
   * --output--
   *  zen  : Zenith distance (degrees)
   *  azi  : Azimuth (degrees)
   */
  static double s1, s2, s3, a1, a2, a3;
  double fgmt_hours, fazimuth, floc_hours, ft, tp, obl, amb, ambd1, ambda;
  double anom, ann, annom, amr, anr, omeg, omega, sinom, sinm, s2l;
  double cent, solong, sido, sid, sidloc, av, bv, cj, dl, ec, aav, bbv, ccj;
  double ddl, eec, corlo, solap, sidap, oblap, solr, oblr, rdec, ra, sha, rsha;
  SINT4 it;

  double pi = 3.1415926535898;

  /* Side 3 is the distance from the North pole to the observation point: */
  s3 = (90.0 - fposition_a[1]) * pi/180.0;

  /* Longitude in hours */

  fgmt_hours = ((double)idsec_a ) /3600.0;

  /*
   * Local true time is calculated by taking the gmt, and adding the longitude
   * expressed in hours.  Note that longitudes are positive east, negative west.
   */
  floc_hours = fgmt_hours + ( fposition_a[0] / 15.0 );
  if (floc_hours >= 24.) floc_hours = floc_hours - 24.;
  if (floc_hours < 0.) floc_hours = floc_hours + 24.;

  /* Time in days: */
  it = ((SINT4)( 365.25 * (double)(iyear_a-1901) )) + 365 + iyday_a;

  /* Time in centuries from 1900 january 0.5 of Greenwitch
   * midnight of the day of observation
   */
  ft = (((double)it)-0.5) /36525.0;
  /* Time of observation in centuries */
  tp = ft + ( fgmt_hours / 876600.);
  /* Obliquity of the ecliptic */
  obl = 23.452294 - (.0130125 + (1.64E-6 - 5.03e-7 * tp) * tp ) * tp;
  /* Eccentricity of earth's orbit */
  /* ecs = 0.01675104 - (4.18e-5 + 1.26e-7 * tp ) * tp; */
  /* Mean gecoentric longitude of the sun */
  amb = ( .76892 + 3.025e-4 * tp) * tp;
  ambd1 = 279.69668 + amb + 36000. * tp;
  ambda = fmod( ambd1, 360.0);

  /* Mean annomally of the sun */
  anom = -(.95025 + (1.5e-4 + 3.3e-6 * tp) * tp ) * tp;
  ann = -1.52417 + anom + 36000. * tp;
  annom = fmod(ann, 360.0);
  amr = ambda * pi/180.0;
  anr = annom * pi/180.0;
  /* Longitude of moon's ascending node */
  /* Make the solution positive for the next few centuries */
  omeg = 2419.1833 - (1934.142 - 2.078e-3 * tp ) * tp;
  omeg = fmod(omeg, 360.0 );
  omega = omeg * pi/180.0;
  /* A nutation term */
  sinom = .00479 * sin(omega);
  sinm = sin(anr);
  s2l = sin(2. * amr);
  /* Nore nutation */
  sinom = sinom + .000354 * s2l;
  /* Equation of the center -- A specialized form of 
   * Keppler's equation for the sun
   */
  cent = (-.001172 * SQUARE(sinm) + 
	  (1.920339 - (4.789e-3 + 1.4e-5 * tp) * tp)) * sinm +
	    (.020094 - 1.e-4 * tp) * sin(2. * anr);
  solong = ambda + cent;
  /* Sidereal time */
  sido = (.00002581 * ft + .051262) * ft + 6.6460656 + 2400. * ft;
  sid = fmod(sido,24.0);
  sidloc = sid + .002737909 * fgmt_hours + floc_hours;
  if (sidloc >= 24.) sidloc = sidloc - 24.;
  /* The major planetary perturbations on the earth */
  av = 153.23 + 22518.7541 * tp;
  bv = 216.57 + 45037.5082 * tp;
  cj = 312.69 + 32964.3577 * tp;
  dl = (267.1142 - 1.44e-3 * tp) * tp;
  dl = (dl + 350.74) + 445000. * tp;
  ec = 231.19 + 20.20 * tp;
  aav = .00134 * cos(av * pi/180.0);
  bbv = .00154 * cos(bv * pi/180.0);
  ccj = .00200 * cos(cj * pi/180.0);
  ddl = .00179 * sin(dl * pi/180.0);
  eec = .00178 * sin(ec * pi/180.0);
  corlo = aav + bbv + ccj + ddl + eec;
  /* Apparent solar longitude and local sidereal time */
  solap = solong - .00569 - sinom + corlo;
  sidap = sidloc - sinom * .061165;
  if(sidap >= 24.) sidap = sidap - 24.;
  if(sidap < 0.) sidap = sidap + 24.;
  /* Obliquity corrected for nutation */
  oblap = obl + .00256 * cos (omega );
  solr = solap * pi/180.0;
  oblr = oblap * pi/180.0;
  /* Declination and right ascension */
  rdec = asin( sin(oblr) * sin(solr));
  ra = atan( cos(oblr) * tan(solr));
  ra = ra * (180.0/pi) / 15.;
  if ((solr > pi/2.0) && (solr < 1.5*pi)) ra = ra + 12.;
  if (ra< 0) ra = ra + 24.;
  if (ra >= 24.) ra = ra - 24.;

  /* hour angle from sidereal time and ra */
  sha = sidap - ra;
  if (sha > 12.) sha = sha - 24.;
  if (sha <= -12.) sha = sha + 24.;
  rsha = fabs(sha) * pi/12.0;
  s1 = pi/2.0 - rdec;
  a2 = rsha;

  sas( s1, &s2, s3, &a1, a2, &a3);
  fazimuth = a1;
  if (sha > 0.) fazimuth = 2.0*pi - a1;

  /* Output results */
  *fAzimuth_a = fazimuth;
  *fElevation_a = pi/2.0 - s2;

}

/* ------------------------------
 * Given the side-angle-side of a triangle on the surface of a sphere, solve
 * for the remaining pieces.
 */
static void sas
( double s1,
  double *ps2,
  double s3,
  double *pa1,   /* All angles in radians */
  double a2,
  double *pa3 )
{
  double pi = 3.1415926535898;

  double tnha2, hds13, hss13, tnhda13, tnhsa13, hda13, hsa13, sns2, css2;
  SINT2 ii;

  tnha2 = 1. / tan(.5 * a2);
  hds13 = .5 * (s1 - s3);
  hss13 = .5 * (s1 + s3);
  tnhda13 = tnha2 * sin(hds13) / sin(hss13);
  tnhsa13 = tnha2 * cos(hds13) / cos(hss13);
  hda13 = atan(tnhda13);
  hsa13 = atan(tnhsa13);
  if (hsa13 < 0) hsa13 = hsa13 + pi;
  *pa1 = hsa13 + hda13;
  *pa3 = hsa13 - hda13;
  ii = 1;
  if (fabs((pi/2)-*pa3) < fabs((pi/2.)-*pa1)) ii = 3;
  if (ii == 1) sns2 = sin(a2) * sin(s1) / sin(*pa1);
  if (ii == 3) sns2 = sin(a2) * sin(s3) / sin(*pa3);
  css2 = cos(s1) * cos(s3) + sin(s1) * sin(s3) * cos(a2);

  if (sns2 <= 0.71)
    {
      *ps2 = asin(sns2);
      if (css2 < 0) *ps2 = pi - *ps2;
    }
  else
    {
      *ps2 = acos(css2);
    }
}
