[comp.sources.misc] v07i011: astronomical ephemeris - 3 of 3

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (06/04/89)

Posting-number: Volume 7, Issue 11
Submitted-by: ecd@ncs-med.UUCP (Elwood C. Downey)
Archive-name: ephem/part03

[BTW, not putting "guard characters" at the beginnings of lines in a shar'ed
file is asking for trouble on some systems.  Especially with idiot UUCP mail
systems -- some, perhaps all, of this group *does* get sent over mail links.
One "From" will produce a mangled transmission.  And Bitnet seems to know of
other ways to destroy such files.  ++bsa]

#!/bin/sh
echo mkdir lib
mkdir lib
echo cd lib
cd lib
echo extracting Makefile
cat > Makefile << 'xXx'
CLNFLAGS=$(CLNF)
LNFLAGS=$(CLNFLAGS) $(LNF)
CFLAGS=$(CLNFLAGS) $(CF)
LINTFLAGS=$(CFLAGS) $(LINTF)
LINTLIBS=

.c.a:
	-$(CC) -c $(CFLAGS) $<

.PRECIOUS:	lib.a

lib.a:	lib.a(aa_hadec.o) \
	lib.a(anomaly.o) \
	lib.a(cal_mjd.o) \
	lib.a(eq_ecl.o) \
	lib.a(moon.o) \
	lib.a(moonnf.o) \
	lib.a(moonrs.o) \
	lib.a(nutation.o) \
	lib.a(obliq.o) \
	lib.a(parallax.o) \
	lib.a(pelement.o) \
	lib.a(plans.o) \
	lib.a(precess.o) \
	lib.a(refract.o) \
	lib.a(riset.o) \
	lib.a(sex_dec.o) \
	lib.a(sun.o) \
	lib.a(sunrs.o) \
	lib.a(utc_gst.o)
	ar rv $@ $?
	ranlib $@
	rm -f $?
xXx
echo extracting aa_hadec.c
cat > aa_hadec.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given latitude (n+, radians), lat, altitude (up+, radians), alt, and
 * azimuth (angle round to the east from north+, radians),
 * return hour angle (radians), ha, and declination (radians), dec.
 */
aa_hadec (lat, alt, az, ha, dec)
float lat;
float alt, az;
float *ha, *dec;
{
	aaha_aux (lat, az, alt, ha, dec);
}

/* given latitude (n+, radians), lat, hour angle (radians), ha, and declination
 * (radians), dec,
 * return altitude (up+, radians), alt, and
 * azimuth (angle round to the east from north+, radians),
 */
hadec_aa (lat, ha, dec, alt, az)
float lat;
float ha, dec;
float *alt, *az;
{
	aaha_aux (lat, ha, dec, az, alt);
}

/* the actual formula is the same for both transformation directions so
 * do it here once for each way.
 * N.B. all arguments are in radians.
 */
static
aaha_aux (lat, x, y, p, q)
float lat;
float x, y;
float *p, *q;
{
	static float lastlat = -1000.;
	static float sinlastlat, coslastlat;
	float sy, cy;
	float sx, cx;
	float sq, cq;
	float a;
	float cp;

	/* latitude doesn't change much, so try to reuse the sin and cos evals.
	 */
	if (lat != lastlat) {
	    sinlastlat = sin (lat);
	    coslastlat = cos (lat);
	    lastlat = lat;
	}

	sy = sin (y);
	cy = cos (y);
	sx = sin (x);
	cx = cos (x);

/* define GOODATAN2 if atan2 returns full range -PI through +PI.
 */
#ifdef GOODATAN2
	*q = asin ((sy*sinlastlat) + (cy*coslastlat*cx));
	*p = atan2 (-cy*sx, -cy*cx*sinlastlat + sy*coslastlat);
#else
#define	EPS	(1e-20)
	sq = (sy*sinlastlat) + (cy*coslastlat*cx);
	*q = asin (sq);
	cq = cos (*q);
	a = coslastlat*cq;
	if (a > -EPS && a < EPS)
	    a = a < 0 ? -EPS : EPS; /* avoid / 0 */
	cp = (sy - (sinlastlat*sq))/a;
	if (cp >= 1.0)	/* the /a can be slightly > 1 */
	    *p = 0.0;
	else if (cp <= -1.0)
	    *p = PI;
	else
	    *p = acos ((sy - (sinlastlat*sq))/a);
	if (sx>0) *p = 2.0*PI - *p;
#endif
}
xXx
echo extracting anomaly.c
cat > anomaly.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

#define	TWOPI	(2*PI)

/* given the mean anomaly, ma, and the eccentricity, s, of elliptical motion,
 * find the true anomaly, *nu, and the eccentric anomaly, *ea.
 * all angles in radians.
 */
anomaly (ma, s, nu, ea)
float ma, s;
float *nu, *ea;
{
	float m, dla, fea;

	m = ma-TWOPI*(int)(ma/TWOPI);
	fea = m;
	while (1) {
	    dla = fea-(s*sin(fea))-m;
	    if (fabs(dla)<1e-6)
		break;
	    dla /= 1-(s*cos(fea));
	    fea -= dla;
	}

	*nu = 2*atan(sqrt((1+s)/(1-s))*tan(fea/2));
	*ea = fea;
}
xXx
echo extracting astro.h
cat > astro.h << 'xXx'
#ifndef PI
#define	PI		3.141592653589793
#endif

/* conversions among hours (of ra), degrees and radians. */
#define	degrad(x)	((x)*PI/180.)
#define	raddeg(x)	((x)*180./PI)
#define	hrdeg(x)	((x)*15.)
#define	deghr(x)	((x)/15.)
#define	hrrad(x)	degrad(hrdeg(x))
#define	radhr(x)	deghr(raddeg(x))

/* manifest names for planets.
 * N.B. must cooincide with usage in pelement.c and plans.c.
 */
#define	MERCURY	0
#define	VENUS	1
#define	MARS	2
#define	JUPITER	3
#define	SATURN	4
#define	URANUS	5
#define	NEPTUNE	6
#define	PLUTO	7
xXx
echo extracting cal_mjd.c
cat > cal_mjd.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given a date in months, mn, days, dy, years, yr,
 * return the modified Julian date (number of days elapsed since 1900 jan 0.5),
 * *mjd.
 */
cal_mjd (mn, dy, yr, mjd)
int mn, yr;
float dy;
float *mjd;
{
	int b, d, m, y;
	long c;

	m = mn;
	y = (yr < 0) ? yr + 1 : yr;
	if (mn < 3) {
	    m += 12;
	    y -= 1;
	}

	if (yr < 1582 || yr == 1582 && (mn < 10 || mn == 10 && dy < 15)) 
	    b = 0;
	else {
	    int a;
	    a = y/100;
	    b = 2 - a + a/4;
	}

	if (y < 0)
	    c = (long)((365.25*y) - 0.75) - 694025L;
	else
	    c = (long)(365.25*y) - 694025L;

	d = 30.6001*(m+1);

	*mjd = b + c + d + dy - 0.5;
}

/* given the modified Julian date (number of days elapsed since 1900 jan 0.5,),
 * mjd, return the calendar date in months, *mn, days, *dy, and years, *yr.
 */
mjd_cal (mjd, mn, dy, yr)
float mjd;
int *mn, *yr;
float *dy;
{
	float d, f;
	float i, a, b, ce, g;

	d = mjd + 0.5;
	i = floor(d);
	f = d-i;
	if (f == 1) {
	    f = 0;
	    i += 1;
	}

	if (i > -115860.0) {
	    a = floor((i/36524.25)+.9983573)+14;
	    i += 1 + a - floor(a/4.0);
	}

	b = floor((i/365.25)+.802601);
	ce = i - floor((365.25*b)+.750001)+416;
	g = floor(ce/30.6001);
	*mn = g - 1;
	*dy = ce - floor(30.6001*g)+f;
	*yr = b + 1899;

	if (g > 13.5)
	    *mn = g - 13;
	if (*mn < 2.5)
	    *yr = b + 1900;
	if (*yr < 1)
	    *yr -= 1;
}

/* given an mjd, set *dow to 0..6 according to which dayof the week it falls
 * on (0=sunday) or set it to -1 if can't figure it out.
 */
mjd_dow (mjd, dow)
float mjd;
int *dow;
{
	/* cal_mjd() uses Gregorian dates on or after Oct 15, 1582.
	 * (Pope Gregory XIII dropped 10 days, Oct 5..14, and improved the leap-
	 * year algorithm). however, Great Britian and the colonies did not
	 * adopt it until Sept 14, 1752 (they dropped 11 days, Sept 3-13,
	 * due to additional accumulated error). leap years before 1752 thus
	 * can not easily be accounted for from the cal_mjd() number...
	 */
	if (mjd < -53798.5) {
	    /* pre sept 14, 1752 too hard to correct */
	    *dow = -1;
	    return;
	}
	*dow = ((int)floor(mjd-.5) + 1) % 7; /* 1/1/1900 (mjd 0.5) is a Monday*/
	if (*dow < 0)
	    *dow += 7;
}

