home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume19 / xephem / part09 / plot_aux.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-15  |  8.7 KB  |  300 lines

  1. /* code to manage the actual drawing of plots.
  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/DrawingA.h>
  14. #include <Xm/LabelG.h>
  15. #include <Xm/PushBG.h>
  16. #include <Xm/ToggleBG.h>
  17. #include <Xm/Text.h>
  18.  
  19. extern char *myclass;
  20.  
  21. #if defined(__STDC__) || defined(__cplusplus)
  22. #define P_(s) s
  23. #else
  24. #define P_(s) ()
  25. #endif
  26.  
  27. extern int tickmarks P_((double min, double max, int numdiv, double ticks[]));
  28. extern void get_something P_((Widget w, char *resource, char *value));
  29. extern void xe_msg P_((char *msg, int app_modal));
  30.  
  31. int plot_cartesian P_((FILE *pfp, Widget widget, unsigned int nx, unsigned int ny, int flipx, int flipy, int grid));
  32.  
  33. #undef P_
  34.  
  35. /* maximum number of unique functions (ie tags) in the plot file.
  36.  * to be fair, it should be at least as large as the value in plot.
  37.  */
  38. #define    MAXPLTLINES    10
  39.  
  40. static GC plt_gc, plt_gcc[MAXPLTLINES];    /* annotation and plot gcs */
  41. static XFontStruct *plt_fs;
  42.  
  43. /* plot the given file in the drawing area in cartesian coords.
  44.  * drawing space is from 0..(nx-1) and 0..(ny-1).
  45.  * TODO: add z tags somehow
  46.  * return 0 if ok, else give a message about trouble and return -1.
  47.  */
  48. plot_cartesian (pfp, widget, nx, ny, flipx, flipy, grid)
  49. FILE *pfp;
  50. Widget widget;
  51. unsigned int nx, ny;
  52. int flipx, flipy;    /* respectively true to flip their axis */
  53. int grid;        /* whether to include a grid with the tick marks */
  54. {
  55. #define    TL    5    /* tick mark length, in pixels */
  56. #define    NT    10    /* rought number of tick marks on each axis */
  57.     Display *dsp = XtDisplay(widget);
  58.     Window win = XtWindow(widget);
  59.     double ticks[NT+2];
  60.     int nt;
  61.     static char fmt[] = "%c,%lf,%lf";
  62.     double x, y;    /* N.B. be sure these match what scanf's %lf wants*/
  63.     double minx, maxx, miny, maxy, xscale, yscale;
  64.     char buf[128];
  65.     int lx[MAXPLTLINES], ly[MAXPLTLINES], one[MAXPLTLINES];
  66.     char c, tags[MAXPLTLINES];
  67.     XCharStruct overall;
  68.     int sawtitle;
  69.     int ylblw;
  70.     int nlines;
  71.     int ix, iy;    /* misc X drawing coords */
  72.     int x0;        /* X x coord of lower left of plotting box, in pixels */
  73.     int y0;        /* X y coord of lower left of plotting box, in pixels */
  74.     int h, w;    /* width of height of plotting box, in pixels */
  75.     int asc, desc;    /* font ascent and descent, in pixels */
  76.     int maxlblw;    /* width of longest y axis label, in pixels */
  77.     int i;
  78. #define    XCORD(x)    (x0 + (int)((flipx?maxx-(x):(x)-minx)*xscale + 0.5))
  79. #define    YCORD(y)    (y0 - (int)((flipy?maxy-(y):(y)-miny)*yscale + 0.5))
  80.  
  81.     /* find ranges and number of and tags for each unique line */
  82.     nlines = 0;
  83.     while (fgets (buf, sizeof(buf), pfp)) {
  84.         if (sscanf (buf, fmt, &c, &x, &y) != 3)
  85.         continue;
  86.         if (nlines == 0) {
  87.         maxx = minx = x;
  88.         maxy = miny = y;
  89.         }
  90.         for (i = 0; i < nlines; i++)
  91.         if (c == tags[i])
  92.             break;
  93.         if (i == nlines) {
  94.         if (nlines == MAXPLTLINES) {
  95.            (void) sprintf (buf,
  96.              "Plot file contains more than %d functions.", MAXPLTLINES);
  97.            xe_msg (buf, 0);
  98.            return(-1);
  99.         }
  100.         tags[nlines++] = c;
  101.         }
  102.         if (x > maxx) maxx = x;
  103.         else if (x < minx) minx = x;
  104.         if (y > maxy) maxy = y;
  105.         else if (y < miny) miny = y;
  106.     }
  107.  
  108.     if (nlines == 0) {
  109.         xe_msg ("Plot file appears to be empty.", 0);
  110.         return(-1);
  111.     }
  112. #define    SMALL    (1e-6)
  113.     if (fabs(minx-maxx) < SMALL || fabs(miny-maxy) < SMALL) {
  114.         xe_msg ("Plot file values contain insufficient spread.", 0);
  115.         return(-1);
  116.     }
  117.  
  118.     if (!plt_gc) {
  119.         unsigned long da_p;    /* the foreground color of the drawing area */
  120.         XGCValues gcv;
  121.         unsigned gcm = GCForeground;
  122.         Colormap def_cm = DefaultColormap(dsp, 0);
  123.         XColor defxc, dbxc;
  124.  
  125.         /* create the annotation and default plot color gc,
  126.          * using the foreground color of the PlotDA.
  127.          */
  128.         get_something (widget, XmNforeground, (char *)&da_p);
  129.         gcv.foreground = da_p;
  130.         plt_gc = XCreateGC (dsp, win, gcm, &gcv);
  131.         plt_fs = XQueryFont (dsp, XGContextFromGC (plt_gc));
  132.  
  133.         /* fill in plt_gcc array with gc's to use for function plotting.
  134.          * Use colors defined in the plotColor[0-9] resources, else
  135.          * reuse plt_gc.
  136.          */
  137.         for (i = 0; i < MAXPLTLINES; i++) {
  138.         char cnum[100], *cname;
  139.         (void) sprintf (cnum, "plotColor%d", i);
  140.         cname = XGetDefault (dsp, myclass, cnum);
  141.         if (!cname ||
  142.             !XAllocNamedColor (dsp,def_cm,cname,&defxc,&dbxc)) {
  143.             char msg[128];
  144.             if (!cname)
  145.             (void)sprintf(msg, "can't find resource `%.80s'", cnum);
  146.             else
  147.             (void)sprintf(msg, "can't Alloc color `%.80s'", cname);
  148.             (void) sprintf (msg+strlen(msg),
  149.                     "... using PlotDA's foreground color.\n");
  150.             xe_msg(msg, 0);
  151.             plt_gcc[i] = plt_gc;
  152.         } else {
  153.             gcv.foreground = defxc.pixel;
  154.             plt_gcc[i] = XCreateGC (dsp, win, gcm, &gcv);
  155.         }
  156.         }
  157.     }
  158.  
  159.     /* add y-axis tick marks.
  160.      * first compute length of longest y-axis label and other char stuff.
  161.      */
  162.     nt = tickmarks (miny, maxy, NT, ticks);
  163.     maxlblw = 0;
  164.     for (i = 0; i < nt; i++) {
  165.         int dir;
  166.         int l;
  167.         if (ticks[i] < miny || ticks[i] > maxy)
  168.         continue;
  169.         (void) sprintf (buf, "%g", ticks[i]);
  170.         l = strlen(buf);
  171.         XTextExtents (plt_fs, buf, l, &dir, &asc, &desc, &overall);
  172.         if (overall.width > maxlblw)
  173.         maxlblw = overall.width;
  174.     }
  175.  
  176.     /* now we can compute border sizes and the scaling factors */
  177.     x0 = maxlblw+TL+3;
  178.     w = nx - x0 - 30;
  179.     y0 = ny - (asc+desc+2+2*TL);
  180.     h = y0 - (asc+desc+2);
  181.     xscale = w/(maxx-minx);
  182.     yscale = h/(maxy-miny);
  183.  
  184.     /* now draw y axis, its labels, and optionally the horizontal grid */
  185.     for (i = 0; i < nt; i++) {
  186.         int l;
  187.         if (ticks[i] < miny || ticks[i] > maxy)
  188.         continue;
  189.         (void) sprintf (buf, "%g", ticks[i]);
  190.         l = strlen(buf);
  191.         iy = YCORD(ticks[i]);
  192.         XDrawLine (dsp, win, plt_gc, x0-TL, iy, x0, iy);
  193.         XDrawString (dsp, win, plt_gc, 1, iy+(asc-desc)/2, buf, l);
  194.         if (grid)
  195.         XDrawLine (dsp, win, plt_gc, x0, iy, x0+w-1, iy);
  196.     }
  197.  
  198.     /* now draw x axis and label it's first and last tick mark.
  199.      * if there's room, label the center tickmark too.
  200.      * also grid, if requested.
  201.      */
  202.     nt = tickmarks (minx, maxx, NT, ticks);
  203.     ylblw = 0;
  204.     for (i = 0; i < nt; i++) {
  205.         if (ticks[i] < minx || ticks[i] > maxx)
  206.         continue;
  207.         ix = XCORD(ticks[i]);
  208.         XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0);
  209.         if (grid)
  210.         XDrawLine (dsp, win, plt_gc, ix, y0, ix, y0-h-1);
  211.     }
  212.     for (i = 0; i < nt; i++)
  213.         if (ticks[i] >= minx) {
  214.         int di, as, de;
  215.         XCharStruct ovl;
  216.         int l;
  217.         (void) sprintf (buf, "%g", ticks[i]);
  218.         l = strlen(buf);
  219.         ix = XCORD(ticks[i]);
  220.         XTextExtents (plt_fs, buf, l, &di, &as, &de, &ovl);
  221.         ylblw += ovl.width;
  222.         XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0+2*TL);
  223.         XDrawString (dsp, win, plt_gc, ix-ovl.width/2, y0+2*TL+asc+1,
  224.                                     buf, l);
  225.         break;
  226.         }
  227.     for (i = nt; --i >= 0;)
  228.         if (ticks[i] <= maxx) {
  229.         int di, as, de;
  230.         XCharStruct ovl;
  231.         int l;
  232.         (void) sprintf (buf, "%g", ticks[i]);
  233.         l = strlen(buf);
  234.         ix = XCORD(ticks[i]);
  235.         XTextExtents (plt_fs, buf, l, &di, &as, &de, &ovl);
  236.         ylblw += ovl.width;
  237.         XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0+2*TL);
  238.         XDrawString (dsp, win, plt_gc, ix-ovl.width/2, y0+2*TL+asc+1,
  239.                                     buf, l);
  240.         break;
  241.         }
  242.     if (ylblw < w/2) {
  243.         /* pretty likely to be room for another label */
  244.         int di, as, de;
  245.         XCharStruct ovl;
  246.         int l;
  247.         (void) sprintf (buf, "%g", ticks[nt/2]);
  248.         l = strlen(buf);
  249.         ix = XCORD(ticks[nt/2]);
  250.         XTextExtents (plt_fs, buf, l, &di, &as, &de, &ovl);
  251.         XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0+2*TL);
  252.         XDrawString (dsp, win, plt_gc, ix-ovl.width/2, y0+2*TL+asc+1,
  253.                                     buf, l);
  254.     }
  255.  
  256.     /* draw border of actual plotting area */
  257.     XDrawLine (dsp, win, plt_gc, x0, y0-h, x0, y0);
  258.     XDrawLine (dsp, win, plt_gc, x0, y0, x0+w, y0);
  259.     XDrawLine (dsp, win, plt_gc, x0+w, y0, x0+w, y0-h);
  260.     XDrawLine (dsp, win, plt_gc, x0+w, y0-h, x0, y0-h);
  261.  
  262.     /* read file again, this time plotting the data (finally!).
  263.      * also, the first line we see that doesn't look like a point
  264.      * is put up as a title line (minus its first two char and trailing \n).
  265.      */
  266.     sawtitle = 0;
  267.     rewind (pfp);
  268.     for (i = 0; i < nlines; i++)
  269.         one[i] = 0;
  270.     while (fgets (buf, sizeof(buf), pfp)) {
  271.         if (sscanf (buf, fmt, &c, &x, &y) != 3) {
  272.         /* a title line ? */
  273.         int l;
  274.         if (!sawtitle && (l = strlen(buf)) > 2) {
  275.             int di, as, de;
  276.             XCharStruct ovl;
  277.             XTextExtents (plt_fs, buf+2, l-2, &di, &as, &de, &ovl);
  278.             XDrawString (dsp, win, plt_gc, x0+(w-ovl.width)/2, asc+1,
  279.                                 buf+2, l-3);
  280.             sawtitle = 1;
  281.         }
  282.         continue;
  283.         }
  284.         for (i = 0; i < nlines; i++)
  285.         if (c == tags[i])
  286.             break;
  287.         ix = XCORD(x);
  288.         iy = YCORD(y);
  289.         if (one[i]++ > 0)
  290.         XDrawLine (dsp, win, plt_gcc[i], ix, iy, lx[i], ly[i]);
  291.         else {
  292.         int ytop = y0 - h + asc;
  293.         XDrawString(dsp,win,plt_gcc[i], ix, iy<ytop ? ytop : iy, &c, 1);
  294.         }
  295.         lx[i] = ix;
  296.         ly[i] = iy;
  297.     }
  298.     return (0);
  299. }
  300.