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