view tools/x11plot.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
/****************************************************************************
*
*   x11plot  - a no-scale plot for X11 windows.   Mike Allerhand, March 1989.
*               Also for overplotting multiple files.
*
*   usage:  x11plot [options] filename1 [filename2 ...]
*       where filename is a stream of binary shorts.
*       Alternatively, input can be piped, as in:
*           cat filename | x11plot [options]
*
*   mouse:
*       left button   = print pointer coordinates.
*       centre button = re-draw plot (but not any printed coordinates).
*       right button  = exit program (destroy windows).
*
****************************************************************************/
#include <stdio.h>
#include <math.h>
#include "x11coord.h"


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

#define DEFAMPL        1000
#define DEFSCALE        256
#define DEFSAMPLERATE 20000

char    DEFUNITS[] = "p"  ;


#define SAMPLES         0
#define SECONDS         1
#define MILLISECONDS    2

int   xscale_units ;
char *unitstr = DEFUNITS ;


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

int     Yincr=0;        /* Increment y-origin for successive files */

int     plotxorg   = PLOTXORG   ;
int     plotyorg   = PLOTYORG   ;
int     plotheight = PLOTHEIGHT ;
int     plotwidth  = PLOTWIDTH  ;


/****************************************************************************
*   Input-file arguments
****************************************************************************/
int     m;                      /* num files to read */
int     n;                      /* length read from file */
int     s;                      /* start position in file */
short   z = 1;                  /* Flag for drawing zero line */
short   v = 1;                  /* Flag for calibrating box   */

int     samplerate = DEFSAMPLERATE  ;

short   **data    ;             /* data values for each file */
XPoint  **point   ;             /* XPoints (pixel coords) for each file */
int      *npoints ;             /* number of points actually read in from each file */

/****************************************************************************
*       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[] ;
{
    FILE   *fp, *fopen();
    Window  w ;
    float   n0=DEFSCALE, s0=0 ;
    int     i ;

    while (--argc > 0 && **++argv == '-')
	switch (*++*argv) {
	    case 'n':   n0      = atof(++*argv); break;
	    case 's':   s0      = atof(++*argv); break;
	    case 'y':   argYd0  = atof(++*argv); break;
	    case 'a':   argYd1  = atof(++*argv); break;
	    case 'z':   z       = 0;             break;
	    case 'v':   v       = 0;             break;
	    case 'Y':   Yincr   = atoi(++*argv); break;
	    case 'S':   samplerate = atoi(++*argv); break;
	    case 'u':   unitstr = ++*argv ;      break;
	    case 'F':   theFontString = ++*argv ;   break;
	    case 'H':
	    default:    help();
	}

    if (argc==0) m=1;       /* 1 file from stdin.     */
    else         m=argc;    /* m files given as args. */

    if ( strcmp( unitstr, "p" ) == 0 )       xscale_units = SAMPLES ;
    else if ( strcmp( unitstr, "s" ) == 0 )  xscale_units = SECONDS ;
    else if ( strcmp( unitstr, "ms" ) == 0 ) xscale_units = MILLISECONDS ;
    else {
	fprintf( stderr, "x11plot: unknown x-axis units\n" );
	exit( 1 );
    }

    n = to_samples( n0 ) ;
    s = to_samples( s0 ) ;


    /* Allocate a data and an XPoint matrix for m files, each of n points */
    if ( (data    = (short  **) malloc(m * sizeof(short  *)) ) == NULL ||
	 (point   = (XPoint **) malloc(m * sizeof(XPoint *)) ) == NULL ||
	 (npoints = (int     *) malloc(m * sizeof( int    )) ) == NULL    ) {
	fprintf( stderr, "x11plot: malloc out of space\n");
	exit( 1 ) ;
    }

    /* For each of m files ... */
    for ( i=0 ; i<m ; i++, argv++ ) {

	/* Allocate space for data and XPoints */
	if ( (data[i]  = (short  *) malloc(n * sizeof(short )) ) == NULL ||
	     (point[i] = (XPoint *) malloc(n * sizeof(XPoint)) ) == NULL    ) {
	    fprintf( stderr,"x11plot: malloc out of space\n");
	    exit( 1 ) ;
	}

	/* Open file, seek start of data in file and read data in*/
	if (argc==0) fp=stdin;
	else  if ((fp = fopen(*argv, "r")) == NULL) {
		fprintf(stderr,"can't open %s\n", *argv);
		exit(1);
	}
	if (s > 0) seekstart(s,fp);

	if ( ( npoints[i] = fread( data[i], sizeof(short), n, fp ) ) < n ) {
	    if (argc==0)
		fprintf(stderr,"Warning: %d points read from stdin.\n", npoints[i]);
	    else
		fprintf(stderr,"Warning: %d points read from input stream %s.\n", npoints[i], *argv);
	}

	fclose(fp);
    }

    /* Set argument defaults etc. */

    if (argXd0==UNSET)  argXd0 = 0 ;
    if (argXd1==UNSET)  argXd1 = (float) n ;

    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);

    mapwaves() ;
    xopen();
    xgc( 1, theFontString ) ;
    w = xcreate("x11plot", ButtonPressMask | ExposureMask | StructureNotifyMask  ) ;

    xevent_monitor(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) {
	fprintf(stderr,"seek overshot end-of-file\n");
	exit( 1 ) ;
    }
}


