Mercurial > hg > aim92
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:5242703e91d3 |
---|---|
1 /**************************************************************************** | |
2 * Routines for x11coord package. | |
3 ****************************************************************************/ | |
4 | |
5 #include <stdio.h> | |
6 #include <math.h> | |
7 #include "x11coord.h" | |
8 | |
9 /**************************************************************************** | |
10 * Set parameters for data-pixel conversion macros | |
11 ****************************************************************************/ | |
12 /* Initialize parameters for size and position of window on screen */ | |
13 set_window_parameters(xorg,yorg, width,height) | |
14 int xorg,yorg; /* Pixel coords of window origin wrt theDisplay origin */ | |
15 int width,height; /* Size of window (in pixels) */ | |
16 { | |
17 _xorg = xorg; | |
18 _yorg = yorg; | |
19 _width = width; | |
20 _height = height; | |
21 set_bordered_box((int)0); /* defaults */ | |
22 set_data_parameters((int)0,(int)0, (float)0,(float)0, (float)width,(float)height); | |
23 } | |
24 | |
25 /* Initialize parameters for size and position of box in preset window */ | |
26 set_box_parameters(xorg,yorg, width,height) | |
27 int xorg,yorg; /* Pixel coords of box origin wrt bottom-left of window */ | |
28 int width,height; /* Size of window (in pixels) */ | |
29 { | |
30 _Xp0 = xorg; | |
31 _Yp0 = _height - yorg; | |
32 _Xp1 = xorg + width; | |
33 _Yp1 = _height - (yorg + height); | |
34 _Wb = _Xp1 - _Xp0; | |
35 _Hb = _Yp0 - _Yp1; | |
36 set_data_parameters((int)0,(int)0, (float)0,(float)0, (float)width,(float)height); | |
37 } | |
38 | |
39 | |
40 /* Initialize parameters for size and position of box in preset window, */ | |
41 /* given the width of the border as a %age of the window size on any side */ | |
42 set_bordered_box(bpc) | |
43 int bpc; | |
44 { | |
45 int xborder, yborder, Wb, Hb; | |
46 | |
47 xborder = (_width * bpc) / 100; | |
48 yborder = (_height * bpc) / 100; | |
49 Wb = _width - 2*xborder; | |
50 Hb = _height - 2*yborder; | |
51 set_box_parameters(xborder,yborder, Wb,Hb); | |
52 } | |
53 | |
54 /* Initialize parameters for area and location of data-space to appear in box */ | |
55 set_data_parameters(xp0,yp0, xd0,yd0, xrange,yrange) | |
56 int xp0,yp0; /* Box origin shift as a percentage of box width,height */ | |
57 float xd0,yd0; /* Data coord to appear under box origin. */ | |
58 float xrange,yrange;/* Data ranges (corresponding to box width and height). */ | |
59 { | |
60 _xrange = xrange; | |
61 _yrange = yrange; | |
62 _xshift = (_Wb * xp0)/100; | |
63 _yshift = (_Hb * yp0)/100; | |
64 _xd0 = xd0; | |
65 _yd0 = yd0; | |
66 _Xd0 = xd0 - _xrange*((float)_xshift/_Wb); | |
67 _Yd0 = yd0 - _yrange*((float)_yshift/_Hb); | |
68 _Xd1 = xd0 + (_xrange - _xrange*((float)_xshift/_Wb)); | |
69 _Yd1 = yd0 + (_yrange - _yrange*((float)_yshift/_Hb)); | |
70 | |
71 _xoffset = _Xp0 + _xshift - _xd0*_Wb/_xrange ; | |
72 _yoffset = _Yp1 + _Hb - _yshift + _yd0*_Hb/_yrange ; | |
73 _xscale = _Wb/_xrange; | |
74 _yscale = _Hb/_yrange; | |
75 } | |
76 | |
77 | |
78 /**************************************************************************** | |
79 * Creating windows, initializing GC and Font, etc.. (X11 specific) | |
80 ****************************************************************************/ | |
81 xopen() | |
82 { | |
83 | |
84 if ((char *)getenv("DISPLAY") == (char *)0 ) { | |
85 fprintf(stderr,"DISPLAY not set\n"); | |
86 exit(1); | |
87 } | |
88 if ((theDisplay = XOpenDisplay(NULL)) == NULL) { | |
89 fprintf(stderr,"Can't open display %s\n", getenv("DISPLAY")); | |
90 exit(1); | |
91 } | |
92 theScreen = XDefaultScreen(theDisplay); | |
93 theForeground = theBlack = XBlackPixel(theDisplay,theScreen); /* Black lines, text, and borders */ | |
94 theBackground = theWhite = XWhitePixel(theDisplay,theScreen); /* White background */ | |
95 theWidth = XDisplayWidth(theDisplay,theScreen); | |
96 theHeight = XDisplayHeight(theDisplay,theScreen); | |
97 theGC = initGC() ; | |
98 } | |
99 | |
100 | |
101 /* | |
102 eg: xgc( 1, "times_roman14" ) ; | |
103 */ | |
104 | |
105 xgc( linewidth, fontstr ) | |
106 int linewidth ; | |
107 char *fontstr ; | |
108 { | |
109 setLinewidth( linewidth ) ; | |
110 theFont = (XFontStruct *)0; | |
111 if ( setFont( fontstr ) == NULL ) { | |
112 fprintf( stderr,"can't load font %s\n", fontstr ) ; | |
113 exit( 1 ) ; | |
114 } | |
115 } | |
116 | |
117 | |
118 GC initGC() | |
119 { | |
120 GC gc; | |
121 | |
122 gc = XDefaultGC(theDisplay, theScreen); | |
123 /* Set foreground and background pixel values (ie colours) */ | |
124 XSetState(theDisplay, gc, theForeground, theBackground, GXcopy, AllPlanes); | |
125 return gc; | |
126 } | |
127 | |
128 | |
129 | |
130 setLinewidth(width) /* Set line width, used by XDrawLine commands */ | |
131 int width; | |
132 { | |
133 XGCValues gcvalues; | |
134 | |
135 gcvalues.line_width = width; | |
136 XChangeGC(theDisplay, theGC, GCLineWidth, &gcvalues); | |
137 } | |
138 | |
139 | |
140 setFont(fontname) /* Free last theFont (unless null) and load new font */ | |
141 char *fontname; /* return null if can't load font */ | |
142 { | |
143 if (theFont != (XFontStruct *)0) XFreeFont(theDisplay,theFont); | |
144 if ((theFont = XLoadQueryFont(theDisplay, fontname)) == NULL) | |
145 return 0 ; | |
146 XSetFont(theDisplay, theGC, theFont->fid); | |
147 return 1 ; | |
148 } | |
149 | |
150 | |
151 Window xCreate(name, event_mask, xorg,yorg, width,height) | |
152 char *name; | |
153 long event_mask; | |
154 int xorg,yorg, width,height; | |
155 { | |
156 Window w; | |
157 | |
158 if ((w = XCreateSimpleWindow(theDisplay, XDefaultRootWindow(theDisplay), | |
159 xorg, yorg, (unsigned)width, (unsigned)height, 1, | |
160 theForeground, theBackground)) == (Window)0 ) { | |
161 fprintf(stderr,"can't create window\n"); | |
162 exit(1); | |
163 } | |
164 XStoreName(theDisplay, w, name); | |
165 XSelectInput(theDisplay, w, event_mask); | |
166 XMapWindow(theDisplay, w); | |
167 XFlush(theDisplay); | |
168 return w; | |
169 } | |
170 | |
171 | |
172 /**************************************************************************** | |
173 * Drawing axes and boxes in a given window w. | |
174 ****************************************************************************/ | |
175 axis(w, p0,p1, ploc,axis) | |
176 Window w; | |
177 int p0,p1; /* First and last axis pixel distances, relative to parent */ | |
178 int ploc; /* Location of axis (orthogonal pixel dist from parent org) */ | |
179 char axis; /* Orientation of axis ('x' or 'y') */ | |
180 { | |
181 if (axis=='x') XDrawLine(theDisplay, w, theGC, p0,ploc, p1,ploc); | |
182 if (axis=='y') XDrawLine(theDisplay, w, theGC, ploc,p0, ploc,p1); | |
183 } | |
184 | |
185 box(w, x0,y0, x1,y1) /* draw rectangular box */ | |
186 Window w; | |
187 int x0,y0, x1,y1; | |
188 { | |
189 axis(w, y0,y1, x0,'y'); | |
190 axis(w, y0,y1, x1,'y'); | |
191 axis(w, x0,x1, y0,'x'); | |
192 axis(w, x0,x1, y1,'x'); | |
193 } | |
194 | |
195 /**************************************************************************** | |
196 * Calibrating axes and boxes in a given window w. | |
197 ****************************************************************************/ | |
198 struct mark_struct { | |
199 int type; /* type= HALFMARK or FULLMARK */ | |
200 int position; /* mark position on screen relative to the parent system */ | |
201 char label[16]; /* ASCII label of real plot value (FULLMARK only) */ | |
202 }; | |
203 | |
204 #define NMARKS 150 /* size of array of calibration marks */ | |
205 #define FULLMARK 10 /* Box calibration marks */ | |
206 #define HALFMARK 5 | |
207 | |
208 calibrate_Axis(w, p0,p1, d0,d1, ploc,axis) | |
209 Window w; | |
210 int p0,p1; /* First and last axis pixel distances, relative to parent */ | |
211 float d0,d1; /* First and last axis data values */ | |
212 int ploc; /* Location of axis (orthogonal pixel dist from parent org) */ | |
213 char axis; /* Orientation of axis ('x' or 'y') */ | |
214 { | |
215 int n; | |
216 struct mark_struct mark[NMARKS]; | |
217 | |
218 if ((n = calibrate(mark, p0,p1, d0,d1)) < 0) { | |
219 fprintf(stderr,"mark array out of space, increase NMARKS\n"); | |
220 exit(1); | |
221 } | |
222 if (axis=='x') plotX(w, ploc, mark, n); | |
223 if (axis=='y') plotY(w, ploc, mark, n); | |
224 } | |
225 | |
226 | |
227 calibrate_Box(w, xp0,yp0, xp1,yp1, xd0,yd0, xd1,yd1) | |
228 Window w; | |
229 int xp0,yp0, xp1,yp1; | |
230 float xd0,yd0, xd1,yd1; | |
231 { | |
232 calibrate_Axis(w, xp0,xp1, xd0,xd1, yp0,'x'); | |
233 calibrate_Axis(w, yp0,yp1, yd0,yd1, xp0,'y'); | |
234 } | |
235 | |
236 | |
237 plotX(w, Y, mark, n) /* Plot calibration marks along an X axis */ | |
238 Window w; | |
239 int Y; | |
240 struct mark_struct mark[]; | |
241 int n; | |
242 { | |
243 int i, H, W; | |
244 int X; | |
245 | |
246 for (i = 0 ; i < n ; i++) { | |
247 X = mark[i].position; | |
248 XDrawLine(theDisplay, w, theGC, X, Y, X, Y+mark[i].type); | |
249 if (mark[i].type == FULLMARK) /* Label calibration value */ | |
250 { | |
251 W = stringwidth(mark[i].label) / 2; /* Shift label left by half width */ | |
252 H=20; /* Shift label down a bit */ | |
253 XDrawString(theDisplay, w, theGC, X-W, Y+H, mark[i].label, strlen(mark[i].label)); | |
254 } | |
255 } | |
256 } | |
257 | |
258 plotY(w, X, mark, n) /* Plot calibration marks along a Y axis */ | |
259 Window w; | |
260 int X; | |
261 struct mark_struct mark[]; | |
262 int n; | |
263 { | |
264 int i, H, W; | |
265 int Y; | |
266 | |
267 for (i = 0 ; i < n ; i++) { | |
268 Y = mark[i].position; | |
269 XDrawLine(theDisplay, w, theGC, X, Y, X-mark[i].type, Y); | |
270 if (mark[i].type == FULLMARK) { /* Label calibration value */ | |
271 W = stringwidth(mark[i].label) + 10;/* Shift label left by width */ | |
272 H=5; /* Shift label down a bit */ | |
273 XDrawString(theDisplay, w, theGC, X-W, Y+H, mark[i].label, strlen(mark[i].label)); | |
274 } | |
275 } | |
276 } | |
277 | |
278 /**************************************************************************** | |
279 * Macros used by calibration routines | |
280 ****************************************************************************/ | |
281 #define rem(x,y) fabs((x) - (y)*(int)((x)/(y))) /* real remainder */ | |
282 #define rem2(x,y) fabs((x) - (y)*(int)((x)/(y)-0.5)) /* real remainder for -ve x */ | |
283 #define round(x) ((x >= 0) ? ((int)(x+0.5)) : ((int)(x-0.5))) | |
284 #define min(x,y) ((x < y) ? x : y) | |
285 #define EPS 1.0e-5 | |
286 | |
287 /**************************************************************************** | |
288 * Calibrate one axis. | |
289 * Fill the given array "mark" with mark structs, and return the number of | |
290 * marks, or -1 indicating that the mark array is full, (and NMARKS should | |
291 * be increased). | |
292 * Each mark struct in the array gives the mark position (in pixels relative | |
293 * to the given first and last mark positions), the mark type (being HALFMARK | |
294 * or FULLMARK), and a label string (for each FULLMARK only). | |
295 * Arguments are as follows: | |
296 * p0,p1 first and last screen positions in pixels, relative to the parent | |
297 * window, (used to calculate mark positions on the screen). | |
298 * d0,d1 first and last data values (used to calculate axis labels). | |
299 *****************************************************************************/ | |
300 calibrate(mark, p0, p1, d0, d1) | |
301 struct mark_struct mark[]; | |
302 int p0,p1; /* first and last axis pixel distances, relative to parent */ | |
303 float d0,d1; /* first and last axis data values */ | |
304 { | |
305 int position, plotsize, nmarks=0; | |
306 float div, hdiv, offset, hoffset, value, hvalue; | |
307 float range, scalefactor, maxerror, nextvalue, lastvalue; | |
308 float label, real_division (), sig_figs (); | |
309 float tmp; | |
310 | |
311 if (d0 > d1) { /* swap to get +ve range */ | |
312 tmp = d1; d1 = d0; d0 = tmp; | |
313 tmp = p1; p1 = p0; p0 = tmp; | |
314 } | |
315 | |
316 plotsize = p1-p0; /* screen size */ | |
317 range = d1-d0; /* real plot range */ | |
318 | |
319 div = real_division (range); | |
320 hdiv = div/10; /* Halfmarks every 10th labelled division (fullmark) */ | |
321 | |
322 /* calculate real offset and hoffset of 1st fullmark and halfmark */ | |
323 /* respectively, from first (ie min) real value d0. */ | |
324 if (d0 == 0) | |
325 { | |
326 offset = hoffset = 0; | |
327 } | |
328 else | |
329 { | |
330 if (d0 > 0) | |
331 { | |
332 offset = div - rem(d0,div); | |
333 hoffset = hdiv - rem(d0,hdiv); | |
334 } | |
335 else /* (d0 < 0) */ | |
336 { | |
337 offset = rem2(d0,div); | |
338 hoffset = rem2(d0,hdiv); | |
339 } | |
340 } | |
341 | |
342 value = d0 + offset; /* real value of 1st fullmark */ | |
343 hvalue = d0 + hoffset; /* real value of 1st halfmark */ | |
344 | |
345 scalefactor = (float)plotsize/range; /* scale factor between real range and plotted range */ | |
346 maxerror = hdiv/2; | |
347 lastvalue = d0+range+maxerror; | |
348 nextvalue = value-maxerror; | |
349 | |
350 /* Plot halfmarks up to 1st fullmark */ | |
351 | |
352 for ( ; hvalue < nextvalue ; hvalue += hdiv) | |
353 { | |
354 position = (int)((hvalue-d0) * scalefactor); /* actual plotted position (in plot range) */ | |
355 setmark (&mark[nmarks], HALFMARK, p0+position, NULL); | |
356 if (++nmarks >= NMARKS) return -1; | |
357 } | |
358 | |
359 /* Loop plotting fullmarks, with halfmarks between each */ | |
360 | |
361 for ( ; value < lastvalue ; value += div) | |
362 { | |
363 position = (int)((value-d0) * scalefactor); /* actual plotted position */ | |
364 label = sig_figs (value, range); | |
365 setmark (&mark[nmarks], FULLMARK, p0+position, label); | |
366 if (++nmarks >= NMARKS) return -1; | |
367 | |
368 /* Loop plotting halfmarks between each fullmark */ | |
369 | |
370 nextvalue = value+div-maxerror; | |
371 if (nextvalue > lastvalue) nextvalue = lastvalue; | |
372 for (hvalue = value+hdiv ; hvalue < nextvalue ; hvalue += hdiv) | |
373 { | |
374 position = (int)((hvalue-d0) * scalefactor); /* actual plotted position */ | |
375 setmark (&mark[nmarks], HALFMARK, p0+position, NULL); | |
376 if (++nmarks >= NMARKS) return -1; | |
377 } | |
378 } | |
379 return nmarks; | |
380 } | |
381 | |
382 | |
383 float | |
384 real_division (range) /* Return recomended division between fullmarks on real scale */ | |
385 float range; | |
386 { | |
387 int power; | |
388 float scalefactor, scaled_range, div; | |
389 | |
390 if (range <= 0) { | |
391 fprintf(stderr,"range must be positive\n"); | |
392 exit(1); | |
393 } | |
394 | |
395 if (range >= 1.0) | |
396 power = -(int)(log10(range) + EPS); | |
397 else | |
398 power = -(int)(log10(range) - 1 + EPS); | |
399 scalefactor = pow (10.0, (float)power); | |
400 | |
401 scaled_range = range * scalefactor; /* scaled_range is (1 <= range <= 9.9999) */ | |
402 | |
403 /* Set division size (in scaled_range) between given breaks in the scale */ | |
404 | |
405 if (scaled_range < 1.5) div = 0.1; | |
406 else if (scaled_range < 2.5) div = 0.2; | |
407 else if (scaled_range < 5.0) div = 0.5; | |
408 else div = 1.0; | |
409 | |
410 return (div/scalefactor); /* return div scaled down to real range */ | |
411 } | |
412 | |
413 | |
414 float | |
415 sig_figs (value, range) /* Round value to 2 sig figs on the scale of the range */ | |
416 float value, range; | |
417 { | |
418 int power; | |
419 float scalefactor, scaled_value; | |
420 | |
421 if (range >= 1.0) | |
422 power = 1-(int)(log10(range) + EPS); | |
423 else | |
424 power = 1-(int)(log10(range) - 1 + EPS); | |
425 scalefactor = pow (10.0, (float)power); | |
426 | |
427 scaled_value = value * scalefactor; /* scaled_value is in range (10 <= range <= 99.999) */ | |
428 value = round(scaled_value); | |
429 | |
430 return (value/scalefactor); | |
431 } | |
432 | |
433 /* Fill one mark struct with the mark position, type, and label */ | |
434 setmark (mark, mark_type, x, x1) | |
435 struct mark_struct *mark; | |
436 int mark_type; | |
437 int x; /* position */ | |
438 float x1; /* value of label */ | |
439 { | |
440 if ((mark->type = mark_type) == FULLMARK) | |
441 labelstring(mark->label, x1); | |
442 mark->position = x; | |
443 } | |
444 | |
445 /* Return with str containing an appropriate ASCII string of the given value */ | |
446 labelstring(str, value) | |
447 char *str; | |
448 float value; | |
449 { | |
450 float decval; /* decimal part of a number */ | |
451 | |
452 decval = value - (int)value; | |
453 if (value < 0) decval = -decval; | |
454 if (value > -EPS && value < EPS) sprintf(str,"0" ); | |
455 else if (fabs(value) >= 10000) sprintf(str,"%g", value); | |
456 else if (decval <= EPS) sprintf(str,"%d", (int)value); | |
457 else if (decval <= 0.001) sprintf(str,"%.4f", value); | |
458 else if (decval <= 0.01) sprintf(str,"%.3f", value); | |
459 else if (decval <= 0.1) sprintf(str,"%.2f", value); | |
460 else sprintf(str,"%.1f", value); | |
461 } | |
462 | |
463 /**************************************************************************** | |
464 Text printing routines. | |
465 ****************************************************************************/ | |
466 /* The origin for a char is an x-value of `lbearing' to the left of the */ | |
467 /* left-most char ink, and a y-value between the `ascent' and the */ | |
468 /* `descent', (ie along an underline), (ref 6-20). */ | |
469 /* The `margin' is an ad-hoc idea. */ | |
470 | |
471 /* Return the width in pixels of the given string, using the current font */ | |
472 stringwidth(str) | |
473 char *str; | |
474 { | |
475 int width; | |
476 | |
477 width = XTextWidth(theFont, str, strlen(str)); | |
478 return width; | |
479 } | |
480 | |
481 /* Return the height in pixels of the given string, using the current font */ | |
482 stringheight(str) | |
483 char *str; | |
484 { | |
485 XCharStruct stringinfo; /* ref Xlib 6-17 */ | |
486 int dr, fa, fd; | |
487 short asc, desc, width; | |
488 int height; | |
489 | |
490 XTextExtents(theFont, str, strlen(str), &dr,&fa,&fd, &stringinfo); | |
491 asc = stringinfo.ascent; /* max of char ascents in string */ | |
492 desc = stringinfo.descent; /* max of char descents in string */ | |
493 width = stringinfo.width; /* sum of char widths across string */ | |
494 height = asc+desc; /* max height over all chars */ | |
495 return height; | |
496 } | |
497 | |
498 | |
499 /**************************************************************************** | |
500 Misc routines. | |
501 ****************************************************************************/ | |
502 /* Plot a dot at data coord (x,y). Dotsize=0,1,2,3,.., and size 0 is empty */ | |
503 Dot(w,x,y,dotsize) | |
504 Window w; | |
505 float x,y; | |
506 int dotsize; | |
507 { | |
508 int d, X,Y; | |
509 | |
510 if ((d=dotsize-1) >= 0) { | |
511 if (d==0) /* dotsize = 1 */ | |
512 Point(w, x,y); | |
513 else { /* dotsize > 1 */ | |
514 for (X=(-d) ; X<=d ; X++) | |
515 for (Y=(-d) ; Y<=d ; Y++) | |
516 XDrawPoint(theDisplay,w,theGC,px(x)+X,py(y)+Y); | |
517 } | |
518 } | |
519 } |