/* given a mjd, return the the number of days in the month.  */
mjd_dpm (mjd, ndays)
float mjd;
int *ndays;
{
	static short dpm[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int m, y;
	float d;

	mjd_cal (mjd, &m, &d, &y);
	*ndays = (m==2 && ((y%4==0 && y%100!=0)||y%400==0)) ? 29 : dpm[m-1];
}
xXx
echo extracting eq_ecl.c 
cat > eq_ecl.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

#define	EQtoECL	1
#define	ECLtoEQ	(-1)

/* given the modified Julian date, mjd, and an equitorial ra and dec, each in
 * radians, find the corresponding geocentric ecliptic latitude, *lat, and
 * longititude, *lng, also each in radians.
 * the effects of nutation and the angle of the obliquity are included.
 */
eq_ecl (mjd, ra, dec, lat, lng)
float mjd, ra, dec;
float *lat, *lng;
{
	ecleq_aux (EQtoECL, mjd, ra, dec, lng, lat);
}

/* given the modified Julian date, mjd, and a geocentric ecliptic latitude,
 * *lat, and longititude, *lng, each in radians, find the corresponding
 * equitorial ra and dec, also each in radians.
 * the effects of nutation and the angle of the obliquity are included.
 */
ecl_eq (mjd, lat, lng, ra, dec)
float mjd, lat, lng;
float *ra, *dec;
{
	ecleq_aux (ECLtoEQ, mjd, lng, lat, ra, dec);
}

static
ecleq_aux (sw, mjd, x, y, p, q)
int sw;			/* +1 for eq to ecliptic, -1 for vv. */
float mjd, x, y;	/* sw==1: x==ra, y==dec.  sw==-1: x==lng, y==lat. */
float *p, *q;		/* sw==1: p==lng, q==lat. sw==-1: p==ra, q==dec. */
{
	static float lastmjd;		/* last mjd calculated */
	static float seps, ceps;	/* sin and cos of mean obliquity */
	float sx, cx, sy, cy, ty;

	if (mjd != lastmjd) {
	    float deps, dpsi, eps;
	    obliquity (mjd, &eps);		/* mean obliquity for date */
#ifdef NONUTATION
#define NONUTATION
	    deps = 0;				/* checkout handler did not
						 * include nutation correction.
						 */
#else
	    nutation (mjd, &deps, &dpsi);	/* correctin due to nutation */
#endif
	    eps += deps;			/* true obliquity for date */
    	    seps = sin(eps);
	    ceps = cos(eps);
	    lastmjd = mjd;
	}

	sy = sin(y);
	cy = cos(y);				/* always non-negative */
        if (fabs(cy)<1e-20) cy = 1e-20;		/* insure > 0 */
        ty = sy/cy;
	cx = cos(x);
	sx = sin(x);
        *q = asin((sy*ceps)-(cy*seps*sx*sw));
        *p = atan(((sx*ceps)+(ty*seps*sw))/cx);
        if (cx<0) *p += PI;		/* account for atan quad ambiguity */
	range (p, 2*PI);
}
xXx
echo extracting moon.c 
cat > moon.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given the mjd, find the geocentric ecliptic longitude, lam, and latitude,
 * bet, and horizontal parallax, hp for the moon.
 * N.B. series for long and lat are good to about 10 and 3 arcseconds. however,
 *   math errors cause up to 100 and 30 arcseconds error, even if use double.
 *   why?? suspect highly sensitive nature of difference used to get m1..6.
 * N.B. still need to correct for nutation. then for topocentric location
 *   further correct for parallax and refraction.
 */
moon (mjd, lam, bet, hp)
float mjd;
float *lam, *bet, *hp;
{
	float t, t2;
	float ld;
	float ms;
	float md;
	float de;
	float f;
	float n;
	float a, sa, sn, b, sb, c, sc, e, e2, l, g, w1, w2;
	float m1, m2, m3, m4, m5, m6;

	t = mjd/36525.;
	t2 = t*t;

	m1 = mjd/27.32158213;
	m1 = 360.0*(m1-(int)m1);
	m2 = mjd/365.2596407;
	m2 = 360.0*(m2-(int)m2);
	m3 = mjd/27.55455094;
	m3 = 360.0*(m3-(int)m3);
	m4 = mjd/29.53058868;
	m4 = 360.0*(m4-(int)m4);
	m5 = mjd/27.21222039;
	m5 = 360.0*(m5-(int)m5);
	m6 = mjd/6798.363307;
	m6 = 360.0*(m6-(int)m6);

	ld = 270.434164+m1-(.001133-.0000019*t)*t2;
	ms = 358.475833+m2-(.00015+.0000033*t)*t2;
	md = 296.104608+m3+(.009192+.0000144*t)*t2;
	de = 350.737486+m4-(.001436-.0000019*t)*t2;
	f = 11.250889+m5-(.003211+.0000003*t)*t2;
	n = 259.183275-m6+(.002078+.000022*t)*t2;

	a = degrad(51.2+20.2*t);
	sa = sin(a);
	sn = sin(degrad(n));
	b = 346.56+(132.87-.0091731*t)*t;
	sb = .003964*sin(degrad(b));
	c = degrad(n+275.05-2.3*t);
	sc = sin(c);
	ld = ld+.000233*sa+sb+.001964*sn;
	ms = ms-.001778*sa;
	md = md+.000817*sa+sb+.002541*sn;
	f = f+sb-.024691*sn-.004328*sc;
	de = de+.002011*sa+sb+.001964*sn;
	e = 1-(.002495+7.52e-06*t)*t;
	e2 = e*e;

	ld = degrad(ld);
	ms = degrad(ms);
	n = degrad(n);
	de = degrad(de);
	f = degrad(f);
	md = degrad(md);

	l = 6.28875*sin(md)+1.27402*sin(2*de-md)+.658309*sin(2*de)+
	    .213616*sin(2*md)-e*.185596*sin(ms)-.114336*sin(2*f)+
	    .058793*sin(2*(de-md))+.057212*e*sin(2*de-ms-md)+
	    .05332*sin(2*de+md)+.045874*e*sin(2*de-ms)+.041024*e*sin(md-ms);
	l = l-.034718*sin(de)-e*.030465*sin(ms+md)+.015326*sin(2*(de-f))-
	    .012528*sin(2*f+md)-.01098*sin(2*f-md)+.010674*sin(4*de-md)+
	    .010034*sin(3*md)+.008548*sin(4*de-2*md)-e*.00791*sin(ms-md+2*de)-
	    e*.006783*sin(2*de+ms);
	l = l+.005162*sin(md-de)+e*.005*sin(ms+de)+.003862*sin(4*de)+
	    e*.004049*sin(md-ms+2*de)+.003996*sin(2*(md+de))+
	    .003665*sin(2*de-3*md)+e*.002695*sin(2*md-ms)+
	    .002602*sin(md-2*(f+de))+e*.002396*sin(2*(de-md)-ms)-
	    .002349*sin(md+de);
	l = l+e2*.002249*sin(2*(de-ms))-e*.002125*sin(2*md+ms)-
	    e2*.002079*sin(2*ms)+e2*.002059*sin(2*(de-ms)-md)-
	    .001773*sin(md+2*(de-f))-.001595*sin(2*(f+de))+
	    e*.00122*sin(4*de-ms-md)-.00111*sin(2*(md+f))+.000892*sin(md-3*de);
	l = l-e*.000811*sin(ms+md+2*de)+e*.000761*sin(4*de-ms-2*md)+
	     e2*.000704*sin(md-2*(ms+de))+e*.000693*sin(ms-2*(md-de))+
	     e*.000598*sin(2*(de-f)-ms)+.00055*sin(md+4*de)+.000538*sin(4*md)+
	     e*.000521*sin(4*de-ms)+.000486*sin(2*md-de);
	l = l+e2*.000717*sin(md-2*ms);
	*lam = ld+degrad(l);
	range (lam, 2*PI);

	g = 5.12819*sin(f)+.280606*sin(md+f)+.277693*sin(md-f)+
	    .173238*sin(2*de-f)+.055413*sin(2*de+f-md)+.046272*sin(2*de-f-md)+
	    .032573*sin(2*de+f)+.017198*sin(2*md+f)+.009267*sin(2*de+md-f)+
	    .008823*sin(2*md-f)+e*.008247*sin(2*de-ms-f);
	g = g+.004323*sin(2*(de-md)-f)+.0042*sin(2*de+f+md)+
	    e*.003372*sin(f-ms-2*de)+e*.002472*sin(2*de+f-ms-md)+
	    e*.002222*sin(2*de+f-ms)+e*.002072*sin(2*de-f-ms-md)+
	    e*.001877*sin(f-ms+md)+.001828*sin(4*de-f-md)-e*.001803*sin(f+ms)-
	    .00175*sin(3*f);
	g = g+e*.00157*sin(md-ms-f)-.001487*sin(f+de)-e*.001481*sin(f+ms+md)+
	     e*.001417*sin(f-ms-md)+e*.00135*sin(f-ms)+.00133*sin(f-de)+
	     .001106*sin(f+3*md)+.00102*sin(4*de-f)+.000833*sin(f+4*de-md)+
	     .000781*sin(md-3*f)+.00067*sin(f+4*de-2*md);
	g = g+.000606*sin(2*de-3*f)+.000597*sin(2*(de+md)-f)+
	    e*.000492*sin(2*de+md-ms-f)+.00045*sin(2*(md-de)-f)+
	    .000439*sin(3*md-f)+.000423*sin(f+2*(de+md))+
	    .000422*sin(2*de-f-3*md)-e*.000367*sin(ms+f+2*de-md)-
	    e*.000353*sin(ms+f+2*de)+.000331*sin(f+4*de);
	g = g+e*.000317*sin(2*de+f-ms+md)+e2*.000306*sin(2*(de-ms)-f)-
	    .000283*sin(md+3*f);
	w1 = .0004664*cos(n);
	w2 = .0000754*cos(c);
	*bet = degrad(g)*(1-w1-w2);

	*hp = .950724+.051818*cos(md)+.009531*cos(2*de-md)+.007843*cos(2*de)+
	      .002824*cos(2*md)+.000857*cos(2*de+md)+e*.000533*cos(2*de-ms)+
	      e*.000401*cos(2*de-md-ms)+e*.00032*cos(md-ms)-.000271*cos(de)-
	      e*.000264*cos(ms+md)-.000198*cos(2*f-md);
	*hp = *hp+.000173*cos(3*md)+.000167*cos(4*de-md)-e*.000111*cos(ms)+
	     .000103*cos(4*de-2*md)-.000084*cos(2*md-2*de)-
	     e*.000083*cos(2*de+ms)+.000079*cos(2*de+2*md)+.000072*cos(4*de)+
	     e*.000064*cos(2*de-ms+md)-e*.000063*cos(2*de+ms-md)+
	     e*.000041*cos(ms+de);
	*hp = *hp+e*.000035*cos(2*md-ms)-.000033*cos(3*md-2*de)-
	     .00003*cos(md+de)-.000029*cos(2*(f-de))-e*.000029*cos(2*md+ms)+
	     e2*.000026*cos(2*(de-ms))-.000023*cos(2*(f-de)+md)+
	     e*.000019*cos(4*de-ms-md);
	*hp = degrad(*hp);
}
xXx
echo extracting moonnf.c
cat > moonnf.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

#define	unw(w,z)	((w)-floor((w)/(z))*(z))

/* given a modified Julian date, mjd, return the mjd of the new
 * and full moons about then, mjdn and mjdf.
 * TODO: exactly which ones does it find? eg:
 *   5/28/1988 yields 5/15 and 5/31
 *   5/29             6/14     6/29
 */
moonnf (mjd, mjdn, mjdf)
float mjd;
float *mjdn, *mjdf;
{
	int mo, yr;
	float dy;
	float mjd0;
	float k, tn, tf, t;

	mjd_cal (mjd, &mo, &dy, &yr);
	cal_mjd (1, 0., yr, &mjd0);
	k = (yr-1900+((mjd-mjd0)/365))*12.3685;
	k = floor(k+0.5);
	tn = k/1236.85;
	tf = (k+0.5)/1236.85;
	t = tn;
	m (t, k, mjdn);
	t = tf;
	k += 0.5;
	m (t, k, mjdf);
}

static
m (t, k, mjd)
float t, k;
float *mjd;
{
	float t2, a, a1, b, b1, c, ms, mm, f, ddjd;

	t2 = t*t;
	a = 29.53*k;
	c = degrad(166.56+(132.87-9.173e-3*t)*t);
	b = 5.8868e-4*k+(1.178e-4-1.55e-7*t)*t2+3.3e-4*sin(c)+7.5933E-1;
	ms = 359.2242+360*unw(k/1.236886e1,1)-(3.33e-5+3.47e-6*t)*t2;
	mm = 306.0253+360*unw(k/9.330851e-1,1)+(1.07306e-2+1.236e-5*t)*t2;
	f = 21.2964+360*unw(k/9.214926e-1,1)-(1.6528e-3+2.39e-6*t)*t2;
	ms = unw(ms,360);
	mm = unw(mm,360);
	f = unw(f,360);
	ms = degrad(ms);
	mm = degrad(mm);
	f = degrad(f);
	ddjd = (1.734e-1-3.93e-4*t)*sin(ms)+2.1e-3*sin(2*ms)
		-4.068e-1*sin(mm)+1.61e-2*sin(2*mm)-4e-4*sin(3*mm)
		+1.04e-2*sin(2*f)-5.1e-3*sin(ms+mm)-7.4e-3*sin(ms-mm)
		+4e-4*sin(2*f+ms)-4e-4*sin(2*f-ms)-6e-4*sin(2*f+mm)
		+1e-3*sin(2*f-mm)+5e-4*sin(ms+2*mm);
	a1 = (int)a;
	b = b+ddjd+(a-a1);
	b1 = (int)b;
	a = a1+b1;
	b = b-b1;
	*mjd = a + b;
}
xXx
echo extracting moonrs.c
cat > moonrs.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

#define	PASSES	2

/* given the mjd and geographical latitude and longitude, lat and lng, 
 *   find the ut and azimuth of moonrise, utcr and azr, and moonset, utcs and
 *   azs for the day of mjd. all angles are in radians.
 * times are for the upper limb, including effects of refraction (a constant 34
 *   arcminutes), parallax, and nutation. accuracy is to nearest minute.
 * the calculated times can be in error if they occur within about a half hour 
 *   of utc midnight due to the algorithm's confusion about the date. the best
 *   way to verify it is to calculate the times for several days either side of
 *   the date to see whether the problem values conform to a smooth trend set
 *   by the others.
 * possible values of status:
 *    2: can't cope (such as geographical latitude very near +-90).
 *    1: moon never rises/sets on date.
 *    0: all ok.
 *   -1: moon is circumpolar.
 *   -2: possible error in near-midnight moonrise time; see above.
 *   -3: possible error in near-midnight moonset time; see above.
 */
moonrs (mjd, lat, lng, utcr, utcs, azr, azs, status)
float mjd, lat, lng;
float *utcr, *utcs;
float *azr, *azs;
int *status;
{
	float lstr, lsts;	/* local sidereal times of rising/setting */
	float al = radhr(lng);	/* time correction for longitude */
	int midnight = 0;	/* midnight caution */
	float mjd0;		/* start of mjd day */
	float x;		/* discarded tmp value */
	float ut;
	int pass;

	mjd0 = floor(mjd+0.5)-0.5;

	/* first approximation is to find rise/set times of a fixed object
	 * in the position of the moon at local midday.
	 */
	fixedmoonriset (mjd0+(12.0-al)/24.0, lat, &lstr, &lsts, &x, &x, status);
	if (*status != 0) return;

	/* find a better approximation to the rising circumstances based on two
	 * more passes, each using a "fixed" object at the moons location at
	 * previous approximation of the rise time.
	 */
	pass = 0;
	while (1) {
	    gst_utc (mjd0, lstr, &ut);
	    if (++pass > PASSES)
		break;
	    fixedmoonriset (mjd0+(ut-al)/24., lat, &lstr, &x, azr, &x, status);
	    if (*status != 0) return;
	}
	if (ut > 23.5 || ut < 0.5)
	    midnight = -2;		/* moonrise caution near midnight */
	*utcr = ut - (al * .9972696);	/* allow for sidereal shift */

	/* find a better approximation to the setting circumstances based on two
	 * more passes, each using a "fixed" object at the moons location at
	 * previous approximation of the setting time.
	 */
	pass = 0;
	while (1) {
	    gst_utc (mjd0, lsts, &ut);
	    if (++pass > PASSES)
		break;
	    fixedmoonriset (mjd0+(ut-al)/24., lat, &x, &lsts, &x, azs, status);
	    if (*status != 0) return;
	}
	if (ut > 23.5 || ut < 0.5)
	    midnight = -3;		/* moonset caution near midnight */
	*utcs = ut - (al * .9972696);	/* allow for sidereal shift */

	if (midnight)
	    *status = midnight;		/* report caution if near midnight */
}

/* find the local rise/set sidereal times and azimuths of an object fixed
 * at the ra/dec of the moon on the given mjd time as seen from lat.
 */
static
fixedmoonriset (mjd, lat, lstr, lsts, azr, azs, status)
float mjd, lat;
float *lstr, *lsts;
float *azr, *azs;
int *status;
{
	float lam, bet, hp;
	float deps, dpsi;
	float dis;
	float ra, dec;

	/* find geocentric ecliptic location and equatorial horizontal parallax
	 * of moon at mjd.
	 */
	moon (mjd, &lam, &bet, &hp);

	/* allow for nutation */
	nutation (mjd, &deps, &dpsi);
        lam += dpsi;

	/* convert ecliptic to equatorial coords */
	ecl_eq (mjd, bet, lam, &ra, &dec);

	/* find local sidereal times of rise/set times/azimuths for given
	 * equatorial coords, allowing for
	 * .27249*sin(hp)   parallax (hp is radius of earth from moon;
	 *                  .27249 is radius of moon from earth where
	 *                  the ratio is the dia_moon/dia_earth).
	 * 34' (9.8902e-3)  nominal refraction
	 * hp               nominal angular earth radius. subtract because
	 *                  tangential line-of-sight makes moon appear lower
	 *                  as move out from center of earth.
	 * TODO: do better at refraction; see fixedsunriset() in sunrs.c.
	 */
	dis = .27249*sin(hp) + 9.8902e-3 - hp;
	riset (ra, dec, lat, dis, lstr, lsts, azr, azs, status);
}
xXx
echo extracting nutation.c
cat > nutation.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given the modified JD, mjd, find the nutation in obliquity, *deps, and
 * the nutation in longitude, *dpsi, each in radians.
 */
nutation (mjd, deps, dpsi)
float mjd;
float *deps, *dpsi;
{
	static float lastmjd, lastdeps, lastdpsi;
	float ls, ld;	/* sun's mean longitude, moon's mean longitude */
	float ms, md;	/* sun's mean anomaly, moon's mean anomaly */
	float nm;	/* longitude of moon's ascending node */
	float t, t2;	/* number of Julian centuries of 36525 days since
			 * Jan 0.5 1900.
			 */
	float tls, tnm, tld;	/* twice above */
	double a, b;	/* temps */

	if (mjd == lastmjd) {
	    *deps = lastdeps;
	    *dpsi = lastdpsi;
	    return;
	}
	    
	t = mjd/36525.;
	t2 = t*t;

	a = 100.0021358*t;
	b = 360.*(a-(int)a);
	ls = 279.697+.000303*t2+b;

	a = 1336.855231*t;
	b = 360.*(a-(int)a);
	ld = 270.434-.001133*t2+b;

	a = 99.99736056000026*t;
	b = 360.*(a-(int)a);
	ms = 358.476-.00015*t2+b;

	a = 13255523.59*t;
	b = 360.*(a-(int)a);
	md = 296.105+.009192*t2+b;

	a = 5.372616667*t;
	b = 360.*(a-(int)a);
	nm = 259.183+.002078*t2-b;

	/* convert to radian forms for use with trig functions.
	 */
	tls = 2*degrad(ls);
	nm = degrad(nm);
	tnm = 2*degrad(nm);
	ms = degrad(ms);
	tld = 2*degrad(ld);
	md = degrad(md);

	/* find delta psi and eps, in arcseconds.
	 */
	lastdpsi = (-17.2327-.01737*t)*sin(nm)+(-1.2729-.00013*t)*sin(tls)
		   +.2088*sin(tnm)-.2037*sin(tld)+(.1261-.00031*t)*sin(ms)
		   +.0675*sin(md)-(.0497-.00012*t)*sin(tls+ms)
		   -.0342*sin(tld-nm)-.0261*sin(tld+md)+.0214*sin(tls-ms)
		   -.0149*sin(tls-tld+md)+.0124*sin(tls-nm)+.0114*sin(tld-md);
	lastdeps = (9.21+.00091*t)*cos(nm)+(.5522-.00029*t)*cos(tls)
		   -.0904*cos(tnm)+.0884*cos(tld)+.0216*cos(tls+ms)
		   +.0183*cos(tld-nm)+.0113*cos(tld+md)-.0093*cos(tls-ms)
		   -.0066*cos(tls-nm);

	/* convert to radians.
	 */
	lastdpsi = degrad(lastdpsi/3600);
	lastdeps = degrad(lastdeps/3600);

	lastmjd = mjd;
	*deps = lastdeps;
	*dpsi = lastdpsi;
}
xXx
echo extracting obliq.c
cat > obliq.c << 'xXx'
#include <stdio.h>
#include "astro.h"

/* given the modified Julian date, mjd, find the obliquity of the
 * ecliptic, *eps, in radians.
 */
obliquity (mjd, eps)
float mjd;
float *eps;
{
	static float lastmjd, lasteps;

	if (mjd != lastmjd) {
	    float t;
	    t = mjd/36525.;
	    lasteps = degrad(2.345229444E1 - ((((-1.81E-3*t)+5.9E-3)*t+4.6845E1)*t)/3600.0);
	    lastmjd = mjd;
	}
	*eps = lasteps;
}
xXx
echo extracting parallax.c
cat > parallax.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given true ha and dec, tha and tdec, the geographical latitude, phi, the
 * height above sea-level (as a fraction of the earths radius, 6378.16km),
 * ht, and the equatorial horizontal parallax, ehp, find the apparent
 * ha and dec, aha and adec allowing for parallax.
 * all angles in radians. ehp is the angle subtended at the body by the
 * earth's equator.
 */
ta_par (tha, tdec, phi, ht, ehp, aha, adec)
float tha, tdec, phi, ht, ehp;
float *aha, *adec;
{
	static float last_phi, last_ht, rsp, rcp;
	float rp;	/* distance to object in Earth radii */
	float ctha;
	float stdec, ctdec;
	float tdtha, dtha;
	float caha;

	/* avoid calcs involving the same phi and ht */
	if (phi != last_phi || ht != last_ht) {
	    float cphi, sphi, u;
	    cphi = cos(phi);
	    sphi = sin(phi);
	    u = atan(9.96647e-1*sphi/cphi);
	    rsp = (9.96647e-1*sin(u))+(ht*sphi);
	    rcp = cos(u)+(ht*cphi);
	    last_phi  =  phi;
	    last_ht  =  ht;
	}

        rp = 1/sin(ehp);

        ctha = cos(tha);
	stdec = sin(tdec);
	ctdec = cos(tdec);
        tdtha = (rcp*sin(tha))/((rp*ctdec)-(rcp*ctha));
        dtha = atan(tdtha);
	*aha = tha+dtha;
	caha = cos(*aha);
	range (aha, 2*PI);
        *adec = atan(caha*(rp*stdec-rsp)/(rp*ctdec*ctha-rcp));
}

/* given the apparent ha and dec, aha and adec, the geographical latitude, phi,
 * the height above sea-level (as a fraction of the earths radius, 6378.16km),
 * ht, and the equatorial horizontal parallax, ehp, find the true ha and dec,
 * tha and tdec allowing for parallax.
 * all angles in radians. ehp is the angle subtended at the body by the
 * earth's equator.
 * uses ta_par() iteratively: find a set of true ha/dec that converts back
  *  to the given apparent ha/dec.
 */
at_par (aha, adec, phi, ht, ehp, tha, tdec)
float aha, adec, phi, ht, ehp;
float *tha, *tdec;
{
	float nha, ndec;	/* ha/dec corres. to current true guesses */
	float eha, edec;	/* error in ha/dec */

	/* first guess for true is just the apparent */
	*tha = aha;
	*tdec = adec;

	while (1) {
	    ta_par (*tha, *tdec, phi, ht, ehp, &nha, &ndec);
	    eha = aha - nha;
	    edec = adec - ndec;
	    if (fabs(eha)<1e-6 && fabs(edec)<1e-6)
		break;
	    *tha += eha;
	    *tdec += edec;
	}
}
xXx
echo extracting pelement.c
cat > pelement.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* this array contains polynomial coefficients to find the various orbital
 *   elements for the mean orbit at any instant in time for each major planet.
 *   the first five elements are in the form a0 + a1*t + a2*t**2 + a3*t**3,
 *   where t is the number of Julian centuries of 36525 Julian days since 1900
 *   Jan 0.5. the last three elements are constants.
 *
 * the orbital element (column) indeces are:
 *   [ 0- 3]: coefficients for mean longitude, in degrees;
 *   [ 4- 7]: coefficients for longitude of the perihelion, in degrees;
 *   [ 8-11]: coefficients for eccentricity;
 *   [12-15]: coefficients for inclination, in degrees;
 *   [16-19]: coefficients for longitude of the ascending node, in degrees;
 *      [20]: semi-major axis, in AU;
 *      [21]: angular diameter at 1 AU, in arcsec;
 *      [22]: standard visual magnitude, ie, the visual magnitude of the planet
 *	      when at a distance of 1 AU from both the Sun and the Earth and
 *	      with zero phase angle.
 *
 * the planent (row) indeces are:
 *   [0]: Mercury; [1]: Venus;   [2]: Mars;  [3]: Jupiter; [4]: Saturn;
 *   [5]: Uranus;  [6]: Neptune; [7]: Pluto.
 */
#define	NPELE	(5*4 + 3)	/* 4 coeffs for ea of 5 elems, + 3 constants */
static float elements[8][NPELE] = {

	{   /*     mercury... */

	    178.179078,	415.2057519,	3.011e-4,	0.0,
	    75.899697,	1.5554889,	2.947e-4,	0.0,
	    .20561421,	2.046e-5,	3e-8,		0.0,
	    7.002881,	1.8608e-3,	-1.83e-5,	0.0,
	    47.145944,	1.1852083,	1.739e-4,	0.0,
	    .3870986,	6.74, 		-0.42
	},

	{   /*     venus... */

	    342.767053,	162.5533664,	3.097e-4,	0.0,
	    130.163833,	1.4080361,	-9.764e-4,	0.0,
	    6.82069e-3,	-4.774e-5,	9.1e-8,		0.0,
	    3.393631,	1.0058e-3,	-1e-6,		0.0,
	    75.779647,	.89985,		4.1e-4,		0.0,
	    .7233316,	16.92,		-4.4
	},

	{   /*     mars... */

	    293.737334,	53.17137642,	3.107e-4,	0.0,
	    3.34218203e2, 1.8407584,	1.299e-4,	-1.19e-6,
	    9.33129e-2,	9.2064e-5,	7.7e-8,		0.0,
	    1.850333,	-6.75e-4,	1.26e-5,	0.0,
	    48.786442,	.7709917,	-1.4e-6,	-5.33e-6,
	    1.5236883,	9.36,		-1.52
	},

	{   /*     jupiter... */

	    238.049257,	8.434172183,	3.347e-4,	-1.65e-6,
	    1.2720972e1, 1.6099617,	1.05627e-3,	-3.43e-6,
	    4.833475e-2, 1.6418e-4,	-4.676e-7,	-1.7e-9,
	    1.308736,	-5.6961e-3,	3.9e-6,		0.0,
	    99.443414,	1.01053,	3.5222e-4,	-8.51e-6,
	    5.202561,	196.74,		-9.4
	},

	{   /*     saturn... */

	    266.564377,	3.398638567,	3.245e-4,	-5.8e-6,
	    9.1098214e1, 1.9584158,	8.2636e-4,	4.61e-6,
	    5.589232e-2, -3.455e-4,	-7.28e-7,	7.4e-10,
	    2.492519,	-3.9189e-3,	-1.549e-5,	4e-8,
	    112.790414,	.8731951,	-1.5218e-4,	-5.31e-6,
	    9.554747,	165.6,		-8.88
	},

	{   /*     uranus... */

	    244.19747,	1.194065406,	3.16e-4,	-6e-7,
	    1.71548692e2, 1.4844328,	2.372e-4,	-6.1e-7,
	    4.63444e-2,	-2.658e-5,	7.7e-8,		0.0,
	    .772464,	6.253e-4,	3.95e-5,	0.0,
	    73.477111,	.4986678,	1.3117e-3,	0.0,
	    19.21814,	65.8,		-7.19
	},

	{   /*     neptune... */

	    84.457994,	.6107942056,	3.205e-4,	-6e-7,
	    4.6727364e1, 1.4245744,	3.9082e-4,	-6.05e-7,
	    8.99704e-3,	6.33e-6,	-2e-9,		0.0,
	    1.779242,	-9.5436e-3,	-9.1e-6,	0.0,
	    130.681389,	1.098935,	2.4987e-4,	-4.718e-6,
	    30.10957,	62.2,		-6.87
	},

	{   /*     pluto...(osculating 1984 jan 21) */

	    95.3113544,	.3980332167,	0.0,		0.0,
	    224.017,	0.0,		0.0,		0.0,
	    .25515,	0.0,		0.0,		0.0,
	    17.1329,	0.0,		0.0,		0.0,
	    110.191,	0.0,		0.0,		0.0,
	    39.8151,	8.2,		-1.0
	}
};

/* given a modified Julian date, mjd, return the elements for the mean orbit
 *   at that instant of all the major planets, together with their
 *   mean daily motions in longitude, angular diameter and standard visual
 *   magnitude.
 * plan[i][j] contains all the values for all the planets at mjd, such that
 *   i = 0..7: mercury, venus, mars, jupiter, saturn, unranus, neptune, pluto;
 *   j = 0..8: mean longitude, mean daily motion in longitude, longitude of 
 *     the perihelion, eccentricity, inclination, longitude of the ascending
 *     node, length of the semi-major axis, angular diameter from 1 AU, and
 *     the standard visual magnitude (see elements[][] comment, above).
 */
pelement (mjd, plan)
float mjd;
float plan[8][9];
{
	register float *ep, *pp;
	register float t = mjd/36525.;
	float aa;
	int planet, i;

	for (planet = 0; planet < 8; planet++) {
	    ep = elements[planet];
	    pp = plan[planet];
	    aa = ep[1]*t;
	    pp[0] = ep[0] + 360.*(aa-(int)aa) + (ep[3]*t + ep[2])*t*t;
	    range (pp, 360.);
	    pp[1] = (ep[1]*9.856263e-3) + (ep[2] + ep[3])/36525;

	    for (i = 4; i < 20; i += 4)
		pp[i/4+1] = ((ep[i+3]*t + ep[i+2])*t + ep[i+1])*t + ep[i+0];

	    pp[6] = ep[20];
	    pp[7] = ep[21];
	    pp[8] = ep[22];
	}
}
xXx
echo extracting plans.c
cat > plans.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

#define	TWOPI		(2*PI)
#define	mod2PI(x)	((x) - (int)((x)/TWOPI)*TWOPI)

/* given a modified Julian date, mjd, and a planet, p, find:
 *   lpd0: heliocentric longitude, 
 *   psi0: heliocentric latitude,
 *   rp0:  distance from the sun to the planet, 
 *   rho0: distance from the Earth to the planet,
 *         none corrected for light time, ie, they are the true values for the
 *         given instant.
 *   lam:  geocentric ecliptic longitude, 
 *   bet:  geocentric ecliptic latitude,
 *         each corrected for light time, ie, they are the apparent values as
 *	   seen from the center of the Earth for the given instant.
 *   dia:  angular diameter in arcsec at 1 AU, 
 *   mag:  visual magnitude when 1 AU from sun and earth at 0 phase angle.
 *
 * all angles are in radians, all distances in AU.
 * the mean orbital elements are found by calling pelement(), then mutual
 *   perturbation corrections are applied as necessary.
 *
 * corrections for nutation and abberation must be made by the caller. The RA 
 *   and DEC calculated from the fully-corrected ecliptic coordinates are then
 *   the apparent geocentric coordinates. Further corrections can be made, if
 *   required, for atmospheric refraction and geocentric parallax although the
 *   intrinsic error herein of about 10 arcseconds is usually the dominant
 *   error at this stage.
 * TODO: combine the several intermediate expressions when get a good compiler.
 */
plans (mjd, p, lpd0, psi0, rp0, rho0, lam, bet, dia, mag)
float mjd;
int p;
float *lpd0, *psi0, *rp0, *rho0, *lam, *bet, *dia, *mag;
{
	static float plan[8][9];
	static lastmjd = -10000;
	float dl;	/* perturbation correction for longitude */
	float dr;	/*  "   orbital radius */
	float dml;	/*  "   mean longitude */
	float ds;	/*  "   eccentricity */
	float dm;	/*  "   mean anomaly */
	float da;	/*  "   semi-major axis */
	float dhl;	/*  "   heliocentric longitude */
	float lsn, rsn;	/* true geocentric longitude of sun and sun-earth rad */
	float mas;	/* mean anomaly of the sun */
	float re;	/* radius of earth's orbit */
	float lg;	/* longitude of earth */
	float map[8];	/* array of mean anomalies for each planet */
	float lpd, psi, rp, rho;
	float ll, sll, cll;
	float t;
	float dt;
	int pass;
	int j;
	float s, ma;
	float nu, ea;
	float lp, om;
	float lo, slo, clo;
	float inc, y;
	float spsi, cpsi;
	float rpd;

	/* only need to fill in plan[] once for a given mjd */
	if (mjd != lastmjd) {
	    pelement (mjd, plan);
	    lastmjd = mjd;
	}

	dt = 0;
	t = mjd/36525.;
	sun (mjd, &lsn, &rsn);
	masun (mjd, &mas);
        re = rsn;
	lg = lsn+PI;

	/* first find the true position of the planet at mjd.
	 * then repeat a second time for a slightly different time based
	 * on the position found in the first pass to account for light-travel
	 * time.
	 */
	for (pass = 0; pass < 2; pass++) {

	    for (j = 0; j < 8; j++)
		map[j] = degrad(plan[j][0]-plan[j][2]-dt*plan[j][1]);

	    /* set initial corrections to 0.
	     * then modify as necessary for the planet of interest.
	     */
	    dl = 0;
	    dr = 0;
	    dml = 0;
	    ds = 0;
	    dm = 0;
	    da = 0;
	    dhl = 0;

	    switch (p) {

	    case MERCURY:
		p_mercury (map, &dl, &dr);
		break;

	    case VENUS:
		p_venus (t, mas, map, &dl, &dr, &dml, &dm);
		break;

	    case MARS:
		p_mars (mas, map, &dl, &dr, &dml, &dm);
		break;

	    case JUPITER:
		p_jupiter (t, plan[p][3], &dml, &ds, &dm, &da);
		break;

	    case SATURN:
		p_saturn (t, plan[p][3], &dml, &ds, &dm, &da, &dhl);
		break;

	    case URANUS:
		p_uranus (t, plan[p][3], &dl, &dr, &dml, &ds, &dm, &da, &dhl);
		break;

	    case NEPTUNE:
		p_neptune (t, plan[p][3], &dl, &dr, &dml, &ds, &dm, &da, &dhl);
		break;

	    case PLUTO:
		/* no perturbation theory for pluto */
		break;
	    }

	    s = plan[p][3]+ds;
	    ma = map[p]+dm;
	    anomaly (ma, s, &nu, &ea);
	    rp = (plan[p][6]+da)*(1-s*s)/(1+s*cos(nu));
	    lp = raddeg(nu)+plan[p][2]+raddeg(dml-dm);
	    lp = degrad(lp);
	    om = degrad(plan[p][5]);
	    lo = lp-om;
	    slo = sin(lo);
	    clo = cos(lo);
	    inc = degrad(plan[p][4]);
	    rp = rp+dr;
	    spsi = slo*sin(inc);
	    y = slo*cos(inc);
	    psi = asin(spsi)+dhl;
	    spsi = sin(psi);
	    lpd = atan(y/clo)+om+degrad(dl);
	    if (clo<0) lpd += PI;
	    if (lpd>TWOPI) lpd -= TWOPI;
	    cpsi = cos(psi);
	    rpd = rp*cpsi;
	    ll = lpd-lg;
	    rho = sqrt(re*re+rp*rp-2*re*rp*cpsi*cos(ll));

	    /* when we view a planet we see it in the position it occupied
	     * dt hours ago, where rho is the distance between it and earth,
	     * in AU. use this as the new time for the next pass.
	     */
	    dt = rho*5.775518e-3;

	    if (pass == 0) {
		/* save heliocentric coordinates after first pass since, being
		 * true, they are NOT to be corrected for light-travel time.
		 */
		*lpd0 = lpd;
		*psi0 = psi;
		*rp0 = rp;
		*rho0 = rho;
	    }
	}

        sll = sin(ll);
	cll = cos(ll);
        if (p < MARS) 
	    *lam = atan(-1*rpd*sll/(re-rpd*cll))+lg+PI;
	else
	    *lam = atan(re*sll/(rpd-re*cll))+lpd;
	range (lam, TWOPI);
        *bet = atan(rpd*spsi*sin(*lam-lpd)/(cpsi*re*sll));
	*dia = plan[p][7];
	*mag = plan[p][8];
}

/* set auxilliary variables used for jupiter, saturn, uranus, and neptune */
static
aux_jsun (t, j1, j2, j3, j4, j5, j6)
float t;
float *j1, *j2, *j3, *j4, *j5, *j6;
{
        *j1 = t/5+0.1;
        *j2 = mod2PI(4.14473+5.29691e1*t);
        *j3 = mod2PI(4.641118+2.132991e1*t);
        *j4 = mod2PI(4.250177+7.478172*t);
        *j5 = 5 * *j3 - 2 * *j2;
	*j6 = 2 * *j2 - 6 * *j3 + 3 * *j4;
}

/* find the mean anomaly of the sun at mjd.
 * this is the same as that used in sun() but when it was converted to C it
 * was not known it would be required outside that routine.
 * TODO: add an argument to sun() to return mas and eliminate this routine.
 */
static
masun (mjd, mas)
float mjd;
float *mas;
{
	float t, t2;
	float a, b;

	t = mjd/36525;
	t2 = t*t;
	a = 9.999736042e1*t;
	b = 360.*(a-(int)a);
	*mas = degrad (3.5847583e2-(1.5e-4+3.3e-6*t)*t2+b);
}

/* perturbations for mercury */
static
p_mercury (map, dl, dr)
float map[];
float *dl, *dr;
{
	*dl = 2.04e-3*cos(5*map[2-1]-2*map[1-1]+2.1328e-1)+
	     1.03e-3*cos(2*map[2-1]-map[1-1]-2.8046)+
	     9.1e-4*cos(2*map[3]-map[1-1]-6.4582e-1)+
	     7.8e-4*cos(5*map[2-1]-3*map[1-1]+1.7692e-1);

	*dr = 7.525e-6*cos(2*map[3]-map[1-1]+9.25251e-1)+
	     6.802e-6*cos(5*map[2-1]-3*map[1-1]-4.53642)+
	     5.457e-6*cos(2*map[2-1]-2*map[1-1]-1.24246)+
	     3.569e-6*cos(5*map[2-1]-map[1-1]-1.35699);
}

/* ....venus */
static
p_venus (t, mas, map, dl, dr, dml, dm)
float t, mas, map[];
float *dl, *dr, *dml, *dm;
{
	*dml = degrad (7.7e-4*sin(4.1406+t*2.6227));
	*dm = *dml;

	*dl = 3.13e-3*cos(2*mas-2*map[2-1]-2.587)+
	     1.98e-3*cos(3*mas-3*map[2-1]+4.4768e-2)+
	     1.36e-3*cos(mas-map[2-1]-2.0788)+
	     9.6e-4*cos(3*mas-2*map[2-1]-2.3721)+
	     8.2e-4*cos(map[3]-map[2-1]-3.6318);

	*dr = 2.2501e-5*cos(2*mas-2*map[2-1]-1.01592)+
	     1.9045e-5*cos(3*mas-3*map[2-1]+1.61577)+
	     6.887e-6*cos(map[3]-map[2-1]-2.06106)+
	     5.172e-6*cos(mas-map[2-1]-5.08065e-1)+
	     3.62e-6*cos(5*mas-4*map[2-1]-1.81877)+
	     3.283e-6*cos(4*mas-4*map[2-1]+1.10851)+
	     3.074e-6*cos(2*map[3]-2*map[2-1]-9.62846e-1);
}

/* ....mars */
static
p_mars (mas, map, dl, dr, dml, dm)
float mas, map[];
float *dl, *dr, *dml, *dm;
{
	float a;

	a = 3*map[3]-8*map[2]+4*mas;
	*dml = degrad (-1*(1.133e-2*sin(a)+9.33e-3*cos(a)));
	*dm = *dml;

	*dl = 7.05e-3*cos(map[3]-map[2]-8.5448e-1)+
	     6.07e-3*cos(2*map[3]-map[2]-3.2873)+
	     4.45e-3*cos(2*map[3]-2*map[2]-3.3492)+
	     3.88e-3*cos(mas-2*map[2]+3.5771e-1)+
	     2.38e-3*cos(mas-map[2]+6.1256e-1)+
	     2.04e-3*cos(2*mas-3*map[2]+2.7688)+
	     1.77e-3*cos(3*map[2]-map[2-1]-1.0053)+
	     1.36e-3*cos(2*mas-4*map[2]+2.6894)+
	     1.04e-3*cos(map[3]+3.0749e-1);

	*dr = 5.3227e-5*cos(map[3]-map[2]+7.17864e-1)+
	     5.0989e-5*cos(2*map[3]-2*map[2]-1.77997)+
	     3.8278e-5*cos(2*map[3]-map[2]-1.71617)+
	     1.5996e-5*cos(mas-map[2]-9.69618e-1)+
	     1.4764e-5*cos(2*mas-3*map[2]+1.19768)+
	     8.966e-6*cos(map[3]-2*map[2]+7.61225e-1)+
	     7.914e-6*cos(3*map[3]-2*map[2]-2.43887)+
	     7.004e-6*cos(2*map[3]-3*map[2]-1.79573)+
	     6.62e-6*cos(mas-2*map[2]+1.97575)+
	     4.93e-6*cos(3*map[3]-3*map[2]-1.33069)+
	     4.693e-6*cos(3*mas-5*map[2]+3.32665)+
	     4.571e-6*cos(2*mas-4*map[2]+4.27086)+
	     4.409e-6*cos(3*map[3]-map[2]-2.02158);
}

/* ....jupiter */
static
p_jupiter (t, s, dml, ds, dm, da)
float t, s;
float *dml, *ds, *dm, *da;
{
	float dp;
	float j1, j2, j3, j4, j5, j6, j7;
	float sj3, cj3, s2j3, c2j3;
        float sj5, cj5, s2j5;
	float sj6;
        float sj7, cj7, s2j7, c2j7, s3j7, c3j7, s4j7, c4j7, c5j7;

	aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6);
        j7 = j3-j2;
	sj3 = sin(j3);
	cj3 = cos(j3);
        s2j3 = sin(2*j3);
	c2j3 = cos(2*j3);
        sj5 = sin(j5);
	cj5 = cos(j5);
        s2j5 = sin(2*j5);
	sj6 = sin(j6);
        sj7 = sin(j7);
	cj7 = cos(j7);
        s2j7 = sin(2*j7);
	c2j7 = cos(2*j7);
        s3j7 = sin(3*j7);
	c3j7 = cos(3*j7);
        s4j7 = sin(4*j7);
	c4j7 = cos(4*j7);
        c5j7 = cos(5*j7);

	*dml = (3.31364e-1-(1.0281e-2+4.692e-3*j1)*j1)*sj5+
	      (3.228e-3-(6.4436e-2-2.075e-3*j1)*j1)*cj5-
	      (3.083e-3+(2.75e-4-4.89e-4*j1)*j1)*s2j5+
	      2.472e-3*sj6+1.3619e-2*sj7+1.8472e-2*s2j7+6.717e-3*s3j7+
	      2.775e-3*s4j7+6.417e-3*s2j7*sj3+
	      (7.275e-3-1.253e-3*j1)*sj7*sj3+
	      2.439e-3*s3j7*sj3-(3.5681e-2+1.208e-3*j1)*sj7*cj3-
	      3.767e-3*c2j7*sj3-(3.3839e-2+1.125e-3*j1)*cj7*sj3-
	      4.261e-3*s2j7*cj3+
	      (1.161e-3*j1-6.333e-3)*cj7*cj3+
	      2.178e-3*cj3-6.675e-3*c2j7*cj3-2.664e-3*c3j7*cj3-
	      2.572e-3*sj7*s2j3-3.567e-3*s2j7*s2j3+2.094e-3*cj7*c2j3+
	      3.342e-3*c2j7*c2j3;
	*dml = degrad(*dml);

	*ds = (3606+(130-43*j1)*j1)*sj5+(1289-580*j1)*cj5-6764*sj7*sj3-
	     1110*s2j7*sj3-224*s3j7*sj3-204*sj3+(1284+116*j1)*cj7*sj3+
	     188*c2j7*sj3+(1460+130*j1)*sj7*cj3+224*s2j7*cj3-817*cj3+
	     6074*cj3*cj7+992*c2j7*cj3+
	     508*c3j7*cj3+230*c4j7*cj3+108*c5j7*cj3-
	     (956+73*j1)*sj7*s2j3+448*s2j7*s2j3+137*s3j7*s2j3+
	     (108*j1-997)*cj7*s2j3+480*c2j7*s2j3+148*c3j7*s2j3+
	     (99*j1-956)*sj7*c2j3+490*s2j7*c2j3+
	     158*s3j7*c2j3+179*c2j3+(1024+75*j1)*cj7*c2j3-
	     437*c2j7*c2j3-132*c3j7*c2j3;
	*ds *= 1e-7;

	dp = (7.192e-3-3.147e-3*j1)*sj5-4.344e-3*sj3+
	     (j1*(1.97e-4*j1-6.75e-4)-2.0428e-2)*cj5+
	     3.4036e-2*cj7*sj3+(7.269e-3+6.72e-4*j1)*sj7*sj3+
	     5.614e-3*c2j7*sj3+2.964e-3*c3j7*sj3+3.7761e-2*sj7*cj3+
	     6.158e-3*s2j7*cj3-
	     6.603e-3*cj7*cj3-5.356e-3*sj7*s2j3+2.722e-3*s2j7*s2j3+
	     4.483e-3*cj7*s2j3-2.642e-3*c2j7*s2j3+4.403e-3*sj7*c2j3-
	     2.536e-3*s2j7*c2j3+5.547e-3*cj7*c2j3-2.689e-3*c2j7*c2j3;

	*dm = *dml-(degrad(dp)/s);

	*da = 205*cj7-263*cj5+693*c2j7+312*c3j7+147*c4j7+299*sj7*sj3+
	     181*c2j7*sj3+204*s2j7*cj3+111*s3j7*cj3-337*cj7*cj3-
	     111*c2j7*cj3;
	*da *= 1e-6;
}

