mirror of https://github.com/XEphem/XEphem.git
5406 lines
148 KiB
C
5406 lines
148 KiB
C
/* code to manage the stuff on the "earth view" display.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/cursorfont.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 <Xm/Scale.h>
|
|
#include <Xm/CascadeB.h>
|
|
|
|
#include "xephem.h"
|
|
|
|
/* these are from earthmap.c */
|
|
extern MRegion ereg[];
|
|
extern int nereg;
|
|
|
|
/* info to keep track of object trails.
|
|
*/
|
|
typedef struct {
|
|
Now t_now; /* Now for object at a given time */
|
|
Obj t_obj; /* it's Obj at that time */
|
|
double t_sublat, t_sublng; /* sub lat/lng of object at that time */
|
|
int t_lbl; /* whether this tickmark gets labeled */
|
|
short lvis, lx, ly; /* if land mark visible: screen x and y */
|
|
} Trail;
|
|
|
|
/* one row -- one per object */
|
|
#define PNL (MAXNM+16) /* size of room for userData pick name */
|
|
/* N.B. use malloced space for _pn because this struct gets realloced around */
|
|
typedef struct {
|
|
Obj *op; /* handy pointer from favs */
|
|
TrState trstate; /* initial and retaining trails options */
|
|
Trail *trail; /* malloced list, current pos always at [0] */
|
|
int ntrail; /* entries in trail[] */
|
|
Widget name_w; /* label to show current object */
|
|
Widget show_w; /* TB whether to show at all */
|
|
Widget wantlbl_w; /* TB whether to add label */
|
|
Widget wantfoot_w; /* TB whether to show footprint */
|
|
Widget wantorb_w; /* TB whether to show earth satellite orbit */
|
|
Widget wantnoorb_w; /* label spacer when orbit not appropriate */
|
|
Widget showtr_w; /* TB whether to show trail (if any) */
|
|
Widget track_w; /* TB whether to keep centered */
|
|
Widget pick_w; /* TB mouse pick info refers to this object */
|
|
Widget slat_w; /* Label for Sub latitude */
|
|
char *slat_pn; /* persistent location for pick name userData */
|
|
Widget slng_w; /* Label for Sub longitude */
|
|
char *slng_pn; /* persistent location for pick name userData */
|
|
Widget el_w; /* Label for Elevation */
|
|
char *el_pn; /* persistent location for pick name userData */
|
|
Widget range_w; /* Label for Range */
|
|
char *range_pn; /* persistent location for pick name userData */
|
|
Widget rrate_w; /* Label for Range Rate */
|
|
char *rrate_pn; /* persistent location for pick name userData */
|
|
Widget sun_w; /* Label for whether sunlit */
|
|
char *sun_pn; /* persistent location for pick name userData */
|
|
Widget age_w; /* Label for TLE age */
|
|
char *age_pn; /* persistent location for pick name userData */
|
|
Pixel pix; /* color to draw */
|
|
int shownbefore; /* set after first shown */
|
|
|
|
short ovis, ox, oy; /* if orbit visible: screen x and y */
|
|
} EObj;
|
|
|
|
|
|
/* projection style */
|
|
typedef enum {
|
|
CYLG, /* cylindrical graphics */
|
|
CYLI, /* cylindrical image */
|
|
SPHG, /* spherical graphics */
|
|
SPHI, /* spherical image */
|
|
WXMAP /* special weather map */
|
|
} Proj;
|
|
|
|
static void e_create_shell (void);
|
|
static void e_create_ctrl (void);
|
|
static void e_buildfavs (void);
|
|
static void e_point_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_stat_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_popdown_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_close_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_webupdate_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_cclose_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_show_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_wantlbl_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_wantfoot_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_wantorb_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_anim_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_mloop_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_set_buttons (int whether);
|
|
static void e_chelp_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_mhelp_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_helpon_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_print_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_print (void);
|
|
static void e_ps_annotate (Now *np);
|
|
static void e_ps_ll (char *tag, double lt, double lg, int x, int y);
|
|
static void e_exp_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_motion_eh (Widget w, XtPointer client, XEvent *ev,
|
|
Boolean *continue_to_dispatch);
|
|
static void e_copen_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_tb_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_ontrack_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_onpick_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_trail_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_showtgl_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_wantfoottgl_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_wantlbltgl_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_wantorbtgl_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_wxreload_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_proj_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_setmain_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_latlong_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_lat0_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void e_track_latlng (Widget w, int d, int xb, int yb, double lt,
|
|
double lg);
|
|
static void e_popup (Widget w, XEvent *ev, unsigned d, unsigned xb,
|
|
unsigned yb, int x, int y);
|
|
static void e_create_popup (void);
|
|
static void e_init_gcs (void);
|
|
static void e_copy_pm (void);
|
|
static void e_setelatlng (double lt, double lg);
|
|
static void e_subobject (Now *np, Obj *op, double *latp, double *longp);
|
|
static void e_show_esat_stats (EObj *eop);
|
|
static int e_coord (unsigned d, unsigned wb, unsigned hb, double pl,
|
|
double pL, short *xp, short *yp);
|
|
static void e_drawgrid (unsigned d, unsigned wb, unsigned hb);
|
|
static void e_drawtrail (EObj *eop, int d, int wb, int hb);
|
|
static void e_draworbit (EObj *eop, int d, int wb, int hb);
|
|
static void e_drawname (EObj *eop, int d, int wb, int hb);
|
|
static void e_draworbname (EObj *eop, int x, int y);
|
|
static int e_drawcross (unsigned d, unsigned wb, unsigned hb, double lt,
|
|
double lg, int style);
|
|
static int e_drawobject (Now *np, EObj *eop, int d, int wb, int hb);
|
|
static int e_drawfootprint (Now *np, EObj *eop, int d, int wb, int hb,
|
|
double slat, double slng, double el);
|
|
static int e_drawcircle (Pixel pix, unsigned d, unsigned wb, unsigned hb,
|
|
double slat, double slng, double rad);
|
|
static int e_set_dasize (void);
|
|
static int e_uncoord (Proj proj, unsigned d, unsigned xb, unsigned yb,
|
|
int x, int y, double *ltp, double *lgp);
|
|
static void e_all (int statstoo);
|
|
static void e_getcircle (int *wp, int *hp, int *rp, int *xbp, int *ybp);
|
|
static void e_map (Now *np);
|
|
static void e_mainmenuloc (Now *np, unsigned d, unsigned wb, unsigned hb);
|
|
static void e_soleclipse (Now *np, unsigned d, unsigned wb, unsigned hb);
|
|
static int e_ano (double *latp, double *longp, int *xp, int *yp, int w2x,
|
|
int arg);
|
|
static void e_sunlit (Now *np, unsigned int d, unsigned int wb,
|
|
unsigned int hb);
|
|
static void e_msunlit (Now *np, unsigned int d, unsigned int wb,
|
|
unsigned int hb);
|
|
static void e_ssunlit (Now *np, unsigned int d, unsigned int wb,
|
|
unsigned int hb);
|
|
static void e_drawcontinents (unsigned d, unsigned wb, unsigned hb);
|
|
static void e_drawsites (unsigned d, unsigned wb, unsigned hb);
|
|
static int add_to_polyline (XPoint xp[], int xpsize, int i, int vis, int nxp,
|
|
int max, int w, int x, int y);
|
|
static void e_viewrad (Now *np, double height, double alt, double *radp);
|
|
static void e_resettrail (EObj *eop, Now *np, int discard);
|
|
static int e_mktrail (TrTS ts[], TrState *statep, XtPointer client);
|
|
static Trail *e_growtrail (EObj *eop);
|
|
static int e_setupwxpm (int reload, int rebuild);
|
|
static int e_issunlit (Now *np, double l, double L);
|
|
static void noTrack (void);
|
|
static void mollweide_llxy (double l, double L, short *xp, short *yp);
|
|
static int mollweide_xyll (int x, int y, double *lp, double *Lp);
|
|
static void rd2ll (double ra, double dec, double *lp, double *Lp);
|
|
static void ll2rd (double l, double L, double *rap, double *decp);
|
|
static int loaddei (void);
|
|
static int loadnei (void);
|
|
static void drawei (unsigned int ww, unsigned int wh, unsigned int d,
|
|
unsigned int xb, unsigned int yb);
|
|
static void e_greatCircle (double lt, double lg, double *dp, double *bp);
|
|
static void e_plotGreatCircle (unsigned d, unsigned wb, unsigned hb, double lt, double lg);
|
|
|
|
static Widget eshell_w; /* main shell */
|
|
static Widget ectrl_w; /* control shell */
|
|
static Widget e_da_w; /* map DrawingArea widget */
|
|
static Widget e_dt_w; /* main date/time stamp label widget */
|
|
static Widget e_cdt_w; /* ctrl menu date/time stamp label widget */
|
|
static Pixmap e_pm; /* use off screen pixmap for smoother drawing */
|
|
static Widget lat_w; /* latitude scale widget */
|
|
static Widget lat0_w; /* PB to set lat 0 */
|
|
static Widget long_w; /* longitude scale widget */
|
|
static Widget zoom_w; /* zoom scale widget */
|
|
static Widget objrc_w; /* main RC in object control dialog */
|
|
static Widget cylg_w; /* cylindrical graphics view toggle button */
|
|
static Widget sphg_w; /* spherical graphics view toggle button */
|
|
static Widget cyli_w; /* cylindrical image view toggle button */
|
|
static Widget sphi_w; /* spherical image view toggle button */
|
|
static Widget wxm_w; /* weather map view toggle button */
|
|
static Widget sites_w; /* TB whether to show sites */
|
|
static Widget altlbl_w; /* label for Altitude, showing units */
|
|
static Widget rangelbl_w; /* label for Range, showing units */
|
|
static Widget rangerlbl_w; /* label for Range Rate, showing units */
|
|
static Widget inertial_w; /* TB whether to maintain inertial reference */
|
|
static Pixel e_bg; /* bg color */
|
|
static GC e_strgc; /* used for text within the drawing area */
|
|
static GC e_olgc; /* used to draw map overlay details */
|
|
static GC e_gc; /* used for all other GXCopy map drawing uses */
|
|
static XFontStruct *e_f; /* used to compute string extents */
|
|
static Proj projection; /* projection style */
|
|
|
|
/* describe each column.
|
|
* N.B. meanings must agree with usage in e_buildfavs()
|
|
*/
|
|
static struct {
|
|
Widget *l_wp; /* label widget, if changes at runtime */
|
|
char *label; /* label */
|
|
XtCallbackProc cb; /* column-wide callback, if used */
|
|
char *tip; /* tip */
|
|
Widget col_w; /* the column RC */
|
|
} rhd[] = {
|
|
{NULL, "Object\n ", NULL, "Name of object"},
|
|
{NULL, "Show \n ", e_showtgl_cb,
|
|
"Toggle the buttons below, which control whether to display object at all"},
|
|
{NULL, "Label\n ", e_wantlbltgl_cb,
|
|
"Toggle the buttons below, which control whether to show obj name"},
|
|
{NULL, "Foot\nPrint", e_wantfoottgl_cb,
|
|
"Toggle the buttons below, which control whether to show footprint"},
|
|
{NULL, "Orbit\n ", e_wantorbtgl_cb,
|
|
"Toggle the buttons below, which control whether to show earth satellite orbit"},
|
|
{NULL, "Trail\n ", NULL,
|
|
"Define trail and whether to show time ticks"},
|
|
{NULL, "Track\n ", NULL, "Choose one object to stay centered"},
|
|
{NULL, "Popup\nRef", NULL,
|
|
"Choose one object as reference in popup"},
|
|
{NULL, "Sub\nLat", NULL, "Latitude of object ground track, +N"},
|
|
{NULL, "Sub\nLong", NULL, "Longitude of object ground track, +W"},
|
|
{&altlbl_w, "Alt\n ", NULL, "Height above sea level"},
|
|
{&rangelbl_w, "Range\n ", NULL, "Distance from Main Site to object"},
|
|
{&rangerlbl_w,"Range\nRate", NULL, "Rate of change of Range"},
|
|
{NULL, "Sun\nlit", NULL,
|
|
"1 if object is in Sun light, 0 in shadow"},
|
|
{NULL, "Age\ndays", NULL, "Age of TLE orbital element set, days"},
|
|
};
|
|
|
|
/* this is to save info about the popup: widgets, and current pointing dir.
|
|
*/
|
|
#define MAXPUL 8 /* max label widgets we ever need at once */
|
|
typedef struct {
|
|
Widget pu_w; /* main Popup parent widget */
|
|
Widget pu_labels[MAXPUL]; /* the misc labels */
|
|
double pu_lt; /* popup's latitude */
|
|
double pu_lg; /* popup's longitude */
|
|
Site *pu_sp; /* Site info if one nearby, else NULL */
|
|
} PopupInfo;
|
|
static PopupInfo pu_info;
|
|
|
|
/* info to get and keep track of the Earth color resources.
|
|
* this does not include the trail colors.
|
|
* N.B. the order of the entries in the enum must match the stuff in ecolors[].
|
|
*/
|
|
typedef enum {
|
|
BORDERC, GRIDC, SITEC, ECLIPSEC, SUNC, HEREC, GREATC, NCOLORS
|
|
} EColors;
|
|
typedef struct {
|
|
char *name;
|
|
Pixel p;
|
|
} EColor;
|
|
static EColor ecolors[NCOLORS] = {
|
|
{"EarthBorderColor"},
|
|
{"EarthGridColor"},
|
|
{"EarthSiteColor"},
|
|
{"EarthEclipseColor"},
|
|
{"EarthSunColor"},
|
|
{"EarthHereColor"},
|
|
{"EarthGreatCircleColor"},
|
|
};
|
|
|
|
/* info to keep track of all the "wants" toggle buttons */
|
|
typedef enum { /* client codes for e_tb_cb and indices into wants[] */
|
|
GRID, SITES, SUNLIGHT, LIVEDRAG, MAINMARKER, NITELITES, INERTIALF,
|
|
NWANTS /* used to count number of entries -- must be last */
|
|
} Wants;
|
|
static int wants[NWANTS]; /* fast state for each of the "wants" TB */
|
|
|
|
enum {SET_MAIN, SET_FROM_MAIN}; /* client codes for e_setmain_cb */
|
|
static char earthcategory[] = "Earth"; /* Save category */
|
|
static char etrres[] = "EarthTrailState"; /* trail resource */
|
|
|
|
static double elat, elng; /* view center lat/long: +N +E rads */
|
|
static double selat, celat; /* sin and cos of map elat */
|
|
static double ira, idec; /* inertial frame ra/dec, rads */
|
|
static Site refsite; /* current reference Site info, if siteok */
|
|
static int refsiteok; /* whether site is valid */
|
|
static Obj **favs; /* current list of loaded favorite objects */
|
|
static int nfavs; /* n favs[] */
|
|
static EObj *eobjs; /* malloced array of column info */
|
|
static int neobjs; /* number of object columns, always >= nfavs */
|
|
static int e_selecting; /* set while our fields are being selected */
|
|
|
|
/* handy ways to fiddle with TBs w/o invoking callbacks */
|
|
#define TBISON(w) XmToggleButtonGetState(w)
|
|
#define TBISOFF(w) (!TBISON(w))
|
|
#define TBOFF(w) XmToggleButtonSetState(w, False, False)
|
|
#define TBON(w) XmToggleButtonSetState(w, True, False)
|
|
|
|
/* constants that define details of various drawing actions */
|
|
#define WIDE_LW 1 /* wide line width */
|
|
#define NARROW_LW 0 /* narrow line width */
|
|
#define LINE_ST LineSolid /* line style for lines */
|
|
#define CAP_ST CapRound /* cap style for lines */
|
|
#define JOIN_ST JoinRound /* join style for lines */
|
|
#define CROSSH 1 /* drawcross code for a cross hair */
|
|
#define PLUSS 2 /* drawcross code for a plus sign */
|
|
#define PLLEN degrad(3) /* plussign arm radius, rads */
|
|
#define CHLEN degrad(1) /* cross hair leg length, rads */
|
|
#define LNGSTEP 15 /* longitude grid spacing, degrees */
|
|
#define LATSTEP 15 /* latitude grid spacing, degrees */
|
|
#define MAXPDIST 10 /* max screen pick distance, pixels */
|
|
#define CYLASPECT 2.0 /* cylndrical view w/h ratio */
|
|
#define TICKLN 2 /* length of tickmarks on trails */
|
|
#define MOVIE_SS (5./60) /* movie step size, hours */
|
|
#define MAXDW 1024 /* max dsp wdth, bewre large vir root */
|
|
#define MAXZOOM 6.0 /* max zoom, earth diams */
|
|
#define MINZOOM 0.05 /* min zoom, earth diams */
|
|
#define ZOOMSCALE 100 /* max zoom scale */
|
|
#define NORBSTEPS 256 /* number of orbit time steps */
|
|
#define SATSZ 5 /* sat marker size, pixels */
|
|
|
|
/* default trail definition */
|
|
static TrState defts = {
|
|
TRLR_2, TRI_5MIN, TRF_TIME, TRR_INTER, TRO_RIGHT, TRS_MEDIUM, 20
|
|
};
|
|
|
|
/* stuff for the weather ("wx") map gif
|
|
* N.B. we assume image is simple cyl proj, N up, 180 long at left, E to right
|
|
*/
|
|
static char wxhost[] = "www.ssec.wisc.edu";
|
|
static char wxfile[] = "/data/comp/latest_cmoll.gif";
|
|
#define WXM_W 640 /* overall gif width */
|
|
#define WXM_H 480 /* overall gif height */
|
|
#define WXM_LX 11 /* offset to left edge of map */
|
|
#define WXM_RX 629 /* offset to right edge of map */
|
|
#define WXM_TY 84 /* offset down to top of map */
|
|
#define WXM_BY 396 /* offset down to bottom of map */
|
|
static unsigned char *wxgifpix; /* malloced exploded gif pixel array */
|
|
static XColor wxxcols[256]; /* gif pixels and colors */
|
|
static Pixmap e_wxpm; /* off screen pixmap for wx map */
|
|
static Widget wxreload_w; /* PB to force reloading weather gif */
|
|
|
|
/* stuff for the surface maps */
|
|
static int deiw, deih; /* size of daytime image */
|
|
static unsigned char *deipix; /* malloced exploded daytime pixel array */
|
|
static XColor deixcols[256]; /* daytime colors */
|
|
static int neiw, neih; /* size of nighttime image */
|
|
static unsigned char *neipix; /* malloced exploded nighttime pixel array */
|
|
static XColor neixcols[256]; /* nighttime colors */
|
|
|
|
void
|
|
e_manage()
|
|
{
|
|
if (!eshell_w) {
|
|
/* first call: create and init view to main menu's loc.
|
|
* rely on an expose to do the drawing.
|
|
*/
|
|
Now *np = mm_get_now();
|
|
|
|
e_create_shell();
|
|
e_create_ctrl();
|
|
e_buildfavs();
|
|
e_setelatlng (lat, lng);
|
|
}
|
|
|
|
XtPopup (eshell_w, XtGrabNone);
|
|
set_something (eshell_w, XmNiconic, (XtArgVal)False);
|
|
|
|
setXRes (e_viewupres(), "1");
|
|
}
|
|
|
|
/* update the earth details.
|
|
* remove all trail history if any.
|
|
*/
|
|
void
|
|
e_update(np, force)
|
|
Now *np;
|
|
int force;
|
|
{
|
|
EObj *eop;
|
|
|
|
/* don't bother if we've never been created */
|
|
if (!eshell_w)
|
|
return;
|
|
|
|
/* put np in trail list as current (first) entry.
|
|
* discard trail info if not being shown.
|
|
*/
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++)
|
|
e_resettrail(eop, np, !TBISON(eop->showtr_w));
|
|
|
|
/* don't bother with map if we're not up now.
|
|
* still do stats though if anyone cares about our values.
|
|
*/
|
|
if (!isUp(eshell_w) && !force) {
|
|
if (any_ison())
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++)
|
|
e_show_esat_stats (eop);
|
|
return;
|
|
}
|
|
|
|
e_all (1);
|
|
}
|
|
|
|
/* called when basic resources change.
|
|
* rebuild and redraw.
|
|
*/
|
|
void
|
|
e_newres()
|
|
{
|
|
if (!eshell_w)
|
|
return;
|
|
e_init_gcs();
|
|
e_update (mm_get_now(), 1);
|
|
}
|
|
|
|
int
|
|
e_ison()
|
|
{
|
|
return (isUp(eshell_w));
|
|
}
|
|
|
|
/* called whenever the favorites list changes */
|
|
void
|
|
e_newfavs()
|
|
{
|
|
if (!eshell_w)
|
|
return;
|
|
|
|
/* rebuld rows */
|
|
e_buildfavs();
|
|
}
|
|
|
|
/* called whenever the db beyond the builtin objects has changed.
|
|
* if we've never been up or it was appended we don't have to do anything.
|
|
* if it shrunk, that means some of the fav pointers might be different
|
|
* so we rebuild the favorites list.
|
|
*/
|
|
void
|
|
e_newdb (appended)
|
|
int appended;
|
|
{
|
|
if (!eshell_w)
|
|
return;
|
|
|
|
/* rebuild rows */
|
|
e_buildfavs();
|
|
}
|
|
|
|
/* called by other menus as they want to hear from our buttons or not.
|
|
* the ons and offs stack.
|
|
*/
|
|
void
|
|
e_selection_mode (whether)
|
|
int whether;
|
|
{
|
|
if (whether)
|
|
e_selecting++;
|
|
else if (e_selecting > 0)
|
|
--e_selecting;
|
|
|
|
if (eshell_w)
|
|
if ((whether && e_selecting == 1) /* first one to want on */
|
|
|| (!whether && e_selecting == 0) /* first one to want off */)
|
|
e_set_buttons (whether);
|
|
}
|
|
|
|
void
|
|
e_cursor(c)
|
|
Cursor c;
|
|
{
|
|
Window win;
|
|
|
|
if (eshell_w && (win = XtWindow(eshell_w)) != 0) {
|
|
Display *dsp = XtDisplay(eshell_w);
|
|
if (c)
|
|
XDefineCursor(dsp, win, c);
|
|
else
|
|
XUndefineCursor(dsp, win);
|
|
}
|
|
|
|
if (ectrl_w && (win = XtWindow(ectrl_w)) != 0) {
|
|
Display *dsp = XtDisplay(ectrl_w);
|
|
if (c)
|
|
XDefineCursor(dsp, win, c);
|
|
else
|
|
XUndefineCursor(dsp, win);
|
|
}
|
|
}
|
|
|
|
/* return the name of the resource containing whether this view is up */
|
|
char *
|
|
e_viewupres()
|
|
{
|
|
return ("EarthViewUp");
|
|
}
|
|
|
|
/* create the main form.
|
|
* the earth stats form is created separately.
|
|
*/
|
|
static void
|
|
e_create_shell()
|
|
{
|
|
typedef struct {
|
|
char *label; /* what goes on the help label */
|
|
char *key; /* string to call hlp_dialog() */
|
|
} HelpOn;
|
|
static HelpOn helpon[] = {
|
|
{"Intro...", "Earth"},
|
|
{"on Mouse...", "Earth_mouse"},
|
|
{"on Control...", "Earth_control"},
|
|
{"on View...", "Earth_view"},
|
|
};
|
|
typedef struct {
|
|
char *name;
|
|
char *label;
|
|
void (*cb)();
|
|
int client;
|
|
Widget *wp;
|
|
char *tip;
|
|
} BtnInfo;
|
|
static BtnInfo ctl[] = {
|
|
{"EPrint", "Print...", e_print_cb, 0, NULL,
|
|
"Print the current Earth map"},
|
|
{"ECtrl", "Objects...", e_copen_cb, 0, NULL,
|
|
"Open window to define and overlay target Objects"},
|
|
{"EAnno", "User annotation...", ano_cb, 0, NULL,
|
|
"Open window to create and manage your own annotation"},
|
|
{"EMloop", "Add to movie...", e_mloop_cb, 0, NULL,
|
|
"Add scene to movie loop"},
|
|
{"Sep0"},
|
|
{"SetMain", "Set Main", e_setmain_cb, SET_MAIN, NULL,
|
|
"Set location in Main menu to the current center location"},
|
|
{"SetFrom", "Set from Main", e_setmain_cb, SET_FROM_MAIN, NULL,
|
|
"Set current center location to that of the Main menu"},
|
|
{"Animation", "Animation demo", e_anim_cb, 0, NULL,
|
|
"Start/Stop a fun time-lapse animation"},
|
|
{"Sep1"},
|
|
{"Close", "Close", e_close_cb, 0, NULL,
|
|
"Close this and all supporting dialogs"},
|
|
};
|
|
static BtnInfo view[] = {
|
|
{"grid", "Grid", e_tb_cb, GRID, NULL,
|
|
"Overlay map with Lat and Long grid spaced every 15 degrees"},
|
|
{"sites", "Sites", e_tb_cb, SITES, &sites_w,
|
|
"Mark each location in the Sites list on the map"},
|
|
{"sunlight", "Sunlight", e_tb_cb, SUNLIGHT, NULL,
|
|
"Draw the area currently in sunlight in a different color"},
|
|
{"mainmarker", "Main marker", e_tb_cb, MAINMARKER, NULL,
|
|
"Mark the location currently defined in the Main window"},
|
|
{"nightlights", "Nightside lights", e_tb_cb, NITELITES, NULL,
|
|
"Show NASA image of lights at night seen from space"},
|
|
{"livedrag", "Live dragging",e_tb_cb, LIVEDRAG, NULL,
|
|
"Update scene while dragging scales, not just when release"},
|
|
{"inertial", "Inertial frame", e_tb_cb, INERTIALF, &inertial_w,
|
|
"Maintain current inertial reference frame"},
|
|
};
|
|
Widget pd_w, cas_w, mb_w;
|
|
EventMask mask;
|
|
Widget fr_w, eform_w;
|
|
XmString str;
|
|
Widget w;
|
|
Arg args[20];
|
|
int n;
|
|
int i;
|
|
|
|
/* create shell and form */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNallowShellResize, True); n++;
|
|
XtSetArg (args[n], XmNtitle, "xephem Earth view"); n++;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNiconName, "Earth"); n++;
|
|
XtSetArg (args[n], XmNdeleteResponse, XmUNMAP); n++;
|
|
eshell_w = XtCreatePopupShell ("Earth", topLevelShellWidgetClass,
|
|
toplevel_w, args, n);
|
|
|
|
setup_icon (eshell_w);
|
|
set_something (eshell_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
XtAddCallback (eshell_w, XmNpopdownCallback, e_popdown_cb, 0);
|
|
sr_reg (eshell_w, "XEphem*Earth.width", earthcategory, 0);
|
|
sr_reg (eshell_w, "XEphem*Earth.height", earthcategory, 0);
|
|
sr_reg (eshell_w, "XEphem*Earth.x", earthcategory, 0);
|
|
sr_reg (eshell_w, "XEphem*Earth.y", earthcategory, 0);
|
|
sr_reg (NULL, e_viewupres(), earthcategory, 0);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNverticalSpacing, 2); n++;
|
|
XtSetArg (args[n], XmNhorizontalSpacing, 2); n++;
|
|
eform_w = XmCreateForm (eshell_w, "EarthForm", args, n);
|
|
XtAddCallback (eform_w, XmNhelpCallback, e_mhelp_cb, 0);
|
|
XtManageChild (eform_w);
|
|
|
|
/* make the menu bar and all its pulldowns */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
mb_w = XmCreateMenuBar (eform_w, "MB", args, n);
|
|
XtManageChild (mb_w);
|
|
|
|
/* make the Control pulldown */
|
|
|
|
n = 0;
|
|
pd_w = XmCreatePulldownMenu (mb_w, "ControlPD", args, n);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNsubMenuId, pd_w); n++;
|
|
XtSetArg (args[n], XmNmnemonic, 'C'); n++;
|
|
cas_w = XmCreateCascadeButton (mb_w, "ControlCB", args, n);
|
|
set_xmstring (cas_w, XmNlabelString, "Control");
|
|
XtManageChild (cas_w);
|
|
|
|
for (i = 0; i < XtNumber(ctl); i++) {
|
|
BtnInfo *bip = &ctl[i];
|
|
|
|
n = 0;
|
|
if (!bip->label)
|
|
w = XmCreateSeparator (pd_w, bip->name, args, n);
|
|
else {
|
|
if (bip->cb == e_mloop_cb)
|
|
n += ml_addacc (args, n);
|
|
w = XmCreatePushButton (pd_w, bip->name, args, n);
|
|
set_xmstring (w, XmNlabelString, bip->label);
|
|
XtAddCallback (w, XmNactivateCallback, bip->cb,
|
|
(XtPointer)(long int)bip->client);
|
|
}
|
|
if (bip->wp)
|
|
*bip->wp = w;
|
|
if (bip->tip)
|
|
wtip (w, bip->tip);
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* make the View pulldown */
|
|
|
|
n = 0;
|
|
pd_w = XmCreatePulldownMenu (mb_w, "ViewPD", args, n);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNsubMenuId, pd_w); n++;
|
|
XtSetArg (args[n], XmNmnemonic, 'V'); n++;
|
|
cas_w = XmCreateCascadeButton (mb_w, "ViewCB", args, n);
|
|
set_xmstring (cas_w, XmNlabelString, "View");
|
|
XtManageChild (cas_w);
|
|
|
|
/* simulate a radio box for the projection selections */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY); n++;
|
|
cylg_w = XmCreateToggleButton (pd_w, "cylGraphic", args, n);
|
|
set_xmstring (cylg_w, XmNlabelString, "Cyl graphic");
|
|
XtAddCallback (cylg_w, XmNvalueChangedCallback, e_proj_cb,
|
|
(XtPointer)CYLG);
|
|
wtip (cylg_w, "Display graphical map with cylindrical projection");
|
|
XtManageChild (cylg_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY); n++;
|
|
cyli_w = XmCreateToggleButton (pd_w, "cylImage", args, n);
|
|
set_xmstring (cyli_w, XmNlabelString, "Cyl image");
|
|
XtAddCallback (cyli_w, XmNvalueChangedCallback, e_proj_cb,
|
|
(XtPointer)CYLI);
|
|
wtip (cyli_w, "Display image map with cylindrical projection");
|
|
XtManageChild (cyli_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY); n++;
|
|
sphg_w = XmCreateToggleButton (pd_w, "sphGraphic", args, n);
|
|
set_xmstring (sphg_w, XmNlabelString, "Sph graphic");
|
|
XtAddCallback (sphg_w, XmNvalueChangedCallback, e_proj_cb,
|
|
(XtPointer)SPHG);
|
|
wtip (sphg_w, "Display graphical with using spherical projection");
|
|
XtManageChild (sphg_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY); n++;
|
|
sphi_w = XmCreateToggleButton (pd_w, "sphImage", args, n);
|
|
set_xmstring (sphi_w, XmNlabelString, "Sph image");
|
|
XtAddCallback (sphi_w, XmNvalueChangedCallback, e_proj_cb,
|
|
(XtPointer)SPHI);
|
|
wtip (sphi_w, "Display image map with spherical projection");
|
|
XtManageChild (sphi_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY); n++;
|
|
wxm_w = XmCreateToggleButton (pd_w, "wxmap", args, n);
|
|
set_xmstring (wxm_w, XmNlabelString, "Weather map");
|
|
XtAddCallback (wxm_w, XmNvalueChangedCallback, e_proj_cb,
|
|
(XtPointer)WXMAP);
|
|
wtip (wxm_w, "Display graphics over a live weather map");
|
|
XtManageChild (wxm_w);
|
|
|
|
n = 0;
|
|
wxreload_w = XmCreatePushButton (pd_w, "wxmap", args, n);
|
|
set_xmstring (wxreload_w, XmNlabelString, "Reload map");
|
|
XtAddCallback (wxreload_w, XmNactivateCallback, e_wxreload_cb, 0);
|
|
wtip (wxreload_w, "Force reloading weather map gif file");
|
|
/* N.B. defer managing */
|
|
|
|
sr_reg (cyli_w, NULL, earthcategory, 1);
|
|
sr_reg (cylg_w, NULL, earthcategory, 1);
|
|
sr_reg (sphi_w, NULL, earthcategory, 1);
|
|
sr_reg (sphg_w, NULL, earthcategory, 1);
|
|
sr_reg (wxm_w, NULL, earthcategory, 1);
|
|
|
|
n = 0;
|
|
w = XmCreateSeparator (pd_w, "Sep", args, n);
|
|
XtManageChild (w);
|
|
|
|
for (i = 0; i < XtNumber(view); i++) {
|
|
BtnInfo *bip = &view[i];
|
|
|
|
n = 0;
|
|
if (!bip->label)
|
|
w = XmCreateSeparator (pd_w, bip->name, args, n);
|
|
else {
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
w = XmCreateToggleButton (pd_w, bip->name, args, n);
|
|
wants[bip->client] = TBISON(w);
|
|
set_xmstring (w, XmNlabelString, bip->label);
|
|
XtAddCallback (w, XmNvalueChangedCallback, bip->cb,
|
|
(XtPointer)(long int)bip->client);
|
|
sr_reg (w, NULL, earthcategory, 1);
|
|
}
|
|
|
|
if (bip->wp)
|
|
*bip->wp = w;
|
|
if (bip->tip)
|
|
wtip (w, bip->tip);
|
|
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* confirm ok for Sites to be on */
|
|
if (wants[SITES] && sites_get_list(NULL) < 0) {
|
|
wants[SITES] = 0;
|
|
TBOFF (sites_w);
|
|
xe_msg (0, "No Sites File found.");
|
|
}
|
|
|
|
/* make the help pulldown */
|
|
|
|
n = 0;
|
|
pd_w = XmCreatePulldownMenu (mb_w, "HelpPD", args, n);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNsubMenuId, pd_w); n++;
|
|
XtSetArg (args[n], XmNmnemonic, 'H'); n++;
|
|
cas_w = XmCreateCascadeButton (mb_w, "HelpCB", args, n);
|
|
set_xmstring (cas_w, XmNlabelString, "Help");
|
|
XtManageChild (cas_w);
|
|
set_something (mb_w, XmNmenuHelpWidget, (XtArgVal)cas_w);
|
|
|
|
for (i = 0; i < XtNumber(helpon); i++) {
|
|
HelpOn *hp = &helpon[i];
|
|
|
|
str = XmStringCreate (hp->label, XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
w = XmCreatePushButton (pd_w, "Help", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, e_helpon_cb,
|
|
(XtPointer)(hp->key));
|
|
XtManageChild (w);
|
|
XmStringFree(str);
|
|
}
|
|
|
|
/* 0 lat PB */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
lat0_w = XmCreatePushButton (eform_w, "Lat0", args, n);
|
|
set_xmstring (lat0_w, XmNlabelString, "0:00");
|
|
XtAddCallback (lat0_w, XmNactivateCallback, e_lat0_cb, NULL);
|
|
wtip (lat0_w,"Set latitude to 0 (only active in Spherical projection)");
|
|
XtManageChild (lat0_w);
|
|
|
|
/* make the date/time indicator label */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNrightWidget, lat0_w); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
|
XtSetArg (args[n], XmNrecomputeSize, False); n++;
|
|
e_dt_w = XmCreateLabel (eform_w, "DTstamp", args, n);
|
|
wtip (e_dt_w, "Date and Time for which map is computed");
|
|
XtManageChild (e_dt_w);
|
|
|
|
/* make the zoom, long and lat scales */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNbottomWidget, lat0_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNminimum, -180); n++;
|
|
XtSetArg (args[n], XmNmaximum, 179); n++;
|
|
XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_LEFT); n++;
|
|
XtSetArg (args[n], XmNscaleMultiple, 1); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
XtSetArg (args[n], XmNshowValue, True); n++;
|
|
long_w = XmCreateScale (eform_w, "LongScale", args, n);
|
|
wtip (long_w, "Longitude control");
|
|
XtAddCallback (long_w, XmNvalueChangedCallback, e_latlong_cb, NULL);
|
|
XtAddCallback (long_w, XmNdragCallback, e_latlong_cb, NULL);
|
|
XtManageChild (long_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, mb_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNbottomWidget, long_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNminimum, 0); n++;
|
|
XtSetArg (args[n], XmNmaximum, ZOOMSCALE); n++;
|
|
XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
|
|
XtSetArg (args[n], XmNscaleMultiple, 1); n++;
|
|
XtSetArg (args[n], XmNorientation, XmVERTICAL); n++;
|
|
XtSetArg (args[n], XmNshowValue, False); n++;
|
|
zoom_w = XmCreateScale (eform_w, "ZoomScale", args, n);
|
|
wtip (zoom_w, "Zoom control");
|
|
sr_reg (zoom_w, NULL, earthcategory, 0);
|
|
XtAddCallback (zoom_w, XmNvalueChangedCallback, e_latlong_cb, NULL);
|
|
XtAddCallback (zoom_w, XmNdragCallback, e_latlong_cb, NULL);
|
|
XtManageChild (zoom_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, mb_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNbottomWidget, long_w); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNminimum, -90); n++;
|
|
XtSetArg (args[n], XmNmaximum, 90); n++;
|
|
XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
|
|
XtSetArg (args[n], XmNscaleMultiple, 1); n++;
|
|
XtSetArg (args[n], XmNorientation, XmVERTICAL); n++;
|
|
XtSetArg (args[n], XmNshowValue, True); n++;
|
|
lat_w = XmCreateScale (eform_w, "LatScale", args, n);
|
|
wtip (lat_w, "Latitude control (only active in Spherical projection)");
|
|
XtAddCallback (lat_w, XmNvalueChangedCallback, e_latlong_cb, NULL);
|
|
XtAddCallback (lat_w, XmNdragCallback, e_latlong_cb, NULL);
|
|
XtManageChild (lat_w);
|
|
|
|
/* make a drawing area on top */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, mb_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNbottomWidget, long_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNleftWidget, zoom_w); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNrightWidget, lat_w); n++;
|
|
fr_w = XmCreateFrame (eform_w, "MFr", args, n);
|
|
XtManageChild (fr_w);
|
|
|
|
n = 0;
|
|
e_da_w = XmCreateDrawingArea (fr_w, "EarthMap", args, n);
|
|
XtAddCallback (e_da_w, XmNexposeCallback, e_exp_cb, NULL);
|
|
mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask
|
|
| EnterWindowMask | LeaveWindowMask;
|
|
XtAddEventHandler (e_da_w, mask, False, e_motion_eh, 0);
|
|
XtManageChild (e_da_w);
|
|
|
|
/* init da's size */
|
|
(void) e_set_dasize();
|
|
|
|
/* register trail resource and init setup */
|
|
sr_reg (NULL, etrres, earthcategory, 0);
|
|
tr_getres (etrres, &defts);
|
|
|
|
/* if projection not unique, set default to spherical view */
|
|
i = 0;
|
|
i += TBISON(cylg_w) ? 1 : 0;
|
|
i += TBISON(cyli_w) ? 1 : 0;
|
|
i += TBISON(sphg_w) ? 1 : 0;
|
|
i += TBISON(sphi_w) ? 1 : 0;
|
|
i += TBISON(wxm_w) ? 1 : 0;
|
|
if (i != 1) {
|
|
xe_msg (0, "Earth projection conflict -- forcing Sph graphic");
|
|
TBOFF (cylg_w);
|
|
TBOFF (cyli_w);
|
|
TBON (sphg_w);
|
|
TBOFF (sphi_w);
|
|
TBOFF (wxm_w);
|
|
}
|
|
|
|
/* init projection info */
|
|
if (TBISON(cylg_w)) {
|
|
projection = CYLG;
|
|
XtSetSensitive (lat_w, False);
|
|
XtSetSensitive (lat0_w, False);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, False);
|
|
XtUnmanageChild (wxreload_w);
|
|
} else if (TBISON(cyli_w)) {
|
|
projection = CYLI;
|
|
XtSetSensitive (lat_w, False);
|
|
XtSetSensitive (lat0_w, False);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, False);
|
|
XtUnmanageChild (wxreload_w);
|
|
} else if (TBISON(sphg_w)) {
|
|
projection = SPHG;
|
|
XtSetSensitive (lat_w, True);
|
|
XtSetSensitive (lat0_w, True);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, True);
|
|
XtUnmanageChild (wxreload_w);
|
|
} else if (TBISON(sphi_w)) {
|
|
projection = SPHI;
|
|
XtSetSensitive (lat_w, True);
|
|
XtSetSensitive (lat0_w, True);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, True);
|
|
XtUnmanageChild (wxreload_w);
|
|
} else {
|
|
projection = WXMAP;
|
|
XtSetSensitive (lat_w, False);
|
|
XtSetSensitive (lat0_w, False);
|
|
XtSetSensitive (long_w, False);
|
|
XtSetSensitive (zoom_w, False);
|
|
XtManageChild (wxreload_w);
|
|
}
|
|
}
|
|
|
|
/* make the object control dialog -- real work is in e_buildfavs() */
|
|
static void
|
|
e_create_ctrl()
|
|
{
|
|
Arg args[20];
|
|
Widget sep_w;
|
|
Widget eform_w;
|
|
Widget w;
|
|
int n;
|
|
int i;
|
|
|
|
/* create shell and form */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNallowShellResize, True); n++;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNtitle, "xephem Earth objects"); n++;
|
|
XtSetArg (args[n], XmNiconName, "EObjs"); n++;
|
|
XtSetArg (args[n], XmNdeleteResponse, XmUNMAP); n++;
|
|
ectrl_w = XtCreatePopupShell ("EarthObjs", topLevelShellWidgetClass,
|
|
toplevel_w, args, n);
|
|
setup_icon (ectrl_w);
|
|
set_something (ectrl_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
sr_reg (ectrl_w, "XEphem*EarthObjs.x", earthcategory, 0);
|
|
sr_reg (ectrl_w, "XEphem*EarthObjs.y", earthcategory, 0);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNmarginHeight, 5); n++;
|
|
XtSetArg (args[n], XmNmarginWidth, 5); n++;
|
|
XtSetArg (args[n], XmNhorizontalSpacing, 5); n++;
|
|
XtSetArg (args[n], XmNverticalSpacing, 5); n++;
|
|
XtSetArg (args[n], XmNautoUnmanage, False); n++;
|
|
eform_w = XmCreateForm (ectrl_w, "EOForm", args, n);
|
|
XtAddCallback (eform_w, XmNhelpCallback, e_chelp_cb, 0);
|
|
XtManageChild (eform_w);
|
|
|
|
/* make one big hor RC table to hold each column */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNpacking, XmPACK_TIGHT); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
XtSetArg (args[n], XmNisAligned, False); n++;
|
|
XtSetArg (args[n], XmNadjustMargin, False); n++;
|
|
objrc_w = XmCreateRowColumn (eform_w, "EMH", args, n);
|
|
XtManageChild(objrc_w);
|
|
|
|
/* one RC for each column, first entry is heading label */
|
|
|
|
for (i = 0; i < XtNumber(rhd); i++) {
|
|
n = 0;
|
|
XtSetArg (args[n], XmNpacking, XmPACK_TIGHT); n++;
|
|
XtSetArg (args[n], XmNorientation, XmVERTICAL); n++;
|
|
XtSetArg (args[n], XmNisAligned, False); n++;
|
|
XtSetArg (args[n], XmNadjustMargin, False); n++;
|
|
w = XmCreateRowColumn (objrc_w, "EVC", args, n);
|
|
XtManageChild (w);
|
|
rhd[i].col_w = w;
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
|
w = XmCreatePushButton (rhd[i].col_w, "ECBL", args, n);
|
|
set_xmstring (w, XmNlabelString, rhd[i].label);
|
|
wtip (w, rhd[i].tip);
|
|
if (rhd[i].cb) {
|
|
XtAddCallback (w, XmNactivateCallback, rhd[i].cb, NULL);
|
|
buttonAsButton (w, 1);
|
|
} else
|
|
buttonAsButton (w, 0);
|
|
XtManageChild (w);
|
|
|
|
/* save the labels for the headers that change */
|
|
if (rhd[i].l_wp)
|
|
*rhd[i].l_wp = w;
|
|
}
|
|
|
|
/* add a separator at bottom */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, objrc_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
sep_w = XmCreateSeparator (eform_w, "Sep", args, n);
|
|
XtManageChild (sep_w);
|
|
|
|
/* add a label for the current date/time stamp */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, sep_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
|
XtSetArg (args[n], XmNrecomputeSize, False); n++;
|
|
e_cdt_w = XmCreateLabel (eform_w, "SDTstamp", args, n);
|
|
wtip (e_cdt_w, "Date and Time for which data are computed");
|
|
XtManageChild (e_cdt_w);
|
|
|
|
/* add a close button */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, e_cdt_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 30); n++;
|
|
w = XmCreatePushButton (eform_w, "Close", args, n);
|
|
wtip (w, "Close this window");
|
|
XtAddCallback (w, XmNactivateCallback, e_cclose_cb, 0);
|
|
XtManageChild (w);
|
|
|
|
/* add web update button */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, e_cdt_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 40); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 60); n++;
|
|
w = XmCreatePushButton (eform_w, "Close", args, n);
|
|
set_xmstring (w, XmNlabelString, "Web update ...");
|
|
wtip (w, "Update Earth satellites from web");
|
|
XtAddCallback (w, XmNactivateCallback, e_webupdate_cb, 0);
|
|
XtManageChild (w);
|
|
|
|
/* add a Help button */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, e_cdt_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 70); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 90); n++;
|
|
w = XmCreatePushButton (eform_w, "Help", args, n);
|
|
wtip (w, "Get more info about this window");
|
|
XtAddCallback (w, XmNactivateCallback, e_chelp_cb, 0);
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* return a unique number between 0 and 1 for every non-neg value of i.
|
|
* arrange for them to move along ever finer binary steps.
|
|
*/
|
|
static double
|
|
binsplit (int i)
|
|
{
|
|
/* 1-based */
|
|
double oneb = i + 1;
|
|
|
|
/* divide into base power of two parts */
|
|
double ndiv = pow (2.0, floor(log(oneb)/log(2.0)));
|
|
|
|
/* add remainder, divide last evenly on both ends */
|
|
return ((0.5 + oneb - ndiv)/ndiv);
|
|
}
|
|
|
|
/* set up one "row" in objrc for each favorite..
|
|
* this means one row in each column.
|
|
* remember the first row is just the col headers so leave it alone.
|
|
* preserve existing entries based on same name.
|
|
*/
|
|
static void
|
|
e_buildfavs()
|
|
{
|
|
Arg args[20];
|
|
Widget w;
|
|
EObj *eop;
|
|
int i, n;
|
|
char *rowname;
|
|
|
|
/* get current set of favorites and columns */
|
|
nfavs = fav_get_loaded (&favs);
|
|
|
|
/* insure one row for each fav in each col and one EObj to match */
|
|
for (i = 0; i < nfavs; i++) {
|
|
if (i >= neobjs) {
|
|
/* create another row and its EObj */
|
|
|
|
double r, g, b;
|
|
XColor xc;
|
|
|
|
eobjs = (EObj*) XtRealloc((char*)eobjs,(neobjs+1)*sizeof(EObj));
|
|
eop = &eobjs[neobjs++];
|
|
memset (eop, 0, sizeof(*eop));
|
|
|
|
/* init mem for selecting names */
|
|
|
|
eop->slat_pn = XtCalloc (PNL, 1);
|
|
eop->slng_pn = XtCalloc (PNL, 1);
|
|
eop->el_pn = XtCalloc (PNL, 1);
|
|
eop->range_pn = XtCalloc (PNL, 1);
|
|
eop->rrate_pn = XtCalloc (PNL, 1);
|
|
eop->sun_pn = XtCalloc (PNL, 1);
|
|
eop->age_pn = XtCalloc (PNL, 1);
|
|
|
|
/* init trail options */
|
|
|
|
eop->trstate = defts;
|
|
|
|
/* pick a color */
|
|
|
|
toRGB (1-binsplit (i), 1.0, 1.0, &r, &g, &b);
|
|
xc.red = (int)(r*65535);
|
|
xc.green = (int)(g*65535);
|
|
xc.blue = (int)(b*65535);
|
|
if (XAllocColor (XtD, xe_cm, &xc))
|
|
eop->pix = xc.pixel;
|
|
else
|
|
eop->pix = WhitePixel (XtD, DefaultScreen(XtD));
|
|
|
|
/* label for row name (really a PB just to match size) */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
eop->name_w = XmCreatePushButton (rhd[0].col_w, "EN", args, n);
|
|
buttonAsButton (eop->name_w, 0);
|
|
XtManageChild (eop->name_w);
|
|
|
|
/* whether to display object at all */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNshadowThickness, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNselectColor, (XtArgVal)eop->pix); n++;
|
|
XtSetArg (args[n], XmNfillOnSelect, (XtArgVal)True); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rhd[1].col_w, "OTB", args, n);
|
|
XtAddCallback (w, XmNvalueChangedCallback, e_show_cb,
|
|
(XtPointer)(long int)i);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
XtManageChild (w);
|
|
eop->show_w = w;
|
|
|
|
/* whether to show Label */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNshadowThickness, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rhd[2].col_w, "LblTB", args, n);
|
|
XtAddCallback (w, XmNvalueChangedCallback, e_wantlbl_cb,
|
|
(XtPointer)(long int)i);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
XtManageChild (w);
|
|
eop->wantlbl_w = w;
|
|
|
|
/* whether to show footprint */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNshadowThickness, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rhd[3].col_w, "FootTB", args, n);
|
|
XtAddCallback (w, XmNvalueChangedCallback, e_wantfoot_cb,
|
|
(XtPointer)(long int)i);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
XtManageChild (w);
|
|
eop->wantfoot_w = w;
|
|
|
|
/* whether to show orbit ... */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNshadowThickness, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rhd[4].col_w, "OrbitTB", args, n);
|
|
XtAddCallback (w, XmNvalueChangedCallback, e_wantorb_cb,
|
|
(XtPointer)(long int)i);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
eop->wantorb_w = w;
|
|
|
|
/* .. or spacer when not appropriate */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (rhd[4].col_w, "OrbitLbl", args, n);
|
|
buttonAsButton (w, 0);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
eop->wantnoorb_w = w;
|
|
|
|
/* whether to show Trail */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNshadowThickness, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rhd[5].col_w, "TrailTB", args, n);
|
|
XtAddCallback (w, XmNvalueChangedCallback, e_trail_cb,
|
|
(XtPointer)(long int)i);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
XtManageChild (w);
|
|
eop->showtr_w = w;
|
|
|
|
/* whether to Track */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNshadowThickness, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rhd[6].col_w, "TrackTB", args, n);
|
|
XtAddCallback (w, XmNvalueChangedCallback, e_ontrack_cb,
|
|
(XtPointer)(long int)i);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
XtManageChild (w);
|
|
eop->track_w = w;
|
|
|
|
/* whether to use as popup reference */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNshadowThickness, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmONE_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rhd[7].col_w, "MTB", args, n);
|
|
XtAddCallback (w, XmNvalueChangedCallback, e_onpick_cb,
|
|
(XtPointer)(long int)i);
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
XtManageChild (w);
|
|
eop->pick_w = w;
|
|
|
|
/* label to show SubLat */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
w = XmCreatePushButton (rhd[8].col_w, "LatTB", args, n);
|
|
set_something (w, XmNuserData, (XtArgVal)eop->slat_pn);
|
|
XtAddCallback (w, XmNactivateCallback, e_stat_cb, (XtPointer)(long int)i);
|
|
XtManageChild (w);
|
|
eop->slat_w = w;
|
|
|
|
/* lable to show SubLong */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
w = XmCreatePushButton (rhd[9].col_w, "LngTB", args, n);
|
|
set_something (w, XmNuserData, (XtArgVal)eop->slng_pn);
|
|
XtAddCallback (w, XmNactivateCallback, e_stat_cb, (XtPointer)(long int)i);
|
|
XtManageChild (w);
|
|
eop->slng_w = w;
|
|
|
|
/* label to show Alt */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
w = XmCreatePushButton (rhd[10].col_w, "AltTB", args, n);
|
|
set_something (w, XmNuserData, (XtArgVal)eop->el_pn);
|
|
XtAddCallback (w, XmNactivateCallback, e_stat_cb, (XtPointer)(long int)i);
|
|
XtManageChild (w);
|
|
eop->el_w = w;
|
|
|
|
/* label to show Range */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
w = XmCreatePushButton (rhd[11].col_w, "RanTB", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, e_stat_cb, (XtPointer)(long int)i);
|
|
set_something(w, XmNuserData, (XtArgVal)eop->range_pn);
|
|
XtManageChild (w);
|
|
eop->range_w = w;
|
|
|
|
/* label to show Range Rate */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
w = XmCreatePushButton (rhd[12].col_w, "RRTB", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, e_stat_cb, (XtPointer)(long int)i);
|
|
set_something(w, XmNuserData, (XtArgVal)eop->rrate_pn);
|
|
XtManageChild (w);
|
|
eop->rrate_w = w;
|
|
|
|
/* label to show whether in Sun light */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
w = XmCreatePushButton (rhd[13].col_w, "SunTB", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, e_stat_cb, (XtPointer)(long int)i);
|
|
set_something (w, XmNuserData, (XtArgVal)eop->sun_pn);
|
|
XtManageChild (w);
|
|
eop->sun_w = w;
|
|
|
|
/* label to show elements Age */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
w = XmCreatePushButton (rhd[14].col_w, "AgeTB", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, e_stat_cb, (XtPointer)(long int)i);
|
|
set_something (w, XmNuserData, (XtArgVal)eop->age_pn);
|
|
XtManageChild (w);
|
|
eop->age_w = w;
|
|
|
|
/* probably not look like buttons yet */
|
|
|
|
e_set_buttons(e_selecting);
|
|
}
|
|
|
|
/* build row, preserve controls if same name */
|
|
|
|
eop = &eobjs[i];
|
|
eop->op = favs[i];
|
|
|
|
get_xmstring (eop->name_w, XmNlabelString, &rowname);
|
|
if (strcmp (rowname, favs[i]->o_name)) {
|
|
set_xmstring (eop->name_w, XmNlabelString, favs[i]->o_name);
|
|
TBOFF (eop->show_w);
|
|
TBOFF (eop->wantlbl_w);
|
|
TBOFF (eop->wantfoot_w);
|
|
TBOFF (eop->wantorb_w);
|
|
TBOFF (eop->showtr_w);
|
|
TBOFF (eop->track_w);
|
|
TBOFF (eop->pick_w);
|
|
}
|
|
XtFree (rowname);
|
|
|
|
XtManageChild (eop->name_w);
|
|
|
|
XtManageChild (eop->show_w);
|
|
|
|
XtManageChild (eop->wantlbl_w);
|
|
|
|
XtManageChild (eop->wantfoot_w);
|
|
|
|
if (is_type (eop->op, EARTHSATM)) {
|
|
XtManageChild (eop->wantorb_w);
|
|
XtUnmanageChild (eop->wantnoorb_w);
|
|
} else {
|
|
XtUnmanageChild (eop->wantorb_w);
|
|
XtManageChild (eop->wantnoorb_w);
|
|
}
|
|
|
|
XtManageChild (eop->showtr_w);
|
|
|
|
XtManageChild (eop->track_w);
|
|
|
|
XtManageChild (eop->pick_w);
|
|
|
|
sprintf (eop->slat_pn, "%s.SatSubLat", favs[i]->o_name);
|
|
XtManageChild (eop->slat_w);
|
|
|
|
sprintf (eop->slng_pn, "%s.SatSubLong", favs[i]->o_name);
|
|
XtManageChild (eop->slng_w);
|
|
|
|
sprintf (eop->el_pn, "%s.SatAlt", favs[i]->o_name);
|
|
XtManageChild (eop->el_w);
|
|
|
|
sprintf (eop->range_pn, "%s.SatRange", favs[i]->o_name);
|
|
XtManageChild (eop->range_w);
|
|
|
|
sprintf (eop->rrate_pn, "%s.SatRangeR", favs[i]->o_name);
|
|
XtManageChild (eop->rrate_w);
|
|
|
|
sprintf (eop->sun_pn, "%s.SatSunlit", favs[i]->o_name);
|
|
XtManageChild (eop->sun_w);
|
|
|
|
sprintf (eop->age_pn, "%s.SatAge", favs[i]->o_name);
|
|
XtManageChild (eop->age_w);
|
|
}
|
|
|
|
/* turn off any remaining rows */
|
|
for ( ; i < neobjs; i++) {
|
|
eop = &eobjs[i];
|
|
eop->op = NULL;
|
|
XtUnmanageChild (eop->name_w);
|
|
XtUnmanageChild (eop->show_w);
|
|
XtUnmanageChild (eop->wantlbl_w);
|
|
XtUnmanageChild (eop->wantfoot_w);
|
|
XtUnmanageChild (eop->wantorb_w);
|
|
XtUnmanageChild (eop->wantnoorb_w);
|
|
XtUnmanageChild (eop->showtr_w);
|
|
XtUnmanageChild (eop->track_w);
|
|
XtUnmanageChild (eop->pick_w);
|
|
XtUnmanageChild (eop->slat_w);
|
|
XtUnmanageChild (eop->slng_w);
|
|
XtUnmanageChild (eop->el_w);
|
|
XtUnmanageChild (eop->range_w);
|
|
XtUnmanageChild (eop->rrate_w);
|
|
XtUnmanageChild (eop->sun_w);
|
|
XtUnmanageChild (eop->age_w);
|
|
}
|
|
|
|
/* fill in current values */
|
|
e_update (mm_get_now(), 1);
|
|
}
|
|
|
|
/* callback when any of the stat buttons are activated. */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_stat_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
if (e_selecting) {
|
|
char *userD;
|
|
|
|
get_something (w, XmNuserData, (XtArgVal)&userD);
|
|
register_selection (userD);
|
|
}
|
|
}
|
|
|
|
/* callback when the main form in popped down */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_popdown_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XtPopdown(ectrl_w);
|
|
|
|
if (e_pm) {
|
|
XFreePixmap (XtDisplay(w), e_pm);
|
|
e_pm = (Pixmap) 0;
|
|
}
|
|
|
|
/* leave e_wxpm since it can take a while to reload */
|
|
|
|
/* stop movie that might be running */
|
|
mm_movie (0.0);
|
|
|
|
/* record we are now down */
|
|
setXRes (e_viewupres(), "0");
|
|
}
|
|
|
|
/* callback for when the main Close button is activated */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_close_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
/* let popdown to the real work */
|
|
XtPopdown (eshell_w);
|
|
}
|
|
|
|
/* callback for when the control dialog is closed */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_cclose_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XtPopdown (ectrl_w);
|
|
}
|
|
|
|
/* callback to bring up web update window */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_webupdate_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
wdb_manage();
|
|
}
|
|
|
|
/* callback when a Track TB is changed.
|
|
* client is index into eobjs[]
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_ontrack_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
EObj *eop = &eobjs[(long int)client];
|
|
|
|
/* do nothing if turning off */
|
|
if (!TBISON(w))
|
|
return;
|
|
|
|
/* insure shown as a friendly gesture */
|
|
TBON(eop->show_w);
|
|
eop->shownbefore = 1;
|
|
|
|
/* turn off others to simulate a radio box */
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++)
|
|
if (w != eop->track_w && TBISON(eop->track_w))
|
|
TBOFF (eop->track_w);
|
|
|
|
/* turn off INERTIAL */
|
|
if (wants[INERTIALF]) {
|
|
TBOFF (inertial_w);
|
|
wants[INERTIALF] = 0;
|
|
}
|
|
|
|
/* redraw to reorient */
|
|
e_all(1);
|
|
}
|
|
|
|
/* callback when a Pick TB is changed.
|
|
* client is index into eobjs[]
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_onpick_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
EObj *eop;
|
|
|
|
/* if turning this one on, turn off others to simulate a radio box */
|
|
if (TBISON(w))
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++)
|
|
if (w != eop->pick_w)
|
|
TBOFF (eop->pick_w);
|
|
}
|
|
|
|
/* callback when a Show TB is changed.
|
|
* client is index into eobjs[]
|
|
* N.B. logic is duplicated in e_showtgl_cb
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_show_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
EObj *eop = &eobjs[(long int)client];
|
|
|
|
/* courtesies */
|
|
if (TBISON(w)) {
|
|
if (!eop->shownbefore) {
|
|
TBON(eop->wantfoot_w);
|
|
TBON(eop->wantlbl_w);
|
|
TBON(eop->wantorb_w);
|
|
eop->shownbefore = 1;
|
|
}
|
|
} else {
|
|
TBOFF (eop->track_w);
|
|
TBOFF (eop->pick_w);
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* callback when a Label TB is changed.
|
|
* client is index into eobjs[]
|
|
* N.B. logic is duplicated in e_wantlbltgl_cb
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_wantlbl_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
/* if coming on, show as a courtesy */
|
|
if (TBISON(w)) {
|
|
TBON (eobjs[(long int)client].show_w);
|
|
eobjs[(long int)client].shownbefore = 1;
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* callback when a Footprint TB is changed.
|
|
* client is index into eobjs[]
|
|
* N.B. logic is duplicated in e_wantfoottgl_cb
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_wantfoot_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
/* if coming on, show as a courtesy */
|
|
if (TBISON(w)) {
|
|
TBON (eobjs[(long int)client].show_w);
|
|
eobjs[(long int)client].shownbefore = 1;
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* callback when an orbit TB is changed.
|
|
* client is index into eobjs[]
|
|
* N.B. logic is duplicated in e_wantorbtgl_cb
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_wantorb_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
/* if coming on, show as a courtesy */
|
|
if (TBISON(w)) {
|
|
TBON (eobjs[(long int)client].show_w);
|
|
eobjs[(long int)client].shownbefore = 1;
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* callback for when the Movie button is activated. */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_anim_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
mm_movie (MOVIE_SS);
|
|
}
|
|
|
|
/* callback to add scene to movie loop */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_mloop_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
ml_add (e_pm, e_dt_w);
|
|
}
|
|
|
|
/* go through all the buttons and set whether they
|
|
* should appear to look like buttons or just flat labels.
|
|
*/
|
|
static void
|
|
e_set_buttons (whether)
|
|
int whether; /* whether setting up for plotting or for not plotting */
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < neobjs; i++) {
|
|
EObj *eop = eobjs + i;
|
|
buttonAsButton (eop->slat_w, whether);
|
|
buttonAsButton (eop->slng_w, whether);
|
|
buttonAsButton (eop->el_w, whether);
|
|
buttonAsButton (eop->range_w, whether);
|
|
buttonAsButton (eop->rrate_w, whether);
|
|
buttonAsButton (eop->sun_w, whether);
|
|
buttonAsButton (eop->age_w, whether);
|
|
}
|
|
}
|
|
|
|
/* callback from the main Help all button
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_mhelp_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
static char *msg[] = {
|
|
"This is a simple schematic depiction of the Earth surface at the given time.",
|
|
"The view shows the sunlit portion and the location of any object.",
|
|
};
|
|
|
|
hlp_dialog ("Earth", msg, XtNumber(msg));
|
|
}
|
|
|
|
/* callback from the Control Help all button
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_chelp_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
static char *msg[] = {
|
|
"Controls which objects are displayed and their current stats"
|
|
};
|
|
|
|
hlp_dialog ("Earth_control_dialog", msg, XtNumber(msg));
|
|
}
|
|
|
|
/* callback from a specific Help button.
|
|
* client is a string to use with hlp_dialog().
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_helpon_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
hlp_dialog ((char *)client, NULL, 0);
|
|
}
|
|
|
|
/* callback from Print control.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_print_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XPSAsk ("Earth", e_print);
|
|
}
|
|
|
|
/* proceed to generate a postscript file.
|
|
* call XPSClose() when finished.
|
|
*/
|
|
static void
|
|
e_print ()
|
|
{
|
|
Now *np = mm_get_now();
|
|
int w, h, d, wb, hb;
|
|
|
|
if (!e_ison()) {
|
|
xe_msg (1, "Earth must be open to save a file.");
|
|
XPSClose();
|
|
return;
|
|
}
|
|
|
|
watch_cursor(1);
|
|
|
|
/* get size of the rendering area */
|
|
e_getcircle (&w, &h, &d, &wb, &hb);
|
|
|
|
/* draw in an area 6.5w x 6.5h centered 1in down from top */
|
|
if (w >= h)
|
|
XPSXBegin (e_pm, 0, 0, w, h, 1*72, 10*72, (int)(6.5*72));
|
|
else {
|
|
int pw = (int)(72*6.5*w/h+.5); /* width on paper when 6.5 hi */
|
|
XPSXBegin (e_pm, 0, 0, w, h, (int)((8.5*72-pw)/2), 10*72, pw);
|
|
}
|
|
|
|
/* redraw */
|
|
e_map (np);
|
|
|
|
/* no more X captures */
|
|
XPSXEnd();
|
|
|
|
/* add some extra info */
|
|
e_ps_annotate (np);
|
|
|
|
/* finished */
|
|
XPSClose();
|
|
|
|
watch_cursor(0);
|
|
}
|
|
|
|
static void
|
|
e_ps_annotate (np)
|
|
Now *np;
|
|
{
|
|
int unitspref = pref_get (PREF_UNITS);
|
|
double sslat, sslong;
|
|
char buf[32], buf2[32];
|
|
char dir[128];
|
|
EObj *eop;
|
|
int hdr;
|
|
int r, y;
|
|
|
|
/* scroll up by number of favs to show */
|
|
r = 11;
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++)
|
|
if (TBISON(eop->show_w))
|
|
r++;
|
|
|
|
/* title */
|
|
y = AROWY(r);
|
|
(void) sprintf (dir, "(XEphem %s Earth View) 306 %d cstr\n",
|
|
projection == CYLG ? "Cylindrical graphic" :
|
|
projection == CYLI ? "Cylindrical image" :
|
|
projection == SPHG ? "Spherical graphic" :
|
|
projection == SPHI ? "Spherical image" :
|
|
"Weather Map", y);
|
|
XPSDirect (dir);
|
|
|
|
/* date, time, jd */
|
|
y = AROWY(r -= 2);
|
|
fs_time (buf, mjd_hr(mjd));
|
|
fs_date (buf2, pref_get(PREF_DATE_FORMAT), mjd_day(mjd));
|
|
(void) sprintf (dir, "(UTC:) 144 %d rstr (%s %s) 154 %d lstr\n",
|
|
y, buf, buf2, y);
|
|
XPSDirect (dir);
|
|
(void) sprintf (dir,"(JD:) 410 %d rstr (%13.5f) 420 %d lstr\n", y,
|
|
mjd+MJD0, y);
|
|
XPSDirect (dir);
|
|
|
|
/* map center, subsolar loc */
|
|
y = AROWY(--r);
|
|
e_ps_ll ("Map Center", elat, elng, 144, y);
|
|
e_subobject (np, db_basic(SUN), &sslat, &sslong);
|
|
e_ps_ll ("SubSolar", sslat, sslong, 410, y);
|
|
|
|
/* marker, if on */
|
|
if (wants[MAINMARKER]) {
|
|
char *site = mm_getsite();
|
|
y = AROWY(--r);
|
|
e_ps_ll ("Reference", lat, lng, 144, y);
|
|
if (site) {
|
|
sprintf (dir,"(, %s) show\n", XPSCleanStr(site,strlen(site)));
|
|
XPSDirect (dir);
|
|
}
|
|
}
|
|
|
|
/* info about Targets that are shown */
|
|
hdr = 0;
|
|
r--;
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++) {
|
|
if (TBISON(eop->show_w)) {
|
|
Trail *tp = &eop->trail[0];
|
|
Obj *op = &tp->t_obj;
|
|
|
|
y = AROWY(--r);
|
|
|
|
if (!hdr) {
|
|
int yup = AROWY(r+1);
|
|
|
|
sprintf (dir, "(SubLat/Long) 200 %d cstr\n", y);
|
|
XPSDirect(dir);
|
|
sprintf (dir, "(Sun) 285 %d cstr\n", y);
|
|
XPSDirect(dir);
|
|
sprintf (dir, "(Ref Alt/Az) 360 %d cstr\n", y);
|
|
XPSDirect(dir);
|
|
|
|
sprintf (dir, "(Alt) 418 %d cstr (%s) 418 %d cstr\n", yup,
|
|
unitspref == PREF_ENGLISH ? "mi" : "km", y);
|
|
XPSDirect(dir);
|
|
sprintf (dir, "(Range) 450 %d cstr (%s) 450 %d cstr\n", yup,
|
|
unitspref == PREF_ENGLISH ? "mi" : "km", y);
|
|
XPSDirect(dir);
|
|
sprintf (dir, "(Range') 488 %d cstr (%s) 488 %d cstr\n",yup,
|
|
unitspref == PREF_ENGLISH ? "f/s" : "m/s", y);
|
|
XPSDirect(dir);
|
|
sprintf (dir, "(Age) 525 %d cstr (days) 525 %d cstr\n",
|
|
yup, y);
|
|
XPSDirect(dir);
|
|
hdr = 1;
|
|
|
|
y = AROWY(--r);
|
|
}
|
|
|
|
e_ps_ll (op->o_name, tp->t_sublat, tp->t_sublng, 144, y);
|
|
|
|
sprintf (dir, "(%s) 280 %d lstr\n", op->o_type == EARTHSAT
|
|
? (op->s_eclipsed ? " N" : " Y")
|
|
: "", y);
|
|
XPSDirect (dir);
|
|
|
|
fs_sexa (buf, raddeg(op->s_alt), 3, 3600);
|
|
fs_sexa (buf2, raddeg(op->s_az), 4, 3600);
|
|
sprintf (dir, "(%s %s) 395 %d rstr\n", buf, buf2, y);
|
|
XPSDirect (dir);
|
|
|
|
if (op->o_type == EARTHSAT) {
|
|
double tmp;
|
|
|
|
if (unitspref == PREF_ENGLISH)
|
|
tmp = op->s_elev*FTPM/5280.0;
|
|
else
|
|
tmp = op->s_elev/1000.0;
|
|
sprintf (dir, "( %5.0f) 425 %d rstr\n", tmp, y);
|
|
XPSDirect (dir);
|
|
|
|
if (unitspref == PREF_ENGLISH)
|
|
tmp = op->s_range*FTPM/5280.0;
|
|
else
|
|
tmp = op->s_range/1000.0;
|
|
sprintf (dir, "( %5.0f) 462 %d rstr\n", tmp, y);
|
|
XPSDirect (dir);
|
|
|
|
if (unitspref == PREF_ENGLISH)
|
|
tmp = op->s_rangev*FTPM;
|
|
else
|
|
tmp = op->s_rangev;
|
|
sprintf (dir, "( %5.0f) 500 %d rstr\n", tmp, y);
|
|
XPSDirect (dir);
|
|
|
|
tmp = mjd - op->es_epoch;
|
|
sprintf (dir, "( %5.2f) 535 %d rstr\n", tmp, y);
|
|
XPSDirect (dir);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* label print with center lat/long */
|
|
static void
|
|
e_ps_ll (tag, lt, lg, x, y)
|
|
char *tag;
|
|
double lt, lg;
|
|
int x, y;
|
|
{
|
|
char ltstr[32], lgstr[32];
|
|
char buf[128];
|
|
|
|
fs_sexa (ltstr, raddeg(fabs(lt)), 3, 3600);
|
|
(void) strcat (ltstr, lt < 0 ? " S" : " N");
|
|
|
|
fs_sexa (lgstr, raddeg(fabs(lg)), 4, 3600);
|
|
(void) strcat (lgstr, lg < 0 ? " W" : " E");
|
|
|
|
(void) sprintf (buf, "(%s:) %d %d rstr (%s %s) %d %d lstr\n",
|
|
tag, x, y, ltstr, lgstr, x+10, y);
|
|
XPSDirect (buf);
|
|
}
|
|
|
|
/* called whenever the earth drawing area gets an expose.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_exp_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
static unsigned last_wid, last_hei;
|
|
XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
|
|
Display *dsp = XtDisplay(w);
|
|
Window win = XtWindow(w);
|
|
Window root;
|
|
int x, y;
|
|
unsigned int bw, d;
|
|
unsigned wid, hei;
|
|
|
|
/* 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 int before;
|
|
XExposeEvent *e = &c->event->xexpose;
|
|
|
|
if (!before) {
|
|
XSetWindowAttributes swa;
|
|
unsigned long mask = CWBitGravity | CWBackingStore;
|
|
|
|
swa.bit_gravity = ForgetGravity;
|
|
swa.backing_store = NotUseful;
|
|
XChangeWindowAttributes (e->display, e->window, mask, &swa);
|
|
before = 1;
|
|
}
|
|
|
|
/* wait for the last in the series */
|
|
if (e->count != 0)
|
|
return;
|
|
break;
|
|
}
|
|
default:
|
|
printf ("Unexpected eshell_w event. type=%d\n", c->reason);
|
|
abort();
|
|
}
|
|
|
|
XGetGeometry (dsp, win, &root, &x, &y, &wid, &hei, &bw, &d);
|
|
|
|
|
|
/* if no pixmap or we're a new size then (re)build everything */
|
|
if (!e_pm || wid != last_wid || hei != last_hei) {
|
|
if (e_pm)
|
|
XFreePixmap (dsp, e_pm);
|
|
|
|
if (!e_gc)
|
|
e_init_gcs();
|
|
|
|
e_pm = XCreatePixmap (dsp, win, wid, hei, d);
|
|
XSetForeground (dsp, e_gc, e_bg);
|
|
XFillRectangle (dsp, e_pm, e_gc, 0, 0, wid, hei);
|
|
last_wid = wid;
|
|
last_hei = hei;
|
|
|
|
e_all(1);
|
|
} else {
|
|
/* nothing new so just copy from the pixmap */
|
|
e_copy_pm();
|
|
}
|
|
}
|
|
|
|
/* called on receipt of a MotionNotify or ButtonPress or ButtonRelease event.
|
|
* button 1 shows great circle from Main site.
|
|
* button 2 causes rotation, if LIVEDRAG;
|
|
* button 3 causes a popup.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_motion_eh (w, client, ev, continue_to_dispatch)
|
|
Widget w;
|
|
XtPointer client;
|
|
XEvent *ev;
|
|
Boolean *continue_to_dispatch;
|
|
{
|
|
static int inwin;
|
|
Display *dsp = XtDisplay(w);
|
|
Window win = XtWindow(w);
|
|
int evt = ev->type;
|
|
int mo = evt == MotionNotify;
|
|
int bp = evt == ButtonPress;
|
|
int br = evt == ButtonRelease;
|
|
int en = evt == EnterNotify;
|
|
int lv = evt == LeaveNotify;
|
|
int b3p = bp && ev->xbutton.button == Button3;
|
|
int b2p = bp && ev->xbutton.button == Button2;
|
|
int b2r = br && ev->xbutton.button == Button2;
|
|
int b1r = br && ev->xbutton.button == Button1;
|
|
int m2 = mo && ev->xmotion.state & Button2Mask;
|
|
int m1 = mo && ev->xmotion.state & Button1Mask;
|
|
int wide, h, d, xb, yb;
|
|
Window root, child;
|
|
double lt, lg;
|
|
int rx, ry, wx, wy;
|
|
int overearth;
|
|
unsigned mask;
|
|
|
|
if (en) inwin = 1;
|
|
if (lv) inwin = 0;
|
|
|
|
XQueryPointer (dsp, win, &root, &child, &rx, &ry, &wx, &wy, &mask);
|
|
e_getcircle (&wide, &h, &d, &xb, &yb);
|
|
overearth = e_uncoord (projection, d, xb, yb, wx, wy, <, &lg);
|
|
|
|
if (m1 && overearth)
|
|
e_plotGreatCircle (d, xb, yb, lt, lg);
|
|
if (b1r)
|
|
e_map(mm_get_now());
|
|
|
|
if (b3p)
|
|
e_popup (w, ev, d, xb, yb, wx, wy);
|
|
|
|
if ((b2p || m2) && wants[LIVEDRAG] && projection != WXMAP) {
|
|
static int lastx, lasty;
|
|
double lt, lg;
|
|
|
|
/* if first time turn off any tracking and change cursor */
|
|
if (b2p) {
|
|
noTrack();
|
|
lastx = wx;
|
|
lasty = wy;
|
|
XDefineCursor (dsp, win, XCreateFontCursor (dsp, XC_fleur));
|
|
}
|
|
|
|
/* update based on motion */
|
|
lg = elng - PI*(wx - lastx)/d;
|
|
lt = elat - PI*(lasty - wy)/d;
|
|
if (lt > PI/2)
|
|
lt = PI/2;
|
|
else if (lt < -PI/2)
|
|
lt = -PI/2;
|
|
lastx = wx;
|
|
lasty = wy;
|
|
e_setelatlng (lt, lg);
|
|
|
|
/* site code is certainly voided */
|
|
refsiteok = 0;
|
|
|
|
/* redraw */
|
|
e_all (0);
|
|
}
|
|
|
|
if (b2r)
|
|
XUndefineCursor(dsp, win);
|
|
|
|
if (overearth && !m2 && !b1r) /* flashes badly while dragging */
|
|
e_track_latlng (w, d, xb, yb, lt, lg);
|
|
else if (e_pm) /* under a pulldown we can get called after popdown */
|
|
e_copy_pm();
|
|
}
|
|
|
|
/* called when any of the option toggle buttons changes state.
|
|
* client is one of the Wants enum.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_tb_cb (wid, client, call)
|
|
Widget wid;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
int state = TBISON (wid);
|
|
int want = (long int) client;
|
|
int w, h, d, wb, hb;
|
|
|
|
watch_cursor (1);
|
|
|
|
/* set option to new value */
|
|
wants[want] = state;
|
|
|
|
/* prepare for graphics */
|
|
e_getcircle (&w, &h, &d, &wb, &hb);
|
|
|
|
/* generally we draw just what we need if turning on, everything if off.
|
|
* this is faster than e_all but can lead to a different overlay order.
|
|
*/
|
|
switch (want) {
|
|
case GRID:
|
|
if (state) {
|
|
e_drawgrid (d, wb, hb);
|
|
e_copy_pm();
|
|
} else
|
|
e_all (0);
|
|
break;
|
|
|
|
case SITES:
|
|
if (state) {
|
|
if (sites_get_list(NULL) < 0) {
|
|
wants[SITES] = 0;
|
|
TBOFF (sites_w);
|
|
xe_msg (1, "No Sites file found.");
|
|
} else {
|
|
e_drawsites (d, wb, hb);
|
|
e_copy_pm();
|
|
}
|
|
} else
|
|
e_all (0);
|
|
break;
|
|
|
|
case SUNLIGHT:
|
|
if (projection != WXMAP || e_setupwxpm(0, 1) == 0)
|
|
e_all (0);
|
|
|
|
case NITELITES:
|
|
if (projection != WXMAP || e_setupwxpm(0, 1) == 0)
|
|
e_all (0);
|
|
|
|
case LIVEDRAG:
|
|
break; /* enough to just record it */
|
|
|
|
case INERTIALF:
|
|
if (state) {
|
|
/* capture current ra/dec overhead */
|
|
ll2rd (elat, elng, &ira, &idec);
|
|
/* turn off any tracking */
|
|
noTrack();
|
|
}
|
|
break;
|
|
|
|
case MAINMARKER:
|
|
if (state) {
|
|
e_mainmenuloc (mm_get_now(), d, wb, hb);
|
|
e_copy_pm();
|
|
} else
|
|
e_all (0);
|
|
break;
|
|
|
|
default:
|
|
printf ("e_tb_cb: bad client: %d\n", want);
|
|
abort();
|
|
}
|
|
|
|
watch_cursor (0);
|
|
}
|
|
|
|
/* called to open the object control window */
|
|
/* ARGSUSED */
|
|
static void
|
|
e_copen_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
e_set_buttons(e_selecting);
|
|
XtPopup (ectrl_w, XtGrabNone);
|
|
set_something (ectrl_w, XmNiconic, (XtArgVal)False);
|
|
|
|
}
|
|
|
|
/* called when a Trail PB is activated.
|
|
* client is eobjs[] index.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_trail_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
EObj *eop = &eobjs[(long int)client];
|
|
|
|
if (TBISOFF(w)) {
|
|
/* erase, if anything to erase */
|
|
if (eop->ntrail > 1)
|
|
e_all(0);
|
|
} else {
|
|
/* turning on trail.. insure shown too as a friendly gesture */
|
|
if (TBISOFF(eop->show_w)) {
|
|
TBON(eop->show_w);
|
|
eop->shownbefore = 1;
|
|
}
|
|
|
|
/* allow to define if none */
|
|
if (eop->ntrail <= 1)
|
|
tr_setup ("xephem Earth Trail setup",
|
|
eop->trail[0].t_obj.o_name, &eop->trstate, e_mktrail,
|
|
(XtPointer)client);
|
|
|
|
/* show */
|
|
e_all(0);
|
|
}
|
|
}
|
|
|
|
/* called to toggle all buttons in the Show column.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_showtgl_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < neobjs; i++) {
|
|
EObj *eop = &eobjs[i];
|
|
|
|
if (TBISON(eop->show_w))
|
|
TBOFF (eop->show_w);
|
|
else
|
|
TBON (eop->show_w);
|
|
|
|
/* duplicate e_show_cb() but without e_all() */
|
|
if (TBISON(eop->show_w)) {
|
|
if (!eop->shownbefore) {
|
|
TBON(eop->wantfoot_w);
|
|
TBON(eop->wantlbl_w);
|
|
eop->shownbefore = 1;
|
|
}
|
|
} else {
|
|
TBOFF (eop->track_w);
|
|
TBOFF (eop->pick_w);
|
|
}
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* called to toggle all buttons in the Label column.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_wantlbltgl_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < neobjs; i++) {
|
|
EObj *eop = &eobjs[i];
|
|
|
|
if (TBISON(eop->wantlbl_w))
|
|
TBOFF (eop->wantlbl_w);
|
|
else
|
|
TBON (eop->wantlbl_w);
|
|
|
|
/* duplicate e_wantlbl_cb() but without e_all() */
|
|
if (TBISON(eop->wantlbl_w)) {
|
|
TBON (eop->show_w);
|
|
eop->shownbefore = 1;
|
|
}
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* called to toggle all buttons in the Foot Print column.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_wantfoottgl_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < neobjs; i++) {
|
|
EObj *eop = &eobjs[i];
|
|
|
|
if (TBISON(eop->wantfoot_w))
|
|
TBOFF (eop->wantfoot_w);
|
|
else
|
|
TBON (eop->wantfoot_w);
|
|
|
|
/* duplicate e_wantfoot_cb() but without e_all() */
|
|
if (TBISON(eop->wantfoot_w)) {
|
|
TBON (eop->show_w);
|
|
eop->shownbefore = 1;
|
|
}
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* called to toggle all buttons in the Orbit column.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_wantorbtgl_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < neobjs; i++) {
|
|
EObj *eop = &eobjs[i];
|
|
|
|
if (TBISON(eop->wantorb_w))
|
|
TBOFF (eop->wantorb_w);
|
|
else
|
|
TBON (eop->wantorb_w);
|
|
|
|
/* duplicate e_wantorb_cb() but without e_all() */
|
|
if (TBISON(eop->wantorb_w)) {
|
|
TBON (eop->show_w);
|
|
eop->shownbefore = 1;
|
|
}
|
|
}
|
|
|
|
e_all(0);
|
|
}
|
|
|
|
/* called when the Reload weather map PB is pressed.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_wxreload_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
if (e_setupwxpm(1, 1) == 0)
|
|
e_all (0);
|
|
}
|
|
|
|
/* called when any projection button changes state.
|
|
* client will be one of Proj.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_proj_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
Proj newproj = (Proj)client;
|
|
|
|
switch (newproj) {
|
|
case CYLG:
|
|
TBON (cylg_w);
|
|
TBOFF (cyli_w);
|
|
TBOFF (sphg_w);
|
|
TBOFF (sphi_w);
|
|
TBOFF (wxm_w);
|
|
XtSetSensitive (lat_w, False);
|
|
XtSetSensitive (lat0_w, False);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, False);
|
|
XtUnmanageChild (wxreload_w);
|
|
projection = newproj;
|
|
break;
|
|
|
|
case CYLI:
|
|
TBOFF (cylg_w);
|
|
TBON (cyli_w);
|
|
TBOFF (sphg_w);
|
|
TBOFF (sphi_w);
|
|
TBOFF (wxm_w);
|
|
XtSetSensitive (lat_w, False);
|
|
XtSetSensitive (lat0_w, False);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, False);
|
|
XtUnmanageChild (wxreload_w);
|
|
projection = newproj;
|
|
break;
|
|
|
|
case SPHG:
|
|
TBOFF (cylg_w);
|
|
TBOFF (cyli_w);
|
|
TBON (sphg_w);
|
|
TBOFF (sphi_w);
|
|
TBOFF (wxm_w);
|
|
XtSetSensitive (lat_w, True);
|
|
XtSetSensitive (lat0_w, True);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, True);
|
|
XtUnmanageChild (wxreload_w);
|
|
projection = newproj;
|
|
break;
|
|
|
|
case SPHI:
|
|
TBOFF (cylg_w);
|
|
TBOFF (cyli_w);
|
|
TBOFF (sphg_w);
|
|
TBON (sphi_w);
|
|
TBOFF (wxm_w);
|
|
XtSetSensitive (lat_w, True);
|
|
XtSetSensitive (lat0_w, True);
|
|
XtSetSensitive (long_w, True);
|
|
XtSetSensitive (zoom_w, True);
|
|
XtUnmanageChild (wxreload_w);
|
|
projection = newproj;
|
|
break;
|
|
|
|
case WXMAP:
|
|
if (e_setupwxpm(0, 0) == 0) {
|
|
TBOFF (cylg_w);
|
|
TBOFF (sphg_w);
|
|
TBON (wxm_w);
|
|
XtSetSensitive (lat_w, False);
|
|
XtSetSensitive (lat0_w, False);
|
|
XtSetSensitive (long_w, False);
|
|
XtSetSensitive (zoom_w, False);
|
|
XtManageChild (wxreload_w);
|
|
projection = newproj;
|
|
} else
|
|
TBOFF (wxm_w);
|
|
break;
|
|
}
|
|
|
|
/* recompute the new size.
|
|
* if no change we call e_all() else leave it up to the expose.
|
|
*/
|
|
if (e_set_dasize() == 0)
|
|
e_all (0);
|
|
}
|
|
|
|
/* adjust the size of e_da_w for the current projection, if necessary.
|
|
* return 1 if the size really does change, else 0.
|
|
*/
|
|
static int
|
|
e_set_dasize()
|
|
{
|
|
Dimension nwid = 0, nhei = 0;
|
|
Dimension wid, hei;
|
|
int maxw;
|
|
Position x;
|
|
Arg args[10];
|
|
int n;
|
|
|
|
/* get max width, beware huge virtual screen size */
|
|
maxw = DisplayWidth(XtD, DefaultScreen(XtD));
|
|
if (maxw > MAXDW)
|
|
maxw = MAXDW;
|
|
maxw = 9*maxw/10;
|
|
|
|
/* get drawing area size now */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNwidth, (XtArgVal)&wid); n++;
|
|
XtSetArg (args[n], XmNheight, (XtArgVal)&hei); n++;
|
|
XtGetValues (e_da_w, args, n);
|
|
|
|
/* get shell position */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNx, (XtArgVal)&x); n++;
|
|
XtGetValues (eshell_w, args, n);
|
|
|
|
/* change set nwid/hei to achieve desired aspect ratio, but never
|
|
* wider than screen.
|
|
*/
|
|
switch (projection) {
|
|
case SPHG: /* FALLTHRU */
|
|
case SPHI:
|
|
/* 1:1 */
|
|
nhei = nwid = hei;
|
|
break;
|
|
|
|
case CYLG: /* FALLTHRU */
|
|
case CYLI:
|
|
/* CYLASPECT:1 */
|
|
nhei = hei;
|
|
nwid = (Dimension)(hei*CYLASPECT + 0.5);
|
|
if (nwid > maxw) {
|
|
nwid = maxw;
|
|
nhei = (Dimension)(nwid/CYLASPECT + 0.5);
|
|
}
|
|
break;
|
|
|
|
case WXMAP:
|
|
/* force size to fit map */
|
|
nhei = WXM_H;
|
|
nwid = WXM_W;
|
|
break;
|
|
}
|
|
|
|
/* react if either changed */
|
|
if (nwid != wid || nhei != hei) {
|
|
/* change both at once to disuade multiple exposures */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNwidth, (XtArgVal)nwid); n++;
|
|
XtSetArg (args[n], XmNheight, (XtArgVal)nhei); n++;
|
|
XtSetValues (e_da_w, args, n);
|
|
|
|
/* reposition if necessary to fit on screen */
|
|
if (x + nwid > maxw) {
|
|
x = maxw - nwid + 10;
|
|
n = 0;
|
|
XtSetArg (args[n], XmNx, x); n++;
|
|
XtSetValues (eshell_w, args, n);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* called when Set Main or Set from Main is activated.
|
|
* client is set to SET_MAIN or SET_FROM_MAIN.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_setmain_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
Now *np = mm_get_now();
|
|
int which = (long int)client;
|
|
|
|
switch (which) {
|
|
case SET_MAIN:
|
|
if (refsiteok)
|
|
mm_setsite (&refsite, 1);
|
|
else
|
|
mm_setll (elat, elng, 1);
|
|
break;
|
|
case SET_FROM_MAIN:
|
|
e_setelatlng (lat, lng);
|
|
noTrack();
|
|
e_all (0);
|
|
break;
|
|
default:
|
|
printf ("e_setmain_cb: Bad client: %d\n", which);
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/* called when either the longitude or latitude scale moves.
|
|
* doesn't matter which -- just update pointing direction and redraw.
|
|
* as a convenience, also insure tracking is off now.
|
|
* also forget any remembered refsites name.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_latlong_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XmScaleCallbackStruct *s = (XmScaleCallbackStruct *)call;
|
|
|
|
if (wants[LIVEDRAG] || s->reason == XmCR_VALUE_CHANGED) {
|
|
int lt, lg;
|
|
|
|
XmScaleGetValue (lat_w, <);
|
|
XmScaleGetValue (long_w, &lg);
|
|
e_setelatlng (degrad(lt), degrad(-lg)); /*want +E but scale is +W */
|
|
|
|
/* manually sliding lat or long certainly voids a valid site code */
|
|
refsiteok = 0;
|
|
|
|
noTrack();
|
|
|
|
e_all (0);
|
|
}
|
|
}
|
|
|
|
/* called to force latitude = 0.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_lat0_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
int lg;
|
|
|
|
XmScaleGetValue (long_w, &lg);
|
|
e_setelatlng (0.0, degrad(-lg)); /*want +E but scale is +W */
|
|
|
|
refsiteok = 0;
|
|
|
|
noTrack();
|
|
|
|
e_all (0);
|
|
}
|
|
|
|
/* called when the Point button is selected on the roaming popup.
|
|
* get the details from pu_info.
|
|
* center the point of view to point_lt/point_lg.
|
|
* as a convenience, also turn off tracking.
|
|
* save the site info, if there was one with this pick.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_point_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
e_setelatlng (pu_info.pu_lt, pu_info.pu_lg);
|
|
noTrack();
|
|
if ((refsiteok = !!pu_info.pu_sp)) /* might be NULL */
|
|
refsite = *pu_info.pu_sp;
|
|
e_all (0);
|
|
}
|
|
|
|
/* make all the GCs, define all the e_*pix pixels and set the XFontStruct e_f
|
|
* we get the color names and save the pixels in the global ecolors[] arrary.
|
|
*/
|
|
static void
|
|
e_init_gcs ()
|
|
{
|
|
Display *dsp = XtDisplay (e_da_w);
|
|
Window win = XtWindow (e_da_w);
|
|
unsigned long gcm;
|
|
XGCValues gcv;
|
|
Pixel fg, p;
|
|
int i;
|
|
|
|
/* just in case we are not up yet */
|
|
if (!win)
|
|
return;
|
|
|
|
/* create the main gc.
|
|
* it's GCForeground is set each time it's used.
|
|
*/
|
|
gcm = GCFunction;
|
|
gcv.function = GXcopy;
|
|
e_gc = XCreateGC (dsp, win, gcm, &gcv);
|
|
|
|
/* get the foreground and background colors */
|
|
get_something (e_da_w, XmNforeground, (XtArgVal)&fg);
|
|
get_color_resource (e_da_w, "EarthBackground", &e_bg);
|
|
|
|
/* collect all the Earth color resources */
|
|
for (i = 0; i < XtNumber(ecolors); i++) {
|
|
EColor *ecp = &ecolors[i];
|
|
(void) get_color_resource (e_da_w, ecp->name, &ecp->p);
|
|
}
|
|
|
|
/* make the overlay gc, e_olgc */
|
|
/* got all the colors -- overlay can just be drawn directly */
|
|
gcm = GCFunction;
|
|
gcv.function = GXcopy;
|
|
e_olgc = XCreateGC (dsp, win, gcm, &gcv);
|
|
|
|
/* make the lat/long string gc and get's it's font */
|
|
|
|
gcm = GCForeground | GCBackground | GCFont;
|
|
get_something (e_dt_w, XmNforeground, (XtArgVal)&p);
|
|
gcv.foreground = p;
|
|
gcv.background = e_bg;
|
|
get_tracking_font (dsp, &e_f);
|
|
gcv.font = e_f->fid;
|
|
e_strgc = XCreateGC (dsp, win, gcm, &gcv);
|
|
}
|
|
|
|
/* copy the pixmap e_pm to the window of e_da_w. */
|
|
static void
|
|
e_copy_pm()
|
|
{
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
Window win = XtWindow(e_da_w);
|
|
int w, h, r, wb, hb;
|
|
|
|
e_getcircle (&w, &h, &r, &wb, &hb);
|
|
XCopyArea (dsp, e_pm, win, e_gc, 0, 0, w, h, 0, 0);
|
|
}
|
|
|
|
/* right button has been hit: find the closest thing to x/y and display what we
|
|
* know about it. if nothing is very close, at least show the lat/long.
|
|
* always give the choice to point to the spot.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
e_popup (wid, ev, d, xb, yb, x, y)
|
|
Widget wid;
|
|
XEvent *ev;
|
|
unsigned d;
|
|
unsigned xb, yb;
|
|
int x, y;
|
|
{
|
|
Now *np = mm_get_now();
|
|
int mind = 10000000; /* min pick dist so far */
|
|
Site *minsip = NULL; /* closest site so far */
|
|
Trail *mintp = NULL; /* closest trail or orbit so far */
|
|
double lmt; /* local mean time: UT - radhr(lng) */
|
|
double gst, lst; /* Greenich and local sidereal times */
|
|
double lt, lg;
|
|
Trail *tp;
|
|
EObj *eop;
|
|
char buf[128];
|
|
Widget w;
|
|
int i, nl;
|
|
|
|
/* admit we might be busy for a while */
|
|
watch_cursor (1);
|
|
|
|
/* make the popup if this is our first time */
|
|
if (!pu_info.pu_w)
|
|
e_create_popup();
|
|
|
|
/* find the closest site in minsip, if sites are enabled */
|
|
if (wants[SITES]) {
|
|
Site *sipa;
|
|
int nsa;
|
|
|
|
for (nsa = sites_get_list(&sipa); --nsa >= 0; ) {
|
|
Site *sip = &sipa[nsa];
|
|
short sx, sy;
|
|
|
|
if (e_coord (d, xb, yb, sip->si_lat, sip->si_lng, &sx, &sy)) {
|
|
int md = abs(sx-x) + abs(sy-y);
|
|
if (md < mind) {
|
|
minsip = sip;
|
|
mind = md;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* now check object positions, including any trail markers and orbits,
|
|
* for anything closer still. if so, put it in mintp.
|
|
* remember: the object in its current position is also on trail[].
|
|
*/
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++) {
|
|
if (TBISOFF(eop->show_w))
|
|
continue;
|
|
for (tp = eop->trail; tp && tp < &eop->trail[eop->ntrail]; tp++) {
|
|
if (tp->lvis) {
|
|
int md = abs(tp->lx-x) + abs(tp->ly-y);
|
|
if (md < mind) {
|
|
mintp = tp;
|
|
mind = md;
|
|
}
|
|
}
|
|
}
|
|
if (eop->ovis) {
|
|
int md = abs(eop->ox-x) + abs(eop->oy-y);
|
|
if (md < mind) {
|
|
mintp = &eop->trail[0];
|
|
mind = md;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* build the popup */
|
|
|
|
/* first unmanage all the labels -- we'll turn on what we want */
|
|
for (i = 0; i < MAXPUL; i++)
|
|
XtUnmanageChild (pu_info.pu_labels[i]);
|
|
nl = 0;
|
|
|
|
/* assume no sites entry for now */
|
|
pu_info.pu_sp = NULL;
|
|
|
|
if (mind <= MAXPDIST) {
|
|
/* found something, question is: a trailed object or a site?
|
|
* check them in the opposite order than which they were searched.
|
|
*/
|
|
if (mintp) {
|
|
double tzo = pref_get(PREF_ZONE)==PREF_LOCALTZ ? -tz/24.0 : 0;
|
|
Obj *op = &mintp->t_obj;
|
|
|
|
/* a trail item was closest.
|
|
* put the name, time, lat and lng in the popup.
|
|
*/
|
|
w = pu_info.pu_labels[nl++];
|
|
set_xmstring (w, XmNlabelString, mintp->t_obj.o_name);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Date: ");
|
|
fs_date (buf+strlen(buf), pref_get(PREF_DATE_FORMAT),
|
|
mjd_day(mintp->t_now.n_mjd+tzo));
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Time: ");
|
|
fs_time (buf+strlen(buf), mjd_hr(mintp->t_now.n_mjd+tzo));
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
if (pref_get (PREF_UNITS) == PREF_ENGLISH)
|
|
sprintf (buf, "Alt: %.0f mi", op->s_elev*FTPM/5280.);
|
|
else
|
|
sprintf (buf, "Alt: %.0f km", op->s_elev/1000.);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
if (pref_get (PREF_UNITS) == PREF_ENGLISH)
|
|
sprintf (buf, "Range: %.0f mi", op->s_range*FTPM/5280.);
|
|
else
|
|
sprintf (buf, "Range: %.0f km", op->s_range/1000.);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Sub Lat: ");
|
|
fs_dms_angle (buf+strlen(buf), mintp->t_sublat);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Sub Long: ");
|
|
fs_dms_angle (buf+strlen(buf), -mintp->t_sublng); /* want +W */
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
if (is_type(&mintp->t_obj,EARTHSATM)) {
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Sunlit: %s",
|
|
mintp->t_obj.s_eclipsed ? "No" : "Yes");
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* save lat/long for Point and if want to display alt/az */
|
|
pu_info.pu_lt = mintp->t_sublat;
|
|
pu_info.pu_lg = mintp->t_sublng;
|
|
} else if (minsip) {
|
|
/* a site entry was closest.
|
|
* put it's name, lat/long and alt/az in the popup.
|
|
*/
|
|
double dist, bear;
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
set_xmstring (w, XmNlabelString, minsip->si_name);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "LMT: ");
|
|
lmt = mjd_hr(mjd) + radhr(minsip->si_lng);
|
|
range (&lmt, 24.0);
|
|
fs_time (buf+strlen(buf), lmt);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "LST: ");
|
|
utc_gst (mjd_day(mjd), mjd_hr(mjd), &gst);
|
|
lst = gst + radhr(minsip->si_lng);
|
|
range (&lst, 24.0);
|
|
fs_time (buf+strlen(buf), lst);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Lat: ");
|
|
fs_dms_angle (buf+strlen(buf), minsip->si_lat);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Long: ");
|
|
fs_dms_angle (buf+strlen(buf), -minsip->si_lng); /* want +W */
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
e_greatCircle (minsip->si_lat, minsip->si_lng, &dist, &bear);
|
|
w = pu_info.pu_labels[nl++];
|
|
if (pref_get (PREF_UNITS) == PREF_ENGLISH)
|
|
(void) sprintf (buf, "Dist: %.1f mi", dist*0.62137119e-3);
|
|
else
|
|
(void) sprintf (buf, "Dist: %.1f km", dist*1e-3);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Bearing: ");
|
|
fs_dms_angle (buf+strlen(buf), bear);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
/* save lat/long for Point and if want to display alt/az */
|
|
pu_info.pu_lt = minsip->si_lat;
|
|
pu_info.pu_lg = minsip->si_lng;
|
|
|
|
/* now we have site info too */
|
|
pu_info.pu_sp = minsip;
|
|
} else {
|
|
printf ("e_popup: unknown closest! mind = %d\n", mind);
|
|
abort();
|
|
}
|
|
} else {
|
|
/* nothing was close enough.
|
|
* just put the lat/long and alt/az of the cursor loc in the popup.
|
|
* if not over the earth, forget it.
|
|
*/
|
|
double dist, bear;
|
|
|
|
if (!e_uncoord (projection, d, xb, yb, x, y, <, &lg)) {
|
|
watch_cursor(0);
|
|
return;
|
|
}
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "LMT: ");
|
|
lmt = mjd_hr(mjd) + radhr(lg);
|
|
range (&lmt, 24.0);
|
|
fs_time (buf+strlen(buf), lmt);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "LST: ");
|
|
utc_gst (mjd_day(mjd), mjd_hr(mjd), &gst);
|
|
lst = gst + radhr(lg);
|
|
range (&lst, 24.0);
|
|
fs_time (buf+strlen(buf), lst);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Lat: ");
|
|
fs_dms_angle (buf+strlen(buf), lt);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Long: ");
|
|
fs_dms_angle (buf+strlen(buf), -lg); /* want +W */
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
e_greatCircle (lt, lg, &dist, &bear);
|
|
w = pu_info.pu_labels[nl++];
|
|
if (pref_get (PREF_UNITS) == PREF_ENGLISH)
|
|
(void) sprintf (buf, "Dist: %.1f mi", dist*0.62137119e-3);
|
|
else
|
|
(void) sprintf (buf, "Dist: %.1f km", dist*1e-3);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "Bearing: ");
|
|
fs_dms_angle (buf+strlen(buf), bear);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
/* save lat/long for Point and if want to display alt/az */
|
|
pu_info.pu_lt = lt;
|
|
pu_info.pu_lg = lg;
|
|
|
|
/* signal no trail found for pick_w work */
|
|
mintp = NULL;
|
|
}
|
|
|
|
/* unless we found a trail entry, show alt/az of pick_w object (if any)
|
|
*/
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++)
|
|
if (TBISON(eop->pick_w))
|
|
break;
|
|
if (!mintp && eop < &eobjs[nfavs]) {
|
|
Now now_here; /* temp Now */
|
|
Obj obj_here; /* temp Obj */
|
|
|
|
(void) memcpy ((void *)&now_here, (void *)&eop->trail[0].t_now,
|
|
sizeof (Now));
|
|
now_here.n_lat = pu_info.pu_lt;
|
|
now_here.n_lng = pu_info.pu_lg;
|
|
(void) memcpy ((void *)&obj_here, (void *)&eop->trail[0].t_obj,
|
|
sizeof (Obj));
|
|
(void) obj_cir (&now_here, &obj_here);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "%s Alt: ", obj_here.o_name);
|
|
fs_pangle (buf+strlen(buf), obj_here.s_alt);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
|
|
w = pu_info.pu_labels[nl++];
|
|
(void) sprintf (buf, "%s Az: ", obj_here.o_name);
|
|
fs_pangle (buf+strlen(buf), obj_here.s_az);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
XtManageChild (w);
|
|
}
|
|
|
|
if (nl > MAXPUL) {
|
|
printf ("Too many earth popup labels: %d of %d\n", nl, MAXPUL);
|
|
abort();
|
|
}
|
|
|
|
XmMenuPosition (pu_info.pu_w, (XButtonPressedEvent *)ev);
|
|
XtManageChild (pu_info.pu_w);
|
|
|
|
watch_cursor(0);
|
|
}
|
|
|
|
/* create the popup
|
|
* save all its widgets in the pu_info struct.
|
|
*/
|
|
static void
|
|
e_create_popup()
|
|
{
|
|
Widget w;
|
|
Arg args[20];
|
|
int n;
|
|
int i;
|
|
|
|
/* make the popup shell which includes a handy row/column */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNisAligned, True); n++;
|
|
XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
|
|
pu_info.pu_w = XmCreatePopupMenu (e_da_w, "EPopup", args, n);
|
|
|
|
/* add the max labels we'll ever need -- all unmanaged for now. */
|
|
for (i = 0; i < MAXPUL; i++) {
|
|
n = 0;
|
|
pu_info.pu_labels[i] = XmCreateLabel (pu_info.pu_w, "EPUL",args,n);
|
|
}
|
|
|
|
/* and add the separator and the "Point" button.
|
|
* we always wants these so manage them now.
|
|
*/
|
|
w = XmCreateSeparator (pu_info.pu_w, "PUSep", args, 0);
|
|
XtManageChild (w);
|
|
w = XmCreatePushButton (pu_info.pu_w, "Point", args, 0);
|
|
XtAddCallback (w, XmNactivateCallback, e_point_cb, 0);
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* given diameter and x/y border display info at the given lat/long
|
|
*/
|
|
static void
|
|
e_track_latlng (w, d, xb, yb, lt, lg)
|
|
Widget w;
|
|
int d;
|
|
int xb, yb;
|
|
double lt, lg;
|
|
{
|
|
static int last_lst_w, last_lmt_w, last_ll_w, last_db_w;
|
|
int topy = projection == WXMAP ? WXM_TY : 0;
|
|
int boty = projection == WXMAP ? WXM_BY : d + 2*yb;
|
|
int wide = d + 2*xb;
|
|
Now *np = mm_get_now();
|
|
Window win = XtWindow(w);
|
|
char lst_buf[64], lmt_buf[64], lng_buf[64], lat_buf[64];
|
|
char dist_buf[64], bear_buf[64];
|
|
Pixel fg, bg;
|
|
XCharStruct all;
|
|
double dist, bear;
|
|
double lst, gst, lmt;
|
|
int dir, asc, des;
|
|
int len;
|
|
|
|
/* great circle info */
|
|
e_greatCircle (lt, lg, &dist, &bear);
|
|
|
|
/* fill in the strings */
|
|
(void) strcpy (bear_buf, "Bearing: ");
|
|
fs_dms_angle (bear_buf+strlen(bear_buf), bear);
|
|
if (pref_get (PREF_UNITS) == PREF_ENGLISH)
|
|
(void) sprintf (dist_buf, "Distance: %7.1f mi", dist*0.62137119e-3);
|
|
else
|
|
(void) sprintf (dist_buf, "Distance: %7.1f km", dist*1e-3);
|
|
(void) strcpy (lat_buf, " Lat: ");
|
|
fs_dms_angle (lat_buf+strlen(lat_buf), lt);
|
|
(void) strcpy (lng_buf, "Long: ");
|
|
fs_dms_angle (lng_buf+strlen(lng_buf), -lg); /* want +W */
|
|
lmt = mjd_hr(mjd) + radhr(lg);
|
|
range (&lmt, 24.0);
|
|
(void) strcpy (lmt_buf, "LMT: ");
|
|
fs_time (lmt_buf+strlen(lmt_buf), lmt);
|
|
utc_gst (mjd_day(mjd), mjd_hr(mjd), &gst);
|
|
lst = gst + radhr(lg);
|
|
range (&lst, 24.0);
|
|
(void) strcpy (lst_buf, "LST: ");
|
|
fs_time (lst_buf+strlen(lst_buf), lst);
|
|
|
|
/* set colors */
|
|
fg = ecolors[SUNC].p;
|
|
bg = e_bg;
|
|
|
|
/* draw the strings, first erasing the previous */
|
|
|
|
/* lat/long in upper left */
|
|
len = strlen (lat_buf);
|
|
XTextExtents (e_f, lat_buf, len, &dir, &asc, &des, &all);
|
|
if (all.width > last_ll_w)
|
|
last_ll_w = all.width;
|
|
len = strlen (lng_buf);
|
|
XTextExtents (e_f, lng_buf, len, &dir, &asc, &des, &all);
|
|
if (all.width > last_ll_w)
|
|
last_ll_w = all.width;
|
|
XSetForeground (XtD, e_strgc, bg);
|
|
XFillRectangle (XtD, win, e_strgc, 0, topy, last_ll_w, 2*(asc+des));
|
|
XSetForeground (XtD, e_strgc, fg);
|
|
XDrawString (XtD, win, e_strgc, 0, topy+asc, lat_buf, strlen(lat_buf));
|
|
XDrawString (XtD, win, e_strgc, 0, topy+2*asc+des, lng_buf, strlen(lng_buf));
|
|
|
|
/* dist/bear in upper right */
|
|
len = strlen (dist_buf);
|
|
XTextExtents (e_f, dist_buf, len, &dir, &asc, &des, &all);
|
|
if (all.width > last_db_w)
|
|
last_db_w = all.width;
|
|
len = strlen (bear_buf);
|
|
XTextExtents (e_f, bear_buf, len, &dir, &asc, &des, &all);
|
|
if (all.width > last_db_w)
|
|
last_db_w = all.width;
|
|
XSetForeground (XtD, e_strgc, bg);
|
|
XFillRectangle (XtD, win, e_strgc, wide-last_db_w, topy, last_db_w, 2*(asc+des));
|
|
XSetForeground (XtD, e_strgc, fg);
|
|
XDrawString (XtD, win, e_strgc, wide-last_db_w, topy+asc, dist_buf, strlen(dist_buf));
|
|
XDrawString (XtD, win, e_strgc, wide-last_db_w, topy+2*asc+des, bear_buf, strlen(bear_buf));
|
|
|
|
/* lmt in lower left */
|
|
len = strlen (lmt_buf);
|
|
XTextExtents (e_f, lmt_buf, len, &dir, &asc, &des, &all);
|
|
if (all.width > last_lmt_w)
|
|
last_lmt_w = all.width;
|
|
XSetForeground (XtD, e_strgc, bg);
|
|
XFillRectangle (XtD, win, e_strgc, 0, boty-(asc+des), last_lmt_w,
|
|
asc+des);
|
|
XSetForeground (XtD, e_strgc, fg);
|
|
XDrawString (XtD, win, e_strgc, 0, boty-des, lmt_buf, len);
|
|
|
|
/* lst in lower right */
|
|
len = strlen (lst_buf);
|
|
XTextExtents (e_f, lst_buf, len, &dir, &asc, &des, &all);
|
|
if (all.width > last_lst_w)
|
|
last_lst_w = all.width;
|
|
XSetForeground (XtD, e_strgc, bg);
|
|
XFillRectangle (XtD, win, e_strgc, wide-last_lst_w, boty-(asc+des),
|
|
last_lst_w, asc+des);
|
|
XSetForeground (XtD, e_strgc, fg);
|
|
XDrawString (XtD, win, e_strgc, wide-last_lst_w, boty-des,
|
|
lst_buf, len);
|
|
}
|
|
|
|
/* set the elat/selat/celat/elng values, taking care to put them into ranges
|
|
* -PI/2 .. elat .. PI/2 and -PI .. elng .. PI.
|
|
*/
|
|
static void
|
|
e_setelatlng (lt, lg)
|
|
double lt, lg;
|
|
{
|
|
elat = lt;
|
|
selat = sin(elat);
|
|
celat = cos(elat);
|
|
elng = lg;
|
|
range (&elng, 2*PI);
|
|
if (elng > PI)
|
|
elng -= 2*PI;
|
|
|
|
/* capture new inertial frame if on */
|
|
if (wants[INERTIALF])
|
|
ll2rd (elat, elng, &ira, &idec);
|
|
}
|
|
|
|
/* return the lat/lng of the subobject point (lat/long of where the object
|
|
* is directly overhead) at np.
|
|
* both are in rads, lat is +N, long is +E.
|
|
*/
|
|
static void
|
|
e_subobject(np, op, latp, longp)
|
|
Now *np;
|
|
Obj *op;
|
|
double *latp, *longp;
|
|
{
|
|
if (op->o_type == EARTHSAT) {
|
|
/* these are all ready to go */
|
|
*latp = op->s_sublat;
|
|
*longp = op->s_sublng;
|
|
} else {
|
|
double gst;
|
|
double ra, dec;
|
|
|
|
ra = op->s_gaera;
|
|
dec = op->s_gaedec;
|
|
|
|
*latp = dec;
|
|
|
|
utc_gst (mjd_day(mjd), mjd_hr(mjd), &gst);
|
|
*longp = ra - hrrad(gst); /* remember: we want +E */
|
|
range (longp, 2*PI);
|
|
if (*longp > PI)
|
|
*longp -= 2*PI;
|
|
}
|
|
}
|
|
|
|
/* find the rate of change of op->s_edist in m/s
|
|
*/
|
|
static double
|
|
e_edist_rate (Now *np, Obj *op)
|
|
{
|
|
double h = 0.5/24.0; /* step size, days */
|
|
double e0, e1; /* edist @ mjd-h and mjd+h */
|
|
Now myn = *np; /* copy for modified times */
|
|
|
|
myn.n_mjd = mjd - h;
|
|
obj_cir (&myn, op);
|
|
e0 = op->s_edist;
|
|
|
|
myn.n_mjd = mjd + h;
|
|
obj_cir (&myn, op);
|
|
e1 = op->s_edist;
|
|
|
|
return ((MAU/SPD)*(e1-e0)/(2*h));
|
|
}
|
|
|
|
/* show the stats for the object in the given trow in its current
|
|
* position. if it's of type EARTHSAT then display its s_ fields; otherwise
|
|
* turn off the display of these items.
|
|
*/
|
|
static void
|
|
e_show_esat_stats (eop)
|
|
EObj *eop;
|
|
{
|
|
Now *np = mm_get_now();
|
|
Obj *op = &eop->trail[0].t_obj;
|
|
int unitspref = pref_get (PREF_UNITS);
|
|
int dok = dateOK (np, op) == 0;
|
|
|
|
/* all objects show sublocation unless invalid date */
|
|
if (dok) {
|
|
f_dms_angle (eop->slat_w, eop->trail[0].t_sublat);
|
|
f_dms_angle (eop->slng_w, -eop->trail[0].t_sublng);
|
|
} else {
|
|
f_string (eop->slat_w, " ");
|
|
f_string (eop->slng_w, " ");
|
|
}
|
|
|
|
if (dok && op->o_type == EARTHSAT) {
|
|
if (unitspref == PREF_ENGLISH) {
|
|
f_showit (altlbl_w, "Alt\nmiles");
|
|
f_double (eop->el_w, "%7.5g", op->s_elev*FTPM/5280.0);
|
|
} else {
|
|
f_showit (altlbl_w, "Alt\nkm");
|
|
f_double (eop->el_w, "%7.5g", op->s_elev/1000.0);
|
|
}
|
|
|
|
if (unitspref == PREF_ENGLISH) {
|
|
f_showit (rangelbl_w, "Range\nmiles");
|
|
f_double (eop->range_w, "%7.5g", op->s_range*FTPM/5280.0);
|
|
} else {
|
|
f_showit (rangelbl_w, "Range\nkm");
|
|
f_double (eop->range_w, "%7.5g", op->s_range/1000.0);
|
|
}
|
|
|
|
if (unitspref == PREF_ENGLISH) {
|
|
f_showit (rangerlbl_w, "Range'\nft/s");
|
|
f_double (eop->rrate_w, "%7.5g", op->s_rangev*FTPM);
|
|
} else {
|
|
f_showit (rangerlbl_w, "Range'\nm/s");
|
|
f_double (eop->rrate_w, "%7.5g", op->s_rangev);
|
|
}
|
|
|
|
f_double (eop->sun_w, "%.0f", op->s_eclipsed ? 0.0 : 1.0);
|
|
|
|
f_double (eop->age_w, "%.2f", mjd - op->es_epoch);
|
|
|
|
} else if (dok && is_type(op,ELLIPTICALM|HYPERBOLICM|PARABOLICM|PLANETM)) {
|
|
f_string (eop->el_w, " ");
|
|
f_string (eop->range_w, " ");
|
|
|
|
if (unitspref == PREF_ENGLISH) {
|
|
f_showit (rangerlbl_w, "Range'\nft/s");
|
|
f_double (eop->rrate_w, "%7.5g", e_edist_rate (np, op)*FTPM);
|
|
} else {
|
|
f_showit (rangerlbl_w, "Range'\nm/s");
|
|
f_double (eop->rrate_w, "%7.5g", e_edist_rate (np, op));
|
|
}
|
|
|
|
f_string (eop->sun_w, " ");
|
|
f_string (eop->age_w, " ");
|
|
|
|
} else {
|
|
f_string (eop->el_w, " ");
|
|
f_string (eop->range_w, " ");
|
|
f_string (eop->rrate_w, " ");
|
|
f_string (eop->sun_w, " ");
|
|
f_string (eop->age_w, " ");
|
|
}
|
|
}
|
|
|
|
/* given a lat/long now find ra/dec overhead */
|
|
static void
|
|
ll2rd (double l, double L, double *rap, double *decp)
|
|
{
|
|
Now *np = mm_get_now();
|
|
double gst;
|
|
|
|
utc_gst (mjd_day(mjd), mjd_hr(mjd), &gst);
|
|
*rap = hrrad(gst) + L; /* because overhead HA == 0 */
|
|
range (rap, 2*PI);
|
|
*decp = l;
|
|
}
|
|
|
|
/* given a ra/dec return lat/long where it is overhead */
|
|
static void
|
|
rd2ll (double ra, double dec, double *lp, double *Lp)
|
|
{
|
|
Now *np = mm_get_now();
|
|
double gst;
|
|
|
|
utc_gst (mjd_day(mjd), mjd_hr(mjd), &gst);
|
|
*Lp = ra - hrrad(gst); /* because overhead HA == 0 */
|
|
range (Lp, 2*PI);
|
|
*lp = dec;
|
|
}
|
|
|
|
/* given:
|
|
* the current viewpoint coords (from globals selat/celat/elng)
|
|
* diameter and borders of circle in current window
|
|
* latitude and longitude of a point p: pl, pL;
|
|
* projection
|
|
* find:
|
|
* x and y coords of point on screen
|
|
* always return the coordinates, but return 1 if the point is visible or 0 if
|
|
* it's over the limb.
|
|
*/
|
|
static int
|
|
e_coord (d, wb, hb, pl, pL, xp, yp)
|
|
unsigned d; /* diameter of drawing surface circle */
|
|
unsigned wb, hb; /* width/height borders between circle and edges */
|
|
double pl, pL; /* point p lat, rads, +N; long, rads, +E */
|
|
short *xp, *yp; /* projected location onto drawing surface */
|
|
{
|
|
switch (projection) {
|
|
case CYLI: /* FALLTHRU */
|
|
case CYLG: {
|
|
unsigned w = d + 2*wb;
|
|
unsigned h = d + 2*hb;
|
|
double dL;
|
|
|
|
// *yp = (int)floor(h/2.0 * (1.0 - sin(pl)) + 0.5);
|
|
*yp = (int)floor(h/2.0 * (1.0 - 2*pl/PI) + 0.5);
|
|
|
|
dL = pL - elng;
|
|
range(&dL, 2*PI);
|
|
if (dL > PI) dL -= 2*PI;
|
|
*xp = (int)floor(w/2.0 * (1.0 + dL/PI) + 0.5);
|
|
|
|
return (1);
|
|
}
|
|
|
|
case SPHI: /* FALLTHRU */
|
|
case SPHG: {
|
|
double sR, cR; /* R is radius from viewpoint to p */
|
|
double A, sA,cA; /* A is azimuth of p as seen from viewpoint */
|
|
unsigned int r = d/2;
|
|
|
|
solve_sphere (pL - elng, PI/2 - pl, selat, celat, &cR, &A);
|
|
sR = sqrt(1.0 - cR*cR);
|
|
sA = sin(A);
|
|
cA = cos(A);
|
|
|
|
*xp = wb + r + (int)floor(r*sR*sA + 0.5);
|
|
*yp = hb + r - (int)floor(r*sR*cA + 0.5);
|
|
|
|
return (cR > -.0001);
|
|
}
|
|
|
|
case WXMAP: {
|
|
mollweide_llxy (pl, pL, xp, yp);
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* draw circles onto e_pm within circle of diameter d and width and height
|
|
* borders wb and hb showing where the satellite is seen as being 0, 30 and 60
|
|
* degrees altitude above horizon as well.
|
|
* also draw a crosshair at the actual location.
|
|
* return 1 if any part was visible, else 0.
|
|
*/
|
|
static int
|
|
e_drawfootprint (np, eop, d, wb, hb, slat, slng, el)
|
|
Now *np; /* circumstances */
|
|
EObj *eop; /* object info */
|
|
int d, wb, hb; /* dia and width/height borders of circle to use */
|
|
double slat, slng; /* satellite's lat and lng */
|
|
double el; /* satellite's elevation above surface, m */
|
|
{
|
|
double rad; /* viewing altitude radius, rads */
|
|
int isvis;
|
|
|
|
e_viewrad (np, el, degrad(0.0), &rad);
|
|
isvis = e_drawcircle (eop->pix, d, wb, hb, slat, slng, rad);
|
|
e_viewrad (np, el, degrad(30.0), &rad);
|
|
e_drawcircle (eop->pix, d, wb, hb, slat, slng, rad);
|
|
e_viewrad (np, el, degrad(60.0), &rad);
|
|
e_drawcircle (eop->pix, d, wb, hb, slat, slng, rad);
|
|
e_drawcross (d, wb, hb, slat, slng, CROSSH);
|
|
|
|
return (isvis);
|
|
}
|
|
|
|
/* assuming the current vantage point of elat/elng, draw a circle around the
|
|
* given lat/long point of given angular radius.
|
|
* all angles in rads.
|
|
* we do it by sweeping an arc from the given location and collecting the end
|
|
* points. beware going over the horizon or wrapping around the edge.
|
|
* return 1 if any part of the circle is visible, else 0.
|
|
*/
|
|
static int
|
|
e_drawcircle (pix, d, wb, hb, slat, slng, rad)
|
|
Pixel pix; /* drawing color */
|
|
unsigned d, wb, hb; /* dia and width/height borders of circle to use */
|
|
double slat, slng; /* lat/long of object */
|
|
double rad; /* angular radius of circle to draw */
|
|
{
|
|
#define MAXVCIRSEGS 62
|
|
XPoint xp[MAXVCIRSEGS+1];
|
|
double cosc = cos(PI/2 - slat); /* cos/sin of N-pole-to-slat angle */
|
|
double sinc = sin(PI/2 - slat);
|
|
double b = rad; /* sat-to-arc angle */
|
|
double A; /* subobject azimuth */
|
|
double cosa; /* cos of pole-to-arc angle */
|
|
double B; /* subobj-to-view angle from pole */
|
|
int nvcirsegs = MAXVCIRSEGS;
|
|
int nxp = 0;
|
|
int isvis;
|
|
int w = d + 2*wb;
|
|
int vis;
|
|
int i;
|
|
|
|
/* use the overlay gc, wide lines, pix color */
|
|
XSetLineAttributes (XtD, e_olgc, NARROW_LW, LINE_ST, CAP_ST, JOIN_ST);
|
|
XSetForeground (XtD, e_olgc, pix);
|
|
|
|
isvis = 0;
|
|
for (i = 0; i <= nvcirsegs; i++) {
|
|
short x, y;
|
|
A = 2*PI/nvcirsegs * i;
|
|
solve_sphere (A, b, cosc, sinc, &cosa, &B);
|
|
vis = e_coord (d, wb, hb, PI/2-acos(cosa), B+slng, &x, &y);
|
|
if (vis)
|
|
isvis = 1;
|
|
|
|
nxp = add_to_polyline (xp, XtNumber(xp), i,vis,nxp,nvcirsegs,w,x,y);
|
|
}
|
|
|
|
return (isvis);
|
|
}
|
|
|
|
/* draw a little crosshair or plussign at the given location with the e_olgc
|
|
* return whether visible
|
|
*/
|
|
static int
|
|
e_drawcross (d, wb, hb, lt, lg, style)
|
|
unsigned d, wb, hb; /* dia and width/height borders of circle to use */
|
|
double lt, lg; /* desired center location */
|
|
int style; /* CROSSH or PLUSS */
|
|
{
|
|
double lats[4], lngs[4]; /* lats and longs of endpoints */
|
|
XSegment xs[4]; /* one for each cardinal direction */
|
|
double a, cosa; /* north-to-cross from view */
|
|
double B; /* cross-width from north */
|
|
short sx, sy; /* x and y of the center */
|
|
int w = d + 2*wb;
|
|
int linew = 0;
|
|
int nxs;
|
|
int vis;
|
|
int xwrap;
|
|
int i;
|
|
|
|
/* find location of center of cross-hair */
|
|
vis = e_coord (d, wb, hb, lt, lg, &sx, &sy);
|
|
if (!vis)
|
|
return (0); /* center is not visible so forget the rest */
|
|
|
|
/* find longitude sweep to produce given e/w arc */
|
|
|
|
switch (style) {
|
|
case CROSSH:
|
|
solve_sphere (PI/4, CHLEN, sin(lt), cos(lt), &cosa, &B);
|
|
a = acos(cosa);
|
|
lats[0] = PI/2-a; lngs[0] = lg+B;
|
|
lats[1] = PI/2-a; lngs[1] = lg-B;
|
|
solve_sphere (3*PI/4, CHLEN, sin(lt), cos(lt), &cosa, &B);
|
|
a = acos(cosa);
|
|
lats[2] = PI/2-a; lngs[2] = lg+B;
|
|
lats[3] = PI/2-a; lngs[3] = lg-B;
|
|
linew = NARROW_LW;
|
|
break;
|
|
case PLUSS:
|
|
solve_sphere (PI/2, PLLEN, sin(lt), cos(lt), &cosa, &B);
|
|
a = acos(cosa);
|
|
lats[0] = PI/2-a; lngs[0] = lg+B;
|
|
lats[1] = PI/2-a; lngs[1] = lg-B;
|
|
lats[2] = lt-PLLEN; lngs[2] = lg;
|
|
if (lats[2] < -PI/2) {
|
|
lats[2] = -PI - lats[2];lngs[2] += PI; /* went under S pole */
|
|
}
|
|
lats[3] = lt+PLLEN; lngs[3] = lg;
|
|
if (lats[3] > PI/2) {
|
|
lats[3] = PI - lats[3]; lngs[3] += PI; /* went over N pole */
|
|
}
|
|
linew = WIDE_LW;
|
|
break;
|
|
default:
|
|
printf ("e_drawcross: bad style: %d\n", style);
|
|
abort();
|
|
}
|
|
|
|
nxs = 0;
|
|
for (i = 0; i < 4; i++) {
|
|
short x, y;
|
|
vis = e_coord (d, wb, hb, lats[i], lngs[i], &x, &y);
|
|
|
|
if (projection != SPHG && projection != SPHI
|
|
&& (sx - x > w/2 || x - sx > w/2))
|
|
xwrap = 1;
|
|
else
|
|
xwrap = 0;
|
|
|
|
if (vis && !xwrap) {
|
|
xs[nxs].x1 = x;
|
|
xs[nxs].y1 = y;
|
|
xs[nxs].x2 = sx;
|
|
xs[nxs].y2 = sy;
|
|
nxs++;
|
|
}
|
|
}
|
|
|
|
if (nxs > 0) {
|
|
XSetLineAttributes (XtD, e_olgc, linew, LINE_ST, CAP_ST, JOIN_ST);
|
|
XPSDrawSegments (XtD, e_pm, e_olgc, xs, nxs);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
/* draw the lat/long grid lines */
|
|
static void
|
|
e_drawgrid (d, wb, hb)
|
|
unsigned d, wb, hb; /* dia and width/height borders of circle to use */
|
|
{
|
|
#define MAXGRIDSEGS 60 /* max segments per grid line */
|
|
int nsegs = MAXGRIDSEGS;
|
|
XPoint xp[MAXGRIDSEGS+1];
|
|
int mxp = XtNumber(xp);
|
|
int w = d + 2*wb;
|
|
int i, j;
|
|
|
|
/* use the overlay GC, narrow lines, GRIDC color */
|
|
XSetLineAttributes (XtD, e_olgc, NARROW_LW, LINE_ST, CAP_ST, JOIN_ST);
|
|
XSetForeground (XtD, e_olgc, ecolors[GRIDC].p);
|
|
|
|
/* draw each line of constant longitude */
|
|
for (i = 0; i < 360/LNGSTEP; i++) {
|
|
double lg = i * degrad(LNGSTEP);
|
|
int nxp = 0;
|
|
for (j = 0; j <= nsegs; j++) {
|
|
short x, y;
|
|
double lt = degrad (90 - j*180.0/nsegs);
|
|
int vis = e_coord (d, wb, hb, lt, lg, &x, &y);
|
|
nxp = add_to_polyline (xp, mxp, j, vis, nxp, nsegs, w, x, y);
|
|
}
|
|
}
|
|
|
|
/* draw each line of constant latitude -- beware of x wrap */
|
|
for (i = 1; i < 180/LATSTEP; i++) {
|
|
double lt = degrad (90 - i*LATSTEP);
|
|
int nxp = 0;
|
|
for (j = 0; j <= nsegs; j++) {
|
|
short x, y;
|
|
double lg = degrad(180.0 - j*360.0/nsegs);
|
|
int vis = e_coord (d, wb, hb, lt, lg, &x, &y);
|
|
nxp = add_to_polyline (xp, mxp, j, vis, nxp, nsegs, w, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* given projection, diam and size of window and X-coord x/y, return lat/long.
|
|
* see e_getcircle() for meanings in each projection.
|
|
* return 1 if inside the map, else 0.
|
|
*/
|
|
static int
|
|
e_uncoord (proj, d, xb, yb, x, y, ltp, lgp)
|
|
Proj proj; /* which projection to use */
|
|
unsigned int d; /* diameter of earth limb, pixels */
|
|
unsigned xb, yb; /* borders around circle */
|
|
int x, y; /* X-windows coords of loc */
|
|
double *ltp, *lgp; /* resulting lat/long, rads */
|
|
{
|
|
switch (proj) {
|
|
|
|
case CYLI: /* FALLTHRU */
|
|
case CYLG: {
|
|
int maxx = d + 2*xb;
|
|
int maxy = d + 2*yb;
|
|
|
|
if (x < 0 || x >= maxx || y < 0 || y >= maxy)
|
|
return (0);
|
|
|
|
//*ltp = asin (1.0 - 2.0*y/maxy);
|
|
*ltp = PI * (1.0 - 2.0*y/maxy) / 2;
|
|
|
|
*lgp = 2*PI*(x - maxx/2)/maxx + elng;
|
|
if (*lgp > PI) *lgp -= 2*PI;
|
|
if (*lgp < -PI) *lgp += 2*PI;
|
|
|
|
return (1);
|
|
}
|
|
|
|
case SPHI: /* FALLTHRU */
|
|
case SPHG: {
|
|
double X, Y;/* x/y but signed from center +x right +y up, pixels*/
|
|
double R; /* pixels x/y is from center */
|
|
double b; /* angle from viewpoint to x/y */
|
|
double A; /* angle between N pole and x/y as seen from viewpt */
|
|
double a, ca; /* angle from N pole to x/y */
|
|
double B; /* angle from viewpoint to x/y as seen from N pole */
|
|
unsigned int r = d/2;
|
|
|
|
X = x - (int)(r + xb);
|
|
Y = (int)(r + yb) - y;
|
|
R = sqrt (X*X + Y*Y);
|
|
if (R >= r)
|
|
return (0);
|
|
|
|
if (R < 1.0) {
|
|
*ltp = elat;
|
|
*lgp = elng;
|
|
} else {
|
|
b = asin (R/r);
|
|
A = atan2 (X, Y);
|
|
solve_sphere (A, b, selat, celat, &ca, &B);
|
|
a = acos (ca);
|
|
*ltp = PI/2 - a;
|
|
*lgp = elng + B;
|
|
range (lgp, 2*PI);
|
|
if (*lgp > PI)
|
|
*lgp -= 2*PI;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
case WXMAP: {
|
|
return (mollweide_xyll (x, y, ltp, lgp));
|
|
}
|
|
|
|
default:
|
|
printf ("Unknown earth projection: %d\n", proj);
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/* Turn off track_w in all eobjs */
|
|
static void
|
|
noTrack()
|
|
{
|
|
EObj *eop;
|
|
|
|
for (eop = eobjs; eop < &eobjs[neobjs]; eop++)
|
|
TBOFF (eop->track_w);
|
|
}
|
|
|
|
/* draw everything: fields (always) and the picture (if managed).
|
|
* if statstoo then redraw the info table too. making this explicit allows
|
|
* for faster redraw when we know full well the stats have not changed.
|
|
*/
|
|
static void
|
|
e_all (statstoo)
|
|
int statstoo;
|
|
{
|
|
Now *np = mm_get_now();
|
|
EObj *eop;
|
|
|
|
watch_cursor(1);
|
|
|
|
/* point at it if tracking is on */
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++) {
|
|
if (TBISON (eop->track_w)) {
|
|
e_setelatlng (eop->trail[0].t_sublat, eop->trail[0].t_sublng);
|
|
break; /* there can only be one On */
|
|
}
|
|
}
|
|
|
|
/* if want inertial frame, use it to set lat/long */
|
|
if (wants[INERTIALF]) {
|
|
double l, L;
|
|
rd2ll (ira, idec, &l, &L);
|
|
e_setelatlng (l, L);
|
|
}
|
|
|
|
/* update the scale -- remember we want +W longitude, -180..+179 */
|
|
XmScaleSetValue (lat_w, (int)floor(raddeg(elat)+0.5));
|
|
XmScaleSetValue (long_w, (((int)floor(raddeg(-elng)+.5)+180)%360)-180);
|
|
|
|
/* display the picture now if we are up for sure.
|
|
* N.B. don't just use whether eshell_w is up: if we are looping
|
|
* and get managed drawing occurs before the first expose makes the pm.
|
|
*/
|
|
if (e_pm) {
|
|
e_map (np);
|
|
e_copy_pm();
|
|
}
|
|
|
|
/* update stats.
|
|
* N.B. do after graphics to avoid flashing
|
|
*/
|
|
if (statstoo)
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++)
|
|
e_show_esat_stats (eop);
|
|
|
|
/* put up the current time */
|
|
timestamp (np, e_dt_w);
|
|
timestamp (np, e_cdt_w);
|
|
|
|
watch_cursor(0);
|
|
}
|
|
|
|
/* find size and borders for drawing earth.
|
|
* if spherical, center a circle of max size that completely fits.
|
|
* if cylindrical, use entire rectangle.
|
|
* if wxmap, assume correct (fixed) size, r is horizontal half-width.
|
|
*/
|
|
static void
|
|
e_getcircle (wp, hp, dp, xbp, ybp)
|
|
int *wp, *hp; /* overall width and height */
|
|
int *dp; /* circle diameter */
|
|
int *xbp, *ybp; /* x and y border */
|
|
{
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
Window win = XtWindow(e_da_w);
|
|
Window root;
|
|
unsigned int bw, d;
|
|
int x, y;
|
|
int z;
|
|
|
|
if (projection == WXMAP) {
|
|
*wp = WXM_W;
|
|
*hp = WXM_H;
|
|
*dp = WXM_W - WXM_LX;
|
|
*xbp = WXM_LX;
|
|
*ybp = WXM_TY;
|
|
return;
|
|
}
|
|
|
|
XGetGeometry (dsp, win, &root, &x, &y, (unsigned int *)wp,
|
|
(unsigned int *)hp, &bw, &d);
|
|
|
|
*dp = *wp > *hp ? *hp : *wp; /* diameter is smaller dimension */
|
|
XmScaleGetValue (zoom_w, &z);
|
|
*dp = (int)(*dp * MINZOOM * pow(MAXZOOM/MINZOOM,(double)z/ZOOMSCALE));
|
|
*xbp = (*wp - *dp)/2; /* x border */
|
|
*ybp = (*hp - *dp)/2; /* y border */
|
|
|
|
}
|
|
|
|
/* draw everything centered at elat/elng onto e_pm.
|
|
*/
|
|
static void
|
|
e_map (np)
|
|
Now *np;
|
|
{
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
int w, h, d, wb, hb;
|
|
EObj *eop;
|
|
|
|
/* get size of the rendering area */
|
|
e_getcircle (&w, &h, &d, &wb, &hb);
|
|
|
|
/* setup the background and night on screen, but don't print */
|
|
switch (projection) {
|
|
case CYLI:
|
|
if ((!deipix && loaddei() < 0) || (!neipix && loadnei() < 0))
|
|
return; /* bzzt */
|
|
drawei(w, h, d, wb, hb);
|
|
XSetForeground (dsp, e_gc, e_bg);
|
|
XPSPixmap (e_pm, w, h, xe_cm, e_gc, 0);
|
|
break;
|
|
|
|
case CYLG:
|
|
XSetForeground (dsp, e_gc, e_bg);
|
|
XFillRectangle (dsp, e_pm, e_gc, 0, 0, w, h);
|
|
break;
|
|
|
|
case SPHI:
|
|
if ((!deipix && loaddei() < 0) || (!neipix && loadnei() < 0))
|
|
return; /* bzzt */
|
|
drawei(w, h, d, wb, hb);
|
|
XSetForeground (dsp, e_gc, e_bg);
|
|
XPSPixmap (e_pm, w, h, xe_cm, e_gc, 0);
|
|
break;
|
|
|
|
case SPHG:
|
|
XSetForeground (dsp, e_gc, e_bg);
|
|
XFillRectangle (dsp, e_pm, e_gc, 0, 0, w, h);
|
|
XFillArc (dsp, e_pm, e_gc, wb, hb, d, d, 0, 360*64);
|
|
break;
|
|
|
|
case WXMAP:
|
|
if (e_setupwxpm(0, 0) < 0)
|
|
return;
|
|
XCopyArea (dsp, e_wxpm, e_pm, e_gc, 0, 0, w, h, 0, 0);
|
|
XPSPixmap (e_pm, w, h, xe_cm, 0, 0);
|
|
break;
|
|
}
|
|
|
|
/* draw sunlit portion of earth */
|
|
if (wants[SUNLIGHT])
|
|
e_sunlit (np, d, wb, hb);
|
|
|
|
/* draw coord grid */
|
|
if (wants[GRID])
|
|
e_drawgrid (d, wb, hb);
|
|
|
|
/* draw each continent border -- just on night side sometimes */
|
|
if (projection == CYLG || projection == SPHG || wants[SUNLIGHT])
|
|
e_drawcontinents (d, wb, hb);
|
|
|
|
/* draw each site */
|
|
if (wants[SITES])
|
|
e_drawsites (d, wb, hb);
|
|
|
|
/* draw each shown object subject to date range and its trails if any */
|
|
for (eop = eobjs; eop < &eobjs[nfavs]; eop++) {
|
|
if (dateOK(np, eop->op) == 0 && TBISON(eop->show_w)) {
|
|
int dreworb = 0;
|
|
if (is_type(eop->op, EARTHSATM) && TBISON(eop->wantorb_w)) {
|
|
e_draworbit (eop, d, wb, hb); /*always draws name if want*/
|
|
dreworb = 1;
|
|
} else
|
|
eop->ovis = 0;
|
|
if (e_drawobject (np, eop, d, wb, hb) && !dreworb &&
|
|
TBISON(eop->wantlbl_w))
|
|
e_drawname (eop, d, wb, hb);
|
|
if (TBISON(eop->showtr_w))
|
|
e_drawtrail (eop, d, wb, hb);
|
|
}
|
|
}
|
|
|
|
/* mark the mainmenu location */
|
|
if (wants[MAINMARKER])
|
|
e_mainmenuloc (np, d, wb, hb);
|
|
|
|
/* mark any solar eclipse location */
|
|
e_soleclipse (np, d, wb, hb);
|
|
|
|
/* draw any annotation */
|
|
ano_draw (e_da_w, e_pm, e_ano, 0);
|
|
}
|
|
|
|
/* convert world to/from X coords depending on w2x.
|
|
* return whether visible.
|
|
*/
|
|
static int
|
|
e_ano (double *latp, double *longp, int *xp, int *yp, int w2x, int arg)
|
|
{
|
|
int w, h, d, wb, hb;
|
|
int v;
|
|
|
|
/* get size of the rendering area */
|
|
e_getcircle (&w, &h, &d, &wb, &hb);
|
|
|
|
if (w2x) {
|
|
short sx, sy;
|
|
v = e_coord (d, wb, hb, *latp, *longp, &sx, &sy);
|
|
*xp = sx;
|
|
*yp = sy;
|
|
} else {
|
|
v = e_uncoord (projection, d, wb, hb, *xp, *yp, latp, longp);
|
|
}
|
|
|
|
return (v);
|
|
}
|
|
|
|
/* draw the portion of the earth lit by the sun */
|
|
static void
|
|
e_sunlit (np, d, wb, hb)
|
|
Now *np; /* circumstances */
|
|
unsigned int d, wb, hb; /* circle dia, width and height borders in pixmap */
|
|
{
|
|
switch (projection) {
|
|
case CYLI:
|
|
/* already done in background */
|
|
break;
|
|
case CYLG:
|
|
e_msunlit (np, d, wb, hb);
|
|
break;
|
|
case SPHI:
|
|
/* already done in background */
|
|
break;
|
|
case SPHG:
|
|
e_ssunlit (np, d, wb, hb);
|
|
break;
|
|
case WXMAP:
|
|
/* already part of e_wxpm */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* draw the sunlit portion of the Earth in cylindrical projection.
|
|
*/
|
|
static void
|
|
e_msunlit (np, d, wb, hb)
|
|
Now *np; /* circumstances */
|
|
unsigned int d, wb, hb; /* circle dia, width and height borders in pixmap */
|
|
{
|
|
#define MAXNMPTS 256 /* n segments -- larger is finer but slower */
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
XPoint xp[MAXNMPTS+4]; /* extra room for top or bottom box */
|
|
double sslat, sslong; /* subsolar lat/long, rads, +N +E */
|
|
double az0, daz; /* initial and delta az so we move +x */
|
|
int nmpts = MAXNMPTS;
|
|
double ssl, csl;
|
|
int w = d + 2*wb;
|
|
int h = d + 2*hb;
|
|
short x, y;
|
|
int yi;
|
|
int wrapn, i;
|
|
|
|
e_subobject (np, db_basic(SUN), &sslat, &sslong);
|
|
ssl = sin(sslat);
|
|
csl = cos(sslat);
|
|
|
|
if (sslat < 0) {
|
|
az0 = 0;
|
|
daz = 2*PI/nmpts;
|
|
} else {
|
|
az0 = PI;
|
|
daz = -2*PI/nmpts;
|
|
}
|
|
|
|
/* fill in the circle of nmpts points that lie PI/2 from the
|
|
* subsolar point and projecting from the viewpoint.
|
|
* when wrap, shuffle points up so final polygon doesn't wrap.
|
|
*/
|
|
XSetForeground (dsp, e_gc, ecolors[SUNC].p);
|
|
wrapn = 0;
|
|
for (i = 0; i < nmpts; i++) {
|
|
double A = az0 + i*daz; /* azimuth of p from subsol */
|
|
double sA = sin(A), cA = cos(A);
|
|
double plat = asin (csl*cA); /* latitude of p */
|
|
double plong = atan2(sA, -ssl*cA) + sslong; /* long of p */
|
|
XPoint *xpp = &xp[i-wrapn];
|
|
|
|
(void) e_coord (d, wb, hb, plat, plong, &x, &y);
|
|
|
|
xpp->x = x;
|
|
xpp->y = y;
|
|
|
|
if (wrapn == 0 && i > 0 && x < xpp[-1].x) {
|
|
/* when wrap copy points so far to end and this one is first.
|
|
* N.B. go backwards in case we are over half way.
|
|
*/
|
|
for ( ; wrapn < i; wrapn++)
|
|
xp[nmpts-1-wrapn] = xp[i-1-wrapn];
|
|
xp[0].x = x;
|
|
xp[0].y = y;
|
|
}
|
|
}
|
|
|
|
/* y-intercept at the edges is the average of the y's at each end */
|
|
yi = (xp[0].y + xp[nmpts-1].y)/2;
|
|
|
|
/* complete polygon across bottom if sun is below equator, or vv */
|
|
if (sslat < 0) {
|
|
xp[i].x = w; xp[i].y = yi; i++; /* right */
|
|
xp[i].x = w; xp[i].y = h; i++; /* down */
|
|
xp[i].x = 0; xp[i].y = h; i++; /* left */
|
|
xp[i].x = 0; xp[i].y = yi; i++; /* up */
|
|
} else {
|
|
xp[i].x = w; xp[i].y = yi; i++; /* right */
|
|
xp[i].x = w; xp[i].y = 0; i++; /* up */
|
|
xp[i].x = 0; xp[i].y = 0; i++; /* left */
|
|
xp[i].x = 0; xp[i].y = yi; i++; /* down */
|
|
}
|
|
|
|
XPSFillPolygon (dsp, e_pm, e_gc, xp, i, Complex, CoordModeOrigin);
|
|
}
|
|
|
|
/* draw the solid gibbous or crescent sun-lit portion of the Earth in spherical
|
|
* projection.
|
|
*/
|
|
static void
|
|
e_ssunlit (np, d, wb, hb)
|
|
Now *np; /* circumstances */
|
|
unsigned int d, wb, hb; /* circle dia, width and height borders in pixmap */
|
|
{
|
|
#define MAXNSPTS 52 /* max number of polyline points */
|
|
#define FULLANGLE degrad(5)/* consider full if within this angle */
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
double sslat, sslong; /* subsolar lat/long, rads, +N +E */
|
|
double ssl, csl; /* sin/cos of sslat */
|
|
int dx, dy; /* slope from center to subsolar point */
|
|
double ca; /* angular sep from viewpoint to subsolar */
|
|
double B; /* cw angle up from center to subsolar point */
|
|
int maxpts = MAXNSPTS;
|
|
XPoint xp[MAXNSPTS];
|
|
int npts;
|
|
int i;
|
|
|
|
/* find where the sun is */
|
|
e_subobject (np, db_basic(SUN), &sslat, &sslong);
|
|
|
|
/* set up color */
|
|
XSetForeground (dsp, e_gc, ecolors[SUNC].p);
|
|
|
|
/* find direction and length of line from center to subsolar point */
|
|
solve_sphere (sslong - elng, PI/2-sslat, selat, celat, &ca, &B);
|
|
|
|
/* check for special cases of eclipsed and directly over subsolar pt */
|
|
if (acos(ca) < FULLANGLE) {
|
|
short x, y;
|
|
int vis = e_coord (d, wb, hb, sslat, sslong, &x, &y);
|
|
if (vis)
|
|
XPSFillArc (dsp, e_pm, e_gc, wb, hb, d, d, 0, 360*64);
|
|
return;
|
|
}
|
|
|
|
/* find direction of line parallel to line from center to subsolar
|
|
* location and long enough to be well outside perimeter.
|
|
*/
|
|
dx = (int)floor(1.5*d*sin(B) + 0.5); /* +x to right */
|
|
dy = (int)floor(1.5*d*cos(B) + 0.5); /* +y up */
|
|
|
|
/* follow the circle of points which lie PI/2 from the subsolar point.
|
|
* those which are visible are used directly; those which are not are
|
|
* projected to limb on a line parallel to the center/subsolar point.
|
|
*/
|
|
ssl = sin(sslat);
|
|
csl = cos(sslat);
|
|
for (npts = i = 0; i < maxpts; i++) {
|
|
double T = degrad(i*360.0/maxpts); /* pole to p as seen frm subso*/
|
|
double plat, plong; /* lat/long of point on said circle */
|
|
short px, py;
|
|
|
|
solve_sphere (T, PI/2, ssl, csl, &ca, &B);
|
|
plat = PI/2 - acos(ca);
|
|
plong = sslong - B;
|
|
if (!e_coord (d, wb, hb, plat, plong, &px, &py)) {
|
|
int tx, ty, lx, ly; /* tmp and limb point */
|
|
|
|
if (lc (wb, hb, d, (int)px, (int)py, px+dx, py-dy,
|
|
&tx, &ty, &lx, &ly) == 0) {
|
|
px = lx;
|
|
py = ly;
|
|
}
|
|
}
|
|
xp[npts].x = px;
|
|
xp[npts].y = py;
|
|
npts++;
|
|
}
|
|
|
|
XPSFillPolygon (dsp, e_pm, e_gc, xp, npts, Complex, CoordModeOrigin);
|
|
}
|
|
|
|
/* draw each continent border */
|
|
static void
|
|
e_drawcontinents (d, wb, hb)
|
|
unsigned d, wb, hb;
|
|
{
|
|
#define MINSEP 1000 /* min sep to draw in low prec, 100ths deg */
|
|
#define PTCACHE 64 /* number of XPoints to cache */
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
Now *np = mm_get_now();
|
|
XPoint xp[PTCACHE];
|
|
MRegion *rp;
|
|
int w = d + 2*wb;
|
|
|
|
/* use the overlay GC, wide lines and the BORDERC color */
|
|
XSetLineAttributes (dsp, e_olgc, WIDE_LW, LINE_ST, CAP_ST, JOIN_ST);
|
|
XSetForeground (dsp, e_olgc, ecolors[BORDERC].p);
|
|
|
|
for (rp = ereg; rp < ereg + nereg; rp++) {
|
|
short lastlt = rp->mcp[0].lt, lastlg = rp->mcp[0].lg;
|
|
int n = rp->nmcp;
|
|
int nxp = 0;
|
|
int i;
|
|
|
|
/* draw the region -- including closure at the end */
|
|
for (i = 0; i <= n; i++) {
|
|
MCoord *cp = rp->mcp + (i%n);
|
|
double l, L;
|
|
short x, y;
|
|
int vis;
|
|
|
|
/* don't draw things that are real close if in low prec mode */
|
|
lastlt = cp->lt;
|
|
lastlg = cp->lg;
|
|
l = degrad(cp->lt/100.0);
|
|
L = degrad(cp->lg)/100.0;
|
|
|
|
vis = e_coord (d, wb, hb, l, L, &x, &y) &&
|
|
(projection == CYLG || projection == SPHG
|
|
|| !e_issunlit (np, l, L));
|
|
nxp = add_to_polyline (xp, XtNumber(xp), i, vis, nxp, n, w,x,y);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* draw each site */
|
|
static void
|
|
e_drawsites (d, wb, hb)
|
|
unsigned d, wb, hb;
|
|
{
|
|
#define NPCACHE 64 /* number of XPoints to cache */
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
XPoint xps[NPCACHE];
|
|
Site *sipa;
|
|
int nsa;
|
|
int nxp;
|
|
|
|
/* use the overlay GC and the SITEC color */
|
|
XSetForeground (dsp, e_olgc, ecolors[SITEC].p);
|
|
|
|
nxp = 0;
|
|
for (nsa = sites_get_list(&sipa); --nsa >= 0; ) {
|
|
Site *sip = &sipa[nsa];
|
|
short x, y;
|
|
int vis;
|
|
|
|
vis = e_coord (d, wb, hb, sip->si_lat, sip->si_lng, &x, &y);
|
|
if (vis) {
|
|
/* show each site as a little square */
|
|
xps[nxp].x = x; xps[nxp].y = y; nxp++;
|
|
xps[nxp].x = x+1; xps[nxp].y = y; nxp++;
|
|
xps[nxp].x = x; xps[nxp].y = y+1; nxp++;
|
|
xps[nxp].x = x+1; xps[nxp].y = y+1; nxp++;
|
|
}
|
|
if (nxp > XtNumber(xps)-4 || nsa == 0) {
|
|
if (nxp > 0)
|
|
XPSDrawPoints (dsp, e_pm, e_olgc, xps, nxp,CoordModeOrigin);
|
|
nxp = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* draw all but the first object in the trails list onto e_pm relative to
|
|
* elat/elng connected lines, with tickmarks and possible time stamps.
|
|
*/
|
|
static void
|
|
e_drawtrail (eop, d, wb, hb)
|
|
EObj *eop; /* info about object */
|
|
int d; /* Earth circle diameter, pixels */
|
|
int wb, hb; /* width and height borders, pixels */
|
|
{
|
|
int w = d + 2*wb;
|
|
short lx = 0, ly = 0, lv;
|
|
int i;
|
|
|
|
XSetLineAttributes (XtD, e_olgc, NARROW_LW, LINE_ST, CAP_ST, JOIN_ST);
|
|
XSetForeground (XtD, e_olgc, eop->pix);
|
|
XSetForeground (XtD, e_gc, eop->pix);
|
|
|
|
lv = 0;
|
|
for (i = 1; i < eop->ntrail; i++) {
|
|
Trail *tp = &eop->trail[i];
|
|
Obj *top = &tp->t_obj;
|
|
short x, y;
|
|
int v;
|
|
|
|
v = e_coord (d, wb, hb, tp->t_sublat, tp->t_sublng, &x, &y);
|
|
tp->lvis= v;
|
|
tp->lx = x;
|
|
tp->ly = y;
|
|
|
|
if (v && lv) {
|
|
TrTS ts, lts, *ltsp;
|
|
int e = (is_type(top,EARTHSATM) && top->s_eclipsed);
|
|
|
|
/* establish a TrTS for tr_draw() */
|
|
ts.t = tp->t_now.n_mjd;
|
|
ts.lbl = tp->t_lbl;
|
|
|
|
/* and go back to pick up the first if this is the second tick*/
|
|
if (i == 2) {
|
|
lts.t = eop->trail[1].t_now.n_mjd;
|
|
lts.lbl = eop->trail[1].t_lbl;
|
|
ltsp = <s;
|
|
} else
|
|
ltsp = NULL;
|
|
|
|
switch (projection) {
|
|
case CYLI: /* FALLTHRU */
|
|
case CYLG:
|
|
if (abs(x-lx) > w/2) {
|
|
/* break in two when wraps */
|
|
if (x > lx) {
|
|
/* wrapped over the left edge */
|
|
tr_draw (XtD, e_pm, e_olgc, e, TICKLN, &ts, ltsp,
|
|
&eop->trstate, lx, ly, x-w, y);
|
|
tr_draw (XtD, e_pm, e_olgc, e, TICKLN, &ts, ltsp,
|
|
&eop->trstate, lx+w, ly, x, y);
|
|
} else {
|
|
/* wrapped over the right edge */
|
|
tr_draw (XtD, e_pm, e_olgc, e, TICKLN, &ts, ltsp,
|
|
&eop->trstate, lx, ly, x+w, y);
|
|
tr_draw (XtD, e_pm, e_olgc, e, TICKLN, &ts, ltsp,
|
|
&eop->trstate, lx-w, ly, x, y);
|
|
}
|
|
} else
|
|
tr_draw (XtD, e_pm, e_olgc, e, TICKLN, &ts, ltsp,
|
|
&eop->trstate, lx, ly, x, y);
|
|
break;
|
|
|
|
case SPHI: /* FALLTHRU */
|
|
case SPHG:
|
|
tr_draw (XtD, e_pm, e_olgc, e, TICKLN, &ts, ltsp,
|
|
&eop->trstate, lx, ly, x, y);
|
|
break;
|
|
|
|
case WXMAP:
|
|
if (abs(x-lx) < w/10)
|
|
tr_draw (XtD, e_pm, e_olgc, e, TICKLN, &ts, ltsp,
|
|
&eop->trstate, lx, ly, x, y);
|
|
break;
|
|
}
|
|
}
|
|
|
|
lv = v;
|
|
lx = x;
|
|
ly = y;
|
|
}
|
|
}
|
|
|
|
/* draw the first object in the trails list onto e_pm relative to elat/elng
|
|
* with a full bullseye.
|
|
* return 1 if any part was visible, else 0.
|
|
*/
|
|
static int
|
|
e_drawobject (np, eop, d, wb, hb)
|
|
Now *np; /* circumstances */
|
|
EObj *eop; /* which object */
|
|
int d; /* Earth circle diameter, pixels */
|
|
int wb, hb; /* width and height borders, pixels */
|
|
{
|
|
Trail *tp = eop->trail;
|
|
int isvis;
|
|
|
|
XSetForeground (XtD, e_olgc, eop->pix);
|
|
XSetForeground (XtD, e_gc, eop->pix);
|
|
|
|
/* draw the current location (first object on trails) */
|
|
if (TBISON(eop->wantfoot_w))
|
|
isvis = e_drawfootprint (np, eop, d, wb, hb, tp->t_sublat, tp->t_sublng,
|
|
tp->t_obj.o_type == EARTHSAT ? tp->t_obj.s_elev : 1e9);
|
|
else
|
|
isvis = e_drawcross (d, wb, hb, tp->t_sublat, tp->t_sublng, CROSSH);
|
|
|
|
/* store location -- TODO: already computed this by now */
|
|
tp->lvis = e_coord (d, wb, hb, tp->t_sublat, tp->t_sublng, &tp->lx,
|
|
&tp->ly);
|
|
|
|
return (isvis);
|
|
}
|
|
|
|
/* draw one orbit of the given Earth satellite object.
|
|
* orbit begins over current ground location then proceeds in a sidereal
|
|
* reference frame, ie, ignores rotation of the earth.
|
|
* draw name if want.
|
|
*/
|
|
static void
|
|
e_draworbit (eop, d, wb, hb)
|
|
EObj *eop; /* which object */
|
|
int d; /* Earth circle diameter, pixels */
|
|
int wb, hb; /* width and height borders, pixels */
|
|
{
|
|
Now now, *np; /* advance time through one rev */
|
|
Obj obj, *op; /* advance object through one rev */
|
|
double t0; /* start time */
|
|
XPoint xpts[NORBSTEPS+1];/* orbit steps */
|
|
XPoint xpt0; /* first point, reuse for closure */
|
|
int wasvis; /* whether visible last step */
|
|
int w = d + 2*wb; /* screen width */
|
|
int re = d/2; /* earth radiu, pixels */
|
|
int drewname = 0; /* whether name has been drawn */
|
|
int sproj = (projection == SPHI || projection == SPHG);
|
|
int i;
|
|
int nxpts;
|
|
|
|
/* make local copies of time and object */
|
|
np = mm_get_now();
|
|
now = *np;
|
|
np = &now;
|
|
obj = *eop->op;
|
|
op = &obj;
|
|
t0 = mjd;
|
|
|
|
/* set color */
|
|
XSetForeground (XtD, e_gc, eop->pix);
|
|
|
|
/* step along for one rev */
|
|
nxpts = 0;
|
|
wasvis = 0;
|
|
xpt0.x = xpt0.y = 0; /* lint */
|
|
for (i = 0; i < NORBSTEPS; i++) {
|
|
double dt, lg; /* time step and sidereal longitude */
|
|
int xs, ys; /* coords of orbit from upper left */
|
|
int isvis;
|
|
|
|
/* compute circumstances at next time step */
|
|
dt = i/op->es_n/NORBSTEPS;
|
|
mjd = t0 + dt;
|
|
obj_cir (np, op);
|
|
lg = op->s_sublng;
|
|
|
|
/* project onto screen, note visibility */
|
|
if (sproj) {
|
|
double sR, cR; /* R= radius from viewpoint to p */
|
|
double A, sA,cA; /* A= az of p as seen from viewpoint */
|
|
int ro; /* orbit radius, pixels */
|
|
int xo, yo; /* coords of orbit from center */
|
|
|
|
/* remove rotation effect */
|
|
lg += hrrad(24/SIDRATE*dt);
|
|
|
|
solve_sphere (lg - elng,PI/2 - op->s_sublat,selat,celat,&cR,&A);
|
|
sR = sqrt(1.0 - cR*cR);
|
|
sA = sin(A);
|
|
cA = cos(A);
|
|
ro = re + re*op->s_elev/ERAD;
|
|
xs = wb + re + (xo = (int)floor(ro*sR*sA + 0.5));
|
|
ys = hb + re - (yo = (int)floor(ro*sR*cA + 0.5));
|
|
isvis = xo*xo + yo*yo > re*re || cR > 0;
|
|
} else {
|
|
short sx, sy;
|
|
isvis = e_coord (d, wb, hb, op->s_sublat, lg, &sx, &sy);
|
|
xs = sx;
|
|
ys = sy;
|
|
}
|
|
|
|
if (i == 0) {
|
|
/* first time = position now */
|
|
wasvis = isvis;
|
|
xpt0.x = xs;
|
|
xpt0.y = ys;
|
|
|
|
/* mark if vis */
|
|
eop->ovis = isvis;
|
|
if (isvis) {
|
|
XPSFillArc (XtD, e_pm, e_gc, xs-SATSZ/2, ys-SATSZ/2,
|
|
SATSZ+1, SATSZ+1, 0, 360*64);
|
|
eop->ox = xs;
|
|
eop->oy = ys;
|
|
}
|
|
}
|
|
|
|
/* draw name first time orbit is visible */
|
|
if (isvis && !drewname && TBISON(eop->wantlbl_w)) {
|
|
e_draworbname (eop, xs, ys);
|
|
drewname = 1;
|
|
}
|
|
|
|
/* process depending on what happens at limb/edge */
|
|
if (isvis && wasvis) {
|
|
/* still visible - add to list -- beware of wrap in cyl mode */
|
|
if (!sproj && nxpts > 0 && abs(xpts[nxpts-1].x-xs) > w/2) {
|
|
/* cyl wrap */
|
|
if (xs > w/2) {
|
|
xpts[nxpts].x = 0;
|
|
xpts[nxpts].y = xpts[nxpts-1].y;
|
|
nxpts++;
|
|
XPSDrawLines (XtD,e_pm,e_gc,xpts,nxpts,CoordModeOrigin);
|
|
xpts[0].x = w;
|
|
xpts[0].y = ys;
|
|
xpts[1].x = xs;
|
|
xpts[1].y = ys;
|
|
nxpts = 2;
|
|
} else {
|
|
xpts[nxpts].x = w;
|
|
xpts[nxpts].y = xpts[nxpts-1].y;
|
|
nxpts++;
|
|
XPSDrawLines (XtD,e_pm,e_gc,xpts,nxpts,CoordModeOrigin);
|
|
xpts[0].x = 0;
|
|
xpts[0].y = ys;
|
|
xpts[1].x = xs;
|
|
xpts[1].y = ys;
|
|
nxpts = 2;
|
|
}
|
|
} else {
|
|
xpts[nxpts].x = xs;
|
|
xpts[nxpts].y = ys;
|
|
nxpts++;
|
|
}
|
|
} else if (!isvis && !wasvis) {
|
|
/* still hidden - just need one history */
|
|
xpts[0].x = xs;
|
|
xpts[0].y = ys;
|
|
nxpts = 1;
|
|
} else if (isvis && !wasvis) {
|
|
/* just became visible around limb - use one history */
|
|
int sx1, sy1, sx2, sy2;
|
|
/* expand circle slightly to avoid 1-pixel grazings */
|
|
lc (wb-1, hb-1, d+2, xs, ys, xpts[0].x, xpts[0].y,
|
|
&sx1, &sy1, &sx2, &sy2);
|
|
xpts[0].x = sx1;
|
|
xpts[0].y = sy1;
|
|
xpts[1].x = xs;
|
|
xpts[1].y = ys;
|
|
nxpts = 2;
|
|
} else if (!isvis && wasvis) {
|
|
/* just went behind limb - draw and start one history */
|
|
int sx1, sy1, sx2, sy2;
|
|
/* expand circle slightly to avoid 1-pixel grazings */
|
|
lc (wb-1, hb-1, d+2, xpts[nxpts-1].x, xpts[nxpts-1].y, xs, ys,
|
|
&sx1, &sy1, &sx2, &sy2);
|
|
xpts[nxpts].x = sx1;
|
|
xpts[nxpts].y = sy1;
|
|
nxpts++;
|
|
XPSDrawLines (XtD, e_pm, e_gc, xpts, nxpts, CoordModeOrigin);
|
|
xpts[0].x = xs;
|
|
xpts[0].y = ys;
|
|
nxpts = 1;
|
|
}
|
|
|
|
wasvis = isvis;
|
|
}
|
|
|
|
/* finish remaining segment */
|
|
if (wasvis && nxpts > 0) {
|
|
if (sproj)
|
|
xpts[nxpts++] = xpt0; /* close */
|
|
XPSDrawLines (XtD, e_pm, e_gc, xpts, nxpts, CoordModeOrigin);
|
|
}
|
|
}
|
|
|
|
/* draw obj's name */
|
|
static void
|
|
e_drawname (eop, d, wb, hb)
|
|
EObj *eop; /* which object */
|
|
int d; /* Earth circle diameter, pixels */
|
|
int wb, hb; /* width and height borders, pixels */
|
|
{
|
|
Trail *tp = &eop->trail[0];
|
|
char *name = tp->t_obj.o_name;
|
|
int nl = strlen (name);
|
|
XCharStruct all;
|
|
int dir, asc, des;
|
|
short x, y;
|
|
|
|
XTextExtents (e_f, name, nl, &dir, &asc, &des, &all);
|
|
XSetForeground (XtD, e_strgc, eop->pix);
|
|
e_coord (d, wb, hb, tp->t_sublat, tp->t_sublng, &x, &y);
|
|
XPSDrawString (XtD, e_pm, e_strgc, x-all.width/2, y-10-des, name, nl);
|
|
}
|
|
|
|
/* draw orbit's name */
|
|
static void
|
|
e_draworbname (EObj *eop, int x, int y)
|
|
{
|
|
Trail *tp = &eop->trail[0];
|
|
char *name = tp->t_obj.o_name;
|
|
int nl = strlen (name);
|
|
XCharStruct all;
|
|
int dir, asc, des;
|
|
|
|
XTextExtents (e_f, name, nl, &dir, &asc, &des, &all);
|
|
XSetForeground (XtD, e_strgc, eop->pix);
|
|
XPSDrawString (XtD, e_pm, e_strgc, x-all.width/2, y-10-des, name, nl);
|
|
}
|
|
|
|
/* this function just captures the code we were inventing over and over to draw
|
|
* polylines.
|
|
*/
|
|
static int
|
|
add_to_polyline (xp, xpsize, i, vis, nxp, max, w, x, y)
|
|
XPoint xp[]; /* working array */
|
|
int xpsize; /* entries in xp[] */
|
|
int i; /* item we are on: 0..max */
|
|
int vis; /* is this point visible */
|
|
int nxp; /* number of items in xp[] in use -- next goes in xp[npx] */
|
|
int max; /* largest item number we will draw */
|
|
int w; /* window width -- used to check top wraps */
|
|
int x, y; /* the point to add to polyline */
|
|
{
|
|
int lx = 0, ly = 0;
|
|
int xwrap = 0;
|
|
|
|
if (vis) {
|
|
xp[nxp].x = x;
|
|
xp[nxp].y = y;
|
|
nxp++;
|
|
}
|
|
|
|
if (nxp > 1) {
|
|
int dx;
|
|
|
|
lx = xp[nxp-2].x;
|
|
dx = lx - xp[nxp-1].x;
|
|
|
|
switch (projection) {
|
|
case CYLI: /* FALLTHRU */
|
|
case CYLG:
|
|
if (dx >= w/2) {
|
|
/* wrapped around right edge */
|
|
xp[nxp-1].x += w;
|
|
ly = xp[nxp-2].y;
|
|
xwrap = 1;
|
|
} else if (-dx >= w/2) {
|
|
/* wrapped around left edge */
|
|
xp[nxp-1].x -= w;
|
|
ly = xp[nxp-2].y;
|
|
xwrap = -1;
|
|
} else
|
|
xwrap = 0;
|
|
break;
|
|
|
|
case SPHI: /* FALLTHRU */
|
|
case SPHG:
|
|
/* never wraps due to not being visible over edge */
|
|
xwrap = 0;
|
|
break;
|
|
|
|
case WXMAP:
|
|
xwrap = abs(dx) > w/10;
|
|
if (xwrap)
|
|
nxp--;
|
|
break;
|
|
}
|
|
|
|
} else
|
|
xwrap = 0;
|
|
|
|
/* draw the line if it just turned invisible, done or wrapped */
|
|
if (!vis || i == max || nxp == xpsize || xwrap != 0) {
|
|
if (nxp > 1)
|
|
XPSDrawLines (XtD, e_pm, e_olgc, xp, nxp, CoordModeOrigin);
|
|
if (nxp == xpsize) {
|
|
xp[0] = xp[nxp-1];
|
|
nxp = 1;
|
|
} else
|
|
nxp = 0;
|
|
|
|
switch (projection) {
|
|
case CYLI: /* FALLTHRU */
|
|
case CYLG:
|
|
/* if we wrapped then pick up fragment on opposite end */
|
|
if (xwrap > 0) {
|
|
/* pick up fragment on left end */
|
|
xp[nxp].x = lx-w; xp[nxp].y = ly; nxp++;
|
|
xp[nxp].x = x; xp[nxp].y = y; nxp++;
|
|
} else if (xwrap < 0) {
|
|
/* pick up fragment on right end */
|
|
xp[nxp].x = lx+w; xp[nxp].y = ly; nxp++;
|
|
xp[nxp].x = x; xp[nxp].y = y; nxp++;
|
|
}
|
|
break;
|
|
|
|
case SPHI: /* FALLTHRU */
|
|
case SPHG:
|
|
break;
|
|
|
|
case WXMAP:
|
|
/* put new at front of line */
|
|
xp[nxp].x = x; xp[nxp].y = y; nxp++;
|
|
break;
|
|
}
|
|
|
|
/* leave at front of line but draw if this is all */
|
|
if (i == max && nxp > 0)
|
|
XPSDrawLines (XtD, e_pm, e_olgc, xp, nxp, CoordModeOrigin);
|
|
}
|
|
|
|
return (nxp);
|
|
}
|
|
|
|
/* mark the mainmenu location */
|
|
static void
|
|
e_mainmenuloc (np, d, wb, hb)
|
|
Now *np;
|
|
unsigned d, wb, hb;
|
|
{
|
|
XSetForeground (XtD, e_olgc, ecolors[HEREC].p);
|
|
e_drawcross (d, wb, hb, lat, lng, PLUSS);
|
|
}
|
|
|
|
/* mark the location of a solar ecipse, if any.
|
|
*
|
|
* N.B. this code is geometrically correct for all objects, but in practice
|
|
* only the sun and moon are computed accurately enough by xephem to make this
|
|
* worth while for now. in particular, I have tried tests against several S&T
|
|
* tables of minor planet occultations and while the asteroids are computed
|
|
* well enough for visual identification remember that at even 1 AU the earth
|
|
* only subtends 18 arc seconds and the asteroids are not computed *that*
|
|
* accurately (especially since we do not yet include perturbations).
|
|
*
|
|
* I will try to describe the algorithm: the exective summary is that we
|
|
* are striving for the spherical arc subtended by the intersection of a line
|
|
* from one object and the earth's center and the line from the other object
|
|
* to the earth's center.
|
|
*
|
|
* N.B. I tried just computing the intersection of a line connecting the two
|
|
* objects and a unit sphere but it suffered from terrible numerical instabilty.
|
|
*
|
|
* start in a plane defined by the center of the earth, the north pole and
|
|
* object obj0. label the center of the earth as O, the location of object 0
|
|
* as P0, and place object 1 someplace off the line O-P0 and label it P1.
|
|
* what you have actually placed is the location of P1 as it projected onto
|
|
* this place; ie, we are only working with dec here. define decA as the
|
|
* angle P1-O-P0; it is so named because it is the amount of declication
|
|
* subtended from P0 to P1. Project the line P0-P1 back to a line
|
|
* perpendicular to the line O-P0 at O. decD is the distance from O to the
|
|
* point where P0-P1 intersects the line. if it is less than the earth radius
|
|
* we have an occultation! now do all this again only this time place
|
|
* yourself in a plane defined by the real locations of O, P0 and P1. and
|
|
* repeat everything except this time use the real angled subtended in the
|
|
* sky between P0 and P1 (not just the dec difference). this angle we define
|
|
* as skyA (and its projection back onto a plane perpendicular to P0-P1
|
|
* through O we call skyD). what we want next is the spherical angle
|
|
* subtended between the point at which O-P0 intersects the earth's surface
|
|
* (which is just the geocentric coords of P0) and the point where a line
|
|
* from the tip of skyD to P1 intersects the earth's surface. we call this
|
|
* skyT (I used tau in my original sketch) and I will let you work out the
|
|
* trig (it's just planar trig since you are working in the O-P0-P1 plane).
|
|
* this gives us the spherical angle between the two lines and the earth
|
|
* surface; now all we need is the angle.image yourself at P0 now looking
|
|
* right at O. we see decD as a vertical line and SkyD as a line going off
|
|
* from O at an angle somewhere. the angle between these lines we define as
|
|
* theta. knowing decD and skyD and knowing that there is a right angle at
|
|
* the tip of decD between O and the tip of skyD we can compute the angle
|
|
* between them. theta. now just use a little spherical trig to find where
|
|
* our arc ends up, compute the new RA, compute longitude by subtracting
|
|
* gst, set latitude to dec, project and draw!
|
|
*/
|
|
static void
|
|
e_soleclipse (np, d, wb, hb)
|
|
Now *np;
|
|
unsigned d, wb, hb;
|
|
{
|
|
Obj *op0 = db_basic (SUN); /* op0 must be the further one */
|
|
Obj *op1 = db_basic (MOON);
|
|
Obj obj0, obj1; /* use copies */
|
|
double r0, r1; /* dist to objects, in earth radii */
|
|
double theta; /* angle between projections */
|
|
double decD, decA; /* dec-only proj dist and angle */
|
|
double skyD, skyA, skyP, skyT; /* full sky projection */
|
|
Now now; /* local copy to compute EOD info */
|
|
double lst, gst; /* local and UTC time */
|
|
double lt, lg; /* lat/long */
|
|
double sD, dRA;
|
|
|
|
now = *np;
|
|
obj0 = *op0;
|
|
obj1 = *op1;
|
|
|
|
now.n_epoch = EOD;
|
|
(void) obj_cir (&now, &obj0);
|
|
if (is_ssobj(&obj0))
|
|
r0 = obj0.s_edist*(MAU/ERAD); /* au to earth radii */
|
|
else
|
|
r0 = 1e7; /* way past pluto */
|
|
|
|
(void) obj_cir (&now, &obj1);
|
|
if (is_ssobj(&obj1))
|
|
r1 = obj1.s_edist*(MAU/ERAD); /* au to earth radii */
|
|
else
|
|
r1 = 1e7; /* way past pluto */
|
|
|
|
decA = obj1.s_gaedec - obj0.s_gaedec;
|
|
decD = r0*r1*sin(decA)/(r0 - r1); /* similar triangles */
|
|
if (fabs(decD) >= 1.0)
|
|
return;
|
|
|
|
skyA = acos (sin(obj0.s_gaedec)*sin(obj1.s_gaedec) +
|
|
cos(obj0.s_gaedec)*cos(obj1.s_gaedec) *
|
|
cos(obj0.s_gaera-obj1.s_gaera));
|
|
skyD = r0*r1*sin(skyA)/(r0 - r1); /* similar triangles */
|
|
if (fabs(skyD) >= 1.0)
|
|
return;
|
|
|
|
/* skyP is angle subtended by skyD as seen from obj0 (I called it psi).
|
|
* skyT is angle subtended by line from earth center to obj0 to a
|
|
* point where the line from obj0 to the tip of skyD intersects the
|
|
* earth surface (I called it tau).
|
|
*/
|
|
skyP = atan(skyD/r0);
|
|
skyT = asin(skyD*r0/sqrt(r0*r0+skyD*skyD)) - skyP;
|
|
|
|
theta = acos(decD/skyD);
|
|
solve_sphere (theta, skyT, sin(obj0.s_gaedec), cos(obj0.s_gaedec),
|
|
&sD, &dRA);
|
|
|
|
lt = asin(sD);
|
|
|
|
if (obj1.s_gaera > obj0.s_gaera)
|
|
dRA = -dRA; /* eastward */
|
|
|
|
lst = obj0.s_gaera - dRA;
|
|
utc_gst (mjd_day(mjd), mjd_hr(mjd), &gst);
|
|
lg = lst - hrrad(gst);
|
|
while (lg < -PI) lg += 2*PI;
|
|
while (lg > PI) lg -= 2*PI;
|
|
|
|
XSetForeground (XtD, e_olgc, ecolors[ECLIPSEC].p);
|
|
e_drawcross (d, wb, hb, lt, lg, CROSSH);
|
|
}
|
|
|
|
/* given a height above the earth, in meters, and an altitude above the
|
|
* horizon, in rads, return the great-circle angular distance from the subpoint
|
|
* to the point at which the given height appears at the given altitude, in
|
|
* rads.
|
|
* N.B. beware of negative heights (deorbited ;-))
|
|
*/
|
|
static void
|
|
e_viewrad (np, height, alt, radp)
|
|
Now *np; /* refraction circumstances */
|
|
double height; /* satellite elevation, m above mean earth */
|
|
double alt; /* viewing altitude, rads above horizon */
|
|
double *radp; /* great-circle distance from subpoint to viewing circle, rads*/
|
|
{
|
|
/* remove effect of refraction from geometry */
|
|
unrefract (pressure, temp, alt, &alt);
|
|
|
|
if (height > 0)
|
|
*radp = acos(ERAD/(ERAD+height)*cos(alt)) - alt;
|
|
else
|
|
*radp = 0;
|
|
}
|
|
|
|
/* make the first entry in the trail list, ie the current position of eop->op,
|
|
* correct as of *np. then, if desired, discard any existing trail history.
|
|
* return 0 if ok else -1 if no memory.
|
|
*/
|
|
static void
|
|
e_resettrail(eop, np, discard)
|
|
EObj *eop;
|
|
Now *np;
|
|
int discard;
|
|
{
|
|
Obj *op = eop->op;
|
|
Trail *tp = eop->trail;
|
|
|
|
db_update (op);
|
|
if (discard) {
|
|
if (eop->trail) {
|
|
free ((char *)eop->trail);
|
|
eop->trail = NULL;
|
|
}
|
|
eop->ntrail = 0;
|
|
tp = e_growtrail(eop);
|
|
}
|
|
|
|
/* first entry is for the current time, regardless of whether there
|
|
* are additional entries.
|
|
*/
|
|
tp = &eop->trail[0];
|
|
|
|
tp->t_lbl = 0;
|
|
tp->t_now = *np;
|
|
tp->t_obj = *op;
|
|
e_subobject (&tp->t_now, &tp->t_obj, &tp->t_sublat, &tp->t_sublng);
|
|
}
|
|
|
|
/* called from the trails facilty to build up a trail.
|
|
* do it and refresh the view.
|
|
* client is index into eobjs[].
|
|
* return 0 if ok, else -1.
|
|
*/
|
|
/* ARGSUSED */
|
|
static int
|
|
e_mktrail (ts, statep, client)
|
|
TrTS ts[];
|
|
TrState *statep;
|
|
XtPointer client;
|
|
{
|
|
EObj *eop = &eobjs[(long int)client];
|
|
Obj *op = eop->op;
|
|
Now *np = mm_get_now();
|
|
int wastrail = eop->ntrail > 1;
|
|
int i;
|
|
|
|
watch_cursor (1);
|
|
|
|
/* erase all but the first entry (ie, leave current alone) */
|
|
db_update (op);
|
|
e_resettrail(eop, np, 1);
|
|
|
|
for (i = 0; i < statep->nticks; i++, ts++) {
|
|
Trail *tp;
|
|
Now now;
|
|
|
|
/* check date range */
|
|
now = *np;
|
|
now.n_mjd = ts->t;
|
|
if (dateOK (&now, op) < 0)
|
|
continue;
|
|
|
|
/* ok, add to trail */
|
|
tp = e_growtrail(eop);
|
|
if (!tp)
|
|
return (-1);
|
|
tp->t_lbl = ts->lbl;
|
|
tp->t_now = now;
|
|
tp->t_obj = *op;
|
|
(void) obj_cir (&tp->t_now, &tp->t_obj);
|
|
e_subobject (&tp->t_now, &tp->t_obj, &tp->t_sublat, &tp->t_sublng);
|
|
}
|
|
|
|
/* save trail setup as next default */
|
|
eop->trstate = *statep;
|
|
|
|
/* update trail state resource */
|
|
tr_setres (etrres, statep);
|
|
|
|
/* draw the trail display if desired but beware getting called while
|
|
* not up.
|
|
*/
|
|
if (TBISON(eop->showtr_w) && TBISON(eop->show_w) && isUp(eshell_w)) {
|
|
if (wastrail)
|
|
e_all(0); /* erase old and draw new */
|
|
else if (TBISON(eop->show_w)) {
|
|
/* just draw new */
|
|
int w, h, d, wb, hb;
|
|
|
|
e_getcircle (&w, &h, &d, &wb, &hb);
|
|
e_drawtrail (eop, d, wb, hb);
|
|
e_copy_pm();
|
|
}
|
|
}
|
|
|
|
watch_cursor (0);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* grow the trails list by one and return the address of the new entry.
|
|
*/
|
|
static Trail *
|
|
e_growtrail (eop)
|
|
EObj *eop;
|
|
{
|
|
eop->trail = (Trail *) XtRealloc ((char *)eop->trail,
|
|
(eop->ntrail+1)*sizeof(Trail));
|
|
return (&eop->trail[eop->ntrail++]);
|
|
}
|
|
/* fetch the weather map, and fill wxgifpix and wxxcols[]
|
|
* return 0 if ok, else -1
|
|
*/
|
|
static int
|
|
e_getwxgif()
|
|
{
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
unsigned char rawgif[200000];
|
|
int nrawgif;
|
|
char buf[1024];
|
|
int w, h;
|
|
int fd;
|
|
|
|
/* open test case, else real network */
|
|
fd = openh ("/tmp/latest_cmoll.gif", O_RDONLY);
|
|
if (fd >= 0) {
|
|
nrawgif = read (fd, rawgif, sizeof(rawgif));
|
|
close (fd);
|
|
} else {
|
|
int isgif;
|
|
int length;
|
|
int nr;
|
|
|
|
/* announce net activity and give user a way to stop */
|
|
stopd_up();
|
|
|
|
/* make connection to server for the file */
|
|
xe_msg (0, "Getting\nhttp://%s%s", wxhost, wxfile);
|
|
(void) sprintf (buf, "GET http://%s%s HTTP/1.0\r\nUser-Agent: xephem/%s\r\n\r\n",
|
|
wxhost, wxfile, PATCHLEVEL);
|
|
fd = httpGET (wxhost, buf, buf);
|
|
if (fd < 0) {
|
|
xe_msg (1, "http get:\n%s", buf);
|
|
stopd_down();
|
|
return (-1);
|
|
}
|
|
|
|
/* read header, looking for some header info */
|
|
isgif = 0;
|
|
length = 0;
|
|
while (recvline (fd, buf, sizeof(buf)) > 1) {
|
|
xe_msg (0, "Rcv: %s", buf);
|
|
if (strstr (buf, "image/gif"))
|
|
isgif = 1;
|
|
if (strstr (buf, "Content-Length"))
|
|
length = atoi (buf+15);
|
|
}
|
|
if (!isgif) {
|
|
while (recvline (fd, buf, sizeof(buf)) > 1)
|
|
xe_msg (0, "Rcv: %s", buf);
|
|
close (fd);
|
|
stopd_down();
|
|
return (-1);
|
|
}
|
|
if (length == 0)
|
|
length = 100000; /* ?? */
|
|
|
|
/* read gif into rawgif[] */
|
|
pm_up();
|
|
for (nrawgif = 0; nrawgif < sizeof(rawgif); nrawgif += nr) {
|
|
pm_set (100*nrawgif/length);
|
|
nr = readbytes (fd, rawgif+nrawgif, 4096);
|
|
if (nr < 0) {
|
|
xe_msg (1, "%s:\n%s", wxhost, syserrstr());
|
|
stopd_down();
|
|
pm_down();
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
if (nr == 0)
|
|
break;
|
|
}
|
|
stopd_down();
|
|
pm_down();
|
|
close (fd);
|
|
if (nr > 0) {
|
|
xe_msg (1, "File too large");
|
|
return (-1);
|
|
}
|
|
}
|
|
|
|
/* uncompress the gif into X terms */
|
|
if (wxgifpix) {
|
|
free (wxgifpix);
|
|
wxgifpix = NULL;
|
|
freeXColors (dsp, xe_cm, wxxcols, 256);
|
|
}
|
|
if (gif2X (dsp,xe_cm,rawgif,nrawgif,&w,&h,&wxgifpix,wxxcols,buf)<0) {
|
|
xe_msg (1, "Gif: %s", buf);
|
|
return (-1);
|
|
}
|
|
if (w != WXM_W || h != WXM_H) {
|
|
xe_msg (1, "Expecting %dx%d but found %dx%d", WXM_W, WXM_H, w,h);
|
|
free (wxgifpix);
|
|
wxgifpix = NULL;
|
|
freeXColors (dsp, xe_cm, wxxcols, 256);
|
|
return (-1);
|
|
}
|
|
|
|
/* ok */
|
|
return (0);
|
|
}
|
|
|
|
/* create an XImage of size wXh.
|
|
* return XImage * if ok else NULL and xe_msg().
|
|
*/
|
|
static XImage *
|
|
e_create_xim (w, h)
|
|
int w, h;
|
|
{
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
XImage *xip;
|
|
int mdepth;
|
|
int mbpp;
|
|
int nbytes;
|
|
char *data;
|
|
|
|
/* establish depth and bits per pixel */
|
|
get_something (e_da_w, XmNdepth, (XtArgVal)&mdepth);
|
|
if (mdepth < 8) {
|
|
xe_msg (1, "Require at least 8 bit pixel depth");
|
|
return (NULL);
|
|
}
|
|
mbpp = mdepth>=17 ? 32 : (mdepth >= 9 ? 16 : 8);
|
|
nbytes = w*h*mbpp/8;
|
|
|
|
/* get memory for image pixels. */
|
|
data = malloc (nbytes);
|
|
if (!data) {
|
|
xe_msg (1,"Can not get %d bytes for image pixels", nbytes);
|
|
return (NULL);
|
|
}
|
|
|
|
/* create the XImage */
|
|
xip = XCreateImage (dsp, DefaultVisual (dsp, DefaultScreen(dsp)),
|
|
/* depth */ mdepth,
|
|
/* format */ ZPixmap,
|
|
/* offset */ 0,
|
|
/* data */ data,
|
|
/* width */ w,
|
|
/* height */ h,
|
|
/* pad */ mbpp,
|
|
/* bpl */ 0);
|
|
if (!xip) {
|
|
xe_msg (1, "Can not create shadow XImage");
|
|
free ((void *)data);
|
|
return (NULL);
|
|
}
|
|
|
|
xip->bitmap_bit_order = LSBFirst;
|
|
xip->byte_order = LSBFirst;
|
|
|
|
/* ok */
|
|
return (xip);
|
|
}
|
|
|
|
/* given a time and location, return 1 if location is in sunlight, else 0 */
|
|
static int
|
|
e_issunlit (np, l, L)
|
|
Now *np;
|
|
double l, L;
|
|
{
|
|
static double last_mjd;
|
|
static double csslat, ssslat;
|
|
static double sslong;
|
|
double ca;
|
|
|
|
if (mjd != last_mjd) {
|
|
double sslat;
|
|
e_subobject (np, db_basic(SUN), &sslat, &sslong);
|
|
csslat = cos (sslat);
|
|
ssslat = sin (sslat);
|
|
last_mjd = mjd;
|
|
}
|
|
solve_sphere (L - sslong, PI/2-l, ssslat, csslat, &ca, NULL);
|
|
return (ca > 0.);
|
|
}
|
|
|
|
/* return 1 if the given wxgifpix is gray, else 0 */
|
|
static int
|
|
e_wxisgray (p)
|
|
int p;
|
|
{
|
|
int r = (int)wxxcols[p].red >> 8;
|
|
int g = (int)wxxcols[p].green >> 8;
|
|
int b = (int)wxxcols[p].blue >> 8;
|
|
int mean = (r+g+b)/3;
|
|
int gray = abs(r-mean)<20 && abs(g-mean)<20 && abs(b-mean)<20;
|
|
|
|
return (gray);
|
|
}
|
|
|
|
/* see that e_wxpm exists and is filled properly.
|
|
* return 0 if ok, else -1
|
|
*/
|
|
static int
|
|
e_newwxpm()
|
|
{
|
|
Display *dsp = XtDisplay(e_da_w);
|
|
Window win = RootWindow(dsp, DefaultScreen(dsp));
|
|
unsigned long black = BlackPixel (dsp, DefaultScreen(dsp));
|
|
Now *np = mm_get_now();
|
|
XImage *xip;
|
|
int x, y;
|
|
|
|
/* required */
|
|
if (!wxgifpix) {
|
|
printf ("newwxpm but no wxgifpix!\n");
|
|
abort();
|
|
}
|
|
|
|
/* create XImage */
|
|
xip = e_create_xim (WXM_W, WXM_H);
|
|
if (!xip)
|
|
return (-1);
|
|
|
|
/* fill XImage with weather map */
|
|
for (y = 0; y < WXM_H; y++) {
|
|
int yrow = y*WXM_W;
|
|
for (x = 0; x < WXM_W; x++) {
|
|
int gp = (int)wxgifpix[x + yrow];
|
|
unsigned long p;
|
|
double l, L;
|
|
|
|
p = !e_uncoord (WXMAP,0,0,0,x,y,&l,&L) || !wants[SUNLIGHT] ||
|
|
e_issunlit (np,l,L) || e_wxisgray (gp)
|
|
? wxxcols[gp].pixel : black;
|
|
XPutPixel (xip, x, y, p);
|
|
}
|
|
}
|
|
|
|
/* create pixmap if necessary and fill with weather map */
|
|
if (!e_wxpm)
|
|
e_wxpm = XCreatePixmap (dsp, win, WXM_W, WXM_H, xip->depth);
|
|
XPutImage (dsp, e_wxpm, e_gc, xip, 0, 0, 0, 0, WXM_W, WXM_H);
|
|
|
|
/* ok */
|
|
free ((void *)xip->data);
|
|
xip->data = NULL;
|
|
XDestroyImage (xip);
|
|
return (0);
|
|
}
|
|
|
|
/* see that e_wxpm is ready.
|
|
* return 0 if ok, else -1.
|
|
*/
|
|
static int
|
|
e_setupwxpm (reload, rebuild)
|
|
int reload;
|
|
int rebuild;
|
|
{
|
|
static double last_mjd;
|
|
Now *np = mm_get_now();
|
|
int newpm;
|
|
|
|
watch_cursor(1);
|
|
|
|
/* insure we have the weather gif */
|
|
newpm = reload || (e_wxpm == (Pixmap)0);
|
|
if ((!wxgifpix || reload) && e_getwxgif() < 0) {
|
|
watch_cursor(0);
|
|
return (-1);
|
|
}
|
|
|
|
/* build the pixmap, as necessary */
|
|
if (rebuild || newpm || (wants[SUNLIGHT] && mjd != last_mjd)) {
|
|
if (e_newwxpm() < 0) {
|
|
watch_cursor(0);
|
|
return (-1);
|
|
}
|
|
last_mjd = mjd;
|
|
}
|
|
|
|
/* e_wxpm is ready */
|
|
watch_cursor(0);
|
|
return (0);
|
|
}
|
|
|
|
/* convert lat/long to x/y on www.ssec.wisc.edu/data/comp/latest_cmoll.gif */
|
|
static void
|
|
mollweide_llxy (l, L, xp, yp)
|
|
double l, L; /* lat, long, rads, +N, +E */
|
|
short *xp, *yp; /* gif location */
|
|
{
|
|
double tmp;
|
|
|
|
tmp = 1.116*sin(.7071*l);
|
|
*yp = (short)((WXM_TY+WXM_BY)/2 - tmp*(WXM_BY-WXM_TY)/2);
|
|
range (&L, 2*PI);
|
|
if (L > PI)
|
|
L -= 2*PI;
|
|
tmp = L/PI*sqrt(1. - tmp*tmp);
|
|
*xp = (short)((WXM_LX+WXM_RX)/2 + tmp*(WXM_RX-WXM_LX)/2);
|
|
}
|
|
|
|
/* convert x/y to lat/long on www.ssec.wisc.edu/data/comp/latest_cmoll.gif.
|
|
* return 1 if actually on the earth map, else 0.
|
|
*/
|
|
static int
|
|
mollweide_xyll (x, y, lp, Lp)
|
|
int x, y; /* gif location */
|
|
double *lp, *Lp; /* lat, long, rads, +N, +E */
|
|
{
|
|
double fx, fy;
|
|
|
|
fy = 2.*((WXM_BY + WXM_TY)/2 - y)/(WXM_BY - WXM_TY);
|
|
if (fabs(fy) > 1.)
|
|
return (0);
|
|
*lp = 1.414*asin(fy/1.116);
|
|
fx = 2.*(x - (WXM_RX + WXM_LX)/2)/(WXM_RX - WXM_LX);
|
|
*Lp = PI*fx/sqrt(1. - fy*fy);
|
|
return (fabs(*Lp) <= PI);
|
|
}
|
|
|
|
/* load the daytime earth image file into deipix and colors in deixcols.
|
|
* return 0 if ok, else write xe_msg and return -1.
|
|
*/
|
|
static int
|
|
loaddei()
|
|
{
|
|
struct stat s;
|
|
char *rawgif;
|
|
int nrawgif;
|
|
char buf[1024];
|
|
char fn[256];
|
|
int n, fd;
|
|
|
|
/* open map file */
|
|
(void) sprintf (fn, "%s/auxil/dearth.gif", getShareDir());
|
|
fd = openh (fn, 0);
|
|
if (fd < 0) {
|
|
xe_msg (1, "%s: %s", fn, syserrstr());
|
|
return (-1);
|
|
}
|
|
|
|
/* read in */
|
|
fstat (fd, &s);
|
|
n = (int)s.st_size;
|
|
rawgif = malloc (n);
|
|
if (!rawgif) {
|
|
xe_msg (1, "%s: can not get %d to read", fn, n);
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
nrawgif = read (fd, rawgif, n);
|
|
if (nrawgif < 0) {
|
|
xe_msg (1, "%s: %s", fn, syserrstr());
|
|
free (rawgif);
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
if (nrawgif == 0) {
|
|
xe_msg (1, "%s: contains 0 bytes", fn);
|
|
free (rawgif);
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
close (fd);
|
|
|
|
/* crack open */
|
|
if (gif2X (XtD, xe_cm, (unsigned char *)rawgif, nrawgif, &deiw, &deih,
|
|
&deipix, deixcols, buf) < 0) {
|
|
xe_msg (1, "%s: %s", fn, buf);
|
|
free (rawgif);
|
|
return (-1);
|
|
}
|
|
|
|
/* ok */
|
|
free (rawgif);
|
|
return (0);
|
|
}
|
|
|
|
/* load the nighttime earth image file into neipix and colors in deixcols.
|
|
* return 0 if ok, else write xe_msg and return -1.
|
|
*/
|
|
static int
|
|
loadnei()
|
|
{
|
|
struct stat s;
|
|
char *rawgif;
|
|
int nrawgif;
|
|
char buf[1024];
|
|
char fn[256];
|
|
int n, fd;
|
|
|
|
/* open map file */
|
|
(void) sprintf (fn, "%s/auxil/nearth.gif", getShareDir());
|
|
fd = openh (fn, 0);
|
|
if (fd < 0) {
|
|
xe_msg (1, "%s: %s", fn, syserrstr());
|
|
return (-1);
|
|
}
|
|
|
|
/* read in */
|
|
fstat (fd, &s);
|
|
n = (int)s.st_size;
|
|
rawgif = malloc (n);
|
|
if (!rawgif) {
|
|
xe_msg (1, "%s: can not get %d to read", fn, n);
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
nrawgif = read (fd, rawgif, n);
|
|
if (nrawgif < 0) {
|
|
xe_msg (1, "%s: %s", fn, syserrstr());
|
|
free (rawgif);
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
if (nrawgif == 0) {
|
|
xe_msg (1, "%s: contains 0 bytes", fn);
|
|
free (rawgif);
|
|
close (fd);
|
|
return (-1);
|
|
}
|
|
close (fd);
|
|
|
|
/* crack open */
|
|
if (gif2X (XtD, xe_cm, (unsigned char *)rawgif, nrawgif, &neiw, &neih,
|
|
&neipix, neixcols, buf) < 0) {
|
|
xe_msg (1, "%s: %s", fn, buf);
|
|
free (rawgif);
|
|
return (-1);
|
|
}
|
|
|
|
/* ok */
|
|
free (rawgif);
|
|
return (0);
|
|
}
|
|
|
|
/* render deipix and neipix into e_pm */
|
|
static void
|
|
drawei (ww, wh, d, xb, yb)
|
|
unsigned int ww, wh, d, xb, yb;
|
|
{
|
|
Now *np = mm_get_now();
|
|
Display *dsp = XtD;
|
|
unsigned long p;
|
|
XImage *xip;
|
|
double lt, lg;
|
|
int wx, wy;
|
|
|
|
/* required */
|
|
if (!deipix) {
|
|
printf ("no deipix!\n");
|
|
abort();
|
|
}
|
|
if (!neipix) {
|
|
printf ("no neipix!\n");
|
|
abort();
|
|
}
|
|
|
|
/* create XImage */
|
|
xip = e_create_xim (ww, wh);
|
|
if (!xip)
|
|
return;
|
|
|
|
/* fill XImage with earth image */
|
|
for (wy = 0; wy < wh; wy++) {
|
|
for (wx = 0; wx < ww; wx++) {
|
|
if (!e_uncoord (projection, d, xb, yb, wx, wy, <, &lg))
|
|
p = e_bg;
|
|
else if (!wants[SUNLIGHT] || e_issunlit (np,lt,lg)) {
|
|
int eix = (int)(deiw*(lg+PI)/(2*PI));
|
|
int eiy = deiw*(int)(deih*(PI/2-lt)/PI);
|
|
int pi = (int)deipix[eix + eiy];
|
|
p = deixcols[pi].pixel;
|
|
} else if (wants[NITELITES]) {
|
|
int eix = (int)(neiw*(lg+PI)/(2*PI));
|
|
int eiy = neiw*(int)(neih*(PI/2-lt)/PI);
|
|
int pi = (int)neipix[eix + eiy];
|
|
p = neixcols[pi].pixel;
|
|
} else
|
|
p = e_bg;
|
|
XPutPixel (xip, wx, wy, p);
|
|
}
|
|
}
|
|
|
|
/* fill e_pm with image */
|
|
XPutImage (dsp, e_pm, e_gc, xip, 0, 0, 0, 0, ww, wh);
|
|
|
|
/* ok */
|
|
free ((void *)xip->data);
|
|
xip->data = NULL;
|
|
XDestroyImage (xip);
|
|
}
|
|
|
|
/* given lat long find Great cirle distance and bearing from Main site.
|
|
* distance will be in m.
|
|
*/
|
|
static void
|
|
e_greatCircle (double lt, double lg, double *dp, double *bp)
|
|
{
|
|
Now *np = mm_get_now();
|
|
double ca;
|
|
|
|
solve_sphere (lg-lng, PI/2-lt, sin(lat), cos(lat), &ca, bp);
|
|
*dp = acos(ca)*ERAD; /* arc to distance */
|
|
|
|
}
|
|
|
|
/* given window info and a lat/lng, draw the great circle through it
|
|
* and the Main site.
|
|
*/
|
|
static void
|
|
e_plotGreatCircle (unsigned d, unsigned wb, unsigned hb, double lt, double lg)
|
|
{
|
|
Now *np = mm_get_now();
|
|
double dist, bear;
|
|
double ca, a, B;
|
|
|
|
/* draw fresh map */
|
|
e_map (np);
|
|
|
|
/* find bearing from Main to here */
|
|
e_greatCircle (lt, lg, &dist, &bear);
|
|
|
|
/* find point normal to plane define by center, here and Main loc */
|
|
solve_sphere (bear+PI/2, PI/2, sin(lat), cos(lat), &ca, &B);
|
|
a = acos(ca);
|
|
|
|
/* draw circle with radius 90 degrees about said point */
|
|
e_drawcircle (ecolors[GREATC].p, d, wb, hb, PI/2-a, lng+B, PI/2);
|
|
|
|
e_copy_pm();
|
|
}
|
|
|
|
|