home *** CD-ROM | disk | FTP | other *** search
- /* Planets
- * A program to determine the position of
- * the Sun., Mer., Ven., Mars, Jup, Sat & Ura
- *
- * reference Jean Meeus's book, " Astronomical Formulae for
- * Calculators
- * program by
- *
- * F.T. Mendenhall
- * ihnp4!inuxe!fred
- *
- * Copyright 1985 by F.T. Mendenhall
- * all rights reserved
- *
- * (This copyright prevents you from selling the program - the
- * author grants anyone the right to copy and install the program
- * on any machine it will run on)
- !
- ! Modified by Alan Paeth, awpaeth@watcgl, January 1987 for
- ! (1) non-interactive mode (uses current GMT)
- ! (2) output in simplified Yale format for use with star charter software
- ! (3) lines 365-380 rewritten as a simplier C expression (awpaeth, Apr '87)
- !
- ! Modified by Petri Launiainen, pl@intrin.FI, February 1987 for
- ! easier LOGFILE definition/modification in Makefile
- !
- ! Modified by Alan Paeth, September 1987, for command line flags.
- ! The program continues to provide reduced Yale output in the old style,
- ! but new versions of "starchart" accept either. The old format allows
- ! representation of magnitudes below -.99 (useful for planets), but no
- ! spectral or stellar identification, which is not useful for planets.
- !
- ! Modified by Jim Cobb, March 1988, to compute moon positions as well.
- ! Also, to change slightly the computation of epli, the obliquity
- ! of the ecliptic. Formerly epli had a term
- ! +0.00256*cos(omeg*rad).
- ! This term is a compensation for computing the apparent position
- ! of the sun (Chapter 18 in Meeus). But for converting
- ! ecliptical coordinates to right ascension and declination we want
- ! the mean value (that is, we don't want this term).
- !
- ! Modified by Bob Leivian, Sept 1989, to compute local azimuth and altitude
- ! given a lat/lon, also fixed time so you can replace a single item
- ! without having to supply all (i.e. for today at 9:00 put -t 9)
- ! also ran the code through 'cb' to standardize the indention.
- ! I split the code in to more managible pieces.
- ! Also printed out time in local and UTC as well as JD
- !
- ! See "Time Notes" section below if you plan to rewrite the user interface.
- */
-
- #include <stdio.h>
- #include <math.h>
-
- /* default latitude longitude (of Tempe, AZ) -- replace with your favorite place */
- #define DEFLONG -111.94
- #define DEFLAT 33.32
- #define DEFZONE 7 /* MST */
-
- #ifndef PLANETFILE
- #define PLANETFILE "./planet.star"
- #endif
-
- double pie, rad;
- double htod(), atof(), kepler(), truean();
- double longi(), lati(), poly(), to_int(), range();
- int cls(), helio_trans(), geo_trans(), speak();
-
- double planet_pos();
- double sidereal_time();
- int zone;
- double longitude = DEFLONG;
- double latitude = DEFLAT;
- double GHA_Aries;
-
-
- FILE *logfile;
- char *progname;
-
- /*
- * Times Notes.
- *
- * This software would ideally use a generic UNIX system call to which would
- * provide day and date info as integers, plus current time west of GMT.
- * These values would become the default settings for each of the -m -d -y -t
- * & -z. Unfortunately, time on across many UNIX systems does not (to my
- * knowledge) exist as a uniform subroutine call.
- *
- * Instead, we presume that the very low level "gettimeofday" (GMT in seconds,
- * from 1 Jan 1970) exists on all UNIX installations, and use this subroutine
- * to use the present time of day when no command line parameters are
- * present, as defaults for the current time have not been filled in.
- *
- * When any flag-style command line parameters are present, hardcoded defaults
- * are substitude for -m, -d, -y -t switches, which may then be overridden.
- * The -z flag is filled in by a companion return value from "gettimeofday".
- * This approach makes for poor (on account of hard coding) defaults.
- *
- * A worthwhile change would be to simplify the command line control structure
- * and default mechanism by using a higher level system call, or (safer),
- * write the routine to convert Unix GMT into day, month, year, so that it
- * lives within this program. This would allow for more reasonable defaults,
- * and still merely one UNIX system call to get GMT time. Perhaps sources
- * from a UNIX system may be studied to do this correctly.
- *
- * Expertise in "time" on a specific UNIX system is *NOT* what is required --
- * what *IS* required is knowledge and access to enough independent UNIX
- * systems to insure (to a high probability) that the code remains portable.
- * In other words, only low-level system calls known to work across a large
- * range of systems should be employed.
- *
- */
-
- #include <sys/time.h> /* for getting current GMT */
-
- double
- current_time(m, d, y, t, z)
- int *m;
- int *d;
- int *y;
- double *t;
- int *z;
- {
- #define SECSPERDAY (60.0 * 60.0 * 24.0)
-
- #ifdef UNIX
- #define GMT1970 2440587.5
- struct timeval tv;
- struct timezone tz;
- struct tm *p;
-
- gettimeofday(&tv, &tz);
- p = localtime(&tv);
-
- *y = p->tm_year + 1900; /* local year */
- *m = p->tm_mon + 1; /* local month */
- *d = p->tm_mday; /* local day of month */
-
- *t = p->tm_hour + (p->tm_min / 60.0); /* local time (0.0-23.999) */
- *z = tz.tz_minuteswest; /* local time hrs west of Greenwich */
-
- return (GMT1970 + tv.tv_sec / SECSPERDAY);
- #endif
-
- #ifdef AMIGA
- time_t amiga_now;
- struct tm *p;
-
- #define GMT1978 2443509.5
- amiga_now = time(&amiga_now);
-
- p = localtime(&amiga_now);
-
- *t = p->tm_hour + (p->tm_min / 60.0); /* local time (0.0-23.999) */
- *z = DEFZONE * 60;
- *y = p->tm_year + 1900; /* local year */
- *m = p->tm_mon + 1; /* local month */
- *d = p->tm_mday; /* local day of month */
- return GMT1978 + (amiga_now / SECSPERDAY) + (DEFZONE / 24.0);
- #endif
-
- #ifdef NO_TIME_AVAIL
- #define MST1989 2447528.291667
- /* no time is avail, pick a default i.e. Noon Jan 1 1989 */
- *y = 1989;
- *m = 1;
- *d = 1;
-
- *t = 12.0;
- *z = DEFZONE * 60.;
- return MST1989;
- #endif
- }
-
- double
- commandtime(argc, argv)
- char **argv;
- {
- int mm, dd, yy, aa1, bb1;
- double jd, year, month, day, time, timez;
- int j;
- double now;
- static char *usage =
- "\nusage:planet {current time used}\nor\tplanet juliandate\nor\tplanet [-t hh.mm -z zone -y year -m mon -d day ]";
-
- /* get current time for defaults */
- now = current_time(&mm, &dd, &yy, &time, &zone);
- timez = zone / 60.; /* time zone in hours */
-
- /* no args - use current time */
- if (argc == 1)
- return now;
-
- if ((argv[1][0] != '-')) {
- /* one numeric arg - use it as the julian date */
- if (argc == 2)
- return (atof(argv[1]));
- die("no switches - %s", usage);
- } else {
- /* flags present, set up defaults */
-
- /* process any user overrides */
- for (j = 1; j < argc; j++) {
- if (argv[j][0] != '-')
- die("unknown argument - %s", usage /*argv[j]*/);
- switch (argv[j][1]) {
- case 't':
- time = htod(argv[++j]);
- break;
- case 'z':
- timez = htod(argv[++j]);
- if (timez < 0 || timez > 24)
- die("time zone must be 0 to 24 west of UTC\n");
- zone = timez * 60.;
- break;
- case 'y':
- yy = atoi(argv[++j]);
- break;
- case 'm':
- mm = atoi(argv[++j]);
- if (mm < 1 || mm > 12)
- die("month must be 1..12\n");
- break;
- case 'd':
- dd = atoi(argv[++j]);
- if (dd < 1 || dd > 31)
- die("day must be 1..31\n");
- break;
- case 'l':
- switch (argv[j][2]) {
- case 'o':
- longitude = atof(argv[++j]);
- if (longitude < -180 || longitude > 180)
- die("longitude must be +-180\n");
- break;
- case 'a':
- latitude = atof(argv[++j]);
- if (latitude < -90 || latitude > 90)
- die("latitude must be +-90\n");
- break;
- default:
- die("specify lat or lon\n");
- }
- break;
- default:
- die("unknown switch - %s", usage /*argv[j]*/ );
- }
- if (j == argc)
- die("trailing command line flag - %s", argv[j - 1]);
- }
- }
- day = ((float) dd + (time + timez) / 24.0);
- if (mm > 2) {
- year = yy;
- month = mm;
- } else {
- year = yy - 1;
- month = mm + 12;
- }
- aa1 = (int) (year / 100);
- bb1 = 2 - aa1 + (int) (aa1 / 4);
- jd = to_int(365.25 * year) + to_int(30.6001 * (month + 1));
- jd = jd + day + 1720994.5;
- if ((year + month / 100) > 1582.10)
- jd = jd + bb1;
- return (jd);
- }
-
-
- caltim(jd_frac, hour, min)
- double jd_frac;
- int *hour;
- int *min;
- {
- double x;
-
- x = jd_frac * 24.0;
- *hour = (int) floor(x);
- x -= floor(x);
- x *= 60.0;
- *min = (int) floor(x);
- }
-
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- double jd, T0, epli;
- double temp;
- long int_jd;
- int y, m, d, h, min, lh, lmin;
- char *str;
-
- progname = argv[0];
- #ifdef AMIGA
- logfile = 0; /* don't write a log */
- #else
- if ((logfile = fopen(PLANETFILE, "w")) == 0)
- /*if ((logfile = fopen("/tmp/planet.star", "w")) == 0) {
-
- die("fail on opening logfile %s\n", "/tmp/planet.star");
- }*/
- #endif
-
- cls();
-
- pie = 3.1415926535898;
- rad = pie / 180.0;
-
- /* calculate time T0 from 1900 January 0.5 ET */
- jd = commandtime(argc, argv);
-
- /* jd to calendar day */
- int_jd = jd +.5001;
- caldat(int_jd, &m, &d, &y);
-
- /* julian day to UTC */
- temp = jd - .4999;
- caltim(temp - floor(temp), &h, &min);
- printf("At %d/%d %d %d:%02d UTC (Julian: %.3f)\n", m, d, y, h, min, jd);
-
- /* UTC to Local */
- temp -= (zone / 1440.);
- caltim(temp - floor(temp), &lh, &lmin);
- int_jd = jd + .5001 - (zone / 1440.);
- caldat(int_jd, &m, &d, &y);
- if (lh > 12) {
- lh -= 12;
- str = "pm";
- } else {
- str = "am";
- if (lh == 0)
- lh = 12;
- }
- printf("local %d/%d %d:%02d%s (", m, d, lh, lmin, str);
-
- /* compute exact local time for a given longitude */
- temp = jd - .5 + (longitude / 360.);
- caltim(temp - floor(temp), &lh, &lmin);
- GHA_Aries = 15. * sidereal_time(jd);
-
- printf("%2d:%02d true local at lat:%1.1f lon:%1.1f, GHA Aries:%1.1f)\n",
- lh, lmin, latitude, longitude, GHA_Aries);
-
- T0 = (jd - 2415020.0) / 36525.0;
- printf("\nOBJECT R.A. DEC DISTANCE altitude azimuth\n");
-
- epli = planet_pos(jd, T0);
-
- moon_pos(T0, epli);
-
- putchar('\n');
- if (logfile)
- close(logfile);
- logfile = 0;
-
- /* show local position of some stars also */
- speak(101.1714, -16.7013, 0., -1.46, " " , "Sirius");
- speak(213.7956, 19.236, 0., -0.04, " " , "Arcturus");
- speak(88.6508, 7.4057, 0., 0.5, " " , "Betelgeuse");
- exit(0);
- } /* end of program main */
-
-
- int
- cls()
- {
- #define CLEARCNT 1
- int i;
- for (i = 0; i < CLEARCNT; i++)
- putchar('\n');
- }
-
-
- double
- poly(a0, a1, a2, a3, t)
- double a0, a1, a2, a3, t;
- {
- return (a0 + a1 * t + a2 * t * t + a3 * t * t * t);
- }
-
-
- double
- to_int(z)
- double z;
- {
- long trunk;
-
- trunk = (long) z;
- z = (double) trunk;
- return (z);
- }
-
-
- double
- kepler(e, M)
- double e, M;
- {
- double corr, e0, E0, E1;
- e0 = e / rad;
- corr = 1;
- E0 = M;
- while (corr > 0.000001) {
- corr = (M + e0 * sin(E0 * rad) - E0) / (1 - e * cos(E0 * rad));
- E1 = E0 + corr;
- if (corr < 0) {
- corr = -1.0 * corr;
- }
- E0 = E1;
- }
-
- return (E1);
- }
-
-
- double
- truean(e, E)
- double e, E;
- {
- double nu;
-
- nu = 2.0 * atan(sqrt((1 + e) / (1 - e)) * tan(E * rad / 2));
- nu = nu / rad;
- if (nu < 0.0) {
- nu = nu + 360.0;
- }
- if (fabs(nu - E) > 90.0) {
- if (nu > 180.0) {
- nu = nu - 180.0;
- } else {
- nu = nu + 180.0;
- }
- }
- return (nu);
- }
-
-
- double
- longi(w2, i, u)
- double w2, i, u;
- {
- double x, y, l;
-
- y = cos(i * rad) * sin(u * rad);
- x = cos(u * rad);
- l = atan2(y, x);
- l = l / rad;
- if (l < 0.0) {
- l = l + 360.0;
- }
- return (l + w2);
- }
-
-
- double
- lati(u, i)
- double u, i;
- {
- double b;
- b = asin(sin(u * rad) * sin(i * rad)) / rad;
- return (b);
- }
-
-
- int
- speak(ra, dec, dis, mag, sym, str)
- double ra, dec, dis, mag;
- char *sym, *str;
- {
- int h, m, s, deg;
- double lha, sha, altitude, azimuth;
- ;
-
- if (ra < 0) {
- ra = ra + 360.0;
- }
- sha = 360. - ra;
- ra = ra / 15.0; /* convert from degs to hours */
- h = (int) to_int(ra);
- m = (int) ((ra - h) * 60);
- s = (int) (((ra - h) * 60 - m) * 60);
- printf("%-12s%2dh %2dm %2ds ", str, h, m, s);
- if (logfile)
- fprintf(logfile, "%02d%02d%02d", h, m, s);
- deg = (int) to_int(dec);
- m = (int) ((dec - deg) * 60);
- s = (int) (((dec - deg) * 60 - m) * 60);
- if (m < 0) {
- m = m * -1;
- }
- if (s < 0) {
- s = s * -1;
- }
- #ifdef AMIGA
- /* its printf doesn't know about signed */
- if (deg > 0)
- printf(" +%2ddeg %2dm %2ds ", deg, m, s);
- else
- printf(" %3ddeg %2dm %2ds ", deg, m, s);
- #else
- printf(" %+3ddeg %2dm %2ds ", deg, m, s);
- #endif
-
- if (dis > 0.0001)
- printf(" %6.3f", dis);
- else
- printf(" ");
- if (logfile)
- if (mag < 0.0)
- fprintf(logfile, "%+03d%02d-%2d%s %s\n",
- deg, m, -(int) (10 * mag), sym, str);
- else
- fprintf(logfile, "%+03d%02d%3d%s %s\n",
- deg, m, (int) (100 * mag), sym, str);
-
- /* if we have a valid angle */
- if (GHA_Aries > 0) {
- /* now tell where it is at a given place on earth */
- lha = range(GHA_Aries + sha + longitude);
-
- altitude = sin(latitude * rad) * sin(dec * rad) +
- cos(latitude * rad) * cos(dec * rad) * cos(lha * rad);
- altitude = asin(altitude) / rad;
-
- azimuth = sin(lha * rad) /
- (cos(lha * rad) * sin(latitude * rad) -
- tan(dec * rad) * cos(latitude * rad));
-
- /* correct for quadrant */
- if (lha <= 180.) {
- if (azimuth > 0)
- azimuth = 180. + atan(azimuth) / rad;
- else
- azimuth = 360. + atan(azimuth) / rad;
- } else {
- if (azimuth <= 0.)
- azimuth = 180. + atan(azimuth) / rad;
- else
- azimuth = atan(azimuth) / rad;
- }
-
- printf(" %5.1f %5.1f\n", altitude, azimuth);
- } else
- printf("\n");
- return (0);
- }
-
-
- double
- range(val)
- double val;
- {
- while (val < 0.0) {
- val = val + 360.0;
- }
- if (val > 360.0) {
- val = val - (to_int(val / 360.0) * 360.0);
- }
- return (val);
- }
-
-
- /*
- * Helio_trans converts heliocentric ecliptical coordinates to geocentric
- * right ascension and declination. It also outputs the converted value.
- */
- int
- helio_trans(r, b, ll, Stheta, Sr, epli, mag, sym, str)
- double r, b, ll, Stheta, Sr, epli, mag;
- char *sym, *str;
- {
- double N, D, lambda, delta, beta;
-
- N = r * cos(b * rad) * sin((ll - Stheta) * rad);
- D = r * cos(b * rad) * cos((ll - Stheta) * rad) + Sr;
- lambda = atan2(N, D) / rad;
- if (lambda < 0.0) {
- lambda = lambda + 360.0;
- }
- lambda = range(lambda + Stheta);
- delta = sqrt(N * N + D * D + (r * sin(b * rad)) * (r * sin(b * rad)));
- beta = asin(r * sin(b * rad) / delta) / rad;
- geo_trans(lambda, beta, epli, delta, mag, sym, str);
- return (0);
- }
-
-
- /*
- * Geo_trans converts geocentric ecliptical coordinates to geocentric right
- * ascension and declination. It also outputs the converted value. Note
- * that the output coordinates are referred to the mean equinox of date. If
- * these coordinates are to be used in conjunction with a star database, use
- * the epoch program to convert the planet's coordinates to the epoch for the
- * star database.
- */
- int
- geo_trans(lambda, beta, epli, delta, mag, sym, str)
- double lambda, beta, epli, delta, mag;
- char *sym, *str;
- {
- double N, D, RA, DEC;
-
- N = sin(lambda * rad) * cos(epli * rad)
- -tan(beta * rad) * sin(epli * rad);
- D = cos(lambda * rad);
- RA = atan2(N, D) / rad;
- DEC = asin(sin(beta * rad) * cos(epli * rad)
- + cos(beta * rad) * sin(epli * rad) * sin(lambda * rad)) / rad;
- speak(RA, DEC, delta, mag, sym, str);
- return (0);
- }
-
-
- double
- htod(s)
- char *s;
- {
- /*
- * htod(str) reads floating point strings of the form {+-}hh.{mm} thus
- * allowing for fractional values in base 60 (ie, degrees/minutes).
- */
- double x, sign;
- int full, frac;
- char *t;
- t = s - 1;
- while (*++t) {
- if (((*t < '0') || (*t > '9')) && (*t != '.') && (*t != '+') && (*t != '-'))
- die("non-digit in dd.mm style numeric argument");
- }
- if (s == NULL)
- return 0.0;
- full = frac = 0;
- sign = 1.0;
- if (*s == '-') {
- sign = -1.0;
- s++;
- } else if (*s == '+')
- s++;
- while (*s && *s != '.')
- full = 10 * full + *s++ - '0';
- if (*s++ == '.') {
- if (*s)
- frac = 10 * (*s++ - '0');
- if (*s)
- frac += *s++ - '0';
- if (frac > 59)
- frac = 59;
- }
- x = (double) full + ((double) frac) / 60.0;
- return sign * x;
- }
-
-
- die(a, b)
- char *a, *b;
- {
- fprintf(stderr, "%s: ", progname);
- fprintf(stderr, a, b);
- fprintf(stderr, "\n");
- fflush(stderr);
- exit(1);
- }
-