/* ....saturn */
static
p_saturn (t, s, dml, ds, dm, da, dhl)
float t, s;
float *dml, *ds, *dm, *da, *dhl;
{
	float dp;
	float j1, j2, j3, j4, j5, j6, j7, j8;
	float sj3, cj3, s2j3, c2j3, s3j3, c3j3, s4j3, c4j3;
        float sj5, cj5, s2j5, c2j5;
	float sj6;
        float sj7, cj7, s2j7, c2j7, s3j7, c3j7, s4j7, c4j7, c5j7, s5j7;
	float s2j8, c2j8, s3j8, c3j8;

	aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6);
        j7 = j3-j2;
	sj3 = sin(j3);
	cj3 = cos(j3);
        s2j3 = sin(2*j3);
	c2j3 = cos(2*j3);
        sj5 = sin(j5);
	cj5 = cos(j5);
        s2j5 = sin(2*j5);
	sj6 = sin(j6);
        sj7 = sin(j7);
	cj7 = cos(j7);
        s2j7 = sin(2*j7);
	c2j7 = cos(2*j7);
        s3j7 = sin(3*j7);
	c3j7 = cos(3*j7);
        s4j7 = sin(4*j7);
	c4j7 = cos(4*j7);
        c5j7 = cos(5*j7);

	s3j3 = sin(3*j3);
	c3j3 = cos(3*j3);
	s4j3 = sin(4*j3);
	c4j3 = cos(4*j3);
	c2j5 = cos(2*j5);
	s5j7 = sin(5*j7);
	j8 = j4-j3;
	s2j8 = sin(2*j8);
	c2j8 = cos(2*j8);
	s3j8 = sin(3*j8);
	c3j8 = cos(3*j8);

	*dml = 7.581e-3*s2j5-7.986e-3*sj6-1.48811e-1*sj7-4.0786e-2*s2j7-
	      (8.14181e-1-(1.815e-2-1.6714e-2*j1)*j1)*sj5-
	      (1.0497e-2-(1.60906e-1-4.1e-3*j1)*j1)*cj5-1.5208e-2*s3j7-
	      6.339e-3*s4j7-6.244e-3*sj3-1.65e-2*s2j7*sj3+
	      (8.931e-3+2.728e-3*j1)*sj7*sj3-5.775e-3*s3j7*sj3+
	      (8.1344e-2+3.206e-3*j1)*cj7*sj3+1.5019e-2*c2j7*sj3+
	      (8.5581e-2+2.494e-3*j1)*sj7*cj3+1.4394e-2*c2j7*cj3+
	      (2.5328e-2-3.117e-3*j1)*cj7*cj3+
	      6.319e-3*c3j7*cj3+6.369e-3*sj7*s2j3+9.156e-3*s2j7*s2j3+
	      7.525e-3*s3j8*s2j3-5.236e-3*cj7*c2j3-7.736e-3*c2j7*c2j3-
	      7.528e-3*c3j8*c2j3;
	*dml = degrad(*dml);

	*ds = (-7927+(2548+91*j1)*j1)*sj5+(13381+(1226-253*j1)*j1)*cj5+
	     (248-121*j1)*s2j5-(305+91*j1)*c2j5+412*s2j7+12415*sj3+
	     (390-617*j1)*sj7*sj3+(165-204*j1)*s2j7*sj3+26599*cj7*sj3-
	     4687*c2j7*sj3-1870*c3j7*sj3-821*c4j7*sj3-
	     377*c5j7*sj3+497*c2j8*sj3+(163-611*j1)*cj3-
	     12696*sj7*cj3-4200*s2j7*cj3-1503*s3j7*cj3-619*s4j7*cj3-
	     268*s5j7*cj3-(282+1306*j1)*cj7*cj3+(-86+230*j1)*c2j7*cj3+
	     461*s2j8*cj3-350*s2j3+(2211-286*j1)*sj7*s2j3-
	     2208*s2j7*s2j3-568*s3j7*s2j3-346*s4j7*s2j3-
	     (2780+222*j1)*cj7*s2j3+(2022+263*j1)*c2j7*s2j3+248*c3j7*s2j3+
	     242*s3j8*s2j3+467*c3j8*s2j3-490*c2j3-(2842+279*j1)*sj7*c2j3+
	     (128+226*j1)*s2j7*c2j3+224*s3j7*c2j3+
	     (-1594+282*j1)*cj7*c2j3+(2162-207*j1)*c2j7*c2j3+
	     561*c3j7*c2j3+343*c4j7*c2j3+469*s3j8*c2j3-242*c3j8*c2j3-
	     205*sj7*s3j3+262*s3j7*s3j3+208*cj7*c3j3-271*c3j7*c3j3-
	     382*c3j7*s4j3-376*s3j7*c4j3;
	*ds *= 1e-7;

	dp = (7.7108e-2+(7.186e-3-1.533e-3*j1)*j1)*sj5-7.075e-3*sj7+
	     (4.5803e-2-(1.4766e-2+5.36e-4*j1)*j1)*cj5-7.2586e-2*cj3-
	     7.5825e-2*sj7*sj3-2.4839e-2*s2j7*sj3-8.631e-3*s3j7*sj3-
	     1.50383e-1*cj7*cj3+2.6897e-2*c2j7*cj3+1.0053e-2*c3j7*cj3-
	     (1.3597e-2+1.719e-3*j1)*sj7*s2j3+1.1981e-2*s2j7*c2j3-
	     (7.742e-3-1.517e-3*j1)*cj7*s2j3+
	     (1.3586e-2-1.375e-3*j1)*c2j7*c2j3-
	     (1.3667e-2-1.239e-3*j1)*sj7*c2j3+
	     (1.4861e-2+1.136e-3*j1)*cj7*c2j3-
	     (1.3064e-2+1.628e-3*j1)*c2j7*c2j3;

	*dm = *dml-(degrad(dp)/s);

	*da = 572*sj5-1590*s2j7*cj3+2933*cj5-647*s3j7*cj3+33629*cj7-
	     344*s4j7*cj3-3081*c2j7+2885*cj7*cj3-1423*c3j7+
	     (2172+102*j1)*c2j7*cj3-671*c4j7+296*c3j7*cj3-320*c5j7-
	     267*s2j7*s2j3+1098*sj3-778*cj7*s2j3-2812*sj7*sj3+
	     495*c2j7*s2j3+688*s2j7*sj3+250*c3j7*s2j3-393*s3j7*sj3-
	     856*sj7*c2j3-228*s4j7*sj3+441*s2j7*c2j3+2138*cj7*sj3+
	     296*c2j7*c2j3-999*c2j7*sj3+211*c3j7*c2j3-642*c3j7*sj3-
	     427*sj7*s3j3-325*c4j7*sj3+398*s3j7*s3j3-890*cj3+
	     344*cj7*c3j3+2206*sj7*cj3-427*c3j7*c3j3;
	*da *= 1e-6;

	*dhl = 7.47e-4*cj7*sj3+1.069e-3*cj7*cj3+2.108e-3*s2j7*s2j3+
	      1.261e-3*c2j7*s2j3+1.236e-3*s2j7*c2j3-2.075e-3*c2j7*c2j3;
	*dhl = degrad(*dhl);
}

