view tools/x11coord.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
/****************************************************************************
*       Routines for x11coord package.
****************************************************************************/

#include <stdio.h>
#include <math.h>
#include "x11coord.h"

/****************************************************************************
*   Set parameters for data-pixel conversion macros
****************************************************************************/
/* Initialize parameters for size and position of window on screen */
set_window_parameters(xorg,yorg, width,height)
int xorg,yorg;      /* Pixel coords of window origin wrt theDisplay origin */
int width,height;   /* Size of window (in pixels) */
{
    _xorg   = xorg;
    _yorg   = yorg;
    _width  = width;
    _height = height;
    set_bordered_box((int)0);   /* defaults */
    set_data_parameters((int)0,(int)0, (float)0,(float)0, (float)width,(float)height);
}

/* Initialize parameters for size and position of box in preset window */
set_box_parameters(xorg,yorg, width,height)
int xorg,yorg;      /* Pixel coords of box origin wrt bottom-left of window */
int width,height;   /* Size of window (in pixels) */
{
    _Xp0    = xorg;
    _Yp0    = _height - yorg;
    _Xp1    = xorg + width;
    _Yp1    = _height - (yorg + height);
    _Wb     = _Xp1 - _Xp0;
    _Hb     = _Yp0 - _Yp1;
    set_data_parameters((int)0,(int)0, (float)0,(float)0, (float)width,(float)height);
}


/* Initialize parameters for size and position of box in preset window,   */
/* given the width of the border as a %age of the window size on any side */
set_bordered_box(bpc)
int bpc;
{
    int  xborder, yborder, Wb, Hb;

    xborder = (_width *  bpc) / 100;
    yborder = (_height * bpc) / 100;
    Wb      = _width -  2*xborder;
    Hb      = _height - 2*yborder;
    set_box_parameters(xborder,yborder, Wb,Hb);
}

/* Initialize parameters for area and location of data-space to appear in box */
set_data_parameters(xp0,yp0, xd0,yd0, xrange,yrange)
int   xp0,yp0;      /* Box origin shift as a percentage of box width,height */
float xd0,yd0;      /* Data coord to appear under box origin.               */
float xrange,yrange;/* Data ranges (corresponding to box width and height). */
{
    _xrange = xrange;
    _yrange = yrange;
    _xshift = (_Wb * xp0)/100;
    _yshift = (_Hb * yp0)/100;
    _xd0    = xd0;
    _yd0    = yd0;
    _Xd0    = xd0 - _xrange*((float)_xshift/_Wb);
    _Yd0    = yd0 - _yrange*((float)_yshift/_Hb);
    _Xd1    = xd0 + (_xrange - _xrange*((float)_xshift/_Wb));
    _Yd1    = yd0 + (_yrange - _yrange*((float)_yshift/_Hb));

    _xoffset = _Xp0       + _xshift - _xd0*_Wb/_xrange ;
    _yoffset = _Yp1 + _Hb - _yshift + _yd0*_Hb/_yrange ;
    _xscale  = _Wb/_xrange;
    _yscale  = _Hb/_yrange;
}


/****************************************************************************
*       Creating windows, initializing GC and Font,  etc..   (X11 specific)
****************************************************************************/
xopen()
{

    if ((char *)getenv("DISPLAY") == (char *)0 )  {
	fprintf(stderr,"DISPLAY not set\n");
	exit(1);
    }
    if ((theDisplay = XOpenDisplay(NULL)) == NULL)  {
	fprintf(stderr,"Can't open display %s\n", getenv("DISPLAY"));
	exit(1);
    }
    theScreen = XDefaultScreen(theDisplay);
    theForeground = theBlack = XBlackPixel(theDisplay,theScreen);  /* Black lines, text, and borders */
    theBackground = theWhite = XWhitePixel(theDisplay,theScreen);  /* White background */
    theWidth = XDisplayWidth(theDisplay,theScreen);
    theHeight = XDisplayHeight(theDisplay,theScreen);
    theGC = initGC() ;
}


/*
eg: xgc( 1, "times_roman14" ) ;
*/

xgc( linewidth, fontstr )
int   linewidth ;
char *fontstr   ;
{
    setLinewidth( linewidth ) ;
    theFont = (XFontStruct *)0;
    if ( setFont( fontstr ) == NULL ) {
	fprintf( stderr,"can't load font %s\n", fontstr ) ;
	exit( 1 ) ;
    }
}


GC initGC()
{
    GC  gc;

    gc = XDefaultGC(theDisplay, theScreen);
    /* Set foreground and background pixel values (ie colours) */
    XSetState(theDisplay, gc, theForeground, theBackground, GXcopy, AllPlanes);
    return gc;
}



