Mercurial > hg > aim92
view 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 source
/* 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();