Mercurial > hg > aim92
comparison tools/x11play.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 * | |
3 * x11play -Animate successive plots of n points. | |
4 The points are read as binary shorts. | |
5 * Like x11plot, but plots successive blocks of n points | |
6 * on top of each other, rubbing out the previous plot, so | |
7 * as to form an "animated" sequence of plots. | |
8 * | |
9 * -Help: x11play -H | |
10 * -Usage, EG: | |
11 * fft -n128 -o120 file | x11play -n64 -y0 -c5000 | |
12 * Quit program with left mouse button. | |
13 * -Step-mode | |
14 * With a -S flag, single-step through frames using | |
15 * the mouse as follows: | |
16 * | |
17 * left - quit | |
18 * centre - freeze animation (successive centre | |
19 * buttons give single successive frames). | |
20 * right - continue animation | |
21 * | |
22 * Note: animation is slower in step-mode because | |
23 * XSynchronise has to be on. | |
24 ****************************************************************************/ | |
25 #include <stdio.h> | |
26 #include <math.h> | |
27 #include "x11coord.h" | |
28 | |
29 /**************************************************************************** | |
30 * Defaults | |
31 ****************************************************************************/ | |
32 #define UNSET (-9999) | |
33 | |
34 #define DEFAMPL 1000 | |
35 #define DEFSCALE 256 | |
36 | |
37 float argXd0=UNSET, argYd0=UNSET; | |
38 float argXd1=UNSET, argYd1=UNSET; | |
39 | |
40 /**************************************************************************** | |
41 * Input-file arguments | |
42 ****************************************************************************/ | |
43 int n = DEFSCALE; /* num points to read from file */ | |
44 int s = 0; /* start position in file */ | |
45 short summary= 0; /* Flag for method of block summary in downsample */ | |
46 short z = 1; /* Flag for drawing zero line */ | |
47 short stepmode=0; /* Flag for single-step mode */ | |
48 short overplot=0; /* Flag for overplot mode */ | |
49 short stepcount=0; | |
50 char DEFNAME[]="stdin"; | |
51 char *name=DEFNAME; | |
52 short *data; | |
53 XPoint *points; | |
54 | |
55 FILE *fp, *fopen(); | |
56 | |
57 /**************************************************************************** | |
58 * main | |
59 * The window is plotted when an expose event is (automatically) generated. | |
60 * The plotting routines are called from within the event monitor. | |
61 ****************************************************************************/ | |
62 main(argc, argv) | |
63 int argc ; | |
64 char *argv[] ; | |
65 { | |
66 Window w; | |
67 int npoints; | |
68 | |
69 while (--argc > 0 && **++argv == '-') | |
70 switch (*++*argv) { | |
71 case 'n': n = atoi(++*argv); break; | |
72 case 's': s = atoi(++*argv); break; | |
73 case 'x': argXd0 = atof(++*argv); break; | |
74 case 'y': argYd0 = atof(++*argv); break; | |
75 case 'c': argXd1 = atof(++*argv); break; | |
76 case 'a': argYd1 = atof(++*argv); break; | |
77 case 'b': summary = atoi(++*argv); break; | |
78 case 'z': z = 0; break; | |
79 case 'S': stepmode++; break; | |
80 case 'O': overplot++; break; | |
81 case 'F': theFontString = ++*argv; break; | |
82 case 'H': | |
83 default: help(); | |
84 } | |
85 | |
86 if (argXd0==UNSET) argXd0 = s; | |
87 if (argXd1==UNSET) argXd1 = n; | |
88 else argXd1 = argXd1-argXd0; /* ie, a range */ | |
89 if (argYd0==UNSET) { | |
90 if (argYd1==UNSET) argYd1 = 2*DEFAMPL; | |
91 else argYd1 = 2*argYd1; | |
92 argYd0 = argYd1/2; | |
93 } | |
94 else { | |
95 if (argYd1==UNSET) argYd1 = DEFAMPL+argYd0; | |
96 else argYd1 = argYd1+argYd0; | |
97 } | |
98 argYd0 = (-argYd0); | |
99 | |
100 if ((data = (short*) malloc(n * sizeof(short))) == NULL) | |
101 error("malloc out of space\n"); | |
102 if ((points = (XPoint*)malloc(n * sizeof(XPoint))) == NULL) | |
103 error("malloc out of space\n"); | |
104 | |
105 if (argc) { | |
106 /* Open data file */ | |
107 name = *argv; | |
108 if ((fp = fopen(name, "r")) == NULL) { | |
109 fprintf(stderr,"can't open %s\n", *argv); | |
110 exit(1); | |
111 } | |
112 } | |
113 else fp = stdin; | |
114 | |
115 /* Seek start of data in file */ | |
116 if (s > 0) seekstart(s,fp); | |
117 | |
118 set_window_parameters(PLOTXORG,PLOTYORG, PLOTWIDTH,PLOTHEIGHT); | |
119 set_bordered_box(10); | |
120 set_data_parameters(0,0, argXd0,argYd0, argXd1,argYd1); | |
121 xopen(); | |
122 xgc( 1, theFontString ) ; | |
123 w = xcreate(name, ButtonPressMask | ExposureMask); | |
124 init_xevent(w); | |
125 } | |
126 | |
127 | |
128 /**************************************************************************** | |
129 * Seek s points from current position in stream. | |
130 * This general seek works even when fp is stdin, unlike fseek. | |
131 ****************************************************************************/ | |
132 seekstart(s,fp) | |
133 int s; | |
134 FILE *fp; | |
135 { | |
136 int i; | |
137 short p; | |
138 | |
139 for (i=0 ; i<s && fread(&p, sizeof(short), 1, fp) ; i++) | |
140 ; | |
141 if (i<s) error("seek overshot end-of-file\n"); | |
142 } | |
143 | |
144 | |
145 /**************************************************************************** | |
146 * X11 Event Monitor. | |
147 * The window is plotted when an expose event is (automatically) generated. | |
148 * This routine catches the initial expose event to first draw the window. | |
149 * After this, the xevent_monitor is called from upsample, which is called | |
150 * from draw_plot. | |
151 ****************************************************************************/ | |
152 init_xevent(w) /* to catch initial expose event and draw first plot */ | |
153 Window w; | |
154 { | |
155 XEvent event; | |
156 | |
157 for ( ; ; ) { | |
158 XNextEvent(theDisplay,&event); | |
159 switch (event.type) { | |
160 case ButtonPress: | |
161 switch(event.xbutton.button) { | |
162 case Button1: /* Left */ | |
163 XDestroyWindow(theDisplay,w); | |
164 exit(0); | |
165 case Button2: /* Middle */ | |
166 case Button3: break; /* Right */ | |
167 default: | |
168 fprintf(stderr,"button %d not used\n", event.xbutton.button); | |
169 } | |
170 break; | |
171 case Expose: | |
172 if (event.xexpose.count == 0) { | |
173 draw_calibrated_box(w); | |
174 draw_plot(w); | |
175 } | |
176 break; | |
177 default: | |
178 fprintf(stderr,"event type %d not found\n", event.type); | |
179 } | |
180 } | |
181 } | |
182 | |
183 | |
184 xevent_monitor(w) | |
185 Window w; | |
186 { | |
187 XEvent event; | |
188 static short wait=1; | |
189 | |
190 if (!stepmode) wait=0; | |
191 do { | |
192 /* get next event provided one is on queue; don't wait otherwise */ | |
193 if (wait || XEventsQueued(theDisplay,QueuedAlready) > 0) { | |
194 XNextEvent(theDisplay,&event); | |
195 switch (event.type) { | |
196 case ButtonPress: | |
197 switch(event.xbutton.button) { | |
198 case Button1: /* Left */ | |
199 XDestroyWindow(theDisplay,w); | |
200 exit(0); | |
201 case Button2: /* Middle */ | |
202 if (stepmode) { | |
203 if (wait) single_shot(w,fp); | |
204 else wait=1; | |
205 } | |
206 break; | |
207 case Button3: if (stepmode) wait=0; break;/* Right */ | |
208 default: | |
209 fprintf(stderr,"button %d not used\n", event.xbutton.button); | |
210 } | |
211 break; | |
212 default: | |
213 fprintf(stderr,"event type %d not found\n", event.type); | |
214 } | |
215 } | |
216 } while (wait); | |
217 } | |
218 | |
219 | |
220 /**************************************************************************** | |
221 * Draw a calibrated box in a window and plot data inside it. | |
222 ****************************************************************************/ | |
223 draw_plot(w) | |
224 Window w; | |
225 { | |
226 int i, npoints; | |
227 | |
228 if (z) draw_Xaxis(w,0); /* Draw zero line */ | |
229 if (!overplot) XSetFunction(theDisplay,theGC,GXinvert); | |
230 if (stepmode) XSynchronize(theDisplay,True); | |
231 if (n <= pwidth()) npoints = upsample(w,fp); | |
232 else fprintf(stderr,"successive downsampling not implemented yet!\n"); | |
233 /* npoints = downsample(w,fp); */ | |
234 } | |
235 | |
236 | |
237 /**************************************************************************** | |
238 * Up and Down sampling. | |
239 ****************************************************************************/ | |
240 char stepcountstr[128]; | |
241 | |
242 upsample (w,fp) | |
243 Window w; | |
244 FILE *fp; | |
245 { | |
246 int i, x, j=0; | |
247 int lastx,lasty, X,Y; | |
248 short y, notfirst=0; | |
249 float res, incr, carry; | |
250 | |
251 res = (float)pwidth()/(n-1); /* resolution of plot */ | |
252 incr = res; /* x-value increment */ | |
253 x = 0; /* initial x-value */ | |
254 while (fread(&y, sizeof(short), 1, fp)) { | |
255 if (stepmode) { | |
256 if (stepcount > 0) supertopline(w,stepcountstr); | |
257 sprintf(stepcountstr,"%d", ++stepcount); | |
258 supertopline(w,stepcountstr); | |
259 } | |
260 lastx=pleft(); lasty=py(y); | |
261 carry = res - (int)res; | |
262 incr = res + carry; | |
263 x = (int)incr; | |
264 for (i=1 ; i<n && fread(&y, sizeof(short), 1, fp) ; i++) { | |
265 X = x+pleft(); | |
266 Y = py(y); | |
267 /* Plot only inside y-limits of box */ | |
268 if (Y > pbottom()) Y = pbottom(); | |
269 if (Y < ptop()) Y = ptop(); | |
270 | |
271 /* rub-out a segment of last plot */ | |
272 if (notfirst) | |
273 XDrawLine(theDisplay, w, theGC, points[i-1].x, points[i-1].y, points[i].x, points[i].y); | |
274 else notfirst=1; | |
275 /* draw a new segment for current plot */ | |
276 XDrawLine(theDisplay, w, theGC, lastx, lasty, X, Y); | |
277 | |
278 points[i-1].x = lastx; | |
279 points[i-1].y = lasty; | |
280 lastx = X; | |
281 lasty = Y; | |
282 | |
283 carry = incr - (int)incr; | |
284 incr = res + carry; | |
285 x += (int)incr; | |
286 } | |
287 points[i-1].x = lastx; | |
288 points[i-1].y = lasty; | |
289 /* if (XEventsQueued(theDisplay,QueuedAlready) > 0) */ | |
290 xevent_monitor(w); | |
291 } | |
292 } | |
293 | |
294 | |
295 single_shot (w,fp) | |
296 Window w; | |
297 FILE *fp; | |
298 { | |
299 int i, x, j=0; | |
300 int lastx,lasty, X,Y; | |
301 short y, notfirst=0; | |
302 float res, incr, carry; | |
303 | |
304 res = (float)pwidth()/(n-1); /* resolution of plot */ | |
305 incr = res; /* x-value increment */ | |
306 x = 0; /* initial x-value */ | |
307 if (fread(&y, sizeof(short), 1, fp)) { | |
308 if (stepmode) { | |
309 if (stepcount > 0) supertopline(w,stepcountstr); | |
310 sprintf(stepcountstr,"%d", ++stepcount); | |
311 supertopline(w,stepcountstr); | |
312 } | |
313 lastx=pleft(); lasty=py(y); | |
314 carry = res - (int)res; | |
315 incr = res + carry; | |
316 x = (int)incr; | |
317 for (i=1 ; i<n && fread(&y, sizeof(short), 1, fp) ; i++) { | |
318 X = x+pleft(); | |
319 Y = py(y); | |
320 /* Plot only inside y-limits of box */ | |
321 if (Y > pbottom()) Y = pbottom(); | |
322 if (Y < ptop()) Y = ptop(); | |
323 | |
324 /* rub-out a segment of last plot */ | |
325 if (notfirst) | |
326 XDrawLine(theDisplay, w, theGC, points[i-1].x, points[i-1].y, points[i].x, points[i].y); | |
327 else notfirst=1; | |
328 /* draw a new segment for current plot */ | |
329 XDrawLine(theDisplay, w, theGC, lastx, lasty, X, Y); | |
330 | |
331 points[i-1].x = lastx; | |
332 points[i-1].y = lasty; | |
333 lastx = X; | |
334 lasty = Y; | |
335 | |
336 carry = incr - (int)incr; | |
337 incr = res + carry; | |
338 x += (int)incr; | |
339 } | |
340 points[i-1].x = lastx; | |
341 points[i-1].y = lasty; | |
342 } | |
343 } | |
344 | |
345 | |
346 #define BLOCK 256 | |
347 float block; /* for averaging in downsample */ | |
348 | |
349 | |
350 downsample (w,fp) | |
351 Window w; | |
352 FILE *fp; | |
353 { | |
354 int i, x, j = 0; | |
355 short y; | |
356 float rate; | |
357 float res; | |
358 float incr; | |
359 float carry; | |
360 | |
361 rate = (float)n/pwidth(); | |
362 if ((block = rate) >= BLOCK) | |
363 error ("excessive downsampling; re-define BLOCK\n"); | |
364 | |
365 res = (float)pwidth()/(n-1); /* resolution of plot */ | |
366 incr = res; /* x-value increment */ | |
367 x = 0; /* initial x-value */ | |
368 for (i=0 ; i<n ; i++) { | |
369 if (incr >= 1.0) { | |
370 if (sample(&y, i, rate)) { | |
371 points[j].x = x+pleft(); | |
372 points[j].y = py(y); | |
373 | |
374 /* Plot only inside y-limits of box */ | |
375 if (points[j].y > pbottom()) points[j].y = pbottom(); | |
376 if (points[j].y < ptop()) points[j].y = ptop(); | |
377 j++; | |
378 } | |
379 } | |
380 carry = incr - (int)incr; | |
381 incr = res + carry; | |
382 x += (int)incr; | |
383 } | |
384 return j; | |
385 } | |
386 | |
387 sample (y, i, rate) | |
388 short *y; | |
389 int i; | |
390 float rate; | |
391 { | |
392 short average(); | |
393 float carry; | |
394 | |
395 if (block <= n-i) { | |
396 *y = average ((int)block, &data[i]); | |
397 carry = block - (int)block; | |
398 block = rate + carry; | |
399 return 1; | |
400 } | |
401 else | |
402 return 0; | |
403 } | |
404 | |
405 /* | |
406 short | |
407 average (block, p) | |
408 int block; | |
409 short p[]; | |
410 { | |
411 int i; | |
412 float sum = 0; | |
413 | |
414 for (i = 0 ; i < block ; i++) | |
415 sum += p[i]; | |
416 return (short)(sum / block); | |
417 } | |
418 */ | |
419 | |
420 short | |
421 average (block, p) | |
422 int block; | |
423 short p[]; | |
424 { | |
425 int i; | |
426 float sum = 0; | |
427 short MIN = 32000, MAX = 0; | |
428 | |
429 for (i = 0 ; i < block ; i++) { | |
430 sum += p[i]; | |
431 if (p[i] < MIN) MIN = p[i]; | |
432 if (p[i] > MAX) MAX = p[i]; | |
433 } | |
434 if (summary==0) { /* summary of block is largest extremal value */ | |
435 if (MAX >= (-MIN)) return MAX; /* summary of block is MAX value */ | |
436 else return MIN; /* summary of block is MIN value */ | |
437 } | |
438 if (summary == 1) return (p[0]); /* summary of block is sample value */ | |
439 return (short)(sum / block); /* summary of block is mean value */ | |
440 } | |
441 | |
442 | |
443 /**************************************************************************** | |
444 * Miscellaneous | |
445 ****************************************************************************/ | |
446 error(s) | |
447 { | |
448 fprintf(stderr,"%s",s); | |
449 exit(1); | |
450 } | |
451 | |
452 | |
453 help () | |
454 { | |
455 printf ("\nx11play: animated plot of sets of n points, read as binary shorts.\n"); | |
456 printf ("Usage: a) x11play [options] filename\n"); | |
457 printf (" b) cat filename | x11play [options]\n"); | |
458 printf (" where filename is an input stream of 16-bit binary numbers (shorts)\n"); | |
459 printf ("Options:\n"); | |
460 printf ("-n [int] = Number of points plotted (default=%d).\n", DEFSCALE); | |
461 printf ("-s [int] = Offset points from start of file (default=0).\n"); | |
462 printf ("-a [float] = Amplitude between zero-line and top of box (default=%d).\n", DEFAMPL); | |
463 printf ("-y [int] = Amplitude between zero-line and bottom of box (default=a).\n"); | |
464 printf ("-c [float] = Calibration at right end of x-axis (default=n+s).\n"); | |
465 printf ("-x [int] = Calibration at left end of x-axis (default=s).\n"); | |
466 printf ("-z = Suppress zero-line.\n"); | |
467 printf ("-b [0,1,2] = Method of block summary for down-sampling.\n"); | |
468 printf (" 0=MAX, 1=SAMPLE, 2=MEAN, (default=MAX).\n"); | |
469 printf ("-S = Step-mode, (centre-button=single-step, right-button=play).\n"); | |
470 printf ("-O = Over-plot successive plots of n points.\n"); | |
471 printf ("-F [font] = Font name (default=%s)\n", theFontString); | |
472 exit (0); | |
473 } | |
474 | |
475 |