/* ....uranus */
static
p_uranus (t, s, dl, dr, dml, ds, dm, da, dhl)
float t, s;
float *dl, *dr, *dml, *ds, *dm, *da, *dhl;
{
	float dp;
	float j1, j2, j3, j4, j5, j6;
	float j8, j9, j10, j11, j12;
	float sj4, cj4, s2j4, c2j4;
	float sj9, cj9, s2j9, c2j9;
	float sj11, cj11;

	aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6);

        j8 = mod2PI(1.46205+3.81337*t);
        j9 = 2*j8-j4;
	sj9 = sin(j9);
	cj9 = cos(j9);
        s2j9 = sin(2*j9);
	c2j9 = cos(2*j9);

	j10 = j4-j2;
	j11 = j4-j3;
	j12 = j8-j4;

	*dml = (8.64319e-1-1.583e-3*j1)*sj9+(8.2222e-2-6.833e-3*j1)*cj9+
	      3.6017e-2*s2j9-3.019e-3*c2j9+8.122e-3*sin(j6);
	*dml = degrad(*dml);

	dp = 1.20303e-1*sj9+6.197e-3*s2j9+(1.9472e-2-9.47e-4*j1)*cj9;
	*dm = *dml-(degrad(dp)/s);

	*ds = (163*j1-3349)*sj9+20981*cj9+1311*c2j9;
	*ds *= 1e-7;

	*da = -3.825e-3*cj9;

	*dl = (1.0122e-2-9.88e-4*j1)*sin(j4+j11)+
	     (-3.8581e-2+(2.031e-3-1.91e-3*j1)*j1)*cos(j4+j11)+
	     (3.4964e-2-(1.038e-3-8.68e-4*j1)*j1)*cos(2*j4+j11)+
	     5.594e-3*sin(j4+3*j12)-1.4808e-2*sin(j10)-
	     5.794e-3*sin(j11)+2.347e-3*cos(j11)+9.872e-3*sin(j12)+
	     8.803e-3*sin(2*j12)-4.308e-3*sin(3*j12);

	sj11 = sin(j11);
	cj11 = cos(j11);
	sj4 = sin(j4);
	cj4 = cos(j4);
	s2j4 = sin(2*j4);
	c2j4 = cos(2*j4);
	*dhl = (4.58e-4*sj11-6.42e-4*cj11-5.17e-4*cos(4*j12))*sj4-
	      (3.47e-4*sj11+8.53e-4*cj11+5.17e-4*sin(4*j11))*cj4+
	      4.03e-4*(cos(2*j12)*s2j4+sin(2*j12)*c2j4);
	*dhl = degrad(*dhl);

	*dr = -25948+4985*cos(j10)-1230*cj4+3354*cos(j11)+904*cos(2*j12)+
	     894*(cos(j12)-cos(3*j12))+(5795*cj4-1165*sj4+1388*c2j4)*sj11+
	     (1351*cj4+5702*sj4+1388*s2j4)*cos(j11);
	*dr *= 1e-6;
}

