Mercurial > hg > aim92
diff tools/x11coord.h @ 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.h Fri May 20 15:19:45 2011 +0100 @@ -0,0 +1,520 @@ +/* + Still to consider: + + A structure for a box-object, containing a complete set of internal + variables for one box. A routine could allocate a structure, call the + routines set_box_parameters() and set_data_parameters(), and return a ptr + to the structure. Now a set of #defines could take a structure pointer + (just as they currently often take a window ptr), and could call the + appropriate sub-routines using the internal variables for that box. + (The window could be a member of the structute too). + + With this, you could easily maintain a set of boxes, and plot anything + in any of them. But if you need ore than one window, then you'll need a + window structure too, (to hold window parameters for each window). + For example: + + struct st_window { + Window w; + int x,y; window origin wrt display + unsigned int width,height; window size + GC gc; + }; + + struct st_box { + struct st_window * pt; parent window + char *fname; file name for data + int n, s; num points and start point in file + ...all system variables... + }; + +*/ + + +/**************************************************************************** + + x11coord.h A file for inclusion into X11 plotting programs. + ---------- (See x11test.c for example). + + **************************************************************************** + +User parameters: +================ +1. Window parameters - Set size and position of a window on the display. + set_window_parameters(xorg,yorg, width,height) + int xorg,yorg Window origin (pixel coords of top-left wrt Display). + int width,height Window size (pixels). + +2. Box parameters - Set size and position of a box in a preset window. + a) set_box_parameters(xorg,yorg, width,height) + int xorg,yorg Box origin (pixel coords of bottom-left wrt window). + int width,height Box size (pixels). + b) set_bordered_box(bpc) + int bpc Box border (constant width) as %age of window size. + +3. Data parameters - Set area and location of data space to appear in box. + set_data_parameters(xp0,yp0, xd0,yd0, xrange,yrange) + int xp0,yp0 Plot origin (as a %age of box size from box origin). + float xd0,yd0 Data origin (data coords to appear under plot origin). + float xrange,yrange Data ranges (area of data space to appear under plot). + +Notes: +1. Pixel coordinates and sizes are ints. Data coordinates and sizes are floats. +2. Pixel coords refer to the X11 coord system which has origin (0,0) in the + top-left of each window. Data coords refer to the user coord system which + has its origin (0,0) in the bottom-left of each box. +3. The parameter initialization routines must be called in order, (window, + box, data), and must be done first, otherwise macros which use the system + variables will not work. As a minimum, you MUST do set_window_parameters(), + and this will give you a box the same size as the window, with origin in + the bottom-left, with data origin at the box origin, and data ranges the + same as pixels. +4. Although its true that set_window_parameters only sets window pixel sizes, + set_box_parameters only sets box pixel sizes, and set_data_parameters only + sets data sizes, the data sizes are somewhat dependent upon the pixel + sizes, and so if you change the window or box parameters during a program, + (eg, to resize a box), then you must re-initialize set_data_parameters at + the same time. (Call it again with the same initial arguments; it will + re-initialize internal parameters). + +User routines and macros: +========================= +Set system private parameters. +----------------------------- + set_window_parameters(xorg,yorg, width,height) + set_box_parameters(xorg,yorg, width,height) + set_bordered_box(bpc) + set_data_parameters(xp0,yp0, xd0,yd0, xrange,yrange) +Open connection and create window. +--------------------------------- + xopen() +Window xcreate(name, event_mask) +Convert coordinates. +------------------- +int px(x) +int py(y) +float xp(p) +float yp(p) +float xpc(pc) +float ypc(pc) +Return pixel coordinates. +----------------------- +int pleft() +int pright() +int pbottom() +int ptop() +int pwidth() +int pheight() +Return data coordinates. +----------------------- +float xleft() +float xright() +float ybottom() +float ytop() +float xwidth() +float yheight() +float xcentre() +float ycentre() +float Xjitter(x,p) +float Yjitter(y,p) +Test data coordinates. +--------------------- +bool Xinbox(x) +bool Yinbox(y) +bool inbox(x,y) +Draw and calibrate boxes and axes. +--------------------------------- + draw_Xaxis(w,yval) + calibrate_Xaxis(w,yval) + draw_Yaxis(w,xval) + calibrate_Yaxis(w,xval) + draw_box(w) + calibrate_box(w) + draw_calibrated_box(w) +Draw points, lines, and strings, etc.. +------------------------------------- + setLinewidth(width) + Point(w,x,y) + xPoint(w,x,y) + Line(w,x1,y1,x2,y2) + xLine(w,x1,y1,x2,y2) + String(w,x,y,string) + xString(w,x,y,string) + Cross(w,x,y) + xCross(w,x,y) + Dot(w,x,y,dotsize) + xDot(w,x,y,dotsize) +Text string parameters. +----------------------- + setFont("fontname") +int nlines() +int ncols() +Return pixel sizes based on current "theFont". +---------------------------------------------- +int max_charwidth() +int max_charheight() +int stringwidth(string) +int stringheight(string) +int linespacing() white space between lines. +int lineheight() total line (y-value) increment. +int colwidth() total character (x-value) increment. +int margin() white space at sides of page. +int headroom() white space at head and foot of page. +Return pixel coordinates. +------------------------- +int leftmargin() +int rightmargin() +int topmargin() +int bottommargin() +int line(i) +int col(j) +Draw text strings. +------------------ + topline(w,string) + bottomline(w,string) + lineString(w,string,i,j) + leftString(w,string,i) + rightString(w,string,i) + centreString(w,string,i) + supertopline(w,string) + + +Notes: +1. The user routines conventionally take data coordinate arguments. + To convert pixel coordinates to data, use the xp,yp macros. + +Development of coord system scaling transformations: +==================================================== +Internal variables (initialized by the `set' routines and used by the `px' +macros) are pixel coords and sizes, and refer to the X11 coord system: + + | _Xp0 | + +---------------+ + | | + + | _Xp1 | + +---------------------------+ + | | + (0,0) + -+- -+- +-------------------------------------------+ + | | |Window | + | _Yp1| | | + | | | _Wb | +_Yp0| -+- | (_Xp0,_Yp1) +-----------+ (_Xp1,_Yp1) | + | | |Box | | + | | | |_Hb | + | | | | | + -+- | (_Xp0,_Yp0) +-----------+ (_Xp1,_Yp0) | + | | + | | + | | + +-------------------------------------------+ + +Consider a box of width Wb pixels (on horizontal axis) and height Hb pixels +(on vertical axis). Let this box size represent data ranges xrange and yrange, +(corresponding to Wb and Hb respectively). Let the pixel origin and the data +origin be superimposed at (0,0) in the bottom-left corner. Then a data coord +(x,y) is transformed into a pixel coord by the scaling: + px(x) = x * Wb/xrange + py(y) = y * Hb/yrange + +If the data coordinate which we wish to appear at the plot origin is actually +(xd0,yd0), then the data origin must be shifted off the pixel origin, so that +the data coord (xd0,yd0) is represented by pixel coord (0,0). Hence: + px(x) = (x-xd0) * Wb/xrange + py(y) = (y-yd0) * Hb/yrange + +It is necessary to invert the y-axis so that pixel coords are consistent with +the X11 coord system, (with pixel origin in the top-left of a window and pixel +y-values which increase down the window). Let the box be positioned in the +top-left corner of its parent window, so that the X11 origin corresponds with +the top-left corner of the box. Then the y-axis is inverted by: + px(x) = (x-xd0) * Wb/xrange + py(y) = Hb - (y-yd0) * Hb/yrange + +In general, the box will be positioned within its parent window as in the +diagram above. The box is shifted into the window by an x-value Xp0 and a +y-value Yp1, and these must be added to any pixel coordinate: + px(x) = Xp0 + (x-xd0) * Wb/xrange + py(y) = Yp1 + Hb - (y-yd0) * Hb/yrange + +Although Yp0 is the y-value at the bottom of the box, at its default origin, +note that Yp0>Yp1, since y-values increase down the window in the X11 pixel +coordinate system. +Finally, we may want the user origin of the box to be somewhere other than the +bottom-left corner, (Eg, scatter plots often have the user origin in the +centre of the plot; time-waveform plot often have the origin half-way up the +left side of the plot). To place the user origin at a pixel coordinate of +(xshift,yshift), we add xshift and subtract yshift from the transformed pixel +coordinates. (We subtract yshift since the transformed pixel coord is in the +X11 coord system). So we have: + px(x) = Xp0 + xshift + (x-xd0) * Wb/xrange + py(y) = Yp1 + Hb - yshift - (y-yd0) * Hb/yrange + +Grouping terms we have: + px(x) = Xp0 + xshift - xd0*Wb/xrange + x*Wb/xrange + py(y) = Yp1 + Hb - yshift + yd0*Hb/yrange - y*Hb/yrange + +Now substituting: + xoffset = Xp0 + xshift - xd0*Wb/xrange ; xscale = Wb/xrange + yoffset = Yp1 + Hb - yshift + yd0*Hb/yrange ; yscale = Hb/yrange +We have: + px(x) = xoffset + x * xscale + py(y) = yoffset - y * yscale + +The inverse transformations xp(p) and yp(p) are just the inverse of these. + +A typical program might be as follows: +------------------------------------- + ------------------------------------------------------------------ + |#include <stdio.h> | + |#include <math.h> | + | | + |#include "x11coord.h" | + | | + | | + |main() | + |{ | + | Window w; | + | ..... | + | | + | set_window_parameters(100,85, 775,775); | + | set_bordered_box(10); | + | set_data_parameters(50,50, 0,0, 2.0,2.0); | + | | + | xopen(); | + | w = xcreate("test", ButtonPressMask | ExposureMask); | + | xevent_monitor(w); | + |} | + | | + | | + |xevent_monitor(w) | + |Window w; | + |{ | + | XEvent event; | + | | + | for ( ; ; ) { | + | XNextEvent(theDisplay,&event); | + | switch (event.type) { | + | .... | + | case ButtonPress: | + | switch(event.xbutton.button) { | + | case Button1: | + | XDestroyWindow(theDisplay,w); | + | return; | + | case Button2: | + | .... | + | } | + | break; | + | case Expose: | + | if (event.xexpose.count == 0) { | + | draw_calibrated_box(w); | + | plot(w); | + | } | + | break; | + | .... | + | } | + | } | + |} | + | | + ------------------------------------------------------------------ +The purpose of the xevent_monitor is to loop endlessly and keep the program +running while the window is displayed. The window vanishes when the monitor +is quit using (in this example) the left mouse button. +Note that you let all plotting routines be called when an expose-event has +been caught. This is not just so that the screen re-draws itself when exposed, +but also to avoid data at the start of the plot going missing. +If you don't set up for expose-events, but try to plot data as soon as the +window is created, then it turns out that you tend to lose the first few bytes +of plot data. The correct way is to plot data when the window is exposed. +The window-creation and mapping process generates an expose event +automatically and, when caught by the event monitor, this causes the window to +be first plotted. + + +*****************************************************************************/ +#include <X11/X.h> /* /usr/include/X11/X.h */ +#include <X11/Xlib.h> /* /usr/include/X11/Xlib.h */ + + +static char defFontString[] = "fixed" , *theFontString = defFontString ; + + +/**************************************************************************** +* Defaults for some standard window sizes +****************************************************************************/ +#define FULLXORG 5 /* Full screen size */ +#define FULLYORG 90 +#define FULLWIDTH 1000 +#define FULLHEIGHT 750 + +#define A4XORG 190 /* A4 size */ +#define A4YORG 85 +#define A4WIDTH 620 +#define A4HEIGHT 760 + +#define PLOTXORG 100 /* Rectangular plotting area */ +#define PLOTYORG 155 +#define PLOTWIDTH 800 +#define PLOTHEIGHT 600 + +#define BOXXORG 100 /* Square box */ +#define BOXYORG 85 +#define BOXWIDTH 775 +#define BOXHEIGHT 775 + +/**************************************************************************** +* Macros for pixel-data transformation +****************************************************************************/ +/* pixel coord from data coord */ +#define px(x) ( (int)(_xoffset + (x) * _xscale) ) +#define py(y) ( (int)(_yoffset - (y) * _yscale) ) +/* data coord from pixel coord */ +#define xp(p) ( (float)(((p) - _xoffset) / _xscale) ) +#define yp(p) ( (float)((_yoffset - (p)) / _yscale) ) +/* data coord from a %age of data range */ +#define xpc(pc) ( ((xleft()+xright())*pc) / 100 ) +#define ypc(pc) ( ((ybottom()+ytop())*pc) / 100 ) +/* data coord of box centre */ +#define xcentre() xpc(50) +#define ycentre() ypc(50) +/* pixel limits of box (note that ptop() < pbottom() ). */ +#define pleft() (_Xp0) +#define pright() (_Xp1) +#define pbottom() (_Yp0) +#define ptop() (_Yp1) +#define pwidth() (_Wb) +#define pheight() (_Hb) +/* data limits of box */ +#define xleft() xp(_Xp0) +#define xright() xp(_Xp1) +#define ybottom() yp(_Yp0) +#define ytop() yp(_Yp1) +#define xwidth() xp(_Wb) +#define yheight() yp(_Hb) +/* test if data argument is in box */ +#define Xinbox(x) ( (xleft()<=x && x<=xright()) ? 1 : 0 ) +#define Yinbox(y) ( (ybottom()<=y && y<=ytop()) ? 1 : 0 ) +#define inbox(x,y) ( (Xinbox(x) && Yinbox(y)) ? 1 : 0 ) +/* jitter data value (ie move by a given pixel distance) */ +#define Xjitter(x,p) ( xp(px(x)+(p)) ) +#define Yjitter(y,p) ( yp(py(y)+(p)) ) + +/**************************************************************************** +* Macros for routines (using preset system parameters) +****************************************************************************/ +/* Xaxes: yval is a data value at which to place a horizontal axis. */ +/* For example: 0 (zero line), ybottom() (box-bottom), ytop() (box-top). */ +#define draw_Xaxis(w,yval) if (Yinbox(yval)) axis(w, _Xp0,_Xp1, py(yval),'x') +#define calibrate_Xaxis(w,yval) calibrate_Axis(w, _Xp0,_Xp1, _Xd0,_Xd1, py(yval),'x') + +/* Yaxes: xval is a data value at which to place a vertical axis. */ +/* For example: 0 (zero line), xleft() (box-left), xright() (box-right). */ +#define draw_Yaxis(w,xval) if (Xinbox(xval)) axis(w, _Yp0,_Yp1, px(xval),'y') +#define calibrate_Yaxis(w,xval) calibrate_Axis(w, _Yp0,_Yp1, _Yd0,_Yd1, px(xval),'y') + +#define draw_box(w) box(w, _Xp0,_Yp0, _Xp1,_Yp1) +#define calibrate_box(w) calibrate_Box(w, _Xp0,_Yp0, _Xp1,_Yp1, _Xd0,_Yd0, _Xd1,_Yd1) +#define draw_calibrated_box(w) draw_box(w); calibrate_box(w) + +#define xcreate(name,mask) xCreate(name,mask, _xorg,_yorg, _width,_height) + +/**************************************************************************** +* Macros for standard X11 commands +****************************************************************************/ +#define Point(w,x,y) XDrawPoint(theDisplay,w,theGC,px(x),py(y)) +#define Line(w,x1,y1,x2,y2) XDrawLine(theDisplay,w,theGC,px(x1),py(y1),px(x2),py(y2)) +#define String(w,x,y,string) XDrawString(theDisplay, w, theGC, px(x),py(y), string, strlen(string)) + +#define Cross(w,x,y) XDrawLine(theDisplay,w,theGC,px(x)-10,py(y),px(x)+10,py(y)); XDrawLine(theDisplay,w,theGC,px(x),py(y)-10,px(x),py(y)+10) + +#define xPoint(w,x,y) if (inbox(x,y)) Point(w,x,y) +#define xLine(w,x1,y1,x2,y2) if (inbox(x1,y1) && inbox(x2,y2)) Line(w,x1,y1,x2,y2) +#define xString(w,x,y,string) if (inbox(x,y)) String(w,x,y,string) + +#define xCross(w,x,y) if (inbox(x,y)) Cross(w,x,y) +#define xDot(w,x,y,dotsize) if (inbox(x,y)) Dot(w,x,y,dotsize) + +/* Max width and height (pixels) of chars in current font, (ref 6-17, 6-19) */ +#define max_charwidth() ( theFont->max_bounds.rbearing - theFont->min_bounds.lbearing ) +#define max_charheight() ( theFont->max_bounds.ascent + theFont->max_bounds.descent ) +/* Number of lines and cols (chars) of current font which fit into box */ +#define linespacing() ( (theFont->max_bounds.descent)>>1 ) +#define lineheight() ( max_charheight()+linespacing() ) +#define colwidth() ( max_charwidth() ) +#define nlines() ( pheight() / lineheight() ) +#define ncols() ( pwidth() / colwidth() ) +#define topline(w,string) lineString(w,string,1,1) +#define bottomline(w,string) lineString(w,string,nlines(),1) +#define margin() ( theFont->max_bounds.lbearing + theFont->max_bounds.rbearing ) +#define headroom() ( theFont->max_bounds.ascent ) +#define leftmargin() ( pleft() + margin() ) +#define rightmargin() ( pright() - margin() ) +#define topmargin() ( ptop() + headroom() ) +#define bottommargin() ( pbottom() - headroom() ) +#define line(i) ( topmargin() + (i-1)*lineheight() ) +#define col(j) ( leftmargin() + (j-1)*colwidth() ) +#define lineString(w,string,i,j) ( XDrawString(theDisplay,w,theGC,col(j),line(i),string,strlen(string)) ) +#define leftString(w,string,i) ( XDrawString(theDisplay,w,theGC,leftmargin(),line(i),string,strlen(string)) ) +#define rightString(w,string,i) ( XDrawString(theDisplay,w,theGC,rightmargin()-stringwidth(string),line(i),string,strlen(string)) ) +#define centreString(w,string,i) ( XDrawString(theDisplay,w,theGC,(pwidth()-stringwidth(string))>>1,line(i),string,strlen(string)) ) +#define supertopline(w,string) ( XDrawString(theDisplay,w,theGC,col(1),ptop()-max_charheight()-headroom(),string,strlen(string)) ) + + +/**************************************************************************** +* Window parameters (X11-specific). +****************************************************************************/ +Display *theDisplay; +int theScreen; /* screen_number */ +int theWidth; /* horizontal size, in pixels */ +int theHeight; /* vertical size, in pixels */ +unsigned long theForeground; /* lines, text, and border pixel value */ +unsigned long theBackground; /* background pixel value */ +GC theGC; /* graphics context */ +XFontStruct *theFont; /* current font used to print text */ +unsigned long theBlack; /* pixel value for black */ +unsigned long theWhite; /* pixel value for white */ + +/**************************************************************************** +* System (global) variables +*****************************************************************************/ +int _xorg, _yorg; /* Window origin (pixel coords top-left wrt Display)*/ +int _width, _height;/* Window size (pixels). */ + +int _Xp0, _Yp0; /* Box origin (pixel coords at bottom-left) */ +int _Xp1, _Yp1; /* Box limits (pixel coords at top-right) */ +int _Wb, _Hb; /* Box size (pixels). */ + +float _Xd0, _Yd0; /* Box origin (data coords at bottom-left) */ +float _Xd1, _Yd1; /* Box limits (data coords at top-right) */ +float _xrange,_yrange;/* Box size (data ranges). */ + +int _xshift,_yshift;/* Plot origin (pixel coords from box origin) */ +float _xd0, _yd0; /* Data coords fixed at plot origin */ + +float _xoffset,_yoffset; +float _xscale, _yscale; + +/**************************************************************************** +* Functions (in x11coord.c) +*****************************************************************************/ +extern set_window_parameters(); +extern set_box_parameters(); +extern set_bordered_box(); +extern set_data_parameters(); +extern xopen(); +extern GC initGC(); +extern setLinewidth(); +extern setFont(); +extern Window xCreate(); +extern axis(); +extern box(); +extern calibrate_Axis(); +extern calibrate_Box(); +extern plotX(); +extern plotY(); +extern int stringwidth(); +extern int stringheight(); +extern calibrate(); +extern Dot(); +