view tools/x11play.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
line wrap: on
line source
/****************************************************************************
*
*   x11play    -Animate successive plots of n points.
		The points are read as binary shorts.
*               Like x11plot, but plots successive blocks of n points
*               on top of each other, rubbing out the previous plot, so
*               as to form an "animated" sequence of plots.
*
*              -Help:  x11play -H
*              -Usage, EG:
*                      fft -n128 -o120 file | x11play -n64 -y0 -c5000
*                      Quit program with left mouse button.
*             -Step-mode
*                      With a -S flag, single-step through frames using
*                      the mouse as follows:
*
*                      left -   quit
*                      centre - freeze animation (successive centre
*                               buttons give single successive frames).
*                      right  - continue animation
*
*                      Note: animation is slower in step-mode because
*                      XSynchronise has to be on.
****************************************************************************/
#include <stdio.h>
#include <math.h>
#include "x11coord.h"

/****************************************************************************
*   Defaults
****************************************************************************/
#define UNSET        (-9999)

#define DEFAMPL        1000
#define DEFSCALE        256

float   argXd0=UNSET,   argYd0=UNSET;
float   argXd1=UNSET,   argYd1=UNSET;

/****************************************************************************
*   Input-file arguments
****************************************************************************/
int     n =      DEFSCALE;      /* num points to read from file */
int     s =      0;             /* start position in file */
short   summary= 0;             /* Flag for method of block summary in downsample */
short   z =      1;             /* Flag for drawing zero line */
short   stepmode=0;             /* Flag for single-step mode */
short   overplot=0;             /* Flag for overplot mode */
short   stepcount=0;
char    DEFNAME[]="stdin";
char    *name=DEFNAME;
short   *data;
XPoint  *points;

FILE    *fp, *fopen();

/****************************************************************************
*       main
*   The window is plotted when an expose event is (automatically) generated.
*   The plotting routines are called from within the event monitor.
****************************************************************************/
main(argc, argv)
int   argc ;
char *argv[] ;
{
    Window  w;
    int     npoints;

    while (--argc > 0 && **++argv == '-')
	switch (*++*argv) {
	    case 'n':   n       = atoi(++*argv); break;
	    case 's':   s       = atoi(++*argv); break;
	    case 'x':   argXd0  = atof(++*argv); break;
	    case 'y':   argYd0  = atof(++*argv); break;
	    case 'c':   argXd1  = atof(++*argv); break;
	    case 'a':   argYd1  = atof(++*argv); break;
	    case 'b':   summary = atoi(++*argv); break;
	    case 'z':   z       = 0;             break;
	    case 'S':   stepmode++;              break;
	    case 'O':   overplot++;              break;
	    case 'F':   theFontString = ++*argv; break;
	    case 'H':
	    default:    help();
	}

    if (argXd0==UNSET)  argXd0 = s;
    if (argXd1==UNSET)  argXd1 = n;
    else                argXd1 = argXd1-argXd0; /* ie, a range */
    if (argYd0==UNSET) {
	if (argYd1==UNSET)  argYd1 = 2*DEFAMPL;
	else                argYd1 = 2*argYd1;
	argYd0 = argYd1/2;
    }
    else {
	if (argYd1==UNSET)  argYd1 = DEFAMPL+argYd0;
	else                argYd1 = argYd1+argYd0;
    }
    argYd0 = (-argYd0);

    if ((data = (short*) malloc(n * sizeof(short))) == NULL)
	error("malloc out of space\n");
    if ((points = (XPoint*)malloc(n * sizeof(XPoint))) == NULL)
	error("malloc out of space\n");

    if (argc) {
	/* Open data file */
	name = *argv;
	if ((fp = fopen(name, "r")) == NULL) {
	    fprintf(stderr,"can't open %s\n", *argv);
	    exit(1);
	}
    }
    else fp = stdin;

    /* Seek start of data in file */
    if (s > 0) seekstart(s,fp);

    set_window_parameters(PLOTXORG,PLOTYORG, PLOTWIDTH,PLOTHEIGHT);
    set_bordered_box(10);
    set_data_parameters(0,0, argXd0,argYd0, argXd1,argYd1);
    xopen();
    xgc( 1, theFontString ) ;
    w = xcreate(name, ButtonPressMask | ExposureMask);
    init_xevent(w);
}


/****************************************************************************
*   Seek s points from current position in stream.
*   This general seek works even when fp is stdin, unlike fseek.
****************************************************************************/
seekstart(s,fp)
int   s;
FILE  *fp;
{
    int   i;
    short p;

    for (i=0 ; i<s && fread(&p, sizeof(short), 1, fp) ; i++)
	;
    if (i<s) error("seek overshot end-of-file\n");
}