/* ....neptune */
static
p_neptune (t, s, dl, dr, dml, ds, dm, da, dhl)
float t, s;
float *dl, *dr, *dml, *ds, *dm, *da, *dhl;
{
	float dp;
	float j1, j2, j3, j4, j5, j6;
	float j8, j9, j10, j11, j12;
	float sj8, cj8;
	float sj9, cj9, s2j9, c2j9;
	float s2j12, c2j12;

	aux_jsun (t, &j1, &j2, &j3, &j4, &j5, &j6);

        j8 = mod2PI(1.46205+3.81337*t);
        j9 = 2*j8-j4;
	sj9 = sin(j9);
	cj9 = cos(j9);
        s2j9 = sin(2*j9);
	c2j9 = cos(2*j9);

	j10 = j8-j2;
	j11 = j8-j3;
	j12 = j8-j4;

	*dml = (1.089e-3*j1-5.89833e-1)*sj9+(4.658e-3*j1-5.6094e-2)*cj9-
	      2.4286e-2*s2j9;
	*dml = degrad(*dml);

	dp = 2.4039e-2*sj9-2.5303e-2*cj9+6.206e-3*s2j9-5.992e-3*c2j9;

	*dm = *dml-(degrad(dp)/s);

	*ds = 4389*sj9+1129*s2j9+4262*cj9+1089*c2j9;
	*ds *= 1e-7;

	*da = 8189*cj9-817*sj9+781*c2j9;
	*da *= 1e-6;

	s2j12 = sin(2*j12);
	c2j12 = cos(2*j12);
	sj8 = sin(j8);
	cj8 = cos(j8);
	*dl = -9.556e-3*sin(j10)-5.178e-3*sin(j11)+2.572e-3*s2j12-
	     2.972e-3*c2j12*sj8-2.833e-3*s2j12*cj8;

	*dhl = 3.36e-4*c2j12*sj8+3.64e-4*s2j12*cj8;
	*dhl = degrad(*dhl);

	*dr = -40596+4992*cos(j10)+2744*cos(j11)+2044*cos(j12)+1051*c2j12;
	*dr *= 1e-6;
}
xXx
echo extracting precess.c
cat > precess.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* corrects ra and dec, both in radians, for precession from epoch 1 to epoch 2.
 * the epochs are given by their modified JDs, mjd1 and mjd2, respectively.
 * N.B. ra and dec are modifed IN PLACE.
 */
