v14i079: ephem, 4 of 6
downey at cs.umn.edu
downey at cs.umn.edu
Fri Aug 31 10:54:43 AEST 1990
Posting-number: Volume 14, Issue 79
Submitted-by: downey at cs.umn.edu@dimed1.UUCP
Archive-name: ephem-4.21/part04
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 6)."
# Contents: compiler.c plans.c watch.c
# Wrapped by allbery at uunet on Thu Aug 30 20:46:35 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'compiler.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'compiler.c'\"
else
echo shar: Extracting \"'compiler.c'\" \(15331 characters\)
sed "s/^X//" >'compiler.c' <<'END_OF_FILE'
X/* module to compile and execute a c-style arithmetic expression.
X * public entry points are compile_expr() and execute_expr().
X *
X * one reason this is so nice and tight is that all opcodes are the same size
X * (an int) and the tokens the parser returns are directly usable as opcodes,
X * for the most part. constants and variables are compiled as an opcode
X * with an offset into the auxiliary opcode tape, opx.
X */
X
X#include <math.h>
X#ifdef VMS
X#include <stdlib.h>
X#endif
X#include "screen.h"
X
X/* parser tokens and opcodes, as necessary */
X#define HALT 0 /* good value for HALT since program is inited to 0 */
X/* binary operators (precedences in table, below) */
X#define ADD 1
X#define SUB 2
X#define MULT 3
X#define DIV 4
X#define AND 5
X#define OR 6
X#define GT 7
X#define GE 8
X#define EQ 9
X#define NE 10
X#define LT 11
X#define LE 12
X/* unary op, precedence in NEG_PREC #define, below */
X#define NEG 13
X/* symantically operands, ie, constants, variables and all functions */
X#define CONST 14
X#define VAR 15
X#define ABS 16 /* add functions if desired just like this is done */
X/* purely tokens - never get compiled as such */
X#define LPAREN 255
X#define RPAREN 254
X#define ERR (-1)
X
X/* precedence of each of the binary operators.
X * in case of a tie, compiler associates left-to-right.
X * N.B. each entry's index must correspond to its #define!
X */
Xstatic int precedence[] = {0,5,5,6,6,2,1,4,4,3,3,4,4};
X#define NEG_PREC 7 /* negation is highest */
X
X/* execute-time operand stack */
X#define MAX_STACK 16
Xstatic double stack[MAX_STACK], *sp;
X
X/* space for compiled opcodes - the "program".
X * opcodes go in lower 8 bits.
X * when an opcode has an operand (as CONST and VAR) it is really in opx[] and
X * the index is in the remaining upper bits.
X */
X#define MAX_PROG 32
Xstatic int program[MAX_PROG], *pc;
X#define OP_SHIFT 8
X#define OP_MASK 0xff
X
X/* auxiliary operand info.
X * the operands (all but lower 8 bits) of CONST and VAR are really indeces
X * into this array. thus, no point in making this any longer than you have
X * bits more than 8 in your machine's int to index into it, ie, make
X * MAX_OPX <= 1 << ((sizeof(int)-1)*8)
X * also, the fld's must refer to ones being flog'd, so not point in more
X * of these then that might be used for plotting and srching combined.
X */
X#define MAX_OPX 16
Xtypedef union {
X double opu_f; /* value when opcode is CONST */
X int opu_fld; /* rcfpack() of field when opcode is VAR */
X} OpX;
Xstatic OpX opx[MAX_OPX];
Xstatic int opxidx;
X
X/* these are global just for easy/rapid access */
Xstatic int parens_nest; /* to check that parens end up nested */
Xstatic char *err_msg; /* caller provides storage; we point at it with this */
Xstatic char *cexpr, *lcexpr; /* pointers that move along caller's expression */
Xstatic int good_prog; /* != 0 when program appears to be good */
X
X/* compile the given c-style expression.
X * return 0 and set good_prog if ok,
X * else return -1 and a reason message in errbuf.
X */
Xcompile_expr (ex, errbuf)
Xchar *ex;
Xchar *errbuf;
X{
X int instr;
X
X /* init the globals.
X * also delete any flogs used in the previous program.
X */
X cexpr = ex;
X err_msg = errbuf;
X pc = program;
X opxidx = 0;
X parens_nest = 0;
X do {
X instr = *pc++;
X if ((instr & OP_MASK) == VAR)
X flog_delete (opx[instr >> OP_SHIFT].opu_fld);
X } while (instr != HALT);
X
X pc = program;
X if (compile(0) == ERR) {
X (void) sprintf (err_msg + strlen(err_msg), " at \"%.10s\"", lcexpr);
X good_prog = 0;
X return (-1);
X }
X *pc++ = HALT;
X good_prog = 1;
X return (0);
X}
X
X/* execute the expression previously compiled with compile_expr().
X * return 0 with *vp set to the answer if ok, else return -1 with a reason
X * why not message in errbuf.
X */
Xexecute_expr (vp, errbuf)
Xdouble *vp;
Xchar *errbuf;
X{
X int s;
X
X err_msg = errbuf;
X sp = stack + MAX_STACK; /* grows towards lower addresses */
X pc = program;
X s = execute(vp);
X if (s < 0)
X good_prog = 0;
X return (s);
X}
X
X/* this is a way for the outside world to ask whether there is currently a
X * reasonable program compiled and able to execute.
X */
Xprog_isgood()
X{
X return (good_prog);
X}
X
X/* get and return the opcode corresponding to the next token.
X * leave with lcexpr pointing at the new token, cexpr just after it.
X * also watch for mismatches parens and proper operator/operand alternation.
X */
Xstatic
Xnext_token ()
X{
X static char toomt[] = "More than %d terms";
X static char badop[] = "Illegal operator";
X int tok = ERR; /* just something illegal */
X char c;
X
X while ((c = *cexpr) == ' ')
X cexpr++;
X lcexpr = cexpr++;
X
X /* mainly check for a binary operator */
X switch (c) {
X case '\0': --cexpr; tok = HALT; break; /* keep returning HALT */
X case '+': tok = ADD; break; /* compiler knows when it's really unary */
X case '-': tok = SUB; break; /* compiler knows when it's really negate */
X case '*': tok = MULT; break;
X case '/': tok = DIV; break;
X case '(': parens_nest++; tok = LPAREN; break;
X case ')':
X if (--parens_nest < 0) {
X (void) sprintf (err_msg, "Too many right parens");
X return (ERR);
X } else
X tok = RPAREN;
X break;
X case '|':
X if (*cexpr == '|') { cexpr++; tok = OR; }
X else { (void) sprintf (err_msg, badop); return (ERR); }
X break;
X case '&':
X if (*cexpr == '&') { cexpr++; tok = AND; }
X else { (void) sprintf (err_msg, badop); return (ERR); }
X break;
X case '=':
X if (*cexpr == '=') { cexpr++; tok = EQ; }
X else { (void) sprintf (err_msg, badop); return (ERR); }
X break;
X case '!':
X if (*cexpr == '=') { cexpr++; tok = NE; }
X else { (void) sprintf (err_msg, badop); return (ERR); }
X break;
X case '<':
X if (*cexpr == '=') { cexpr++; tok = LE; }
X else tok = LT;
X break;
X case '>':
X if (*cexpr == '=') { cexpr++; tok = GE; }
X else tok = GT;
X break;
X }
X
X if (tok != ERR)
X return (tok);
X
X /* not op so check for a constant, variable or function */
X if (isdigit(c) || c == '.') {
X if (opxidx > MAX_OPX) {
X (void) sprintf (err_msg, toomt, MAX_OPX);
X return (ERR);
X }
X opx[opxidx].opu_f = atof (lcexpr);
X tok = CONST | (opxidx++ << OP_SHIFT);
X skip_double();
X } else if (isalpha(c)) {
X /* check list of functions */
X if (strncmp (lcexpr, "abs", 3) == 0) {
X cexpr += 2;
X tok = ABS;
X } else {
X /* not a function, so assume it's a variable */
X int fld;
X if (opxidx > MAX_OPX) {
X (void) sprintf (err_msg, toomt, MAX_OPX);
X return (ERR);
X }
X fld = parse_fieldname ();
X if (fld < 0) {
X (void) sprintf (err_msg, "Unknown field");
X return (ERR);
X } else {
X if (flog_add (fld) < 0) { /* register with field logger */
X (void) sprintf (err_msg, "Sorry; too many fields");
X return (ERR);
X }
X opx[opxidx].opu_fld = fld;
X tok = VAR | (opxidx++ << OP_SHIFT);
X }
X }
X }
X
X return (tok);
X}
X
X/* move cexpr on past a double.
X * allow sci notation.
X * no need to worry about a leading '-' or '+' but allow them after an 'e'.
X * TODO: this handles all the desired cases, but also admits a bit too much
X * such as things like 1eee2...3. geeze; to skip a double right you almost
X * have to go ahead and crack it!
X */
Xstatic
Xskip_double()
X{
X int sawe = 0; /* so we can allow '-' or '+' right after an 'e' */
X
X while (1) {
X char c = *cexpr;
X if (isdigit(c) || c=='.' || (sawe && (c=='-' || c=='+'))) {
X sawe = 0;
X cexpr++;
X } else if (c == 'e') {
X sawe = 1;
X cexpr++;
X } else
X break;
X }
X}
X
X/* call this whenever you want to dig out the next (sub)expression.
X * keep compiling instructions as long as the operators are higher precedence
X * than prec, then return that "look-ahead" token that wasn't (higher prec).
X * if error, fill in a message in err_msg[] and return ERR.
X */
Xstatic
Xcompile (prec)
Xint prec;
X{
X int expect_binop = 0; /* set after we have seen any operand.
X * used by SUB so it can tell if it really
X * should be taken to be a NEG instead.
X */
X int tok = next_token ();
X
X while (1) {
X int p;
X if (tok == ERR)
X return (ERR);
X if (pc - program >= MAX_PROG) {
X (void) sprintf (err_msg, "Program is too long");
X return (ERR);
X }
X
X /* check for special things like functions, constants and parens */
X switch (tok & OP_MASK) {
X case HALT: return (tok);
X case ADD:
X if (expect_binop)
X break; /* procede with binary addition */
X /* just skip a unary positive(?) */
X tok = next_token();
X continue;
X case SUB:
X if (expect_binop)
X break; /* procede with binary subtract */
X tok = compile (NEG_PREC);
X *pc++ = NEG;
X expect_binop = 1;
X continue;
X case ABS: /* other funcs would be handled the same too ... */
X /* eat up the function parenthesized argument */
X if (next_token() != LPAREN || compile (0) != RPAREN) {
X (void) sprintf (err_msg, "Function arglist error");
X return (ERR);
X }
X /* then handled same as ... */
X case CONST: /* handled same as... */
X case VAR:
X *pc++ = tok;
X tok = next_token();
X expect_binop = 1;
X continue;
X case LPAREN:
X if (compile (0) != RPAREN) {
X (void) sprintf (err_msg, "Unmatched left paren");
X return (ERR);
X }
X tok = next_token();
X expect_binop = 1;
X continue;
X case RPAREN:
X return (RPAREN);
X }
X
X /* everything else is a binary operator */
X p = precedence[tok];
X if (p > prec) {
X int newtok = compile (p);
X if (newtok == ERR)
X return (ERR);
X *pc++ = tok;
X expect_binop = 1;
X tok = newtok;
X } else
X return (tok);
X }
X}
X
X/* "run" the program[] compiled with compile().
X * if ok, return 0 and the final result,
X * else return -1 with a reason why not message in err_msg.
X */
Xstatic
Xexecute(result)
Xdouble *result;
X{
X int instr;
X
X do {
X instr = *pc++;
X switch (instr & OP_MASK) {
X /* put these in numberic order so hopefully even the dumbest
X * compiler will choose to use a jump table, not a cascade of ifs.
X */
X case HALT: break; /* outer loop will stop us */
X case ADD: sp[1] = sp[1] + sp[0]; sp++; break;
X case SUB: sp[1] = sp[1] - sp[0]; sp++; break;
X case MULT: sp[1] = sp[1] * sp[0]; sp++; break;
X case DIV: sp[1] = sp[1] / sp[0]; sp++; break;
X case AND: sp[1] = sp[1] && sp[0] ? 1 : 0; sp++; break;
X case OR: sp[1] = sp[1] || sp[0] ? 1 : 0; sp++; break;
X case GT: sp[1] = sp[1] > sp[0] ? 1 : 0; sp++; break;
X case GE: sp[1] = sp[1] >= sp[0] ? 1 : 0; sp++; break;
X case EQ: sp[1] = sp[1] == sp[0] ? 1 : 0; sp++; break;
X case NE: sp[1] = sp[1] != sp[0] ? 1 : 0; sp++; break;
X case LT: sp[1] = sp[1] < sp[0] ? 1 : 0; sp++; break;
X case LE: sp[1] = sp[1] <= sp[0] ? 1 : 0; sp++; break;
X case NEG: *sp = -*sp; break;
X case CONST: *--sp = opx[instr >> OP_SHIFT].opu_f; break;
X case VAR:
X if (flog_get(opx[instr>>OP_SHIFT].opu_fld, --sp, (char *)0)<0) {
X (void) sprintf (err_msg, "Bug! VAR field not logged");
X return (-1);
X }
X break;
X case ABS: *sp = fabs (*sp); break;
X default:
X (void) sprintf (err_msg, "Bug! bad opcode: 0x%x", instr);
X return (-1);
X }
X if (sp < stack) {
X (void) sprintf (err_msg, "Runtime stack overflow");
X return (-1);
X } else if (sp - stack > MAX_STACK) {
X (void) sprintf (err_msg, "Bug! runtime stack underflow");
X return (-1);
X }
X } while (instr != HALT);
X
X /* result should now be on top of stack */
X if (sp != &stack[MAX_STACK - 1]) {
X (void) sprintf (err_msg, "Bug! stack has %d items",
X MAX_STACK - (sp-stack));
X return (-1);
X }
X *result = *sp;
X return (0);
X}
X
Xstatic
Xisdigit(c)
Xchar c;
X{
X return (c >= '0' && c <= '9');
X}
X
Xstatic
Xisalpha (c)
Xchar c;
X{
X return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
X}
X
X/* starting with lcexpr pointing at a string expected to be a field name,
X * return an rcfpack(r,c,0) of the field else -1 if bad.
X * when return, leave lcexpr alone but move cexpr to just after the name.
X */
Xstatic
Xparse_fieldname ()
X{
X int r = -1, c = -1; /* anything illegal */
X char *fn = lcexpr; /* likely faster than using the global */
X char f0, f1;
X char *dp;
X
X /* search for first thing not an alpha char.
X * leave it in f0 and leave dp pointing to it.
X */
X dp = fn;
X while (isalpha(f0 = *dp))
X dp++;
X
X /* crack the new field name.
X * when done trying, leave dp pointing at first char just after it.
X * set r and c if we recognized it.
X */
X if (f0 == '.') {
X /* planet.column pair.
X * first crack the planet portion (pointed to by fn): set r.
X * then the second portion (pointed to by dp+1): set c.
X */
X f0 = fn[0];
X f1 = fn[1];
X switch (f0) {
X case 'j':
X r = R_JUPITER;
X break;
X case 'm':
X if (f1 == 'a') r = R_MARS;
X else if (f1 == 'e') r = R_MERCURY;
X else if (f1 == 'o') r = R_MOON;
X break;
X case 'n':
X r = R_NEPTUNE;
X break;
X case 'p':
X r = R_PLUTO;
X break;
X case 's':
X if (f1 == 'a') r = R_SATURN;
X else if (f1 == 'u') r = R_SUN;
X break;
X case 'u':
X r = R_URANUS;
X break;
X case 'x':
X r = R_OBJX;
X break;
X case 'y':
X r = R_OBJY;
X break;
X case 'v':
X r = R_VENUS;
X break;
X }
X
X /* now crack the column (stuff after the dp) */
X dp++; /* point at good stuff just after the decimal pt */
X f0 = dp[0];
X f1 = dp[1];
X switch (f0) {
X case 'a':
X if (f1 == 'l') c = C_ALT;
X else if (f1 == 'z') c = C_AZ;
X break;
X case 'd':
X c = C_DEC;
X break;
X case 'e':
X if (f1 == 'd') c = C_EDIST;
X else if (f1 == 'l') c = C_ELONG;
X break;
X case 'h':
X if (f1 == 'l') {
X if (dp[2] == 'a') c = C_HLAT;
X else if (dp[2] == 'o') c = C_HLONG;
X } else if (f1 == 'r' || f1 == 'u') c = C_TUP;
X break;
X case 'j':
X c = C_JUPITER;
X break;
X case 'm':
X if (f1 == 'a') c = C_MARS;
X else if (f1 == 'e') c = C_MERCURY;
X else if (f1 == 'o') c = C_MOON;
X break;
X case 'n':
X c = C_NEPTUNE;
X break;
X case 'p':
X if (f1 == 'h') c = C_PHASE;
X else if (f1 == 'l') c = C_PLUTO;
X break;
X case 'r':
X if (f1 == 'a') {
X if (dp[2] == 'z') c = C_RISEAZ;
X else c = C_RA;
X } else if (f1 == 't') c = C_RISETM;
X break;
X case 's':
X if (f1 == 'a') {
X if (dp[2] == 'z') c = C_SETAZ;
X else c = C_SATURN;
X } else if (f1 == 'd') c = C_SDIST;
X else if (f1 == 'i') c = C_SIZE;
X else if (f1 == 't') c = C_SETTM;
X else if (f1 == 'u') c = C_SUN;
X break;
X case 't':
X if (f1 == 'a') c = C_TRANSALT;
X else if (f1 == 't') c = C_TRANSTM;
X break;
X case 'u':
X c = C_URANUS;
X break;
X case 'x':
X c = C_OBJX;
X break;
X case 'y':
X c = C_OBJY;
X break;
X case 'v':
X if (f1 == 'e') c = C_VENUS;
X else if (f1 == 'm') c = C_MAG;
X break;
X }
X
X /* now skip dp on past the column stuff */
X while (isalpha(*dp))
X dp++;
X } else {
X /* no decimal point; some field in the top of the screen */
X f0 = fn[0];
X f1 = fn[1];
X switch (f0) {
X case 'd':
X if (f1 == 'a') r = R_DAWN, c = C_DAWNV;
X else if (f1 == 'u') r = R_DUSK, c = C_DUSKV;
X break;
X case 'n':
X r = R_LON, c = C_LONV;
X break;
X }
X }
X
X cexpr = dp;
X if (r <= 0 || c <= 0) return (-1);
X return (rcfpack (r, c, 0));
X}
END_OF_FILE
if test 15331 -ne `wc -c <'compiler.c'`; then
echo shar: \"'compiler.c'\" unpacked with wrong size!
fi
# end of 'compiler.c'
fi
if test -f 'plans.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'plans.c'\"
else
echo shar: Extracting \"'plans.c'\" \(17647 characters\)
sed "s/^X//" >'plans.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <math.h>
X#include "astro.h"
X
X#define TWOPI (2*PI)
X#define mod2PI(x) ((x) - (long)((x)/TWOPI)*TWOPI)
X
X/* given a modified Julian date, mjd, and a planet, p, find:
X * lpd0: heliocentric longitude,
X * psi0: heliocentric latitude,
X * rp0: distance from the sun to the planet,
X * rho0: distance from the Earth to the planet,
X * none corrected for light time, ie, they are the true values for the
X * given instant.
X * lam: geocentric ecliptic longitude,
X * bet: geocentric ecliptic latitude,
X * each corrected for light time, ie, they are the apparent values as
X * seen from the center of the Earth for the given instant.
X * dia: angular diameter in arcsec at 1 AU,
X * mag: visual magnitude when 1 AU from sun and earth at 0 phase angle.
X *
X * all angles are in radians, all distances in AU.
X * the mean orbital elements are found by calling pelement(), then mutual
X * perturbation corrections are applied as necessary.
X *
X * corrections for nutation and abberation must be made by the caller. The RA
X * and DEC calculated from the fully-corrected ecliptic coordinates are then
X * the apparent geocentric coordinates. Further corrections can be made, if
X * required, for atmospheric refraction and geocentric parallax although the
X * intrinsic error herein of about 10 arcseconds is usually the dominant
X * error at this stage.
X * TODO: combine the several intermediate expressions when get a good compiler.
X */
Xplans (mjd, p, lpd0, psi0, rp0, rho0, lam, bet, dia, mag)
Xdouble mjd;
Xint p;
Xdouble *lpd0, *psi0, *rp0, *rho0, *lam, *bet, *dia, *mag;
X{
X static double plan[8][9];
X static double lastmjd = -10000;
X double dl; /* perturbation correction for longitude */
X double dr; /* " orbital radius */
X double dml; /* " mean longitude */
X double ds; /* " eccentricity */
X double dm; /* " mean anomaly */
X double da; /* " semi-major axis */
X double dhl; /* " heliocentric longitude */
X double lsn, rsn;/* true geocentric longitude of sun and sun-earth rad */
X double mas; /* mean anomaly of the sun */
X double re; /* radius of earth's orbit */
X double lg; /* longitude of earth */
X double map[8]; /* array of mean anomalies for each planet */
X double lpd, psi, rp, rho;
X double ll, sll, cll;
X double t;
X double dt;
X int pass;
X int j;
X double s, ma;
X double nu, ea;
X double lp, om;
X double lo, slo, clo;
X double inc, y;
X double spsi, cpsi;
X double rpd;
X
X /* only need to fill in plan[] once for a given mjd */
X if (mjd != lastmjd) {
X pelement (mjd, plan);
X lastmjd = mjd;
X }
X
X dt = 0;
X t = mjd/36525.;
X sunpos (mjd, &lsn, &rsn);
X masun (mjd, &mas);
X re = rsn;
X lg = lsn+PI;
X
X /* first find the true position of the planet at mjd.
X * then repeat a second time for a slightly different time based
X * on the position found in the first pass to account for light-travel
X * time.
X */
X for (pass = 0; pass < 2; pass++) {
X
X for (j = 0; j < 8; j++)
X map[j] = degrad(plan[j][0]-plan[j][2]-dt*plan[j][1]);
X
X /* set initial corrections to 0.
X * then modify as necessary for the planet of interest.
X */
X dl = 0;
X dr = 0;
X dml = 0;
X ds = 0;
X dm = 0;
X da = 0;
X dhl = 0;
X
X switch (p) {
X
X case MERCURY:
X p_mercury (map, &dl, &dr);
X break;
X
X case VENUS:
X p_venus (t, mas, map, &dl, &dr, &dml, &dm);
X break;
X
X case MARS:
X p_mars (mas, map, &dl, &dr, &dml, &dm);
X break;
X
X case JUPITER:
X p_jupiter (t, plan[p][3], &dml, &ds, &dm, &da);
X break;
X
X case SATURN:
X p_saturn (t, plan[p][3], &dml, &ds, &dm, &da, &dhl);
X break;
X
X case URANUS:
X p_uranus (t, plan[p][3], &dl, &dr, &dml, &ds, &dm, &da, &dhl);
X break;
X
X case NEPTUNE:
X p_neptune (t, plan[p][3], &dl, &dr, &dml, &ds, &dm, &da, &dhl);
X break;
X
X case PLUTO:
X /* no perturbation theory for pluto */
X break;
X }
X
X s = plan[p][3]+ds;
X ma = map[p]+dm;
X anomaly (ma, s, &nu, &ea);
X rp = (plan[p][6]+da)*(1-s*s)/(1+s*cos(nu));
X lp = raddeg(nu)+plan[p][2]+raddeg(dml-dm);
X lp = degrad(lp);
X om = degrad(plan[p][5]);
X lo = lp-om;
X slo = sin(lo);
X clo = cos(lo);
X inc = degrad(plan[p][4]);
X rp = rp+dr;
X spsi = slo*sin(inc);
X y = slo*cos(inc);
X psi = asin(spsi)+dhl;
X spsi = sin(psi);
X lpd = atan(y/clo)+om+degrad(dl);
X if (clo<0) lpd += PI;
X range (&lpd, TWOPI);
X cpsi = cos(psi);
X rpd = rp*cpsi;
X ll = lpd-lg;
X rho = sqrt(re*re+rp*rp-2*re*rp*cpsi*cos(ll));
X
X /* when we view a planet we see it in the position it occupied
X * dt days ago, where rho is the distance between it and earth,
X * in AU. use this as the new time for the next pass.
X */
X dt = rho*5.775518e-3;
X
X if (pass == 0) {
X /* save heliocentric coordinates after first pass since, being
X * true, they are NOT to be corrected for light-travel time.
X */
X *lpd0 = lpd;
X range (lpd0, TWOPI);
X *psi0 = psi;
X *rp0 = rp;
X *rho0 = rho;
X }
X }
X
X sll = sin(ll);
X cll = cos(ll);
X if (p < MARS)
X *lam = atan(-1*rpd*sll/(re-rpd*cll))+lg+PI;
X else
X *lam = atan(re*sll/(rpd-re*cll))+lpd;
X range (lam, TWOPI);
X *bet = atan(rpd*spsi*sin(*lam-lpd)/(cpsi*re*sll));
X *dia = plan[p][7];
X *mag = plan[p][8];
X}
X
X/* set auxilliary variables used for jupiter, saturn, uranus, and neptune */
Xstatic
Xaux_jsun (t, x1, x2, x3, x4, x5, x6)
Xdouble t;
Xdouble *x1, *x2, *x3, *x4, *x5, *x6;
X{
X *x1 = t/5+0.1;
X *x2 = mod2PI(4.14473+5.29691e1*t);
X *x3 = mod2PI(4.641118+2.132991e1*t);
X *x4 = mod2PI(4.250177+7.478172*t);
X *x5 = 5 * *x3 - 2 * *x2;
X *x6 = 2 * *x2 - 6 * *x3 + 3 * *x4;
X}
X
X/* find the mean anomaly of the sun at mjd.
X * this is the same as that used in sun() but when it was converted to C it
X * was not known it would be required outside that routine.
X * TODO: add an argument to sun() to return mas and eliminate this routine.
X */
Xstatic
Xmasun (mjd, mas)
Xdouble mjd;
Xdouble *mas;
X{
X double t, t2;
X double a, b;
X
X t = mjd/36525;
X t2 = t*t;
X a = 9.999736042e1*t;
X b = 360.*(a-(long)a);
X *mas = degrad (3.5847583e2-(1.5e-4+3.3e-6*t)*t2+b);
X}
X
X/* perturbations for mercury */
Xstatic
Xp_mercury (map, dl, dr)
Xdouble map[];
Xdouble *dl, *dr;
X{
X *dl = 2.04e-3*cos(5*map[2-1]-2*map[1-1]+2.1328e-1)+
X 1.03e-3*cos(2*map[2-1]-map[1-1]-2.8046)+
X 9.1e-4*cos(2*map[3]-map[1-1]-6.4582e-1)+
X 7.8e-4*cos(5*map[2-1]-3*map[1-1]+1.7692e-1);
X
X *dr = 7.525e-6*cos(2*map[3]-map[1-1]+9.25251e-1)+
X 6.802e-6*cos(5*map[2-1]-3*map[1-1]-4.53642)+
X 5.457e-6*cos(2*map[2-1]-2*map[1-1]-1.24246)+
X 3.569e-6*cos(5*map[2-1]-map[1-1]-1.35699);
X}
X
X/* ....venus */
Xstatic
Xp_venus (t, mas, map, dl, dr, dml, dm)
Xdouble t, mas, map[];
Xdouble *dl, *dr, *dml, *dm;
X{
X *dml = degrad (7.7e-4*sin(4.1406+t*2.6227));
X *dm = *dml;
X
X *dl = 3.13e-3*cos(2*mas-2*map[2-1]-2.587)+
X 1.98e-3*cos(3*mas-3*map[2-1]+4.4768e-2)+
X 1.36e-3*cos(mas-map[2-1]-2.0788)+
X 9.6e-4*cos(3*mas-2*map[2-1]-2.3721)+
X 8.2e-4*cos(map[3]-map[2-1]-3.6318);
X
X *dr = 2.2501e-5*cos(2*mas-2*map[2-1]-1.01592)+
X 1.9045e-5*cos(3*mas-3*map[2-1]+1.61577)+
X 6.887e-6*cos(map[3]-map[2-1]-2.06106)+
X 5.172e-6*cos(mas-map[2-1]-5.08065e-1)+
X 3.62e-6*cos(5*mas-4*map[2-1]-1.81877)+
X 3.283e-6*cos(4*mas-4*map[2-1]+1.10851)+
X 3.074e-6*cos(2*map[3]-2*map[2-1]-9.62846e-1);
X}
X
X/* ....mars */
Xstatic
Xp_mars (mas, map, dl, dr, dml, dm)
Xdouble mas, map[];
Xdouble *dl, *dr, *dml, *dm;
X{
X double a;
X
X a = 3*map[3]-8*map[2]+4*mas;
X *dml = degrad (-1*(1.133e-2*sin(a)+9.33e-3*cos(a)));
X *dm = *dml;
X
X *dl = 7.05e-3*cos(map[3]-map[2]-8.5448e-1)+
X 6.07e-3*cos(2*map[3]-map[2]-3.2873)+
X 4.45e-3*cos(2*map[3]-2*map[2]-3.3492)+
X 3.88e-3*cos(mas-2*map[2]+3.5771e-1)+
X 2.38e-3*cos(mas-map[2]+6.1256e-1)+
X 2.04e-3*cos(2*mas-3*map[2]+2.7688)+
X 1.77e-3*cos(3*map[2]-map[2-1]-1.0053)+
X 1.36e-3*cos(2*mas-4*map[2]+2.6894)+
X 1.04e-3*cos(map[3]+3.0749e-1);
X
X *dr = 5.3227e-5*cos(map[3]-map[2]+7.17864e-1)+
X 5.0989e-5*cos(2*map[3]-2*map[2]-1.77997)+
X 3.8278e-5*cos(2*map[3]-map[2]-1.71617)+
X 1.5996e-5*cos(mas-map[2]-9.69618e-1)+
X 1.4764e-5*cos(2*mas-3*map[2]+1.19768)+
X 8.966e-6*cos(map[3]-2*map[2]+7.61225e-1);
X *dr += 7.914e-6*cos(3*map[3]-2*map[2]-2.43887)+
X 7.004e-6*cos(2*map[3]-3*map[2]-1.79573)+
X 6.62e-6*cos(mas-2*map[2]+1.97575)+
X 4.93e-6*cos(3*map[3]-3*map[2]-1.33069)+
X 4.693e-6*cos(3*mas-5*map[2]+3.32665)+
X 4.571e-6*cos(2*mas-4*map[2]+4.27086)+
X 4.409e-6*cos(3*map[3]-map[2]-2.02158);
X}
X
X/* ....jupiter */
Xstatic
Xp_jupiter (t, s, dml, ds, dm, da)
Xdouble t, s;
Xdouble *dml, *ds, *dm, *da;
X{
X double dp;
X double x1, x2, x3, x4, x5, x6, x7;
X double sx3, cx3, s2x3, c2x3;
X double sx5, cx5, s2x5;
X double sx6;
X double sx7, cx7, s2x7, c2x7, s3x7, c3x7, s4x7, c4x7, c5x7;
X
X aux_jsun (t, &x1, &x2, &x3, &x4, &x5, &x6);
X x7 = x3-x2;
X sx3 = sin(x3);
X cx3 = cos(x3);
X s2x3 = sin(2*x3);
X c2x3 = cos(2*x3);
X sx5 = sin(x5);
X cx5 = cos(x5);
X s2x5 = sin(2*x5);
X sx6 = sin(x6);
X sx7 = sin(x7);
X cx7 = cos(x7);
X s2x7 = sin(2*x7);
X c2x7 = cos(2*x7);
X s3x7 = sin(3*x7);
X c3x7 = cos(3*x7);
X s4x7 = sin(4*x7);
X c4x7 = cos(4*x7);
X c5x7 = cos(5*x7);
X
X *dml = (3.31364e-1-(1.0281e-2+4.692e-3*x1)*x1)*sx5+
X (3.228e-3-(6.4436e-2-2.075e-3*x1)*x1)*cx5-
X (3.083e-3+(2.75e-4-4.89e-4*x1)*x1)*s2x5+
X 2.472e-3*sx6+1.3619e-2*sx7+1.8472e-2*s2x7+6.717e-3*s3x7+
X 2.775e-3*s4x7+6.417e-3*s2x7*sx3+
X (7.275e-3-1.253e-3*x1)*sx7*sx3+
X 2.439e-3*s3x7*sx3-(3.5681e-2+1.208e-3*x1)*sx7*cx3;
X *dml += -3.767e-3*c2x7*sx3-(3.3839e-2+1.125e-3*x1)*cx7*sx3-
X 4.261e-3*s2x7*cx3+
X (1.161e-3*x1-6.333e-3)*cx7*cx3+
X 2.178e-3*cx3-6.675e-3*c2x7*cx3-2.664e-3*c3x7*cx3-
X 2.572e-3*sx7*s2x3-3.567e-3*s2x7*s2x3+2.094e-3*cx7*c2x3+
X 3.342e-3*c2x7*c2x3;
X *dml = degrad(*dml);
X
X *ds = (3606+(130-43*x1)*x1)*sx5+(1289-580*x1)*cx5-6764*sx7*sx3-
X 1110*s2x7*sx3-224*s3x7*sx3-204*sx3+(1284+116*x1)*cx7*sx3+
X 188*c2x7*sx3+(1460+130*x1)*sx7*cx3+224*s2x7*cx3-817*cx3+
X 6074*cx3*cx7+992*c2x7*cx3+
X 508*c3x7*cx3+230*c4x7*cx3+108*c5x7*cx3;
X *ds += -(956+73*x1)*sx7*s2x3+448*s2x7*s2x3+137*s3x7*s2x3+
X (108*x1-997)*cx7*s2x3+480*c2x7*s2x3+148*c3x7*s2x3+
X (99*x1-956)*sx7*c2x3+490*s2x7*c2x3+
X 158*s3x7*c2x3+179*c2x3+(1024+75*x1)*cx7*c2x3-
X 437*c2x7*c2x3-132*c3x7*c2x3;
X *ds *= 1e-7;
X
X dp = (7.192e-3-3.147e-3*x1)*sx5-4.344e-3*sx3+
X (x1*(1.97e-4*x1-6.75e-4)-2.0428e-2)*cx5+
X 3.4036e-2*cx7*sx3+(7.269e-3+6.72e-4*x1)*sx7*sx3+
X 5.614e-3*c2x7*sx3+2.964e-3*c3x7*sx3+3.7761e-2*sx7*cx3+
X 6.158e-3*s2x7*cx3-
X 6.603e-3*cx7*cx3-5.356e-3*sx7*s2x3+2.722e-3*s2x7*s2x3+
X 4.483e-3*cx7*s2x3-2.642e-3*c2x7*s2x3+4.403e-3*sx7*c2x3-
X 2.536e-3*s2x7*c2x3+5.547e-3*cx7*c2x3-2.689e-3*c2x7*c2x3;
X
X *dm = *dml-(degrad(dp)/s);
X
X *da = 205*cx7-263*cx5+693*c2x7+312*c3x7+147*c4x7+299*sx7*sx3+
X 181*c2x7*sx3+204*s2x7*cx3+111*s3x7*cx3-337*cx7*cx3-
X 111*c2x7*cx3;
X *da *= 1e-6;
X}
X
X/* ....saturn */
Xstatic
Xp_saturn (t, s, dml, ds, dm, da, dhl)
Xdouble t, s;
Xdouble *dml, *ds, *dm, *da, *dhl;
X{
X double dp;
X double x1, x2, x3, x4, x5, x6, x7, x8;
X double sx3, cx3, s2x3, c2x3, s3x3, c3x3, s4x3, c4x3;
X double sx5, cx5, s2x5, c2x5;
X double sx6;
X double sx7, cx7, s2x7, c2x7, s3x7, c3x7, s4x7, c4x7, c5x7, s5x7;
X double s2x8, c2x8, s3x8, c3x8;
X
X aux_jsun (t, &x1, &x2, &x3, &x4, &x5, &x6);
X x7 = x3-x2;
X sx3 = sin(x3);
X cx3 = cos(x3);
X s2x3 = sin(2*x3);
X c2x3 = cos(2*x3);
X sx5 = sin(x5);
X cx5 = cos(x5);
X s2x5 = sin(2*x5);
X sx6 = sin(x6);
X sx7 = sin(x7);
X cx7 = cos(x7);
X s2x7 = sin(2*x7);
X c2x7 = cos(2*x7);
X s3x7 = sin(3*x7);
X c3x7 = cos(3*x7);
X s4x7 = sin(4*x7);
X c4x7 = cos(4*x7);
X c5x7 = cos(5*x7);
X
X s3x3 = sin(3*x3);
X c3x3 = cos(3*x3);
X s4x3 = sin(4*x3);
X c4x3 = cos(4*x3);
X c2x5 = cos(2*x5);
X s5x7 = sin(5*x7);
X x8 = x4-x3;
X s2x8 = sin(2*x8);
X c2x8 = cos(2*x8);
X s3x8 = sin(3*x8);
X c3x8 = cos(3*x8);
X
X *dml = 7.581e-3*s2x5-7.986e-3*sx6-1.48811e-1*sx7-4.0786e-2*s2x7-
X (8.14181e-1-(1.815e-2-1.6714e-2*x1)*x1)*sx5-
X (1.0497e-2-(1.60906e-1-4.1e-3*x1)*x1)*cx5-1.5208e-2*s3x7-
X 6.339e-3*s4x7-6.244e-3*sx3-1.65e-2*s2x7*sx3+
X (8.931e-3+2.728e-3*x1)*sx7*sx3-5.775e-3*s3x7*sx3+
X (8.1344e-2+3.206e-3*x1)*cx7*sx3+1.5019e-2*c2x7*sx3;
X *dml += (8.5581e-2+2.494e-3*x1)*sx7*cx3+1.4394e-2*c2x7*cx3+
X (2.5328e-2-3.117e-3*x1)*cx7*cx3+
X 6.319e-3*c3x7*cx3+6.369e-3*sx7*s2x3+9.156e-3*s2x7*s2x3+
X 7.525e-3*s3x8*s2x3-5.236e-3*cx7*c2x3-7.736e-3*c2x7*c2x3-
X 7.528e-3*c3x8*c2x3;
X *dml = degrad(*dml);
X
X *ds = (-7927+(2548+91*x1)*x1)*sx5+(13381+(1226-253*x1)*x1)*cx5+
X (248-121*x1)*s2x5-(305+91*x1)*c2x5+412*s2x7+12415*sx3+
X (390-617*x1)*sx7*sx3+(165-204*x1)*s2x7*sx3+26599*cx7*sx3-
X 4687*c2x7*sx3-1870*c3x7*sx3-821*c4x7*sx3-
X 377*c5x7*sx3+497*c2x8*sx3+(163-611*x1)*cx3;
X *ds += -12696*sx7*cx3-4200*s2x7*cx3-1503*s3x7*cx3-619*s4x7*cx3-
X 268*s5x7*cx3-(282+1306*x1)*cx7*cx3+(-86+230*x1)*c2x7*cx3+
X 461*s2x8*cx3-350*s2x3+(2211-286*x1)*sx7*s2x3-
X 2208*s2x7*s2x3-568*s3x7*s2x3-346*s4x7*s2x3-
X (2780+222*x1)*cx7*s2x3+(2022+263*x1)*c2x7*s2x3+248*c3x7*s2x3+
X 242*s3x8*s2x3+467*c3x8*s2x3-490*c2x3-(2842+279*x1)*sx7*c2x3;
X *ds += (128+226*x1)*s2x7*c2x3+224*s3x7*c2x3+
X (-1594+282*x1)*cx7*c2x3+(2162-207*x1)*c2x7*c2x3+
X 561*c3x7*c2x3+343*c4x7*c2x3+469*s3x8*c2x3-242*c3x8*c2x3-
X 205*sx7*s3x3+262*s3x7*s3x3+208*cx7*c3x3-271*c3x7*c3x3-
X 382*c3x7*s4x3-376*s3x7*c4x3;
X *ds *= 1e-7;
X
X dp = (7.7108e-2+(7.186e-3-1.533e-3*x1)*x1)*sx5-7.075e-3*sx7+
X (4.5803e-2-(1.4766e-2+5.36e-4*x1)*x1)*cx5-7.2586e-2*cx3-
X 7.5825e-2*sx7*sx3-2.4839e-2*s2x7*sx3-8.631e-3*s3x7*sx3-
X 1.50383e-1*cx7*cx3+2.6897e-2*c2x7*cx3+1.0053e-2*c3x7*cx3-
X (1.3597e-2+1.719e-3*x1)*sx7*s2x3+1.1981e-2*s2x7*c2x3;
X dp += -(7.742e-3-1.517e-3*x1)*cx7*s2x3+
X (1.3586e-2-1.375e-3*x1)*c2x7*c2x3-
X (1.3667e-2-1.239e-3*x1)*sx7*c2x3+
X (1.4861e-2+1.136e-3*x1)*cx7*c2x3-
X (1.3064e-2+1.628e-3*x1)*c2x7*c2x3;
X
X *dm = *dml-(degrad(dp)/s);
X
X *da = 572*sx5-1590*s2x7*cx3+2933*cx5-647*s3x7*cx3+33629*cx7-
X 344*s4x7*cx3-3081*c2x7+2885*cx7*cx3-1423*c3x7+
X (2172+102*x1)*c2x7*cx3-671*c4x7+296*c3x7*cx3-320*c5x7-
X 267*s2x7*s2x3+1098*sx3-778*cx7*s2x3-2812*sx7*sx3;
X *da += 495*c2x7*s2x3+688*s2x7*sx3+250*c3x7*s2x3-393*s3x7*sx3-
X 856*sx7*c2x3-228*s4x7*sx3+441*s2x7*c2x3+2138*cx7*sx3+
X 296*c2x7*c2x3-999*c2x7*sx3+211*c3x7*c2x3-642*c3x7*sx3-
X 427*sx7*s3x3-325*c4x7*sx3+398*s3x7*s3x3-890*cx3+
X 344*cx7*c3x3+2206*sx7*cx3-427*c3x7*c3x3;
X *da *= 1e-6;
X
X *dhl = 7.47e-4*cx7*sx3+1.069e-3*cx7*cx3+2.108e-3*s2x7*s2x3+
X 1.261e-3*c2x7*s2x3+1.236e-3*s2x7*c2x3-2.075e-3*c2x7*c2x3;
X *dhl = degrad(*dhl);
X}
X
X/* ....uranus */
Xstatic
Xp_uranus (t, s, dl, dr, dml, ds, dm, da, dhl)
Xdouble t, s;
Xdouble *dl, *dr, *dml, *ds, *dm, *da, *dhl;
X{
X double dp;
X double x1, x2, x3, x4, x5, x6;
X double x8, x9, x10, x11, x12;
X double sx4, cx4, s2x4, c2x4;
X double sx9, cx9, s2x9, c2x9;
X double sx11, cx11;
X
X aux_jsun (t, &x1, &x2, &x3, &x4, &x5, &x6);
X
X x8 = mod2PI(1.46205+3.81337*t);
X x9 = 2*x8-x4;
X sx9 = sin(x9);
X cx9 = cos(x9);
X s2x9 = sin(2*x9);
X c2x9 = cos(2*x9);
X
X x10 = x4-x2;
X x11 = x4-x3;
X x12 = x8-x4;
X
X *dml = (8.64319e-1-1.583e-3*x1)*sx9+(8.2222e-2-6.833e-3*x1)*cx9+
X 3.6017e-2*s2x9-3.019e-3*c2x9+8.122e-3*sin(x6);
X *dml = degrad(*dml);
X
X dp = 1.20303e-1*sx9+6.197e-3*s2x9+(1.9472e-2-9.47e-4*x1)*cx9;
X *dm = *dml-(degrad(dp)/s);
X
X *ds = (163*x1-3349)*sx9+20981*cx9+1311*c2x9;
X *ds *= 1e-7;
X
X *da = -3.825e-3*cx9;
X
X *dl = (1.0122e-2-9.88e-4*x1)*sin(x4+x11)+
X (-3.8581e-2+(2.031e-3-1.91e-3*x1)*x1)*cos(x4+x11)+
X (3.4964e-2-(1.038e-3-8.68e-4*x1)*x1)*cos(2*x4+x11)+
X 5.594e-3*sin(x4+3*x12)-1.4808e-2*sin(x10)-
X 5.794e-3*sin(x11)+2.347e-3*cos(x11)+9.872e-3*sin(x12)+
X 8.803e-3*sin(2*x12)-4.308e-3*sin(3*x12);
X
X sx11 = sin(x11);
X cx11 = cos(x11);
X sx4 = sin(x4);
X cx4 = cos(x4);
X s2x4 = sin(2*x4);
X c2x4 = cos(2*x4);
X *dhl = (4.58e-4*sx11-6.42e-4*cx11-5.17e-4*cos(4*x12))*sx4-
X (3.47e-4*sx11+8.53e-4*cx11+5.17e-4*sin(4*x11))*cx4+
X 4.03e-4*(cos(2*x12)*s2x4+sin(2*x12)*c2x4);
X *dhl = degrad(*dhl);
X
X *dr = -25948+4985*cos(x10)-1230*cx4+3354*cos(x11)+904*cos(2*x12)+
X 894*(cos(x12)-cos(3*x12))+(5795*cx4-1165*sx4+1388*c2x4)*sx11+
X (1351*cx4+5702*sx4+1388*s2x4)*cos(x11);
X *dr *= 1e-6;
X}
X
X/* ....neptune */
Xstatic
Xp_neptune (t, s, dl, dr, dml, ds, dm, da, dhl)
Xdouble t, s;
Xdouble *dl, *dr, *dml, *ds, *dm, *da, *dhl;
X{
X double dp;
X double x1, x2, x3, x4, x5, x6;
X double x8, x9, x10, x11, x12;
X double sx8, cx8;
X double sx9, cx9, s2x9, c2x9;
X double s2x12, c2x12;
X
X aux_jsun (t, &x1, &x2, &x3, &x4, &x5, &x6);
X
X x8 = mod2PI(1.46205+3.81337*t);
X x9 = 2*x8-x4;
X sx9 = sin(x9);
X cx9 = cos(x9);
X s2x9 = sin(2*x9);
X c2x9 = cos(2*x9);
X
X x10 = x8-x2;
X x11 = x8-x3;
X x12 = x8-x4;
X
X *dml = (1.089e-3*x1-5.89833e-1)*sx9+(4.658e-3*x1-5.6094e-2)*cx9-
X 2.4286e-2*s2x9;
X *dml = degrad(*dml);
X
X dp = 2.4039e-2*sx9-2.5303e-2*cx9+6.206e-3*s2x9-5.992e-3*c2x9;
X
X *dm = *dml-(degrad(dp)/s);
X
X *ds = 4389*sx9+1129*s2x9+4262*cx9+1089*c2x9;
X *ds *= 1e-7;
X
X *da = 8189*cx9-817*sx9+781*c2x9;
X *da *= 1e-6;
X
X s2x12 = sin(2*x12);
X c2x12 = cos(2*x12);
X sx8 = sin(x8);
X cx8 = cos(x8);
X *dl = -9.556e-3*sin(x10)-5.178e-3*sin(x11)+2.572e-3*s2x12-
X 2.972e-3*c2x12*sx8-2.833e-3*s2x12*cx8;
X
X *dhl = 3.36e-4*c2x12*sx8+3.64e-4*s2x12*cx8;
X *dhl = degrad(*dhl);
X
X *dr = -40596+4992*cos(x10)+2744*cos(x11)+2044*cos(x12)+1051*c2x12;
X *dr *= 1e-6;
X}
X
END_OF_FILE
if test 17647 -ne `wc -c <'plans.c'`; then
echo shar: \"'plans.c'\" unpacked with wrong size!
fi
# end of 'plans.c'
fi
if test -f 'watch.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'watch.c'\"
else
echo shar: Extracting \"'watch.c'\" \(11959 characters\)
sed "s/^X//" >'watch.c' <<'END_OF_FILE'
X/* these functions allow you to watch the sky or the solar system via a
X * simple character-graphics representation on the screen.
X * the interaction starts by using the current time. then control with
X * END returns to table form; or
X * RETURN advances time by one StpSz; or
X * h advances once by 1 hour; or
X * d advances once by 24 hours (1 day); or
X * w advances once by 7 days (1 week); or
X * any other key free runs by StpSz until any key is hit.
X */
X
X#include <stdio.h>
X#include <math.h>
X#include "astro.h"
X#include "circum.h"
X#include "screen.h"
X
X#define SSZCOL 1 /* column to show solar system z coords */
X
X#define DOMESKY 0 /* flags for watch_sky() */
X#define ALTAZSKY 1 /* flags for watch_sky() */
X
X#define SKYACC 3600. /* desired sky plot accuracy, in arc seconds */
X#define SSACC 3600. /* desired solar system plot accuracy, in arc secs */
X
X/* macros to convert row(col) in range 1..NR(1..NC) to fraction in range 0..1 */
X#define r2fr(r) (((r)-1)/(NR-1))
X#define c2fc(c) (((c)-1)/(NC-1))
X#define fr2r(fr) ((int)((fr)*(NR-1)+.5)+1)
X#define fc2c(fc) ((int)((fc)*(NC-1)+.5)+1)
X
X/* single-character tag for each body.
X * order must match the #defines in astro.h and screen.h additions.
X */
Xstatic char body_tags[] = "evmjsunpSMxy";
X
X/* multiple and single loop prompts */
Xstatic char frprompt[] = "Running... press any key to stop.";
Xstatic char qprompt[] =
X"q to quit, RETURN/h/d/w to step by StpSz/hr/day/wk, or any other to freerun";
X
X/* used to locate, record and then erase last plotted chars */
Xtypedef struct {
X double l_fr, l_fc; /* 2d coords as 0..1 (lower left corner is [0,0]) */
X int l_r, l_c; /* screen 2d coords (upper left corner is [1,1]) */
X char l_tag; /* char to use to print on screen */
X} LastDraw;
X
Xstatic int trails; /* !0 if want to leave trails */
X
Xwatch (np, tminc, wbodies)
XNow *np; /* time now and on each step */
Xdouble tminc; /* hrs to increment time by each step */
Xint wbodies; /* each bit is !=0 if want that body */
X{
X static char *flds[4] = {
X "Sky dome", "Alt/az sky", "Solar system"
X };
X static int fn; /* begin with 0, then remember for next time */
X int didone = 0;
X
X while (1) {
X int nf;
X flds[3] = trails ? "Leave trails" : "No trails";
X if ((nf = popup (flds, fn, 4)) < 0)
X break;
X fn = nf;
X switch (nf) {
X case 0: watch_sky (DOMESKY, np, tminc, wbodies); didone = 1; break;
X case 1: watch_sky (ALTAZSKY, np, tminc, wbodies); didone = 1; break;
X case 2: watch_solarsystem (np, tminc, wbodies); didone = 1; break;
X case 3: trails ^= 1; break;
X }
X }
X
X if (didone)
X redraw_screen(2);
X}
X
X/* full alt/az or dome sky view (like the popular astro mags).
X * alt/az: north is at left and right of screen, south at center.
X * 0 elevation is at bottom of screen, zenith at the top.
X * dome: east is left, north is up.
X */
Xstatic
Xwatch_sky (style, np, tminc, wbodies)
Xint style; /* DOMESKY or ALTAZSKY */
XNow *np; /* time now and on each step */
Xdouble tminc; /* hrs to increment time by each step */
Xint wbodies; /* each bit is !=0 if want */
X{
X static char east[] = "East";
X static char west[] = "West";
X static char north[] = "North";
X static char south[] = "South";
X double tminc0 = tminc; /* remember the original */
X /* two draw buffers so we can leave old up while calc new then
X * erase and draw in one quick operation. always calc new in newp
X * buffer and erase previous from lastp. buffers alternate roles.
X */
X LastDraw ld0[NOBJ], ld1[NOBJ], *lp, *lastp = ld0, *newp = ld1;
X int nlast = 0, nnew;
X int once = 1;
X double lmjd, tmp;
X Sky s;
X int p;
X
X /* clear screen and put up the permanent labels */
X c_erase();
X if (style == DOMESKY) {
X f_string (fr2r(.5), fc2c(.5-.5/ASPECT)-7, "East |");
X f_char (fr2r(.5+.5*.707), fc2c(.5-.5*.707/ASPECT)-1, '\\');
X f_string (fr2r(1.), fc2c(.5)-2, south);
X f_char (fr2r(.5+.5*.707), fc2c(.5+.5*.707/ASPECT)+1, '/');
X f_string (fr2r(.5), fc2c(.5+.5/ASPECT)+1, "| West");
X f_char (fr2r(.5-.5*.707), fc2c(.5+.5*.707/ASPECT)+1, '\\');
X f_string (2, NC/2-2, north);
X f_char (fr2r(.5-.5*.707), fc2c(.5-.5*.707/ASPECT)-1, '/');
X } else {
X f_string (NR, 1, north);
X f_string (NR, NC/4, east);
X f_string (NR, NC/2, south);
X f_string (NR, 3*NC/4, west);
X f_string (NR, NC-5, north); /* -1 more to avoid scrolling */
X f_string (2, NC/2-3, "Zenith");
X }
X f_string (2, 1, tznm);
X f_string (3, 1, "LST");
X
X while (1) {
X if (once)
X print_updating();
X
X /* calculate desired stuff into newp[] */
X nnew = 0;
X for (p = nxtbody(-1); p != -1; p = nxtbody(p))
X if (wbodies & (1<<p)) {
X (void) body_cir (p, SKYACC, np, &s);
X if (s.s_alt >= 0) {
X LastDraw *lnp = newp + nnew;
X if (style == DOMESKY) {
X tmp = 0.5 - s.s_alt/PI;
X lnp->l_fr = 0.5 - tmp*cos(s.s_az);
X lnp->l_fc = 0.5 - tmp*sin(s.s_az)/ASPECT;
X } else {
X lnp->l_fr = 1.0 - s.s_alt/(PI/2);
X lnp->l_fc = s.s_az/(2*PI);
X }
X lnp->l_tag = body_tags[p];
X nnew++;
X }
X }
X set_screencoords (newp, nnew);
X
X /* unless we want trails,
X * erase any previous tags (in same order as written) from lastp[].
X */
X if (!trails)
X for (lp = lastp; --nlast >= 0; lp++)
X f_char (lp->l_r, lp->l_c, ' ');
X
X /* print LOCAL time and date we will be using */
X lmjd = mjd - tz/24.0;
X f_time (2, 5, mjd_hr(lmjd));
X f_date (2, 14, mjd_day(lmjd));
X now_lst (np, &tmp);
X f_time (3, 5, tmp);
X
X /* now draw new stuff from newp[] */
X for (lp = newp; lp < newp + nnew; lp++)
X f_char (lp->l_r, lp->l_c, lp->l_tag);
X
X /* swap new and last roles and save new count */
X if (newp == ld0)
X newp = ld1, lastp = ld0;
X else
X newp = ld0, lastp = ld1;
X nlast = nnew;
X
X if (!once)
X slp_sync();
X
X if (once || (chk_char()==0 && read_char()!=0)) {
X if (readwcmd (tminc0, &tminc, &once) < 0)
X break;
X }
X
X /* advance time */
X inc_mjd (np, tminc);
X }
X}
X
X/* solar system view, "down from the top", first point of aries to the right.
X * always include earth.
X */
Xstatic
Xwatch_solarsystem (np, tminc, wbodies)
XNow *np; /* time now and on each step */
Xdouble tminc; /* hrs to increment time by each step */
Xint wbodies;
X{
X /* max au of each planet from sun; in astro.h #defines order */
X static double auscale[] = {.38, .75, 1.7, 5.2, 11., 20., 31., 50.};
X double tminc0 = tminc; /* remember the original */
X /* two draw buffers so we can leave old up while calc new then
X * erase and draw in one quick operation. always calc new in newp
X * buffer and erase previous from lastp. buffers alternate roles.
X */
X LastDraw ld0[2*NOBJ], ld1[2*NOBJ], *lp, *lastp = ld0, *newp = ld1;
X int nlast = 0, nnew;
X int once = 1;
X double lmjd;
X double scale;
X Sky s;
X int p;
X
X /* set screen scale: largest au we will have to plot.
X * never make it less than 1 au since we always show earth.
X */
X scale = 1.0;
X for (p = MARS; p <= PLUTO; p++)
X if ((wbodies & (1<<p)) && auscale[p] > scale)
X scale = auscale[p];
X
X /* clear screen and put up the permanent labels */
X c_erase();
X f_string (2, 1, tznm);
X
X while (1) {
X if (once)
X print_updating();
X
X /* calculate desired stuff into newp[].
X * fake a sun at center and add earth first.
X * (we get earth's loc when ask for sun)
X */
X nnew = 0;
X set_ss (newp+nnew, 0.0, 0.0, 0.0, 'S');
X nnew += 2;
X (void) body_cir (SUN, SSACC, np, &s);
X set_ss (newp+nnew, s.s_edist/scale, s.s_hlong, 0.0, 'E');
X nnew += 2;
X for (p = MERCURY; p <= PLUTO; p++)
X if (p != MOON && (wbodies & (1<<p))) {
X (void) body_cir (p, SSACC, np, &s);
X set_ss (newp+nnew, s.s_sdist/scale, s.s_hlong, s.s_hlat,
X body_tags[p]);
X nnew += 2;
X }
X for (p = OBJX; p != -1; p = (p == OBJX) ? OBJY : -1)
X if (wbodies & (1<<p)) {
X (void) body_cir (p, SSACC, np, &s);
X if (s.s_hlong != NOHELIO && s.s_sdist <= scale) {
X set_ss (newp+nnew, s.s_sdist/scale, s.s_hlong, s.s_hlat,
X body_tags[p]);
X nnew += 2;
X }
X }
X
X set_screencoords (newp, nnew);
X
X /* unless we want trails,
X * erase any previous tags (in same order as written) from lastp[].
X */
X if (!trails)
X for (lp = lastp; --nlast >= 0; lp++)
X safe_f_char (lp->l_r, lp->l_c, ' ');
X
X /* print LOCAL time and date we will be using */
X lmjd = mjd - tz/24.0;
X f_time (2, 5, mjd_hr(lmjd));
X f_date (2, 14, mjd_day(lmjd));
X
X /* now draw new stuff from newp[] */
X for (lp = newp; lp < newp + nnew; lp++)
X safe_f_char (lp->l_r, lp->l_c, lp->l_tag);
X
X /* swap new and last roles and save new count */
X if (newp == ld0)
X newp = ld1, lastp = ld0;
X else
X newp = ld0, lastp = ld1;
X nlast = nnew;
X
X if (!once)
X slp_sync();
X
X if (once || (chk_char()==0 && read_char()!=0)) {
X if (readwcmd (tminc0, &tminc, &once) < 0)
X break;
X }
X
X /* advance time */
X inc_mjd (np, tminc);
X }
X}
X
X/* fill in two LastDraw solar system entries,
X * one for the x/y display, one for the z.
X */
Xstatic
Xset_ss (lp, dist, lg, lt, tag)
XLastDraw *lp;
Xdouble dist, lg, lt; /* scaled heliocentric distance, longitude and lat */
Xchar tag;
X{
X lp->l_fr = 0.5 - dist*sin(lg)*0.5;
X lp->l_fc = 0.5 + dist*cos(lg)*0.5/ASPECT;
X lp->l_tag = tag;
X lp++;
X /* row is to show course helio altitude but since we resolve collisions
X * by adjusting columns we can get more detail by smaller variations
X * within one column.
X */
X lp->l_fr = 0.5 - dist*sin(lt)*0.5;
X lp->l_fc = c2fc(SSZCOL) + (1 - lp->l_fr)/NC;
X lp->l_tag = tag;
X}
X
X/* given a list of LastDraw structs with their l_{fr,fc} filled in,
X * fill in their l_{r,c}.
X * TODO: better collision avoidance.
X */
Xstatic
Xset_screencoords (lp, np)
XLastDraw lp[];
Xint np;
X{
X LastDraw *lpi; /* the current basis for comparison */
X LastDraw *lpj; /* the sweep over other existing cells */
X int i; /* index of the current basis cell, lpi */
X int j; /* index of sweep cell, lpj */
X int n; /* total cells placed so far (ie, # to check) */
X
X /* idea is to place each new item onto the screen.
X * after each placement, look for collisions.
X * if find a colliding pair, move the one with the greater l_fc to
X * the right one cell, then rescan for more collisions.
X * this will yield a result that is sorted by columns by l_fc.
X * TODO: don't just move to the right, try up too for true 2d adjusts.
X */
X for (n = 0; n < np; n++) {
X lpi = lp + n;
X i = n;
X lpi->l_r = fr2r(lpi->l_fr);
X lpi->l_c = fc2c(lpi->l_fc);
X chk:
X for (j = 0; j < n; j++) {
X lpj = lp + j;
X if (i!=j && lpi->l_r == lpj->l_r && lpi->l_c == lpj->l_c) {
X if (lpj->l_fc > lpi->l_fc) {
X /* move lpj and use it as basis for checks now */
X lpi = lpj;
X i = j;
X }
X if (++lpi->l_c > NC)
X lpi->l_c = 1;
X goto chk;
X }
X }
X }
X}
X
X/* since the solar system scaling is only approximate, and doesn't include
X * object x/y at all, characters might get mapped off screen. this funtion
X * guards against drawing chars off screen. it also moves a char being drawn
X * on the lower right corner of the screem left one to avoid scrolling.
X */
Xstatic
Xsafe_f_char (r, c, tag)
Xint r, c;
Xchar tag;
X{
X if (r >= 1 && r <= NR && c >= 1 && c <= NC) {
X if (r == NR && c == NC)
X c -= 1;
X f_char (r, c, tag);
X }
X}
X
X/* see what the op wants to do now and update prompt/times accordingly.
X * return -1 if we are finished, else 0.
X */
Xstatic int
Xreadwcmd (tminc0, tminc, once)
Xdouble tminc0;
Xdouble *tminc;
Xint *once;
X{
X f_prompt (qprompt);
X
X switch (read_char()) {
X case END: /* back to table */
X return (-1);
X case '\r': /* one StpSz step */
X *tminc = tminc0;
X *once = 1;
X break;
X case 'h': /* one 1-hour step */
X *tminc = 1.0;
X *once = 1;
X break;
X case 'd': /* one 24-hr step */
X *tminc = 24.0;
X *once = 1;
X break;
X case 'w': /* 7 day step */
X *tminc = 7*24.0;
X *once = 1;
X break;
X default: /* free-run */
X *once = 0;
X f_prompt (frprompt);
X }
X return (0);
X}
END_OF_FILE
if test 11959 -ne `wc -c <'watch.c'`; then
echo shar: \"'watch.c'\" unpacked with wrong size!
fi
# end of 'watch.c'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 6 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
More information about the Comp.sources.misc
mailing list