/****************************************************************************
*       X11 Event Monitor.
*   The window is plotted when an expose event is (automatically) generated.
*   This routine catches the initial expose event to first draw the window.
*   After this, the xevent_monitor is called from upsample, which is called
*   from draw_plot.
****************************************************************************/
init_xevent(w)  /* to catch initial expose event and draw first plot */
Window w;
{
    XEvent event;

    for ( ; ; ) {
	XNextEvent(theDisplay,&event);
	switch (event.type) {
	    case ButtonPress:
		switch(event.xbutton.button) {
		    case Button1:           /* Left   */
			XDestroyWindow(theDisplay,w);
			exit(0);
		    case Button2:           /* Middle */
		    case Button3: break;    /* Right */
		    default:
			fprintf(stderr,"button %d not used\n", event.xbutton.button);
		}
		break;
	    case Expose:
		if (event.xexpose.count == 0) {
		    draw_calibrated_box(w);
		    draw_plot(w);
		}
		break;
	    default:
		fprintf(stderr,"event type %d not found\n", event.type);
	}
    }
}


xevent_monitor(w)
Window w;
{
    XEvent event;
    static short  wait=1;

    if (!stepmode) wait=0;
    do {
	/* get next event provided one is on queue; don't wait otherwise */
	if (wait || XEventsQueued(theDisplay,QueuedAlready) > 0) {
	    XNextEvent(theDisplay,&event);
	    switch (event.type) {
		case ButtonPress:
		    switch(event.xbutton.button) {
			case Button1:               /* Left   */
			    XDestroyWindow(theDisplay,w);
			    exit(0);
			case Button2: /* Middle */
			    if (stepmode) {
			       if (wait) single_shot(w,fp);
			       else wait=1;
			    }
			    break;
			case Button3: if (stepmode) wait=0; break;/* Right */
			default:
			    fprintf(stderr,"button %d not used\n", event.xbutton.button);
		    }
		    break;
		default:
		    fprintf(stderr,"event type %d not found\n", event.type);
	    }
	}
    } while (wait);
}


/****************************************************************************
*   Draw a calibrated box in a window and plot data inside it.
****************************************************************************/
draw_plot(w)
Window  w;
{
    int i, npoints;

    if (z) draw_Xaxis(w,0);     /* Draw zero line */
    if (!overplot) XSetFunction(theDisplay,theGC,GXinvert);
    if (stepmode) XSynchronize(theDisplay,True);
    if (n <= pwidth()) npoints = upsample(w,fp);
    else  fprintf(stderr,"successive downsampling not implemented yet!\n");
    /*    npoints = downsample(w,fp);   */
}


/****************************************************************************
*       Up and Down sampling.
****************************************************************************/
char stepcountstr[128];

upsample (w,fp)
Window  w;
FILE   *fp;
{
    int    i, x, j=0;
    int    lastx,lasty, X,Y;
    short  y, notfirst=0;
    float  res, incr, carry;

    res = (float)pwidth()/(n-1);                /* resolution of plot */
    incr = res;                                 /* x-value increment */
    x = 0;                                      /* initial x-value */
    while (fread(&y, sizeof(short), 1, fp)) {
	if (stepmode) {
	    if (stepcount > 0) supertopline(w,stepcountstr);
	    sprintf(stepcountstr,"%d", ++stepcount);
	    supertopline(w,stepcountstr);
	}
	lastx=pleft(); lasty=py(y);
	carry = res - (int)res;
	incr = res + carry;
	x = (int)incr;
	for (i=1 ; i<n  && fread(&y, sizeof(short), 1, fp) ; i++) {
	    X = x+pleft();
	    Y = py(y);
	    /* Plot only inside y-limits of box */
	    if (Y > pbottom()) Y = pbottom();
	    if (Y < ptop())    Y = ptop();

	    /* rub-out a segment of last plot */
	    if (notfirst)
		XDrawLine(theDisplay, w, theGC, points[i-1].x, points[i-1].y, points[i].x, points[i].y);
	    else  notfirst=1;
	    /* draw a new segment for current plot */
	    XDrawLine(theDisplay, w, theGC, lastx, lasty, X, Y);

	    points[i-1].x = lastx;
	    points[i-1].y = lasty;
	    lastx = X;
	    lasty = Y;

	    carry = incr - (int)incr;
	    incr = res + carry;
	    x += (int)incr;
	}
	points[i-1].x = lastx;
	points[i-1].y = lasty;
/*        if (XEventsQueued(theDisplay,QueuedAlready) > 0)      */
	    xevent_monitor(w);
    }
}