precess (mjd1, mjd2, ra, dec)
float mjd1, mjd2;	/* initial and final epoch modified JDs */
float *ra, *dec;	/* ra/dec for mjd1 in, for mjd2 out */
{
	static float lastmjd1, lastmjd2;
	static float m, n, nyrs;
	float dra, ddec;	/* ra and dec corrections */

	if (mjd1 != lastmjd1 || mjd2 != lastmjd2) {
	    float t1, t2; /* Julian centuries of 36525 days since Jan .5 1900 */
	    float m1, n1; /* "constants" for t1 */
	    float m2, n2; /* "constants" for t2 */
	    t1 = mjd1/36525.;
	    t2 = mjd2/36525.;
	    m1 = 3.07234+(1.86e-3*t1);
	    n1 = 20.0468-(8.5e-3*t1);
	    m2 = 3.07234+(1.86e-3*t2);
	    n2 = 20.0468-(8.5e-3*t2);
	    m = (m1+m2)/2;	/* average m for the two epochs */
	    n = (n1+n2)/2;	/* average n for the two epochs */
	    nyrs = (mjd2-mjd1)/365.2425;
	    lastmjd1 = mjd1;
	    lastmjd2 = mjd2;
	}

	dra = (m+(n*sin(*ra)*tan(*dec)/15))*7.272205e-5*nyrs;
	ddec = n*cos(*ra)*4.848137e-6*nyrs;
	*ra += dra;
	*dec += ddec;
	range (ra, 2*PI);
}
xXx
echo extracting refract.c
cat > refract.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* correct the true altitude, ta, for refraction to the apparent altitude, aa,
 * each in radians, given the local atmospheric pressure, pr, in mbars, and
 * the temperature, tr, in degrees C.
 */
