diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/x11coord.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,519 @@
+/****************************************************************************
+*       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);
+	}
+    }
+}