Mercurial > hg > aim92
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); + } + } +}