refract (pr, tr, ta, aa)
float pr, tr;
float ta;
float *aa;
{
	float r;	/* refraction correction*/

        if (ta >= degrad(15.)) {
	    /* model for altitudes at least 15 degrees above horizon */
            r = 7.888888e-5*pr/((273+tr)*tan(ta));
	} else if (ta > degrad(-5.)) {
	    /* hairier model for altitudes at least -5 and below 15 degrees */
	    float a, b, tadeg = raddeg(ta);
	    a = ((2e-5*tadeg+1.96e-2)*tadeg+1.594e-1)*pr;
	    b = (273+tr)*((8.45e-2*tadeg+5.05e-1)*tadeg+1);
	    r = degrad(a/b);
	} else {
	    /* do nothing if more than 5 degrees below horizon.
	     */
	    r = 0;
	}

	*aa  =  ta + r;
}

/* correct the apparent altitude, aa, for refraction to the true altitude, ta,
 * each in radians, given the local atmospheric pressure, pr, in mbars, and
 * the temperature, tr, in degrees C.
 */
unrefract (pr, tr, aa, ta)
float pr, tr;
float aa;
float *ta;
{
	float err;
	float appar;
	float true;

	/* iterative solution: search for the true that refracts to the
	 *   given apparent.
	 * since refract() is discontinuous at -5 degrees, there is a range
	 *   of apparent altitudes between about -4.5 and -5 degrees that are
	 *   not invertable (the graph of ap vs. true has a vertical step at
	 *   true = -5). thus, the iteration just oscillates if it gets into
	 *   this region. if this happens the iteration is forced to abort.
	 *   of course, this makes unrefract() discontinuous too.
	 */
	true = aa;
	do {
	    refract (pr, tr, true, &appar);
	    err = appar - aa;
	    true -= err;
	} while (fabs(err) >= 1e-6 && true > degrad(-5));

	*ta = true;
}
xXx
echo extracting riset.c
cat > riset.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given the true geocentric ra and dec of an object, in radians, the observer's
 *   latitude in radians, and a horizon displacement correction, dis, in radians
 *   find the local sidereal times and azimuths of rising and setting, lstr/s
 *   and azr/s, in radians, respectively.
 * dis is the vertical displacement from the true position of the horizon. it
 *   is positive if the apparent position is higher than the true position.
 *   said another way, it is positive if the shift causes the object to spend
 *   longer above the horizon. for example, atmospheric refraction is typically
 *   assumed to produce a vertical shift of 34 arc minutes at the horizon; dis
 *   would then take on the value +9.89e-3 (radians). On the other hand, if
 *   your horizon has hills such that your apparent horizon is, say, 1 degree
 *   above sea level, you would allow for this by setting dis to -1.75e-2
 *   (radians).
 * status: 0: normal; 1: never rises; -1: circumpolar; 2: trouble.
 */
