home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
EFFO
/
pd8.lzh
/
SRC
/
watch.c
< prev
Wrap
Text File
|
1990-04-13
|
10KB
|
369 lines
/* these functions allow you to watch the sky or the solar system via a
* simple character-graphics representation on the screen.
* the interaction starts by using the current time. then control with
* END returns to table form; or
* RETURN advances time by one StpSz; or
* h advances once by 1 hour; or
* d advances once by 24 hours (1 day); or
* w advances once by 7 days (1 week); or
* any other key free runs by StpSz until any key is hit.
*/
#include <stdio.h>
#include <math.h>
#include "astro.h"
#include "circum.h"
#include "screen.h"
#define TROW (R_PROMPT+1) /* time/date row */
#define TCOL C_PROMPT /* " col */
#define SSZCOL 1 /* column to show solar system z coords */
#define SKYACC 3600. /* desired sky plot accuracy, in arc seconds */
#define SSACC 3600. /* desired solar system plot accuracy, in arc secs */
/* macros to convert row(col) in range 1..NR(1..NC) to fraction in range 0..1 */
#define r2fr(r) (((r)-1)/(NR-1))
#define c2fc(c) (((c)-1)/(NC-1))
#define fr2r(fr) ((fr)*(NR-1)+1)
#define fc2c(fc) ((fc)*(NC-1)+1)
/* single-character tag for each body.
* order must match the #defines in astro.h and screen.h additions.
*/
static char body_tags[] = "evmjsunpSMx";
/* multiple and single loop prompts */
static char frprompt[] = "Running... press any key to stop.";
static char qprompt[] =
"q to quit, RETURN/h/d/w to step by StpSz/hr/day/wk, or any other to freerun";
/* used to locate, record and then erase last plotted chars */
typedef struct {
double l_fr, l_fc; /* 2d coords as 0..1 */
int l_r, l_c; /* screen 2d coords */
char l_tag; /* char to use to print on screen */
} LastDraw;
static int trails; /* !0 if want to leave trails */
watch (np, tminc, wbodies)
Now *np; /* time now and on each step */
double tminc; /* hrs to increment time by each step */
int wbodies; /* each bit is !=0 if want that body */
{
static char *flds[3] = {
"Sky", "Solar system"
};
int fn = 0;
ask:
flds[2] = trails ? "Leave trails" : "No trails";
switch (popup (flds, fn, 3)) {
case 0: watch_sky (np, tminc, wbodies); break;
case 1: watch_solarsystem (np, tminc, wbodies); break;
case 2: trails ^= 1; fn = 2; goto ask; /* toggle trails and repeat */
default: break;
}
}
/* full night sky view.
* north is at left and right of screen south at center.
* 0 elevation is at bottom of screen, zenith at the top.
* redraw screen when done.
*/
static
watch_sky (np, tminc, wbodies)
Now *np; /* time now and on each step */
double tminc; /* hrs to increment time by each step */
int wbodies; /* each bit is !=0 if want */
{
static char title[] = "Sky at";
int tcol = sizeof(title)+1;
double tminc0 = tminc; /* remember the original */
/* two draw buffers so we can leave old up while calc new then
* erase and draw in one quick operation. always calc new in newp
* buffer and erase previous from lastp. buffers alternate roles.
*/
LastDraw ld0[NOBJ], ld1[NOBJ], *lp, *lastp = ld0, *newp = ld1;
int nlast = 0, nnew;
int once = 1;
double lmjd, tmp;
Sky s;
int p;
c_erase();
f_string (TROW, TCOL, title);
while (1) {
if (once)
print_updating();
/* calculate desired stuff into newp[] */
nnew = 0;
for (p = nxtbody(-1); p != -1; p = nxtbody(p))
if (wbodies & (1<<p)) {
(void) body_cir (p, SKYACC, np, &s);
if (s.s_alt >= 0) {
LastDraw *lnp = newp + nnew;
lnp->l_fr = 1.0 - s.s_alt/(PI/2);
lnp->l_fc = s.s_az/(2*PI);
lnp->l_tag = body_tags[p];
nnew++;
}
}
set_screencoords (newp, nnew);
/* unless we want trails,
* erase any previous tags (in same order as written) from lastp[].
*/
if (!trails)
for (lp = lastp; --nlast >= 0; lp++)
f_char (lp->l_r, lp->l_c, ' ');
/* print LOCAL time and date we will be using */
lmjd = mjd - tz/24.0;
f_time (TROW, tcol, mjd_hr(lmjd));
f_date (TROW, tcol+9, mjd_day(lmjd));
now_lst (np, &tmp);
f_time (TROW, tcol+20, tmp);
printf ("LST");
/* now draw new stuff from newp[] */
for (lp = newp; lp < newp + nnew; lp++)
f_char (lp->l_r, lp->l_c, lp->l_tag);
/* swap new and last roles and save new count */
if (newp == ld0)
newp = ld1, lastp = ld0;
else
newp = ld0, lastp = ld1;
nlast = nnew;
#ifdef OSK
fflush(stdout);
#endif
if (once || (chk_char()==0 && read_char()!=0)) {
if (readwcmd (tminc0, &tminc, &once) < 0)
break;
}
/* advance time */
inc_mjd (np, tminc);
}
redraw_screen(2);
}
/* solar system view, "down from the top", first point of aries to the right.
* always include earth.
* redraw screen when done.
*/
static
watch_solarsystem (np, tminc, wbodies)
Now *np; /* time now and on each step */
double tminc; /* hrs to increment time by each step */
int wbodies;
{
/* max au of each planet from sun; in astro.h #defines order */
static double auscale[] = {.38, .75, 1.7, 5.2, 11., 20., 31., 39.};
static char title[] = "Solar System at";
int tcol = sizeof(title)+1;
double tminc0 = tminc; /* remember the original */
/* two draw buffers so we can leave old up while calc new then
* erase and draw in one quick operation. always calc new in newp
* buffer and erase previous from lastp. buffers alternate roles.
*/
LastDraw ld0[2*NOBJ], ld1[2*NOBJ], *lp, *lastp = ld0, *newp = ld1;
int nlast = 0, nnew;
int once = 1;
double lmjd;
double scale;
Sky s;
int p;
/* set screen scale: largest au we will have to plot.
* never make it less than 1 au since we always show earth.
*/
scale = 1.0;
for (p = MARS; p <= PLUTO; p++)
if ((wbodies & (1<<p)) && auscale[p] > scale)
scale = auscale[p];
c_erase();
f_string (TROW, TCOL, title);
while (1) {
if (once)
print_updating();
/* calculate desired stuff into newp[].
* fake a sun at center and add earth first.
* (we get earth's loc when ask for sun)
*/
nnew = 0;
set_ss (newp+nnew, 0.0, 0.0, 0.0, 'S');
nnew += 2;
(void) body_cir (SUN, SSACC, np, &s);
set_ss (newp+nnew, s.s_edist/scale, s.s_hlong, 0.0, 'E');
nnew += 2;
for (p = MERCURY; p <= PLUTO; p++)
if (wbodies & (1<<p)) {
(void) body_cir (p, SSACC, np, &s);
set_ss (newp+nnew, s.s_sdist/scale, s.s_hlong, s.s_hlat,
body_tags[p]);
nnew += 2;
}
for (p = OBJX; p != -1; p = (p == OBJX) ? OBJY : -1)
if (wbodies & (1<<p)) {
(void) body_cir (p, SSACC, np, &s);
if (s.s_hlong != NOHELIO && s.s_sdist <= scale) {
set_ss (newp+nnew, s.s_sdist/scale, s.s_hlong, s.s_hlat,
body_tags[p]);
nnew += 2;
}
}
set_screencoords (newp, nnew);
/* unless we want trails,
* erase any previous tags (in same order as written) from lastp[].
*/
if (!trails)
for (lp = lastp; --nlast >= 0; lp++)
f_char (lp->l_r, lp->l_c, ' ');
/* print LOCAL time and date we will be using */
lmjd = mjd - tz/24.0;
f_time (TROW, tcol, mjd_hr(lmjd));
f_date (TROW, tcol+9, mjd_day(lmjd));
/* now draw new stuff from newp[] */
for (lp = newp; lp < newp + nnew; lp++)
f_char (lp->l_r, lp->l_c, lp->l_tag);
/* swap new and last roles and save new count */
if (newp == ld0)
newp = ld1, lastp = ld0;
else
newp = ld0, lastp = ld1;
nlast = nnew;
#ifdef OSK
fflush(stdout);
#endif
if (once || (chk_char()==0 && read_char()!=0)) {
if (readwcmd (tminc0, &tminc, &once) < 0)
break;
}
/* advance time */
inc_mjd (np, tminc);
}
redraw_screen(2);
}
/* fill in two LastDraw solar system entries,
* one for the x/y display, one for the z.
*/
static
set_ss (lp, dist, lg, lt, tag)
LastDraw *lp;
double dist, lg, lt; /* scaled heliocentric distance, longitude and lat */
char tag;
{
lp->l_fr = 0.5 - dist*sin(lg)*0.5;
lp->l_fc = 0.5 + dist*cos(lg)*0.5/ASPECT;
lp->l_tag = tag;
lp++;
/* row is to show course helio altitude but since we resolve collisions
* by adjusting columns we can get more detail by smaller variations
* within one column.
*/
lp->l_fr = 0.5 - dist*sin(lt)*0.5;
lp->l_fc = c2fc(SSZCOL) + (1 - lp->l_fr)/NC;
lp->l_tag = tag;
}
/* given a list of LastDraw structs with their l_{fr,fc} filled in,
* fill in their l_{r,c}.
* TODO: better collision avoidance.
*/
static
set_screencoords (lp, np)
LastDraw lp[];
int np;
{
LastDraw *lpi; /* the current basis for comparison */
LastDraw *lpj; /* the sweep over other existing cells */
int i; /* index of the current basis cell, lpi */
int j; /* index of sweep cell, lpj */
int n; /* total cells placed so far (ie, # to check) */
/* idea is to place each new item onto the screen.
* after each placement, look for collisions.
* if find a colliding pair, move the one with the great l_fc to
* the right one cell, then rescan for more collisions.
* this will yield a result that is sorted by columns by l_fc.
* TODO: don't just move to the right, try up too for true 2d adjusts.
*/
for (n = 0; n < np; n++) {
lpi = lp + n;
i = n;
lpi->l_r = fr2r(lpi->l_fr);
lpi->l_c = fc2c(lpi->l_fc);
chk:
for (j = 0; j < n; j++) {
lpj = lp + j;
if (i!=j && lpi->l_r == lpj->l_r && lpi->l_c == lpj->l_c) {
if (lpj->l_fc > lpi->l_fc) {
/* move lpj and use it as basis for checks now */
lpi = lpj;
i = j;
}
if (++lpi->l_c > NC)
lpi->l_c = 1;
goto chk;
}
}
}
}
/* see what the op wants to do now and update prompt/times accordingly.
* return -1 if we are finished, else 0.
*/
static int
readwcmd (tminc0, tminc, once)
double tminc0;
double *tminc;
int *once;
{
f_prompt (qprompt);
switch (read_char()) {
case END: /* back to table */
return (-1);
case '\r': /* one StpSz step */
*tminc = tminc0;
*once = 1;
break;
case 'h': /* one 1-hour step */
*tminc = 1.0;
*once = 1;
break;
case 'd': /* one 24-hr step */
*tminc = 24.0;
*once = 1;
break;
case 'w': /* 7 day step */
*tminc = 7*24.0;
*once = 1;
break;
default: /* free-run */
*once = 0;
f_prompt (frprompt);
}
return (0);
}