setLinewidth(width)     /* Set line width, used by XDrawLine commands */
int  width;
{
    XGCValues  gcvalues;

    gcvalues.line_width = width;
    XChangeGC(theDisplay, theGC, GCLineWidth, &gcvalues);
}


setFont(fontname)   /* Free last theFont (unless null) and load new font */
char *fontname;     /* return null if can't load font */
{
    if (theFont != (XFontStruct *)0) XFreeFont(theDisplay,theFont);
    if ((theFont = XLoadQueryFont(theDisplay, fontname)) == NULL)
	return 0 ;
    XSetFont(theDisplay, theGC, theFont->fid);
    return 1 ;
}


Window  xCreate(name, event_mask, xorg,yorg, width,height)
char *name;
long  event_mask;
int   xorg,yorg, width,height;
{
    Window w;

    if ((w = XCreateSimpleWindow(theDisplay, XDefaultRootWindow(theDisplay),
			   xorg, yorg, (unsigned)width, (unsigned)height, 1,
				     theForeground, theBackground)) == (Window)0 ) {
	fprintf(stderr,"can't create window\n");
	exit(1);
    }
    XStoreName(theDisplay, w, name);
    XSelectInput(theDisplay, w, event_mask);
    XMapWindow(theDisplay, w);
    XFlush(theDisplay);
    return w;
}


/****************************************************************************
* Drawing axes and boxes in a given window w.
****************************************************************************/
axis(w, p0,p1, ploc,axis)
Window w;
int    p0,p1;   /* First and last axis pixel distances, relative to parent */
int    ploc;    /* Location of axis (orthogonal pixel dist from parent org) */
char   axis;    /* Orientation of axis ('x' or 'y') */
{
    if (axis=='x')  XDrawLine(theDisplay, w, theGC, p0,ploc, p1,ploc);
    if (axis=='y')  XDrawLine(theDisplay, w, theGC, ploc,p0, ploc,p1);
}

box(w, x0,y0, x1,y1)    /* draw rectangular box */
Window w;
int    x0,y0, x1,y1;
{
    axis(w, y0,y1, x0,'y');
    axis(w, y0,y1, x1,'y');
    axis(w, x0,x1, y0,'x');
    axis(w, x0,x1, y1,'x');
}

/****************************************************************************
* Calibrating axes and boxes in a given window w.
****************************************************************************/
struct mark_struct {
    int    type;        /* type= HALFMARK or FULLMARK */
    int    position;    /* mark position on screen relative to the parent system */
    char   label[16];   /* ASCII label of real plot value (FULLMARK only) */
};

#define NMARKS      150 /* size of array of calibration marks */
#define FULLMARK    10  /* Box calibration marks */
#define HALFMARK    5

calibrate_Axis(w, p0,p1, d0,d1, ploc,axis)
Window w;
int    p0,p1;   /* First and last axis pixel distances, relative to parent */
float  d0,d1;   /* First and last axis data values */
int    ploc;    /* Location of axis (orthogonal pixel dist from parent org) */
char   axis;    /* Orientation of axis ('x' or 'y') */
{
    int     n;
    struct  mark_struct mark[NMARKS];

    if ((n = calibrate(mark, p0,p1, d0,d1)) < 0) {
	fprintf(stderr,"mark array out of space, increase NMARKS\n");
	exit(1);
    }
    if (axis=='x')  plotX(w, ploc, mark, n);
    if (axis=='y')  plotY(w, ploc, mark, n);
}


calibrate_Box(w, xp0,yp0, xp1,yp1, xd0,yd0, xd1,yd1)
Window  w;
int     xp0,yp0, xp1,yp1;
float   xd0,yd0, xd1,yd1;
{
    calibrate_Axis(w, xp0,xp1, xd0,xd1, yp0,'x');
    calibrate_Axis(w, yp0,yp1, yd0,yd1, xp0,'y');
}


plotX(w, Y, mark, n)    /* Plot calibration marks along an X axis */
Window w;
int    Y;
struct mark_struct mark[];
int    n;
{
    int   i, H, W;
    int   X;

    for (i = 0 ; i < n ; i++) {
	X = mark[i].position;
	XDrawLine(theDisplay, w, theGC, X, Y, X, Y+mark[i].type);
	if (mark[i].type == FULLMARK)      /* Label calibration value */
	{
	    W = stringwidth(mark[i].label) / 2; /* Shift label left by half width */
	    H=20;                               /* Shift label down a bit */
	    XDrawString(theDisplay, w, theGC, X-W, Y+H, mark[i].label, strlen(mark[i].label));
	}
    }
}

