home *** CD-ROM | disk | FTP | other *** search
- /* code to manage the actual drawing of plots.
- */
-
- #include <stdio.h>
- #include <ctype.h>
- #include <math.h>
- #if defined(__STDC__)
- #include <stdlib.h>
- #endif
- #include <X11/Xlib.h>
- #include <Xm/Xm.h>
- #include <Xm/Form.h>
- #include <Xm/DrawingA.h>
- #include <Xm/LabelG.h>
- #include <Xm/PushBG.h>
- #include <Xm/ToggleBG.h>
- #include <Xm/Text.h>
-
- extern char *myclass;
-
- #if defined(__STDC__) || defined(__cplusplus)
- #define P_(s) s
- #else
- #define P_(s) ()
- #endif
-
- extern int tickmarks P_((double min, double max, int numdiv, double ticks[]));
- extern void get_something P_((Widget w, char *resource, char *value));
- extern void xe_msg P_((char *msg, int app_modal));
-
- int plot_cartesian P_((FILE *pfp, Widget widget, unsigned int nx, unsigned int ny, int flipx, int flipy, int grid));
-
- #undef P_
-
- /* maximum number of unique functions (ie tags) in the plot file.
- * to be fair, it should be at least as large as the value in plot.
- */
- #define MAXPLTLINES 10
-
- static GC plt_gc, plt_gcc[MAXPLTLINES]; /* annotation and plot gcs */
- static XFontStruct *plt_fs;
-
- /* plot the given file in the drawing area in cartesian coords.
- * drawing space is from 0..(nx-1) and 0..(ny-1).
- * TODO: add z tags somehow
- * return 0 if ok, else give a message about trouble and return -1.
- */
- plot_cartesian (pfp, widget, nx, ny, flipx, flipy, grid)
- FILE *pfp;
- Widget widget;
- unsigned int nx, ny;
- int flipx, flipy; /* respectively true to flip their axis */
- int grid; /* whether to include a grid with the tick marks */
- {
- #define TL 5 /* tick mark length, in pixels */
- #define NT 10 /* rought number of tick marks on each axis */
- Display *dsp = XtDisplay(widget);
- Window win = XtWindow(widget);
- double ticks[NT+2];
- int nt;
- static char fmt[] = "%c,%lf,%lf";
- double x, y; /* N.B. be sure these match what scanf's %lf wants*/
- double minx, maxx, miny, maxy, xscale, yscale;
- char buf[128];
- int lx[MAXPLTLINES], ly[MAXPLTLINES], one[MAXPLTLINES];
- char c, tags[MAXPLTLINES];
- XCharStruct overall;
- int sawtitle;
- int ylblw;
- int nlines;
- int ix, iy; /* misc X drawing coords */
- int x0; /* X x coord of lower left of plotting box, in pixels */
- int y0; /* X y coord of lower left of plotting box, in pixels */
- int h, w; /* width of height of plotting box, in pixels */
- int asc, desc; /* font ascent and descent, in pixels */
- int maxlblw; /* width of longest y axis label, in pixels */
- int i;
- #define XCORD(x) (x0 + (int)((flipx?maxx-(x):(x)-minx)*xscale + 0.5))
- #define YCORD(y) (y0 - (int)((flipy?maxy-(y):(y)-miny)*yscale + 0.5))
-
- /* find ranges and number of and tags for each unique line */
- nlines = 0;
- while (fgets (buf, sizeof(buf), pfp)) {
- if (sscanf (buf, fmt, &c, &x, &y) != 3)
- continue;
- if (nlines == 0) {
- maxx = minx = x;
- maxy = miny = y;
- }
- for (i = 0; i < nlines; i++)
- if (c == tags[i])
- break;
- if (i == nlines) {
- if (nlines == MAXPLTLINES) {
- (void) sprintf (buf,
- "Plot file contains more than %d functions.", MAXPLTLINES);
- xe_msg (buf, 0);
- return(-1);
- }
- tags[nlines++] = c;
- }
- if (x > maxx) maxx = x;
- else if (x < minx) minx = x;
- if (y > maxy) maxy = y;
- else if (y < miny) miny = y;
- }
-
- if (nlines == 0) {
- xe_msg ("Plot file appears to be empty.", 0);
- return(-1);
- }
- #define SMALL (1e-6)
- if (fabs(minx-maxx) < SMALL || fabs(miny-maxy) < SMALL) {
- xe_msg ("Plot file values contain insufficient spread.", 0);
- return(-1);
- }
-
- if (!plt_gc) {
- unsigned long da_p; /* the foreground color of the drawing area */
- XGCValues gcv;
- unsigned gcm = GCForeground;
- Colormap def_cm = DefaultColormap(dsp, 0);
- XColor defxc, dbxc;
-
- /* create the annotation and default plot color gc,
- * using the foreground color of the PlotDA.
- */
- get_something (widget, XmNforeground, (char *)&da_p);
- gcv.foreground = da_p;
- plt_gc = XCreateGC (dsp, win, gcm, &gcv);
- plt_fs = XQueryFont (dsp, XGContextFromGC (plt_gc));
-
- /* fill in plt_gcc array with gc's to use for function plotting.
- * Use colors defined in the plotColor[0-9] resources, else
- * reuse plt_gc.
- */
- for (i = 0; i < MAXPLTLINES; i++) {
- char cnum[100], *cname;
- (void) sprintf (cnum, "plotColor%d", i);
- cname = XGetDefault (dsp, myclass, cnum);
- if (!cname ||
- !XAllocNamedColor (dsp,def_cm,cname,&defxc,&dbxc)) {
- char msg[128];
- if (!cname)
- (void)sprintf(msg, "can't find resource `%.80s'", cnum);
- else
- (void)sprintf(msg, "can't Alloc color `%.80s'", cname);
- (void) sprintf (msg+strlen(msg),
- "... using PlotDA's foreground color.\n");
- xe_msg(msg, 0);
- plt_gcc[i] = plt_gc;
- } else {
- gcv.foreground = defxc.pixel;
- plt_gcc[i] = XCreateGC (dsp, win, gcm, &gcv);
- }
- }
- }
-
- /* add y-axis tick marks.
- * first compute length of longest y-axis label and other char stuff.
- */
- nt = tickmarks (miny, maxy, NT, ticks);
- maxlblw = 0;
- for (i = 0; i < nt; i++) {
- int dir;
- int l;
- if (ticks[i] < miny || ticks[i] > maxy)
- continue;
- (void) sprintf (buf, "%g", ticks[i]);
- l = strlen(buf);
- XTextExtents (plt_fs, buf, l, &dir, &asc, &desc, &overall);
- if (overall.width > maxlblw)
- maxlblw = overall.width;
- }
-
- /* now we can compute border sizes and the scaling factors */
- x0 = maxlblw+TL+3;
- w = nx - x0 - 30;
- y0 = ny - (asc+desc+2+2*TL);
- h = y0 - (asc+desc+2);
- xscale = w/(maxx-minx);
- yscale = h/(maxy-miny);
-
- /* now draw y axis, its labels, and optionally the horizontal grid */
- for (i = 0; i < nt; i++) {
- int l;
- if (ticks[i] < miny || ticks[i] > maxy)
- continue;
- (void) sprintf (buf, "%g", ticks[i]);
- l = strlen(buf);
- iy = YCORD(ticks[i]);
- XDrawLine (dsp, win, plt_gc, x0-TL, iy, x0, iy);
- XDrawString (dsp, win, plt_gc, 1, iy+(asc-desc)/2, buf, l);
- if (grid)
- XDrawLine (dsp, win, plt_gc, x0, iy, x0+w-1, iy);
- }
-
- /* now draw x axis and label it's first and last tick mark.
- * if there's room, label the center tickmark too.
- * also grid, if requested.
- */
- nt = tickmarks (minx, maxx, NT, ticks);
- ylblw = 0;
- for (i = 0; i < nt; i++) {
- if (ticks[i] < minx || ticks[i] > maxx)
- continue;
- ix = XCORD(ticks[i]);
- XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0);
- if (grid)
- XDrawLine (dsp, win, plt_gc, ix, y0, ix, y0-h-1);
- }
- for (i = 0; i < nt; i++)
- if (ticks[i] >= minx) {
- int di, as, de;
- XCharStruct ovl;
- int l;
- (void) sprintf (buf, "%g", ticks[i]);
- l = strlen(buf);
- ix = XCORD(ticks[i]);
- XTextExtents (plt_fs, buf, l, &di, &as, &de, &ovl);
- ylblw += ovl.width;
- XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0+2*TL);
- XDrawString (dsp, win, plt_gc, ix-ovl.width/2, y0+2*TL+asc+1,
- buf, l);
- break;
- }
- for (i = nt; --i >= 0;)
- if (ticks[i] <= maxx) {
- int di, as, de;
- XCharStruct ovl;
- int l;
- (void) sprintf (buf, "%g", ticks[i]);
- l = strlen(buf);
- ix = XCORD(ticks[i]);
- XTextExtents (plt_fs, buf, l, &di, &as, &de, &ovl);
- ylblw += ovl.width;
- XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0+2*TL);
- XDrawString (dsp, win, plt_gc, ix-ovl.width/2, y0+2*TL+asc+1,
- buf, l);
- break;
- }
- if (ylblw < w/2) {
- /* pretty likely to be room for another label */
- int di, as, de;
- XCharStruct ovl;
- int l;
- (void) sprintf (buf, "%g", ticks[nt/2]);
- l = strlen(buf);
- ix = XCORD(ticks[nt/2]);
- XTextExtents (plt_fs, buf, l, &di, &as, &de, &ovl);
- XDrawLine (dsp, win, plt_gc, ix, y0+TL, ix, y0+2*TL);
- XDrawString (dsp, win, plt_gc, ix-ovl.width/2, y0+2*TL+asc+1,
- buf, l);
- }
-
- /* draw border of actual plotting area */
- XDrawLine (dsp, win, plt_gc, x0, y0-h, x0, y0);
- XDrawLine (dsp, win, plt_gc, x0, y0, x0+w, y0);
- XDrawLine (dsp, win, plt_gc, x0+w, y0, x0+w, y0-h);
- XDrawLine (dsp, win, plt_gc, x0+w, y0-h, x0, y0-h);
-
- /* read file again, this time plotting the data (finally!).
- * also, the first line we see that doesn't look like a point
- * is put up as a title line (minus its first two char and trailing \n).
- */
- sawtitle = 0;
- rewind (pfp);
- for (i = 0; i < nlines; i++)
- one[i] = 0;
- while (fgets (buf, sizeof(buf), pfp)) {
- if (sscanf (buf, fmt, &c, &x, &y) != 3) {
- /* a title line ? */
- int l;
- if (!sawtitle && (l = strlen(buf)) > 2) {
- int di, as, de;
- XCharStruct ovl;
- XTextExtents (plt_fs, buf+2, l-2, &di, &as, &de, &ovl);
- XDrawString (dsp, win, plt_gc, x0+(w-ovl.width)/2, asc+1,
- buf+2, l-3);
- sawtitle = 1;
- }
- continue;
- }
- for (i = 0; i < nlines; i++)
- if (c == tags[i])
- break;
- ix = XCORD(x);
- iy = YCORD(y);
- if (one[i]++ > 0)
- XDrawLine (dsp, win, plt_gcc[i], ix, iy, lx[i], ly[i]);
- else {
- int ytop = y0 - h + asc;
- XDrawString(dsp,win,plt_gcc[i], ix, iy<ytop ? ytop : iy, &c, 1);
- }
- lx[i] = ix;
- ly[i] = iy;
- }
- return (0);
- }
-