home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part15 / skyviewmenu.c.1 < prev   
Encoding:
Text File  |  1993-05-15  |  30.9 KB  |  1,001 lines

  1. /* code to manage the stuff on the sky view display.
  2.  * the filter menu is in filtermenu.c.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <math.h>
  8. #if defined(__STDC__)
  9. #include <stdlib.h>
  10. #endif
  11. #include <X11/Xlib.h>
  12. #include <Xm/Xm.h>
  13. #include <Xm/Form.h>
  14. #include <Xm/Frame.h>
  15. #include <Xm/DrawingA.h>
  16. #include <Xm/Label.h>
  17. #include <Xm/PushB.h>
  18. #include <Xm/CascadeB.h>
  19. #include <Xm/RowColumn.h>
  20. #include <Xm/ToggleB.h>
  21. #include <Xm/Text.h>
  22. #include <Xm/Scale.h>
  23. #include <Xm/Separator.h>
  24. #include "astro.h"
  25. #include "circum.h"
  26.  
  27. /* we keep a linked-list of Objects we want trails for. these in turn "contain"
  28.  * a variable-length array of TSkys for each location in the trail. The TSkys
  29.  * are kept in increasing-time order as they are inserted for later plotting.
  30.  * an item is added when the popup says so; it is removed if we are told the
  31.  * object has been changed via sv_newobj(); all are removed if the whole db
  32.  * changes.
  33.  * also, we add to sky[] in multiples of TRAILCHUNKS for memory efficiency.
  34.  */
  35. typedef struct {
  36.     unsigned flags;    /* OBJF_ things for this particular point */
  37.     double ts_mjd;    /* mjd when this Obj was valid */
  38.     Obj o;        /* copy of the object at ts_mjd */
  39. } TSky;
  40. struct trailObj {
  41.     struct trailObj *ntop;    /* pointer to next, or NULL */
  42.     int on;        /* use to mark on/off; actually remved on next update */
  43.     Obj *op;        /* object being trailed */
  44.     int nsky;        /* number of items in use within sky[] */
  45.     int nskymem;    /* total space of sky[] */
  46.     TSky sky[1];    /* basicaly a variable-length array of Objs */
  47. };
  48. typedef struct trailObj TrailObj;
  49.  
  50. #if defined(__STDC__) || defined(__cplusplus)
  51. #define P_(s) s
  52. #else
  53. #define P_(s) ()
  54. #endif
  55.  
  56. extern Now *mm_get_now P_((void));
  57. extern Obj *db_basic P_((int id));
  58. extern Obj *db_next P_((Obj *op, HowNext how));
  59. extern char *obj_description P_((Obj *op));
  60. extern double mjd_hr P_((double jd));
  61. extern int f_ison P_((void));
  62. extern int lc P_((int cx, int cy, int cw, int x1, int y1, int x2, int y2, int *sx1, int *sy1, int *sx2, int *sy2));
  63. extern int svf_filter_ok P_((Obj *op));
  64. extern int tickmarks P_((double min, double max, int numdiv, double ticks[]));
  65. extern void aa_hadec P_((double lati, double alt, double az, double *ha, double *dec));
  66. extern void db_update P_((Obj *op));
  67. extern void ecl_eq P_((double Mjd, double Lat, double Lng, double *ra, double *dec));
  68. extern void eq_ecl P_((double Mjd, double ra, double dec, double *Lat, double *Lng));
  69. extern void f_showit P_((Widget w, char *s));
  70. extern void fs_angle P_((char out[], double a));
  71. extern void fs_date P_((char out[], double jd));
  72. extern void fs_ra P_((char out[], double ra));
  73. extern void fs_time P_((char out[], double t));
  74. extern void get_something P_((Widget w, char *resource, char *value));
  75. extern void gk_mag P_((double g, double k, double rp, double rho, double *mp));
  76. extern void hadec_aa P_((double lati, double ha, double dec, double *alt, double *az));
  77. extern void hlp_dialog P_((char *tag, char *deflt[], int ndeflt));
  78. extern void now_lst P_((Now *np, double *lst));
  79. extern void obj_pickgc P_((Obj *op, Widget w, GC *gcp));
  80. extern void obj_set P_((Obj *op));
  81. extern void precess P_((double mjd1, double mjd2, double *ra, double *dec));
  82. extern void range P_((double *v, double r));
  83. extern void refract P_((double pr, double tr, double ta, double *aa));
  84. extern void set_something P_((Widget w, char *resource, char *value));
  85. extern void set_xmstring P_((Widget w, char *resource, char *txt));
  86. extern void svf_create P_((void));
  87. extern void svf_manage P_((void));
  88. extern void svf_manage_toggle P_((void));
  89. extern void svf_unmanage P_((void));
  90. extern void timestamp P_((Now *np, Widget w));
  91. extern void unrefract P_((double pr, double tr, double aa, double *ta));
  92. extern void watch_cursor P_((int want));
  93. extern void xe_msg P_((char *msg, int app_modal));
  94.  
  95. void sv_manage P_((void));
  96. int sv_ison P_((void));
  97. void sv_newobj P_((int dbidx));
  98. void sv_newdb P_((int appended));
  99. void sv_update P_((Now *np, int how_much));
  100. void sv_point P_((Obj *op));
  101. int sv_id P_((Obj *op));
  102. void sv_cursor P_((Cursor c));
  103. void sv_all P_((Now *np, int preclr));
  104. void sv_draw_obj P_((Display *dsp, Drawable win, GC gc, Obj *op, int x, int y, int diam, int dotsonly));
  105. static void sv_copy_sky P_((void));
  106. static void sv_create_svform P_((void));
  107. static void sv_create_find P_((Widget parent));
  108. static void sv_close_cb P_((Widget w, XtPointer client, XtPointer call));
  109. static void sv_help_cb P_((Widget w, XtPointer client, XtPointer call));
  110. static void sv_aa_cb P_((Widget w, XtPointer client, XtPointer call));
  111. static void sv_all_labels_cb P_((Widget w, XtPointer client, XtPointer call));
  112. static void sv_filter_cb P_((Widget w, XtPointer client, XtPointer call));
  113. static void sv_grid_cb P_((Widget w, XtPointer client, XtPointer call));
  114. static void sv_set_scales P_((void));
  115. static void sv_da_exp_cb P_((Widget w, XtPointer client, XtPointer call));
  116. static void sv_da_input_cb P_((Widget w, XtPointer client, XtPointer call));
  117. static void sv_da_motion_cb P_((Widget w, XtPointer client, XEvent *ev, Boolean *continue_to_dispatch));
  118. static void sv_changed_cb P_((Widget w, XtPointer client, XtPointer call));
  119. static void sv_ecliptic_cb P_((Widget w, XtPointer client, XtPointer call));
  120. static void sv_justdots_cb P_((Widget w, XtPointer client, XtPointer call));
  121. static void sv_finding_cb P_((Widget wid, XtPointer client, XtPointer call));
  122. static void sv_find_cb P_((Widget w, XtPointer client, XtPointer call));
  123. static void sv_magdrag_cb P_((Widget w, XtPointer client, XtPointer call));
  124. static void sv_set_view P_((void));
  125. static void sv_getcircle P_((unsigned int *wp, unsigned int *hp, unsigned int *rp, unsigned int *xbp, unsigned int *ybp));
  126. static void sv_popup P_((XEvent *ev, Obj *op, TSky *tsp));
  127. static void sv_create_popup P_((void));
  128. static void sv_pu_activate_cb P_((Widget w, XtPointer client, XtPointer call));
  129. static void sv_pu_trail_cb P_((Widget wid, XtPointer client, XtPointer call));
  130. static void sv_pu_label_cb P_((Widget wid, XtPointer client, XtPointer call));
  131. static void tobj_rmoff P_((void));
  132. static void tobj_rmobj P_((Obj *op));
  133. static TrailObj *tobj_addobj P_((Obj *op));
  134. static TrailObj *tobj_growsky P_((TrailObj *top));
  135. static void tobj_reset P_((void));
  136. static TrailObj *tobj_find P_((Obj *op));
  137. static TrailObj *tobj_addsky P_((TrailObj *top, double jd, Obj *op));
  138. static void tobj_display_all P_((unsigned r, unsigned xb, unsigned yb));
  139. static sv_dbobjloc P_((Obj *op, int r, int *xp, int *yp));
  140. static sv_trailobjloc P_((TSky *tsp, int r, int *xp, int *yp));
  141. static sv_precheck P_((Obj *op));
  142. static sv_bright_ok P_((Obj *op));
  143. static sv_infov P_((Obj *op));
  144. static sv_loc P_((int rad, double altdec, double azra, int *xp, int *yp));
  145. static sv_unloc P_((int rad, int x, int y, double *altdecp, double *azrap));
  146. static void draw_ecliptic P_((Display *dsp, Window win, GC gc, unsigned int r, unsigned int xb, unsigned int yb));
  147. static void draw_grid P_((Display *dsp, Window win, GC gc, unsigned int r, unsigned int xb, unsigned int yb));
  148. static magdiam P_((double m));
  149. static void sv_mk_gcs P_((Display *dsp, Window win));
  150. static void draw_label P_((Display *dsp, Window win, GC gc, char label[], int x, int y));
  151.  
  152. #undef P_
  153.  
  154. extern Widget toplevel_w;
  155.  
  156. #define    NGRID    20        /* max grid lines each dimension */
  157. #define    NSEGS    5        /* piecewise segments per arc */
  158. #define    ECL_TICS    2    /* period of points for ecliptic, pixels */
  159.  
  160. #define    MARKER    20        /* pointer marker half-width, pixels */
  161.  
  162. #define    BMAGLIMIT    (-28)    /* brightest setting for the Mag scales */
  163. #define    FMAGLIMIT    20    /* faintest setting for the Mag scales */
  164. #define    TRAILCHUNKS    50    /* we malloc these many at a time */
  165.  
  166. static Widget svform_w;            /* main sky view form dialog */
  167. static Widget svda_w;            /* sky view drawing area */
  168. static Widget fov_w, altdec_w, azra_w;    /* scale widgets */
  169. static Widget fmag_w, bmag_w;        /* magnitude scale widgets */
  170. static Widget hgrid_w, vgrid_w;        /* h and v grid spacing labels */
  171. static Widget aa_w, rad_w;        /* altaz/radec toggle buttons */
  172. static Widget dt_w;            /* the date/time stamp label widget */
  173. static Widget find_w[2];        /* cascade buttons for "find" objx/y */
  174. static Pixmap sv_pm;            /* off-screen pixmap we *really* draw */
  175. static Widget talt_w, taz_w;        /* tracking alt/az report widgets */
  176. static Widget tra_w, tdec_w;        /* tracking ra/dec report widgets */
  177.  
  178. /* pixels and GCs
  179.  */
  180. static Pixel fg_p, bg_p, sky_p;    /* default fg, background, and sky colors */
  181. static GC sv_gc;        /* the default GC */
  182.  
  183. static int aa_mode = -1;    /* 1 for alt/az or 0 for ra/dec */
  184. static double sv_altdec;    /* view center alt or dec, rads */
  185. static double sv_azra;        /* view center az or ra, rads */
  186. static double sv_fov;        /* field of view, rads */
  187. static int fmag, bmag;        /* faintest/brightest magnitude to display */
  188. static int justdots;        /* set when only want to use dots on the map */
  189. static int want_ecliptic;    /* set when want to see the ecliptic */
  190. static TrailObj *trailobj;    /* head of a malloced linked-list -- 0 when
  191.                  * empty
  192.                  */
  193. static int want_grid;        /* set when we want to draw the coord grid */
  194. static all_labels;        /* !0 when want to display all labels */
  195. static int sv_ournewobj;    /* used to inhibit useless redrawing */
  196.  
  197. static char null_grid_str[] = "             ";
  198.  
  199. /* info about the popup widget.
  200.  * we make one once and keep reusing it -- seems to be a bit faster that way.
  201.  */
  202. typedef struct {
  203.     Widget pu_w;
  204.     Widget name_w;
  205.     Widget desc_w;
  206.     Widget spect_w;
  207.     Widget ud_w;
  208.     Widget ut_w;
  209.     Widget ra_w;
  210.     Widget dec_w;
  211.     Widget alt_w;
  212.     Widget az_w;
  213.     Widget mag_w;
  214.     Widget trail_w;
  215.     Widget label_w;
  216.     Obj *op;
  217.     TSky *tsp;    /* this is used if we are displaying a trailed object */
  218. } Popup;
  219. static Popup pu;
  220.  
  221. enum {AIM, MK_OBJX};        /* popup button activate codes */
  222.  
  223. /* Obj.flags or TSky flags values */
  224. #define    OBJF_ONSCREEN    0x1    /* bit set if obj is on screen */
  225. #define    OBJF_LABEL    0x2    /* set if label is to be on */
  226.  
  227. /* called when the sky view is activated via the main menu pulldown.
  228.  * if never called before, create and manage all the widgets as a child of a
  229.  * form. otherwise, just toggle whether the form is managed.
  230.  * also manage the corresponding filter dialog along with.
  231.  * freeing the pixmap will force a fresh update on the next expose.
  232.  */
  233. void
  234. sv_manage ()
  235. {
  236.     if (!svform_w)
  237.         sv_create_svform(); /* also creates the filter */
  238.     
  239.     if (XtIsManaged(svform_w)) {
  240.         XtUnmanageChild (svform_w);
  241.         svf_unmanage();
  242.         if (sv_pm) {
  243.         XFreePixmap (XtDisplay(svda_w), sv_pm);
  244.         sv_pm = (Pixmap) NULL;
  245.         }
  246.     } else {
  247.         XtManageChild (svform_w);
  248.         /* rely on expose to a fresh update */
  249.     }
  250. }
  251.  
  252. sv_ison()
  253. {
  254.     return (svform_w && XtIsManaged(svform_w));
  255. }
  256.  
  257. /* called when a user-defined object has changed.
  258.  * take it off the trailobj list, if it's there (it's ok if it's not).
  259.  * then since we rely on knowing our update will be called we need do nothing
  260.  *   more to redisplay without the object.
  261.  */
  262. void
  263. sv_newobj(dbidx)
  264. int dbidx;        /* OBJX or OBJY */
  265. {
  266.     Obj *op = db_basic(dbidx);
  267.  
  268.     tobj_rmobj (op);
  269.  
  270. }
  271.  
  272. /* called when the db (beyond NOBJ) has changed.
  273.  * if it was appended to we can just redraw; if it was changed we need to
  274.  * discard any trails we are keeping first.
  275.  */
  276. void
  277. sv_newdb(appended)
  278. int appended;
  279. {
  280.     if (!appended)
  281.         tobj_reset();
  282.     sv_update (mm_get_now(), 1);
  283. }
  284.  
  285. /* called when we are to update our view.
  286.  * don't bother if we are unmanaged unless there are trails to be saved.
  287.  * add any objects in the trails list then redraw the screen if we are up.
  288.  * also don't bother if we are the reason for an all_newobj() or if fields are
  289.  *   off.
  290.  * we also remove any trails that have been turned off.
  291.  */
  292. /* ARGSUSED */
  293. void
  294. sv_update (np, how_much)
  295. Now *np;
  296. int how_much;
  297. {
  298.     TrailObj *top;
  299.     int up;
  300.  
  301.     if (sv_ournewobj)
  302.         return;
  303.  
  304.     up = svform_w && XtIsManaged(svform_w);
  305.     if (!up && !trailobj)
  306.         return;
  307.  
  308.     /* remove trails no longer wanted. */
  309.     tobj_rmoff();
  310.  
  311.     /* add an entry to each trailed object for this time. */
  312.     for (top = trailobj; top; top = top->ntop) {
  313.         db_update (top->op);
  314.         top = tobj_addsky (top, mjd, top->op);
  315.     }
  316.  
  317.     if (up && f_ison())
  318.         sv_all(np, 1);
  319. }
  320.  
  321. /* point at the given object and mark it.
  322.  * N.B. we do *not* update the s_ fields of op.
  323.  */
  324. void
  325. sv_point (op)
  326. Obj *op;
  327. {
  328.     double d;
  329.  
  330.     if (!svform_w || !op || op->type == UNDEFOBJ)
  331.         return;
  332.  
  333.     if (aa_mode && op->s_alt < 0.0) {
  334.         xe_msg ("Object is below the horizon", 1);
  335.         return;
  336.     }
  337.  
  338.     d = raddeg(aa_mode ? op->s_alt : op->s_dec);
  339.     XmScaleSetValue (altdec_w, (int)floor(d + 0.5));
  340.     d = aa_mode ? raddeg(op->s_az) : 10.0*radhr(op->s_ra);
  341.     XmScaleSetValue (azra_w, (int)floor(d + 0.5));
  342.     sv_set_view();
  343.     sv_all(mm_get_now(), 1);
  344.  
  345.     switch (sv_id(op)) {
  346.     case -1: xe_msg ("sv_point: object is below horizon", 0); break;
  347.     case -2: xe_msg ("sv_point: object is outside FOV", 0); break;
  348.     }
  349. }
  350.  
  351. /* show a marker at the location of the given object.
  352.  * return 0 if object was in fact in the field of view;
  353.  *       -1 if in alt/az mode and op is below the horizon now;
  354.  *       -2 if object is otherwise outside the field of view now.
  355.  * N.B. we do *not* update the s_ fields of op.
  356.  */
  357. sv_id (op)
  358. Obj *op;
  359. {
  360.     Display *dsp = XtDisplay (svda_w);
  361.     Window win = XtWindow (svda_w);
  362.     unsigned int wide, h, r, xb, yb;
  363.     double altdec, azra;
  364.     int x, y;
  365.  
  366.     if (!svform_w || !XtIsManaged(svform_w) || !op || op->type == UNDEFOBJ)
  367.         return (-2);
  368.  
  369.     sv_getcircle (&wide, &h, &r, &xb, &yb);
  370.  
  371.     altdec = aa_mode ? op->s_alt : op->s_dec;
  372.     azra   = aa_mode ? op->s_az  : op->s_ra;
  373.     if (!sv_loc (r, altdec, azra, &x, &y))
  374.         return (aa_mode && op->s_alt < 0.0 ? -1 : -2);
  375.  
  376.     x += xb;
  377.     y += yb;
  378.  
  379.     XSetForeground (dsp, sv_gc, fg_p);
  380.     XDrawLine (dsp, win, sv_gc, x-MARKER, y-MARKER, x+MARKER, y+MARKER);
  381.     XDrawLine (dsp, win, sv_gc, x+MARKER, y-MARKER, x-MARKER, y+MARKER);
  382.  
  383.     return (0);
  384. }
  385.  
  386. /* called to put up or remove the watch cursor.  */
  387. void
  388. sv_cursor (c)
  389. Cursor c;
  390. {
  391.     Window win;
  392.  
  393.     if (svform_w && (win = XtWindow(svform_w))) {
  394.         Display *dsp = XtDisplay(svform_w);
  395.         if (c)
  396.         XDefineCursor (dsp, win, c);
  397.         else
  398.         XUndefineCursor (dsp, win);
  399.     }
  400. }
  401.  
  402. /* draw everything subject to any filtering.
  403.  */
  404. /* ARGSUSED */
  405. void
  406. sv_all(np, preclr)
  407. Now *np;
  408. int preclr;
  409. {
  410.     Display *dsp = XtDisplay(svda_w);
  411.     Window win = sv_pm;
  412.     unsigned int w, h, r, xb, yb;
  413.     Obj *op;
  414.  
  415.     watch_cursor(1);
  416.  
  417.     /* put up the timestamp */
  418.     timestamp (np, dt_w);
  419.  
  420.     sv_getcircle (&w, &h, &r, &xb, &yb);
  421.  
  422.     /* rebuild the clean circle */
  423.     XSetForeground (dsp, sv_gc, bg_p);
  424.     XFillRectangle (dsp, win, sv_gc, 0, 0, w, h);
  425.     XSetForeground (dsp, sv_gc, sky_p);
  426.     XFillArc (dsp, win, sv_gc, xb+1, yb+1, 2*r-2, 2*r-2, 0, 360*64);
  427.     XSetForeground (dsp, sv_gc, fg_p);
  428.     XDrawArc (dsp, win, sv_gc, xb, yb, 2*r-1, 2*r-1, 0, 360*64);
  429.  
  430.     /* go through the database and display what we want */
  431.     for (op = db_next(NULL, OBJS_ALL); op; op = db_next(op, OBJS_ALL)) {
  432.         GC gc;
  433.         int x, y;
  434.         obj_pickgc(op, svda_w, &gc);
  435.         if (!sv_dbobjloc(op, r, &x, &y))
  436.         op->o_flags &= ~OBJF_ONSCREEN;
  437.         else {
  438.         /* yup, it's really supposed to be on the screen */
  439.         db_update (op);
  440.         x += xb;
  441.         y += yb;
  442.         sv_draw_obj (dsp, win, gc, op, x, y,
  443.                     magdiam(op->s_mag/MAGSCALE), justdots);
  444.         op->o_flags |= OBJF_ONSCREEN;
  445.         if (all_labels || (op->o_flags & OBJF_LABEL))
  446.             draw_label (dsp, win, gc, op->o_name, x, y);
  447.         }
  448.     }
  449.  
  450.     sv_draw_obj (dsp, win, (GC)0, NULL, 0, 0, 0, 0);    /* flush */
  451.  
  452.     /* go through the trailobj list and display that stuff too. */
  453.     tobj_display_all(r, xb, yb);
  454.  
  455.     /* draw a grid on top if desired */
  456.     if (want_grid) {
  457.         XSetForeground (dsp, sv_gc, fg_p);
  458.         draw_grid(dsp, win, sv_gc, r, xb, yb);
  459.     }
  460.  
  461.     /* and finally draw the ecliptic on top if desired */
  462.     if (want_ecliptic) {
  463.         XSetForeground (dsp, sv_gc, fg_p);
  464.         draw_ecliptic (dsp, win, sv_gc, r, xb, yb);
  465.     }
  466.  
  467.     /* and we're done */
  468.     sv_copy_sky();
  469.  
  470.     watch_cursor(0);
  471. }
  472.  
  473. /* draw the given object so it has a nominal diameter of diam pixels.
  474.  * we maintain a static cache of common X drawing objects for efficiency.
  475.  * (mallocing seemed to keep the memory arena too fragmented).
  476.  * to force a flush, call with op == NULL.
  477.  */
  478. void
  479. sv_draw_obj (dsp, win, gc, op, x, y, diam, dotsonly)
  480. Display *dsp;
  481. Drawable win;
  482. GC gc;
  483. Obj *op;
  484. int x, y;
  485. int diam;
  486. int dotsonly;
  487. {
  488. #define    CACHE_SZ    100
  489. #define    CACHE_PAD    10    /* most we ever need in one call */
  490. #define    CACHE_HWM    (CACHE_SZ - CACHE_PAD)    /* hi water mark */
  491.     static XPoint   xpoints[CACHE_SZ],   *xp  = xpoints;
  492.     static XArc     xdrawarcs[CACHE_SZ], *xda = xdrawarcs;
  493.     static XArc     xfillarcs[CACHE_SZ], *xfa = xfillarcs;
  494.     static XSegment xsegments[CACHE_SZ], *xs  = xsegments;
  495.     static GC cache_gc;
  496.     int force;
  497.     int t;
  498.  
  499.     /* for sure if no op or different gc */
  500.     force = !op || gc != cache_gc;
  501.  
  502.     if (force || xp >= xpoints + CACHE_HWM) {
  503.         int n;
  504.         if ((n = xp - xpoints) > 0) {
  505.         XDrawPoints (dsp, win, cache_gc, xpoints, n, CoordModeOrigin);
  506.         xp = xpoints;
  507. #ifdef SVTRACE
  508.         printf ("points=%d\n", n);
  509. #endif
  510.         }
  511.     }
  512.     if (force || xda >= xdrawarcs + CACHE_HWM) {
  513.         int n;
  514.         if ((n = xda - xdrawarcs) > 0) {
  515.         XDrawArcs (dsp, win, cache_gc, xdrawarcs, n);
  516.         xda = xdrawarcs;
  517. #ifdef SVTRACE
  518.         printf ("drawarcs=%d\n", n);
  519. #endif
  520.         }
  521.     }
  522.     if (force || xfa >= xfillarcs + CACHE_HWM) {
  523.         int n;
  524.         if ((n = xfa - xfillarcs) > 0) {
  525.         XFillArcs (dsp, win, cache_gc, xfillarcs, n);
  526.         xfa = xfillarcs;
  527. #ifdef SVTRACE
  528.         printf ("fillarcs=%d\b", n);
  529. #endif
  530.         }
  531.     }
  532.     if (force || xs >= xsegments + CACHE_HWM) {
  533.         int n;
  534.         if ((n = xs - xsegments) > 0) {
  535.         XDrawSegments (dsp, win, cache_gc, xsegments, n);
  536.         xs = xsegments;
  537. #ifdef SVTRACE
  538.         printf ("segments=%d\n", n);
  539. #endif
  540.         }
  541.     }
  542.  
  543.     cache_gc = gc;
  544.  
  545.     if (!op)
  546.         return;    /* just flushing, thanks */
  547.  
  548.     /* one-pixel wide anything is just a dot */
  549.     if (diam <= 1) {
  550.         xp->x = x;
  551.         xp->y = y;
  552.         xp++;
  553.         return;
  554.     }
  555.  
  556.     /* if dotsonly is on don't use the fancy symbols, just use dots */
  557.     if (dotsonly) {
  558.         xfa->x = x - diam/2;
  559.         xfa->y = y - diam/2;
  560.         xfa->width = diam;
  561.         xfa->height = diam;
  562.         xfa->angle1 = 0;
  563.         xfa->angle2 = 360*64;
  564.         xfa++;
  565.         return;
  566.     }
  567.  
  568.     switch (op->type) {
  569.     case PLANET:
  570.         /* filled circle */
  571.         xfa->x = x - diam/2;
  572.         xfa->y = y - diam/2;
  573.         xfa->width = diam;
  574.         xfa->height = diam;
  575.         xfa->angle1 = 0;
  576.         xfa->angle2 = 360*64;
  577.         xfa++;
  578.         break;
  579.     case FIXED:
  580.         switch (op->f_class) {
  581.         case 'G': case 'H': case 'A': /* galaxy */
  582.         /* filled ellipse */
  583.         xfa->x = x - diam/2;
  584.         xfa->y = y - diam/4;
  585.         xfa->width = diam;
  586.         xfa->height = diam/2;
  587.         xfa->angle1 = 0;
  588.         xfa->angle2 = 360*64;
  589.         xfa++;
  590.         break;
  591.         case 'C': case 'U': /* globular clusters */
  592.         /* same as cluster but with a central dot */
  593.         xfa->x = x - 1;
  594.         xfa->y = y - 1;
  595.         xfa->width = 3;
  596.         xfa->height = 3;
  597.         xfa->angle1 = 0;
  598.         xfa->angle2 = 360*64;
  599.         xfa++;
  600.         /* fall through */
  601.         case 'O': /* open cluster */
  602.         /* open circle of dots */
  603.         xp->x = x;    xp->y = y-3;    xp++;
  604.         xp->x = x+3;    xp->y = y-1;    xp++;
  605.         xp->x = x+3;    xp->y = y+1;    xp++;
  606.         xp->x = x;    xp->y = y+3;    xp++;
  607.         xp->x = x-3;    xp->y = y+1;    xp++;
  608.         xp->x = x-3;    xp->y = y-1;    xp++;
  609.         break;
  610.         case 'P': /* planetary nebula */
  611.         /* open ellipse */
  612.         xda->x = x - diam/2;
  613.         xda->y = y - diam/4;
  614.         xda->width = diam;
  615.         xda->height = diam/2;
  616.         xda->angle1 = 0;
  617.         xda->angle2 = 360*64;
  618.         xda++;
  619.         break;
  620.         case 'S': /* stars */
  621.         /* filled circle */
  622.         xfa->x = x - diam/2;
  623.         xfa->y = y - diam/2;
  624.         xfa->width = diam;
  625.         xfa->height = diam;
  626.         xfa->angle1 = 0;
  627.         xfa->angle2 = 360*64;
  628.         xfa++;
  629.         break;
  630.         case 'B': case 'D': /* binary and double stars */
  631.         /* filled circle with one horizontal line through it */
  632.         xfa->x = x - diam/2;
  633.         xfa->y = y - diam/2;
  634.         xfa->width = diam;
  635.         xfa->height = diam;
  636.         xfa->angle1 = 0;
  637.         xfa->angle2 = 360*64;
  638.         xfa++;
  639.         t = 3*diam/4;
  640.         xs->x1 = x - t;
  641.         xs->y1 = y;
  642.         xs->x2 = x + t;
  643.         xs->y2 = y;
  644.         xs++;
  645.         break;
  646.         case 'M': /* multiple stars */
  647.         /* filled circle with two horizontal lines through it */
  648.         xfa->x = x - diam/2;
  649.         xfa->y = y - diam/2;
  650.         xfa->width = diam;
  651.         xfa->height = diam;
  652.         xfa->angle1 = 0;
  653.         xfa->angle2 = 360*64;
  654.         xfa++;
  655.         t = 3*diam/4;
  656.         xs->x1 = x - t;
  657.         xs->y1 = y - diam/6;
  658.         xs->x2 = x + t;
  659.         xs->y2 = y - diam/6;
  660.         xs++;
  661.         xs->x1 = x - t;
  662.         xs->y1 = y + diam/6;
  663.         xs->x2 = x + t;
  664.         xs->y2 = y + diam/6;
  665.         xs++;
  666.         break;
  667.         case 'V': /* variable star */
  668.         /* central dot with concentric circle */
  669.         xfa->x = x - diam/4;
  670.         xfa->y = y - diam/4;
  671.         xfa->width = diam/2;
  672.         xfa->height = diam/2;
  673.         xfa->angle1 = 0;
  674.         xfa->angle2 = 360*64;
  675.         xfa++;
  676.         xda->x = x - diam/2;
  677.         xda->y = y - diam/2;
  678.         xda->width = diam;
  679.         xda->height = diam;
  680.         xda->angle1 = 0;
  681.         xda->angle2 = 360*64;
  682.         xda++;
  683.         break;
  684.         case 'F': case 'K': /* diffuse and dark nebulea */
  685.         /* open diamond */
  686.         xs->x1 = x-diam/2;    xs->y1 = y;
  687.             xs->x2 = x;            xs->y2 = y-diam/2;    xs++;
  688.         xs->x1 = x;        xs->y1 = y-diam/2;
  689.             xs->x2 = x+diam/2;        xs->y2 = y;        xs++;
  690.         xs->x1 = x+diam/2;    xs->y1 = y;
  691.             xs->x2 = x;            xs->y2 = y+diam/2;    xs++;
  692.         xs->x1 = x;        xs->y1 = y+diam/2;
  693.             xs->x2 = x-diam/2;        xs->y2 = y;        xs++;
  694.         break;
  695.         case 'N': /* bright nebulea */
  696.         /* filled diamond */
  697.         {   XPoint p[5];
  698.             p[0].x = x-diam/2;    p[0].y = y;
  699.             p[1].x = x;        p[1].y = y-diam/2;
  700.             p[2].x = x+diam/2;    p[2].y = y;
  701.             p[3].x = x;        p[3].y = y+diam/2;
  702.             p[4].x = x-diam/2;    p[4].y = y;
  703.             XFillPolygon (dsp, win, gc, p, 5, Convex, CoordModeOrigin);
  704.         }
  705.         break;
  706.         case 'Q': /* Quasar */
  707.         /* plus sign */
  708.         xs->x1 = x-diam/2;    xs->y1 = y;
  709.             xs->x2 = x+diam/2;        xs->y2 = y;        xs++;
  710.         xs->x1 = x;        xs->y1 = y-diam/2;
  711.             xs->x2 = x;            xs->y2 = y+diam/2;    xs++;
  712.         break;
  713.         case 'T':    /* stellar object */
  714.         case '\0':    /* undefined type */
  715.         default:    /* unknown type */
  716.         /* an X */
  717.         xs->x1 = x-diam/3;    xs->y1 = y-diam/3;
  718.             xs->x2 = x+diam/3;        xs->y2 = y+diam/3;    xs++;
  719.         xs->x1 = x-diam/3;    xs->y1 = y+diam/3;
  720.             xs->x2 = x+diam/3;        xs->y2 = y-diam/3;    xs++;
  721.         break;
  722.         }
  723.         break;
  724.     case HYPERBOLIC:
  725.     case PARABOLIC:
  726.         /* usually cometose -- draw a filled circle with tail */
  727.         t = 3*diam/4;
  728.         xfa->x = x - diam/4;
  729.         xfa->y = y - diam/4;
  730.         xfa->width = diam/2;
  731.         xfa->height = diam/2;
  732.         xfa->angle1 = 0;
  733.         xfa->angle2 = 360*64;
  734.         xfa++;
  735.         xfa->x = x - t;
  736.         xfa->y = y - t;
  737.         xfa->width = 2*t;
  738.         xfa->height = 2*t;
  739.         xfa->angle1 = 120*64;
  740.         xfa->angle2 = 30*64;
  741.         xfa++;
  742.         break;
  743.     case ELLIPTICAL:
  744.         /* filled square */
  745.         XFillRectangle (dsp, win, gc, x-diam/2, y-diam/2, diam, diam);
  746.         break;
  747.     }
  748. }
  749.  
  750. /* create the main skyview form */
  751. static void
  752. sv_create_svform()
  753. {
  754.     static struct {
  755.         char *name;
  756.         void (*cb)();
  757.     } cbs[] = {
  758.         {"Filter", sv_filter_cb},
  759.         {"Close", sv_close_cb},
  760.         {"Help", sv_help_cb},
  761.     };
  762.     Widget rc_w;
  763.     Widget w;
  764.     Widget rb_w;
  765.     Widget sep_w;
  766.     Widget ctlfr_w, ctl_w;
  767.     XmString str;
  768.     Arg args[20];
  769.     EventMask mask;
  770.     int i, n;
  771.  
  772.     /* create form */
  773.     n = 0;
  774.     XtSetArg (args[n], XmNautoUnmanage, False); n++;
  775.     XtSetArg (args[n], XmNdefaultPosition, False); n++;
  776.     XtSetArg (args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
  777.     svform_w = XmCreateFormDialog (toplevel_w, "SkyView", args, n);
  778.  
  779.     /* set some stuff in the parent DialogShell.
  780.      * setting XmNdialogTitle in the Form didn't work..
  781.      */
  782.     n = 0;
  783.     XtSetArg (args[n], XmNtitle, "xephem Sky view"); n++;
  784.     XtSetValues (XtParent(svform_w), args, n);
  785.  
  786.     /* make a form across the bottom in a frame for the control buttons */
  787.  
  788.     n = 0;
  789.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  790.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  791.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  792.     ctlfr_w = XmCreateFrame (svform_w, "CtlFr", args, n);
  793.     XtManageChild (ctlfr_w);
  794.  
  795.     n = 0;
  796.     XtSetArg (args[n], XmNfractionBase, 10); n++;
  797.     ctl_w = XmCreateForm (ctlfr_w, "CtlF", args, n);
  798.     XtManageChild (ctl_w);
  799.  
  800.         /* make the control buttons */
  801.  
  802.         for (i = 0; i < XtNumber(cbs); i++) {
  803.         n = 0;
  804.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  805.         XtSetArg (args[n], XmNtopOffset, 10); n++;
  806.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  807.         XtSetArg (args[n], XmNbottomOffset, 10); n++;
  808.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  809.         XtSetArg (args[n], XmNleftPosition, 1+i*3); n++;
  810.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  811.         XtSetArg (args[n], XmNrightPosition, 3+i*3); n++;
  812.         w = XmCreatePushButton (ctl_w, cbs[i].name, args, n);
  813.         XtAddCallback (w, XmNactivateCallback, cbs[i].cb, 0);
  814.         XtManageChild (w);
  815.         }
  816.  
  817.     /* make a RowColumn down the left side for the misc controls */
  818.  
  819.     n = 0;
  820.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  821.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  822.     XtSetArg (args[n], XmNbottomWidget, ctlfr_w); n++;
  823.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  824.     XtSetArg (args[n], XmNisAligned, False); n++;
  825.     XtSetArg (args[n], XmNadjustMargin, False); n++;
  826.     rc_w = XmCreateRowColumn (svform_w, "SVRC", args, n);
  827.     XtManageChild (rc_w);
  828.  
  829.         /* make the radio box for alt/az vs ra/dec */
  830.  
  831.         n = 0;
  832.         rb_w = XmCreateRadioBox (rc_w, "SVModeRB", args, n);
  833.         XtManageChild (rb_w);
  834.  
  835.         str = XmStringCreate ("Alt-Az", XmSTRING_DEFAULT_CHARSET);
  836.         n = 0;
  837.         XtSetArg (args[n], XmNlabelString, str); n++;
  838.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  839.         aa_w = XmCreateToggleButton (rb_w, "AltAzMode", args, n);
  840.         XtAddCallback (aa_w, XmNvalueChangedCallback, sv_aa_cb, NULL);
  841.         XtManageChild (aa_w);
  842.         XmStringFree (str);
  843.  
  844.         str = XmStringCreate ("RA-Dec", XmSTRING_DEFAULT_CHARSET);
  845.         n = 0;
  846.         XtSetArg (args[n], XmNlabelString, str); n++;
  847.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  848.         rad_w = XmCreateToggleButton(rb_w, "RADecMode", args, n);
  849.         XtManageChild (rad_w);
  850.         XmStringFree (str);
  851.  
  852.         if(XmToggleButtonGetState(aa_w)==XmToggleButtonGetState(rad_w)){
  853.             xe_msg("Sky View display mode conflicts -- using Alt/Az",0);
  854.             aa_mode = 1;    /* default to aa if they conflict */
  855.             XmToggleButtonSetState (aa_w, aa_mode, False); 
  856.             XmToggleButtonSetState (rad_w, !aa_mode, False); 
  857.         }
  858.         aa_mode = XmToggleButtonGetState(aa_w);
  859.  
  860.         n = 0;
  861.         w = XmCreateSeparator (rc_w, "RCSep1", args, n);
  862.         XtManageChild (w);
  863.  
  864.         /* make the "grid" toggle button and calibration labels */
  865.  
  866.         n = 0;
  867.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  868.         w = XmCreateToggleButton (rc_w, "Grid", args, n);
  869.         XtAddCallback (w, XmNvalueChangedCallback, sv_grid_cb, 0);
  870.         XtManageChild (w);
  871.  
  872.         n = 0;
  873.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  874.         vgrid_w = XmCreateLabel (rc_w, "SVGridV", args, n);
  875.         set_xmstring (vgrid_w, XmNlabelString, null_grid_str);
  876.         XtManageChild (vgrid_w);
  877.  
  878.         n = 0;
  879.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  880.         hgrid_w = XmCreateLabel (rc_w, "SVGridH", args, n);
  881.         set_xmstring (hgrid_w, XmNlabelString, null_grid_str);
  882.         XtManageChild (hgrid_w);
  883.  
  884.         n = 0;
  885.         w = XmCreateSeparator (rc_w, "RCSep2", args, n);
  886.         XtManageChild (w);
  887.  
  888.         /* make the faint magnitude slider scale */
  889.  
  890.         str = XmStringCreate ("Faintest Mag", XmSTRING_DEFAULT_CHARSET);
  891.         n = 0;
  892.         XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
  893.         XtSetArg (args[n], XmNminimum, BMAGLIMIT); n++;
  894.         XtSetArg (args[n], XmNmaximum, FMAGLIMIT); n++;
  895.         XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_LEFT); n++;
  896.         XtSetArg (args[n], XmNscaleMultiple, 1); n++;
  897.         XtSetArg (args[n], XmNshowValue, True); n++;
  898.         XtSetArg (args[n], XmNtitleString, str); n++;
  899.         fmag_w = XmCreateScale (rc_w, "FaintMagScale", args, n);
  900.         XtAddCallback(fmag_w, XmNvalueChangedCallback, sv_changed_cb, NULL);
  901.         XtAddCallback(fmag_w, XmNdragCallback, sv_magdrag_cb, NULL);
  902.         XtManageChild (fmag_w);
  903.         XmStringFree (str);
  904.  
  905.         /* make the bright magnitude slider scale */
  906.  
  907.         str = XmStringCreate ("Brightest Mag", XmSTRING_DEFAULT_CHARSET);
  908.         n = 0;
  909.         XtSetArg (args[n], XmNorientation, XmHORIZONTAL); n++;
  910.         XtSetArg (args[n], XmNminimum, BMAGLIMIT); n++;
  911.         XtSetArg (args[n], XmNmaximum, FMAGLIMIT); n++;
  912.         XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_LEFT); n++;
  913.         XtSetArg (args[n], XmNscaleMultiple, 1); n++;
  914.         XtSetArg (args[n], XmNshowValue, True); n++;
  915.         XtSetArg (args[n], XmNtitleString, str); n++;
  916.         bmag_w = XmCreateScale (rc_w, "BrightMagScale", args, n);
  917.         XtAddCallback(bmag_w, XmNvalueChangedCallback, sv_changed_cb, NULL);
  918.         XtAddCallback(bmag_w, XmNdragCallback, sv_magdrag_cb, NULL);
  919.         XtManageChild (bmag_w);
  920.         XmStringFree (str);
  921.  
  922.         n = 0;
  923.         w = XmCreateSeparator (rc_w, "RCSep3", args, n);
  924.         XtManageChild (w);
  925.  
  926.         /* make the "just dots" toggle button */
  927.  
  928.         str = XmStringCreate ("Just Dots", XmSTRING_DEFAULT_CHARSET);
  929.         n = 0;
  930.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  931.         XtSetArg (args[n], XmNlabelString, str); n++;
  932.         w = XmCreateToggleButton (rc_w, "JustDots", args, n);
  933.         XtAddCallback (w, XmNvalueChangedCallback, sv_justdots_cb, NULL);
  934.         XtManageChild (w);
  935.         justdots = XmToggleButtonGetState (w);
  936.         XmStringFree(str);
  937.  
  938.         /* make the "ecliptic" toggle button */
  939.  
  940.         str = XmStringCreate ("Ecliptic", XmSTRING_DEFAULT_CHARSET);
  941.         n = 0;
  942.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  943.         XtSetArg (args[n], XmNlabelString, str); n++;
  944.         w = XmCreateToggleButton (rc_w, "Ecliptic", args, n);
  945.         XtAddCallback (w, XmNvalueChangedCallback, sv_ecliptic_cb, NULL);
  946.         XtManageChild (w);
  947.         want_ecliptic = XmToggleButtonGetState (w);
  948.         XmStringFree(str);
  949.  
  950.         /* make the "All labels" toggle button */
  951.  
  952.         str = XmStringCreate ("All labels", XmSTRING_DEFAULT_CHARSET);
  953.         n = 0;
  954.         XtSetArg (args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
  955.         XtSetArg (args[n], XmNlabelString, str); n++;
  956.         w = XmCreateToggleButton (rc_w, "AllLabels", args, n);
  957.         XtAddCallback (w, XmNvalueChangedCallback, sv_all_labels_cb, NULL);
  958.         XtManageChild (w);
  959.         all_labels = XmToggleButtonGetState (w);
  960.         XmStringFree(str);
  961.  
  962.         n = 0;
  963.         w = XmCreateSeparator (rc_w, "RCSep4", args, n);
  964.         XtManageChild (w);
  965.  
  966.         /* make the "find" cascade button */
  967.         sv_create_find (rc_w);
  968.  
  969.     /* make a vertical sep to the right of the left row/col */
  970.  
  971.     n = 0;
  972.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  973.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  974.     XtSetArg (args[n], XmNbottomWidget, ctlfr_w); n++;
  975.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  976.     XtSetArg (args[n], XmNleftWidget, rc_w); n++;
  977.     XtSetArg (args[n], XmNorientation, XmVERTICAL); n++;
  978.     sep_w = XmCreateSeparator (svform_w, "Sep1", args, n);
  979.     XtManageChild(sep_w);
  980.  
  981.     /* make a timestamp label just above the control panel's frame */
  982.  
  983.     n = 0;
  984.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  985.     XtSetArg (args[n], XmNleftWidget, sep_w); n++;
  986.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  987.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  988.     XtSetArg (args[n], XmNbottomWidget, ctlfr_w); n++;
  989.     XtSetArg (args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
  990.     dt_w = XmCreateLabel (svform_w, "TimeStamp", args, n);
  991.     XtManageChild(dt_w);
  992.  
  993.     /* make the bottom scale above the time stamp */
  994.  
  995.     n = 0;
  996.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  997.     XtSetArg (args[n], XmNleftWidget, sep_w); n++;
  998.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  999.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  1000.     XtSetArg (args[n], XmNbottomWidget, dt_w); n++;
  1001.