single_shot (w,fp)
Window  w;
FILE   *fp;
{
    int    i, x, j=0;
    int    lastx,lasty, X,Y;
    short  y, notfirst=0;
    float  res, incr, carry;

    res = (float)pwidth()/(n-1);                /* resolution of plot */
    incr = res;                                 /* x-value increment */
    x = 0;                                      /* initial x-value */
    if (fread(&y, sizeof(short), 1, fp)) {
	if (stepmode) {
	    if (stepcount > 0) supertopline(w,stepcountstr);
	    sprintf(stepcountstr,"%d", ++stepcount);
	    supertopline(w,stepcountstr);
	}
	lastx=pleft(); lasty=py(y);
	carry = res - (int)res;
	incr = res + carry;
	x = (int)incr;
	for (i=1 ; i<n  && fread(&y, sizeof(short), 1, fp) ; i++) {
	    X = x+pleft();
	    Y = py(y);
	    /* Plot only inside y-limits of box */
	    if (Y > pbottom()) Y = pbottom();
	    if (Y < ptop())    Y = ptop();

	    /* rub-out a segment of last plot */
	    if (notfirst)
		XDrawLine(theDisplay, w, theGC, points[i-1].x, points[i-1].y, points[i].x, points[i].y);
	    else  notfirst=1;
	    /* draw a new segment for current plot */
	    XDrawLine(theDisplay, w, theGC, lastx, lasty, X, Y);

	    points[i-1].x = lastx;
	    points[i-1].y = lasty;
	    lastx = X;
	    lasty = Y;

	    carry = incr - (int)incr;
	    incr = res + carry;
	    x += (int)incr;
	}
	points[i-1].x = lastx;
	points[i-1].y = lasty;
    }
}


#define BLOCK   256
float block;            /* for averaging in downsample */


downsample (w,fp)
Window  w;
FILE   *fp;
{
    int   i, x, j = 0;
    short y;
    float rate;
    float res;
    float incr;
    float carry;

    rate = (float)n/pwidth();
    if ((block = rate) >= BLOCK)
	error ("excessive downsampling; re-define BLOCK\n");

    res = (float)pwidth()/(n-1);                /* resolution of plot */
    incr = res;                                 /* x-value increment */
    x = 0;                                      /* initial x-value */
    for (i=0 ; i<n ; i++) {
	if (incr >= 1.0) {
	    if (sample(&y, i, rate)) {
		points[j].x = x+pleft();
		points[j].y = py(y);

		/* Plot only inside y-limits of box */
		if (points[j].y > pbottom()) points[j].y = pbottom();
		if (points[j].y < ptop())    points[j].y = ptop();
		j++;
	    }
	}
	carry = incr - (int)incr;
	incr = res + carry;
	x += (int)incr;
    }
    return j;
}

sample (y, i, rate)
short  *y;
int     i;
float   rate;
{
    short average();
    float carry;

    if (block <= n-i) {
	*y = average ((int)block, &data[i]);
	carry = block - (int)block;
	block = rate + carry;
	return 1;
    }
    else
	return 0;
}

/*
short
average (block, p)
int block;
short p[];
{
    int   i;
    float sum = 0;

    for (i = 0 ; i < block ; i++)
	sum += p[i];
    return (short)(sum / block);
}
*/

short
average (block, p)
int block;
short p[];
{
    int   i;
    float sum = 0;
    short MIN = 32000, MAX = 0;

    for (i = 0 ; i < block ; i++) {
	sum += p[i];
	if (p[i] < MIN) MIN = p[i];
	if (p[i] > MAX) MAX = p[i];
    }
    if (summary==0) {                   /* summary of block is largest extremal value */
	if (MAX >= (-MIN)) return MAX;     /* summary of block is MAX value */
	else               return MIN;     /* summary of block is MIN value */
    }
    if (summary == 1) return (p[0]);    /* summary of block is sample value */
    return (short)(sum / block);        /* summary of block is mean value */
}


/****************************************************************************
*       Miscellaneous
****************************************************************************/
error(s)
{
    fprintf(stderr,"%s",s);
    exit(1);
}


help ()
{
    printf ("\nx11play: animated plot of sets of n points, read as binary shorts.\n");
    printf ("Usage: a) x11play  [options]  filename\n");
    printf ("       b) cat filename  |  x11play  [options]\n");
    printf ("    where filename is an input stream of 16-bit binary numbers (shorts)\n");
    printf ("Options:\n");
    printf ("-n [int]      = Number of points plotted (default=%d).\n", DEFSCALE);
    printf ("-s [int]      = Offset points from start of file (default=0).\n");
    printf ("-a [float]    = Amplitude between zero-line and top of box (default=%d).\n", DEFAMPL);
    printf ("-y [int]      = Amplitude between zero-line and bottom of box (default=a).\n");
    printf ("-c [float]    = Calibration at right end of x-axis (default=n+s).\n");
    printf ("-x [int]      = Calibration at left end of x-axis (default=s).\n");
    printf ("-z            = Suppress zero-line.\n");
    printf ("-b [0,1,2]    = Method of block summary for down-sampling.\n");
    printf ("                0=MAX, 1=SAMPLE, 2=MEAN, (default=MAX).\n");
    printf ("-S            = Step-mode, (centre-button=single-step, right-button=play).\n");
    printf ("-O            = Over-plot successive plots of n points.\n");
    printf ("-F [font]     = Font name (default=%s)\n", theFontString);
    exit (0);
}