/* $Id: astronomy.c,v 1.2 2003/03/19 23:39:21 d3august Exp $ */
/* xtraceroute - graphically show traceroute information.
* Copyright (C) 1996-2003 Björn Augustsson
* Copyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <time.h>
#include <math.h>
#include "xt.h"
/* Most of this code was cheerfully stolen from the excellent xplanet
* by Hari Nair <hari@alumni.caltech.edu>
* see http://xplanet.sourceforge.net/
*
* Some of this code is (to me anyway) pretty scary. There are _a_lot_
* of magic numbers in here, and I don't understand all of it. So don't
* expect me to explain this stuff to you... :)
*
* /August.
*/
static double
julian(int year, int month, int day, int hour, int min, int sec)
{
if(month < 3)
{
year -= 1;
month += 12;
}
// assume it's the Gregorian calendar (after 1582 Oct 15)
{
int a = year/100;
int b = 2 - a + a/4;
int c = (int)(365.25 * year);
int d = (int)(30.6001 * (month + 1));
double e = day + ((sec/60. + min) / 60. + hour) / 24.;
double jd = b + c + d + e + 1720994.5;
return(jd);
}
}
static double
julianCentury(const time_t tv_sec)
{
double jd = julian(gmtime(&tv_sec)->tm_year + 1900,
gmtime(&tv_sec)->tm_mon + 1,
gmtime(&tv_sec)->tm_mday,
gmtime(&tv_sec)->tm_hour,
gmtime(&tv_sec)->tm_min,
gmtime(&tv_sec)->tm_sec);
return((jd - 2415020)/36525);
}
/* Really scary function. */
static double
poly(const double a1, const double a2, const double a3, const double a4,
const double t)
{
return(a1 + t*(a2 + t*(a3 + t*a4)));
}
/* Solve kepler's equation. */
static double
kepler(const double e, const double M)
{
double E = M;
double delta = 1.0;
while (fabs(delta) > 1E-10)
{
delta = (M + e * sin(E) - E)/(1.0 - e * cos(E));
E += delta;
}
return(E);
}
static double
gmst(const double T, const time_t tv_sec)
{
// Sidereal time at Greenwich at 0 UT
double g = poly(6.6460656, 2400.051262, 0.00002581, 0, T);
// Now find current sidereal time at Greenwich
double currgmt = (gmtime(&tv_sec)->tm_hour
+ gmtime(&tv_sec)->tm_min/60.
+ gmtime(&tv_sec)->tm_sec/3600.);
currgmt *= 1.002737908;
g += currgmt;
g = fmod(g, 24.0);
if (g < 0) g += 24;
return(g);
}
/* Return the current sun position, in eclipitic coodinates. */
/* Based on Chapter 18 of Astronomical Formulae for Calculators by Meeus */
static void
sunpos(const double T, double* sunlat, double* sunlon)
{
double L = (poly(2.7969668E2, 3.600076892E4, 3.025E-4, 0, T)
* torad);
double M = (poly(3.5847583E2, 3.599904975E4, -1.5E-4, -3.3E-6, T)
* torad);
/* Eccentricity of the Earth's orbit. */
double ecc = poly(1.675104E-2, -4.18E-5, -1.26E-7, 0, T);
/* Eccentric anomaly. */
double eccanom = kepler(ecc, M);
double nu = 2.0 * atan(sqrt((1.0+ecc) / (1.0-ecc)) * tan(eccanom / 2.0));
double theta = L + nu - M;
*sunlon = theta;
*sunlat = 0.0;
// sundist = 1.0000002 * (1 - ecc * cos(eccanom));
}
/**
* This converts a position (lat, lon) in the ecliptic plane (the sun's
* plane) to a "normal" position, ie the position on earth where the
* sun is in zenith.
*
* NOTE: All lat, lon values are in radians!
*
* I could optimize this a bit. Since I'm always interested in the suns's
* position, the ec_lat value is always zero. Doesn't matter though.
*/
static void
eclipticToEquatorial(const double ec_lon, const double ec_lat,
const double eps,
double *eq_lon, double *eq_lat)
{
*eq_lat = asin(sin(eps)*sin(ec_lon)*cos(ec_lat) + sin(ec_lat)*cos(eps));
*eq_lon = atan2(cos(eps)*sin(ec_lon) - tan(ec_lat)*sin(eps), cos(ec_lon));
}
/* I have no idea what this does... */
/* 23.452294 might be angle (in degrees) between the earths' and the
suns' orbital planes. Or something. */
static double
calcObliquity(const double T)
{
return (poly(23.452294, -1.30125E-2, -1.64E-6, 5.03E-7, T)
* torad);
}
/**
* Figure out where the sun is, from current time
*
* NOTE: The lat, lon values "returned" are in radians!
*/
void
get_sun_position(double* lat, double* lon)
{
const time_t t = time(NULL);
// gmtime here?
const double jt = julianCentury(t);
const double eps = calcObliquity(jt);
double ec_lat, ec_lon;
double mylat, mylon;
double gst = 2.0*M_PI * gmst(jt, t) / 24;
sunpos(jt, &ec_lat, &ec_lon);
/* Ah, but these are eclipitic coodinates! Better convert them. */
eclipticToEquatorial(ec_lon, ec_lat, eps, &mylon, &mylat);
mylon -= gst;
/* These (lat, lon) values are in radians. */
*lat = mylat;
*lon = mylon;
}
syntax highlighted by Code2HTML, v. 0.9.1