/****************************************************************************
*       X11 Event Monitor.
*   The window is plotted when an expose event is (automatically) generated.
*   The plotting routines are called from within the event monitor.
****************************************************************************/
xevent_monitor(w)
Window w;
{
    XEvent event;
    XWindowAttributes attribs ;

    for ( ; ; ) {
	XNextEvent(theDisplay,&event);
	switch (event.type) {
	    case ButtonPress:
		switch(event.xbutton.button) {
		    case Button1 :              /* Left   */
			report(w, event);
			break;
		    case Button2 :              /* Centre */
			clearplot( w, plotwidth, plotheight ) ;
			drawwaves( w ) ;
			break;
		    case Button3 :              /* Right  */
			XDestroyWindow(theDisplay,w);
			return;
		    default:
			fprintf(stderr,"button %d not used\n", event.xbutton.button);
		}
		break;
	    case ConfigureNotify :
		plotwidth  = event.xconfigure.width  ;
		plotheight = event.xconfigure.height ;
		mapwaves() ;
		clearplot( w, plotwidth, plotheight ) ;
/*                drawwaves( w ) ;      */
		break;
	    case Expose:
		if (event.xexpose.count == 0) {
		    drawwaves( w ) ;
		}
		break;
	}
    }
}



/****************************************************************************
*   Set the parameters for mapping data coords onto pixel coords.
*   For each data file, map the data onto pixel coords in the corresponding
*   XPoints array.
****************************************************************************/
mapwaves()
{
    int     i, j, n ;
    short  *dat ;
    XPoint *pix ;

    set_window_parameters( plotxorg, plotyorg, plotwidth, plotheight );
    set_bordered_box(10);
    set_data_parameters(0,0, argXd0,argYd0, argXd1,argYd1);

    for ( i = 0 ; i < m ; i++ ) {
	dat = data[i]    ;
	pix = point[i]   ;
	n   = npoints[i] ;
	for ( j = 0 ; j < n ; j++ ) {
	    pix[j].x = px(j) ;
	    if ( ( pix[j].y = py(dat[j]) ) > pbottom() ) pix[j].y = pbottom();
	    else if ( pix[j].y < ptop() )                pix[j].y = ptop();
	}
	if ( Yincr > 0 ) /* Increment Y-origin for successive files (Y decreases upwards) */
	    set_data_parameters(0,0, argXd0,argYd0-((i+1)*Yincr), argXd1,argYd1);
    }

    if ( Yincr > 0 ) /* Reset original values so that "report" works for first file */
	set_data_parameters(0,0, argXd0,argYd0, argXd1,argYd1);
}