riset (ra, dec, lat, dis, lstr, lsts, azr, azs, status)
float ra, dec;
float lat, dis;
float *lstr, *lsts;
float *azr, *azs;
int *status;
{
	static float lastlat = 0, slat = 0, clat = 1.0;
	float dec1, sdec, cdec, tdec;
	float psi, spsi, cpsi;
	float h, dh, ch;	/* hr angle, delta and cos */

	/* avoid needless sin/cos since latitude doesn't change often */
        if (lat != lastlat) {
	    clat = cos(lat);
	    slat = sin(lat);
	    lastlat = lat;
	}

	/* can't cope with objects very near the celestial pole nor if we 
	 * are located very near the earth's poles.
	 */
	cdec = cos(dec);
        if (fabs(cdec*clat) < 1e-10) {
	    /* trouble */
	    *status = 2;
	    return;
	}

        cpsi = slat/cdec;
        if (cpsi>1.0) cpsi = 1.0;
        else if (cpsi<-1.0) cpsi = -1.0;
        psi = acos(cpsi);
	spsi = sin(psi);

        dh = dis*spsi;
	dec1 = dec + (dis*cpsi);
        sdec = sin(dec1);
	tdec = tan(dec1);

        ch = (-1*slat*tdec)/clat;

        if (ch < -1) {
	    /* circumpolar */
	    *status = -1;
	    return;
	}
        if (ch > 1) {
	    /* never rises */
	    *status = 1;
	    return;
	}

        *status = 0;
	h = acos(ch)+dh;

        *lstr = 24+radhr(ra-h);
	*lsts = radhr(ra+h);
	range (lstr, 24.0);
	range (lsts, 24.0);

	*azr = acos(sdec/clat);
	range (azr, 2*PI);
        *azs = 2*PI - *azr;
}
xXx
echo extracting sex_dec.c
cat > sex_dec.c << 'xXx'
/* given hours (or degrees), hd, minutes, m, and seconds, s, 
 * return decimal hours (or degrees), *d.
 * in the case of hours (angles) < 0, only the first non-zero element should
 *   be negative.
 */
sex_dec (hd, m, s, d)
int hd, m, s;
float *d;
{
	int sign = 1;

	if (hd < 0) {
	    sign = -1;
	    hd = -hd;
	} else if (m < 0) {
	    sign = -1;
	    m = -m;
	} else if (s < 0) {
	    sign = -1;
	    s = -s;
	}

	*d = ((s/60.0 + m)/60.0 + hd) * sign;
}

/* given decimal hours (or degrees), d.
 * return nearest hours (or degrees), *hd, minutes, *m, and seconds, *s, 
 * each always non-negative; *isneg is set to 1 if d is < 0, else to 0.
 */
dec_sex (d, hd, m, s, isneg)
float d;
int *hd, *m, *s, *isneg;
{
	float min;

	if (d < 0) {
	    *isneg = 1;
	    d = -d;
	} else
	    *isneg = 0;

	*hd = (int)d;
	min = (d - *hd)*60.;
	*m = (int)min;
	*s = (int)((min - *m)*60. + 0.5);

	if (*s == 60) {
	    if ((*m += 1) == 60) {
		*hd += 1;
		*m = 0;
	    }
	    *s = 0;
	}
	/* no  negative 0's */
	if (*hd == 0 && *m == 0 && *s == 0)
	    *isneg = 0;
}

/* insure 0 <= *v < r.
 */
range (v, r)
float *v, r;
{
	while (*v <  0) *v += r;
	while (*v >= r) *v -= r;
}
xXx
echo extracting sun.c
cat > sun.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given the modified JD, mjd, return the true geocentric ecliptic longitude
 *   of the sun for the mean equinox of the date, *lsn, in radians, and the
 *   sun-earth distance, *rsn, in AU. (the true ecliptic latitude is never more
 *   than 1.2 arc seconds and so may be taken to be a constant 0.)
 * if the APPARENT ecliptic longitude is required, correct the longitude for
 *   nutation to the true equinox of date and for aberration (light travel time,
 *   approximately  -9.27e7/186000/(3600*24*365)*2*pi = -9.93e-5 radians).
 */
sun (mjd, lsn, rsn)
float mjd;
float *lsn, *rsn;
{
	float t, t2;
	float ls, ms;    /* mean longitude and mean anomoay */
	float s, nu, ea; /* eccentricity, true anomaly, eccentric anomaly */
	double a, b, a1, b1, c1, d1, e1, h1, dl, dr;

	t = mjd/36525.;
	t2 = t*t;
	a = 100.0021359*t;
	b = 360.*(a-(int)a);
	ls = 279.69668+.0003025*t2+b;
	a = 99.99736042000039*t;
	b = 360*(a-(int)a);
	ms = 358.47583-(.00015+.0000033*t)*t2+b;
	s = .016751-.0000418*t-1.26e-07*t2;
	anomaly (degrad(ms), s, &nu, &ea);
	a = 62.55209472000015*t;
	b = 360*(a-(int)a);
	a1 = degrad(153.23+b);
	a = 125.1041894*t;
	b = 360*(a-(int)a);
	b1 = degrad(216.57+b);
	a = 91.56766028*t;
	b = 360*(a = (int)a);
	c1 = degrad(312.69+b);
	a = 1236.853095*t;
	b = 360*(a-(int)a);
	d1 = degrad(350.74-.00144*t2+b);
	e1 = degrad(231.19+20.2*t);
	a = 183.1353208*t;
	b = 360*(a-(int)a);
	h1 = degrad(353.4+b);
	dl = .00134*cos(a1)+.00154*cos(b1)+.002*cos(c1)+.00179*sin(d1)+
								.00178*sin(e1);
	dr = 5.43e-06*sin(a1)+1.575e-05*sin(b1)+1.627e-05*sin(c1)+
					    3.076e-05*cos(d1)+9.27e-06*sin(h1);
	*lsn = nu+degrad(ls-ms+dl);
	*rsn = 1.0000002*(1-s*cos(ea))+dr;
	range (lsn, 2*PI);
}
xXx
echo extracting sunrs.c
cat > sunrs.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"

/* given the modified julian date, mjd, geographical latitude, lat, and
 *   longitude, lng, each in radians with west lng < 0, and a horizon
 *   displacement, dis, find the utc times of sunrise, utcr, and sunset, utcs,
 *   and the azimuths of sunrise, azr, and sunset, azs. all angles in radians;
 *   azimuths are E of N.
 * times are for the upper limb, including effects of nutation and aberration.
 * displacement is additional amount added to suns altitude compared to its
 *   true location; see riset.c for more discussion. it can be used to
 *   account for irregular horizons, various refraction models, even times
 *   of twilight. eg, refraction to a level horizon is often taken to be about
 *   32/2(sun's semi-diameter) + 34(nominal refraction) = 50 arc minutes.
 *   better is:
 *      unrefract (pre, temp, 0.0, &a);	/* true alt of upper limb 
 *      a -= SUN_DIAM;			/* true alt of sun center
 * also used to find astro twilight by calling with dis of 18 degrees.
 * status:
 *   2: error
 *   1: never rises
 *   0: normal
 *  -1: circumpolar
 */
sunrs (mjd, lat, lng, dis, utcr, utcs, azr, azs, status)
float mjd, lat, lng, dis;
float *utcr, *utcs;
float *azr, *azs;
int *status;
{
	float lstr, lsts;	/* local sidereal times of rising/setting */
	float al = radhr(lng);	/* time correction for longitude */
	float tmp1, tmp2;	/* tmp */
	float mjd0, t;

	mjd0 = floor(mjd+0.5)-0.5; /* insure mjd0 is greenwich start of day */

	/* first approximation is to find rise/set times of a fixed object
	 * in the position of the sun at local midday. the sun is not
	 * fixed but moves about a degree per day so these are then refined.
	 */
	fixedsunriset(mjd0+(12.-al)/24.,lat,dis,&lstr,&lsts,&tmp1,&tmp2,status);
	if (*status != 0) return;

	/* find a better approximation to the rising circumstances based on a
	 * fixed object at the suns location at the first approximation of the
	 * rise time.
	 * N.B. more iterations are less than sp float precision.
	 */
	gst_utc (mjd0, lstr, &t);
	fixedsunriset(mjd0+(t-al)/24.,lat,dis,&lstr,&tmp1,azr,&tmp2,status);
	if (*status != 0) return;
	gst_utc (mjd0, lstr, utcr);
	*utcr -= al*.9972696;	/* allow for sideral shift */

	/* find a better approximation to the setting circumstances based on a
	 * fixed object at the suns location at the first approximation of the
	 * setting time.
	 */
	gst_utc (mjd0, lsts, &t);
	fixedsunriset (mjd0+(t-al)/24.,lat,dis,&tmp1,&lsts,&tmp2,azs,status);
	if (*status != 0) return;
	gst_utc (mjd0, lsts, utcs);
	*utcs -= al*.9972696;	/* allow for sideral shift */
}

/* find the local rise/set sidereal times and azimuths of an object fixed
 * at the ra/dec of the sun on the given mjd time as seen from lat.
 */
static
fixedsunriset (mjd, lat, dis, lstr, lsts, azr, azs, status)
float mjd, lat, dis;
float *lstr, *lsts;
float *azr, *azs;
int *status;
{
	float lsn, rsn;
	float deps, dpsi;
	float ra, dec;

	/* find ecliptic position of sun at mjd */
	sun (mjd, &lsn, &rsn);

	/* allow for 20.4" aberation and nutation */
	nutation (mjd, &deps, &dpsi);
        lsn += dpsi - degrad(20.4/3600.0);

	/* convert ecliptic to equatorial coords */
	ecl_eq (mjd, 0.0, lsn, &ra, &dec);

	/* find circumstances for given horizon displacement */
	riset (ra, dec, lat, dis, lstr, lsts, azr, azs, status);
}
xXx
echo extracting utc_gst.c
cat > utc_gst.c << 'xXx'
/* given a modified julian date, mjd, and a universally coordinated time, utc,
 * return greenwich mean siderial time, *gst.
 */
utc_gst (mjd, utc, gst)
float mjd;
float utc;
float *gst;
{
	float tnaught();
	static float lastmjd;
	static float t0;

	if (mjd != lastmjd) {
	    t0 = tnaught (mjd);
	    lastmjd = mjd;
	}
	*gst = 1.002737908*utc + t0;
	range (gst, 24.0);
}

/* given a modified julian date, mjd, and a greenwich mean siderial time, gst,
 * return universally coordinated time, *utc.
 */
gst_utc (mjd, gst, utc)
float mjd;
float gst;
float *utc;
{
	float tnaught();
	static float lastmjd;
	static float t0;

	if (mjd != lastmjd) {
	    t0 = tnaught (mjd);
	    range (&t0, 24.0);
	    lastmjd = mjd;
	}
	*utc = gst - t0;
	range (utc, 24.0);
	*utc *= .9972695677;
}

static float
tnaught (mjd)
float mjd;	/* julian days since 1900 jan 0.5 */
{
	float dmjd;
	int m, y;
	float d;
	float t, t0;

	mjd_cal (mjd, &m, &d, &y);
	cal_mjd (1, 0., y, &dmjd);
	t = dmjd/36525;
	t0 = 6.57098e-2 * (mjd - dmjd) - 
	     (24 - (6.6460656 + (5.1262e-2 + (t * 2.581e-5))*t) -
		   (2400 * (t - (((float)y - 1900)/100))));
	return (t0);
}
xXx