home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / astrnomy / ephem421.zip / PLOT.C < prev    next >
C/C++ Source or Header  |  1990-09-13  |  12KB  |  436 lines

  1. /* code to support the plotting capabilities.
  2.  * idea is to let the operator name a plot file and mark some fields for
  3.  * logging. then after each screen update, the logged fields are written to
  4.  * the plot file. later, the file may be plotted (very simplistically by 
  5.  * ephem, for now anyway, or by some other program entirely.).
  6.  * 
  7.  * format of the plot file is one line per coordinate: label,x,y
  8.  * if z was specified, it is a fourth field.
  9.  * x,y,z are plotted using %g format.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include "screen.h"
  15.  
  16. extern char *strcpy();
  17. extern errno;
  18. extern char *sys_errlist[];
  19. #define    errsys    (sys_errlist[errno])
  20.  
  21. #define    TRACE(x)    {FILE *fp = fopen("trace","a"); fprintf x; fclose(fp);}
  22.  
  23. #define    MAXPLTLINES    10    /* max number of labeled lines we can track.
  24.                  * note we can't store more than NFLOGS fields
  25.                  * anyway (see flog.c).
  26.                  */
  27. #define    FNLEN        (14+1)    /* longest filename; plus 1 for \0 */
  28.  
  29. static char plt_filename[FNLEN] = "ephem.plt";    /* default plot file name */
  30. static FILE *plt_fp;        /* the plot file; == 0 means don't plot */
  31.  
  32. /* store the label and rcfpack()s for each line to track. */
  33. typedef struct {
  34.     char pl_label;
  35.     int pl_rcpx, pl_rcpy, pl_rcpz;
  36. } PltLine;
  37. static PltLine pltlines[MAXPLTLINES];
  38. static int npltlines;        /* number of pltlines[] in actual use */
  39.  
  40. static int plt_in_polar;    /*if true plot in polar coords, else cartesian*/
  41. static int pltsrchfld;        /* set when the Search field is to be plotted */
  42.  
  43. /* picked the Plot label:
  44.  * if on, just turn it off.
  45.  * if off, turn on, define fields or select name of file to plot and do it.
  46.  * TODO: more flexibility, more relevance.
  47.  */
  48. plot_setup()
  49. {
  50.     if (plt_fp)
  51.         plt_turn_off();
  52.     else {
  53.         static char *chcs[4] = {
  54.         "Select fields", "Display a plot file", (char *)0,
  55.         "Begin plotting"
  56.         };
  57.         static int fn;    /* start with 0, then remember for next time */
  58.     ask:
  59.         chcs[2] = plt_in_polar ? "Polar coords" : "Cartesian coords";
  60.         switch (popup(chcs, fn, npltlines > 0 ? 4 : 3)) {
  61.         case 0: fn = 0; plt_select_fields(); goto ask;
  62.         case 1: fn = 1; plt_file(); goto ask;
  63.         case 2: fn = 2; plt_in_polar ^= 1; goto ask;
  64.         case 3: fn = 3; plt_turn_on(); break;
  65.         default: break;
  66.         }
  67.     }
  68. }
  69.  
  70. /* write the active plotfields to the current plot file, if one is open. */
  71. plot()
  72. {
  73.     if (plt_fp) {
  74.         PltLine *plp;
  75.         double x, y, z;
  76.         if (!srch_ison() && pltsrchfld) {
  77.         /* if searching is not on but we are plotting the search
  78.          * funtion we must evaluate and log it ourselves here and now.
  79.          * plt_turn_on() insured there is a good function to eval.
  80.          * N.B. if searching IS on, we rely on main() having called
  81.          * srch_eval() BEFORE plot() so it is already evaluated.
  82.          */
  83.         double e;
  84.         char errmsg[128];
  85.         if (execute_expr (&e, errmsg) < 0) {
  86.             f_msg (errmsg);
  87.             plt_turn_off();
  88.             return;
  89.         } else
  90.             (void) flog_log (R_SRCH, C_SRCH, e, "");
  91.         }
  92.         /* plot in order of original selection */
  93.         for (plp = pltlines; plp < &pltlines[npltlines]; plp++) {
  94.         if (flog_get (plp->pl_rcpx, &x, (char *)0) == 0 
  95.             && flog_get (plp->pl_rcpy, &y, (char *)0) == 0) {
  96.             (void) fprintf (plt_fp, "%c,%.12g,%.12g", plp->pl_label,
  97.                                     x, y);
  98.             if (flog_get (plp->pl_rcpz, &z, (char *)0) == 0)
  99.             (void) fprintf (plt_fp, ",%.12g", z);
  100.             (void) fprintf (plt_fp, "\n");
  101.         }
  102.         }
  103.     }
  104. }
  105.  
  106. plot_prstate (force)
  107. int force;
  108. {
  109.     static last;
  110.     int this = plt_fp != 0;
  111.  
  112.     if (force || this != last) {
  113.         f_string (R_PLOT, C_PLOTV, this ? " on" : "off");
  114.         last = this;
  115.     }
  116. }
  117.  
  118. plot_ison()
  119. {
  120.     return (plt_fp != 0);
  121. }
  122.  
  123. static
  124. plt_reset()
  125. {
  126.     PltLine *plp;
  127.  
  128.     for (plp = &pltlines[npltlines]; --plp >= pltlines; ) {
  129.         (void) flog_delete (plp->pl_rcpx);
  130.         (void) flog_delete (plp->pl_rcpy);
  131.         (void) flog_delete (plp->pl_rcpz);
  132.         plp->pl_rcpx = plp->pl_rcpy = plp->pl_rcpz = 0;
  133.     }
  134.     npltlines = 0;
  135.     pltsrchfld = 0;
  136. }
  137.  
  138. /* let operator select the fields he wants to plot.
  139.  * register them with flog and keep rcfpack() in pltlines[] array.
  140.  * as a special case, set pltsrchfld if Search field is selected.
  141.  */
  142. static
  143. plt_select_fields()
  144. {
  145.     static char hlp[] = "move and RETURN to select a field, or q to quit";
  146.     static char sry[] = "Sorry; can not log any more fields.";
  147.     int r = R_UT, c = C_UTV; /* TODO: start where main was? */
  148.     int sf = rcfpack (R_SRCH, C_SRCH, 0);
  149.     char buf[64];
  150.     int rcp;
  151.     int i;
  152.  
  153.     plt_reset();
  154.     for (i = 0; i < MAXPLTLINES; i++) {
  155.         (void) sprintf (buf, "select x field for line %d", i+1);
  156.         rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp);
  157.         if (!rcp)
  158.         break;
  159.         if (flog_add (rcp) < 0) {
  160.         f_msg (sry);
  161.         break;
  162.         }
  163.         pltlines[i].pl_rcpx = rcp;
  164.         if (rcp == sf)
  165.         pltsrchfld = 1;
  166.  
  167.         (void) sprintf (buf, "select y field for line %d", i+1);
  168.         r = unpackr (rcp); c = unpackc (rcp);
  169.         rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp);
  170.         if (!rcp) {
  171.         (void) flog_delete (pltlines[i].pl_rcpx);
  172.         break;
  173.         }
  174.         if (flog_add (rcp) < 0) {
  175.         (void) flog_delete (pltlines[i].pl_rcpx);
  176.         f_msg (sry);
  177.         break;
  178.         }
  179.         pltlines[i].pl_rcpy = rcp;
  180.         if (rcp == sf)
  181.         pltsrchfld = 1;
  182.  
  183.         (void) sprintf (buf, "select z field for line %d", i+1);
  184.         r = unpackr (rcp); c = unpackc (rcp);
  185.         rcp = sel_fld (r, c, alt_menumask()|F_PLT, buf, hlp);
  186.         if (rcp) {
  187.         if (flog_add (rcp) < 0) {
  188.             (void) flog_delete (pltlines[i].pl_rcpx);
  189.             (void) flog_delete (pltlines[i].pl_rcpy);
  190.             f_msg (sry);
  191.             break;
  192.         }
  193.         pltlines[i].pl_rcpz = rcp;
  194.         if (rcp == sf)
  195.             pltsrchfld = 1;
  196.         r = unpackr (rcp); c = unpackc (rcp);
  197.         }
  198.  
  199.         do {
  200.         (void) sprintf(buf,"enter a one-character label for line %d: ",
  201.                                     i+1);
  202.         f_prompt (buf);
  203.         } while (read_line (buf, 1) != 1);
  204.         pltlines[i].pl_label = *buf;
  205.     }
  206.     npltlines = i;
  207. }
  208.  
  209. static
  210. plt_turn_off ()
  211. {
  212.     (void) fclose (plt_fp);
  213.     plt_fp = 0;
  214.     plot_prstate(0);
  215. }
  216.  
  217. /* turn on plotting.
  218.  * establish a file to use (and thereby set plt_fp, the plotting_is_on flag).
  219.  * also check that there is a srch function if it is being plotted.
  220.  */
  221. static
  222. plt_turn_on ()
  223. {
  224.     int sf = rcfpack(R_SRCH, C_SRCH, 0);
  225.     char fn[FNLEN], fnq[NC];
  226.     char *optype;
  227.     int n;
  228.     PltLine *plp;
  229.  
  230.     /* insure there is a valid srch function if we are to plot it */
  231.     for (plp = &pltlines[npltlines]; --plp >= pltlines; )
  232.         if ((plp->pl_rcpx == sf || plp->pl_rcpy == sf || plp->pl_rcpz == sf)
  233.             && !prog_isgood()) {
  234.         f_msg ("Plotting search function but it is not defined.");
  235.         return;
  236.         }
  237.  
  238.     /* prompt for file name, giving current as default */
  239.     (void) sprintf (fnq, "file to write <%s>: ", plt_filename);
  240.     f_prompt (fnq);
  241.     n = read_line (fn, sizeof(fn)-1);
  242.  
  243.     /* leave plotting off if type END.
  244.      * reuse same fn if just type \n
  245.      */
  246.     if (n < 0)
  247.         return;
  248.     if (n > 0)
  249.         (void) strcpy (plt_filename, fn);
  250.  
  251.     /* give option to append if file already exists */
  252.     optype = "w";
  253.     if (access (plt_filename, 2) == 0) {
  254.         while (1) {
  255.         f_prompt ("files exists; append or overwrite (a/o)?: ");
  256.         n = read_char();
  257.         if (n == 'a') {
  258.             optype = "a";
  259.             break;
  260.         }
  261.         if (n == 'o')
  262.             break;
  263.         }
  264.     }
  265.  
  266.     /* plotting is on if file opens ok */
  267.     plt_fp = fopen (plt_filename, optype);
  268.     if (!plt_fp) {
  269.         char buf[NC];
  270.         (void) sprintf (buf, "can not open %s: %s", plt_filename, errsys);
  271.         f_prompt (buf);
  272.         (void)read_char();
  273.     } else {
  274.         /* add a title if desired */
  275.         static char tp[] = "Title (q to skip): ";
  276.         f_prompt (tp);
  277.         if (read_line (fnq, PW - sizeof(tp)) > 0)
  278.         (void) fprintf (plt_fp, "* %s\n", fnq);
  279.     }
  280.     plot_prstate (0);
  281. }
  282.  
  283. /* ask operator for a file to plot. if it's ok, do it.
  284.  */
  285. static
  286. plt_file ()
  287. {
  288.     char fn[FNLEN], fnq[64];
  289.     FILE *pfp;
  290.     int n;
  291.  
  292.     /* prompt for file name, giving current as default */
  293.     (void) sprintf (fnq, "file to read <%s>: ", plt_filename);
  294.     f_prompt (fnq);
  295.     n = read_line (fn, sizeof(fn)-1);
  296.  
  297.     /* forget it if type END.
  298.      * reuse same fn if just type \n
  299.      */
  300.     if (n < 0)
  301.         return;
  302.     if (n > 0)
  303.         (void) strcpy (plt_filename, fn);
  304.  
  305.     /* do the plot if file opens ok */
  306.     pfp = fopen (plt_filename, "r");
  307.     if (pfp) {
  308.         if (plt_in_polar)
  309.         plot_polar (pfp);
  310.         else
  311.         plot_cartesian (pfp);
  312.         (void) fclose (pfp);
  313.     } else {
  314.         char buf[NC];
  315.         (void) sprintf (buf, "can not open %s: %s", plt_filename, errsys);
  316.         f_prompt (buf);
  317.         (void)read_char();
  318.     }
  319. }
  320.  
  321. /* plot the given file on the screen in cartesian coords.
  322.  * TODO: add z tags somehow
  323.  * N.B. do whatever you like but redraw the screen when done.
  324.  */
  325. static
  326. plot_cartesian (pfp)
  327. FILE *pfp;
  328. {
  329.     static char fmt[] = "%c,%lf,%lf";
  330.     double x, y;    /* N.B. be sure these match what scanf's %lf wants*/
  331.     double minx, maxx, miny, maxy;
  332.     char buf[128];
  333.     int npts = 0;
  334.     char c;
  335.  
  336.     /* find ranges and number of points */
  337.     while (fgets (buf, sizeof(buf), pfp)) {
  338.         if (sscanf (buf, fmt, &c, &x, &y) != 3)
  339.         continue;
  340.         if (npts++ == 0) {
  341.         maxx = minx = x;
  342.         maxy = miny = y;
  343.         } else {
  344.         if (x > maxx) maxx = x;
  345.         else if (x < minx) minx = x;
  346.         if (y > maxy) maxy = y;
  347.         else if (y < miny) miny = y;
  348.         }
  349.     }
  350.  
  351. #define    SMALL    (1e-10)
  352.     if (npts < 2 || fabs(minx-maxx) < SMALL || fabs(miny-maxy) < SMALL)
  353.         f_prompt ("At least two different points required to plot.");
  354.     else {
  355.         /* read file again, this time plotting */
  356.         rewind (pfp);
  357.         c_erase();
  358.         while (fgets (buf, sizeof(buf), pfp)) {
  359.         int row, col;
  360.         if (sscanf (buf, fmt, &c, &x, &y) != 3)
  361.             continue;
  362.         row = NR-(int)((NR-1)*(y-miny)/(maxy-miny)+0.5);
  363.         col =  1+(int)((NC-1)*(x-minx)/(maxx-minx)+0.5);
  364.         if (row == NR && col == NC)
  365.             col--;    /* avoid lower right scrolling corner */
  366.         f_char (row, col, c);
  367.         }
  368.  
  369.         /* label axes */
  370.         f_double (1, 1, "%g", maxy);
  371.         f_double (NR-1, 1, "%g", miny);
  372.         f_double (NR, 1, "%g", minx);
  373.         f_double (NR, NC-10, "%g", maxx);
  374.     }
  375.  
  376.     /* hit any key to resume... */
  377.     (void) read_char();
  378.     redraw_screen (2);    /* full redraw */
  379. }
  380.  
  381. /* plot the given file on the screen in polar coords.
  382.  * first numberic field in plot file is r, second is theta in degrees.
  383.  * TODO: add z tags somehow
  384.  * N.B. do whatever you like but redraw the screen when done.
  385.  */
  386. static
  387. plot_polar (pfp)
  388. FILE *pfp;
  389. {
  390.     static char fmt[] = "%c,%lf,%lf";
  391.     double r, th;    /* N.B. be sure these match what scanf's %lf wants*/
  392.     double maxr;
  393.     char buf[128];
  394.     int npts = 0;
  395.     char c;
  396.  
  397.     /* find ranges and number of points */
  398.     while (fgets (buf, sizeof(buf), pfp)) {
  399.         if (sscanf (buf, fmt, &c, &r, &th) != 3)
  400.         continue;
  401.         if (npts++ == 0)
  402.         maxr = r;
  403.         else
  404.         if (r > maxr)
  405.             maxr = r;
  406.     }
  407.  
  408.     if (npts < 2)
  409.         f_prompt ("At least two points required to plot.");
  410.     else {
  411.         /* read file again, this time plotting */
  412.         rewind (pfp);
  413.         c_erase();
  414.         while (fgets (buf, sizeof(buf), pfp)) {
  415.         int row, col;
  416.         double x, y;
  417.         if (sscanf (buf, fmt, &c, &r, &th) != 3)
  418.             continue;
  419.         x = r * cos(th/57.2958);    /* degs to rads */
  420.         y = r * sin(th/57.2958);
  421.         row = NR-(int)((NR-1)*(y+maxr)/(2.0*maxr)+0.5);
  422.         col =  1+(int)((NC-1)*(x+maxr)/(2.0*maxr)/ASPECT+0.5);
  423.         if (row == NR && col == NC)
  424.             col--;    /* avoid lower right scrolling corner */
  425.         f_char (row, col, c);
  426.         }
  427.  
  428.         /* label radius */
  429.         f_double (NR/2, NC-10, "%g", maxr);
  430.     }
  431.  
  432.     /* hit any key to resume... */
  433.     (void) read_char();
  434.     redraw_screen (2);    /* full redraw */
  435. }
  436.