clearplot( w, width, height )   /* clear the plot window */
Window w;
int    width, height ;
{
    XClearArea( theDisplay, w, 0, 0, width, height, 0 ) ;
}

drawwaves( w )                  /* draw the mapped data for all files */
Window w;
{
    int     i   ;

    draw_box(w);
    if (v) draw_calibration( w );
    if (z) draw_Xaxis(w,0);     /* Draw zero line */

    for ( i = 0 ; i < m ; i++ )
	XDrawLines(theDisplay, w, theGC, point[i], npoints[i], CoordModeOrigin ) ;

    XFlush(theDisplay);
}


draw_calibration( w )
Window w ;
{
    float d0, d1 ;

    switch ( xscale_units ) {
	case SAMPLES      :     d0 = (float) s ;
				d1 = d0 + (float) n ;
				break ;
	case SECONDS      :     d0 = (float) s / samplerate ;
				d1 = d0 + (float) n / samplerate ;
				break ;
	case MILLISECONDS :     d0 = (float) s * 1000. / samplerate ;
				d1 = d0 + (float) n * 1000. / samplerate ;
				break ;
    }

    calibrate_Axis( w,  pleft(),pright(),  d0,d1,     pbottom(),  'x' ) ;
    calibrate_Axis( w,  pbottom(),ptop(),  _Yd0,_Yd1, pleft(),    'y' ) ;
}



/****************************************************************************
*       Report position of cursor on screen.
****************************************************************************/
report(w, event)
Window  w;
XEvent event;
{
    char  str[32];
    int   x, y;                 /* pixel coords of cursor, wrt window origin */
    int   X, Y;                 /* data system coords */
    float xscale;
    int   XCALIBSPACE = 100;    /* Space for calib value labels for X axis (ie in Y direction) */
    int   YCALIBSPACE = 190;    /* Space for calib value labels for Y axis (ie in X direction) */

    x = event.xbutton.x;
    y = event.xbutton.y;
    xscale = (float)pwidth()/n;
/*    X = s + (x-Xp0)/xscale;   */   /* addition of s offset assumes time scale only */
    X = xp(x);
    Y = yp(y);
    sprintf(str,"(%d,%d)", X, Y);
    XDrawLine(theDisplay, w, theGC, x-10, y, x+10, y);
    XDrawLine(theDisplay, w, theGC, x, y-10, x, y+10);
    XDrawString(theDisplay, w, theGC, x+5, y-5, str, strlen(str));
}


/****************************************************************************
*       Convert length to samples according to given xscale_units.
****************************************************************************/

to_samples( x )
float x ;
{
    int  samples ;

    switch ( xscale_units ) {
	case SAMPLES      :     samples = x ;
				break ;
	case SECONDS      :     samples = x * samplerate  ;
				break ;
	case MILLISECONDS :     samples = x * samplerate * 0.001 ;
				break ;
    }
    return samples ;
}


help ()
{
    printf ("\nx11plot: plot n points, read as binary shorts.\n");
    printf ("Usage: a) x11plot  [options]  filename1  [filename2 ... ]\n");
    printf ("       b) cat filename  |  x11plot  [options]\n");
    printf ("    where filename is an input stream of 16-bit binary numbers (shorts)\n");
    printf ("Options:\n");
    printf ("-S [int]      = Samplerate in Hz (default 20000).\n");
    printf ("-u [string]   = Units (s, ms, or default p (samples)).\n");
    printf ("\n");
    printf ("-n [int]      = Length plotted (default=%d samples).\n", DEFSCALE);
    printf ("-s [int]      = Offset from start of file (default=0 samples).\n");
    printf ("\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 ("-Y [int]      = Increment Y-origin for successive files (default=0).\n");
    printf ("\n");
    printf ("-v            = Suppress calibration.\n");
    printf ("-z            = Suppress zero-line.\n");
    printf ("-F [font]     = Font name (default=%s)\n", theFontString);
    exit (0);
}