home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
x
/
volume19
/
xephem
/
part20
/
marsmenu.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-15
|
15KB
|
564 lines
/* code to manage the stuff on the "mars" menu.
*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#if defined(__STDC__)
#include <stdlib.h>
#endif
#include <X11/Xlib.h>
#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/Frame.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/RowColumn.h>
#include <Xm/DrawingA.h>
#include <Xm/Separator.h>
#include <Xm/ToggleB.h>
#include "astro.h"
#include "circum.h"
#include "map.h"
#if defined(__STDC__) || defined(__cplusplus)
#define P_(s) s
#else
#define P_(s) ()
#endif
extern Now *mm_get_now P_((void));
extern Obj *db_basic P_((int id));
extern int any_ison P_((void));
extern void db_update P_((Obj *op));
extern void f_double P_((Widget w, char *fmt, double f));
extern void get_something P_((Widget w, char *resource, char *value));
extern void hlp_dialog P_((char *tag, char *deflt[], int ndeflt));
extern void range P_((double *v, double r));
extern void register_selection P_((char *name));
extern void timestamp P_((Now *np, Widget w));
void mars_manage P_((void));
void mars_update P_((Now *np, int force));
int mars_ison P_((void));
void mars_selection_mode P_((int whether));
void mars_cursor P_((Cursor c));
static void mars_create_form P_((void));
static void mars_cml_cb P_((Widget w, XtPointer client, XtPointer call));
static void mars_close_cb P_((Widget w, XtPointer client, XtPointer call));
static void mars_help_cb P_((Widget w, XtPointer client, XtPointer call));
static void mars_exp_cb P_((Widget w, XtPointer client, XtPointer call));
static void mars_set_buttons P_((int whether));
static double mars_cml P_((Now *np));
static void mars_map P_((Now *np, double cml));
#undef P_
extern MRegion mreg[];
extern int nmreg;
extern Widget toplevel_w;
#define XtD XtDisplay(toplevel_w)
#define M_CML0 degrad(325.845) /* Mars' CML towards Aries at M_MJD0 */
#define M_PER degrad(350.891962) /* Mars' rotation period, rads/day */
#define M_MJD0 (2418322.0 - MJD0) /* mjd date of M_CML0 */
static int mars_selecting; /* set while our fields are being selected */
static Widget marsform_w; /* main form dialog */
static Widget mars_cml_w; /* CML numberic display widget */
static Widget mars_da_w; /* map DrawingArea widget */
static Widget mars_dt_w; /* data/time stamp label widget */
#define DSIN(x) sin(degrad(x))
#define DCOS(x) cos(degrad(x))
#ifdef __STDC__
static double mars_cml(Now *np);
#else
static double mars_cml();
#endif
void
mars_manage()
{
if (!marsform_w)
mars_create_form();
if (XtIsManaged(marsform_w))
XtUnmanageChild(marsform_w);
else {
XtManageChild(marsform_w);
mars_set_buttons(mars_selecting);
}
}
/* display the map and CML info for circumstances described by *np..
* don't bother with the computation of CML unless we are managed or someone
* cares.
* don't bother with the map unless we are managed.
*/
void
mars_update(np, force)
Now *np;
int force;
{
double cml;
if (!marsform_w)
return;
if (!XtIsManaged(marsform_w) && !any_ison() && !force)
return;
cml = mars_cml (np);
f_double (mars_cml_w, "%5.1f", cml);
if (XtIsManaged(marsform_w))
mars_map (np, cml);
}
mars_ison()
{
return (marsform_w && XtIsManaged(marsform_w));
}
/* called by other menus as they want to hear from our buttons or not.
* the ons and offs stack.
*/
void
mars_selection_mode (whether)
int whether;
{
mars_selecting += whether ? 1 : -1;
if (mars_ison())
if (whether && mars_selecting == 1 /* first one to want on */
|| !whether && mars_selecting == 0 /* first one to want off */)
mars_set_buttons (whether);
}
void
mars_cursor(c)
Cursor c;
{
Window win;
if (marsform_w && (win = XtWindow(marsform_w))) {
Display *dsp = XtDisplay(marsform_w);
if (c)
XDefineCursor(dsp, win, c);
else
XUndefineCursor(dsp, win);
}
}
static void
mars_create_form()
{
static struct {
char *name;
void (*cb)();
} ctls[] = {
{"Close", mars_close_cb},
{"Help", mars_help_cb}
};
Widget w;
Widget fr_w;
Widget f_w;
Widget sep_w;
XmString str;
Arg args[20];
int n;
int i;
/* create form */
n = 0;
XtSetArg (args[n], XmNautoUnmanage, False); n++;
XtSetArg (args[n], XmNdefaultPosition, False); n++;
XtSetArg (args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
XtSetArg (args[n], XmNhorizontalSpacing, 4); n++;
XtSetArg (args[n], XmNverticalSpacing, 4); n++;
marsform_w = XmCreateFormDialog (toplevel_w, "Mars", args, n);
/* set some stuff in the parent DialogShell.
* setting XmNdialogTitle in the Form didn't work..
*/
n = 0;
XtSetArg (args[n], XmNtitle, "xephem Mars view"); n++;
XtSetValues (XtParent(marsform_w), args, n);
/* make the bottom control panel form */
n = 0;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNfractionBase, 9); n++;
XtSetArg (args[n], XmNverticalSpacing, 5); n++;
f_w = XmCreateForm (marsform_w, "CtlF", args, n);
XtManageChild (f_w);
for (i = 0; i < XtNumber(ctls); i++) {
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNleftPosition, 1+i*4); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg (args[n], XmNrightPosition, 4+i*4); n++;
w = XmCreatePushButton (f_w, ctls[i].name, args, n);
XtManageChild (w);
XtAddCallback (w, XmNactivateCallback, ctls[i].cb, NULL);
}
/* make a separator */
n = 0;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNbottomWidget, f_w); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
sep_w = XmCreateSeparator (marsform_w, "Sep", args, n);
XtManageChild(sep_w);
/* make the "cml" label and push button pair */
str = XmStringCreateLtoR("Central Meridian Longitude (degs): ",
XmSTRING_DEFAULT_CHARSET);
n = 0;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNbottomWidget, sep_w); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
XtSetArg (args[n], XmNlabelString, str); n++;
w = XmCreateLabel (marsform_w, "CMLLbl", args, n);
XtManageChild (w);
XmStringFree(str);
n = 0;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNbottomWidget, sep_w); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNleftWidget, w); n++;
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
XtSetArg (args[n], XmNuserData, "Mars.CML"); n++;
mars_cml_w = XmCreatePushButton (marsform_w, "CMLVal", args, n);
XtAddCallback (mars_cml_w, XmNactivateCallback, mars_cml_cb, 0);
XtManageChild (mars_cml_w);
/* make the date/time indicator label */
n = 0;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNbottomWidget, mars_cml_w); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
mars_dt_w = XmCreateLabel (marsform_w, "DTstamp", args, n);
XtManageChild (mars_dt_w);
/* make a drawing area in a frame on top */
n = 0;
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg (args[n], XmNbottomWidget, mars_dt_w); n++;
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg (args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); n++;
fr_w = XmCreateFrame (marsform_w, "MarsFrame", args, n);
XtManageChild (fr_w);
n = 0;
mars_da_w = XmCreateDrawingArea (fr_w, "Map", args, n);
XtAddCallback (mars_da_w, XmNexposeCallback, mars_exp_cb, NULL);
XtManageChild (mars_da_w);
}
/* callback for when the mars CML button is activated. */
/* ARGSUSED */
static void
mars_cml_cb (w, client, call)
Widget w;
XtPointer client;
XtPointer call;
{
if (mars_selecting) {
char *userD;
get_something (w, XmNuserData, (char *)&userD);
register_selection (userD);
}
}
/* callback for when the Close button is activated. */
/* ARGSUSED */
static void
mars_close_cb (w, client, call)
Widget w;
XtPointer client;
XtPointer call;
{
XtUnmanageChild (marsform_w);
}
/* callback from the Help button
*/
/* ARGSUSED */
static void
mars_help_cb (w, client, call)
Widget w;
XtPointer client;
XtPointer call;
{
static char *msg[] = {
"This is a simple schematic depiction of the Martian surface at the given time.",
"Also included is the current Central Meridian Longitude, in degrees.",
"South is up and longitude increases to the right; therefore, the planet",
"appears to rotate CW as seen from above."
};
hlp_dialog ("Mars", msg, XtNumber(msg));
}
/* called whenever the mars drawing area gets an expose.
*/
/* ARGSUSED */
static void
mars_exp_cb (w, client, call)
Widget w;
XtPointer client;
XtPointer call;
{
XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
/* filter out a few oddball cases */
switch (c->reason) {
case XmCR_EXPOSE: {
/* turn off gravity so we get expose events for either shrink or
* expand.
*/
static before;
XExposeEvent *e = &c->event->xexpose;
if (!before) {
XSetWindowAttributes swa;
swa.bit_gravity = ForgetGravity;
XChangeWindowAttributes (e->display, e->window,
CWBitGravity, &swa);
before = 1;
}
/* wait for the last in the series */
if (e->count != 0)
return;
break;
}
default:
printf ("Unexpected marsform_w event. type=%d\n", c->reason);
exit(1);
}
mars_update (mm_get_now(), 1);
}
/* go through all the buttons and set whether they
* should appear to look like buttons or just flat labels.
*/
static void
mars_set_buttons (whether)
int whether; /* whether setting up for plotting or for not plotting */
{
static Arg look_like_button[] = {
{XmNtopShadowColor, (XtArgVal) 0},
{XmNbottomShadowColor, (XtArgVal) 0},
{XmNfillOnArm, (XtArgVal) True},
};
static Arg look_like_label[] = {
{XmNtopShadowColor, (XtArgVal) 0},
{XmNbottomShadowColor, (XtArgVal) 0},
{XmNfillOnArm, (XtArgVal) False},
};
static int called;
Arg *ap;
int na;
if (!called) {
/* get baseline label and shadow appearances.
*/
Pixel topshad, botshad, bgcol;
Arg args[20];
int n;
n = 0;
XtSetArg (args[n], XmNtopShadowColor, &topshad); n++;
XtSetArg (args[n], XmNbottomShadowColor, &botshad); n++;
XtSetArg (args[n], XmNbackground, &bgcol); n++;
XtGetValues (mars_cml_w, args, n);
look_like_button[0].value = topshad;
look_like_button[1].value = botshad;
look_like_label[0].value = bgcol;
look_like_label[1].value = bgcol;
called = 1;
}
if (whether) {
ap = look_like_button;
na = XtNumber(look_like_button);
} else {
ap = look_like_label;
na = XtNumber(look_like_label);
}
XtSetValues (mars_cml_w, ap, na);
}
/* return the Martian central meridian longitude at np, in degrees. */
static double
mars_cml(np)
Now *np;
{
Obj *sp, *mp;
double a; /* angle from Sun ccw to Earth seen from Mars, rads */
double Ae; /* planetocentric longitude of Earth from Mars, rads */
double cml0; /* Mar's CML towards Aries, rads */
double lc; /* Mars rotation correction for light travel, rads */
double cml;
sp = db_basic (SUN);
db_update (sp);
mp = db_basic (MARS);
db_update (mp);
a = asin (sp->s_edist/mp->s_edist*sin(mp->s_hlong-sp->s_hlong));
Ae = mp->s_hlong + PI + a;
cml0 = M_CML0 + M_PER*(mjd-M_MJD0) + PI/2;
range(&cml0, 2*PI);
lc = LTAU * mp->s_edist/SPD*M_PER;
cml = cml0 - Ae - lc;
range (&cml, 2*PI);
cml = raddeg(cml);
/*
printf ("a=%g Ae=%g cml0=%g lc=%g cml=%g\n", raddeg(a), raddeg(Ae),
raddeg(cml0), raddeg(lc), cml);
*/
return (cml);
}
static void
mars_map(np, cml)
Now *np;
double cml;
{
static unsigned long last_w, last_h;
static Pixmap mars_pm;
static GC mars_gc;
static Pixel mars_fg, mars_bg;
Display *dsp = XtDisplay(mars_da_w);
Window win = XtWindow(mars_da_w);
int x, y;
unsigned w, h, b, d;
MRegion *rp;
XPoint p[128];
int npts;
Window root;
int wb, hb, r;
MCoord *cp;
int maxx, minx, maxy, miny;
/* make the GC if this is our first time */
if (!mars_gc) {
XGCValues gcv;
unsigned long gcm;
gcm = 0;
mars_gc = XCreateGC (dsp, win, gcm, &gcv);
get_something (mars_da_w, XmNforeground, (char *)&mars_fg);
get_something (mars_da_w, XmNbackground, (char *)&mars_bg);
}
/* set up width and height borders and the radius so the
* planetary sphere is a circle centered within the window.
*/
XGetGeometry (dsp, win, &root, &x, &y, &w, &h, &b, &d);
if (w > h) {
wb = (w - h)/2;
hb = 0;
r = h/2;
} else {
wb = 0;
hb = (h - w)/2;
r = w/2;
}
/* make the pixmap if this is our first time or the size has changed */
if (!mars_pm || w != last_w || h != last_h) {
last_w = w;
last_h = h;
if (mars_pm)
XFreePixmap (dsp, mars_pm);
mars_pm = XCreatePixmap (dsp, win, w, h, d);
}
/* clear the scene, draw filled circle in foreground then fill in
* regions in background. Then make another pass and overlay the names.
* we draw south (negative latitudes) downwards (in X's +y diretion)
* and with increasing longitudes progressing to the right. this
* means the planet appears to rotate CW as seen from above.
*/
XSetFunction (dsp, mars_gc, GXcopy);
XSetForeground (dsp, mars_gc, mars_bg);
XFillRectangle (dsp, mars_pm, mars_gc, 0, 0, w, h);
XSetForeground (dsp, mars_gc, mars_fg);
XFillArc (dsp, mars_pm, mars_gc, wb, hb, 2*r, 2*r, 0, 360*64);
XSetForeground (dsp, mars_gc, mars_bg);
for (rp = mreg; rp < mreg+nmreg; rp++) {
npts = 0;
for (cp = rp->mcp; cp < rp->mcp+rp->nmcp; cp++) {
double dlg = cp->lg - cml;
range (&dlg, 360.0);
if (dlg >= 90 && dlg <= 270)
goto skip_region;
p[npts].x = wb + r*(1 + DSIN(dlg)*DCOS(cp->lt));
p[npts].y = hb + r*(1 + DSIN(cp->lt));
npts++;
}
XFillPolygon (dsp, mars_pm, mars_gc, p, npts,Nonconvex,CoordModeOrigin);
skip_region:
continue;
}
XSetFunction (dsp, mars_gc, GXxor);
XSetForeground (dsp, mars_gc, mars_fg^mars_bg);
for (rp = mreg; rp < mreg+nmreg; rp++) {
maxx = 0; minx = w; maxy = 0; miny = h;
for (cp = rp->mcp; cp < rp->mcp+rp->nmcp; cp++) {
double dlg = cp->lg - cml;
range (&dlg, 360.0);
if (dlg >= 90 && dlg <= 270)
goto skip_name;
x = wb + r*(1 + DSIN(dlg)*DCOS(cp->lt));
y = hb + r*(1 + DSIN(cp->lt));
if (x > maxx) maxx = x;
if (x < minx) minx = x;
if (y > maxy) maxy = y;
if (y < miny) miny = y;
}
XDrawString (dsp, mars_pm, mars_gc, (minx+maxx)/2, (miny+maxy)/2,
rp->rname, strlen(rp->rname));
skip_name:
continue;
}
XSetFunction (dsp, mars_gc, GXcopy);
XCopyArea (dsp, mars_pm, win, mars_gc, 0, 0, w, h, 0, 0);
timestamp (np, mars_dt_w);
}