mirror of https://github.com/XEphem/XEphem.git
2992 lines
78 KiB
C
2992 lines
78 KiB
C
/* code to manage the stuff on the mars display.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.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/List.h>
|
|
#include <Xm/PushB.h>
|
|
#include <Xm/CascadeB.h>
|
|
#include <Xm/Scale.h>
|
|
#include <Xm/ToggleB.h>
|
|
#include <Xm/RowColumn.h>
|
|
#include <Xm/Separator.h>
|
|
#include <Xm/ScrolledW.h>
|
|
|
|
#include "xephem.h"
|
|
|
|
/* shared by marsmmenu.c */
|
|
char marscategory[] = "Mars -- View and Info"; /* Save category */
|
|
|
|
#define POLE_RA degrad(317.61)
|
|
#define POLE_DEC degrad(52.85)
|
|
|
|
static void m_popup (XEvent *ep);
|
|
static void m_create_popup (void);
|
|
|
|
static void m_create_shell (void);
|
|
static void m_create_msform (void);
|
|
static void m_create_mfform (void);
|
|
static void m_set_buttons (int whether);
|
|
static void m_mstats_close_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_mstats_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_features_ctrl_cb (Widget w, XtPointer client,XtPointer call);
|
|
static void m_features_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_feasel_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_moons_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_selection_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_cml_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_slt_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_see_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_apply_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_aim_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 m_close_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_mloop_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_list_cb (Widget w, XtPointer client, XtPointer call);
|
|
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_option_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_exp_cb (Widget w, XtPointer client, XtPointer call);
|
|
static void m_pointer_eh (Widget w, XtPointer client, XEvent *ev,
|
|
Boolean *continue_to_dispatch);
|
|
static void m_redraw (int newim);
|
|
static void m_refresh (XExposeEvent *ep);
|
|
static void m_stats (void);
|
|
static void m_drawpm (void);
|
|
static void m_setsize(void);
|
|
static void m_drFeatures (void);
|
|
static void mxim_setup (void);
|
|
static void m_orientation (void);
|
|
static void m_sizecal (void);
|
|
static void m_grid (void);
|
|
static void m_reportloc (int x, int y);
|
|
static void m_eqproject (Now *np, double ra, double dec, int *xp, int *yp);
|
|
static void m_setselected(void);
|
|
static void m_setnewpos (double l, double L);
|
|
static void mars_cml (Now *np, double *cmlp, double *sltp, double *pap);
|
|
static void swap_colors (void);
|
|
static int mxim_create (void);
|
|
static int m_readmap (void);
|
|
static int m_readFeatures (void);
|
|
static int xy2ll (int x, int y, double *ltp, double *lgp);
|
|
static int ll2xy (double l, double L, int *xp, int *yp);
|
|
static int mfsa_qsort (const void *p1, const void *p2);
|
|
static int mf_qsort (const void *p1, const void *p2);
|
|
static int m_ano (double *ixp, double *iyp, int *xp, int *yp, int w2x, int arg);
|
|
|
|
/* the map image, read into mimage, is a IMHx(2*IMH) 8bit file of relief in
|
|
* square degree steps starting at longitude LONG0 on the left moving to the
|
|
* west, south latitude on the bottom. use it to build a window winszXwinsz of
|
|
* the visible face in m_xim.
|
|
*/
|
|
#define XEVERS 5 /* required version in header */
|
|
#define LONG0 0 /* long of left side, degs */
|
|
#define IMH 1440 /* n rows in file map */
|
|
#define IMW (IMH*2) /* n columns in file map */
|
|
#define WINR (winsz/2) /* handy window radius */
|
|
#define REDCOLORS 50 /* n red ramp colors in map */
|
|
#define BORD 80 /* extra drawing area border for labels/stars */
|
|
#define LGAP 20 /* gap between NSEW labels and image edge */
|
|
#define FMAG 16 /* faintest mag of sky background object */
|
|
#define MAXR 10 /* max gap when picking sky objects, pixels */
|
|
#define GSP degrad(15.0) /* grid spacing */
|
|
#define FSP (GSP/5.) /* fine spacing */
|
|
#define XRAD 5 /* radius of central mark, pixels */
|
|
#define LANDSR 3 /* radius of landing site symbol */
|
|
#define MARSD 6776. /* mars diam, km */
|
|
|
|
static unsigned char *mimage; /* malloced array of raw mars image */
|
|
static Pixel mcolors[REDCOLORS];/* color-scale ramp for drawing image */
|
|
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 winsz; /* n rows&cols in X window image */
|
|
static XImage *m_xim; /* XImage of mars now at current size */
|
|
static double m_cml; /* current central meridian longitude, rads */
|
|
static double m_slt; /* current subearth latitude, rads */
|
|
static double m_sslt, m_cslt; /* " handy sin/cos */
|
|
static double m_pa; /* current N pole position angle, rads */
|
|
static double m_spa, m_cpa; /* " handy sin/cos */
|
|
static int m_seeing; /* seeing, tenths of arc seconds */
|
|
static Obj *marsop; /* current mars info */
|
|
static double cm_dec, sm_dec; /* handy cos and sin of mars' dec */
|
|
|
|
/* main's widgets */
|
|
static Widget mshell_w; /* main mars shell */
|
|
static Widget msw_w; /* main scrolled window */
|
|
static Widget mda_w; /* image view DrawingArea */
|
|
static Pixmap m_pm; /* image view staging pixmap */
|
|
static Widget dt_w; /* main date/time stamp widget */
|
|
|
|
/* "More info" stats widgets */
|
|
static Widget msform_w; /* statistics form dialog */
|
|
static Widget sdt_w; /* statistics date/time stamp widget */
|
|
static Widget lat_w, lng_w; /* lat/long under cursor */
|
|
static Widget cml_w; /* central merdian longitude PB */
|
|
static Widget cmls_w; /* central merdian longitude scale */
|
|
static Widget slt_w; /* subearth latitude PB */
|
|
static Widget slts_w; /* subearth latitude scale */
|
|
static Widget see_w; /* seeing label */
|
|
static Widget sees_w; /* seeing scale */
|
|
static Widget apply_w; /* the Apply PB -- we fiddle with sensitive */
|
|
static int fakepos; /* set when cml/slt/pa etc are not true */
|
|
|
|
/* surface object's widgets */
|
|
static Widget pu_w; /* popup */
|
|
static Widget pu_name_w; /* popup name label */
|
|
static Widget pu_type_w; /* popup type label */
|
|
static Widget pu_size_w; /* popup size label */
|
|
static Widget pu_l_w; /* popup lat label */
|
|
static Widget pu_L_w; /* popup Long label */
|
|
static Widget pu_aim_w; /* popup Point PB */
|
|
static double pu_l; /* latitude if Point PB is activated */
|
|
static double pu_L; /* longitude if Point PB is activated */
|
|
|
|
static GC m_fgc, m_bgc, m_agc; /* various GCs */
|
|
static XFontStruct *m_fsp; /* label font */
|
|
|
|
static int m_selecting; /* set while our fields are being selected */
|
|
static char marsfcategory[] = "Mars -- Features"; /* Save category */
|
|
|
|
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 {
|
|
HALFSIZ_OPT, GRID_OPT, FLIPLR_OPT, FLIPTB_OPT,
|
|
N_OPT
|
|
} Option;
|
|
static int option[N_OPT];
|
|
|
|
/* Image to X Windows coord converter macros, including flipping.
|
|
* image coords have 0 in the center +x/right +y/down of the m_xim,
|
|
* X Windows coords have upper left +x/right +y/down of the mda_w.
|
|
*/
|
|
#define IX2XX(x) (BORD + WINR + (option[FLIPLR_OPT] ? -(x) : (x)))
|
|
#define IY2XY(y) (BORD + WINR + (option[FLIPTB_OPT] ? -(y) : (y)))
|
|
#define XX2IX(x) (((x) - (BORD + WINR)) * (option[FLIPLR_OPT] ? -1 : 1))
|
|
#define XY2IY(y) (((y) - (BORD + WINR)) * (option[FLIPTB_OPT] ? -1 : 1))
|
|
|
|
/* manage the feature labeling */
|
|
typedef enum {
|
|
MFC_OK,
|
|
MFC_APPLY,
|
|
MFC_ALL,
|
|
MFC_NONE,
|
|
MFC_TOGGLE,
|
|
MFC_CLOSE,
|
|
MFC_HELP
|
|
} MFCtrl; /* feature controls */
|
|
static Widget mfform_w; /* feature type form dialog */
|
|
static Widget flist_w; /* feature scrolled list */
|
|
typedef struct {
|
|
Widget tb; /* selection toggle button */
|
|
int set; /* whether currently set */
|
|
char type[128]; /* type */
|
|
int n; /* count */
|
|
} MFSel;
|
|
static MFSel *mfsa; /* malloced array of MFSel's */
|
|
static int nmfsa; /* n entries in mfsp[] */
|
|
typedef struct {
|
|
char name[32]; /* name */
|
|
double lt, lg; /* lat/long, rads +N/+W */
|
|
double dia; /* dia or largest dimenstion, km */
|
|
int mfsai; /* feature type index into mfsa */
|
|
} MFeature;
|
|
static MFeature *mf; /* malloced list of features */
|
|
static int nmf; /* entries in mf[] */
|
|
|
|
/* called when the mars view is activated via the main menu pulldown.
|
|
* if first time, build everything, else just toggle whether we are mapped.
|
|
* allow for retrying to read the image file each time until find it.
|
|
*/
|
|
void
|
|
mars_manage ()
|
|
{
|
|
if (!mshell_w) {
|
|
/* one-time-only work */
|
|
|
|
/* all for nothing without the file and features db. */
|
|
if (m_readmap() < 0 || m_readFeatures() < 0)
|
|
return;
|
|
|
|
/* build dialogs */
|
|
m_create_shell();
|
|
m_create_msform();
|
|
m_create_mfform();
|
|
|
|
/* establish depth, colors and bits per pixel */
|
|
get_something (mda_w, XmNdepth, (XtArgVal)&mdepth);
|
|
m_init_gcs();
|
|
mbpp = (mdepth==1) ? 1 : (mdepth>=17 ? 32 : (mdepth >= 9 ? 16 : 8));
|
|
|
|
/* establish initial mars circumstances */
|
|
m_stats();
|
|
m_setsize();
|
|
}
|
|
|
|
XtPopup (mshell_w, XtGrabNone);
|
|
set_something (mshell_w, XmNiconic, (XtArgVal)False);
|
|
centerScrollBars (msw_w);
|
|
|
|
/* register we are now up */
|
|
setXRes (mars_viewupres(), "1");
|
|
}
|
|
|
|
/* commanded from main to update with a new set of circumstances */
|
|
void
|
|
mars_update (np, how_much)
|
|
Now *np;
|
|
int how_much;
|
|
{
|
|
if (!mshell_w)
|
|
return;
|
|
if (!isUp(mshell_w) && !any_ison())
|
|
return;
|
|
|
|
/* new mars stats */
|
|
m_stats();
|
|
|
|
/* new image */
|
|
m_redraw(1);
|
|
}
|
|
|
|
/* called when basic resources change.
|
|
* we also take care of mars moons.
|
|
* rebuild and redraw.
|
|
*/
|
|
void
|
|
mars_newres()
|
|
{
|
|
marsm_newres();
|
|
if (!mshell_w)
|
|
return;
|
|
m_init_gcs();
|
|
mars_update (mm_get_now(), 1);
|
|
}
|
|
|
|
int
|
|
mars_ison()
|
|
{
|
|
return (isUp(mshell_w));
|
|
}
|
|
|
|
/* 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
|
|
mars_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 (mars_ison()) {
|
|
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
|
|
mars_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 (msform_w && (win = XtWindow(msform_w)) != 0) {
|
|
Display *dsp = XtDisplay(msform_w);
|
|
if (c)
|
|
XDefineCursor (dsp, win, c);
|
|
else
|
|
XUndefineCursor (dsp, win);
|
|
}
|
|
|
|
if (mfform_w && (win = XtWindow(mfform_w)) != 0) {
|
|
Display *dsp = XtDisplay(mfform_w);
|
|
if (c)
|
|
XDefineCursor (dsp, win, c);
|
|
else
|
|
XUndefineCursor (dsp, win);
|
|
}
|
|
}
|
|
|
|
/* return the name of the resource containing whether this view is up */
|
|
char *
|
|
mars_viewupres()
|
|
{
|
|
return ("MarsViewUp");
|
|
}
|
|
|
|
static void
|
|
m_create_shell()
|
|
{
|
|
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[] = {
|
|
{HALFSIZ_OPT, "HalfSize", "Half size",
|
|
"Display map at half size"},
|
|
{FLIPTB_OPT, "FlipTB", "Flip T/B",
|
|
"Flip the map top-to-bottom"},
|
|
{FLIPLR_OPT, "FlipLR", "Flip L/R",
|
|
"Flip the map left-to-right"},
|
|
{GRID_OPT, "Grid", "Grid",
|
|
"Overlay a 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...", "Mars"},
|
|
{"on Mouse...", "Mars_mouse"},
|
|
{"on Control...", "Mars_control"},
|
|
{"on View...", "Mars_view"},
|
|
};
|
|
Widget mb_w, pd_w, cb_w;
|
|
Widget mform_w;
|
|
Widget w;
|
|
unsigned long mask;
|
|
XmString str;
|
|
Arg args[20];
|
|
int i;
|
|
int n;
|
|
|
|
/* create master form in its shell */
|
|
n = 0;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNtitle, "xephem Mars view"); n++;
|
|
XtSetArg (args[n], XmNiconName, "Mars"); n++;
|
|
XtSetArg (args[n], XmNdeleteResponse, XmUNMAP); n++;
|
|
mshell_w = XtCreatePopupShell ("Mars", 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*Mars.width", marscategory, 0);
|
|
sr_reg (mshell_w, "XEphem*Mars.height", marscategory, 0);
|
|
sr_reg (mshell_w, "XEphem*Mars.x", marscategory, 0);
|
|
sr_reg (mshell_w, "XEphem*Mars.y", marscategory, 0);
|
|
sr_reg (NULL, mars_viewupres(), marscategory, 0);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNhorizontalSpacing, 5); n++;
|
|
XtSetArg (args[n], XmNverticalSpacing, 5); n++;
|
|
mform_w = XmCreateForm (mshell_w, "MarsForm", 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, "MPrint", args, n);
|
|
set_xmstring (w, XmNlabelString, "Print...");
|
|
XtAddCallback (w, XmNactivateCallback, m_print_cb, 0);
|
|
wtip (w, "Print the current Mars map");
|
|
XtManageChild (w);
|
|
|
|
/* the "Annot" push button */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "MAnn", 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 "movie loop" push button */
|
|
|
|
n = 0;
|
|
n += ml_addacc (args, n);
|
|
w = XmCreatePushButton (pd_w, "MML", args, n);
|
|
set_xmstring (w, XmNlabelString, "Add to movie...");
|
|
XtAddCallback (w, XmNactivateCallback, m_mloop_cb, 0);
|
|
wtip (w, "Add this scene to the 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++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); 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);
|
|
if (osp->tip)
|
|
wtip (w, osp->tip);
|
|
XtManageChild (w);
|
|
sr_reg (w, NULL, marscategory, 1);
|
|
}
|
|
|
|
/* add a separator */
|
|
|
|
n = 0;
|
|
w = XmCreateSeparator (pd_w, "Sep", args, n);
|
|
XtManageChild (w);
|
|
|
|
/* add the Feature control */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "Features", args, n);
|
|
set_xmstring (w, XmNlabelString, "Features...");
|
|
XtAddCallback (w, XmNactivateCallback, m_features_cb, NULL);
|
|
wtip (w, "Display labeled features");
|
|
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, NULL);
|
|
wtip (w, "Display additional information and controls");
|
|
XtManageChild (w);
|
|
|
|
/* add the Moons control */
|
|
|
|
n = 0;
|
|
w = XmCreatePushButton (pd_w, "Moons", args, n);
|
|
set_xmstring (w, XmNlabelString, "Moon view...");
|
|
XtAddCallback (w, XmNactivateCallback, m_moons_cb, NULL);
|
|
wtip (w, "Display schematic view of Mars and its moons");
|
|
XtManageChild (w);
|
|
|
|
/* 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 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_FORM); n++;
|
|
XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
|
|
XtSetArg (args[n], XmNvisualPolicy, XmVARIABLE); n++;
|
|
msw_w = XmCreateScrolledWindow (mform_w, "MarsSW", args, n);
|
|
XtManageChild (msw_w);
|
|
|
|
/* size gets changed to match the display later */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNmarginWidth, 0); n++;
|
|
XtSetArg (args[n], XmNmarginHeight, 0); n++;
|
|
mda_w = XmCreateDrawingArea (msw_w, "MarsMap", 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);
|
|
}
|
|
}
|
|
|
|
/* create the "more info" stats dialog */
|
|
static void
|
|
m_create_msform()
|
|
{
|
|
typedef struct {
|
|
char *label;
|
|
Widget *wp;
|
|
char *tip;
|
|
} DItem;
|
|
static DItem citems[] = {
|
|
{"Under Cursor:", NULL, NULL},
|
|
{"Latitude +N:", &lat_w, "Martian Latitude under cursor"},
|
|
{"Longitude +W:", &lng_w, "Martian Longitude under cursor"},
|
|
};
|
|
Widget rc_w;
|
|
Widget sep_w;
|
|
Widget f_w;
|
|
Widget w;
|
|
char str[32];
|
|
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], XmNdefaultPosition, False); n++;
|
|
msform_w = XmCreateFormDialog (mshell_w, "MarsStats", args, n);
|
|
set_something (msform_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
sr_reg (XtParent(msform_w), "XEphem*MarsStats.x", marscategory,0);
|
|
sr_reg (XtParent(msform_w), "XEphem*MarsStats.y", marscategory,0);
|
|
|
|
/* set some stuff in the parent DialogShell.
|
|
* setting XmNdialogTitle in the Form didn't work..
|
|
*/
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtitle, "xephem Mars info"); n++;
|
|
XtSetValues (XtParent(msform_w), args, n);
|
|
|
|
/* make a rowcolumn to hold the cursor tracking info */
|
|
|
|
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], XmNspacing, 5); n++;
|
|
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++;
|
|
w = XmCreateLabel (rc_w, "CVal", args, n);
|
|
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], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
sep_w = XmCreateSeparator (msform_w, "Sep1", args, n);
|
|
XtManageChild(sep_w);
|
|
|
|
/* make the slt row */
|
|
|
|
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], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
w = XmCreateLabel (msform_w, "SLTL", args, n);
|
|
set_xmstring (w, XmNlabelString, "Sub Earth Lat (+N):");
|
|
XtManageChild (w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, sep_w); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Mars.SubLat"); n++;
|
|
slt_w = XmCreatePushButton (msform_w, "SLTVal", args, n);
|
|
XtAddCallback (slt_w, XmNactivateCallback, m_selection_cb, NULL);
|
|
wtip (slt_w, "Martian latitude at center of map");
|
|
XtManageChild (slt_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, slt_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++;
|
|
XtSetArg (args[n], XmNminimum, -90); n++;
|
|
XtSetArg (args[n], XmNmaximum, 90); n++;
|
|
XtSetArg (args[n], XmNscaleMultiple, 1); n++;
|
|
XtSetArg (args[n], XmNshowValue, False); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
slts_w = XmCreateScale (msform_w, "SLTS", args, n);
|
|
XtAddCallback (slts_w, XmNvalueChangedCallback, m_slt_cb, NULL);
|
|
XtAddCallback (slts_w, XmNdragCallback, m_slt_cb, NULL);
|
|
wtip (slts_w, "Set arbitrary central latitude, then use Apply");
|
|
XtManageChild (slts_w);
|
|
|
|
/* make the cml row */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, slts_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
w = XmCreateLabel (msform_w, "CMLL", args, n);
|
|
set_xmstring (w, XmNlabelString, "Central M Long (+W):");
|
|
XtManageChild (w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, slts_w); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
XtSetArg (args[n], XmNuserData, "Mars.CML"); n++;
|
|
cml_w = XmCreatePushButton (msform_w, "CMLVal", args, n);
|
|
XtAddCallback (cml_w, XmNactivateCallback, m_selection_cb, NULL);
|
|
wtip (cml_w, "Martian longitude at center of map");
|
|
XtManageChild (cml_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, cml_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++;
|
|
XtSetArg (args[n], XmNminimum, 0); n++;
|
|
XtSetArg (args[n], XmNmaximum, 359); n++;
|
|
XtSetArg (args[n], XmNscaleMultiple, 1); n++;
|
|
XtSetArg (args[n], XmNshowValue, False); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
cmls_w = XmCreateScale (msform_w, "CMLS", args, n);
|
|
XtAddCallback (cmls_w, XmNvalueChangedCallback, m_cml_cb, NULL);
|
|
XtAddCallback (cmls_w, XmNdragCallback, m_cml_cb, NULL);
|
|
wtip (cmls_w, "Set arbitrary central longitude, then use Apply");
|
|
XtManageChild (cmls_w);
|
|
|
|
/* make the seeing row */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, cmls_w); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
w = XmCreateLabel (msform_w, "SeeingL", args, n);
|
|
set_xmstring (w, XmNlabelString, "Seeing (arc seconds):");
|
|
XtManageChild (w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, cmls_w); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
XtSetArg (args[n], XmNalignment, XmALIGNMENT_END); n++;
|
|
see_w = XmCreateLabel (msform_w, "SeeingV", args, n);
|
|
wtip (see_w, "Image is blurred to simulate this seeing value");
|
|
XtManageChild (see_w);
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, see_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++;
|
|
XtSetArg (args[n], XmNscaleMultiple, 1); n++;
|
|
XtSetArg (args[n], XmNshowValue, False); n++;
|
|
XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
|
|
XtSetArg (args[n], XmNminimum, 0); n++;
|
|
XtSetArg (args[n], XmNmaximum, 50); n++; /* 5 arcsecs */
|
|
sees_w = XmCreateScale (msform_w, "Seeing", args, n);
|
|
XtAddCallback (sees_w, XmNvalueChangedCallback, m_see_cb, NULL);
|
|
XtAddCallback (sees_w, XmNdragCallback, m_see_cb, NULL);
|
|
wtip (sees_w, "Set desired seeing, then use Apply");
|
|
XtManageChild (sees_w);
|
|
sr_reg (sees_w, NULL, marscategory, 1);
|
|
|
|
/* pick up initial value */
|
|
XmScaleGetValue (sees_w, &m_seeing);
|
|
(void) sprintf (str, "%.1f", m_seeing/10.0);
|
|
set_xmstring (see_w, XmNlabelString, str);
|
|
|
|
/* add a label for the current date/time stamp */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNtopWidget, sees_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++;
|
|
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], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
sep_w = XmCreateSeparator (msform_w, "Sep3", args, n);
|
|
XtManageChild (sep_w);
|
|
|
|
/* put the bottom controls in their own form */
|
|
|
|
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], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 10); n++;
|
|
XtSetArg (args[n], XmNfractionBase, 13); n++;
|
|
f_w = XmCreateForm (msform_w, "ACH", args, n);
|
|
XtManageChild (f_w);
|
|
|
|
/* the apply button */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 1); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 4); n++;
|
|
apply_w = XmCreatePushButton (f_w, "Apply", args, n);
|
|
XtAddCallback (apply_w, XmNactivateCallback, m_apply_cb, NULL);
|
|
wtip (apply_w, "Apply the new values");
|
|
XtManageChild (apply_w);
|
|
|
|
/* the close button */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 5); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 8); n++;
|
|
w = XmCreatePushButton (f_w, "Close", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_mstats_close_cb, NULL);
|
|
wtip (w, "Close this dialog");
|
|
XtManageChild (w);
|
|
|
|
/* the help button */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 9); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 12); n++;
|
|
w = XmCreatePushButton (f_w, "Help", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_helpon_cb,
|
|
(XtPointer)"Mars_moreinfo");
|
|
wtip (w, "More info about this dialog");
|
|
XtManageChild (w);
|
|
}
|
|
|
|
/* given two pointers to MFSel pointers sort by type, qsort-style */
|
|
static int
|
|
mfsa_qsort (const void *p1, const void *p2)
|
|
{
|
|
MFSel *m1 = *(MFSel**)p1;
|
|
MFSel *m2 = *(MFSel**)p2;
|
|
return (strcmp (m1->type, m2->type));
|
|
}
|
|
|
|
/* create the "features" stats dialog.
|
|
* N.B. we assume mfsa[] and mf[] are all set up.
|
|
*/
|
|
static void
|
|
m_create_mfform()
|
|
{
|
|
typedef struct {
|
|
MFCtrl mfce; /* which feature control */
|
|
char *label; /* label */
|
|
char *tip; /* helpfull tip */
|
|
} MFC;
|
|
static MFC mfc[] = {
|
|
{MFC_OK, "Ok", "Draw the chosen features and close this dialog"},
|
|
{MFC_APPLY, "Apply", "Draw the chosen features"},
|
|
{MFC_TOGGLE, "Toggle", "Swap features on/off"},
|
|
{MFC_ALL, "All", "Turn all features on"},
|
|
{MFC_NONE, "None", "Turn all features off"},
|
|
{MFC_CLOSE, "Close", "Close this dialog"},
|
|
{MFC_HELP, "Help", "More info about this dialog"},
|
|
};
|
|
Widget rc_w, sep_w, f_w;
|
|
MFSel **sortmfsa;
|
|
XmString *flist;
|
|
Widget w;
|
|
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], XmNmarginHeight, 10); n++;
|
|
XtSetArg (args[n], XmNcolormap, xe_cm); n++;
|
|
XtSetArg (args[n], XmNdefaultPosition, False); n++;
|
|
mfform_w = XmCreateFormDialog (mshell_w, "MarsFeatures", args, n);
|
|
set_something (mfform_w, XmNcolormap, (XtArgVal)xe_cm);
|
|
sr_reg(XtParent(mfform_w), "XEphem*MarsFeatures.x", marsfcategory, 0);
|
|
sr_reg(XtParent(mfform_w), "XEphem*MarsFeatures.y", marsfcategory, 0);
|
|
|
|
/* set some stuff in the parent DialogShell.
|
|
* setting XmNdialogTitle in the Form didn't work..
|
|
*/
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtitle, "xephem Mars features"); n++;
|
|
XtSetValues (XtParent(mfform_w), args, n);
|
|
|
|
/* make a rowcolumn and add the feature type TBs sorted by type */
|
|
|
|
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], XmNspacing, 1); n++;
|
|
rc_w = XmCreateRowColumn (mfform_w, "SRC", args, n);
|
|
XtManageChild (rc_w);
|
|
|
|
sortmfsa = (MFSel **) XtMalloc (nmfsa * sizeof(MFSel*));
|
|
for (i = 0; i < nmfsa; i++)
|
|
sortmfsa[i] = mfsa + i;
|
|
qsort (sortmfsa, nmfsa, sizeof(MFSel*), mfsa_qsort);
|
|
|
|
for (i = 0; i < nmfsa; i++) {
|
|
MFSel *mfsp = sortmfsa[i];
|
|
char buf[1024];
|
|
int j;
|
|
|
|
/* widget name is first word in type */
|
|
for (j = 0; isalpha(mfsp->type[j]); j++)
|
|
buf[j] = mfsp->type[j];
|
|
buf[j] = '\0';
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNvisibleWhenOff, True); n++;
|
|
XtSetArg (args[n], XmNindicatorType, XmN_OF_MANY); n++;
|
|
w = XmCreateToggleButton (rc_w, buf, args, n);
|
|
XtAddCallback(w, XmNvalueChangedCallback, m_feasel_cb, mfsp);
|
|
(void) sprintf (buf, "%4d %s", mfsp->n, mfsp->type);
|
|
set_xmstring (w, XmNlabelString, buf);
|
|
mfsp->set = XmToggleButtonGetState (w);
|
|
mfsp->tb = w;
|
|
XtManageChild (w);
|
|
sr_reg (w, NULL, marsfcategory, 1);
|
|
}
|
|
XtFree ((char*)sortmfsa);
|
|
|
|
|
|
/* 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], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
sep_w = XmCreateSeparator (mfform_w, "Sep1", args, n);
|
|
XtManageChild (sep_w);
|
|
|
|
/* add feature list */
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNtopOffset, 10); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNbottomWidget, sep_w); n++;
|
|
XtSetArg (args[n], XmNbottomOffset, 10); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
|
|
XtSetArg (args[n], XmNleftWidget, rc_w); n++;
|
|
XtSetArg (args[n], XmNleftOffset, 10); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNrightOffset, 10); n++;
|
|
XtSetArg (args[n], XmNselectionPolicy, XmMULTIPLE_SELECT); n++;
|
|
flist_w = XmCreateScrolledList (mfform_w, "FL", args, n);
|
|
XtAddCallback (flist_w, XmNmultipleSelectionCallback, m_list_cb, 0);
|
|
XtManageChild (flist_w);
|
|
|
|
flist = (XmString *) XtMalloc (nmf * sizeof(XmString));
|
|
for (i = 0; i < nmf; i++)
|
|
flist[i] = XmStringCreateSimple (mf[i].name);
|
|
XmListAddItemsUnselected (flist_w, flist, nmf, 0);
|
|
for (i = 0; i < nmf; i++)
|
|
XmStringFree (flist[i]);
|
|
XtFree ((char*)flist);
|
|
m_setselected();
|
|
|
|
/* add the controls in their own form */
|
|
|
|
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_FORM); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNfractionBase, 3*XtNumber(mfc)+1); n++;
|
|
f_w = XmCreateForm (mfform_w, "MFTF", args, n);
|
|
XtManageChild (f_w);
|
|
|
|
for (i = 0; i < XtNumber(mfc); i++) {
|
|
MFC *mp = &mfc[i];
|
|
|
|
n = 0;
|
|
XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNleftPosition, 1+3*i); n++;
|
|
XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
|
|
XtSetArg (args[n], XmNrightPosition, 3+3*i); n++;
|
|
w = XmCreatePushButton (f_w, "MFTPB", args, n);
|
|
XtAddCallback (w, XmNactivateCallback, m_features_ctrl_cb,
|
|
(XtPointer)mp->mfce);
|
|
set_xmstring (w, XmNlabelString, mp->label);
|
|
wtip (w, mp->tip);
|
|
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 (cml_w, whether);
|
|
buttonAsButton (slt_w, whether);
|
|
}
|
|
|
|
/* callback when an item is de/selected in the feature list */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_list_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XmListCallbackStruct *lp = (XmListCallbackStruct *)call;
|
|
|
|
if (lp->selected_item_count == 1) {
|
|
int i = lp->selected_item_positions[0]-1;
|
|
m_setnewpos (mf[i].lt, mf[i].lg);
|
|
} else
|
|
m_redraw(0);
|
|
}
|
|
|
|
/* callback from the Moons button */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_moons_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
marsm_manage();
|
|
}
|
|
|
|
/* callback from the Close button on the stats menu */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_mstats_close_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XtUnmanageChild (msform_w);
|
|
}
|
|
|
|
/* callback when want stats menu up */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_mstats_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XtManageChild (msform_w);
|
|
m_set_buttons(m_selecting);
|
|
}
|
|
|
|
/* callback from any of the Features dialog bottom controls.
|
|
* client is one of MFCtrl.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_features_ctrl_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
MFSel *mfsp;
|
|
|
|
switch ((MFCtrl)client) {
|
|
case MFC_OK:
|
|
m_setselected();
|
|
m_redraw(0);
|
|
XtUnmanageChild (mfform_w);
|
|
break;
|
|
case MFC_APPLY:
|
|
m_setselected();
|
|
m_redraw(0);
|
|
break;
|
|
case MFC_ALL:
|
|
for (mfsp = mfsa; mfsp < &mfsa[nmfsa]; mfsp++)
|
|
XmToggleButtonSetState (mfsp->tb, mfsp->set=1, False);
|
|
break;
|
|
case MFC_NONE:
|
|
for (mfsp = mfsa; mfsp < &mfsa[nmfsa]; mfsp++)
|
|
XmToggleButtonSetState (mfsp->tb, mfsp->set=0, False);
|
|
break;
|
|
case MFC_TOGGLE:
|
|
for (mfsp = mfsa; mfsp < &mfsa[nmfsa]; mfsp++)
|
|
XmToggleButtonSetState (mfsp->tb,
|
|
mfsp->set = !XmToggleButtonGetState(mfsp->tb), False);
|
|
break;
|
|
case MFC_CLOSE:
|
|
XtUnmanageChild (mfform_w);
|
|
break;
|
|
case MFC_HELP:
|
|
hlp_dialog ("Mars_features", NULL, 0);
|
|
break;
|
|
default:
|
|
printf ("Bad MFCtrl: %d\n", (int)(long int)client);
|
|
abort();
|
|
}
|
|
}
|
|
|
|
/* callback when want features dialog up */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_features_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XtManageChild (mfform_w);
|
|
}
|
|
|
|
/* callback when want a features TB changes.
|
|
* client is pointer to MFSel whose set state is being changed.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_feasel_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
MFSel *mfsp = (MFSel *) client;
|
|
mfsp->set = XmToggleButtonGetState(w);
|
|
}
|
|
|
|
/* callback from the Print PB */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_print_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XPSAsk ("Mars View", m_print);
|
|
}
|
|
|
|
/* proceed to generate a postscript file.
|
|
* call XPSClose() when finished.
|
|
*/
|
|
static void
|
|
m_print ()
|
|
{
|
|
/* must be up */
|
|
if (!mars_ison()) {
|
|
xe_msg (1, "Mars 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, winsz, winsz, 1*72, 10*72, (int)(6.5*72));
|
|
|
|
/* redraw everything into m_pm */
|
|
m_redraw(1);
|
|
|
|
/* no more X captures */
|
|
XPSXEnd();
|
|
|
|
/* add some extra info */
|
|
m_ps_annotate ();
|
|
|
|
/* finished */
|
|
XPSClose();
|
|
|
|
watch_cursor(0);
|
|
}
|
|
|
|
static void
|
|
m_ps_annotate ()
|
|
{
|
|
Now *np = mm_get_now();
|
|
char dir[128];
|
|
char buf[128];
|
|
int ctr = 306; /* = 8.5*72/2 */
|
|
int lx = 145, rx = 460;
|
|
int y;
|
|
|
|
/* caption */
|
|
y = AROWY(13);
|
|
(void) strcpy (buf, "XEphem Mars View");
|
|
(void) sprintf (dir, "(%s) %d %d cstr", 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_dm_angle (buf, m_slt);
|
|
(void) sprintf (dir,"(%s Latitude:) %d %d rstr (%s) %d %d lstr\n",
|
|
fakepos ? "Center" : "Sub Earth", rx, y, buf, rx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
y = AROWY(8);
|
|
fs_time (buf, mjd_hr(mjd));
|
|
(void) sprintf (dir, "(UTC Time:) %d %d rstr (%s) %d %d lstr\n",
|
|
lx, y, buf, lx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
fs_dm_angle (buf, m_cml);
|
|
(void) sprintf (dir,"(%s Longitude:) %d %d rstr (%s) %d %d lstr\n",
|
|
fakepos ? "Center" : "Sub Earth", rx, y, buf, rx+10, y);
|
|
XPSDirect (dir);
|
|
|
|
/* add site/lat/long if topocentric */
|
|
if (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);
|
|
}
|
|
|
|
/* add seeing if > 0 */
|
|
if (m_seeing) {
|
|
y = AROWY(6);
|
|
(void) sprintf(dir,"(Simulated %.1f Arcsecond Seeing) %d %d cstr\n",
|
|
m_seeing/10.0, ctr, y);
|
|
XPSDirect (dir);
|
|
}
|
|
}
|
|
|
|
/* callback from CML or SLT button being activated.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_selection_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
if (m_selecting) {
|
|
char *name;
|
|
get_something (w, XmNuserData, (XtArgVal)&name);
|
|
register_selection (name);
|
|
}
|
|
}
|
|
|
|
/* callback from the CML scale */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_cml_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XmScaleCallbackStruct *sp = (XmScaleCallbackStruct *)call;
|
|
int v = sp->value;
|
|
|
|
f_dm_angle (cml_w, degrad((double)v));
|
|
|
|
/* Apply button is now useful */
|
|
XtSetSensitive (apply_w, True);
|
|
}
|
|
|
|
/* callback from the SLT scale */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_slt_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XmScaleCallbackStruct *sp = (XmScaleCallbackStruct *)call;
|
|
int v = sp->value;
|
|
|
|
f_dm_angle (slt_w, degrad((double)v));
|
|
|
|
/* Apply button is now useful */
|
|
XtSetSensitive (apply_w, True);
|
|
}
|
|
|
|
/* callback from the Seeing scale */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_see_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XmScaleCallbackStruct *sp = (XmScaleCallbackStruct *)call;
|
|
char str[32];
|
|
int v;
|
|
|
|
v = sp->value;
|
|
(void) sprintf (str, "%4.1f", v/10.0);
|
|
set_xmstring (see_w, XmNlabelString, str);
|
|
|
|
/* Apply button is now useful */
|
|
XtSetSensitive (apply_w, True);
|
|
}
|
|
|
|
/* callback from the Apply PB */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_apply_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
int v;
|
|
|
|
/* gather the new values */
|
|
XmScaleGetValue (cmls_w, &v);
|
|
m_cml = degrad(v);
|
|
f_dm_angle (cml_w, m_cml);
|
|
|
|
XmScaleGetValue (slts_w, &v);
|
|
m_slt = degrad(v);
|
|
m_sslt = sin(m_slt);
|
|
m_cslt = cos(m_slt);
|
|
f_dm_angle (slt_w, m_slt);
|
|
|
|
XmScaleGetValue (sees_w, &v);
|
|
m_seeing = v;
|
|
|
|
/* force a redraw */
|
|
fakepos = 1;
|
|
m_redraw(1);
|
|
}
|
|
|
|
/* callback from the Point PB */
|
|
/* ARGSUSED */
|
|
static void
|
|
m_aim_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
m_setnewpos (pu_l, pu_L);
|
|
}
|
|
|
|
/* install a new lat/long with pa 0 */
|
|
static void
|
|
m_setnewpos (double l, double L)
|
|
{
|
|
m_slt = l;
|
|
m_sslt = sin(m_slt);
|
|
m_cslt = cos(m_slt);
|
|
f_dm_angle (slt_w, m_slt);
|
|
XmScaleSetValue (slts_w, (int)(raddeg(m_slt)));
|
|
|
|
m_cml = L;
|
|
f_dm_angle (cml_w, m_cml);
|
|
XmScaleSetValue (cmls_w, (int)(raddeg(m_cml)));
|
|
|
|
m_pa = 0.0;
|
|
m_spa = 0.0;
|
|
m_cpa = 1.0;
|
|
|
|
fakepos = 1;
|
|
m_redraw(1);
|
|
}
|
|
|
|
/* callback from mshell_w being popped down.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_popdown_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XtUnmanageChild (msform_w);
|
|
XtUnmanageChild (mfform_w);
|
|
|
|
/* register we are now down */
|
|
setXRes (mars_viewupres(), "0");
|
|
}
|
|
|
|
/* called from Close button */
|
|
static void
|
|
m_close_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XtPopdown (mshell_w);
|
|
/* popdown will do all the real work */
|
|
}
|
|
|
|
/* called to add scene to the movie loop */
|
|
static void
|
|
m_mloop_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
ml_add (m_pm, dt_w);
|
|
}
|
|
|
|
/* callback from the any of the option TBs.
|
|
* Option enum is in client.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_option_cb (w, client, call)
|
|
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 HALFSIZ_OPT:
|
|
m_setsize();
|
|
m_redraw(1);
|
|
break;
|
|
|
|
case GRID_OPT:
|
|
if (set) {
|
|
m_grid();
|
|
m_refresh (NULL);
|
|
} else
|
|
m_redraw(0);
|
|
break;
|
|
|
|
case FLIPTB_OPT:
|
|
/* swap color map when flip top/bottom */
|
|
swap_colors();
|
|
m_redraw(1);
|
|
break;
|
|
|
|
case FLIPLR_OPT:
|
|
m_redraw(1);
|
|
break;
|
|
|
|
case N_OPT:
|
|
break;
|
|
}
|
|
|
|
|
|
watch_cursor (0);
|
|
}
|
|
|
|
/* swap dark-bright color map.
|
|
* this is used to keep mountains looking like mountains when flipping t/b
|
|
*/
|
|
static void
|
|
swap_colors()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < REDCOLORS/2; i++) {
|
|
int tmp = mcolors[i];
|
|
mcolors[i] = mcolors[REDCOLORS-1-i];
|
|
mcolors[REDCOLORS-1-i] = tmp;
|
|
}
|
|
}
|
|
|
|
/* callback from the Help all button
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_help_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
static char *msg[] = {
|
|
"This is a map of Mars.",
|
|
};
|
|
|
|
hlp_dialog ("Mars", msg, XtNumber(msg));
|
|
}
|
|
|
|
/* callback from a specific Help button.
|
|
* client is a string to use with hlp_dialog().
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_helpon_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
hlp_dialog ((char *)client, NULL, 0);
|
|
}
|
|
|
|
/* set winsz from HALFSIZ_OPT then size of the scrolling window, image and pm.*/
|
|
static void
|
|
m_setsize()
|
|
{
|
|
Window win = RootWindow(XtD, DefaultScreen(XtD));
|
|
Dimension wid, hei;
|
|
int fullsz;
|
|
|
|
/* full size is IMH/(PI/2) because of wrapping cyl onto sphere */
|
|
fullsz = (int)(IMH/(PI/2));
|
|
winsz = option[HALFSIZ_OPT] ? fullsz/2 : fullsz;
|
|
|
|
mxim_create();
|
|
|
|
wid = 2*BORD+winsz;
|
|
hei = 2*BORD+winsz;
|
|
set_something (mda_w, XmNwidth, (XtArgVal)wid);
|
|
set_something (mda_w, XmNheight, (XtArgVal)hei);
|
|
|
|
if (m_pm)
|
|
XFreePixmap (XtD, m_pm);
|
|
m_pm = XCreatePixmap (XtD, win, wid, hei, mdepth);
|
|
}
|
|
|
|
/* expose (or reconfig) of mars image view drawing area.
|
|
*/
|
|
/* ARGSUSED */
|
|
static void
|
|
m_exp_cb (w, client, call)
|
|
Widget w;
|
|
XtPointer client;
|
|
XtPointer call;
|
|
{
|
|
XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
|
|
XExposeEvent *e = &c->event->xexpose;
|
|
|
|
watch_cursor (1);
|
|
|
|
switch (c->reason) {
|
|
case XmCR_EXPOSE: {
|
|
static int before;
|
|
|
|
if (!before) {
|
|
/* turn off backing store, do first full draw */
|
|
XSetWindowAttributes swa;
|
|
unsigned long mask = CWBackingStore;
|
|
|
|
swa.backing_store = NotUseful;
|
|
XChangeWindowAttributes (e->display, e->window, mask, &swa);
|
|
|
|
m_redraw(1);
|
|
|
|
before = 1;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
printf ("Unexpected mars mda_w event. type=%d\n", c->reason);
|
|
abort();
|
|
}
|
|
|
|
/* update exposed area */
|
|
m_refresh (e);
|
|
|
|
watch_cursor (0);
|
|
}
|
|
|
|
/* 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;
|
|
|
|
if (get_color_resource (mda_w, "GlassBorderColor", &p) < 0) {
|
|
xe_msg (0, "Can not get GlassBorderColor -- using White");
|
|
p = WhitePixel(dsp, DefaultScreen(dsp));
|
|
}
|
|
gcm = GCForeground;
|
|
gcv.foreground = p;
|
|
glassGC = XCreateGC (dsp, win, gcm, &gcv);
|
|
}
|
|
|
|
/* fill glass_xim with GLASSSZ*GLASSMAG view of m_xim centered at coords
|
|
* xc,yc. take care at the edges (m_xim is winsz x winsz)
|
|
*/
|
|
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 >= winsz || sy < 0 || sy >= winsz)
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
/* 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 (x, y);
|
|
}
|
|
}
|
|
|
|
/* establish mimage and m_xim and return 0 else xe_msg() and return -1 */
|
|
static int
|
|
m_readmap()
|
|
{
|
|
unsigned char r[256], g[256], b[256];
|
|
char why[256];
|
|
char fn[1024];
|
|
FILE *fp;
|
|
int w, h;
|
|
int i;
|
|
|
|
/* open mars map */
|
|
(void) sprintf (fn, "%s/auxil/marsmap.jpg", getShareDir());
|
|
fp = fopenh (fn, "r");
|
|
if (!fp) {
|
|
xe_msg (1, "%s:\n%s", fn, syserrstr());
|
|
return (-1);
|
|
}
|
|
|
|
/* read mars file into mimage */
|
|
mimage = jpegRead (fp, &w, &h, r, g, b, why);
|
|
fclose (fp);
|
|
if (!mimage) {
|
|
xe_msg (1, "%s:\n%s", fn, why);
|
|
return (-1);
|
|
}
|
|
|
|
/* make some sanity checks */
|
|
if (w != 2*IMH || h != IMH) {
|
|
xe_msg (1, "%s:\nExpected %d x %d but found %d x %d", fn,
|
|
2*IMH, IMH, w, h);
|
|
free (mimage);
|
|
mimage = NULL;
|
|
return (-1);
|
|
}
|
|
|
|
/* convert colormap index to gray using SMPTE convention */
|
|
for (i = 0; i < w*h; i++) {
|
|
int c = mimage[i];
|
|
mimage[i] = (unsigned char)(.33*r[c] + .5*g[c] + .17*b[c]);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* create m_xim of size winszxwinsz, 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 ()
|
|
{
|
|
Display *dsp = XtDisplay (mda_w);
|
|
int nbytes = winsz*winsz*mbpp/8;
|
|
char *data;
|
|
|
|
/* delete if old exists */
|
|
if (m_xim) {
|
|
free ((void *)m_xim->data);
|
|
m_xim->data = NULL;
|
|
XDestroyImage (m_xim);
|
|
m_xim = NULL;
|
|
}
|
|
|
|
/* 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, DefaultVisual (dsp, DefaultScreen(dsp)),
|
|
/* depth */ mbpp == 1 ? 1 : mdepth,
|
|
/* format */ mbpp == 1 ? XYBitmap : ZPixmap,
|
|
/* offset */ 0,
|
|
/* data */ data,
|
|
/* width */ winsz,
|
|
/* height */ winsz,
|
|
/* 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);
|
|
}
|
|
|
|
/* select each entry in the scrolled list if and only if it is implied
|
|
* from the current list of chosen types.
|
|
*/
|
|
static void
|
|
m_setselected()
|
|
{
|
|
int i;
|
|
|
|
/* unselect all entries */
|
|
XmListDeselectAllItems (flist_w);
|
|
|
|
/* select each entry whose type is set */
|
|
for (i = 0; i < nmf; i++)
|
|
if (mfsa[mf[i].mfsai].set)
|
|
XmListSelectPos (flist_w, i+1, False);
|
|
}
|
|
|
|
/* full redraw takes three steps: fill image, fill pixmap, copy to screen.
|
|
* this does the first step if desired, then always the next 2.
|
|
*/
|
|
static void
|
|
m_redraw(newim)
|
|
int newim;
|
|
{
|
|
watch_cursor (1);
|
|
|
|
XmUpdateDisplay (toplevel_w);
|
|
if (newim)
|
|
mxim_setup ();
|
|
m_drawpm ();
|
|
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 of no pixmap now */
|
|
if (!pm)
|
|
return;
|
|
|
|
if (ep) {
|
|
x = ep->x;
|
|
y = ep->y;
|
|
w = ep->width;
|
|
h = ep->height;
|
|
} else {
|
|
w = winsz+2*BORD;
|
|
h = winsz+2*BORD;
|
|
x = y = 0;
|
|
}
|
|
|
|
XCopyArea (dsp, pm, win, m_fgc, x, y, w, h, x, y);
|
|
}
|
|
|
|
/* make the various gcs, handy pixel values and fill in mcolors[].
|
|
* N.B. just call this once.
|
|
* TODO: reclaim old stuff if called again
|
|
*/
|
|
static void
|
|
m_init_gcs()
|
|
{
|
|
Display *dsp = XtD;
|
|
Window win = XtWindow(toplevel_w);
|
|
Colormap cm = xe_cm;
|
|
XGCValues gcv;
|
|
Pixel reds[REDCOLORS];
|
|
int nreds;
|
|
XColor xc;
|
|
unsigned int gcm;
|
|
Pixel fg;
|
|
Pixel p;
|
|
int i;
|
|
|
|
/* fg and bg */
|
|
get_color_resource (mda_w, "marsColor", &fg);
|
|
(void) get_color_resource (mda_w, "MarsBackground", &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, "MarsAnnotColor", &p);
|
|
gcm = GCForeground | GCBackground;
|
|
gcv.foreground = p;
|
|
gcv.background = mbg;
|
|
m_agc = XCreateGC (dsp, win, gcm, &gcv);
|
|
|
|
get_views_font (dsp, &m_fsp);
|
|
|
|
/* build red ramp for image.
|
|
* base the scale off the foreground color.
|
|
*/
|
|
xc.pixel = fg;
|
|
XQueryColor (dsp, cm, &xc);
|
|
nreds = alloc_ramp (dsp, &xc, cm, reds, REDCOLORS);
|
|
if (nreds < REDCOLORS) {
|
|
xe_msg (0, "Wanted %d but only found %d colors for Mars.",
|
|
REDCOLORS, nreds);
|
|
}
|
|
|
|
/* set mcolors[] */
|
|
for (i = 0; i < REDCOLORS; i++)
|
|
mcolors[i] = reds[nreds*i/REDCOLORS];
|
|
if (!option[FLIPTB_OPT])
|
|
swap_colors();
|
|
}
|
|
|
|
/* update mars info and draw the stat labels */
|
|
static void
|
|
m_stats ()
|
|
{
|
|
Now *np = mm_get_now();
|
|
|
|
/* get fresh mars info */
|
|
marsop = db_basic (MARS);
|
|
db_update (marsop);
|
|
cm_dec = cos(marsop->s_gaedec);
|
|
sm_dec = sin(marsop->s_gaedec);
|
|
|
|
/* compute and display the CML and SLT and polar position angle */
|
|
mars_cml (np, &m_cml, &m_slt, &m_pa);
|
|
m_sslt = sin(m_slt);
|
|
m_cslt = cos(m_slt);
|
|
m_spa = sin(m_pa);
|
|
m_cpa = cos(m_pa);
|
|
|
|
f_dm_angle (cml_w, m_cml);
|
|
XmScaleSetValue (cmls_w, (int)(raddeg(m_cml)));
|
|
f_dm_angle (slt_w, m_slt);
|
|
XmScaleSetValue (slts_w, (int)(raddeg(m_slt)));
|
|
|
|
/* reset fake flag */
|
|
fakepos = 0;
|
|
|
|
/* update time stamps too */
|
|
timestamp (np, dt_w);
|
|
timestamp (np, sdt_w);
|
|
}
|
|
|
|
/* fill the pixmap, m_pm.
|
|
* N.B. if mars image changed, call mxim_setup() before this.
|
|
* N.B. if want to draw, call m_refresh() after this.
|
|
*/
|
|
static void
|
|
m_drawpm ()
|
|
{
|
|
/* check assumptions */
|
|
if (!m_pm) {
|
|
printf ("No mars m_pm Pixmap!\n");
|
|
abort();
|
|
}
|
|
|
|
/* Apply button is no longer useful */
|
|
XtSetSensitive (apply_w, False);
|
|
|
|
/* clear m_pm, and copy m_xim within BORDER */
|
|
XPSPaperColor (mbg);
|
|
XPSFillRectangle (XtD, m_pm, m_bgc, 0, 0, winsz+2*BORD, winsz+2*BORD);
|
|
XPutImage (XtD, m_pm, m_fgc, m_xim, 0, 0, BORD, BORD, winsz, winsz);
|
|
XPSPixmap (m_pm, winsz+2*BORD, winsz+2*BORD, xe_cm, m_bgc, 1);
|
|
|
|
/* add grid, if enabled */
|
|
if (option[GRID_OPT])
|
|
m_grid();
|
|
|
|
/* add feature labels, as enabled */
|
|
m_drFeatures();
|
|
|
|
/* add orientation markings */
|
|
m_orientation();
|
|
|
|
/* and the size calibration */
|
|
m_sizecal();
|
|
|
|
/* user annotation */
|
|
ano_draw (mda_w, m_pm, m_ano, 0);
|
|
}
|
|
|
|
static int
|
|
m_ano (double *latp, double *lngp, int *xp, int *yp, int w2x, int arg)
|
|
{
|
|
int x, y;
|
|
|
|
if (w2x) {
|
|
if (ll2xy (*latp, *lngp, &x, &y) < 0)
|
|
return (0);
|
|
*xp = IX2XX(x);
|
|
*yp = IY2XY(y);
|
|
} else {
|
|
x = XX2IX(*xp);
|
|
y = XY2IY(*yp);
|
|
if (xy2ll (x, y, latp, lngp) < 0)
|
|
return (0);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
/* discard trailing whitespace in name IN PLACE */
|
|
static void
|
|
noTrWhite (name)
|
|
char *name;
|
|
{
|
|
int l;
|
|
|
|
for (l = strlen(name)-1; l >= 0 && isspace(name[l]); --l)
|
|
name[l] = '\0';
|
|
}
|
|
|
|
/* look through mfsa[] for type.
|
|
* if first time for this type, add to list.
|
|
* increment count.
|
|
* return index into mfsa.
|
|
*/
|
|
static int
|
|
findMFSel (type)
|
|
char *type;
|
|
{
|
|
MFSel *mfsp;
|
|
|
|
/* check for existing */
|
|
for (mfsp = mfsa; mfsp < &mfsa[nmfsa]; mfsp++)
|
|
if (!strcmp (type, mfsp->type)) {
|
|
mfsp->n++;
|
|
return (mfsp-mfsa);
|
|
}
|
|
|
|
/* add one */
|
|
mfsa = (MFSel *) XtRealloc ((char*)mfsa, (nmfsa+1)*sizeof(MFSel));
|
|
mfsp = &mfsa[nmfsa++];
|
|
strcpy (mfsp->type, type);
|
|
mfsp->n = 1;
|
|
return (mfsp-mfsa);
|
|
}
|
|
|
|
/* given two pointers to MFeature sort by name, qsort-style */
|
|
static int
|
|
mf_qsort (const void *p1, const void *p2)
|
|
{
|
|
MFeature *f1 = (MFeature*)p1;
|
|
MFeature *f2 = (MFeature*)p2;
|
|
return (strcmp (f1->name, f2->name));
|
|
}
|
|
|
|
/* read in the mars_db features list.
|
|
* build malloced lists mf and mfsa.
|
|
* features in mf[] will be sorted by name.
|
|
* N.B. mf[] point into mfsa[] so don't move them.
|
|
* return 0 if ok, else -1.
|
|
*/
|
|
static int
|
|
m_readFeatures()
|
|
{
|
|
char buf[1024];
|
|
char fn[1024];
|
|
FILE *fp;
|
|
|
|
/* open the file */
|
|
(void) sprintf (fn, "%s/auxil/mars_db", getShareDir());
|
|
fp = fopenh (fn, "r");
|
|
if (!fp) {
|
|
xe_msg (1, "%s:\n%s", fn, syserrstr());
|
|
return (-1);
|
|
}
|
|
|
|
/* prepare lists.
|
|
* really +1 to allow always using realloc, and as staging for next.
|
|
*/
|
|
if (mf)
|
|
XtFree ((void*)mf);
|
|
mf = (MFeature *) XtMalloc (sizeof(MFeature));
|
|
nmf = 0;
|
|
if (mfsa)
|
|
XtFree ((void*)mfsa);
|
|
mfsa = (MFSel *) XtMalloc (sizeof(MFSel));
|
|
nmfsa = 0;
|
|
|
|
/* read and add each feature and unique feature type */
|
|
while (fgets (buf, sizeof(buf), fp)) {
|
|
MFeature *mfp = &mf[nmf];
|
|
char type[sizeof(((MFSel*)0)->type)];
|
|
char name[128];
|
|
int nf;
|
|
|
|
/* ignore all lines that do not follow the pattern */
|
|
nf = sscanf(buf,"%[^|]| %lf | %lf | %lf | %[^\n]", name,
|
|
&mfp->lt, &mfp->lg, &mfp->dia, type);
|
|
if (nf != 5)
|
|
continue;
|
|
mfp->lt = degrad(mfp->lt);
|
|
mfp->lg = degrad(mfp->lg);
|
|
|
|
/* remove trailing white space */
|
|
noTrWhite(type);
|
|
noTrWhite(name);
|
|
strncpy(mfp->name, name, sizeof(mfp->name));
|
|
|
|
/* find type, creating new if first time seen */
|
|
mfp->mfsai = findMFSel (type);
|
|
|
|
/* add */
|
|
nmf++;
|
|
mf = (MFeature *) XtRealloc ((void*)mf, (nmf+1)*sizeof(MFeature));
|
|
}
|
|
fclose(fp);
|
|
|
|
/* sort features by name */
|
|
qsort (mf, nmf, sizeof(MFeature), mf_qsort);
|
|
|
|
/* ok */
|
|
xe_msg (0, "Read %d features from mars_db", nmf);
|
|
return (0);
|
|
}
|
|
|
|
/* draw the mf list, based on what is selected in flist_w */
|
|
static void
|
|
m_drFeatures ()
|
|
{
|
|
Display *dsp = XtDisplay (mda_w);
|
|
int *selected, nselected;
|
|
int i;
|
|
|
|
if (!XmListGetSelectedPos (flist_w, &selected, &nselected))
|
|
return;
|
|
|
|
XSetFont (dsp, m_agc, m_fsp->fid);
|
|
|
|
for (i = 0; i < nselected; i++) {
|
|
MFeature *mfp = &mf[selected[i]-1];
|
|
int dir, asc, des;
|
|
XCharStruct all;
|
|
int r, x, y;
|
|
int l;
|
|
|
|
/* find map location in X windows coords */
|
|
if (ll2xy (mfp->lt, mfp->lg, &x, &y) < 0)
|
|
continue;
|
|
x = IX2XX(x);
|
|
y = IY2XY(y);
|
|
|
|
/* find radius if crater or single mountain or 0, in X pixels */
|
|
if (!strncmp (mfsa[mfp->mfsai].type, "Crater", 6)
|
|
|| strstr (mfp->name, "Mons"))
|
|
r = (int)(winsz*mfp->dia/MARSD)/2;
|
|
else if (!strncmp (mfsa[mfp->mfsai].type, "Landing", 7))
|
|
r = LANDSR;
|
|
else
|
|
r = 0;
|
|
|
|
/* center and display the name */
|
|
l = strlen(mfp->name);
|
|
XTextExtents (m_fsp, mfp->name, l, &dir, &asc, &des, &all);
|
|
XPSDrawString (dsp, m_pm, m_agc, x-all.width/2,y-(r+2),mfp->name,l);
|
|
if (r > 0)
|
|
XPSDrawArc (dsp, m_pm, m_agc, x-r, y-r, 2*r, 2*r, 0, 360*64);
|
|
}
|
|
|
|
XtFree ((char *)selected);
|
|
}
|
|
|
|
/* draw the N/S E/W labels on m_pm */
|
|
static void
|
|
m_orientation()
|
|
{
|
|
Now *np = mm_get_now();
|
|
double mr, mra, mdec;
|
|
double ra, dec;
|
|
int x, y;
|
|
|
|
/* celestial plane has not meaning at arbitrary orientations */
|
|
if (fakepos)
|
|
return;
|
|
|
|
XSetFont (XtD, m_agc, m_fsp->fid);
|
|
mr = degrad(marsop->s_size/3600.0)/2 * 1.1;
|
|
mra = marsop->s_gaera;
|
|
mdec = marsop->s_gaedec;
|
|
|
|
ra = mra + mr/cm_dec;
|
|
dec = mdec;
|
|
m_eqproject (np, ra, dec, &x, &y);
|
|
x = IX2XX(x);
|
|
y = IY2XY(y);
|
|
XPSDrawString (XtD, m_pm, m_agc, x, y, "E", 1);
|
|
|
|
ra = mra - mr/cm_dec;
|
|
m_eqproject (np, ra, dec, &x, &y);
|
|
x = IX2XX(x);
|
|
y = IY2XY(y);
|
|
XPSDrawString (XtD, m_pm, m_agc, x, y, "W", 1);
|
|
|
|
ra = mra;
|
|
dec = mdec + mr;
|
|
m_eqproject (np, ra, dec, &x, &y);
|
|
x = IX2XX(x);
|
|
y = IY2XY(y);
|
|
XPSDrawString (XtD, m_pm, m_agc, x, y, "N", 1);
|
|
|
|
dec = mdec - mr;
|
|
m_eqproject (np, ra, dec, &x, &y);
|
|
x = IX2XX(x);
|
|
y = IY2XY(y);
|
|
XPSDrawString (XtD, m_pm, m_agc, x, y, "S", 1);
|
|
}
|
|
|
|
/* draw the size calibration */
|
|
static void
|
|
m_sizecal()
|
|
{
|
|
int dir, asc, des;
|
|
XCharStruct xcs;
|
|
char buf[64];
|
|
int l;
|
|
|
|
(void) sprintf (buf, "%.1f\"", marsop->s_size);
|
|
l = strlen (buf);
|
|
XQueryTextExtents (XtD, m_fsp->fid, buf, l, &dir, &asc, &des, &xcs);
|
|
|
|
XSetFont (XtD, m_agc, m_fsp->fid);
|
|
XPSDrawLine (XtD, m_pm, m_agc, BORD, winsz+3*BORD/2, winsz+BORD,
|
|
winsz+3*BORD/2);
|
|
XPSDrawLine (XtD, m_pm, m_agc, BORD, winsz+3*BORD/2-3, BORD,
|
|
winsz+3*BORD/2+3);
|
|
XPSDrawLine (XtD, m_pm, m_agc, BORD+winsz, winsz+3*BORD/2-3, BORD+winsz,
|
|
winsz+3*BORD/2+3);
|
|
XPSDrawString (XtD, m_pm, m_agc, BORD+winsz/2-xcs.width/2,
|
|
winsz+3*BORD/2+xcs.ascent+6, buf, l);
|
|
}
|
|
|
|
/* draw a coordinate grid over the image already on m_pm */
|
|
static void
|
|
m_grid()
|
|
{
|
|
Display *dsp = XtDisplay (mda_w);
|
|
double fsp = FSP;
|
|
double lt, lg;
|
|
int x, y;
|
|
|
|
/* set current font */
|
|
XSetFont (dsp, m_agc, m_fsp->fid);
|
|
|
|
/* lines of constant lat */
|
|
for (lt = -PI/2 + GSP; lt < PI/2; lt += GSP) {
|
|
XPoint xpt[(int)(2*PI/FSP)+2];
|
|
int npts = 0;
|
|
|
|
for (lg = 0; lg <= 2*PI+fsp; lg += fsp) {
|
|
if (ll2xy(lt, lg, &x, &y) < 0) {
|
|
if (npts > 0) {
|
|
XPSDrawLines (dsp, m_pm,m_agc,xpt,npts,CoordModeOrigin);
|
|
npts = 0;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (npts >= XtNumber(xpt)) {
|
|
printf ("Mars lat grid overflow\n");
|
|
abort();
|
|
}
|
|
xpt[npts].x = IX2XX(x);
|
|
xpt[npts].y = IY2XY(y);
|
|
npts++;
|
|
}
|
|
|
|
if (npts > 0)
|
|
XPSDrawLines (dsp, m_pm, m_agc, xpt, npts, CoordModeOrigin);
|
|
}
|
|
|
|
/* lines of constant longitude */
|
|
for (lg = 0; lg < 2*PI; lg += GSP) {
|
|
XPoint xpt[(int)(2*PI/FSP)+1];
|
|
int npts = 0;
|
|
|
|
for (lt = -PI/2; lt <= PI/2; lt += fsp) {
|
|
if (ll2xy(lt, lg, &x, &y) < 0) {
|
|
if (npts > 0) {
|
|
XPSDrawLines (dsp, m_pm,m_agc,xpt,npts,CoordModeOrigin);
|
|
npts = 0;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (npts >= XtNumber(xpt)) {
|
|
printf ("Mars lng grid overflow\n");
|
|
abort();
|
|
}
|
|
xpt[npts].x = IX2XX(x);
|
|
xpt[npts].y = IY2XY(y);
|
|
npts++;
|
|
}
|
|
|
|
if (npts > 0)
|
|
XPSDrawLines (dsp, m_pm, m_agc, xpt, npts, CoordModeOrigin);
|
|
}
|
|
|
|
/* X marks the center, unless rotated by hand */
|
|
if (!fakepos) {
|
|
XPSDrawLine (dsp, m_pm, m_agc, IX2XX(-XRAD), IY2XY(-XRAD),
|
|
IX2XX(XRAD), IY2XY(XRAD));
|
|
XPSDrawLine (dsp, m_pm, m_agc, IX2XX(-XRAD), IY2XY(XRAD),
|
|
IX2XX(XRAD), IY2XY(-XRAD));
|
|
}
|
|
}
|
|
|
|
/* fill in m_xim from mimage and current circumstances.
|
|
* m_xim is winszxwinsz, mimage is 2*IMH wide x IMH high.
|
|
*/
|
|
static void
|
|
mxim_setup ()
|
|
{
|
|
#define SQR(x) ((x)*(x))
|
|
int pixseeing = (int)(winsz*m_seeing/marsop->s_size/10);
|
|
int tb = option[FLIPTB_OPT];
|
|
int lr = option[FLIPLR_OPT];
|
|
unsigned char *see; /* seeing temp array */
|
|
unsigned char *pict; /* working temp copy */
|
|
double csh;
|
|
int lsh;
|
|
int x, y;
|
|
|
|
/* check assumptions */
|
|
if (!m_xim) {
|
|
printf ("No mars m_xim!\n");
|
|
abort();
|
|
}
|
|
if (!mimage) {
|
|
printf ("No mars mimage!\n");
|
|
abort();
|
|
}
|
|
|
|
/* make working copy -- background is 0 */
|
|
pict = (unsigned char *) XtCalloc (winsz*winsz, 1);
|
|
|
|
/* make seeing temp array if non-0 seeing */
|
|
see = pixseeing > 0 ? (unsigned char *) XtMalloc (winsz) : NULL;
|
|
|
|
/* scan to build up the morphed relief map, and allow for flipping */
|
|
for (y = -WINR; y < WINR; y++) {
|
|
int iy = (tb ? -y-1 : y) + WINR;
|
|
unsigned char *prow = &pict[iy*winsz];
|
|
|
|
pm_set ((y+WINR)*50/winsz);
|
|
|
|
for (x = -WINR; x < WINR; x++) {
|
|
int ix = (lr ? -x-1 : x) + WINR;
|
|
unsigned char *px = &prow[ix];
|
|
|
|
if (x*x + y*y < WINR*WINR) {
|
|
double l, L;
|
|
int mx, my;
|
|
|
|
if (xy2ll (x, y, &l, &L) == 0) {
|
|
/* find the mimage pixel at l/L */
|
|
my = (int)(IMH*(PI/2-l)/PI);
|
|
L = degrad(LONG0) - L;
|
|
range (&L, 2*PI);
|
|
mx = (int)(IMW*L/(2*PI));
|
|
*px = mimage[my*IMW+mx];
|
|
if (!*px)
|
|
*px = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* find cos of shadow foreshortening angle based on planar
|
|
* sun-mars-earth triangle and earth-sun == 1.
|
|
* if we are faking it, turn off the shadow.
|
|
*/
|
|
csh = fakepos ? 1.0 : (SQR(marsop->s_sdist) + SQR(marsop->s_edist) - 1)
|
|
/ (2*marsop->s_sdist*marsop->s_edist);
|
|
|
|
/* shadow is on left if elongation is positive and flipped lr
|
|
* or elongation is negative and not flipped lr.
|
|
*/
|
|
lsh = (marsop->s_elong > 0.0 && lr) || (marsop->s_elong < 0.0 && !lr);
|
|
|
|
/* scan again to blur, add shadow and place real pixels */
|
|
for (y = -WINR; y < WINR; y++) {
|
|
int iy = y + WINR;
|
|
unsigned char *prow = &pict[iy*winsz];
|
|
int lx, rx;
|
|
|
|
pm_set (50+(y+WINR)*50/winsz);
|
|
|
|
if (lsh) {
|
|
lx = (int)(-csh*sqrt((double)(WINR*WINR - y*y)) + .5);
|
|
rx = WINR;
|
|
} else {
|
|
lx = -WINR;
|
|
rx = (int)(csh*sqrt((double)(WINR*WINR - y*y)) + .5);
|
|
}
|
|
|
|
/* fill in seeing table for this row */
|
|
if (pixseeing > 0) {
|
|
for (x = -WINR; x < WINR; x++) {
|
|
int ix = x + WINR;
|
|
int s = (pixseeing+1)/2;
|
|
int nsc = 0;
|
|
int sc = 0;
|
|
int dx, dy;
|
|
int step;
|
|
|
|
/* is center within mars circle? */
|
|
if (x*x + y*y > WINR*WINR)
|
|
continue;
|
|
|
|
/* establish sample step size, some fraction of seeing */
|
|
step = s/7;
|
|
if (step < 1)
|
|
step = 1;
|
|
|
|
/* average a sampled circle about ix,iy */
|
|
for (dy = -s; dy <= s; dy += step) {
|
|
int sy = y + dy;
|
|
int maxdxdx = s*s - dy*dy;
|
|
int maxsxsx = WINR*WINR - sy*sy;
|
|
unsigned char *py = &pict[(sy+WINR)*winsz];
|
|
for (dx = -s; dx <= s; dx += step) {
|
|
if (dx*dx <= maxdxdx) { /* within seeing circle? */
|
|
int sx = x + dx;
|
|
if (sx*sx <= maxsxsx) { /* within mars ? */
|
|
sc += py[sx+WINR];
|
|
nsc++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
see[ix] = nsc > 0 ? sc/nsc : 0;
|
|
}
|
|
}
|
|
|
|
for (x = -WINR; x < WINR; x++) {
|
|
int ix = x + WINR;
|
|
unsigned long p;
|
|
int c;
|
|
|
|
if (x < lx || x > rx || x*x + y*y >= WINR*WINR)
|
|
c = 0;
|
|
else if (pixseeing > 0)
|
|
c = see[ix];
|
|
else
|
|
c = prow[ix];
|
|
|
|
p = c ? mcolors[c*REDCOLORS/256] : mbg;
|
|
XPutPixel (m_xim, ix, iy, p);
|
|
}
|
|
}
|
|
|
|
XtFree ((char *)pict);
|
|
if (see)
|
|
XtFree ((char *)see);
|
|
}
|
|
|
|
/* convert [x,y] to true mars lat/long, in rads.
|
|
* x: centered, +right, -WINR .. x .. WINR
|
|
* y: centered, +down, -WINR .. y .. WINR
|
|
* return 0 if x,y are really over the planet, else -1.
|
|
* caller can be assured -PI/2 .. l .. PI/2 and 0 .. L .. 2*PI.
|
|
* N.B. it is up to the caller to deal wth flipping.
|
|
*/
|
|
static int
|
|
xy2ll (x, y, lp, Lp)
|
|
int x, y;
|
|
double *lp, *Lp;
|
|
{
|
|
double R = sqrt ((double)(x*x + y*y));
|
|
double a;
|
|
double ca, B;
|
|
|
|
if (R >= WINR)
|
|
return (-1);
|
|
|
|
if (y == 0)
|
|
a = x < 0 ? -PI/2 : PI/2;
|
|
else
|
|
a = atan2((double)x,(double)y);
|
|
solve_sphere (a, asin(R/WINR), m_sslt, m_cslt, &ca, &B);
|
|
|
|
*lp = PI/2 - acos(ca);
|
|
*Lp = m_cml + B;
|
|
range (Lp, 2*PI);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/* convert true mars lat/long, in rads, to [x,y].
|
|
* x: centered, +right, -WINR .. x .. WINR
|
|
* y: centered, +down, -WINR .. y .. WINR
|
|
* return 0 if loc is on the front face, else -1 (but still compute x,y);
|
|
* N.B. it is up to the caller to deal wth flipping of the resulting locs.
|
|
*/
|
|
static int
|
|
ll2xy (l, L, xp, yp)
|
|
double l, L;
|
|
int *xp, *yp;
|
|
{
|
|
double sR, cR;
|
|
double A, sA, cA;
|
|
|
|
solve_sphere (L - m_cml, PI/2 - l, m_sslt, m_cslt, &cR, &A);
|
|
sR = sqrt(1.0 - cR*cR);
|
|
sA = sin(A);
|
|
cA = cos(A);
|
|
|
|
*xp = (int)floor(WINR*sR*sA + 0.5);
|
|
*yp = (int)floor(WINR*sR*cA + 0.5);
|
|
|
|
return (cR > 0 ? 0 : -1);
|
|
}
|
|
|
|
/* 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 (x, y)
|
|
int x, y;
|
|
{
|
|
double lt, lg;
|
|
|
|
/* convert from mda_w X Windows coords to centered m_xim coords */
|
|
x = XX2IX(x);
|
|
y = XY2IY(y);
|
|
|
|
if (xy2ll (x, y, <, &lg) == 0) {
|
|
f_dm_angle (lat_w, lt);
|
|
f_dm_angle (lng_w, lg);
|
|
} else {
|
|
set_xmstring (lat_w, XmNlabelString, " ");
|
|
set_xmstring (lng_w, XmNlabelString, " ");
|
|
}
|
|
}
|
|
|
|
/* find the smallest entry in mf[] that [x,y] is within.
|
|
* if find one return its *MFeature else NULL.
|
|
* x and y are in image coords.
|
|
* N.B. we allow for flipping.
|
|
*/
|
|
static MFeature *
|
|
closeFeature (x, y)
|
|
int x, y;
|
|
#define RSLOP 5
|
|
{
|
|
MFeature *mfp, *smallp;
|
|
double lt, lg; /* location of [x,y] */
|
|
double forsh; /* foreshortening (cos of angle from center) */
|
|
double minr;
|
|
|
|
/* find forshortening */
|
|
if (xy2ll (x, y, <, &lg) < 0)
|
|
return (NULL);
|
|
solve_sphere (lg - m_cml, PI/2-m_slt, sin(lt), cos(lt), &forsh, NULL);
|
|
|
|
watch_cursor(1);
|
|
|
|
minr = 1e6;
|
|
smallp = NULL;
|
|
for (mfp = mf; mfp < &mf[nmf]; mfp++) {
|
|
int sz; /* radius, in pixels */
|
|
int dx, dy;
|
|
int fx, fy;
|
|
double r;
|
|
|
|
/* find pixels from cursor */
|
|
if (ll2xy (mfp->lt, mfp->lg, &fx, &fy) < 0)
|
|
continue;
|
|
dx = fx - x;
|
|
dy = fy - y;
|
|
r = sqrt((double)dx*dx + (double)dy*dy);
|
|
|
|
/* it's a candidate if we are inside its (foreshortened) size
|
|
* or we are within RSLOP pixel of it.
|
|
*/
|
|
sz = (int)(mfp->dia*(winsz/MARSD/2));
|
|
if (r <= sz*forsh && r < minr) {
|
|
smallp = mfp;
|
|
minr = r;
|
|
}
|
|
}
|
|
|
|
watch_cursor(0);
|
|
|
|
return (smallp);
|
|
}
|
|
|
|
/* called when hit button 3 over image */
|
|
static void
|
|
m_popup (ep)
|
|
XEvent *ep;
|
|
{
|
|
XButtonEvent *bep;
|
|
int overmars;
|
|
int x, y;
|
|
|
|
/* get m_da convert to image coords */
|
|
bep = &ep->xbutton;
|
|
x = XX2IX(bep->x);
|
|
y = XY2IY(bep->y);
|
|
|
|
overmars = xy2ll (x, y, &pu_l, &pu_L) == 0;
|
|
|
|
if (overmars) {
|
|
MFeature *mfp = closeFeature (x, y);
|
|
char buf[32];
|
|
|
|
/* create popup menu first time */
|
|
if (!pu_w)
|
|
m_create_popup();
|
|
|
|
if (mfp) {
|
|
char *type = mfsa[mfp->mfsai].type;
|
|
|
|
set_xmstring (pu_name_w, XmNlabelString, mfp->name);
|
|
XtManageChild (pu_name_w);
|
|
|
|
(void) sprintf (buf, "%.*s", (int)strcspn (type, " ,-"), type);
|
|
set_xmstring (pu_type_w, XmNlabelString, buf);
|
|
XtManageChild (pu_type_w);
|
|
|
|
(void) sprintf (buf, "%.1f km", mfp->dia);
|
|
set_xmstring (pu_size_w, XmNlabelString, buf);
|
|
XtManageChild (pu_size_w);
|
|
|
|
/* show feature's coords */
|
|
fs_sexa (buf, raddeg(mfp->lt), 3, 60);
|
|
(void) strcat (buf, " N");
|
|
set_xmstring (pu_l_w, XmNlabelString, buf);
|
|
fs_sexa (buf, raddeg(mfp->lg), 3, 60);
|
|
(void) strcat (buf, " W");
|
|
set_xmstring (pu_L_w, XmNlabelString, buf);
|
|
} else {
|
|
XtUnmanageChild (pu_name_w);
|
|
XtUnmanageChild (pu_type_w);
|
|
XtUnmanageChild (pu_size_w);
|
|
|
|
/* show cursors coords */
|
|
fs_sexa (buf, raddeg(pu_l), 3, 3600);
|
|
(void) strcat (buf, " N");
|
|
set_xmstring (pu_l_w, XmNlabelString, buf);
|
|
fs_sexa (buf, raddeg(pu_L), 3, 3600);
|
|
(void) strcat (buf, " W");
|
|
set_xmstring (pu_L_w, XmNlabelString, buf);
|
|
}
|
|
|
|
XmMenuPosition (pu_w, (XButtonPressedEvent *)ep);
|
|
XtManageChild (pu_w);
|
|
}
|
|
}
|
|
|
|
/* create the surface popup menu */
|
|
static void
|
|
m_create_popup()
|
|
{
|
|
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, "MSKYPU", args, n);
|
|
|
|
n = 0;
|
|
pu_name_w = XmCreateLabel (pu_w, "MName", args, n);
|
|
wtip (pu_name_w, "Name");
|
|
|
|
n = 0;
|
|
pu_type_w = XmCreateLabel (pu_w, "MType", args, n);
|
|
wtip (pu_type_w, "Type");
|
|
|
|
n = 0;
|
|
pu_size_w = XmCreateLabel (pu_w, "MSizeat", args, n);
|
|
wtip (pu_size_w, "Size");
|
|
|
|
n = 0;
|
|
pu_l_w = XmCreateLabel (pu_w, "MLat", args, n);
|
|
wtip (pu_l_w, "Latitude");
|
|
XtManageChild (pu_l_w);
|
|
|
|
n = 0;
|
|
pu_L_w = XmCreateLabel (pu_w, "MLong", args, n);
|
|
wtip (pu_L_w, "Longitude");
|
|
XtManageChild (pu_L_w);
|
|
|
|
n = 0;
|
|
w = XmCreateSeparator (pu_w, "MSKYPS", args, n);
|
|
XtManageChild (w);
|
|
|
|
n = 0;
|
|
pu_aim_w = XmCreatePushButton (pu_w, "Point", args, n);
|
|
XtAddCallback (pu_aim_w, XmNactivateCallback, m_aim_cb, NULL);
|
|
wtip (pu_aim_w, "Center this location in the view");
|
|
XtManageChild (pu_aim_w);
|
|
}
|
|
|
|
/* given geocentric ra and dec find image [xy] on martian equitorial projection.
|
|
* [0,0] is center, +x martian right/west (celestial east) +y down/north.
|
|
* N.B. we do *not* allow for flipping here.
|
|
* N.B. this only works when ra and dec are near mars.
|
|
* N.B. this uses m_pa.
|
|
*/
|
|
static void
|
|
m_eqproject (np, ra, dec, xp, yp)
|
|
Now *np;
|
|
double ra, dec;
|
|
int *xp, *yp;
|
|
{
|
|
double scale = winsz/degrad(marsop->s_size/3600.0); /* pix/rad */
|
|
double xr, yr;
|
|
double x, y;
|
|
|
|
/* find x and y so +x is celestial right/east and +y is down/north */
|
|
x = scale*(ra - marsop->s_gaera)*cm_dec;
|
|
y = scale*(dec - marsop->s_gaedec);
|
|
|
|
/* rotate by position angle, m_pa.
|
|
*/
|
|
xr = x*m_cpa - y*m_spa;
|
|
yr = x*m_spa + y*m_cpa;
|
|
|
|
*xp = (int)floor(xr + 0.5);
|
|
*yp = (int)floor(yr + 0.5);
|
|
}
|
|
|
|
/* return:
|
|
* *cmlp: Martian central meridian longitude;
|
|
* *sltp: subearth latitude
|
|
* *pap: position angle of N pole (ie, rads E of N)
|
|
* all angles in rads.
|
|
*/
|
|
|
|
#define M_CML0 degrad(325.845) /* Mars' CML towards Aries at M_MJD0 */
|
|
#define M_MJD0 (2418322.0 - MJD0) /* mjd date of M_CML0 */
|
|
#define M_PER degrad(350.891962) /* Mars' rotation period, rads/day */
|
|
|
|
static void
|
|
mars_cml(np, cmlp, sltp, pap)
|
|
Now *np;
|
|
double *cmlp;
|
|
double *sltp;
|
|
double *pap;
|
|
{
|
|
Obj *sp;
|
|
double a; /* angle from Sun ccw to Earth seen from Mars, rads */
|
|
double Ae; /* planetocentric longitude of Earth from Mars, rads */
|
|
double cml0; /* Mar's CML towards Aries, rads */
|
|
double lc; /* Mars rotation correction for light travel, rads */
|
|
double tmp;
|
|
|
|
sp = db_basic (SUN);
|
|
db_update (sp);
|
|
|
|
a = asin (sp->s_edist/marsop->s_edist*sin(marsop->s_hlong-sp->s_hlong));
|
|
Ae = marsop->s_hlong + PI + a;
|
|
cml0 = M_CML0 + M_PER*(mjd-M_MJD0) + PI/2;
|
|
range(&cml0, 2*PI);
|
|
lc = LTAU * marsop->s_edist/SPD*M_PER;
|
|
*cmlp = cml0 - Ae - lc;
|
|
range (cmlp, 2*PI);
|
|
|
|
solve_sphere (POLE_RA - marsop->s_gaera, PI/2-POLE_DEC, sm_dec, cm_dec,
|
|
&tmp, pap);
|
|
|
|
/* from Green (1985) "Spherical Astronomy", Cambridge Univ. Press,
|
|
* p.428. Courtesy Jim Bell.
|
|
*/
|
|
*sltp = asin (-sin(POLE_DEC)*sin(marsop->s_gaedec) -
|
|
cos(POLE_DEC)*cos(marsop->s_gaedec)
|
|
* cos(marsop->s_gaera-POLE_RA));
|
|
}
|
|
|