home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part13 / satmenu.c < prev   
Encoding:
C/C++ Source or Header  |  1993-05-15  |  35.9 KB  |  1,318 lines

  1. /* code to manage the stuff on the "saturn" menu.
  2.  */
  3.  
  4. #include <stdio.h>
  5. #include <ctype.h>
  6. #include <math.h>
  7. #if defined(__STDC__)
  8. #include <stdlib.h>
  9. #endif
  10. #include <X11/Xlib.h>
  11. #include <Xm/Xm.h>
  12. #include <Xm/Form.h>
  13. #include <Xm/Frame.h>
  14. #include <Xm/Label.h>
  15. #include <Xm/PushB.h>
  16. #include <Xm/Scale.h>
  17. #include <Xm/RowColumn.h>
  18. #include <Xm/DrawingA.h>
  19. #include <Xm/ToggleB.h>
  20. #include "astro.h"
  21. #include "circum.h"
  22.  
  23. #if defined(__STDC__) || defined(__cplusplus)
  24. #define P_(s) s
  25. #else
  26. #define P_(s) ()
  27. #endif
  28.  
  29. extern Now *mm_get_now P_((void));
  30. extern int any_ison P_((void));
  31. extern void f_double P_((Widget w, char *fmt, double f));
  32. extern void get_something P_((Widget w, char *resource, char *value));
  33. extern void register_selection P_((char *name));
  34. extern void set_xmstring P_((Widget w, char *resource, char *txt));
  35. extern void timestamp P_((Now *np, Widget w));
  36.  
  37. void sm_manage P_((void));
  38. int sm_ison P_((void));
  39. void sm_selection_mode P_((int whether));
  40. void sm_cursor P_((Cursor c));
  41. static void sm_create_form_w P_((void));
  42. static void sm_set_buttons P_((int whether));
  43. static void sm_set_a_button P_((Widget pbw, int whether));
  44. static void sm_bigd_cb P_((Widget w, XtPointer client, XtPointer call));
  45. static void sm_tags_cb P_((Widget w, XtPointer client, XtPointer call));
  46. static void sm_scale_cb P_((Widget w, XtPointer client, XtPointer call));
  47. static void sm_activate_cb P_((Widget w, XtPointer client, XtPointer call));
  48. static void sm_close_cb P_((Widget w, XtPointer client, XtPointer call));
  49. static void sm_da_exp_cb P_((Widget w, XtPointer client, XtPointer call));
  50. void sm_update P_((Now *np, int how_much));
  51. static double polynom P_((double jd, double a[4]));
  52. static void saturn P_((double jd, double L_, double a_, double e_, double i_, double omega_, double Omega_, double M_, double *r_p, double *l_p, double *b_p, double *C_p));
  53. static void anom_calc P_((double M, double e, double *E_p, double *nu_p));
  54. static double obl_jd P_((double jd));
  55.  
  56. #undef P_
  57.  
  58. extern Widget toplevel_w;
  59. #define    XtD    XtDisplay(toplevel_w)
  60.  
  61. static Widget satform_w;    /* main form */
  62. static Widget sda_w;        /* drawing area */
  63. static Widget ringt_w;        /* widget containing ring tilt */
  64. static Widget scale_w;        /* size scale */
  65. static Widget dt_w;        /* date/time stamp widget */
  66. #define    NM    8        /* number of moons */
  67. static Widget    s_w[NM][4];    /* the data display widgets */
  68. enum {X, Y, Z, MAG};        /* s_w column index */
  69. static int sm_selecting;    /* set while our fields are being selected */
  70. static int bigdots;        /* whether we want big dots */
  71. static int s_tags;        /* whether we want tags on the drawing */
  72.  
  73. #define    MAXSCALE    20.0    /* max sclae mag factor */
  74.  
  75. static struct MoonNames {
  76.     char *full;
  77.     char *tag;
  78. } mnames[NM] = {
  79.     {"Mimas",    "I"},
  80.     {"Enceladus","II"},
  81.     {"Tethys",    "III"},
  82.     {"Dione",    "IV"},
  83.     {"Rhea",    "V"},
  84.     {"Titan",    "VI"},
  85.     {"Hyperion","VII"},
  86.     {"Iapetus",    "VIII"},
  87. };
  88.  
  89. /* called when the saturn menu is activated via the main menu pulldown.
  90.  * if never called before, create and manage all the widgets as a child of a
  91.  * form. otherwise, just toggle whether the form is managed.
  92.  */
  93. void
  94. sm_manage ()
  95. {
  96.     if (!satform_w)
  97.         sm_create_form_w();
  98.     
  99.     if (XtIsManaged(satform_w))
  100.         XtUnmanageChild (satform_w);
  101.     else {
  102.         XtManageChild (satform_w);
  103.         sm_set_buttons(sm_selecting);
  104.         /* rely on expose to do the first draw */
  105.     }
  106. }
  107.  
  108. sm_ison()
  109. {
  110.     return (satform_w && XtIsManaged(satform_w));
  111. }
  112.  
  113. /* called by other menus as they want to hear from our buttons or not.
  114.  * the "on"s and "off"s stack - only really redo the buttons if it's the
  115.  * first on or the last off.
  116.  */
  117. void
  118. sm_selection_mode (whether)
  119. int whether;    /* whether setting up for plotting or for not plotting */
  120. {
  121.     sm_selecting += whether ? 1 : -1;
  122.  
  123.     if (satform_w && XtIsManaged(satform_w))
  124.         if (whether && sm_selecting == 1     /* first one to want on */
  125.         || !whether && sm_selecting == 0 /* last one to want off */)
  126.         sm_set_buttons (whether);
  127. }
  128.  
  129. /* called to put up or remove the watch cursor.  */
  130. void
  131. sm_cursor (c)
  132. Cursor c;
  133. {
  134.     Window win;
  135.  
  136.     if (satform_w && (win = XtWindow(satform_w))) {
  137.         Display *dsp = XtDisplay(satform_w);
  138.         if (c)
  139.         XDefineCursor (dsp, win, c);
  140.         else
  141.         XUndefineCursor (dsp, win);
  142.     }
  143. }
  144.  
  145. static void
  146. sm_create_form_w()
  147. {
  148.     Widget w;
  149.     Widget f_w, fr_w, frame_w, r_w, title_w, col_w;
  150.     XmString str;
  151.     Arg args[20];
  152.     int n;
  153.     int i;
  154.  
  155.     /* create form */
  156.     n = 0;
  157.     XtSetArg (args[n], XmNautoUnmanage, False); n++;
  158.     XtSetArg (args[n], XmNdefaultPosition, False); n++;
  159.     XtSetArg (args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
  160.     satform_w = XmCreateFormDialog (toplevel_w, "Saturn", args, n);
  161.  
  162.     /* set some stuff in the parent DialogShell.
  163.      * setting XmNdialogTitle in the Form didn't work..
  164.      */
  165.     n = 0;
  166.     XtSetArg (args[n], XmNtitle, "xephem Saturn Table"); n++;
  167.     XtSetValues (XtParent(satform_w), args, n);
  168.  
  169.     /* make top row for ring tilt info */
  170.  
  171.     n = 0;
  172.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  173.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  174.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  175.     XtSetArg (args[n], XmNrightPosition, 50); n++;
  176.     r_w = XmCreatePushButton (satform_w, "SatTiltMsg", args, n);
  177.     XtManageChild (r_w);
  178.     set_xmstring (r_w, XmNlabelString, "Ring tilt (degs):");
  179.     sm_set_a_button (r_w, False);
  180.  
  181.     n = 0;
  182.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  183.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  184.     XtSetArg (args[n], XmNleftPosition, 50); n++;
  185.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  186.     XtSetArg (args[n], XmNuserData, "Saturn.Tilt"); n++;
  187.     w = ringt_w = XmCreatePushButton(satform_w, "SatTilt", args, n);
  188.     XtAddCallback(w, XmNactivateCallback, sm_activate_cb, 0);
  189.     XtManageChild (w);
  190.  
  191.     /* make table title label */
  192.  
  193.     n = 0;
  194.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  195.     XtSetArg (args[n], XmNtopWidget, r_w); n++;
  196.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  197.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  198.     title_w = XmCreateLabel (satform_w, "SatLab", args, n);
  199.     XtManageChild (title_w);
  200.     set_xmstring (title_w, XmNlabelString,
  201.                 " \nMoon positions -- in Saturn Radii");
  202.  
  203.     /* make the moon table, one column at a time */
  204.  
  205.     /* moon designator column */
  206.  
  207.     n = 0;
  208.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  209.     XtSetArg (args[n], XmNtopWidget, title_w); n++;
  210.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  211.     XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_BEGINNING); n++;
  212.     XtSetArg (args[n], XmNisAligned, True); n++;
  213.     col_w = XmCreateRowColumn (satform_w, "SatDes", args, n);
  214.     XtManageChild (col_w);
  215.  
  216.         n = 0;
  217.         w = XmCreatePushButton (col_w, " ", args, n);
  218.         XtManageChild (w);
  219.         sm_set_a_button (w, False);
  220.  
  221.         for (i = 0; i < NM; i++) {
  222.         n = 0;
  223.         w = XmCreatePushButton (col_w, mnames[i].tag, args, n);
  224.         XtManageChild (w);
  225.         sm_set_a_button (w, False);
  226.         }
  227.  
  228.     /* moon name column */
  229.  
  230.     n = 0;
  231.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  232.     XtSetArg (args[n], XmNtopWidget, title_w); n++;
  233.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  234.     XtSetArg (args[n], XmNleftPosition, 8); n++;
  235.     XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_BEGINNING); n++;
  236.     XtSetArg (args[n], XmNisAligned, True); n++;
  237.     col_w = XmCreateRowColumn (satform_w, "SatName", args, n);
  238.     XtManageChild (col_w);
  239.  
  240.         n = 0;
  241.         w = XmCreatePushButton (col_w, " ", args, n);
  242.         XtManageChild (w);
  243.         sm_set_a_button (w, False);
  244.  
  245.         for (i = 0; i < NM; i++) {
  246.         n = 0;
  247.         w = XmCreatePushButton (col_w, mnames[i].full, args, n);
  248.         XtManageChild (w);
  249.         sm_set_a_button (w, False);
  250.         }
  251.  
  252.     /* moon X column */
  253.  
  254.     n = 0;
  255.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  256.     XtSetArg (args[n], XmNtopWidget, title_w); n++;
  257.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  258.     XtSetArg (args[n], XmNleftPosition, 30); n++;
  259.     XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
  260.     XtSetArg (args[n], XmNisAligned, True); n++;
  261.     col_w = XmCreateRowColumn (satform_w, "SatX", args, n);
  262.     XtManageChild (col_w);
  263.  
  264.         n = 0;
  265.         w = XmCreatePushButton (col_w, "SatLab", args, n);
  266.         XtManageChild (w);
  267.         sm_set_a_button (w, False);
  268.         set_xmstring (w, XmNlabelString, "X (+E)");
  269.  
  270.         for (i = 0; i < NM; i++) {
  271.         char *sel;
  272.         sel = XtMalloc (strlen(mnames[i].full) + 3); /* '.X\0' */
  273.         (void) sprintf (sel, "%s.X", mnames[i].full);
  274.         n = 0;
  275.         XtSetArg (args[n], XmNuserData, sel); n++;
  276.         w = s_w[i][X] = XmCreatePushButton(col_w, "SatPB", args, n);
  277.         XtAddCallback(w, XmNactivateCallback, sm_activate_cb, 0);
  278.         XtManageChild (w);
  279.         }
  280.  
  281.     /* moon Y column */
  282.  
  283.     n = 0;
  284.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  285.     XtSetArg (args[n], XmNtopWidget, title_w); n++;
  286.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  287.     XtSetArg (args[n], XmNleftPosition, 50); n++;
  288.     XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
  289.     XtSetArg (args[n], XmNisAligned, True); n++;
  290.     col_w = XmCreateRowColumn (satform_w, "SatY", args, n);
  291.     XtManageChild (col_w);
  292.  
  293.         n = 0;
  294.         w = XmCreatePushButton (col_w, "SatLab", args, n);
  295.         XtManageChild (w);
  296.         sm_set_a_button (w, False);
  297.         set_xmstring (w, XmNlabelString, "Y (+S)");
  298.  
  299.         for (i = 0; i < NM; i++) {
  300.         char *sel;
  301.         sel = XtMalloc (strlen(mnames[i].full) + 3); /* '.Y\0' */
  302.         (void) sprintf (sel, "%s.Y", mnames[i].full);
  303.         n = 0;
  304.         XtSetArg (args[n], XmNuserData, sel); n++;
  305.         w = s_w[i][Y] = XmCreatePushButton(col_w, "SatPB", args, n);
  306.         XtAddCallback(w, XmNactivateCallback, sm_activate_cb, 0);
  307.         XtManageChild (w);
  308.         }
  309.  
  310.     /* moon Z column */
  311.  
  312.     n = 0;
  313.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  314.     XtSetArg (args[n], XmNtopWidget, title_w); n++;
  315.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  316.     XtSetArg (args[n], XmNleftPosition, 70); n++;
  317.     XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
  318.     XtSetArg (args[n], XmNisAligned, True); n++;
  319.     col_w = XmCreateRowColumn (satform_w, "SatZ", args, n);
  320.     XtManageChild (col_w);
  321.  
  322.         n = 0;
  323.         w = XmCreatePushButton (col_w, "SatLab", args, n);
  324.         XtManageChild (w);
  325.         sm_set_a_button (w, False);
  326.         set_xmstring (w, XmNlabelString, "Z (+front)");
  327.  
  328.         for (i = 0; i < NM; i++) {
  329.         char *sel;
  330.         sel = XtMalloc (strlen(mnames[i].full) + 3); /* '.Z\0' */
  331.         (void) sprintf (sel, "%s.Z", mnames[i].full);
  332.         n = 0;
  333.         XtSetArg (args[n], XmNuserData, sel); n++;
  334.         w = s_w[i][Z] = XmCreatePushButton(col_w, "SatPB", args, n);
  335.         XtAddCallback(w, XmNactivateCallback, sm_activate_cb, 0);
  336.         XtManageChild (w);
  337.         }
  338.  
  339.     /* moon mag column */
  340.  
  341.     n = 0;
  342.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  343.     XtSetArg (args[n], XmNtopWidget, title_w); n++;
  344.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  345.     XtSetArg (args[n], XmNleftPosition, 90); n++;
  346.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  347.     XtSetArg (args[n], XmNentryAlignment, XmALIGNMENT_CENTER); n++;
  348.     XtSetArg (args[n], XmNisAligned, True); n++;
  349.     col_w = XmCreateRowColumn (satform_w, "SatMag", args, n);
  350.     XtManageChild (col_w);
  351.  
  352.         n = 0;
  353.         w = XmCreatePushButton (col_w, "SatLab", args, n);
  354.         XtManageChild (w);
  355.         sm_set_a_button (w, False);
  356.         set_xmstring (w, XmNlabelString, "Mag");
  357.  
  358.         for (i = 0; i < NM; i++) {
  359.         char *sel;
  360.         sel = XtMalloc (strlen(mnames[i].full) + 5); /* '.Mag\0' */
  361.         (void) sprintf (sel, "%s.Mag", mnames[i].full);
  362.         n = 0;
  363.         XtSetArg (args[n], XmNuserData, sel); n++;
  364.         w = s_w[i][MAG] = XmCreatePushButton(col_w, "SatPB",args,n);
  365.         XtAddCallback(w, XmNactivateCallback, sm_activate_cb, 0);
  366.         XtManageChild (w);
  367.         }
  368.  
  369.     /* make a Form to hold the bottom controls */
  370.  
  371.     n = 0;
  372.     XtSetArg (args[n], XmNfractionBase, 15); n++;
  373.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  374.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  375.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  376.     f_w = XmCreateForm (satform_w, "CtlForm", args, n);
  377.     XtManageChild (f_w);
  378.  
  379.         /* make the close button */
  380.  
  381.         n = 0;
  382.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  383.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  384.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  385.         XtSetArg (args[n], XmNleftPosition, 1); n++;
  386.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  387.         XtSetArg (args[n], XmNrightPosition, 4); n++;
  388.         w = XmCreatePushButton (f_w, "Close", args, n);
  389.         XtAddCallback (w, XmNactivateCallback, sm_close_cb, 0);
  390.         XtManageChild (w);
  391.  
  392.         /* make the tags button in a frame */
  393.  
  394.         n = 0;
  395.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  396.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  397.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  398.         XtSetArg (args[n], XmNleftPosition, 6); n++;
  399.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  400.         XtSetArg (args[n], XmNrightPosition, 9); n++;
  401.         fr_w = XmCreateFrame (f_w, "TagsFr", args, n);
  402.         XtManageChild (fr_w);
  403.         w = XmCreateToggleButton (fr_w, "Tags", args, n);
  404.         XtAddCallback (w, XmNvalueChangedCallback, sm_tags_cb, 0);
  405.         XtManageChild (w);
  406.         s_tags = XmToggleButtonGetState(w);
  407.  
  408.         /* "big dots" toggle button in a frame */
  409.  
  410.         n = 0;
  411.         XtSetArg (args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  412.         XtSetArg (args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  413.         XtSetArg (args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  414.         XtSetArg (args[n], XmNleftPosition, 11); n++;
  415.         XtSetArg (args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  416.         XtSetArg (args[n], XmNrightPosition, 14); n++;
  417.         fr_w = XmCreateFrame(f_w,"BigDotsFr", args, n);
  418.         XtManageChild (fr_w);
  419.         str = XmStringCreate("Big dots", XmSTRING_DEFAULT_CHARSET);
  420.         n = 0;
  421.         XtSetArg (args[n], XmNlabelString, str); n++;
  422.         w = XmCreateToggleButton(fr_w,"BigDots",args,n);
  423.         XtAddCallback(w, XmNvalueChangedCallback, sm_bigd_cb, 0);
  424.         XtManageChild (w);
  425.         XmStringFree (str);
  426.         bigdots = XmToggleButtonGetState(w);
  427.  
  428.     /* make the date/time stamp label */
  429.  
  430.     n = 0;
  431.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  432.     XtSetArg (args[n], XmNbottomWidget, f_w); n++;
  433.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  434.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  435.     dt_w = XmCreateLabel (satform_w, "DateStamp", args, n);
  436.     timestamp (mm_get_now(), dt_w);    /* establishes size */
  437.     XtManageChild (dt_w);
  438.  
  439.     /* make the scale widget
  440.      * attach both top and bottom so it's the one to follow resizing.
  441.      */
  442.  
  443.     n = 0;
  444.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  445.     XtSetArg (args[n], XmNtopWidget, col_w); n++;
  446.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  447.     XtSetArg (args[n], XmNbottomWidget, dt_w); n++;
  448.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  449.     XtSetArg (args[n], XmNmaximum, 100); n++;
  450.     XtSetArg (args[n], XmNminimum, 0); n++;
  451.     XtSetArg (args[n], XmNscaleMultiple, 10); n++;
  452.     XtSetArg (args[n], XmNorientation, XmVERTICAL); n++;
  453.     XtSetArg (args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
  454.     scale_w = XmCreateScale (satform_w, "Scale", args, n);
  455.     XtAddCallback (scale_w, XmNdragCallback, sm_scale_cb, 0);
  456.     XtAddCallback (scale_w, XmNvalueChangedCallback, sm_scale_cb, 0);
  457.     XtManageChild (scale_w);
  458.  
  459.     /* make a frame for the drawing area.
  460.      * attach both top and bottom so it's the one to follow resizing.
  461.      */
  462.  
  463.     n = 0;
  464.     XtSetArg (args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  465.     XtSetArg (args[n], XmNtopWidget, col_w); n++;
  466.     XtSetArg (args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  467.     XtSetArg (args[n], XmNbottomWidget, dt_w); n++;
  468.     XtSetArg (args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
  469.     XtSetArg (args[n], XmNleftWidget, scale_w); n++;
  470.     XtSetArg (args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  471.     XtSetArg (args[n], XmNshadowType, XmSHADOW_ETCHED_OUT); n++;
  472.     frame_w = XmCreateFrame (satform_w, "SatFrame", args, n);
  473.     XtManageChild (frame_w);
  474.  
  475.         /* make a drawing area for drawing the little map */
  476.  
  477.         n = 0;
  478.         sda_w = XmCreateDrawingArea (frame_w, "Map", args, n);
  479.         XtAddCallback (sda_w, XmNexposeCallback, sm_da_exp_cb, 0);
  480.         XtManageChild (sda_w);
  481. }
  482.  
  483. /* go through all the buttons pickable for plotting and set whether they
  484.  * should appear to look like buttons or just flat labels.
  485.  */
  486. static void
  487. sm_set_buttons (whether)
  488. int whether;    /* whether setting up for plotting or for not plotting */
  489. {
  490.     int i;
  491.  
  492.     for (i = 0; i < NM; i++) {
  493.         sm_set_a_button (s_w[i][X], whether);
  494.         sm_set_a_button (s_w[i][Y], whether);
  495.         sm_set_a_button (s_w[i][Z], whether);
  496.         sm_set_a_button (s_w[i][MAG], whether);
  497.     }
  498.     sm_set_a_button (ringt_w, whether);
  499. }
  500.  
  501. /* set whether the given button looks like a label.
  502.  */
  503. static void
  504. sm_set_a_button(pbw, whether)
  505. Widget pbw;
  506. int whether;
  507. {
  508.     static Arg look_like_button[] = {
  509.         {XmNtopShadowColor, (XtArgVal) 0},
  510.         {XmNbottomShadowColor, (XtArgVal) 0},
  511.         {XmNfillOnArm, (XtArgVal) True},
  512.     };
  513.     static Arg look_like_label[] = {
  514.         {XmNtopShadowColor, (XtArgVal) 0},
  515.         {XmNbottomShadowColor, (XtArgVal) 0},
  516.         {XmNfillOnArm, (XtArgVal) False},
  517.     };
  518.     static int called;
  519.     Arg *ap;
  520.     int na;
  521.  
  522.     if (!called) {
  523.         /* get baseline label and shadow appearances.
  524.          */
  525.         Pixel topshad, botshad, bgcol;
  526.         Arg args[20];
  527.         Widget tmpw;
  528.         int n;
  529.  
  530.         n = 0;
  531.         tmpw = XmCreatePushButton (satform_w, "tmp", args, n);
  532.  
  533.         n = 0;
  534.         XtSetArg (args[n], XmNtopShadowColor, &topshad); n++;
  535.         XtSetArg (args[n], XmNbottomShadowColor, &botshad); n++;
  536.         XtSetArg (args[n], XmNbackground, &bgcol); n++;
  537.         XtGetValues (tmpw, args, n);
  538.  
  539.         look_like_button[0].value = topshad;
  540.         look_like_button[1].value = botshad;
  541.         look_like_label[0].value = bgcol;
  542.         look_like_label[1].value = bgcol;
  543.  
  544.         XtDestroyWidget (tmpw);
  545.          
  546.         called = 1;
  547.     }
  548.  
  549.     if (whether) {
  550.         ap = look_like_button;
  551.         na = XtNumber(look_like_button);
  552.     } else {
  553.         ap = look_like_label;
  554.         na = XtNumber(look_like_label);
  555.     }
  556.  
  557.     XtSetValues (pbw, ap, na);
  558. }
  559.  
  560. /* callback from the big dots toggle button
  561.  * TODO: really shouldn't get present time, just redo dots in same location.
  562.  */
  563. /* ARGSUSED */
  564. static void
  565. sm_bigd_cb (w, client, call)
  566. Widget w;
  567. XtPointer client;
  568. XtPointer call;
  569. {
  570.     bigdots = XmToggleButtonGetState(w);
  571.     sm_update (mm_get_now(), 1);
  572. }
  573.  
  574. /* callback from the tags toggle button
  575.  * TODO: really shouldn't get present time, just redo dots in same location.
  576.  */
  577. /* ARGSUSED */
  578. static void
  579. sm_tags_cb (w, client, call)
  580. Widget w;
  581. XtPointer client;
  582. XtPointer call;
  583. {
  584.     s_tags = XmToggleButtonGetState(w);
  585.     sm_update (mm_get_now(), 1);
  586. }
  587.  
  588. /* callback from the scale.
  589.  * TODO: really shouldn't get present time, just redo dots in same location.
  590.  */
  591. /* ARGSUSED */
  592. static void
  593. sm_scale_cb (w, client, call)
  594. Widget w;
  595. XtPointer client;
  596. XtPointer call;
  597. {
  598.     sm_update (mm_get_now(), 1);
  599. }
  600.  
  601. /* callback from any of the data menu buttons being activated.
  602.  */
  603. /* ARGSUSED */
  604. static void
  605. sm_activate_cb (w, client, call)
  606. Widget w;
  607. XtPointer client;
  608. XtPointer call;
  609. {
  610.     if (sm_selecting) {
  611.         char *name;
  612.         get_something (w, XmNuserData, (char *)&name);
  613.         register_selection (name);
  614.     }
  615. }
  616.  
  617. /* callback from the Close button
  618.  */
  619. /* ARGSUSED */
  620. static void
  621. sm_close_cb (w, client, call)
  622. Widget w;
  623. XtPointer client;
  624. XtPointer call;
  625. {
  626.     XtUnmanageChild (satform_w);
  627. }
  628.  
  629. /* callback from either expose or resize of the drawing area.
  630.  */
  631. /* ARGSUSED */
  632. static void
  633. sm_da_exp_cb (w, client, call)
  634. Widget w;
  635. XtPointer client;
  636. XtPointer call;
  637. {
  638.     XmDrawingAreaCallbackStruct *c = (XmDrawingAreaCallbackStruct *)call;
  639.  
  640.     /* filter out a few oddball cases */
  641.     switch (c->reason) {
  642.     case XmCR_EXPOSE: {
  643.         /* turn off gravity so we get expose events for either shrink or
  644.          * expand.
  645.          */
  646.         static before;
  647.         XExposeEvent *e = &c->event->xexpose;
  648.  
  649.         if (!before) {
  650.         XSetWindowAttributes swa;
  651.         swa.bit_gravity = ForgetGravity;
  652.         XChangeWindowAttributes (e->display, e->window, 
  653.                                 CWBitGravity, &swa);
  654.         before = 1;
  655.         }
  656.         /* wait for the last in the series */
  657.         if (e->count != 0)
  658.         return;
  659.         break;
  660.         }
  661.     default:
  662.         printf ("Unexpected satform_w event. type=%d\n", c->reason);
  663.         exit(1);
  664.     }
  665.  
  666.     sm_update (mm_get_now(), 1);
  667. }
  668.  
  669. /* computional support for saturn's detail menu.
  670.  * courtesy Craig Counterman.
  671.  */
  672.  
  673. typedef struct {
  674.   double alpha, delta;        /* position in equinox of date */
  675.   double l, b;            /* ecliptical longitude and latitude */
  676.   double lambda, beta;        /* geocentric longitude and latitude */
  677.   double Cen;            /* Center */
  678.   double psi;            /* elongation */
  679.   double r, Delta;        /* Distance to sun, and earth */
  680.   double mag, phase, size;    /* magnitude, phase (degrees) size (arcsec) */
  681.   double illum_frac;        /* illuminated fraction of disk */
  682.   double beta_e;
  683.                 /* beta_e, p_n, lambda_e */
  684. } planet_data_t;
  685.  
  686.  
  687. typedef struct {
  688.   char *name;
  689.   double alpha, delta;        /* position in equinox of date */
  690.   double R, Theta;        /* Distance to earth, Theta equinox of date */
  691.                 /* times of these events */
  692. } sun_data_t;
  693.  
  694. typedef struct {
  695.   double dx, dy, dz;        /* relative to planet,
  696.                    units of equatorial radius */
  697.   double dalpha, ddelta;    /* displacements in RA and dec. */
  698.   double mag;
  699.   char *name;
  700. } sat_t;
  701.  
  702. /* functions */
  703. static void anom_calc();
  704. static void planet_pos(), sun_pos();
  705. static double obl_jd();
  706. static void satsat();
  707. static void sm_draw_map();
  708. static double into_range();
  709.  
  710.  
  711. /* called to recompute and fill in values for the saturn menu.
  712.  * don't bother if it doesn't exist or is unmanaged now or no one is logging.
  713.  */
  714. void
  715. sm_update (np, how_much)
  716. Now *np;
  717. int how_much;
  718. {
  719.     static char fmt[] = "%7.3f";
  720.         double jd;
  721.         sat_t  saturnsats[8];
  722.         planet_data_t planets;
  723.         sun_data_t sun_data;
  724.     int i;
  725.  
  726.     if (!satform_w)
  727.         return;
  728.     if (!XtIsManaged(satform_w) && !any_ison() && !how_much)
  729.         return;
  730.  
  731.         jd = mjd + MJD0;
  732.     sun_pos(jd, &sun_data);
  733.     planet_pos(jd, sun_data, 4, &planets);
  734.         satsat(jd, planets, saturnsats);
  735.  
  736.     for (i = 0; i < NM; i++) {
  737.         f_double (s_w[i][X], fmt, -saturnsats[i].dx);
  738.         f_double (s_w[i][Y], fmt, -saturnsats[i].dy);
  739.         f_double (s_w[i][Z], fmt, saturnsats[i].dz);
  740.         f_double (s_w[i][MAG], "%5.1f", saturnsats[i].mag);
  741.     }
  742.  
  743.     f_double (ringt_w, fmt, planets.beta_e);
  744.  
  745.     if (XtIsManaged(satform_w)) {
  746.         sm_draw_map (sda_w, saturnsats, planets.beta_e);
  747.         timestamp (np, dt_w);
  748.     }
  749. }
  750.  
  751. /* given the loc of the moons, draw a nifty little picture.
  752.  * scale of the locations is in terms of saturn radii == 1.
  753.  */
  754. static void
  755. sm_draw_map (w, moons, tilt)
  756. Widget w;
  757. sat_t moons[NM];
  758. double tilt;    /* degrees */
  759. {
  760.     static GC s_fgc, s_bgc, s_xgc;
  761.     static XFontStruct *s_fs;
  762.     static last_nx, last_ny;
  763.     static int cw, ch;
  764.     static Pixmap pm;
  765.     Display *dsp = XtDisplay(w);
  766.     Window win = XtWindow(w);
  767.     Window root;
  768.     double scale;
  769.     int sv;
  770.     char c;
  771.     int x, y;
  772.     unsigned int nx, ny, bw, d;
  773.     int irw, orw, irh, orh, irx, iry, orx, ory;
  774.     int i;
  775. #define    RLW    3    /* ring line width, pixels */
  776. #define    NORM    60.0    /* max Iapetus orbit radius; used to normalize */
  777. #define    MAPSCALE(v)    ((v)*((int)nx)/NORM/2*scale)
  778. #define    XCORD(x)    ((int)(((int)nx)/2.0 + MAPSCALE(x) + 0.5))
  779. #define    YCORD(y)    ((int)(((int)ny)/2.0 - MAPSCALE(y) + 0.5))
  780.  
  781.     if (!s_fgc) {
  782.         XGCValues gcv;
  783.         unsigned int gcm;
  784.         Pixel fg, bg;
  785.  
  786.         gcm = GCForeground;
  787.         get_something (w, XmNforeground, (char *)&fg);
  788.         gcv.foreground = fg;
  789.         s_fgc = XCreateGC (dsp, win, gcm, &gcv);
  790.         s_fs = XQueryFont (dsp, XGContextFromGC (s_fgc));
  791.         cw = s_fs->max_bounds.width;
  792.         ch = s_fs->max_bounds.ascent + s_fs->max_bounds.descent;
  793.  
  794.         gcm = GCForeground;
  795.         get_something (w, XmNbackground, (char *)&bg);
  796.         gcv.foreground = bg;
  797.         s_bgc = XCreateGC (dsp, win, gcm, &gcv);
  798.  
  799.         gcm = GCForeground | GCFunction;
  800.         gcv.foreground = fg ^ bg;
  801.         gcv.function = GXxor;
  802.         s_xgc = XCreateGC (dsp, win, gcm, &gcv);
  803.     }
  804.  
  805.     XmScaleGetValue (scale_w, &sv);
  806.     scale = pow(MAXSCALE, sv/100.0);
  807.  
  808.     XGetGeometry(dsp, win, &root, &x, &y, &nx, &ny, &bw, &d);
  809.     if (!pm || nx != last_nx || ny != last_ny) {
  810.         if (pm)
  811.         XFreePixmap (dsp, pm);
  812.         pm = XCreatePixmap (dsp, win, nx, ny, d);
  813.         last_nx = nx;
  814.         last_ny = ny;
  815.     }
  816.  
  817.     XFillRectangle (dsp, pm, s_bgc, 0, 0, nx, ny);
  818.  
  819.     c = 'E'; XDrawString(dsp, pm, s_fgc, nx-cw-1, ny/2-2, &c, 1);
  820.     c = 'S'; XDrawString(dsp, pm, s_fgc, (nx-cw)/2-1, s_fs->ascent, &c, 1);
  821.  
  822.     /* draw Saturn of radius 1 */
  823.     XFillArc (dsp, pm, s_fgc, XCORD(-1), YCORD(1), 2*(int)MAPSCALE(1),
  824.                         2*(int)MAPSCALE(1), 0, 360*64);
  825.     
  826.     /* rings of radius IRR and ORR.
  827.      * draw rings in front of planet using xor.
  828.      * positive tilt means the southern edge of the rings are in front.
  829.      * always draw the solid s_fgc last in case we are near the ring plane.
  830.      */
  831. #define    IRR    1.528    /* inner edge of ring system */
  832. #define    ORR    2.267    /* outter edge of A ring */
  833.     irh = MAPSCALE(2*IRR*fabs(sin(degrad(tilt))));
  834.     irw = (int)MAPSCALE(2*IRR);
  835.     orh = MAPSCALE(2*ORR*fabs(sin(degrad(tilt))));
  836.     orw = (int)MAPSCALE(2*ORR);
  837.     irx = XCORD(-IRR);
  838.     iry = YCORD(IRR*fabs(sin(degrad(tilt))));
  839.     orx = XCORD(-ORR);
  840.     ory = YCORD(ORR*fabs(sin(degrad(tilt))));
  841.     if (irh < RLW || orh < RLW) {
  842.         /* too near the ring plane to draw a fill ellipse */
  843.         XDrawLine (dsp, pm, s_fgc, orx, ny/2, nx-orx, ny/2);
  844.     } else {
  845.         XDrawArc (dsp, pm, s_xgc, irx, iry, irw, irh,
  846.                     tilt > 0.0 ? 0 : 180*64, 180*64-1);
  847.         XDrawArc (dsp, pm, s_xgc, orx, ory, orw, orh,
  848.                     tilt > 0.0 ? 0 : 180*64, 180*64-1);
  849.         XDrawArc (dsp, pm, s_fgc, irx, iry, irw, irh,
  850.                     tilt > 0.0 ? 180*64 : 0, 180*64-1);
  851.         XDrawArc (dsp, pm, s_fgc, orx, ory, orw, orh,
  852.                     tilt > 0.0 ? 180*64 : 0, 180*64-1);
  853.     }
  854.  
  855.     /* draw each moon that is visible.
  856.      */
  857.     for (i = 0; i < NM; i++) {
  858.         double mx = -moons[i].dx;
  859.         double my = -moons[i].dy;
  860.         double mz =  moons[i].dz;
  861.         int outside = mx*mx + my*my > 1.0;
  862.         int infront = mz > 0.0;
  863.  
  864.         if (!outside && !infront)
  865.         continue;    /* behind saturn */
  866.  
  867.         x = XCORD(mx);
  868.         y = YCORD(my);
  869.         XDrawPoint (dsp, pm, s_xgc, x, y);
  870.         if (bigdots) {
  871.         XDrawPoint(dsp,pm, s_xgc, x+1, y);
  872.         XDrawPoint(dsp,pm, s_xgc, x,   y+1);
  873.         XDrawPoint(dsp,pm, s_xgc, x+1, y+1);
  874.         }
  875.         if (s_tags)
  876.         XDrawString(dsp, pm, s_xgc, x-cw/2, y+2*ch,
  877.                     mnames[i].tag, strlen(mnames[i].tag));
  878.     }
  879.  
  880.     XCopyArea (dsp, pm, win, s_fgc, 0, 0, nx, ny, 0, 0);
  881. }
  882.  
  883.  
  884. /* the following is from starchart */
  885.  
  886. #define DEG_TO_RAD 0.01745329251994329600
  887. #define RAD_TO_DEG 57.29577951308232
  888. #define DSIN(x) (sin((x)*DEG_TO_RAD))
  889. #define DCOS(x) (cos((x)*DEG_TO_RAD))
  890. #define DTAN(x) (tan((x)*DEG_TO_RAD))
  891. #define DASIN(x) (asin(x)*RAD_TO_DEG)
  892. #define DACOS(x) (acos(x)*RAD_TO_DEG)
  893. #define DATAN(x) (atan(x)*RAD_TO_DEG)
  894. #define DATAN2(x,y) (atan2(x,y)*RAD_TO_DEG)
  895.  
  896. /* siderial Periods of satellites:
  897.  0.942421813
  898.  1.370217855
  899.  1.887802160
  900.  2.736914742
  901.  4.517500436
  902. 15.94542068
  903. 21.2766088
  904. 79.3301825
  905.  
  906. synodic (approx)
  907.  0.94250436287643326
  908.  1.3703923657888438
  909.  1.8881334260185879
  910.  2.7376110810451278
  911.  4.519397869256954
  912.  15.969085530060568
  913.  21.318764097751611
  914.  79.919403771981642
  915.  
  916. semimajor axes
  917. 185.52
  918. 238.02
  919. 294.66
  920. 377.40
  921. 527.04
  922. 1221.83
  923. 1481.1
  924. 3561.3
  925. */
  926.  
  927. static struct {
  928.   double off; /* angle of satellite at jd 2415020.0 */
  929.   double angvel; /* anbular velocity, degrees per day */
  930.   double r; /* Distance to saturn in saturn radii */
  931.   double mag; /* V(1,0) */
  932.   char *name; /* Name */
  933. } satsat_data[] = {
  934.   {49.0, 381.96109660576467, 3.092, 3.3, "Mimas"},
  935.   {98.7, 262.69848620527883, 3.967, 2.1, "Enceladus"},
  936.   {263.0, 190.66449173515979, 4.911, 0.6, "Tethys"},
  937.   {101.3, 131.50151330574105, 6.290, 0.8, "Dione"},
  938.   {11.2, 79.656629138338852, 8.784, 0.1, "Rhea"},
  939.   {183.7, 22.543557633424146, 20.364, -1.28, "Titan"},
  940.   {95.0, 16.886532368823739, 24.685, 4.63, "Hyperion"},
  941.   {338.4, 4.5045381097576426, 59.355, 1.5, "Iapetus"}
  942. };
  943.  
  944. /* given jd, return sat_t list of major satellites of Saturn */
  945. /* Ignore many corrections to Saturn's orbit,
  946.    assume moons in circular orbits in Saturn's equatorial plane */
  947. static void
  948. satsat(jd, saturn, sats)
  949.      double jd;
  950.      planet_data_t saturn;
  951.      sat_t sats[8];
  952. {
  953.   double d;            /* modified julian date */
  954.   double B;            /* Center of saturn */
  955.   double Delta;            /* Distance from earth to Saturn */
  956.   double psi;            /* Phase angle */
  957.   double u[8];            /* angle */
  958.   double X[8];            /* relative Positions (radii) */
  959.   double Y[8];            /* relative Positions (radii) */
  960.   double Z[8];            /* relative Positions (radii) */
  961.   double dmag;
  962.   int i;
  963.  
  964.   d = jd - MJD0;
  965.  
  966.   Delta = saturn.Delta;
  967.   psi = saturn.phase;
  968.   B = saturn.Cen;
  969.  
  970.  
  971.   dmag = 5.0 * log10(saturn.r*saturn.Delta)
  972.     - 2.5 * log10(saturn.illum_frac);
  973.  
  974.   for (i = 0; i < 8; i++) {
  975.     u[i] = satsat_data[i].off
  976.       + satsat_data[i].angvel * (d - Delta * 0.00577167643528) + psi - B;
  977.     u[i] = into_range(u[i]);
  978.  
  979.     X[i] = satsat_data[i].r * DSIN(u[i]);
  980.     Z[i] = satsat_data[i].r * DCOS(u[i]);
  981.     Y[i] = - satsat_data[i].r * DCOS(u[i]) * DSIN(saturn.beta_e);
  982.  
  983.     sats[i].dx = X[i];
  984.     sats[i].dy = Y[i];
  985.     sats[i].dz = Z[i];
  986.     sats[i].name = satsat_data[i].name;
  987.     sats[i].mag = satsat_data[i].mag + dmag;
  988.   };
  989. }
  990.  
  991. typedef struct {
  992.   double L[4];
  993.   double a;
  994.   double e[4];
  995.   double i[4];
  996.   double omega[4];
  997.   double Omega[4];
  998.   double size_1au;
  999.   double mag0;
  1000. } pelements;
  1001.  
  1002. static pelements peles = {
  1003.  
  1004.     /* Saturn */
  1005.     {266.564377, 1223.509884, 0.0003245, -0.0000058},
  1006.     9.554747,
  1007.     {0.05589232, -0.00034550, -0.000000728, 0.00000000074},
  1008.     {2.492519, -0.0039189, -0.00001549, 0.00000004},
  1009.     {338.307800, 1.0852207, 0.00097854, 0.00000992},
  1010.     {112.790414, 0.8731951, -0.00015218, -0.00000531},
  1011.     165.6,
  1012.     -8.88
  1013.     
  1014. };
  1015.  
  1016. typedef struct {
  1017.   double alpha_1, delta_1;
  1018.   double W_0, W_dot;
  1019. } rot_els_t;
  1020. static rot_els_t rot_els = {
  1021.     40.09, 83.49,
  1022.     223.60, 810.79390
  1023. };
  1024.  
  1025. static double polynom(jd, a)
  1026.      double jd;
  1027.      double a[4];
  1028. {
  1029.   double T;
  1030.  
  1031.   T = (jd - MJD0)/36525.0;
  1032.  
  1033.   return (a[0] + a[1]*T + a[2]*T*T + a[3]*T*T*T);
  1034. }
  1035.  
  1036. static void  saturn();
  1037.  
  1038.  
  1039. /* Calculate alpha and delta
  1040.    from lambda and beta (and epsilon)
  1041.    which are from r, Delta, psi, b, l, and Theta (in sun_data)
  1042.    which are from u, i (given), and Omega (given)
  1043.    u is from L (given), nu, and M
  1044.    nu and M are calculated.
  1045.    r is from E, a (given) and e (given)
  1046.    E is calculated
  1047.  
  1048.    calculate mag from Delta, size form Delta, phase (== beta).
  1049.  */
  1050.  
  1051. /* ARGSUSED */
  1052. static void
  1053. planet_pos(jd, sun_data, nplanet, data)
  1054.      double jd;            /* time, jd */
  1055.      sun_data_t sun_data;
  1056.      planet_data_t *data;
  1057. {
  1058.   double L_, a_, e_, i_, omega_, Omega_, M_;
  1059.   double r;            /* radius distance to sun */
  1060.   double l, b;            /* ecliptical longitude and latitude */
  1061.   double Delta;            /* Distance to earth */
  1062.   double lambda, beta;        /* geocentric longitude and latitude */
  1063.   double alpha, delta;        /* R.A. and dec. both degrees */
  1064.   double psi;            /* elongation */
  1065.   double N, D;            /* temporary variables */
  1066.   double Theta;            /* Theta of the sun */
  1067.   double epsilon;        /* obliquity */
  1068.   double Cen;            /* center */
  1069.  
  1070.   L_ = into_range(polynom(jd, peles.L));
  1071.   a_ = peles.a;
  1072.   e_ = polynom(jd, peles.e);
  1073.   i_ = polynom(jd, peles.i);
  1074.   omega_ = into_range(polynom(jd, peles.omega));
  1075.   Omega_ = into_range(polynom(jd, peles.Omega));
  1076.   M_ = into_range(L_ - omega_ - Omega_);
  1077.  
  1078.   /* Perturb */
  1079.     saturn(jd, L_, a_, e_, i_, omega_, Omega_, M_, &r, &l, &b, &Cen);
  1080.  
  1081.   Theta = sun_data.Theta;
  1082.   N = r * DCOS(b) * DSIN(l - Theta);
  1083.   D = r * DCOS(b) * DCOS(l - Theta) + sun_data.R;
  1084.  
  1085.   epsilon = obl_jd(jd);
  1086.  
  1087.   lambda = into_range(RAD_TO_DEG * atan2(N, D)) + Theta;
  1088.   Delta = sqrt(N*N + D*D + (r * DSIN(b))*(r * DSIN(b)));
  1089.   beta = RAD_TO_DEG * asin(r * DSIN(b) / Delta);
  1090.   psi = RAD_TO_DEG * acos(DCOS(beta) * DCOS(lambda - Theta));
  1091.   if (into_range(lambda - Theta) > 180.0)
  1092.     psi = -psi;
  1093.   alpha = RAD_TO_DEG * atan2(DSIN(lambda)*DCOS(epsilon)
  1094.                  - DTAN(beta) * DSIN(epsilon),
  1095.                  DCOS(lambda));
  1096.   delta = RAD_TO_DEG * asin(DSIN(beta)*DCOS(epsilon)
  1097.                 + DCOS(beta)*DSIN(epsilon)*DSIN(lambda));
  1098.   alpha = into_range(alpha);
  1099.  
  1100. /* should correct for nutation and aberration */
  1101.   data->alpha = alpha;
  1102.   data->delta = delta;
  1103.   data->l = l;
  1104.   data->b = b;
  1105.   data->lambda = lambda;
  1106.   data->beta = beta;
  1107.   data->psi = psi;
  1108.   data->phase =
  1109.     DACOS((r*r + Delta*Delta - sun_data.R*sun_data.R) / (2*r*Delta));
  1110.   if (psi < 0) data->phase = -data->phase;
  1111.   data->r = r;
  1112.   data->Delta = Delta;
  1113.   data->illum_frac = ((r+Delta)*(r+Delta) - sun_data.R*sun_data.R)/(4*r*Delta);
  1114.   data->Cen = Cen;
  1115.  
  1116.   data->mag = 5.0 * log10(r*Delta)
  1117.     - 2.5 * log10(data->illum_frac)
  1118.     + peles.mag0;
  1119.  
  1120.   data->size = peles.size_1au / Delta;
  1121.  
  1122.   data->beta_e =
  1123.     DASIN(-DSIN(rot_els.delta_1)*DSIN(delta)
  1124.       - DCOS(rot_els.delta_1) * DCOS(delta)
  1125.           * DCOS(rot_els.alpha_1 - alpha));
  1126.  
  1127.  
  1128. }
  1129.  
  1130. static void saturn(jd, L_, a_, e_, i_, omega_, Omega_, M_, r_p, l_p, b_p, C_p)
  1131. double jd, L_, a_, e_, i_, omega_, Omega_, M_;
  1132. double *r_p, *l_p, *b_p, *C_p;
  1133. {
  1134.   double E, nu;
  1135.   double r, l, b;
  1136.  
  1137.   double u;            /* argument of latitude */
  1138.   double T;
  1139.   double A, B, e_pert, a_pert, b_pert, v, zeta;
  1140.   double P, Q, V;
  1141.   double Szeta, S2zeta, Dzeta, D2zeta,
  1142.                  DQ, SQ, D2Q, S2Q;
  1143.  
  1144.   /* for perturbations */
  1145.   T = (jd - MJD0)/36525.0;
  1146.  
  1147.   v = T/5.0 + 0.1;
  1148.   P = 237.47555 +3034.9061*T;
  1149.   Q = 265.91650 + 1222.1139*T;
  1150.   V = 5.0*Q -2.0*P;
  1151.   zeta = Q - P;
  1152.  
  1153.   Szeta = DSIN(zeta);
  1154.   S2zeta = DSIN(2*zeta);
  1155.   Dzeta = DCOS(zeta);
  1156.   D2zeta = DCOS(2*zeta);
  1157.   DQ = DCOS(Q);
  1158.   D2Q = DCOS(2*Q);
  1159.   SQ = DSIN(Q);
  1160.   S2Q = DSIN(2*Q);
  1161.   A = (-0.814181 + 0.018150*v + 0.016714*v*v)*DSIN(V)
  1162.     +(-0.010497 + 0.160906*v - 0.004100*v*v)*DCOS(V);
  1163.   A +=        -0.040786*S2zeta
  1164.   + ( (0.008931 + 0.002728*v)*Szeta )*SQ;
  1165.  
  1166.  
  1167.   A +=      ((0.081344 )*Dzeta+
  1168.         0.015019*D2zeta)*SQ;
  1169.   A +=          ((0.085581 + 0.002494*v)*Szeta
  1170.         +(0.025328 - 0.003117*v)*Dzeta
  1171.       )*DQ;
  1172.  
  1173.  
  1174.   e_pert = (-.0007927 + .0002548*v +.0000091*v*v)*DSIN(V)
  1175.     +(.0013381 + .0001226*v -.0000253*v*v)*DCOS(V)
  1176.       ;
  1177.   e_pert +=         .0012415*SQ;
  1178.   e_pert +=  (
  1179.               .0026599*Dzeta)*SQ;
  1180.   e_pert +=         (
  1181.           -.0012696*Szeta
  1182. )*DQ;
  1183.  
  1184.  
  1185.  
  1186.   B = (0.077108 + 0.007186*v - 0.001533*v*v)*DSIN(V)
  1187.     +(0.045803 - 0.014766*v - 0.000536*v*v)*DCOS(V);
  1188.   B +=  
  1189.     (-0.075825*Szeta
  1190.       -0.024839*S2zeta
  1191.           )*SQ;
  1192.   B +=          (-0.072586
  1193.           -0.150383*Dzeta
  1194.           +0.026897*D2zeta
  1195.             )*DQ;
  1196.   B += (-(0.013597 +0.001719*v)*Szeta
  1197.  )*S2Q;
  1198.   B +=     ( (-0.013667 + 0.001239*v)*Szeta
  1199.           +0.011981*S2zeta
  1200.           +(0.014861 + 0.001136*v)*Dzeta
  1201.           -(0.013064 + 0.001628*v)*D2zeta)*D2Q;
  1202.  
  1203.   a_pert =  .033629*Dzeta 
  1204.     -.003081*D2zeta ;
  1205.   a_pert += (.001098 
  1206.       -.002812*Szeta 
  1207.          +.002138*Dzeta
  1208.           )*SQ;
  1209.   a_pert +=    ( -.000890
  1210.           +.002206*Szeta)*DQ;
  1211.   L_ += A;
  1212.   M_ += A - B / e_;
  1213.   e_ += e_pert;
  1214.   a_ += a_pert;
  1215.   omega_ += B;
  1216.  
  1217.   /* Calculate E and nu */
  1218.   anom_calc(M_, e_, &E, &nu);
  1219.   r = a_ * (1 - e_ * DCOS(E));
  1220.  
  1221.  
  1222.   u = L_ + nu - M_ - Omega_;
  1223.   *C_p = nu - M_;
  1224.   l = into_range(RAD_TO_DEG * atan2(DCOS(i_) * DSIN(u), DCOS(u)) + Omega_);
  1225.   b = RAD_TO_DEG * asin(DSIN(u)*DSIN(i_));
  1226.  
  1227.   b_pert = 0.000747*Dzeta*SQ
  1228.       +0.001069*Dzeta*DQ
  1229.     +0.002108*S2zeta*S2Q;
  1230.   b_pert += 0.001261*D2zeta*S2Q
  1231.         +0.001236*S2zeta*D2Q
  1232.           -0.002075*D2zeta*D2Q;
  1233.  
  1234.   *r_p = r;
  1235.   *l_p = l;
  1236.   *b_p = b + b_pert;
  1237. }
  1238.  
  1239. static void anom_calc(M, e, E_p, nu_p)
  1240.      double M, e, *E_p, *nu_p;
  1241. {
  1242.   double corr, e_0, E_0, E_1;
  1243.  
  1244.   e_0 = e * RAD_TO_DEG;
  1245.  
  1246.   corr = 1;
  1247.   E_0 = M;
  1248.   while (corr > 0.00001) {
  1249.     corr = (M + e_0 * DSIN(E_0) - E_0)/(1 - e * DCOS(E_0));
  1250.     E_1 = E_0 + corr;
  1251.     if (corr < 0) corr *= -1.0;
  1252.     E_0 = E_1;
  1253.   };
  1254.     
  1255.   *E_p = E_1;
  1256.  
  1257.   *nu_p = 2.0 * RAD_TO_DEG * atan(sqrt((1+e)/(1-e))*DTAN(E_1/2));
  1258. }
  1259.  
  1260.  
  1261.  
  1262.  
  1263. /* Obliquity epsilon 
  1264. epsilon = 23.439291 - 0.0130042* T - 0.00000016* T*T - 0.000000504* T*T*T;
  1265. */
  1266. static double
  1267. obl_jd(jd)
  1268. double jd;
  1269. {
  1270.   double T = (jd - 2451545.0)/36525.0;
  1271.  
  1272.   return (23.439291 - 0.0130042* T - 0.00000016* T*T - 0.000000504* T*T*T);
  1273. }
  1274.  
  1275.  
  1276.  
  1277. static double
  1278. into_range(ang)
  1279. double ang;
  1280. {
  1281.   long i;
  1282.  
  1283.   i = (long)floor(ang/360.0);
  1284.  
  1285.   ang = ang - i * 360;
  1286.  
  1287.   return(ang);
  1288. }  
  1289.   
  1290. static void
  1291. sun_pos(jd, sun_data)
  1292.      double jd;
  1293.      sun_data_t *sun_data;
  1294. {
  1295.   double L, M, Theta, R;
  1296.   double e, nu, E;
  1297.   double T;
  1298.   double epsilon;
  1299.  
  1300.   T =  (jd - MJD0)/36525.0;
  1301.  
  1302.   M = into_range(358.47583 + 35999.04975*T - 0.000150*T*T - 0.0000033*T*T*T);
  1303.   e = 0.01675104 - 0.0000418*T - 0.000000126*T*T;
  1304.   L = into_range(279.69668 + 36000.76892*T + 0.0003025*T*T);
  1305.   anom_calc(M, e, &E, &nu);
  1306.   Theta = into_range(L + nu - M);
  1307.   R = 1.0000002*(1.0 - e * DCOS(E));
  1308.  
  1309.  
  1310.   sun_data->R = R;
  1311.   sun_data->Theta = Theta;
  1312.   epsilon = 23.439291 - 0.0130042* T - 0.00000016* T*T - 0.000000504* T*T*T;
  1313.   sun_data->alpha
  1314.     = into_range(RAD_TO_DEG * atan2(DCOS(epsilon)*DSIN(Theta), DCOS(Theta)));
  1315.   sun_data->delta = 
  1316.     RAD_TO_DEG * asin(DSIN(epsilon)*DSIN(Theta));
  1317. }
  1318.