mirror of https://github.com/XEphem/XEphem.git
3946 lines
105 KiB
C
3946 lines
105 KiB
C
/* code to manage the stuff on the moon display.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/Form.h>
|
|
#include <Xm/Frame.h>
|
|
#include <Xm/DrawingA.h>
|
|
#include <Xm/Label.h>
|
|
#include <Xm/PushB.h>
|
|
#include <Xm/CascadeB.h>
|
|
#include <Xm/Scale.h>
|
|
#include <Xm/List.h>
|
|
#include <Xm/ToggleB.h>
|
|
#include <Xm/RowColumn.h>
|
|
#include <Xm/Separator.h>
|
|
#include <Xm/ScrolledW.h>
|
|
|
|
#include "xephem.h"
|
|
#include "lilxml.h"
|
|
|
|
typedef struct {
|
|
double curlt, curlg; /* lat/long under cursor */
|
|
double cursunalt; /* sun alt under cursor now */
|
|
double curnsrt; /* next sunrise under cursor, tz mjd */
|
|
double curnsst; /* next sunset under cursor, tz mjd */
|
|
double srlng; /* longitude of the rising sun */
|
|
double sslat; /* lat of subsolar point */
|
|
double llat, llong; /* current libration in lat and long */
|
|
double limb; /* limb angle, rads ccw from up */
|
|
double tilt; /* angle of limb tilt, degrees towards earth */
|
|
double age; /* days since new moon */
|
|
} MoonInfo;
|
|
|
|
typedef struct {
|
|
Obj *op; /* points into real db for more info */
|
|
int x, y; /* X location on mda_w */
|
|
} SkyObj;
|
|
|
|
static SkyObj *skyobjs; /* malloced list of objects in sky background */
|
|
static int nskyobjs; /* number of objects in skyobjs[] list */
|
|
static char mooncategory[] = "Moon"; /* Save category */
|
|
|
|
#define MAXR 10 /* max gap when picking sky objects, pixels */
|
|
|
|
static void resetSkyObj (void);
|
|
static void addSkyObj (Obj *op, int x, int y);
|
|
static FILE *mlo_open (char *base);
|
|
static int mlo_installed(void);
|
|
static Obj *closeSkyObj (int x, int y);
|
|
static void fill_skypopup (Obj *op);
|
|
static void m_create_skypopup (void);
|
|
|
|
static void m_create_shell (void);
|
|
static void mlo_create_shell (void);
|
|
static void m_create_msform (void);
|
|
static void m_create_esform (void);
|
|
static void m_set_buttons (int whether);
|
|
static void m_eshine_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_mloop_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_eshineclose_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_eshineup_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_anim_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_elab_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_select_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_mstats_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_mstats_close_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_activate_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_print_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_print (void);
|
|
static void m_ps_annotate (void);
|
|
static void m_popdown_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void mlo_popdown_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void mlo_select_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void mlo_ann_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_close_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void mlo_close_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_init_gcs (void);
|
|
static void m_init_gcs (void);
|
|
static void m_help_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_helpon_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_pl_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_copy_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_showlo_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_option_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_shrink_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_sizewidgets (void);
|
|
static int xy2ll (int x, int y, double *ltp, double *lgp);
|
|
static int ll2xy (double lt, double lg, int *xp, int *yp);
|
|
static int overMoon (int x, int y);
|
|
static void m_pointer_eh (Widget w, XtPointer client, XEvent *ev,
|
|
Boolean *continue_to_dispatch);
|
|
static void m_exp_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_redraw (void);
|
|
static void m_refresh (XExposeEvent *ep);
|
|
static void m_getsize (Drawable d, unsigned *wp, unsigned *hp,unsigned *dp);
|
|
static void m_info (Now *np);
|
|
static void m_pinfo (void);
|
|
static void m_draw (void);
|
|
static int mxim_create (void);
|
|
static void image_setup (void);
|
|
static int m_esedges (int y, double sinsrl, int right, int *lxp, int *rxp);
|
|
static void m_clip_mask_setup (void);
|
|
static void m_free_clip_mask (void);
|
|
static int m_shrink (int f);
|
|
static void mBWdither (void);
|
|
static void m_resize (unsigned char *in, int nr, int nc, int f,
|
|
unsigned char *out);
|
|
static void m_umbra (void);
|
|
static void fliptb (void);
|
|
static void fliplr (void);
|
|
static void m_fillSL(void);
|
|
static void mi_draw (void);
|
|
static int m_ano (double *latp, double *lngp, int *xp, int *yp, int w2x,
|
|
int arg);
|
|
static void m_orientation (void);
|
|
static void m_labels (void);
|
|
static void m_sky (void);
|
|
static void m_grid (void);
|
|
static void m_sub (void);
|
|
static void m_mark_libr (void);
|
|
static void m_reportloc (Display *dsp, Window win, int x, int y);
|
|
|
|
static void makeGlassImage (Display *dsp);
|
|
static void makeGlassGC (Display *dsp, Window win);
|
|
static void doGlass (Display *dsp, Window win, int b1p, int m1,
|
|
int b1r, int wx, int wy);
|
|
static void fillGlass (int wx, int wy);
|
|
static void m_readdb (void);
|
|
static void m_freedb (void);
|
|
static void m_popup (XEvent *ep);
|
|
|
|
/* stuff for the moon image.
|
|
* obviously, size and centering metrics are tuned to a particular image.
|
|
*/
|
|
#define XEVERS 3 /* required version in header */
|
|
#define MOONRAD 311 /* radius of moon image, pixels */
|
|
#define TOPMARG 25 /* top margin of moon image, pixels */
|
|
#define LEFTMARG 25 /* left margin of moon image, pixels */
|
|
#define MNROWS 670 /* number of rows in moon image */
|
|
#define MNCOLS 670 /* number of columns in moon image */
|
|
#define BORD 150 /* extra drawing area border for labels/stars */
|
|
#define CLNG degrad(-4.6) /* longitude of image center, rads east */
|
|
#define CLAT degrad(1.0) /* latitude of image center, rads north */
|
|
#define MOVIE_STEPSZ (2.) /* movie step size without stars, hours */
|
|
#define MOVIE_SSTEPSZ (1./60) /* movie step size with stars, hours */
|
|
|
|
static unsigned char *mimage; /* malloced array of full-size moon image */
|
|
static Pixel *mgray; /* gray-scale ramp for drawing image */
|
|
static int nmgray; /* number of pixels usable in mgray[] */
|
|
static Pixel mbg; /* background color for image */
|
|
static int mdepth; /* depth of image, in bits */
|
|
static int mbpp; /* bits per pixel in image: 1, 8, 16 or 32 */
|
|
static int topmarg, leftmarg; /* current TOPMARG/LEFTMARG after resize */
|
|
static int moonrad; /* current MOONRAD after resize, pixels */
|
|
static int mnrows, mncols; /* current size of image after resize, pixels */
|
|
static XImage *m_xim; /* XImage of moon now at current size */
|
|
static int mshrink; /* current shrink factor: 1 .. MAXSHRINK */
|
|
static MoonInfo minfo; /* stats about the current situation */
|
|
static Pixmap m_clip_mask; /* clipping mask used for creating m_pm from m_xim */
|
|
|
|
#define MAXSHRINK 6 /* max shrink factor */
|
|
#define SYNP 29.53 /* average synodic period, days */
|
|
#define SIDP 27.32 /* average sidereal period, days */
|
|
#define MINKM 125 /* smallest feature we ever label, km */
|
|
#define ESHINEF 10 /* earthshine factor range: 0 .. this */
|
|
#define LMFRAC 40 /* libr marker is 1/x this of total size */
|
|
#define LGAP 20 /* gap between NSEW labels and image edge */
|
|
#define FMAG 12 /* faintest mag of sky background object */
|
|
|
|
/* main's widgets */
|
|
static Widget mshell_w; /* main moon shell */
|
|
static Widget msform_w; /* statistics form dialog */
|
|
static Widget msw_w; /* main scrolled window */
|
|
static Widget msl_w; /* main scrolled list */
|
|
static Widget mda_w; /* image view DrawingArea */
|
|
static Pixmap m_pm; /* image view staging pixmap */
|
|
static Widget dt_w; /* main date/time stamp widget */
|
|
static Widget sdt_w; /* statistics date/time stamp widget */
|
|
|
|
/* "More info" widgets */
|
|
static Widget srlng_w; /* sunrise longitude PB widget */
|
|
static Widget sslat_w; /* subsolar latitude PB widget */
|
|
static Widget llat_w; /* lib in lat PB widget */
|
|
static Widget llong_w; /* lib in long PB widget */
|
|
static Widget limb_w; /* limb angle PB widget */
|
|
static Widget lib_w; /* total lib PB widget */
|
|
static Widget age_w; /* days since new moon PB widget */
|
|
static Widget sunalt_w; /* sun altitude under cursor */
|
|
static Widget infot_w; /* info title label */
|
|
static Widget lat_w, lng_w; /* lat/long under cursor */
|
|
static Widget nsrt_w, nsrd_w; /* next sunrise time/date under cursor */
|
|
static Widget nsst_w, nssd_w; /* next sunset time/date under cursor */
|
|
|
|
/* lo shell widgets */
|
|
static Widget mlo_shell_w; /* main shell */
|
|
static Widget mlo_sw_w; /* scrolled window for pixmap image */
|
|
static Widget mlo_pml_w; /* L for pixmap image */
|
|
static Widget mlo_sl_w; /* scrolled list to show choices */
|
|
static Widget mlo_ann_w; /* TB whether to show annotated version */
|
|
|
|
/* earthshine widgets */
|
|
static Widget esform_w; /* main dialog */
|
|
static Widget eshine_w; /* earthshine factor scale */
|
|
|
|
/* lunar surface popup's widgets */
|
|
static Widget pu_w; /* main popup */
|
|
static Widget pu_name_w; /* popup name label */
|
|
static Widget pu_type_w; /* popup type label */
|
|
static Widget pu_lat_w; /* popup latitude label */
|
|
static Widget pu_lng_w; /* popup longitude label */
|
|
static Widget pu_alt_w; /* popup sun altitude label */
|
|
static Widget pu_pl_w; /* popup label TB */
|
|
static Widget pu_copy_w; /* popup copy PB */
|
|
static Widget pu_showlo_w; /* popup show lunar orbiter image PB */
|
|
|
|
/* sky background object's widgets */
|
|
static Widget skypu_w; /* main popup */
|
|
static Widget skypu_name_w; /* popup name label */
|
|
static Widget skypu_mag_w; /* popup mag label */
|
|
static Obj *skypu_op; /* current object being referred to */
|
|
|
|
/* field star support */
|
|
static ObjF *fstars; /* malloced list of field stars, or NULL */
|
|
static int nfstars; /* number of entries in fstars[] */
|
|
static double fsdec, fsra; /* location when field stars were loaded */
|
|
#define FSFOV degrad(3.0) /* size of FOV to fetch, rads */
|
|
#define FSMAG ((double)FMAG) /* limiting mag for fetch */
|
|
#define FSMOVE degrad(.2) /* reload when moon has moved this far, rads */
|
|
static void m_loadfs (Now *np, double ra, double dec);
|
|
|
|
static GC m_fgc, m_bgc, m_agc; /* various GCs */
|
|
static XFontStruct *m_fsp; /* label font info */
|
|
|
|
static int m_selecting; /* set while our fields are being selected */
|
|
|
|
static XImage *glass_xim; /* glass XImage -- 0 means new or can't */
|
|
static GC glassGC; /* GC for glass border */
|
|
|
|
#define GLASSSZ 50 /* mag glass width and heigth, pixels */
|
|
#define GLASSMAG 2 /* mag glass factor (may be any integer > 0) */
|
|
|
|
/* options list */
|
|
typedef enum {
|
|
SPACECRAFT_OPT, LABELS_OPT, GRID_OPT, FLIPLR_OPT, FLIPTB_OPT, SKY_OPT,
|
|
UMBRA_OPT, N_OPT
|
|
} Option;
|
|
static int option[N_OPT];
|
|
static Widget option_w[N_OPT];
|
|
|
|
/* return the effective x or y values, allowing for flip options.
|
|
* N.B. this is with respect to the image, not the drawing area.
|
|
*/
|
|
#define FX(x) (option[FLIPLR_OPT] ? mncols-1-(x) : (x))
|
|
#define FY(y) (option[FLIPTB_OPT] ? mnrows-1-(y) : (y))
|
|
|
|
/* lunar database */
|
|
typedef struct {
|
|
char *name; /* malloced name */
|
|
char *type; /* malloced type (may be shared) */
|
|
double lt, lg; /* lunar coords, lat N and long E, rads */
|
|
int x, y; /* image location, X pixels coords */
|
|
char pl; /* whether want label */
|
|
char **lofiles; /* malloced list of lunar orbiter file names */
|
|
int nlofiles; /* number of lofiles */
|
|
} MoonDB;
|
|
static MoonDB *moondb; /* malloced array from file */
|
|
static int nmoondb; /* entries in moondb[] */
|
|
static int m_wantlabel (MoonDB *mp);
|
|
static void fill_popup (MoonDB *mp, int x, int y);
|
|
static void m_create_popup (void);
|
|
static void mlo_load (MoonDB *ep);
|
|
static void mlo_load_image (char *fn);
|
|
static MoonDB *closeMoonDB (int x, int y);
|
|
|
|
/* called when the moon view is activated via the main menu pulldown.
|
|
* if first time, build everything, else just up we go.
|
|
* allow for retrying to read the image file each time until find it.
|
|
*/
|
|
void
|
|
m_manage (void)
|
|
{
|
|
if (!mshell_w) {
|
|
/* menu one-time-only work */
|
|
|
|
/* build dialogs */
|
|
m_create_shell();
|
|
m_create_msform();
|
|
m_create_esform();
|
|
mlo_create_shell();
|
|
|
|
/* establish depth, colors and bits per pixel */
|
|
get_something (mda_w, XmNdepth, (XtArgVal)&mdepth);
|
|
m_init_gcs();
|
|
mbpp = (mdepth == 1 || nmgray == 2) ? 1 :
|
|
(mdepth>=17 ? 32 : (mdepth >= 9 ? 16 : 8));
|
|
|
|
/* read moon database */
|
|
m_readdb();
|
|
m_fillSL();
|
|
}
|
|
|
|
if (!mimage) {
|
|
/* read image and display at initial size */
|
|
if (m_shrink(mshrink) < 0)
|
|
return;
|
|
}
|
|
|
|
XtPopup (mshell_w, XtGrabNone);
|
|
set_something (mshell_w, XmNiconic, (XtArgVal)False);
|
|
centerScrollBars (msw_w);
|
|
|
|
/* register we are now up */
|
|
setXRes (m_viewupres(), "1");
|
|
}
|
|
|
|
int
|
|
m_ison (void)
|
|
{
|
|
return (isUp(mshell_w));
|
|
}
|
|
|
|
/* commanded from main to update with a new set of circumstances */
|
|
void
|
|
m_update (np, how_much)
|
|
Now *np;
|
|
int how_much;
|
|
{
|
|
if (!mshell_w)
|
|
return;
|
|
if (!isUp(mshell_w) && !any_ison() && !how_much)
|
|
return;
|
|
|
|
watch_cursor (1);
|
|
m_redraw();
|
|
watch_cursor (0);
|
|
}
|
|
|
|
/* called when basic resources change.
|
|
* rebuild and redraw.
|
|
*/
|
|
void
|
|
m_newres (void)
|
|
{
|
|
if (!mshell_w)
|
|
return;
|
|
m_init_gcs();
|
|
m_update (mm_get_now(), 1);
|
|
}
|
|
|
|
/* called when the database has changed.
|
|
* if we are drawing background, we'd best redraw everything.
|
|
*/
|
|
void
|
|
m_newdb (appended)
|
|
int appended;
|
|
{
|
|
if (option[SKY_OPT] && isUp(mshell_w)) {
|
|
if (!appended)
|
|
resetSkyObj(); /* still ok if just appended */
|
|
m_redraw();
|
|
}
|
|
}
|
|
|
|
/* called by other menus as they want to hear from our buttons or not.
|
|
* the "on"s and "off"s stack - only really redo the buttons if it's the
|
|
* first on or the last off.
|
|
*/
|
|
void
|
|
m_selection_mode (whether)
|
|
int whether; /* whether setting up for plotting or for not plotting */
|
|
{
|
|
if (whether)
|
|
m_selecting++;
|
|
else if (m_selecting > 0)
|
|
--m_selecting;
|
|
|
|
if (mshell_w) {
|
|
if ((whether && m_selecting == 1) /* first one to want on */
|
|
|| (!whether && m_selecting == 0) /* last one to want off */)
|
|
m_set_buttons (whether);
|
|
}
|
|
}
|
|
|
|
/* called to put up or remove the watch cursor. */
|
|
void
|
|
m_cursor (c)
|
|
Cursor c;
|
|
{
|
|
Window win;
|
|
|
|
if (mshell_w && (win = XtWindow(mshell_w)) != 0) {
|
|
Display *dsp = XtDisplay(mshell_w);
|
|
if (c)
|
|
XDefineCursor (dsp, win, c);
|
|
else
|
|
XUndefineCursor (dsp, win);
|
|
}
|
|
|
|
if (mlo_shell_w && (win = XtWindow(mlo_shell_w)) != 0) {
|
|
Display *dsp = XtDisplay(mlo_shell_w);
|
|
if (c)
|
|
XDefineCursor (dsp, win, c);
|
|
else
|
|
XUndefineCursor (dsp, win);
|
|
}
|
|
|
|
if (msform_w && (win = XtWindow(msform_w)) != 0) {
|
|
Display *dsp = XtDisplay(msform_w);
|
|
if (c)
|
|
XDefineCursor (dsp, win, c);
|
|
else
|
|
XUndefineCursor (dsp, win);
|
|
}
|
|
}
|
|
|
|
/* return the name of the resource containing whether this view is up */
|
|
char *
|
|
m_viewupres (void)
|
|
{
|
|
return ("MoonViewUp");
|
|
}
|
|
|
|
static void
|
|
m_create_shell (void)
|
|
{
|
|
typedef struct {
|
|
Option o; /* which option */
|
|
char *name; /* name of TB */
|
|
char *title; /* title string of option */
|
|
char *tip; /* widget tip */
|
|
} OpSetup;
|
|
static OpSetup ops[] = {
|
|
{SPACECRAFT_OPT, "Spacecraft", "Spacecraft",
|
|
"Label each Spacecraft landing site"},
|
|
{LABELS_OPT, "Labels", "Labels",
|
|
"Whether to display selected labels"},
|
|
{SKY_OPT, "SkyBkg", "Sky background",
|
|
"When on, sky will include database objects and Field Stars"},
|
|
{UMBRA_OPT, "Umbra", "{Pen}Umbra",
|
|
"Display edges of Earth shadow (if near a lunar eclipse)"},
|
|
{FLIPTB_OPT, "FlipTB", "Flip T/B",
|
|
"Flip map top-to-bottom"},
|
|
{FLIPLR_OPT, "FlipLR", "Flip L/R",
|
|
"Flip map left-to-right"},
|
|
{GRID_OPT, "Grid", "Grid",
|
|
"Overlay 15 degree grid and mark Sub-Earth location"},
|
|
};
|
|
typedef struct {
|
|
char *label; /* what goes on the help label */
|
|
char *key; /* string to call hlp_dialog() */
|
|
} HelpOn;
|
|
static HelpOn helpon[] = {
|
|
{"Intro...", "Moon"},
|
|
{"on Mouse...", "Moon_mouse"},
|
|
{"on Control...", "Moon_control"},
|
|
{"on View...", "Moon_view"},
|
|
{"on Scale...", "Moon_scale"},
|
|
{"on Lunar Orbiter...", "Moon_lo"},
|
|
};
|
|
Widget mb_w, pd_w, cb_w;
|
|
Widget w;
|
|
Widget mform_w;
|
|
XmString str;
|
|
unsigned long mask;
|
|
Arg args[20];
|
|
int i;
|
|
int n;
|
|
|
|
/* create master form */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNtitle, "xephem Moon view"); n++;
|
|
XtSetArg (args[n], XmNiconName, "Moon"); n++;
|
|
XtSetArg (args[n], XmNdeleteResponse, XmUNMAP); n++;
|
|
mshell_w = XtCreatePopupShell ("Moon", topLevelShellWidgetClass,
|
|
toplevel_w, args, n);
|
|
setup_icon (mshell_w);
|
|
set_something (mshell_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
XtAddCallback (mshell_w, XmNpopdownCallback, m_popdown_cb, 0);
|
|
sr_reg (mshell_w, "XEphem*Moon.width", mooncategory, 0);
|
|
sr_reg (mshell_w, "XEphem*Moon.height", mooncategory, 0);
|
|
sr_reg (mshell_w, "XEphem*Moon.x", mooncategory, 0);
|
|
sr_reg (mshell_w, "XEphem*Moon.y", mooncategory, 0);
|
|
sr_reg (NULL, m_viewupres(), mooncategory, 0);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNhorizontalSpacing, 5); n++;
|
|
XtSetArg (args[n], XmNverticalSpacing, 5); n++;
|
|
mform_w = XmCreateForm (mshell_w, "MoonF", args, n);
|
|
XtAddCallback (mform_w, XmNhelpCallback, m_help_cb, 0);
|
|
XtManageChild (mform_w);
|
|
|
|
/* create the menu bar across the top */
|
|
|
|
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 (mform_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++;
|
|
cb_w = XmCreateCascadeButton (mb_w, "ControlCB", args, n);
|
|
set_xmstring (cb_w, XmNlabelString, "Control");
|
|
XtManageChild (cb_w);
|
|
|
|
/* the "Print" push button */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "PrintPB", args, n);
|
|
set_xmstring (w, XmNlabelString, "Print...");
|
|
XtAddCallback (w, XmNactivateCallback, m_print_cb, 0);
|
|
wtip (w, "Print the current Moon map");
|
|
XtManageChild (w);
|
|
|
|
/* the "Annot" push button */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "Ann", args, n);
|
|
set_xmstring (w, XmNlabelString, "User annotation...");
|
|
XtAddCallback (w, XmNactivateCallback, ano_cb, 0);
|
|
wtip (w, "Open window to create and manage your own annotation");
|
|
XtManageChild (w);
|
|
|
|
/* the "Field stars" push button */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "FS", args, n);
|
|
set_xmstring (w, XmNlabelString, "Field Stars...");
|
|
XtAddCallback (w, XmNactivateCallback, (XtCallbackProc)fs_manage,0);
|
|
wtip (w, "Define where GSC and PPM catalogs are to be found");
|
|
XtManageChild (w);
|
|
|
|
/* button to bring up the earthshine dialog */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "ESPB", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_eshineup_cb, 0);
|
|
set_xmstring (w, XmNlabelString, "Set Earthshine...");
|
|
wtip (w, "Display a dialog to set brightness of dark half of moon");
|
|
XtManageChild (w);
|
|
|
|
/* button for Movie demo */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "EAnim", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_anim_cb, 0);
|
|
set_xmstring (w, XmNlabelString, "Animation demo");
|
|
wtip (w, "Start/Stop a fun time-lapse animation");
|
|
XtManageChild (w);
|
|
|
|
/* button to erase labels */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "MEL", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_elab_cb, 0);
|
|
set_xmstring (w, XmNlabelString, "Forget labels");
|
|
wtip (w, "Forget all non-spacecraft labels added to the map");
|
|
XtManageChild (w);
|
|
|
|
/* the "Movie" push button */
|
|
|
|
n = 0;
|
|
n += ml_addacc (args, n);
|
|
w = XmCreatePushButton (pd_w, "MovieL", args, n);
|
|
set_xmstring (w, XmNlabelString, "Add to movie...");
|
|
XtAddCallback (w, XmNactivateCallback, m_mloop_cb, 0);
|
|
wtip (w, "Add lunar image to movie loop");
|
|
XtManageChild (w);
|
|
|
|
/* add a separator */
|
|
n = 0;
|
|
w = XmCreateSeparator (pd_w, "CtS", args, n);
|
|
XtManageChild (w);
|
|
|
|
/* add the close button */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "Close", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_close_cb, 0);
|
|
wtip (w, "Close this and all supporting dialogs");
|
|
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++;
|
|
cb_w = XmCreateCascadeButton (mb_w, "ViewCB", args, n);
|
|
set_xmstring (cb_w, XmNlabelString, "View");
|
|
XtManageChild (cb_w);
|
|
|
|
/* add options */
|
|
|
|
for (i = 0; i < XtNumber(ops); i++) {
|
|
OpSetup *osp = &ops[i];
|
|
Option o = osp->o;
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
w = XmCreateToggleButton (pd_w, osp->name, args, n);
|
|
XtAddCallback(w, XmNvalueChangedCallback, m_option_cb,
|
|
(XtPointer)o);
|
|
set_xmstring (w, XmNlabelString, osp->title);
|
|
option[o] = XmToggleButtonGetState (w);
|
|
option_w[o] = w;
|
|
if (osp->tip)
|
|
wtip (w, osp->tip);
|
|
XtManageChild (w);
|
|
sr_reg (w, NULL, mooncategory, 1);
|
|
}
|
|
|
|
/* add a separator */
|
|
|
|
n = 0;
|
|
w = XmCreateSeparator (pd_w, "Sep", args, n);
|
|
XtManageChild (w);
|
|
|
|
/* add the More Info control */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "Stats", args, n);
|
|
set_xmstring (w, XmNlabelString, "More info...");
|
|
XtAddCallback (w, XmNactivateCallback, m_mstats_cb, 0);
|
|
wtip (w, "Display additional information");
|
|
XtManageChild (w);
|
|
|
|
/* make the Scale pulldown */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNradioBehavior, True); n++;
|
|
pd_w = XmCreatePulldownMenu (mb_w, "ScalePD", args, n);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNsubMenuId, pd_w); n++;
|
|
XtSetArg (args[n], XmNmnemonic, 'S'); n++;
|
|
cb_w = XmCreateCascadeButton (mb_w, "ScaleCB", args, n);
|
|
set_xmstring (cb_w, XmNlabelString, "Scale");
|
|
wtip (cb_w, "Set the image size");
|
|
XtManageChild (cb_w);
|
|
|
|
for (i = 1; i <= MAXSHRINK; i++) {
|
|
char name[64], title[64];
|
|
int shrink;
|
|
|
|
/* just advertise whole values */
|
|
if (MAXSHRINK%i)
|
|
continue;
|
|
shrink = MAXSHRINK/i;
|
|
|
|
(void) sprintf (name, "Scale%dX", shrink);
|
|
n = 0;
|
|
w = XmCreateToggleButton (pd_w, name, args, n);
|
|
XtAddCallback(w, XmNvalueChangedCallback, m_shrink_cb,
|
|
(XtPointer)(long int)i);
|
|
(void) sprintf (title, " Scale %d X", shrink);
|
|
set_xmstring (w, XmNlabelString, title);
|
|
XtManageChild (w);
|
|
|
|
/* pick up user's default */
|
|
if (XmToggleButtonGetState(w)) {
|
|
if (mshrink != 0)
|
|
xe_msg (0, "Multiple setting: ignoring Moon*%s", name);
|
|
else
|
|
mshrink = i;
|
|
}
|
|
|
|
/* if done and none set, default to last one */
|
|
if (i == MAXSHRINK && mshrink == 0) {
|
|
xe_msg (0, "No Moon*Scale<n>X resource -- defaulting to 1");
|
|
XmToggleButtonSetState (w, True, False);
|
|
mshrink = MAXSHRINK;
|
|
}
|
|
|
|
sr_reg (w, NULL, mooncategory, 1);
|
|
}
|
|
|
|
/* 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++;
|
|
cb_w = XmCreateCascadeButton (mb_w, "HelpCB", args, n);
|
|
set_xmstring (cb_w, XmNlabelString, "Help");
|
|
XtManageChild (cb_w);
|
|
set_something (mb_w, XmNmenuHelpWidget, (XtArgVal)cb_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, m_helpon_cb,
|
|
(XtPointer)(hp->key));
|
|
XtManageChild (w);
|
|
XmStringFree(str);
|
|
}
|
|
|
|
/* make a label for the date stamp */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrecomputeSize, False); n++;
|
|
dt_w = XmCreateLabel (mform_w, "DateStamp", args, n);
|
|
timestamp (mm_get_now(), dt_w); /* sets initial size */
|
|
wtip (dt_w, "Date and Time for which map is computed");
|
|
XtManageChild (dt_w);
|
|
|
|
/* make a scrolled list on the right for the names */
|
|
|
|
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, dt_w); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNselectionPolicy, XmBROWSE_SELECT); n++;
|
|
msl_w = XmCreateScrolledList (mform_w, "MoonSL", args, n);
|
|
XtAddCallback (msl_w, XmNbrowseSelectionCallback, m_select_cb,0);
|
|
XtAddCallback (msl_w, XmNdefaultActionCallback, m_select_cb,0);
|
|
XtManageChild (msl_w);
|
|
|
|
/* make a drawing area in a scrolled window for the image view */
|
|
|
|
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, dt_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNrightWidget, XtParent(msl_w)); n++;
|
|
XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
|
|
XtSetArg (args[n], XmNvisualPolicy, XmVARIABLE); n++;
|
|
msw_w = XmCreateScrolledWindow (mform_w, "MoonSW", args, n);
|
|
XtManageChild (msw_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNmarginWidth, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
mda_w = XmCreateDrawingArea (msw_w, "MoonMap", args, n);
|
|
XtAddCallback (mda_w, XmNexposeCallback, m_exp_cb, NULL);
|
|
mask = Button1MotionMask | ButtonPressMask | ButtonReleaseMask
|
|
| PointerMotionHintMask;
|
|
XtAddEventHandler (mda_w, mask, False, m_pointer_eh, 0);
|
|
XtManageChild (mda_w);
|
|
|
|
/* SW assumes work is its child but just to be tidy about it .. */
|
|
set_something (msw_w, XmNworkWindow, (XtArgVal)mda_w);
|
|
|
|
/* match SW background to DA */
|
|
get_something (msw_w, XmNclipWindow, (XtArgVal)&w);
|
|
if (w) {
|
|
Pixel p;
|
|
get_something (mda_w, XmNbackground, (XtArgVal)&p);
|
|
set_something (w, XmNbackground, (XtArgVal)p);
|
|
}
|
|
}
|
|
|
|
static void
|
|
m_create_msform (void)
|
|
{
|
|
typedef struct {
|
|
int islabel;
|
|
char *label;
|
|
Widget *wp;
|
|
char *tip;
|
|
} DItem;
|
|
static DItem citems[] = {
|
|
{1,"Latitude +N:", &lat_w, "Selenographic latitude under cursor"},
|
|
{1,"Longitude +E:", &lng_w, "Selenographic longitude under cursor"},
|
|
{0,"Sun altitude:", &sunalt_w,
|
|
"Sun angle above horizon as seen from location under cursor"},
|
|
{1,"Next Sunrise:", &nsrt_w,
|
|
"Time of next sunrise as seen from location under cursor"},
|
|
{1," ", &nsrd_w,
|
|
"Date of next sunrise as seen from location under cursor"},
|
|
{1,"Next Sunset:", &nsst_w,
|
|
"Time of next sunset as seen from location under cursor"},
|
|
{1," ", &nssd_w,
|
|
"Date of next sunset as seen from location under cursor"},
|
|
};
|
|
Widget rc_w;
|
|
Widget sep_w;
|
|
Widget w;
|
|
XmString str;
|
|
Arg args[20];
|
|
int n;
|
|
int i;
|
|
|
|
/* create form */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNautoUnmanage, False); n++;
|
|
XtSetArg (args[n], XmNverticalSpacing, 10); n++;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNmarginWidth, 10); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 10); n++;
|
|
XtSetArg (args[n], XmNdefaultPosition, False); n++;
|
|
msform_w = XmCreateFormDialog (mshell_w, "MoonStats", args, n);
|
|
set_something (msform_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
sr_reg (XtParent(msform_w), "XEphem*MoonStats.x", mooncategory,0);
|
|
sr_reg (XtParent(msform_w), "XEphem*MoonStats.y", mooncategory,0);
|
|
|
|
/* set some stuff in the parent DialogShell.
|
|
* setting XmNdialogTitle in the Form didn't work..
|
|
*/
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtitle, "xephem Moon info"); n++;
|
|
XtSetValues (XtParent(msform_w), args, n);
|
|
|
|
/* label for title */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
infot_w = XmCreateLabel (msform_w, "MIL", args, n);
|
|
set_xmstring (infot_w, XmNlabelString, " ");
|
|
XtManageChild (infot_w);
|
|
|
|
/* make a rowcolumn to hold the cursor tracking info */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, infot_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNspacing, 5); n++; /* matches RC below better */
|
|
XtSetArg (args[n], XmNpacking, XmPACK_COLUMN); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
XtSetArg (args[n], XmNnumColumns, XtNumber(citems)); n++;
|
|
XtSetArg (args[n], XmNisAligned, False); n++;
|
|
rc_w = XmCreateRowColumn (msform_w, "SRC", args, n);
|
|
XtManageChild (rc_w);
|
|
|
|
for (i = 0; i < XtNumber(citems); i++) {
|
|
DItem *dp = &citems[i];
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
w = XmCreateLabel (rc_w, "CLbl", args, n);
|
|
set_xmstring (w, XmNlabelString, dp->label);
|
|
XtManageChild (w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNrecomputeSize, False); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
if (dp->islabel) {
|
|
w = XmCreateLabel (rc_w, "CVal", args, n);
|
|
} else {
|
|
XtSetArg (args[n], XmNuserData, "Moon.SunAlt"); n++;
|
|
w = XmCreatePushButton (rc_w, "CSA", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_activate_cb, NULL);
|
|
}
|
|
set_xmstring (w, XmNlabelString, " ");
|
|
|
|
if (dp->wp)
|
|
*(dp->wp) = w;
|
|
if (dp->tip)
|
|
wtip (w, dp->tip);
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* make a separator between the 2 data sets */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, rc_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
sep_w = XmCreateSeparator (msform_w, "Sep1", args, n);
|
|
XtManageChild(sep_w);
|
|
|
|
/* make a rowcolumn to hold the labels and info buttons */
|
|
|
|
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], XmNpacking, XmPACK_COLUMN); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
XtSetArg (args[n], XmNnumColumns, 8); n++;
|
|
XtSetArg (args[n], XmNisAligned, False); n++;
|
|
rc_w = XmCreateRowColumn (msform_w, "SRC", args, n);
|
|
XtManageChild (rc_w);
|
|
|
|
/* make the srlng, sslat and libration in lat/long rows */
|
|
|
|
str = XmStringCreate ("Sunrise Long:", XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
w = XmCreateLabel (rc_w, "MLCoL", args, n);
|
|
XtManageChild (w);
|
|
XmStringFree (str);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Moon.SunRiseLng"); n++;
|
|
srlng_w = XmCreatePushButton (rc_w, "MLCoLPB", args, n);
|
|
XtAddCallback (srlng_w, XmNactivateCallback, m_activate_cb, NULL);
|
|
wtip (srlng_w, "Selenographic longitude where sun is now rising");
|
|
XtManageChild (srlng_w);
|
|
|
|
str = XmStringCreate ("Subsolar Lat:", XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
w = XmCreateLabel (rc_w, "MLSL", args, n);
|
|
XtManageChild (w);
|
|
XmStringFree (str);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Moon.SubSolLat"); n++;
|
|
sslat_w = XmCreatePushButton (rc_w, "MLSLPB", args, n);
|
|
XtAddCallback (sslat_w, XmNactivateCallback, m_activate_cb, NULL);
|
|
wtip (sslat_w, "Selenographic latitude at which sun is directly overhead");
|
|
XtManageChild (sslat_w);
|
|
|
|
str = XmStringCreate ("Libr in Lat:", XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
w = XmCreateLabel (rc_w, "MLLatL", args, n);
|
|
XtManageChild (w);
|
|
XmStringFree (str);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Moon.LibrLat"); n++;
|
|
llat_w = XmCreatePushButton (rc_w, "MLLatPB", args, n);
|
|
XtAddCallback (llat_w, XmNactivateCallback, m_activate_cb, NULL);
|
|
wtip (llat_w, "Current tilt in latitude from nominal `face-on' direction, + Lunar N");
|
|
XtManageChild (llat_w);
|
|
|
|
str = XmStringCreate ("Libr in Long:", XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
w = XmCreateLabel (rc_w, "MLLongL", args, n);
|
|
XtManageChild (w);
|
|
XmStringFree (str);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Moon.LibrLong"); n++;
|
|
llong_w = XmCreatePushButton (rc_w, "MLLongPB", args, n);
|
|
XtAddCallback (llong_w, XmNactivateCallback, m_activate_cb, NULL);
|
|
wtip (llong_w, "Current tilt in longitude from nominal `face-on' direction, + Lunar E");
|
|
XtManageChild (llong_w);
|
|
|
|
/* make the limb/tilt rows */
|
|
|
|
str = XmStringCreate ("Limb angle:", XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
w = XmCreateLabel (rc_w, "MLimbL", args, n);
|
|
XtManageChild (w);
|
|
XmStringFree (str);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Moon.LibrLimb"); n++;
|
|
limb_w = XmCreatePushButton (rc_w, "MLimbPB", args, n);
|
|
XtAddCallback (limb_w, XmNactivateCallback, m_activate_cb, NULL);
|
|
wtip (limb_w, "Limb angle nearest Earth, + Lunar W of N");
|
|
XtManageChild (limb_w);
|
|
|
|
str = XmStringCreate ("Tilt:", XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
w = XmCreateLabel (rc_w, "MLibL", args, n);
|
|
XtManageChild (w);
|
|
XmStringFree (str);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Moon.LibrTilt"); n++;
|
|
lib_w = XmCreatePushButton (rc_w, "MLibPB", args, n);
|
|
XtAddCallback (lib_w, XmNactivateCallback, m_activate_cb, NULL);
|
|
wtip(lib_w,"Degrees by which nominal face is tilted towards Earth");
|
|
XtManageChild (lib_w);
|
|
|
|
str = XmStringCreate ("Age:", XmSTRING_DEFAULT_CHARSET);
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg (args[n], XmNlabelString, str); n++;
|
|
w = XmCreateLabel (rc_w, "MAge", args, n);
|
|
XtManageChild (w);
|
|
XmStringFree (str);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Moon.Age"); n++;
|
|
age_w = XmCreatePushButton (rc_w, "MLibPB", args, n);
|
|
XtAddCallback (age_w, XmNactivateCallback, m_activate_cb, NULL);
|
|
wtip (age_w, "Days since new moon");
|
|
XtManageChild (age_w);
|
|
|
|
/* add a separator */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, rc_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
sep_w = XmCreateSeparator (msform_w, "Sep2", 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++;
|
|
sdt_w = XmCreateLabel (msform_w, "SDTstamp", args, n);
|
|
wtip (sdt_w, "Date and Time for which data are computed");
|
|
XtManageChild (sdt_w);
|
|
|
|
/* add a separator */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, sdt_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
sep_w = XmCreateSeparator (msform_w, "Sep3", args, n);
|
|
XtManageChild (sep_w);
|
|
|
|
/* add a close button */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, sep_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 20); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 80); n++;
|
|
w = XmCreatePushButton (msform_w, "Close", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_mstats_close_cb, 0);
|
|
wtip (w, "Close this dialog");
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* create the little earthshine scale factor dialog */
|
|
static void
|
|
m_create_esform (void)
|
|
{
|
|
Arg args[20];
|
|
Widget sep_w;
|
|
Widget w;
|
|
int min, max, v;
|
|
int n;
|
|
|
|
/* create form */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNautoUnmanage, False); n++;
|
|
XtSetArg (args[n], XmNfractionBase, 10); n++;
|
|
XtSetArg (args[n], XmNverticalSpacing, 10); n++;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNdefaultPosition, False); n++;
|
|
esform_w = XmCreateFormDialog (mshell_w, "MoonEShine", args, n);
|
|
set_something (esform_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
sr_reg (XtParent(esform_w), "XEphem*MoonEShine.x",mooncategory,0);
|
|
sr_reg (XtParent(esform_w), "XEphem*MoonEShine.y",mooncategory,0);
|
|
|
|
/* set some stuff in the parent DialogShell.
|
|
* setting XmNdialogTitle in the Form didn't work..
|
|
*/
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtitle, "xephem Moon Earthshine"); n++;
|
|
XtSetValues (XtParent(esform_w), args, n);
|
|
|
|
/* make a scale */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNtopOffset, 10); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
XtSetArg (args[n], XmNshowValue, True); n++;
|
|
XtSetArg (args[n], XmNscaleMultiple, 1); n++;
|
|
XtSetArg (args[n], XmNminimum, 0); n++;
|
|
XtSetArg (args[n], XmNmaximum, ESHINEF); n++;
|
|
eshine_w = XmCreateScale (esform_w, "Earthshine", args, n);
|
|
wtip (eshine_w, "Set to desired relative Earthshine brightness");
|
|
XtManageChild (eshine_w);
|
|
sr_reg (eshine_w, NULL, mooncategory, 1);
|
|
|
|
get_something (eshine_w, XmNminimum, (XtArgVal)&min);
|
|
get_something (eshine_w, XmNmaximum, (XtArgVal)&max);
|
|
get_something (eshine_w, XmNvalue, (XtArgVal)&v);
|
|
|
|
if (min >= max || v < min || v > max || v == 0) {
|
|
xe_msg (0, "Bogus moon Earthshine values -- setting defaults");
|
|
set_something (eshine_w, XmNminimum, (XtArgVal)1);
|
|
set_something (eshine_w, XmNmaximum, (XtArgVal)10);
|
|
set_something (eshine_w, XmNvalue, (XtArgVal)4);
|
|
}
|
|
|
|
/* make a separator */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, eshine_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
sep_w = XmCreateSeparator (esform_w, "Sep", args, n);
|
|
XtManageChild(sep_w);
|
|
|
|
/* make the buttons at the bottom */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, sep_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 10); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 2); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 4); n++;
|
|
w = XmCreatePushButton (esform_w, "Apply", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_eshine_cb, NULL);
|
|
wtip (w, "Make it so");
|
|
XtManageChild (w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, sep_w); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 10); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 6); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 8); n++;
|
|
w = XmCreatePushButton (esform_w, "Close", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_eshineclose_cb, NULL);
|
|
wtip (w, "Close this dialog");
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* go through all the buttons pickable for plotting and set whether they
|
|
* should appear to look like buttons or just flat labels.
|
|
*/
|
|
static void
|
|
m_set_buttons (whether)
|
|
int whether; /* whether setting up for plotting or for not plotting */
|
|
{
|
|
buttonAsButton (sunalt_w, whether);
|
|
buttonAsButton (srlng_w, whether);
|
|
buttonAsButton (sslat_w, whether);
|
|
buttonAsButton (llat_w, whether);
|
|
buttonAsButton (llong_w, whether);
|
|
buttonAsButton (limb_w, whether);
|
|
buttonAsButton (lib_w, whether);
|
|
buttonAsButton (age_w, whether);
|
|
}
|
|
|
|
/* callback from the Apply button in the earthshine dialog */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_eshine_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
m_redraw();
|
|
}
|
|
|
|
/* callback to add the current scene to the movie loop */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_mloop_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
ml_add (m_pm, dt_w);
|
|
}
|
|
|
|
/* callback from the Close button in the earthshine dialog */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_eshineclose_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XtUnmanageChild (esform_w);
|
|
}
|
|
|
|
/* called to toggle whether the earthshine eshineactor is dialog */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_eshineup_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
if (XtIsManaged(esform_w))
|
|
XtUnmanageChild (esform_w);
|
|
else
|
|
XtManageChild (esform_w);
|
|
}
|
|
|
|
|
|
/* callback from the Close button on the stats menu.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_mstats_close_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XtUnmanageChild (msform_w);
|
|
}
|
|
|
|
/* callback from the More Info button on the main menu.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_mstats_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XtManageChild (msform_w);
|
|
m_set_buttons(m_selecting);
|
|
}
|
|
|
|
/* callback from the Print PB */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_print_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XPSAsk ("Moon View", m_print);
|
|
}
|
|
|
|
/* proceed to generate a postscript file.
|
|
* call XPSClose() when finished.
|
|
*/
|
|
static void
|
|
m_print (void)
|
|
{
|
|
/* must be up */
|
|
if (!m_ison()) {
|
|
xe_msg (1, "Moon must be open to print.");
|
|
XPSClose();
|
|
return;
|
|
}
|
|
|
|
watch_cursor(1);
|
|
|
|
/* fit view in square across the top and prepare to capture X calls */
|
|
XPSXBegin (m_pm, BORD, BORD, mncols, mnrows, 1*72, 10*72,
|
|
(int)(6.5*72));
|
|
|
|
/* redraw everything now */
|
|
m_redraw();
|
|
|
|
/* no more X captures */
|
|
XPSXEnd();
|
|
|
|
/* add some extra info */
|
|
m_ps_annotate ();
|
|
|
|
/* finished */
|
|
XPSClose();
|
|
|
|
watch_cursor(0);
|
|
}
|
|
|
|
static void
|
|
m_ps_annotate (void)
|
|
{
|
|
Now *np = mm_get_now();
|
|
char dir[128];
|
|
char buf[128];
|
|
int ctr = 306; /* = 8.5*72/2 */
|
|
int lx = 180, rx = 460;
|
|
int y;
|
|
|
|
/* caption */
|
|
y = AROWY(13);
|
|
if (option[SKY_OPT])
|
|
(void) sprintf (buf, "XEphem %s Moon View",
|
|
pref_get(PREF_EQUATORIAL)==PREF_GEO ? "Geocentric"
|
|
: "Topocentric");
|
|
else
|
|
(void) strcpy (buf, "XEphem Moon View");
|
|
(void) sprintf (dir, "(%s) %d %d cstr\n", buf, ctr, y);
|
|
XPSDirect (dir);
|
|
|
|
y = AROWY(9);
|
|
fs_date (buf, pref_get(PREF_DATE_FORMAT), mjd_day(mjd));
|
|
(void) sprintf (dir, "(UTC Date:) %d %d rstr (%s) %d %d lstr\n",
|
|
lx, y, buf, lx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
fs_time (buf, mjd_hr(mjd));
|
|
(void) sprintf (dir, "(UTC Time:) %d %d rstr (%s) %d %d lstr\n",
|
|
rx, y, buf, rx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
(void) sprintf (dir, "(%6.3f days old) %d %d cstr\n", minfo.age, ctr,y);
|
|
XPSDirect (dir);
|
|
|
|
y = AROWY(8);
|
|
fs_dm_angle (buf, minfo.srlng);
|
|
(void) sprintf (dir,"(Sunrise Longitude:) %d %d rstr (%s) %d %d lstr\n",
|
|
lx, y, buf, lx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
fs_dm_angle (buf, minfo.sslat);
|
|
(void) sprintf (dir,"(Subsolar Latitude:) %d %d rstr (%s) %d %d lstr\n",
|
|
rx, y, buf, rx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
y = AROWY(7);
|
|
fs_dm_angle (buf, minfo.llat);
|
|
(void) sprintf (dir,
|
|
"(Libration in Latitude:) %d %d rstr (%s) %d %d lstr\n",
|
|
lx, y, buf, lx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
fs_dm_angle (buf, minfo.llong);
|
|
(void) sprintf (dir,
|
|
"(Libration in Longitude:) %d %d rstr (%s) %d %d lstr\n",
|
|
rx, y, buf, rx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
y = AROWY(6);
|
|
fs_dm_angle (buf, minfo.limb);
|
|
(void) sprintf (dir,
|
|
"(Limb Angle:) %d %d rstr (%s) %d %d lstr\n",
|
|
lx, y, buf, lx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
fs_dm_angle (buf, minfo.limb);
|
|
(void) sprintf (dir,
|
|
"(Limb Tilt Angle:) %d %d rstr (%6.3f) %d %d lstr\n",
|
|
rx, y, minfo.tilt, rx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
/* add site/lat/long if showing real stars and topocentric */
|
|
if (option[SKY_OPT] && pref_get(PREF_EQUATORIAL) == PREF_TOPO) {
|
|
char *site;
|
|
|
|
/* put site name under caption */
|
|
site = mm_getsite();
|
|
if (site) {
|
|
y = AROWY(12);
|
|
(void) sprintf (dir, "(%s) %d %d cstr\n",
|
|
XPSCleanStr(site,strlen(site)), ctr, y);
|
|
XPSDirect (dir);
|
|
}
|
|
|
|
/* then add lat/long */
|
|
y = AROWY(10);
|
|
|
|
fs_sexa (buf, raddeg(fabs(lat)), 3, 3600);
|
|
(void) sprintf (dir, "(Latitude:) %d %d rstr (%s %c) %d %d lstr\n",
|
|
lx, y, buf, lat < 0 ? 'S' : 'N', lx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
fs_sexa (buf, raddeg(fabs(lng)), 4, 3600);
|
|
(void) sprintf (dir,"(Longitude:) %d %d rstr (%s %c) %d %d lstr\n",
|
|
rx, y, buf, lng < 0 ? 'W' : 'E', rx+10, y);
|
|
XPSDirect (dir);
|
|
}
|
|
}
|
|
|
|
/* callback from any of the data menu buttons being activated.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_activate_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
if (m_selecting) {
|
|
char *name;
|
|
get_something (w, XmNuserData, (XtArgVal)&name);
|
|
register_selection (name);
|
|
}
|
|
}
|
|
|
|
/* callback from mshell_w being popped down.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_popdown_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XtUnmanageChild (esform_w);
|
|
XtUnmanageChild (msform_w);
|
|
|
|
/* freeing the pixmap will prevent any useless updates while off and
|
|
* insure a fresh update on the next expose.
|
|
*/
|
|
if (m_pm) {
|
|
XFreePixmap (XtD, m_pm);
|
|
m_pm = 0;
|
|
}
|
|
|
|
/* free any field stars */
|
|
if (fstars) {
|
|
free ((void *)fstars);
|
|
fstars = NULL;
|
|
nfstars = 0;
|
|
}
|
|
|
|
/* stop movie that might be running */
|
|
mm_movie (0.0);
|
|
|
|
/* register we are now down */
|
|
setXRes (m_viewupres(), "0");
|
|
}
|
|
|
|
/* called from Close button */
|
|
static void
|
|
m_close_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XtPopdown (mshell_w);
|
|
/* let popdown do all the work */
|
|
}
|
|
|
|
/* callback from the any of the option TBs.
|
|
* Option enum is in client.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_option_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
Option opt = (Option)client;
|
|
int set;
|
|
|
|
watch_cursor (1);
|
|
|
|
/* toggle the option */
|
|
option[opt] = set = XmToggleButtonGetState (w);
|
|
|
|
switch (opt) {
|
|
case GRID_OPT:
|
|
if (set) {
|
|
m_grid();
|
|
m_refresh (NULL);
|
|
} else
|
|
m_redraw();
|
|
break;
|
|
|
|
case SKY_OPT:
|
|
m_redraw();
|
|
break;
|
|
|
|
case UMBRA_OPT:
|
|
if (set) {
|
|
m_umbra();
|
|
m_sub();
|
|
m_refresh (NULL);
|
|
} else
|
|
m_redraw();
|
|
break;
|
|
|
|
case SPACECRAFT_OPT: /* FALLTHRU */
|
|
case LABELS_OPT:
|
|
if (set) {
|
|
m_labels();
|
|
m_refresh (NULL);
|
|
} else
|
|
m_redraw();
|
|
break;
|
|
|
|
case FLIPTB_OPT:
|
|
m_free_clip_mask();
|
|
fliptb();
|
|
m_redraw();
|
|
break;
|
|
|
|
case FLIPLR_OPT:
|
|
m_free_clip_mask();
|
|
fliplr();
|
|
m_redraw();
|
|
break;
|
|
|
|
case N_OPT:
|
|
break;
|
|
}
|
|
|
|
watch_cursor (0);
|
|
}
|
|
|
|
/* callback from any of the Scale TBs.
|
|
* client is shrink factor: 1..MAXSHRINK
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_shrink_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
int f = (long int)client;
|
|
int set = XmToggleButtonGetState (w);
|
|
|
|
if (!set || f == mshrink)
|
|
return;
|
|
if (m_shrink (f) < 0)
|
|
return;
|
|
mshrink = f;
|
|
}
|
|
|
|
|
|
/* callback to erase all labels */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_elab_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
MoonDB *mp;
|
|
|
|
/* turn off all persistent label flags then redraw to erase */
|
|
for (mp = moondb; mp < &moondb[nmoondb]; mp++)
|
|
mp->pl = 0;
|
|
m_redraw();
|
|
}
|
|
|
|
/* callback for when the Movie button is activated. */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_anim_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
mm_movie (option[SKY_OPT] ? MOVIE_SSTEPSZ : MOVIE_STEPSZ);
|
|
}
|
|
|
|
/* callback from the Help all button
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_help_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
static char *msg[] = {
|
|
"This is a depiction of the Moon.",
|
|
};
|
|
|
|
hlp_dialog ("Moon", msg, XtNumber(msg));
|
|
}
|
|
|
|
/* callback from a specific Help button.
|
|
* client is a string to use with hlp_dialog().
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_helpon_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
hlp_dialog ((char *)client, NULL, 0);
|
|
}
|
|
|
|
|
|
/* given an [x,y] on m_xim, find latitude, rads north, and longitude, rads e.
|
|
* N.B. [x,y] must be with respect to the _original_ image size and orientation.
|
|
* return 0 if ok (inside image) else -1.
|
|
*/
|
|
static int
|
|
xy2ll (x, y, ltp, lgp)
|
|
int x, y;
|
|
double *ltp, *lgp;
|
|
{
|
|
double cx, cy;
|
|
double lt, lg;
|
|
|
|
/* convert to image center, scaled to radius */
|
|
cx = (double)(x - (leftmarg + moonrad))/moonrad; /* + right */
|
|
cy = (double)((topmarg + moonrad) - y)/moonrad; /* + up */
|
|
|
|
if (cx*cx + cy*cy > 1.0)
|
|
return (-1);
|
|
|
|
lt = asin (cy);
|
|
lg = asin(cx/cos(lt));
|
|
|
|
lt += CLAT;
|
|
lg += CLNG;
|
|
if (lt > PI/2) {
|
|
lt = PI - lt;
|
|
lg += PI;
|
|
} else if (lt < -PI/2) {
|
|
lt = -PI - lt;
|
|
lg += PI;
|
|
}
|
|
|
|
*ltp = lt;
|
|
*lgp = lg;
|
|
range (lgp, 2*PI);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* given a lat(+N)/long(+E) find its [x,y] location on the resized imae.
|
|
* N.B. the returned [x,y] is with respect to the image at its current size
|
|
* but does not include flipping or mda_w border.
|
|
* return 0 if ok (on front side) else -1, but always return x and y.
|
|
*/
|
|
static int
|
|
ll2xy (lt, lg, xp, yp)
|
|
double lt, lg;
|
|
int *xp, *yp;
|
|
{
|
|
double cx, cy, cz;
|
|
double coslt, sinlt;
|
|
|
|
lt -= CLAT;
|
|
lg -= CLNG;
|
|
if (lt > PI/2) {
|
|
lt = PI - lt;
|
|
lg += PI;
|
|
} else if (lt < -PI/2) {
|
|
lt = -PI - lt;
|
|
lg += PI;
|
|
}
|
|
|
|
coslt = cos(lt);
|
|
cz = moonrad*coslt*cos(lg);
|
|
|
|
sinlt = sin(lt);
|
|
cx = moonrad*coslt*sin(lg);
|
|
cy = moonrad*sinlt;
|
|
|
|
*xp = (int)(cx + (leftmarg + moonrad) + 0.5);
|
|
*yp = (int)((topmarg + moonrad) - cy + 0.5);
|
|
|
|
return (cz < 0 ? -1 : 0);
|
|
}
|
|
|
|
/* return True if the given [x,y], relative to mda_w, refers to a spot over the
|
|
* lunar image, else return 0.
|
|
*/
|
|
static int
|
|
overMoon (x, y)
|
|
int x, y;
|
|
{
|
|
/* convert to image center */
|
|
x -= BORD + leftmarg + moonrad;
|
|
y -= BORD + topmarg + moonrad;
|
|
|
|
return (x*x + y*y <= moonrad*moonrad);
|
|
}
|
|
|
|
/* event handler from all Button events on the mda_w */
|
|
static void
|
|
m_pointer_eh (w, client, ev, continue_to_dispatch)
|
|
Widget w;
|
|
XtPointer client;
|
|
XEvent *ev;
|
|
Boolean *continue_to_dispatch;
|
|
{
|
|
Display *dsp = ev->xany.display;
|
|
Window win = ev->xany.window;
|
|
int evt = ev->type;
|
|
Window root, child;
|
|
int rx, ry, x, y;
|
|
unsigned mask;
|
|
int m1, b1p, b1r, b3p;
|
|
|
|
/* what happened? */
|
|
m1 = evt == MotionNotify && ev->xmotion.state & Button1Mask;
|
|
b1p = evt == ButtonPress && ev->xbutton.button == Button1;
|
|
b1r = evt == ButtonRelease && ev->xbutton.button == Button1;
|
|
b3p = evt == ButtonPress && ev->xbutton.button == Button3;
|
|
|
|
/* do we care? */
|
|
if (!m1 && !b1p && !b1r && !b3p)
|
|
return;
|
|
|
|
/* where are we? */
|
|
XQueryPointer (dsp, win, &root, &child, &rx, &ry, &x, &y, &mask);
|
|
|
|
/* dispatch */
|
|
if (b3p)
|
|
m_popup (ev);
|
|
if (b1p || m1 || b1r) {
|
|
doGlass (dsp, win, b1p, m1, b1r, x, y);
|
|
m_reportloc (dsp, win, x, y);
|
|
}
|
|
}
|
|
|
|
/* expose (or reconfig) of moon image view drawing area.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_exp_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
|
|
XExposeEvent *e = &c->event->xexpose;
|
|
Display *dsp = e->display;
|
|
Window win = e->window;
|
|
|
|
watch_cursor (1);
|
|
|
|
switch (c->reason) {
|
|
case XmCR_EXPOSE: {
|
|
/* turn off gravity so we get expose events for either shrink or
|
|
* expand.
|
|
* also center the scroll bars initially.
|
|
*/
|
|
static int before;
|
|
|
|
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;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
printf ("Unexpected mda_w event. type=%d\n", c->reason);
|
|
abort();
|
|
}
|
|
|
|
|
|
/* insure pixmap exists -- it gets destroyed whenever mda_w is resized
|
|
* or the dialog is unmanaged.
|
|
*/
|
|
if (!m_pm) {
|
|
unsigned wid, hei, d;
|
|
|
|
m_getsize (win, &wid, &hei, &d);
|
|
if ((int)wid != mncols+2*BORD || (int)hei != mnrows+2*BORD) {
|
|
printf ("m_da: Bad size: wid=%d mncols=%d hei=%d mnrows=%d\n",
|
|
wid, mncols, hei, mnrows);
|
|
abort();
|
|
}
|
|
|
|
m_pm = XCreatePixmap (dsp, win, wid, hei, d);
|
|
m_draw();
|
|
}
|
|
|
|
/* update exposed area */
|
|
m_refresh (e);
|
|
|
|
watch_cursor (0);
|
|
}
|
|
|
|
/* redraw the current scene */
|
|
static void
|
|
m_redraw (void)
|
|
{
|
|
watch_cursor (1);
|
|
|
|
m_draw ();
|
|
m_refresh(NULL);
|
|
|
|
watch_cursor (0);
|
|
}
|
|
|
|
/* copy the m_pm pixmap to the drawing area mda_w.
|
|
* if ep just copy that much, else copy all.
|
|
*/
|
|
static void
|
|
m_refresh(ep)
|
|
XExposeEvent *ep;
|
|
{
|
|
Display *dsp = XtDisplay(mda_w);
|
|
Window win = XtWindow (mda_w);
|
|
Pixmap pm = m_pm;
|
|
unsigned w, h;
|
|
int x, y;
|
|
|
|
/* ignore if no pixmap now */
|
|
if (!pm)
|
|
return;
|
|
|
|
if (ep) {
|
|
x = ep->x;
|
|
y = ep->y;
|
|
w = ep->width;
|
|
h = ep->height;
|
|
} else {
|
|
w = mncols+2*BORD;
|
|
h = mnrows+2*BORD;
|
|
x = y = 0;
|
|
}
|
|
|
|
XCopyArea (dsp, pm, win, m_fgc, x, y, w, h, x, y);
|
|
}
|
|
|
|
/* get the width, height and depth of the given drawable */
|
|
static void
|
|
m_getsize (d, wp, hp, dp)
|
|
Drawable d;
|
|
unsigned *wp, *hp, *dp;
|
|
{
|
|
Window root;
|
|
int x, y;
|
|
unsigned int bw;
|
|
|
|
XGetGeometry (XtD, d, &root, &x, &y, wp, hp, &bw, dp);
|
|
}
|
|
|
|
/* make the various gcs, handy pixel values and fill in mgray[].
|
|
* N.B. just call this once.
|
|
* TODO: reclaim old stuff if called again.
|
|
*/
|
|
static void
|
|
m_init_gcs (void)
|
|
{
|
|
Display *dsp = XtD;
|
|
Window win = XtWindow(toplevel_w);
|
|
Colormap cm = xe_cm;
|
|
XGCValues gcv;
|
|
unsigned int gcm;
|
|
Pixel fg;
|
|
Pixel p;
|
|
|
|
/* fg and bg */
|
|
get_something (mda_w, XmNforeground, (XtArgVal)&fg);
|
|
(void) get_color_resource (mda_w, "MoonBackground", &mbg);
|
|
|
|
gcm = GCForeground | GCBackground;
|
|
gcv.foreground = fg;
|
|
gcv.background = mbg;
|
|
m_fgc = XCreateGC (dsp, win, gcm, &gcv);
|
|
|
|
gcv.foreground = mbg;
|
|
gcv.background = fg;
|
|
m_bgc = XCreateGC (dsp, win, gcm, &gcv);
|
|
|
|
/* make the label marker gc */
|
|
(void) get_color_resource (mda_w, "MoonAnnotColor", &p);
|
|
gcm = GCForeground | GCBackground;
|
|
gcv.foreground = p;
|
|
gcv.background = mbg;
|
|
m_agc = XCreateGC (dsp, win, gcm, &gcv);
|
|
get_views_font (dsp, &m_fsp);
|
|
|
|
/* build gray-scale ramp for image */
|
|
nmgray = gray_ramp (dsp, cm, &mgray);
|
|
|
|
/* unless we will be using a bitmap, force color 0 to background. */
|
|
if (nmgray > 2)
|
|
mgray[0] = mbg;
|
|
}
|
|
|
|
/* given curlt/lg and Now compute supporting moon info in minfo */
|
|
static void
|
|
m_info(np)
|
|
Now *np;
|
|
{
|
|
double tzo = pref_get(PREF_ZONE)==PREF_LOCALTZ ? -tz/24.0 : 0;
|
|
double srlng;
|
|
double t;
|
|
double nfmjd, nm, fm;
|
|
|
|
moon_colong (mjd+MJD0, minfo.curlt, minfo.curlg, &srlng, NULL,
|
|
&minfo.cursunalt, &minfo.sslat);
|
|
|
|
/* convert colong to sunrise longitude */
|
|
srlng = -srlng;
|
|
range (&srlng, 2*PI);
|
|
minfo.srlng = srlng;
|
|
|
|
t = srlng-minfo.curlg;
|
|
range (&t, 2*PI);
|
|
minfo.curnsrt = mjd + tzo + t/(2*PI)*SYNP;
|
|
|
|
t = srlng-minfo.curlg+PI;
|
|
range (&t, 2*PI);
|
|
minfo.curnsst = mjd + tzo + t/(2*PI)*SYNP;
|
|
|
|
/* libration info */
|
|
llibration (mjd+MJD0, &minfo.llat, &minfo.llong);
|
|
minfo.limb = atan2 (-minfo.llong, minfo.llat);
|
|
if (minfo.limb < 0.0)
|
|
minfo.limb += 2*PI; /* limb angle is traditionally 0..360 */
|
|
minfo.tilt =
|
|
raddeg(sqrt(minfo.llat*minfo.llat + minfo.llong*minfo.llong));
|
|
|
|
/* age, days from prev new moon */
|
|
for (nfmjd = mjd, nm = mjd+1; nm > mjd; nfmjd -= 7)
|
|
moonnf (nfmjd, &nm, &fm);
|
|
minfo.age = mjd - nm;
|
|
}
|
|
|
|
/* update "more info" labels.
|
|
* then, if m_pm is defined, compute a scene onto it.
|
|
*/
|
|
static void
|
|
m_draw (void)
|
|
{
|
|
Now *np = mm_get_now();
|
|
|
|
/* update and print the latest info */
|
|
m_info (np);
|
|
m_pinfo ();
|
|
|
|
/* update time stamps too */
|
|
timestamp (np, dt_w);
|
|
timestamp (np, sdt_w);
|
|
|
|
if (m_pm)
|
|
mi_draw ();
|
|
}
|
|
|
|
/* draw moon onto m_pm, using minfo.
|
|
* N.B. this just fills the pixmap; call m_refresh() to copy to the screen.
|
|
*/
|
|
static void
|
|
mi_draw (void)
|
|
{
|
|
XGCValues gcv;
|
|
unsigned int gcm;
|
|
|
|
/* check assumptions -- even graphic uses image under the glass */
|
|
if (!mimage) {
|
|
printf ("No moon mimage!\n");
|
|
abort();
|
|
}
|
|
if (!m_xim) {
|
|
printf ("No m_xim!\n");
|
|
abort();
|
|
}
|
|
if (!m_pm) {
|
|
printf ("No m_pm Pixmap!\n");
|
|
abort();
|
|
}
|
|
|
|
/* fill in m_xim from mimage */
|
|
image_setup ();
|
|
|
|
/* create clip_mask from mimage when needed */
|
|
m_clip_mask_setup ();
|
|
|
|
/* clear m_pm */
|
|
XPSPaperColor (mbg);
|
|
XPSFillRectangle (XtD, m_pm, m_bgc, 0, 0, mncols+2*BORD, mnrows+2*BORD);
|
|
|
|
/* add sky background objects */
|
|
resetSkyObj();
|
|
if (option[SKY_OPT])
|
|
m_sky();
|
|
|
|
/* apply clipping mask to m_fgc */
|
|
gcm = GCClipXOrigin | GCClipYOrigin | GCClipMask;
|
|
gcv.clip_mask = m_clip_mask;
|
|
gcv.clip_x_origin = BORD;
|
|
gcv.clip_y_origin = BORD;
|
|
XChangeGC(XtD, m_fgc, gcm, &gcv);
|
|
|
|
/* copy m_xim within BORDER */
|
|
XPutImage (XtD, m_pm, m_fgc, m_xim, 0, 0, BORD, BORD, mncols, mnrows);
|
|
|
|
/* remove clipping mask from m_fgc */
|
|
gcm = GCClipMask;
|
|
gcv.clip_mask = None;
|
|
XChangeGC(XtD, m_fgc, gcm, &gcv);
|
|
|
|
XPSPixmap (m_pm, mncols+2*BORD, mnrows+2*BORD, xe_cm, m_bgc, 1);
|
|
|
|
/* add eclipse pen/umbra boundaries and sub points, if enabled */
|
|
if (option[UMBRA_OPT]) {
|
|
m_umbra();
|
|
m_sub ();
|
|
}
|
|
|
|
/* add the libration marker */
|
|
m_mark_libr ();
|
|
|
|
/* add grid, if enabled */
|
|
if (option[GRID_OPT])
|
|
m_grid();
|
|
|
|
/* add any desired feature labels */
|
|
m_labels();
|
|
|
|
/* add orientation markings */
|
|
m_orientation();
|
|
|
|
/* user annotation */
|
|
ano_draw (mda_w, m_pm, m_ano, 0);
|
|
}
|
|
|
|
/* convert relative moon center to/from X Windows coords depending on w2x.
|
|
* return whether visible.
|
|
*/
|
|
static int
|
|
m_ano (double *fracx, double *fracy, int *xp, int *yp, int w2x, int arg)
|
|
{
|
|
if (w2x) {
|
|
*xp = (int)floor(FX(*fracx*moonrad+leftmarg+moonrad) + BORD + 0.5);
|
|
*yp = (int)floor(FY(*fracy*moonrad+topmarg+moonrad) + BORD + 0.5);
|
|
} else {
|
|
*fracx = (double)(FX(*xp - BORD) - (leftmarg+moonrad))/moonrad;
|
|
*fracy = (double)(FY(*yp - BORD) - (topmarg+moonrad))/moonrad;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
/* label the database entries marked for name display */
|
|
static void
|
|
m_labels (void)
|
|
{
|
|
MoonDB *mp;
|
|
|
|
XSetFont (XtD, m_agc, m_fsp->fid);
|
|
|
|
for (mp = moondb; mp < &moondb[nmoondb]; mp++)
|
|
if (m_wantlabel(mp)) {
|
|
char *n = mp->name;
|
|
int l = strlen (n);
|
|
int x = FX(mp->x)+BORD;
|
|
int y = FY(mp->y)+BORD;
|
|
|
|
if (strstr (mp->type, "Landing")) {
|
|
XPSDrawArc (XtD, m_pm, m_agc, x-2, y-2, 5, 5, 0, 360*64);
|
|
XPSDrawString (XtD, m_pm, m_agc, x, y-5, n, l);
|
|
} else
|
|
XPSDrawString (XtD, m_pm, m_agc, x, y, n, l);
|
|
}
|
|
}
|
|
|
|
/* add background sky objects to m_pm and to skyobjs[] list */
|
|
static void
|
|
m_sky (void)
|
|
{
|
|
static int before;
|
|
Now *np = mm_get_now();
|
|
double scale; /* image scale, rads per pixel */
|
|
double mra, mdec; /* moon's ra and dec */
|
|
double cmdec; /* cos mdec */
|
|
double mlat, mlng; /* moon's ecliptic coords */
|
|
double cmlat; /* cos mlat*/
|
|
double maxr; /* max dst from center we want to draw, rads */
|
|
double hfov, vfov;
|
|
int w, h;
|
|
DBScan dbs;
|
|
Obj *moonop;
|
|
Obj *op;
|
|
|
|
if (!before && pref_get(PREF_EQUATORIAL) == PREF_GEO) {
|
|
xe_msg (1, "Equatorial preference should probably be set to Topocentric");
|
|
before = 1;
|
|
}
|
|
|
|
/* get current moon info and derive scale, etc */
|
|
moonop = db_basic (MOON);
|
|
db_update (moonop);
|
|
mra = moonop->s_ra;
|
|
mdec = moonop->s_dec;
|
|
cmdec = cos(mdec);
|
|
eq_ecl (mjd, mra, mdec, &mlat, &mlng);
|
|
cmlat = cos(mlat);
|
|
scale = (degrad(moonop->s_size/3600.0)/2.0) / moonrad;
|
|
maxr = 2*(sqrt((double)mnrows*mnrows + mncols*mncols) + BORD)*scale;
|
|
|
|
w = mncols + 2 * BORD;
|
|
h = mnrows + 2 * BORD;
|
|
hfov = w * scale;
|
|
vfov = h * scale;
|
|
|
|
/* load field stars */
|
|
m_loadfs (np, mra, mdec);
|
|
|
|
/* scan the database and draw whatever is near */
|
|
for (db_scaninit(&dbs, ALLM, fstars, nfstars);
|
|
(op = db_scan (&dbs)) != NULL; ) {
|
|
|
|
double ra, dec; /* object's ra/dec */
|
|
double olat, olng; /* object's ecliptic lat/lng */
|
|
double dlat, dlng; /* diff from moon's */
|
|
int dx, dy;
|
|
int x, y;
|
|
int diam;
|
|
GC gc;
|
|
|
|
if (is_planet (op, MOON)) {
|
|
/* we draw it elsewhere :-) */
|
|
continue;
|
|
}
|
|
|
|
db_update (op);
|
|
ra = op->s_ra;
|
|
dec = op->s_dec;
|
|
|
|
/* find size, in pixels. */
|
|
diam = magdiam (FMAG, 2, scale, get_mag(op),
|
|
degrad(op->s_size/3600.0));
|
|
/* reject if too faint */
|
|
if (diam <= 0)
|
|
continue;
|
|
|
|
/* or if it's obviously outside field of view */
|
|
if (fabs(mdec - dec) > maxr || delra(mra - ra)*cmdec > maxr)
|
|
continue;
|
|
|
|
/* ecliptic coords match moons tilt far better than equatorial */
|
|
eq_ecl (mjd, ra, dec, &olat, &olng);
|
|
|
|
/* find [x,y] relative to image center */
|
|
dlat = mlat - olat;
|
|
dlng = mlng - olng;
|
|
dx = (int)floor((dlng*cmlat)/scale + 0.5); /* + right */
|
|
dy = (int)floor(dlat/scale + 0.5); /* + down */
|
|
|
|
/* allow for flipping and shift to find window coords */
|
|
x = FX(dx+mncols/2) + BORD;
|
|
y = FY(dy+mnrows/2) + BORD;
|
|
|
|
/* pick a gc */
|
|
obj_pickgc(op, toplevel_w, &gc);
|
|
|
|
/* draw 'er */
|
|
sv_draw_obj_x (XtD, m_pm, gc, op, x, y, diam, 1, option[FLIPTB_OPT], option[FLIPLR_OPT], 0, 1, mdec, mra, vfov, hfov, w, h);
|
|
|
|
/* add to skyobjs[] list */
|
|
addSkyObj (op, x, y);
|
|
}
|
|
|
|
sv_draw_obj (XtD, m_pm, (GC)0, NULL, 0, 0, 0, 0); /* flush */
|
|
}
|
|
|
|
/* load field stars around the given location, unless current set is
|
|
* already close enough.
|
|
*/
|
|
static void
|
|
m_loadfs (np, ra, dec)
|
|
Now *np;
|
|
double ra, dec;
|
|
{
|
|
|
|
if (fstars && fabs(dec-fsdec)<FSMOVE && cos(dec)*delra(ra-fsra)<FSMOVE)
|
|
return;
|
|
|
|
if (fstars) {
|
|
free ((void *)fstars);
|
|
fstars = NULL;
|
|
nfstars = 0;
|
|
}
|
|
|
|
nfstars = fs_fetch (np, ra, dec, FSFOV, FSMAG, &fstars);
|
|
|
|
if (nfstars > 0) {
|
|
xe_msg (0, "Moon View added %d field stars", nfstars);
|
|
fsdec = dec;
|
|
fsra = ra;
|
|
}
|
|
}
|
|
|
|
/* given a MoonDB entry, return 1 if we want to show its label now, else 0. */
|
|
static int
|
|
m_wantlabel (mp)
|
|
MoonDB *mp;
|
|
{
|
|
/* always show if marked as persistent and labels are on */
|
|
if (option[LABELS_OPT] && mp->pl)
|
|
return (1);
|
|
|
|
/* or if want spacecraft and it appears to be one and
|
|
* we are at full size or this is an Apollo site
|
|
*/
|
|
if (option[SPACECRAFT_OPT] && strstr (mp->type, "Landing")
|
|
&& (mshrink == 1 || strstr (mp->name, "Apollo")))
|
|
return (1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* draw the N/S E/W labels on the four edges of the m_pm
|
|
* we are showing lunar coords.
|
|
*/
|
|
static void
|
|
m_orientation (void)
|
|
{
|
|
int fw, fa, fd;
|
|
int dir, asc, des;
|
|
XCharStruct xcs;
|
|
|
|
XQueryTextExtents (XtD, m_fsp->fid, "W", 1, &dir, &asc, &des, &xcs);
|
|
fw = xcs.width;
|
|
fa = xcs.ascent;
|
|
fd = xcs.descent;
|
|
|
|
XSetFont (XtD, m_agc, m_fsp->fid);
|
|
XPSDrawString (XtD, m_pm, m_agc, BORD+(mncols-fw)/2, BORD-fd-LGAP,
|
|
option[FLIPTB_OPT] ? "S" : "N", 1);
|
|
XPSDrawString (XtD, m_pm, m_agc, BORD+(mncols-fw)/2,BORD+mnrows+fa+LGAP,
|
|
option[FLIPTB_OPT] ? "N" : "S", 1);
|
|
XPSDrawString (XtD, m_pm, m_agc, BORD-fw-LGAP, BORD+(mnrows+fa)/2,
|
|
option[FLIPLR_OPT] ? "E" : "W", 1);
|
|
XPSDrawString (XtD, m_pm, m_agc, BORD+mncols+LGAP, BORD+(mnrows+fa)/2,
|
|
option[FLIPLR_OPT] ? "W" : "E", 1);
|
|
}
|
|
|
|
/* draw a coordinate grid over the image moon on m_pm */
|
|
static void
|
|
m_grid (void)
|
|
{
|
|
#define GSP degrad(15.0) /* grid spacing */
|
|
#define FSP (GSP/4.) /* fine spacing */
|
|
Display *dsp = XtDisplay (mda_w);
|
|
Window win = m_pm;
|
|
double lt, lg;
|
|
int x, y;
|
|
|
|
/* lines of equal lat */
|
|
for (lt = PI/2 - GSP; lt >= -PI/2 + GSP; lt -= GSP) {
|
|
XPoint xpt[(int)(PI/FSP)+1];
|
|
int npts = 0;
|
|
|
|
for (lg = -PI/2; lg <= PI/2; lg += FSP) {
|
|
if (ll2xy(lt, lg, &x, &y) < 0)
|
|
continue;
|
|
if (npts >= XtNumber(xpt)) {
|
|
printf ("Moon lat grid overflow\n");
|
|
abort();
|
|
}
|
|
xpt[npts].x = FX(x) + BORD;
|
|
xpt[npts].y = FY(y) + BORD;
|
|
npts++;
|
|
}
|
|
XPSDrawLines (dsp, win, m_agc, xpt, npts, CoordModeOrigin);
|
|
}
|
|
|
|
/* lines of equal longitude */
|
|
for (lg = -PI/2; lg <= PI/2; lg += GSP) {
|
|
XPoint xpt[(int)(PI/FSP)+1];
|
|
int npts = 0;
|
|
|
|
for (lt = -PI/2; lt <= PI/2; lt += FSP) {
|
|
if (ll2xy(lt, lg, &x, &y) < 0)
|
|
continue;
|
|
if (npts >= XtNumber(xpt)) {
|
|
printf ("Moon lng grid overflow\n");
|
|
abort();
|
|
}
|
|
xpt[npts].x = FX(x) + BORD;
|
|
xpt[npts].y = FY(y) + BORD;
|
|
npts++;
|
|
}
|
|
XPSDrawLines (dsp, win, m_agc, xpt, npts, CoordModeOrigin);
|
|
}
|
|
}
|
|
|
|
/* draw an X at the subearth and a circle at the subsolar spot using minfo */
|
|
static void
|
|
m_sub (void)
|
|
{
|
|
#define SUBR 4
|
|
Display *dsp = XtDisplay (mda_w);
|
|
Window win = m_pm;
|
|
int x, y;
|
|
|
|
/* subearth point */
|
|
if (ll2xy (minfo.llat, minfo.llong, &x, &y) == 0) {
|
|
x = FX(x) + BORD;
|
|
y = FY(y) + BORD;
|
|
XPSDrawLine (dsp, win, m_agc, x-SUBR, y-SUBR, x+SUBR, y+SUBR);
|
|
XPSDrawLine (dsp, win, m_agc, x-SUBR, y+SUBR, x+SUBR, y-SUBR);
|
|
}
|
|
|
|
/* subsolar point -- open circle */
|
|
if (ll2xy (minfo.sslat, minfo.srlng + PI/2, &x, &y) == 0) {
|
|
x = FX(x) + BORD;
|
|
y = FY(y) + BORD;
|
|
XPSDrawArc (dsp, win, m_agc, x-SUBR/2, y-SUBR/2,SUBR,SUBR,0,360*64);
|
|
}
|
|
|
|
/* anti-subsolar point -- filled circle */
|
|
if (ll2xy (-minfo.sslat, minfo.srlng - PI/2, &x, &y) == 0) {
|
|
x = FX(x) + BORD;
|
|
y = FY(y) + BORD;
|
|
XPSFillArc (dsp, win, m_agc, x-SUBR/2, y-SUBR/2,SUBR,SUBR,0,360*64);
|
|
}
|
|
}
|
|
|
|
/* create m_xim of size mnrowsXmncols, depth mdepth and bit-per-pixel mbpp.
|
|
* make a Bitmap if only have 1 bit per pixel, otherwise a Pixmap.
|
|
* return 0 if ok else -1 and xe_msg().
|
|
*/
|
|
static int
|
|
mxim_create (void)
|
|
{
|
|
Display *dsp = XtDisplay (mda_w);
|
|
int nbytes = (mnrows+7)*(mncols+7)*mbpp/8;
|
|
char *data;
|
|
|
|
/* get memory for image pixels. */
|
|
data = (char *) malloc (nbytes);
|
|
if (!data) {
|
|
xe_msg(1, "Can not get %d bytes for shadow pixels", nbytes);
|
|
return (-1);
|
|
}
|
|
|
|
/* create the XImage */
|
|
m_xim = XCreateImage (dsp, XDefaultVisual (dsp, DefaultScreen(dsp)),
|
|
/* depth */ mbpp == 1 ? 1 : mdepth,
|
|
/* format */ mbpp == 1 ? XYBitmap : ZPixmap,
|
|
/* offset */ 0,
|
|
/* data */ data,
|
|
/* width */ mncols,
|
|
/* height */ mnrows,
|
|
/* pad */ mbpp < 8 ? 8 : mbpp,
|
|
/* bpl */ 0);
|
|
if (!m_xim) {
|
|
xe_msg (1, "Can not create shadow XImage");
|
|
free ((void *)data);
|
|
return (-1);
|
|
}
|
|
|
|
m_xim->bitmap_bit_order = LSBFirst;
|
|
m_xim->byte_order = LSBFirst;
|
|
|
|
/* ok */
|
|
return (0);
|
|
}
|
|
|
|
/* compute a scene in m_xim, knowledge of the sunrise longitude and
|
|
* earthshine.
|
|
*/
|
|
static void
|
|
image_setup (void)
|
|
{
|
|
double esrlng = minfo.srlng-CLNG; /* correct for earth viewpoint */
|
|
int right = cos(esrlng) < 0; /*whther shadw reaches to right limb*/
|
|
double sinsrl = sin(esrlng);
|
|
unsigned char *mp;
|
|
int x, y;
|
|
int esf;
|
|
|
|
get_something (eshine_w, XmNvalue, (XtArgVal)&esf);
|
|
|
|
/* copy intensities through mgray[] map to get pixels */
|
|
for (y = 0; y < mnrows; y++) {
|
|
int lx, rx; /* left and right edge of scan line to darken */
|
|
int fy; /* (possibly) flipped y */
|
|
|
|
(void) m_esedges (y, sinsrl, right, &lx, &rx);
|
|
fy = FY(y);
|
|
|
|
/* scan across the whole row, drawing shadow between lx and rx */
|
|
mp = &mimage[fy*mncols];
|
|
for (x = 0; x < mncols; x++) {
|
|
int i = (int)(*mp++);
|
|
int v;
|
|
|
|
if (x >= lx && x <= rx)
|
|
v = i*nmgray*esf/ESHINEF/256; /* shadow */
|
|
else
|
|
v = i*nmgray/256;
|
|
|
|
XPutPixel (m_xim, x, fy, mgray[v]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* compute the left and right edge of earthshine for the given y.
|
|
* all coords wrt to m_xim and current orientation.
|
|
* sinsrl is sin of longitude of the rising sun.
|
|
*/
|
|
static int
|
|
m_esedges (y, sinsrl, right, lxp, rxp)
|
|
int y; /* image y */
|
|
double sinsrl; /* sin of longitude of the rising sun */
|
|
int right; /* whether shadow reaches to right limb */
|
|
int *lxp, *rxp; /* left and right x of edges of earthshine */
|
|
{
|
|
int lx, rx; /* left and right edge of scan line to darken */
|
|
int yc; /* y with respect to moon center */
|
|
int ret; /* return value */
|
|
|
|
yc = y - (topmarg + moonrad);
|
|
|
|
/* find left and right edge of shadow */
|
|
if (abs(yc) <= moonrad) {
|
|
int r; /* pixels to limb at this y */
|
|
|
|
r = (int)(sqrt((double)(moonrad*moonrad - yc*yc))+1); /* round up */
|
|
|
|
/* compute shadow edges with respect to center */
|
|
if (right) {
|
|
rx = r;
|
|
lx = -(int)(r * sinsrl);
|
|
} else {
|
|
lx = -r;
|
|
rx = (int)(r * sinsrl);
|
|
}
|
|
|
|
/* convert to X coords */
|
|
lx += leftmarg + moonrad;
|
|
rx += leftmarg + moonrad;
|
|
|
|
ret = 0;
|
|
} else {
|
|
/* above or below moon image so no shadow */
|
|
lx = -1;
|
|
rx = mncols;
|
|
ret = -1;
|
|
}
|
|
|
|
/* allow for flipping */
|
|
if (option[FLIPLR_OPT]) {
|
|
int tmp = lx;
|
|
lx = FX(rx);
|
|
rx = FX(tmp);
|
|
}
|
|
|
|
*lxp = lx;
|
|
*rxp = rx;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/* create a clipping mask for applying m_xim to m_pm */
|
|
static void
|
|
m_clip_mask_setup (void)
|
|
{
|
|
if (!m_clip_mask)
|
|
{
|
|
XGCValues gcv;
|
|
Window win = RootWindow(XtD, DefaultScreen(XtD));
|
|
GC sky_gc, moon_gc;
|
|
|
|
unsigned char *mp;
|
|
int x, y;
|
|
|
|
m_clip_mask = XCreatePixmap(XtD, win, mncols, mnrows, 1);
|
|
|
|
/* setup clipping mask for m_fgc */
|
|
gcv.foreground = 0;
|
|
sky_gc = XCreateGC(XtD, m_clip_mask, GCForeground, &gcv);
|
|
gcv.foreground = 1;
|
|
moon_gc = XCreateGC(XtD, m_clip_mask, GCForeground, &gcv);
|
|
|
|
XFillRectangle(XtD, m_clip_mask, moon_gc, 0, 0, mncols, mnrows);
|
|
|
|
for (y = 0; y < mnrows; y++) {
|
|
/* scan across the whole row */
|
|
mp = &mimage[y*mncols];
|
|
for (x = 0; x < mncols; x++) {
|
|
int i = (int)(*mp++);
|
|
|
|
if (!i)
|
|
XDrawPoint (XtD, m_clip_mask, sky_gc, x, y);
|
|
}
|
|
}
|
|
XFreeGC(XtD, sky_gc);
|
|
XFreeGC(XtD, moon_gc);
|
|
}
|
|
}
|
|
|
|
/* delete clipping mask so new one will get built when needed */
|
|
static void
|
|
m_free_clip_mask (void)
|
|
{
|
|
if (m_clip_mask) {
|
|
XFreePixmap (XtD, m_clip_mask);
|
|
m_clip_mask = 0;
|
|
}
|
|
}
|
|
|
|
/* go through database and set screen loc given lat/long */
|
|
static void
|
|
m_dbloc (void)
|
|
{
|
|
MoonDB *mp;
|
|
|
|
for (mp = moondb; mp < &moondb[nmoondb]; mp++)
|
|
ll2xy (mp->lt, mp->lg, &mp->x, &mp->y);
|
|
}
|
|
|
|
/* do everything necessary to see a fresh image, shrunk by factor f:
|
|
* read full moon file; shrink by a factor of f; replace mimage with result;
|
|
* resize mda_w and m_xim; recompute image [x,y] values match new scale.
|
|
* when done, set mimage, m_xim, mncols, mnrows, topmarg, leftmarg and moonrad.
|
|
* return 0 if all ok, else xe_msg() and return -1.
|
|
*/
|
|
static int
|
|
m_shrink (f)
|
|
int f;
|
|
{
|
|
char msg[1024];
|
|
char fn[1024];
|
|
FImage moonfits;
|
|
unsigned char *newim, *im;
|
|
int imnr, imnc;
|
|
int newnr, newnc;
|
|
int v;
|
|
int fd;
|
|
|
|
/* open moon image */
|
|
(void) sprintf (fn, "%s/auxil/moon.fts", getShareDir());
|
|
fd = openh (fn, 0);
|
|
if (fd < 0) {
|
|
xe_msg (1, "%s: %s\n", fn, syserrstr());
|
|
return (-1);
|
|
}
|
|
|
|
/* read moon file into moonfits */
|
|
if (readFITS (fd, &moonfits, msg) < 0) {
|
|
xe_msg (1, "%s: %s", fn, msg);
|
|
(void) close (fd);
|
|
return (-1);
|
|
}
|
|
(void) close (fd);
|
|
|
|
/* make sure it's the new flipped version */
|
|
if (getIntFITS (&moonfits, "XEVERS", &v) < 0 || v != XEVERS) {
|
|
xe_msg (1, "%s: Incorrect version", fn);
|
|
return (-1);
|
|
}
|
|
|
|
/* make some local shortcuts */
|
|
im = (unsigned char *) moonfits.image;
|
|
imnr = moonfits.sh;
|
|
imnc = moonfits.sw;
|
|
|
|
/* make some sanity checks */
|
|
|
|
if (moonfits.bitpix != 8 || imnr != MNROWS || imnc != MNCOLS) {
|
|
xe_msg (1, "%s: Expected %d x %d but found %d x %d",
|
|
fn, MNROWS, MNCOLS, imnr, imnc);
|
|
resetFImage (&moonfits);
|
|
return (-1);
|
|
}
|
|
|
|
/* set newim to resized version of im (it _is_ im if f is just 1) */
|
|
if (f != 1) {
|
|
unsigned char *newmem;
|
|
|
|
newnr = imnr / f;
|
|
newnc = imnc / f;
|
|
|
|
/* get memory for resized copy */
|
|
newmem = (unsigned char *) malloc (newnr * newnc);
|
|
if (!newmem) {
|
|
xe_msg (1, "No mem for 1/%dX %d x %d -> %d x %d resize",
|
|
f, imnr, imnc, newnr, newnc);
|
|
free ((void *)im);
|
|
return (-1);
|
|
}
|
|
|
|
m_resize (im, MNROWS, MNCOLS, f, newmem);
|
|
newim = newmem;
|
|
free ((void *)im);
|
|
} else {
|
|
newim = im;
|
|
newnr = MNROWS;
|
|
newnc = MNCOLS;
|
|
}
|
|
|
|
/* commit newim to mimage -- set global metrics */
|
|
if (mimage) {
|
|
free ((void *)mimage);
|
|
mimage = NULL;
|
|
}
|
|
mimage = newim;
|
|
mnrows = newnr;
|
|
mncols = newnc;
|
|
topmarg = (int)((double)TOPMARG/f + 0.5);
|
|
leftmarg = (int)((double)LEFTMARG/f + 0.5);
|
|
moonrad = (int)((double)MOONRAD/f + 0.5);
|
|
|
|
/* dither mimage if we only have 2 colors to work with */
|
|
if (mbpp == 1)
|
|
mBWdither();
|
|
|
|
/* flip mimage, as desired */
|
|
if (option[FLIPTB_OPT])
|
|
fliptb();
|
|
if (option[FLIPLR_OPT])
|
|
fliplr();
|
|
|
|
/* (re)create the X image */
|
|
if (m_xim) {
|
|
free ((void *)m_xim->data);
|
|
m_xim->data = NULL;
|
|
XDestroyImage (m_xim);
|
|
m_xim = NULL;
|
|
}
|
|
if (mxim_create() < 0) {
|
|
resetFImage (&moonfits);
|
|
mimage = NULL;
|
|
return (-1);
|
|
}
|
|
|
|
/* delete clip_mask so new one will get built when needed */
|
|
m_free_clip_mask ();
|
|
|
|
/* delete pixmap so new one will get built on next expose */
|
|
if (m_pm) {
|
|
XFreePixmap (XtD, m_pm);
|
|
m_pm = 0;
|
|
}
|
|
|
|
/* recompute location of db on image at this scale */
|
|
m_dbloc();
|
|
|
|
/* size the drawing area to hold the new image plus a border.
|
|
* this will give us an expose event to show the new image.
|
|
* also center the scrollbars.
|
|
*/
|
|
m_sizewidgets ();
|
|
centerScrollBars(msw_w);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* set size of mda_w as desired based on mnrows and mncols */
|
|
static void
|
|
m_sizewidgets (void)
|
|
{
|
|
int neww = mncols + 2*BORD;
|
|
int newh = mnrows + 2*BORD;
|
|
|
|
/* mda_w should be image size + BORD all around */
|
|
set_something (mda_w, XmNwidth, (XtArgVal)neww);
|
|
set_something (mda_w, XmNheight, (XtArgVal)newh);
|
|
}
|
|
|
|
/* copy image in, of size nr x nr, to out by shrinking a factor f.
|
|
* N.B. we assume out is (nr/f) * (nr/f) bytes.
|
|
*/
|
|
static void
|
|
m_resize(in, nr, nc, f, out)
|
|
unsigned char *in, *out;
|
|
int nr, nc;
|
|
int f;
|
|
{
|
|
int outx, outy;
|
|
int noutx, nouty;
|
|
|
|
noutx = nc/f;
|
|
nouty = nr/f;
|
|
for (outy = 0; outy < nouty; outy++) {
|
|
unsigned char *inrp = &in[outy*f*nr];
|
|
for (outx = 0; outx < noutx; outx++) {
|
|
*out++ = *inrp;
|
|
inrp += f;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* dither mimage into a 2-intensity image: 0 and 255.
|
|
* form 2x2 tiles whose pattern depends on intensity peak and spacial layout.
|
|
*/
|
|
static void
|
|
mBWdither (void)
|
|
{
|
|
int idx[4];
|
|
int y;
|
|
|
|
idx[0] = 0;
|
|
idx[1] = 1;
|
|
idx[2] = mncols;
|
|
idx[3] = mncols+1;
|
|
|
|
for (y = 0; y < mnrows - 1; y += 2) {
|
|
unsigned char *mp = &mimage[y*mncols];
|
|
unsigned char *lp;
|
|
|
|
for (lp = mp + mncols - 1; mp < lp; mp += 2) {
|
|
int sum, numon;
|
|
int i;
|
|
|
|
sum = 0;
|
|
for (i = 0; i < 4; i++)
|
|
sum += (int)mp[idx[i]];
|
|
numon = sum*5/1021; /* 1021 is 255*4 + 1 */
|
|
|
|
for (i = 0; i < 4; i++)
|
|
mp[idx[i]] = 0;
|
|
|
|
switch (numon) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
mp[idx[0]] = 255;
|
|
break;
|
|
case 3:
|
|
mp[idx[0]] = 255;
|
|
mp[idx[1]] = 255;
|
|
mp[idx[3]] = 255;
|
|
break;
|
|
case 4:
|
|
mp[idx[0]] = 255;
|
|
mp[idx[1]] = 255;
|
|
mp[idx[2]] = 255;
|
|
mp[idx[3]] = 255;
|
|
break;
|
|
default:
|
|
printf ("Bad numon: %d\n", numon);
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* draw umbra and penumbra boundaries */
|
|
static void
|
|
m_umbra (void)
|
|
{
|
|
Now *np = mm_get_now();
|
|
Obj *mop = db_basic (MOON);
|
|
Obj *sop = db_basic (SUN);
|
|
double scale; /* image scale, rads per pixel */
|
|
double mrad; /* moon radius, rads */
|
|
double ara, adec; /* anti-solar loc, equatorial coords, rads */
|
|
double alat, alng; /* anti-solar loc, ecliptic coords, rads */
|
|
double mlat, mlng; /* moon loc, ecliptic coords, rads */
|
|
double dlat, dlng; /* difference, rads */
|
|
double cmlat; /* cos moon's lat */
|
|
double sed, med; /* sun-earth and moon-earth dist, au */
|
|
double u, p; /* umbra and penumbra radius, m at moon dist*/
|
|
double maxr;
|
|
int dx, dy;
|
|
int x, y, r;
|
|
|
|
/* get basic info */
|
|
db_update (mop);
|
|
db_update (sop);
|
|
mrad = degrad(mop->s_size/3600.0)/2.0;
|
|
scale = mrad / moonrad;
|
|
ara = sop->s_gaera + PI;
|
|
adec = -sop->s_gaedec;
|
|
eq_ecl (mjd, ara, adec, &alat, &alng);
|
|
eq_ecl (mjd, mop->s_gaera, mop->s_gaedec, &mlat, &mlng);
|
|
dlat = mlat - alat;
|
|
dlng = mlng - alng;
|
|
cmlat = cos (mlat);
|
|
|
|
/* skip if obviously outside fov */
|
|
maxr = 2*(sqrt((double)mnrows*mnrows + mncols*mncols) + BORD)*scale;
|
|
if (fabs(dlat) > maxr || delra(dlng)*cmlat > maxr)
|
|
return;
|
|
|
|
/* find center of circle */
|
|
dx = (int)floor((dlng*cmlat)/scale + 0.5); /* + right */
|
|
dy = (int)floor(dlat/scale + 0.5); /* + down */
|
|
x = FX(dx+mncols/2) + BORD;
|
|
y = FY(dy+mnrows/2) + BORD;
|
|
|
|
/* compute diameters at moon (based on similar triangles) */
|
|
med = mop->s_edist;
|
|
sed = sop->s_edist;
|
|
u = ERAD - med/sed*(SRAD-ERAD);
|
|
r = (int)floor(u/MRAD*moonrad + 0.5);
|
|
XPSDrawArc (XtD, m_pm, m_fgc, x-r, y-r, 2*r, 2*r, 0, 360*64);
|
|
p = ERAD + med/sed*(SRAD-ERAD);
|
|
r = (int)floor(p/MRAD*moonrad + 0.5);
|
|
XSetLineAttributes (XtD, m_fgc, 0, LineOnOffDash, CapButt, JoinMiter);
|
|
XPSDrawArc (XtD, m_pm, m_fgc, x-r, y-r, 2*r, 2*r, 0, 360*64);
|
|
XSetLineAttributes (XtD, m_fgc, 0, LineSolid, CapButt, JoinMiter);
|
|
|
|
/* tried to draw a line along path by computing ecl loc +- a few
|
|
* hours from now but doesn't work since the perspective changes.
|
|
*/
|
|
}
|
|
|
|
/* flip mimage left/right */
|
|
static void
|
|
fliplr (void)
|
|
{
|
|
int x, y;
|
|
|
|
for (y = 0; y < mnrows; y++) {
|
|
unsigned char *rp = &mimage[y*mncols];
|
|
for (x = 0; x < mncols/2; x++) {
|
|
unsigned char tmp = rp[x];
|
|
rp[x] = rp[mncols-x-1];
|
|
rp[mncols-x-1] = tmp;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* flip mimage top/bottom.
|
|
* N.B. will flip back option if can't do it for some reason.
|
|
*/
|
|
static void
|
|
fliptb (void)
|
|
{
|
|
char buf[2048]; /* plenty :-) */
|
|
int y;
|
|
|
|
if (mncols > sizeof(buf)) {
|
|
xe_msg (1, "Can not flip -- rows are longer than %ld",
|
|
(long)sizeof(buf));
|
|
XmToggleButtonSetState (option_w[FLIPTB_OPT],
|
|
option[FLIPTB_OPT] ^= 1, False);
|
|
return;
|
|
}
|
|
|
|
|
|
for (y = 0; y < mnrows/2; y++) {
|
|
unsigned char *r0 = &mimage[y*mncols];
|
|
unsigned char *r1 = &mimage[(mnrows-y-1)*mncols];
|
|
|
|
(void) memcpy (buf, (void *)r0, mncols);
|
|
(void) memcpy ((void *)r0, (void *)r1, mncols);
|
|
(void) memcpy ((void *)r1, buf, mncols);
|
|
}
|
|
}
|
|
|
|
/* draw a marker on m_pm to show the limb angle favored by libration */
|
|
static void
|
|
m_mark_libr (void)
|
|
{
|
|
int r; /* radius of marker */
|
|
int x, y; /* center of marker */
|
|
|
|
r = moonrad/LMFRAC;
|
|
x = leftmarg + (int)(moonrad*(1 - sin(minfo.limb)));
|
|
y = topmarg + (int)(moonrad*(1 - cos(minfo.limb)));
|
|
|
|
x = FX(x);
|
|
y = FY(y);
|
|
|
|
XPSFillArc (XtD, m_pm, m_agc, BORD+x-r, BORD+y-r, 2*r, 2*r, 0, 360*64);
|
|
}
|
|
|
|
/* report the location of x,y, which are with respect to mda_w.
|
|
* N.B. allow for flipping and the borders.
|
|
*/
|
|
static void
|
|
m_reportloc (dsp, win, x, y)
|
|
Display *dsp;
|
|
Window win;
|
|
int x, y;
|
|
{
|
|
double lt, lg;
|
|
|
|
/* convert from mda_w coords to m_xim coords */
|
|
x -= BORD;
|
|
y -= BORD;
|
|
|
|
if (xy2ll (FX(x), FY(y), <, &lg) == 0) {
|
|
Now *np = mm_get_now();
|
|
|
|
f_showit (infot_w, "User cursor:");
|
|
minfo.curlt = lt;
|
|
minfo.curlg = lg;
|
|
m_info (np);
|
|
m_pinfo ();
|
|
|
|
} else {
|
|
set_xmstring (lat_w, XmNlabelString, " ");
|
|
set_xmstring (lng_w, XmNlabelString, " ");
|
|
set_xmstring (sunalt_w, XmNlabelString, " ");
|
|
set_xmstring (nsrd_w, XmNlabelString, " ");
|
|
set_xmstring (nsrt_w, XmNlabelString, " ");
|
|
set_xmstring (nssd_w, XmNlabelString, " ");
|
|
set_xmstring (nsst_w, XmNlabelString, " ");
|
|
}
|
|
}
|
|
|
|
/* print minfo */
|
|
static void
|
|
m_pinfo (void)
|
|
{
|
|
f_dm_angle (lat_w, minfo.curlt);
|
|
f_dm_angle (lng_w, minfo.curlg);
|
|
f_dm_angle (sunalt_w, minfo.cursunalt);
|
|
f_date (nsrd_w, mjd_day(minfo.curnsrt));
|
|
f_mtime (nsrt_w, mjd_hr(minfo.curnsrt));
|
|
f_date (nssd_w, mjd_day(minfo.curnsst));
|
|
f_mtime (nsst_w, mjd_hr(minfo.curnsst));
|
|
|
|
/* update cursor indep info - always on */
|
|
f_dm_angle (srlng_w, minfo.srlng);
|
|
f_dm_angle (sslat_w, minfo.sslat);
|
|
f_dm_angle (llat_w, minfo.llat);
|
|
f_dm_angle (llong_w, minfo.llong);
|
|
f_dm_angle (limb_w, minfo.limb);
|
|
f_double (lib_w, "%6.3f", minfo.tilt);
|
|
f_double (age_w, "%6.3f", minfo.age);
|
|
}
|
|
|
|
/* make glass_xim of size GLASSSZ*GLASSMAG and same genre as m_xim.
|
|
* leave glass_xim NULL if trouble.
|
|
*/
|
|
static void
|
|
makeGlassImage (dsp)
|
|
Display *dsp;
|
|
{
|
|
int nbytes = (GLASSSZ*GLASSMAG+7) * (GLASSSZ*GLASSMAG+7) * mbpp/8;
|
|
char *glasspix = (char *) malloc (nbytes);
|
|
|
|
if (!glasspix) {
|
|
xe_msg (0, "Can not malloc %d for Glass pixels", nbytes);
|
|
return;
|
|
}
|
|
|
|
glass_xim = XCreateImage (dsp, XDefaultVisual (dsp, DefaultScreen(dsp)),
|
|
/* depth */ m_xim->depth,
|
|
/* format */ m_xim->format,
|
|
/* offset */ 0,
|
|
/* data */ glasspix,
|
|
/* width */ GLASSSZ*GLASSMAG,
|
|
/* height */ GLASSSZ*GLASSMAG,
|
|
/* pad */ mbpp < 8 ? 8 : mbpp,
|
|
/* bpl */ 0);
|
|
|
|
if (!glass_xim) {
|
|
free ((void *)glasspix);
|
|
xe_msg (0, "Can not make Glass XImage");
|
|
return;
|
|
}
|
|
|
|
glass_xim->bitmap_bit_order = LSBFirst;
|
|
glass_xim->byte_order = LSBFirst;
|
|
}
|
|
|
|
/* make glassGC */
|
|
static void
|
|
makeGlassGC (dsp, win)
|
|
Display *dsp;
|
|
Window win;
|
|
{
|
|
XGCValues gcv;
|
|
unsigned int gcm;
|
|
Pixel p;
|
|
|
|
(void) get_color_resource (mda_w, "GlassBorderColor", &p);
|
|
gcm = GCForeground;
|
|
gcv.foreground = p;
|
|
glassGC = XCreateGC (dsp, win, gcm, &gcv);
|
|
}
|
|
|
|
/* handle the operation of the magnifying glass.
|
|
* this is called whenever there is left button activity over the image.
|
|
*/
|
|
static void
|
|
doGlass (dsp, win, b1p, m1, b1r, wx, wy)
|
|
Display *dsp;
|
|
Window win;
|
|
int b1p, m1, b1r; /* button/motion state */
|
|
int wx, wy; /* window coords of cursor */
|
|
{
|
|
static int lastwx, lastwy;
|
|
int rx, ry, rw, rh; /* region */
|
|
|
|
/* check for first-time stuff */
|
|
if (!glass_xim)
|
|
makeGlassImage (dsp);
|
|
if (!glass_xim)
|
|
return; /* oh well */
|
|
if (!glassGC)
|
|
makeGlassGC (dsp, win);
|
|
|
|
if (m1) {
|
|
|
|
/* motion: put back old pixels that won't just be covered again */
|
|
|
|
/* first the vertical strip that is uncovered */
|
|
|
|
rh = GLASSSZ*GLASSMAG;
|
|
ry = lastwy - (GLASSSZ*GLASSMAG/2);
|
|
if (ry < 0) {
|
|
rh += ry;
|
|
ry = 0;
|
|
}
|
|
if (wx < lastwx) {
|
|
rw = lastwx - wx; /* cursor moved left */
|
|
rx = wx + (GLASSSZ*GLASSMAG/2);
|
|
} else {
|
|
rw = wx - lastwx; /* cursor moved right */
|
|
rx = lastwx - (GLASSSZ*GLASSMAG/2);
|
|
}
|
|
if (rx < 0) {
|
|
rw += rx;
|
|
rx = 0;
|
|
}
|
|
|
|
if (rw > 0 && rh > 0)
|
|
XCopyArea (dsp, m_pm, win, m_fgc, rx, ry, rw, rh, rx, ry);
|
|
|
|
/* then the horizontal strip that is uncovered */
|
|
|
|
rw = GLASSSZ*GLASSMAG;
|
|
rx = lastwx - (GLASSSZ*GLASSMAG/2);
|
|
if (rx < 0) {
|
|
rw += rx;
|
|
rx = 0;
|
|
}
|
|
if (wy < lastwy) {
|
|
rh = lastwy - wy; /* cursor moved up */
|
|
ry = wy + (GLASSSZ*GLASSMAG/2);
|
|
} else {
|
|
rh = wy - lastwy; /* cursor moved down */
|
|
ry = lastwy - (GLASSSZ*GLASSMAG/2);
|
|
}
|
|
if (ry < 0) {
|
|
rh += ry;
|
|
ry = 0;
|
|
}
|
|
|
|
if (rw > 0 && rh > 0)
|
|
XCopyArea (dsp, m_pm, win, m_fgc, rx, ry, rw, rh, rx, ry);
|
|
}
|
|
|
|
if (b1p || m1) {
|
|
|
|
/* start or new location: show glass and save new location */
|
|
|
|
fillGlass (wx-BORD, wy-BORD);
|
|
XPutImage (dsp, win, m_fgc, glass_xim, 0, 0,
|
|
wx-(GLASSSZ*GLASSMAG/2), wy-(GLASSSZ*GLASSMAG/2),
|
|
GLASSSZ*GLASSMAG, GLASSSZ*GLASSMAG);
|
|
lastwx = wx;
|
|
lastwy = wy;
|
|
|
|
/* kinda hard to tell boundry of glass so draw a line around it */
|
|
XDrawRectangle (dsp, win, glassGC,
|
|
wx-(GLASSSZ*GLASSMAG/2), wy-(GLASSSZ*GLASSMAG/2),
|
|
GLASSSZ*GLASSMAG-1, GLASSSZ*GLASSMAG-1);
|
|
}
|
|
|
|
if (b1r) {
|
|
|
|
/* end: restore all old pixels */
|
|
|
|
rx = lastwx - (GLASSSZ*GLASSMAG/2);
|
|
rw = GLASSSZ*GLASSMAG;
|
|
if (rx < 0) {
|
|
rw += rx;
|
|
rx = 0;
|
|
}
|
|
|
|
ry = lastwy - (GLASSSZ*GLASSMAG/2);
|
|
rh = GLASSSZ*GLASSMAG;
|
|
if (ry < 0) {
|
|
rh += ry;
|
|
ry = 0;
|
|
}
|
|
|
|
if (rw > 0 && rh > 0)
|
|
XCopyArea (dsp, m_pm, win, m_fgc, rx, ry, rw, rh, rx, ry);
|
|
}
|
|
}
|
|
|
|
/* fill glass_xim with GLASSSZ*GLASSMAG view of m_xim centered at coords
|
|
* xc,yc. take care at the edges (m_xim is mnrows x mncols)
|
|
*/
|
|
static void
|
|
fillGlass (xc, yc)
|
|
int xc, yc;
|
|
{
|
|
int sx, sy; /* coords in m_xim */
|
|
int gx, gy; /* coords in glass_xim */
|
|
int i, j;
|
|
|
|
gy = 0;
|
|
gx = 0;
|
|
for (sy = yc-GLASSSZ/2; sy < yc+GLASSSZ/2; sy++) {
|
|
for (sx = xc-GLASSSZ/2; sx < xc+GLASSSZ/2; sx++) {
|
|
Pixel p;
|
|
|
|
if (sx < 0 || sx >= mncols || sy < 0 || sy >= mnrows)
|
|
p = XGetPixel (m_xim, 0, 0);
|
|
else
|
|
p = XGetPixel (m_xim, sx, sy);
|
|
for (i = 0; i < GLASSMAG; i++)
|
|
for (j = 0; j < GLASSMAG; j++)
|
|
XPutPixel (glass_xim, gx+i, gy+j, p);
|
|
gx += GLASSMAG;
|
|
}
|
|
gx = 0;
|
|
gy += GLASSMAG;
|
|
}
|
|
}
|
|
|
|
/* read Moon database: fill up moodb[] and set nmoondb.
|
|
* N.B. to fill in x,y we assume the lat/long match the image orientation in
|
|
* its original form, ie, up N right E.
|
|
* if fail, leave moondb NULL.
|
|
*/
|
|
static void
|
|
m_readdb (void)
|
|
{
|
|
#define NDBCHUNKS 32 /* malloc room for these many more each time */
|
|
LilXML *xp;
|
|
XMLEle *root, *ep;
|
|
char buf[1024];
|
|
char fn[1024];
|
|
int ndb;
|
|
FILE *fp;
|
|
|
|
/* open file */
|
|
(void) sprintf (fn, "%s/lo/lodb.xml", getShareDir());
|
|
fp = fopenh (fn, "r");
|
|
if (!fp) {
|
|
xe_msg (1, "%s: %s", fn , syserrstr());
|
|
return;
|
|
}
|
|
|
|
/* reset moondb[] */
|
|
m_freedb();
|
|
ndb = 0;
|
|
|
|
watch_cursor (1);
|
|
|
|
/* prep and read the data file */
|
|
xp = newLilXML();
|
|
root = readXMLFile (fp, xp, buf);
|
|
fclose (fp);
|
|
delLilXML (xp);
|
|
if (!root) {
|
|
xe_msg (1, "%s:\n%s", fn, buf);
|
|
return;
|
|
}
|
|
if (strcmp (tagXMLEle(root), "XEphemLunarDB")) {
|
|
xe_msg (1, "%s:\nNot XEphem Lunar database", fn);
|
|
delXMLEle (root);
|
|
return;
|
|
}
|
|
|
|
/* read each feature and add each to list */
|
|
for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle(root,0)) {
|
|
XMLEle *fe;
|
|
MoonDB *mp;
|
|
char *type;
|
|
int x, y;
|
|
int i;
|
|
|
|
/* confirm feature tag */
|
|
if (strcmp (tagXMLEle(ep), "feature"))
|
|
continue;
|
|
|
|
/* grow moondb if now filled */
|
|
if (nmoondb == ndb) {
|
|
moondb = (MoonDB *) XtRealloc ((char *)moondb,
|
|
(ndb+NDBCHUNKS)*sizeof(MoonDB));
|
|
ndb += NDBCHUNKS;
|
|
}
|
|
mp = &moondb[nmoondb];
|
|
memset (mp, 0, sizeof(*mp));
|
|
|
|
/* build new entry at mp */
|
|
|
|
/* lat/long location, x/y gets set once we know the image scale */
|
|
mp->lt = degrad(atof(findXMLAttValu(ep, "lat")));
|
|
mp->lg = degrad(atof(findXMLAttValu(ep, "long")));
|
|
if (ll2xy (mp->lt, mp->lg, &x, &y) < 0)
|
|
continue; /* far side */
|
|
|
|
/* copy name */
|
|
mp->name = XtNewString(findXMLAttValu(ep, "name"));
|
|
|
|
/* copy type, but try to reuse */
|
|
type = findXMLAttValu(ep, "type");
|
|
for (i = 0; i < nmoondb; i++)
|
|
if (strcmp (moondb[i].type, type) == 0) {
|
|
mp->type = moondb[i].type;
|
|
break; /* reuse type string */
|
|
}
|
|
if (i == nmoondb) {
|
|
/* ok, first time we've seen this type */
|
|
mp->type = XtNewString (type);
|
|
}
|
|
|
|
/* add each file basename */
|
|
for (fe = nextXMLEle (ep, 1); fe != NULL; fe = nextXMLEle(ep,0)) {
|
|
if (strcmp(tagXMLEle(fe), "file"))
|
|
continue;
|
|
mp->lofiles = (char **) XtRealloc ((char *)mp->lofiles,
|
|
(mp->nlofiles+1)*sizeof(char*));
|
|
mp->lofiles[mp->nlofiles++] =
|
|
XtNewString (findXMLAttValu(fe, "base"));
|
|
}
|
|
|
|
/* initialy not persistent label */
|
|
mp->pl = 0;
|
|
|
|
/* all ok */
|
|
nmoondb++;
|
|
}
|
|
|
|
/* finished with xml */
|
|
delXMLEle (root);
|
|
|
|
/* warn if nothing found */
|
|
if (nmoondb == 0)
|
|
xe_msg (0, "%s:\nNo moon database entries found", fn);
|
|
|
|
/* ok */
|
|
watch_cursor(0);
|
|
}
|
|
|
|
/* compare two pointers to string, qsort-style */
|
|
static int
|
|
ncmp_qsort (const void *p1, const void *p2)
|
|
{
|
|
return (strcmp (*(char**)p1, *(char**)p2));
|
|
}
|
|
|
|
/* fill the scrolled list with db names */
|
|
static void
|
|
m_fillSL (void)
|
|
{
|
|
char **names;
|
|
int i;
|
|
|
|
/* build the list of names in sorted order */
|
|
names = (char **) XtMalloc (nmoondb * sizeof(char *));
|
|
for (i = 0; i < nmoondb; i++)
|
|
names[i] = moondb[i].name;
|
|
qsort (names, nmoondb, sizeof(char *), ncmp_qsort);
|
|
|
|
/* put in scrolled list */
|
|
XmListDeleteAllItems (msl_w);
|
|
for (i = 0; i < nmoondb; i++) {
|
|
XmString xms = XmStringCreateSimple (names[i]);
|
|
XmListAddItemUnselected (msl_w, xms, 0);
|
|
XmStringFree (xms);
|
|
}
|
|
|
|
/* finished with sorted list */
|
|
XtFree ((char *)names);
|
|
}
|
|
|
|
/* free moondb[] and the names and types.
|
|
* N.B. beware that type strings may not all be unique.
|
|
* N.B. we allow for moondb being already NULL.
|
|
*/
|
|
static void
|
|
m_freedb (void)
|
|
{
|
|
int i, j;
|
|
|
|
if (moondb == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < nmoondb; i++) {
|
|
MoonDB *mp = &moondb[i];
|
|
|
|
/* free name for sure -- each is unique */
|
|
XtFree (mp->name);
|
|
|
|
/* free type once -- pointer might be reused */
|
|
if (mp->type) {
|
|
XtFree (mp->type);
|
|
for (j = i+1; j < nmoondb; j++)
|
|
if (moondb[j].type == mp->type)
|
|
moondb[j].type = NULL;
|
|
}
|
|
|
|
/* free lo images */
|
|
if (mp->lofiles) {
|
|
for (j = 0; j < mp->nlofiles; j++)
|
|
XtFree (mp->lofiles[j]);
|
|
XtFree ((char *)mp->lofiles);
|
|
}
|
|
}
|
|
|
|
/* now free the array itself */
|
|
XtFree ((char *)moondb);
|
|
moondb = NULL;
|
|
nmoondb = 0;
|
|
}
|
|
|
|
/* free the list of sky objects, if any */
|
|
static void
|
|
resetSkyObj (void)
|
|
{
|
|
if (skyobjs) {
|
|
free ((void *) skyobjs);
|
|
skyobjs = NULL;
|
|
}
|
|
nskyobjs = 0;
|
|
}
|
|
|
|
/* add op at [x,y] to the list of background sky objects */
|
|
static void
|
|
addSkyObj (op, x, y)
|
|
Obj *op;
|
|
int x, y;
|
|
{
|
|
char *newmem;
|
|
|
|
if (skyobjs)
|
|
newmem = realloc ((void *)skyobjs, (nskyobjs+1) * sizeof(SkyObj));
|
|
else
|
|
newmem = malloc (sizeof(SkyObj));
|
|
if (!newmem) {
|
|
xe_msg (1, "No mem for more sky objects");
|
|
return;
|
|
}
|
|
|
|
skyobjs = (SkyObj *) newmem;
|
|
skyobjs[nskyobjs].op = op;
|
|
skyobjs[nskyobjs].x = x;
|
|
skyobjs[nskyobjs].y = y;
|
|
nskyobjs++;
|
|
}
|
|
|
|
/* find the object in skyobjs[] that is closest to [x,y].
|
|
* return NULL if none within MAXR.
|
|
*/
|
|
static Obj *
|
|
closeSkyObj (x, y)
|
|
int x, y;
|
|
{
|
|
SkyObj *closesp = NULL;
|
|
int mind = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < nskyobjs; i++) {
|
|
SkyObj *sp = &skyobjs[i];
|
|
int d = abs(sp->x - x) + abs(sp->y - y);
|
|
|
|
if (!closesp || d < mind) {
|
|
mind = d;
|
|
closesp = sp;
|
|
}
|
|
}
|
|
|
|
if (closesp && mind <= MAXR)
|
|
return (closesp->op);
|
|
return (NULL);
|
|
}
|
|
|
|
/* called when hit button 3 over image */
|
|
static void
|
|
m_popup (ep)
|
|
XEvent *ep;
|
|
{
|
|
XButtonEvent *bep;
|
|
int x, y;
|
|
|
|
bep = &ep->xbutton;
|
|
x = bep->x;
|
|
y = bep->y;
|
|
|
|
if (overMoon (x, y)) {
|
|
MoonDB *mp = closeMoonDB (x-BORD, y-BORD);
|
|
fill_popup (mp, x-BORD, y-BORD);
|
|
XmMenuPosition (pu_w, (XButtonPressedEvent *)ep);
|
|
XtManageChild (pu_w);
|
|
} else {
|
|
Obj *op = closeSkyObj (x, y);
|
|
if (op) {
|
|
fill_skypopup (op);
|
|
XmMenuPosition (skypu_w, (XButtonPressedEvent *)ep);
|
|
XtManageChild (skypu_w);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* create the popup menu */
|
|
static void
|
|
m_create_popup (void)
|
|
{
|
|
Widget w;
|
|
Arg args[20];
|
|
int n;
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNisAligned, True); n++;
|
|
XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
|
|
pu_w = XmCreatePopupMenu (mda_w, "MPU", args, n);
|
|
|
|
n = 0;
|
|
pu_name_w = XmCreateLabel (pu_w, "MPN", args, n);
|
|
wtip (pu_name_w, "Name of feature");
|
|
XtManageChild (pu_name_w);
|
|
|
|
n = 0;
|
|
pu_type_w = XmCreateLabel (pu_w, "MPT", args, n);
|
|
wtip (pu_type_w, "Basic type of feature");
|
|
XtManageChild (pu_type_w);
|
|
|
|
n = 0;
|
|
pu_lat_w = XmCreateLabel (pu_w, "MPLat", args, n);
|
|
wtip (pu_lat_w, "Selenographic latitude of this feature");
|
|
XtManageChild (pu_lat_w);
|
|
|
|
n = 0;
|
|
pu_lng_w = XmCreateLabel (pu_w, "MPLng", args, n);
|
|
wtip (pu_lng_w, "Selenographic longitude of this feature");
|
|
XtManageChild (pu_lng_w);
|
|
|
|
n = 0;
|
|
pu_alt_w = XmCreateLabel (pu_w, "MPAlt", args, n);
|
|
wtip (pu_alt_w, "Altitude of Sun above horizon at this feature");
|
|
XtManageChild (pu_alt_w);
|
|
|
|
n = 0;
|
|
w = XmCreateSeparator (pu_w, "MPS", args, n);
|
|
XtManageChild (w);
|
|
|
|
/* persistent label TB -- managed as needed */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); n++;
|
|
pu_pl_w = XmCreateToggleButton (pu_w, "MPPL", args, n);
|
|
XtAddCallback (pu_pl_w, XmNvalueChangedCallback, m_pl_cb, 0);
|
|
set_xmstring (pu_pl_w, XmNlabelString, "Label");
|
|
wtip (pu_pl_w, "Whether to label this object on the map.");
|
|
|
|
/* copy to Info table PB -- managed as needed */
|
|
n = 0;
|
|
pu_copy_w = XmCreatePushButton (pu_w, "MPC", args, n);
|
|
XtAddCallback (pu_copy_w, XmNactivateCallback, m_copy_cb, 0);
|
|
set_xmstring (pu_copy_w, XmNlabelString, "Set info table");
|
|
wtip (pu_copy_w, "Copy this feature location to the Moon info table");
|
|
|
|
/* show LO PB -- managed as needed */
|
|
n = 0;
|
|
pu_showlo_w = XmCreatePushButton (pu_w, "MLO", args, n);
|
|
XtAddCallback (pu_showlo_w, XmNactivateCallback, m_showlo_cb, 0);
|
|
set_xmstring (pu_showlo_w, XmNlabelString, "Lunar Orbiter image");
|
|
wtip (pu_showlo_w, "Show feature in lunar orbiter images");
|
|
}
|
|
|
|
/* fill in popup widgets from mp. if mp == NULL use x,y and skip name.
|
|
* x and y are in image coords, (as in m_xim), not mda_w.
|
|
* N.B. since we assume the database matches the original image orientation
|
|
* there is no need to correct mp->{x,y} for flipping.
|
|
*/
|
|
static void
|
|
fill_popup (mp, x, y)
|
|
MoonDB *mp;
|
|
int x, y;
|
|
{
|
|
Now *np = mm_get_now();
|
|
double lt, lg;
|
|
double a;
|
|
char str[64];
|
|
|
|
/* create popup first time */
|
|
if (!pu_w)
|
|
m_create_popup();
|
|
|
|
if (mp) {
|
|
XtManageChild (pu_name_w);
|
|
f_showit (pu_name_w, mp->name);
|
|
XtManageChild (pu_type_w);
|
|
f_showit (pu_type_w, mp->type);
|
|
XtManageChild (pu_pl_w);
|
|
XmToggleButtonSetState (pu_pl_w, mp->pl, False);
|
|
set_something (pu_pl_w, XmNuserData, (XtArgVal)mp);
|
|
XtManageChild (pu_copy_w);
|
|
set_something (pu_copy_w, XmNuserData, (XtArgVal)mp);
|
|
lt = mp->lt;
|
|
lg = mp->lg;
|
|
if (mlo_installed() && mp->nlofiles > 0) {
|
|
XtManageChild (pu_showlo_w);
|
|
set_something (pu_showlo_w, XmNuserData, (XtArgVal)mp);
|
|
} else
|
|
XtUnmanageChild (pu_showlo_w);
|
|
} else {
|
|
XtUnmanageChild (pu_name_w);
|
|
XtUnmanageChild (pu_type_w);
|
|
XtUnmanageChild (pu_pl_w);
|
|
XtUnmanageChild (pu_copy_w);
|
|
XtUnmanageChild (pu_showlo_w);
|
|
xy2ll (FX(x), FY(y), <, &lg);
|
|
}
|
|
|
|
(void) strcpy (str, "Lat: ");
|
|
if (lt < 0) {
|
|
fs_dm_angle (str+5, -lt);
|
|
(void) strcat (str, " S");
|
|
} else {
|
|
fs_dm_angle (str+5, lt);
|
|
(void) strcat (str, " N");
|
|
}
|
|
f_showit (pu_lat_w, str);
|
|
|
|
(void) strcpy (str, "Long: ");
|
|
if (lg > PI) {
|
|
fs_dm_angle (str+6, 2*PI-lg);
|
|
(void) strcat (str, " W");
|
|
} else {
|
|
fs_dm_angle (str+6, lg);
|
|
(void) strcat (str, " E");
|
|
}
|
|
f_showit (pu_lng_w, str);
|
|
|
|
moon_colong (mjd+MJD0, lt, lg, NULL, NULL, &a, NULL);
|
|
(void) strcpy (str, "Sun alt: ");
|
|
fs_dm_angle (str+9, a);
|
|
f_showit (pu_alt_w, str);
|
|
}
|
|
|
|
/* find the closest entry in moondb[] to [x,y].
|
|
* if find one return its *MoonDB else NULL.
|
|
* x and y are in image coords (as in m_xim), not mda_w.
|
|
* N.B. we allow for flipping.
|
|
*/
|
|
static MoonDB *
|
|
closeMoonDB (x, y)
|
|
int x, y;
|
|
{
|
|
MoonDB *mp, *smallp;
|
|
double lt, lg; /* location of [x,y] */
|
|
double forsh; /* foreshortening (cos of angle from center) */
|
|
int minr2;
|
|
|
|
/* allow for flipping */
|
|
x = FX(x);
|
|
y = FY(y);
|
|
|
|
/* find forshortening */
|
|
if (xy2ll (x, y, <, &lg) < 0)
|
|
return (NULL);
|
|
solve_sphere (lg - CLNG, PI/2-CLAT, sin(lt), cos(lt), &forsh, NULL);
|
|
|
|
watch_cursor(1);
|
|
|
|
minr2 = 100000000;
|
|
smallp = NULL;
|
|
for (mp = moondb; mp < &moondb[nmoondb]; mp++) {
|
|
int dx = mp->x - x;
|
|
int dy = mp->y - y;
|
|
int r2 = dx*dx + dy*dy;
|
|
|
|
if (r2 < minr2) {
|
|
smallp = mp;
|
|
minr2 = r2;
|
|
}
|
|
}
|
|
|
|
watch_cursor(0);
|
|
|
|
return (smallp);
|
|
}
|
|
|
|
/* clicked or double-clicked a name in the main db list */
|
|
static void
|
|
m_select_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XmListCallbackStruct *lcb = (XmListCallbackStruct *)call;
|
|
int dblclick = lcb->reason == XmCR_DEFAULT_ACTION;
|
|
XmString sel = lcb->item;
|
|
char *name;
|
|
MoonDB *mp;
|
|
|
|
XmStringGetLtoR (sel, XmSTRING_DEFAULT_CHARSET, &name);
|
|
|
|
/* toggle label, and display if double-clicked */
|
|
for (mp = moondb; mp < &moondb[nmoondb]; mp++) {
|
|
if (strcmp (mp->name, name) == 0) {
|
|
|
|
if (dblclick) {
|
|
/* display lunar orbiter image if any */
|
|
if (mlo_installed()) {
|
|
mlo_load (mp);
|
|
XtPopup (mlo_shell_w, XtGrabNone);
|
|
}
|
|
} else {
|
|
/* toggle label */
|
|
mp->pl ^= 1;
|
|
if (mp->pl) {
|
|
if (!option[LABELS_OPT]) {
|
|
/* turn on all labels and draw */
|
|
XmToggleButtonSetState (option_w[LABELS_OPT],1,1);
|
|
} else {
|
|
/* draw just this one */
|
|
m_labels();
|
|
m_refresh (NULL);
|
|
}
|
|
} else {
|
|
/* redraw to erase */
|
|
m_redraw();
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
XtFree (name);
|
|
}
|
|
|
|
/* called when the persistent label TB is activated in the popup.
|
|
* userData is the MoonDB entry whose pl we toggle, then redraw.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_pl_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
MoonDB *mp;
|
|
|
|
get_something (w, XmNuserData, (XtArgVal)&mp);
|
|
mp->pl = XmToggleButtonGetState (w);
|
|
|
|
/* draw just labels if adding or redraw all to erase */
|
|
if (mp->pl) {
|
|
m_labels();
|
|
m_refresh (NULL);
|
|
} else
|
|
m_redraw();
|
|
}
|
|
|
|
/* called when to copy the current feature to the moon info table.
|
|
* userData is the MoonDB entry to copy.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_copy_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
Now *np = mm_get_now();
|
|
MoonDB *mp;
|
|
|
|
get_something (w, XmNuserData, (XtArgVal)&mp);
|
|
xy2ll (mp->x, mp->y, &minfo.curlt, &minfo.curlg);
|
|
m_info (np);
|
|
set_xmstring (infot_w, XmNlabelString, mp->name);
|
|
m_pinfo ();
|
|
|
|
/* display too */
|
|
XtManageChild (msform_w);
|
|
m_set_buttons(m_selecting);
|
|
}
|
|
|
|
/* called to display lunar orbiter image from popup.
|
|
* userData is the MoonDB entry to show.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_showlo_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
MoonDB *mp;
|
|
|
|
get_something (w, XmNuserData, (XtArgVal)&mp);
|
|
|
|
/* if there /is/ an image for this feature... */
|
|
if (mp->nlofiles > 0) {
|
|
/* display */
|
|
mlo_load (mp);
|
|
XtPopup (mlo_shell_w, XtGrabNone);
|
|
|
|
/* set label just to be helpful */
|
|
mp->pl = 1;
|
|
m_labels();
|
|
m_refresh (NULL);
|
|
}
|
|
}
|
|
|
|
/* assign the object pointed to by skypu_op to Favorites
|
|
*/
|
|
static void
|
|
m_assign_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
fav_add (skypu_op);
|
|
}
|
|
|
|
/* create the sky background object popup menu */
|
|
static void
|
|
m_create_skypopup (void)
|
|
{
|
|
Widget w;
|
|
Arg args[20];
|
|
int n;
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNisAligned, True); n++;
|
|
XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
|
|
skypu_w = XmCreatePopupMenu (mda_w, "MSKYPU", args, n);
|
|
|
|
n = 0;
|
|
skypu_name_w = XmCreateLabel (skypu_w, "MSKYPN", args, n);
|
|
wtip (skypu_name_w, "Name of object");
|
|
XtManageChild (skypu_name_w);
|
|
|
|
n = 0;
|
|
skypu_mag_w = XmCreateLabel (skypu_w, "MSKYPM", args, n);
|
|
wtip (skypu_mag_w, "Nominal magnitude");
|
|
XtManageChild (skypu_mag_w);
|
|
|
|
/* sep */
|
|
n = 0;
|
|
w = XmCreateSeparator (skypu_w, "MSKYS", args, n);
|
|
XtManageChild (w);
|
|
|
|
/* a PB to add to Favorites */
|
|
n = 0;
|
|
w = XmCreatePushButton (skypu_w, "ABPB", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_assign_cb, 0);
|
|
set_xmstring (w, XmNlabelString, "Add to Favorites");
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* fill skypu_w with info from op */
|
|
static void
|
|
fill_skypopup (op)
|
|
Obj *op;
|
|
{
|
|
char buf[32];
|
|
|
|
/* create popup first time */
|
|
if (!skypu_w)
|
|
m_create_skypopup();
|
|
|
|
/* save in case it's assigned */
|
|
skypu_op = op;
|
|
|
|
/* show name and mag */
|
|
f_showit (skypu_name_w, op->o_name);
|
|
(void) sprintf (buf, "Mag: %.2f", get_mag(op));
|
|
f_showit (skypu_mag_w, buf);
|
|
}
|
|
|
|
/* create the shell to display lunar orbiter images */
|
|
static void
|
|
mlo_create_shell (void)
|
|
{
|
|
Widget w, credit_w;
|
|
Widget mform_w;
|
|
Arg args[20];
|
|
int n;
|
|
|
|
/* create master form */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNtitle, "xephem Lunar Orbiter view"); n++;
|
|
XtSetArg (args[n], XmNiconName, "LOrbiter"); n++;
|
|
XtSetArg (args[n], XmNdeleteResponse, XmUNMAP); n++;
|
|
mlo_shell_w = XtCreatePopupShell ("MoonLO", topLevelShellWidgetClass,
|
|
toplevel_w, args, n);
|
|
setup_icon (mlo_shell_w);
|
|
set_something (mlo_shell_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
XtAddCallback (mlo_shell_w, XmNpopdownCallback, mlo_popdown_cb, 0);
|
|
sr_reg (mlo_shell_w, "XEphem*MoonLO.width", mooncategory, 0);
|
|
sr_reg (mlo_shell_w, "XEphem*MoonLO.height", mooncategory, 0);
|
|
sr_reg (mlo_shell_w, "XEphem*MoonLO.x", mooncategory, 0);
|
|
sr_reg (mlo_shell_w, "XEphem*MoonLO.y", mooncategory, 0);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNhorizontalSpacing, 5); n++;
|
|
XtSetArg (args[n], XmNverticalSpacing, 5); n++;
|
|
mform_w = XmCreateForm (mlo_shell_w, "MoonLOF", args, n);
|
|
XtManageChild (mform_w);
|
|
|
|
/* scrolled list in lower right to display possible file choices */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
XtSetArg (args[n], XmNvisibleItemCount, 4); n++;
|
|
XtSetArg (args[n], XmNselectionPolicy, XmBROWSE_SELECT); n++;
|
|
mlo_sl_w = XmCreateScrolledList (mform_w, "MLOSL", args, n);
|
|
XtAddCallback (mlo_sl_w, XmNbrowseSelectionCallback, mlo_select_cb,0);
|
|
XtManageChild (mlo_sl_w);
|
|
|
|
/* annotation and close buttons */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 15); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 15); n++;
|
|
w = XmCreatePushButton (mform_w, "Close", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, mlo_close_cb, NULL);
|
|
XtManageChild (w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 15); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 30); n++;
|
|
mlo_ann_w = XmCreateToggleButton (mform_w, "Overlay", args, n);
|
|
XtAddCallback (mlo_ann_w, XmNvalueChangedCallback, mlo_ann_cb, NULL);
|
|
set_xmstring (mlo_ann_w, XmNlabelString, "Overlay annotation");
|
|
sr_reg (mlo_ann_w, NULL, mooncategory, 0);
|
|
XtManageChild (mlo_ann_w);
|
|
|
|
/* credit */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNbottomWidget, XtParent(mlo_sl_w)); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 10); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
|
credit_w = XmCreateLabel (mform_w, "LOC", args, n);
|
|
set_xmstring (credit_w, XmNlabelString, "Lunar Orbiter images used by permission of\nLunar and Planetary Institute, http://www.lpi.usra.edu");
|
|
XtManageChild (credit_w);
|
|
|
|
/* label in a scrolled window for image */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNbottomWidget, credit_w); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 10); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
|
|
mlo_sw_w = XmCreateScrolledWindow (mform_w, "MLOSW", args, n);
|
|
XtManageChild (mlo_sw_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNrecomputeSize, True); n++;
|
|
XtSetArg (args[n], XmNlabelType, XmPIXMAP); n++;
|
|
mlo_pml_w = XmCreateLabel (mlo_sw_w, "MLOPML", args, n);
|
|
XtManageChild (mlo_pml_w);
|
|
}
|
|
|
|
/* callback from mlo_shell_w being popped down.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
mlo_popdown_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
}
|
|
|
|
/* called from Close button in lunar orbiter window */
|
|
static void
|
|
mlo_close_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XtPopdown (mlo_shell_w);
|
|
/* let popdown do all the work */
|
|
}
|
|
|
|
/* load the files in the Lunar Orbiter scrolled list and load the first image */
|
|
static void
|
|
mlo_load (MoonDB *mp)
|
|
{
|
|
int i;
|
|
|
|
/* load scrolled list */
|
|
XmListDeleteAllItems (mlo_sl_w);
|
|
for (i = 0; i < mp->nlofiles; i++) {
|
|
XmString xms = XmStringCreateSimple (mp->lofiles[i]);
|
|
XmListAddItemUnselected (mlo_sl_w, xms, 0);
|
|
XmStringFree (xms);
|
|
}
|
|
|
|
/* select first image and show it */
|
|
XmListSelectPos (mlo_sl_w, 1, True);
|
|
}
|
|
|
|
/* a file in the lunar orbiter scrolled list has been selected for display */
|
|
static void
|
|
mlo_select_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XmString sel = ((XmListCallbackStruct *)call)->item;
|
|
char *base;
|
|
|
|
XmStringGetLtoR (sel, XmSTRING_DEFAULT_CHARSET, &base);
|
|
mlo_load_image (base);
|
|
XtFree (base);
|
|
centerScrollBars(mlo_sw_w);
|
|
}
|
|
|
|
/* user has changed whether to show annotated or not */
|
|
static void
|
|
mlo_ann_cb (Widget w, XtPointer client, XtPointer call)
|
|
{
|
|
XmStringTable xmst;
|
|
char *base;
|
|
|
|
get_something (mlo_sl_w, XmNselectedItems, (XtArgVal)&xmst);
|
|
XmStringGetLtoR (xmst[0], XmSTRING_DEFAULT_CHARSET, &base);
|
|
mlo_load_image (base);
|
|
XtFree (base);
|
|
}
|
|
|
|
static void
|
|
mlo_load_image (char *base)
|
|
{
|
|
static XColor xcol[256];
|
|
static int xcolset;
|
|
Pixmap oldpm, pm;
|
|
FILE *fp;
|
|
char msg[1024];
|
|
int w, h;
|
|
|
|
fp = mlo_open (base);
|
|
if (!fp) {
|
|
xe_msg (1, "%s.jpg:\n%s", base, syserrstr());
|
|
return;
|
|
}
|
|
|
|
/* free last batch of colors */
|
|
if (xcolset) {
|
|
freeXColors (XtD, xe_cm, xcol, XtNumber(xcol));
|
|
xcolset = 0;
|
|
}
|
|
|
|
/* create the expose pixmap */
|
|
if (jpeg2pm (XtD, xe_cm, fp, &w, &h, &pm, xcol, msg) < 0) {
|
|
xe_msg (1, "%s:\n%s", base, msg);
|
|
fclose (fp);
|
|
return;
|
|
}
|
|
xcolset = 1;
|
|
|
|
/* replace label pixmap */
|
|
get_something (mlo_pml_w, XmNlabelPixmap, (XtArgVal)&oldpm);
|
|
if (oldpm != XmUNSPECIFIED_PIXMAP)
|
|
XFreePixmap (XtD, oldpm);
|
|
set_something (mlo_pml_w, XmNlabelPixmap, (XtArgVal)pm);
|
|
|
|
/* clean up */
|
|
fclose (fp);
|
|
}
|
|
|
|
/* return 1 if lunar orbiter images appear to be installed, else 0 */
|
|
static int
|
|
mlo_installed (void)
|
|
{
|
|
FILE *fp = mlo_open ("IV-130-H1");
|
|
if (fp) {
|
|
fclose (fp);
|
|
return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/* given the base name open a lunar orbiter image.
|
|
*/
|
|
static FILE *
|
|
mlo_open (char *base)
|
|
{
|
|
int ann = XmToggleButtonGetState (mlo_ann_w);
|
|
char fn[1024];
|
|
|
|
sprintf (fn, "%s/lo/%s/%s.jpg", getShareDir(), ann?"amg":"img", base);
|
|
return (fopen (fn, "r"));
|
|
}
|
|
|