plotY(w, X, mark, n)    /* Plot calibration marks along a Y axis */
Window w;
int    X;
struct mark_struct mark[];
int    n;
{
    int   i, H, W;
    int   Y;

    for (i = 0 ; i < n ; i++) {
	Y = mark[i].position;
	XDrawLine(theDisplay, w, theGC, X, Y, X-mark[i].type, Y);
	if (mark[i].type == FULLMARK) {    /* Label calibration value */
	    W = stringwidth(mark[i].label) + 10;/* Shift label left by width */
	    H=5;                                /* Shift label down a bit */
	    XDrawString(theDisplay, w, theGC, X-W, Y+H, mark[i].label, strlen(mark[i].label));
	}
    }
}

/****************************************************************************
*       Macros used by calibration routines
****************************************************************************/
#define rem(x,y)    fabs((x) - (y)*(int)((x)/(y)))      /* real remainder */
#define rem2(x,y)   fabs((x) - (y)*(int)((x)/(y)-0.5))  /* real remainder for -ve x */
#define round(x)    ((x >= 0) ? ((int)(x+0.5)) : ((int)(x-0.5)))
#define min(x,y)    ((x < y) ? x : y)
#define EPS         1.0e-5

/****************************************************************************
* Calibrate one axis.
* Fill the given array "mark" with mark structs, and return the number of
*   marks, or -1 indicating that the mark array is full, (and NMARKS should
*   be increased).
* Each mark struct in the array gives the mark position (in pixels relative
*   to the given first and last mark positions), the mark type (being HALFMARK
*   or FULLMARK), and a label string (for each FULLMARK only).
* Arguments are as follows:
*   p0,p1   first and last screen positions in pixels, relative to the parent
*           window, (used to calculate mark positions on the screen).
*   d0,d1   first and last data values (used to calculate axis labels).
*****************************************************************************/
calibrate(mark, p0, p1, d0, d1)
struct mark_struct mark[];
int    p0,p1;   /* first and last axis pixel distances, relative to parent */
float  d0,d1;   /* first and last axis data values */
{
    int   position, plotsize, nmarks=0;
    float div, hdiv, offset, hoffset, value, hvalue;
    float range, scalefactor, maxerror, nextvalue, lastvalue;
    float label, real_division (), sig_figs ();
    float tmp;

    if (d0 > d1) {      /* swap to get +ve range */
	tmp = d1; d1 = d0; d0 = tmp;
	tmp = p1; p1 = p0; p0 = tmp;
    }

    plotsize = p1-p0;   /* screen size     */
    range    = d1-d0;   /* real plot range */

    div = real_division (range);
    hdiv = div/10;      /* Halfmarks every 10th labelled division (fullmark) */

    /* calculate real offset and hoffset of 1st fullmark and halfmark */
    /* respectively, from first (ie min) real value d0.               */
    if (d0 == 0)
    {
	offset = hoffset = 0;
    }
    else
    {
	if (d0 > 0)
	{
	    offset = div - rem(d0,div);
	    hoffset = hdiv - rem(d0,hdiv);
	}
	else    /* (d0 < 0) */
	{
	    offset = rem2(d0,div);
	    hoffset = rem2(d0,hdiv);
	}
    }

    value = d0 + offset;       /* real value of 1st fullmark */
    hvalue = d0 + hoffset;     /* real value of 1st halfmark */

    scalefactor = (float)plotsize/range;    /* scale factor between real range and plotted range */
    maxerror = hdiv/2;
    lastvalue = d0+range+maxerror;
    nextvalue = value-maxerror;

    /* Plot halfmarks up to 1st fullmark */

    for (  ; hvalue < nextvalue ; hvalue += hdiv)
    {
	position = (int)((hvalue-d0) * scalefactor);   /* actual plotted position (in plot range) */
	setmark (&mark[nmarks], HALFMARK, p0+position, NULL);
	if (++nmarks >= NMARKS) return -1;
    }

    /* Loop plotting fullmarks, with halfmarks between each */

    for (  ; value < lastvalue ; value += div)
    {
	position = (int)((value-d0) * scalefactor);    /* actual plotted position */
	label = sig_figs (value, range);
	setmark (&mark[nmarks], FULLMARK, p0+position, label);
	if (++nmarks >= NMARKS) return -1;

	/* Loop plotting halfmarks between each fullmark */

	nextvalue = value+div-maxerror;
	if (nextvalue > lastvalue) nextvalue = lastvalue;
	for (hvalue = value+hdiv ; hvalue < nextvalue ; hvalue += hdiv)
	{
	    position = (int)((hvalue-d0) * scalefactor);   /* actual plotted position */
	    setmark (&mark[nmarks], HALFMARK, p0+position, NULL);
	    if (++nmarks >= NMARKS) return -1;
	}
    }
    return nmarks;
}


