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();