float
real_division (range)   /* Return recomended division between fullmarks on real scale */
float range;
{
    int   power;
    float scalefactor, scaled_range, div;

    if (range <= 0) {
	fprintf(stderr,"range must be positive\n");
	exit(1);
    }

    if (range >= 1.0)
	power = -(int)(log10(range) + EPS);
    else
	power = -(int)(log10(range) - 1 + EPS);
    scalefactor = pow (10.0, (float)power);

    scaled_range = range * scalefactor; /* scaled_range is (1 <= range <= 9.9999) */

    /* Set division size (in scaled_range) between given breaks in the scale */

    if      (scaled_range < 1.5) div = 0.1;
    else if (scaled_range < 2.5) div = 0.2;
    else if (scaled_range < 5.0) div = 0.5;
    else                         div = 1.0;

    return (div/scalefactor);   /* return div scaled down to real range */
}


float
sig_figs (value, range) /* Round value to 2 sig figs on the scale of the range */
float value, range;
{
    int   power;
    float scalefactor, scaled_value;

    if (range >= 1.0)
	power = 1-(int)(log10(range) + EPS);
    else
	power = 1-(int)(log10(range) - 1 + EPS);
    scalefactor = pow (10.0, (float)power);

    scaled_value = value * scalefactor; /* scaled_value is in range (10 <= range <= 99.999) */
    value = round(scaled_value);

    return (value/scalefactor);
}

/* Fill one mark struct with the mark position, type, and label */
setmark (mark, mark_type, x, x1)
struct mark_struct *mark;
int   mark_type;
int   x;                /* position */
float x1;               /* value of label */
{
    if ((mark->type = mark_type) == FULLMARK)
	labelstring(mark->label, x1);
    mark->position = x;
}

/* Return with str containing an appropriate ASCII string of the given value */
labelstring(str, value)
char  *str;
float  value;
{
    float decval;       /* decimal part of a number */

    decval = value - (int)value;
    if (value < 0) decval = -decval;
    if (value > -EPS && value < EPS)    sprintf(str,"0"             );
    else if (fabs(value) >= 10000)      sprintf(str,"%g",      value);
    else if (decval <= EPS)             sprintf(str,"%d", (int)value);
    else if (decval <= 0.001)           sprintf(str,"%.4f",    value);
    else if (decval <= 0.01)            sprintf(str,"%.3f",    value);
    else if (decval <= 0.1)             sprintf(str,"%.2f",    value);
    else                                sprintf(str,"%.1f",    value);
}

/****************************************************************************
	Text printing routines.
****************************************************************************/
/* The origin for a char is an x-value of `lbearing' to the left of the    */
/*  left-most char ink, and a y-value between the `ascent' and the         */
/*  `descent', (ie along an underline), (ref 6-20).                        */
/* The `margin' is an ad-hoc idea.                                         */

/* Return the width in pixels of the given string, using the current font */
stringwidth(str)
char *str;
{
    int width;

    width = XTextWidth(theFont, str, strlen(str));
    return width;
}

/* Return the height in pixels of the given string, using the current font */
stringheight(str)
char *str;
{
    XCharStruct stringinfo;     /* ref Xlib 6-17 */
    int   dr, fa, fd;
    short asc, desc, width;
    int   height;

    XTextExtents(theFont, str, strlen(str), &dr,&fa,&fd, &stringinfo);
    asc   = stringinfo.ascent;          /* max of char ascents in string */
    desc  = stringinfo.descent;         /* max of char descents in string */
    width = stringinfo.width;           /* sum of char widths across string */
    height = asc+desc;                  /* max height over all chars  */
    return height;
}


/****************************************************************************
	Misc routines.
****************************************************************************/
/* Plot a dot at data coord (x,y). Dotsize=0,1,2,3,.., and size 0 is empty */
Dot(w,x,y,dotsize)
Window w;
float  x,y;
int    dotsize;
{
    int d, X,Y;

    if ((d=dotsize-1) >= 0) {
	if (d==0)           /* dotsize = 1 */
	    Point(w, x,y);
	else {              /* dotsize > 1 */
	    for (X=(-d) ; X<=d ; X++)
		for (Y=(-d) ; Y<=d ; Y++)
		    XDrawPoint(theDisplay,w,theGC,px(x)+X,py(y)+Y);
	}
    }
}