1 
2 /*
3  * Copyright 1998 - 2004 Graeme W. Gill
4  * All rights reserved.
5  *
6  * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
7  * see the License.txt file for licencing details.
8  */
9 
10 /* This is a simple 2d graph plotter that runs on MSWindows/OSX/X11 */
11 /* The code is in three sections, one for each GUI environment. */
12 /* (Perhaps common code could be consolidated ?) */
13 
14 
15 /*
16  * TTBD:
17  *
18  *		Allow for a window title for each plot.
19  *
20  *		Put all state information in plot_info (window handles etc.)
21  *      Create thread to handle events, so it updates correctly.
22  *		(Will have to lock plot info updates or ping pong them);
23  *		Have call to destroy window.
24  *		(Could then move to having multiple instances of plot).
25  *
26  *    OS X Cocoa code doesn't get window focus. No idea why.
27  *
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #ifdef UNIX
35 #include <unistd.h>
36 #endif
37 #include <math.h>
38 #include "numlib.h"
39 #include "plot.h"
40 //#ifdef STANDALONE_TEST
41 #include "ui.h"
42 //#endif /* STANDALONE_TEST */
43 
44 #undef DODEBUG				/* Print error messages & progress reports */
45 //#define STANDALONE_TEST	/* Defined by build script */
46 
47 #define NTICK 10
48 #define LTHICK 1.2			/* Plot line thickness */
49 #define ILTHICK ((int)(LTHICK+0.5))		/* Integer line thickness */
50 //#define ILTHICK 2
51 #undef CROSSES		/* Mark input points with crosses */
52 
53 #define DEFWWIDTH  500
54 #define DEFWHEIGHT 500
55 
56 /* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */
57 /* Brown = Y7, Orange = Y8, Grey = Y9, Magenta = Y10  */
58 
59 double nicenum(double x, int round);
60 
61 #define MXGPHS	10		/* Number of graphs with common X axis */
62 
63 /* Colors of the graphs */
64 static int gcolors[MXGPHS][3] = {
65 	{   0,   0,   0},	/* Black */
66 	{ 210,  30,   0},	/* Red */
67 	{   0, 200,  90},	/* Green */
68 	{   0,  10, 255},	/* Blue */
69 	{ 200, 200,   0},	/* Yellow */
70 	{ 220,   0, 255},	/* Purple */
71 	{ 136,  86,  68},	/* Brown */
72 	{ 248,  95,   0},	/* Orange */
73 	{ 160, 160, 160},	/* Grey */
74 	{ 220, 30,  220}	/* Magenta */
75 };
76 
77 /* Information defining plot */
78 /* There is one global instance of this. */
79 struct _plot_info {
80 	void *cx;				/* Other Context */
81 
82 	int flags;				/* Flags */
83 	int dowait;				/* Wait for user key if > 0, wait for n secs if < 0 */
84 	double ratio;			/* Aspect ratio of window, X/Y */
85 
86 	/* Plot point information */
87 	double mnx, mxx, mny, mxy;		/* Extrema of values to be plotted */
88 	int graph;						/* NZ if graph, Z if vectors */
89 	int revx;						/* reversed X axis */
90 
91 	double *x1, *x2;
92 	double *yy[MXGPHS];				/* y1 - y10 */
93 	char **ntext;
94 	int n;
95 
96 	double *x7, *y7;
97 	plot_col *mcols;
98 	char **mtext;
99 	int m;
100 
101 	double *x8, *y8, *x9, *y9;
102 	plot_col *ocols;
103 	int o;
104 
105 	/* Plot instance information */
106 	int sx,sy;			/* Screen offset */
107 	int sw,sh;			/* Screen width and height */
108 	double scx, scy;	/* Scale from input values to screen pixels */
109 
110 	}; typedef struct _plot_info plot_info;
111 
112 /* Global to transfer info to window callback */
113 static plot_info pd;
114 
115 #define PLOTF_NONE           0x0000
116 #define PLOTF_GRAPHCROSSES   0x0001			/* Plot crosses at each point on the graphs */
117 #define PLOTF_VECCROSSES     0x0002			/* Plot crosses at the end of x1,y1 -> x2,y2 */
118 
119 /* Declaration of superset */
120 static int do_plot_imp(
121 	int flags,
122     double xmin, double xmax, double ymin, double ymax,	/* Bounding box */
123 	double ratio,	/* Aspect ratio of window, X/Y, 1.0 = nominal */
124 	int dowait,		/* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
125 	double *x1, double *x2,
126 	double *yy[MXGPHS], char **ntext,
127 	int n,
128 	double *x7, double *y7, plot_col *mcols, char **mtext,
129     int m,
130 	double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
131 	int o
132 );
133 
134 
135 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
136 
137 /* Public routines */
138 /* Plot up to 3 graphs. Wait for key */
139 /* return 0 on success, -1 on error */
140 /* If n is -ve, reverse the X axis */
141 int
do_plot(double * x,double * y1,double * y2,double * y3,int n)142 do_plot(
143 double *x,
144 double *y1,	/* Up to 3 graphs */
145 double *y2,
146 double *y3,
147 int n) {
148 	int i, j;
149 	double xmin, xmax, ymin, ymax;
150 	double *yy[MXGPHS];
151 
152 	for (j = 0; j < MXGPHS; j++)
153 		yy[j] = NULL;
154 
155 	yy[0] = y1;
156 	yy[1] = y2;
157 	yy[2] = y3;
158 
159 	/* Determine min and max dimensions of plot */
160 	xmin = ymin = 1e6;
161 	xmax = ymax = -1e6;
162 
163 	for (i = 0; i < n; i++) {
164 		if (xmin > x[i])
165 			xmin = x[i];
166 		if (xmax < x[i])
167 			xmax = x[i];
168 
169 		for (j = 0; j < MXGPHS; j++) {
170 			if (yy[j] != NULL) {
171 				if (ymin > yy[j][i])
172 					ymin = yy[j][i];
173 				if (ymax < yy[j][i])
174 					ymax = yy[j][i];
175 			}
176 		}
177 	}
178 
179 	/* Work out scale factors */
180 	if ((xmax - xmin) == 0.0)
181 		xmax += 0.5, xmin -= 0.5;
182 	if ((ymax - ymin) == 0.0)
183 		ymax += 0.5, ymin -= 0.5;
184 
185 	return do_plot_imp(PLOTF_NONE,
186 	                   xmin, xmax, ymin, ymax, 1.0, 1,
187 	                   x, NULL, yy, NULL, n,
188 	                   NULL, NULL, NULL, NULL, 0,
189 	                   NULL, NULL, NULL, NULL, NULL, 0);
190 }
191 
192 /* Public routines */
193 /* Plot up to 3 graphs + crosses. Wait for key */
194 /* return 0 on success, -1 on error */
195 /* If n is -ve, reverse the X axis */
196 int
do_plot_p(double * x,double * y1,double * y2,double * y3,int n,double * x4,double * y4,int m)197 do_plot_p(
198 double *x,
199 double *y1,	/* Up to 3 graphs */
200 double *y2,
201 double *y3,
202 int n,
203 double *x4, double *y4,		/* And crosses */
204 int m) {
205 	int i, j;
206 	double xmin, xmax, ymin, ymax;
207 	double *yy[MXGPHS];
208 
209 	for (j = 0; j < MXGPHS; j++)
210 		yy[j] = NULL;
211 
212 	yy[0] = y1;
213 	yy[1] = y2;
214 	yy[2] = y3;
215 
216 	/* Determine min and max dimensions of plot */
217 	xmin = ymin = 1e6;
218 	xmax = ymax = -1e6;
219 
220 	for (i = 0; i < n; i++) {
221 		if (xmin > x[i])
222 			xmin = x[i];
223 		if (xmax < x[i])
224 			xmax = x[i];
225 
226 		for (j = 0; j < MXGPHS; j++) {
227 			if (yy[j] != NULL) {
228 				if (ymin > yy[j][i])
229 					ymin = yy[j][i];
230 				if (ymax < yy[j][i])
231 					ymax = yy[j][i];
232 			}
233 		}
234 	}
235 
236 	for (i = 0; i < m; i++) {
237 		if (x4 != NULL) {
238 			if (xmin > x4[i])
239 				xmin = x4[i];
240 			if (xmax < x4[i])
241 				xmax = x4[i];
242 		}
243 		if (y4 != NULL) {
244 			if (ymin > y4[i])
245 				ymin = y4[i];
246 			if (ymax < y4[i])
247 				ymax = y4[i];
248 		}
249 	}
250 
251 	/* Work out scale factors */
252 	if ((xmax - xmin) == 0.0)
253 		xmax += 0.5, xmin -= 0.5;
254 	if ((ymax - ymin) == 0.0)
255 		ymax += 0.5, ymin -= 0.5;
256 
257 	return do_plot_imp(PLOTF_NONE,
258 	                   xmin, xmax, ymin, ymax, 1.0, 1,
259 	                   x, NULL, yy, NULL, n,
260 	                   x4, y4, NULL, NULL, m ,
261 	                   NULL, NULL, NULL, NULL, NULL, 0);
262 }
263 
264 /* Plot up to 3 graphs with specified window size. */
265 /* if dowait > 0, wait for user key */
266 /* if dowait < 0, wait for no seconds */
267 /* If xmax > xmin, use as x scale, else auto. */
268 /* If ymax > ymin, use as y scale, else auto. */
269 /* ratio is window X / Y */
270 /* return 0 on success, -1 on error */
271 /* If n is -ve, reverse the X axis */
272 int
do_plot_x(double * x,double * y1,double * y2,double * y3,int n,int dowait,double pxmin,double pxmax,double pymin,double pymax,double ratio)273 do_plot_x(
274 double *x,
275 double *y1,
276 double *y2,
277 double *y3,
278 int n,
279 int dowait,
280 double pxmin,
281 double pxmax,
282 double pymin,
283 double pymax,
284 double ratio
285 ) {
286 	int i, j;
287 	double xmin, xmax, ymin, ymax;
288 	double *yy[MXGPHS];
289 
290 	for (j = 0; j < MXGPHS; j++)
291 		yy[j] = NULL;
292 
293 	yy[0] = y1;
294 	yy[1] = y2;
295 	yy[2] = y3;
296 
297 	/* Determine min and max dimensions of plot */
298 	xmin = ymin = 1e6;
299 	xmax = ymax = -1e6;
300 
301 	for (i = 0; i < n; i++) {
302 		if (xmin > x[i])
303 			xmin = x[i];
304 		if (xmax < x[i])
305 			xmax = x[i];
306 
307 		for (j = 0; j < MXGPHS; j++) {
308 			if (yy[j] != NULL) {
309 				if (ymin > yy[j][i])
310 					ymin = yy[j][i];
311 				if (ymax < yy[j][i])
312 					ymax = yy[j][i];
313 			}
314 		}
315 	}
316 
317 	/* Work out scale factors */
318 	if ((xmax - xmin) == 0.0)
319 		xmax += 0.5, xmin -= 0.5;
320 	if ((ymax - ymin) == 0.0)
321 		ymax += 0.5, ymin -= 0.5;
322 
323 	if (pxmax > pxmin) {
324 		xmax = pxmax;
325 		xmin = pxmin;
326 	}
327 	if (pymax > pymin) {
328 		ymax = pymax;
329 		ymin = pymin;
330 	}
331 
332 	return do_plot_imp(PLOTF_NONE,
333 	                   xmin, xmax, ymin, ymax, ratio, dowait,
334 	                   x, NULL, yy, NULL, n,
335 	                   NULL, NULL, NULL, NULL, 0,
336 	                   NULL, NULL, NULL, NULL, NULL, 0);
337 }
338 
339 /* Public routines */
340 /* Plot up to 6 graphs. Wait for a key */
341 /* return 0 on success, -1 on error */
342 /* If n is -ve, reverse the X axis */
343 int
do_plot6(double * x,double * y1,double * y2,double * y3,double * y4,double * y5,double * y6,int n)344 do_plot6(
345 double *x,	/* X coord */
346 double *y1,	/* Black */
347 double *y2,	/* Red */
348 double *y3,	/* Green */
349 double *y4,	/* Blue */
350 double *y5,	/* Yellow */
351 double *y6,	/* Purple */
352 int n) {	/* Number of values */
353 	int i, j;
354 	double xmin, xmax, ymin, ymax;
355 	int nn = abs(n);
356 	double *yy[MXGPHS];
357 
358 	for (j = 0; j < MXGPHS; j++)
359 		yy[j] = NULL;
360 
361 	yy[0] = y1;
362 	yy[1] = y2;
363 	yy[2] = y3;
364 	yy[3] = y4;
365 	yy[4] = y5;
366 	yy[5] = y6;
367 
368 	/* Determine min and max dimensions of plot */
369 	xmin = ymin = 1e6;
370 	xmax = ymax = -1e6;
371 
372 	for (i = 0; i < nn; i++) {
373 		if (xmin > x[i])
374 			xmin = x[i];
375 		if (xmax < x[i])
376 			xmax = x[i];
377 
378 		for (j = 0; j < MXGPHS; j++) {
379 			if (yy[j] != NULL) {
380 				if (ymin > yy[j][i])
381 					ymin = yy[j][i];
382 				if (ymax < yy[j][i])
383 					ymax = yy[j][i];
384 			}
385 		}
386 	}
387 
388 	/* Work out scale factors */
389 	if ((xmax - xmin) == 0.0)
390 		xmax += 0.5, xmin -= 0.5;
391 	if ((ymax - ymin) == 0.0)
392 		ymax += 0.5, ymin -= 0.5;
393 
394 	return do_plot_imp(PLOTF_NONE,
395 	                   xmin, xmax, ymin, ymax, 1.0, 1,
396 	                   x, NULL, yy, NULL, n,
397 	                   NULL, NULL, NULL, NULL, n ,
398 	                   NULL, NULL, NULL, NULL, NULL, 0);
399 }
400 
401 /* Public routines */
402 /* Plot up to 6 graphs + optional crosses. Wait for a key */
403 /* return 0 on success, -1 on error */
404 /* If n is -ve, reverse the X axis */
405 int
do_plot6p(double * x,double * y1,double * y2,double * y3,double * y4,double * y5,double * y6,int n,double * xp,double * yp,int m)406 do_plot6p(
407 double *x,	/* X coord */
408 double *y1,	/* Black */
409 double *y2,	/* Red */
410 double *y3,	/* Green */
411 double *y4,	/* Blue */
412 double *y5,	/* Yellow */
413 double *y6,	/* Purple */
414 int n,		/* Number of values */
415 double *xp, double *yp,		/* And crosses */
416 int m) {
417 	int i, j;
418 	double xmin, xmax, ymin, ymax;
419 	int nn = abs(n);
420 	double *yy[MXGPHS];
421 
422 	for (j = 0; j < MXGPHS; j++)
423 		yy[j] = NULL;
424 
425 	yy[0] = y1;
426 	yy[1] = y2;
427 	yy[2] = y3;
428 	yy[3] = y4;
429 	yy[4] = y5;
430 	yy[5] = y6;
431 
432 	/* Determine min and max dimensions of plot */
433 	xmin = ymin = 1e6;
434 	xmax = ymax = -1e6;
435 
436 	for (i = 0; i < nn; i++) {
437 		if (xmin > x[i])
438 			xmin = x[i];
439 		if (xmax < x[i])
440 			xmax = x[i];
441 
442 		for (j = 0; j < MXGPHS; j++) {
443 			if (yy[j] != NULL) {
444 				if (ymin > yy[j][i])
445 					ymin = yy[j][i];
446 				if (ymax < yy[j][i])
447 					ymax = yy[j][i];
448 			}
449 		}
450 	}
451 
452 	for (i = 0; i < m; i++) {
453 		if (xp != NULL) {
454 			if (xmin > xp[i])
455 				xmin = xp[i];
456 			if (xmax < xp[i])
457 				xmax = xp[i];
458 		}
459 		if (yp != NULL) {
460 			if (ymin > yp[i])
461 				ymin = yp[i];
462 			if (ymax < yp[i])
463 				ymax = yp[i];
464 		}
465 	}
466 
467 	/* Work out scale factors */
468 	if ((xmax - xmin) == 0.0)
469 		xmax += 0.5, xmin -= 0.5;
470 	if ((ymax - ymin) == 0.0)
471 		ymax += 0.5, ymin -= 0.5;
472 
473 	return do_plot_imp(PLOTF_NONE,
474 	                   xmin, xmax, ymin, ymax, 1.0, 1,
475 	                   x, NULL, yy, NULL, n,
476 	                   xp, yp, NULL, NULL, m,
477 	                   NULL, NULL, NULL, NULL, NULL, 0);
478 }
479 
480 /* Public routines */
481 /* Plot up to 10 graphs. Wait for a key */
482 /* return 0 on success, -1 on error */
483 /* If n is -ve, reverse the X axis */
484 int
do_plot10(double * x,double * y1,double * y2,double * y3,double * y4,double * y5,double * y6,double * y7,double * y8,double * y9,double * y10,int n,int zero)485 do_plot10(
486 double *x,	/* X coord */
487 double *y1,	/* Black */
488 double *y2,	/* Red */
489 double *y3,	/* Green */
490 double *y4,	/* Blue */
491 double *y5,	/* Yellow */
492 double *y6,	/* Purple */
493 double *y7,	/* Brown */
494 double *y8,	/* Orange */
495 double *y9,	/* Grey */
496 double *y10,/* White */
497 int n,		/* Number of values */
498 int zero	/* Flag - make sure zero is in y range */
499 ) {
500 	int i, j;
501 	double xmin, xmax, ymin, ymax;
502 	int nn = abs(n);
503 	double *yy[MXGPHS];
504 
505 	for (j = 0; j < MXGPHS; j++)
506 		yy[j] = NULL;
507 
508 	yy[0] = y1;
509 	yy[1] = y2;
510 	yy[2] = y3;
511 	yy[3] = y4;
512 	yy[4] = y5;
513 	yy[5] = y6;
514 	yy[6] = y7;
515 	yy[7] = y8;
516 	yy[8] = y9;
517 	yy[9] = y10;
518 
519 	/* Determine min and max dimensions of plot */
520 	xmin = ymin = 1e6;
521 	xmax = ymax = -1e6;
522 
523 	for (i = 0; i < n; i++) {
524 		if (xmin > x[i])
525 			xmin = x[i];
526 		if (xmax < x[i])
527 			xmax = x[i];
528 
529 		for (j = 0; j < MXGPHS; j++) {
530 			if (yy[j] != NULL) {
531 				if (ymin > yy[j][i])
532 					ymin = yy[j][i];
533 				if (ymax < yy[j][i])
534 					ymax = yy[j][i];
535 			}
536 		}
537 	}
538 
539 	if (zero && ymin > 0.0)
540 		ymin = 0.0;
541 
542 	/* Work out scale factors */
543 	if ((xmax - xmin) == 0.0)
544 		xmax += 0.5, xmin -= 0.5;
545 	if ((ymax - ymin) == 0.0)
546 		ymax += 0.5, ymin -= 0.5;
547 
548 	return do_plot_imp(PLOTF_NONE,
549 	                   xmin, xmax, ymin, ymax, 1.0, 1,
550 	                   x, NULL, yy, NULL, n,
551 	                   NULL, NULL, NULL, NULL, n ,
552 	                   NULL, NULL, NULL, NULL, NULL, 0);
553 }
554 
555 /* Public routines */
556 /* Plot up to 10 graphs + optional crosses. Wait for a key */
557 /* return 0 on success, -1 on error */
558 /* If n is -ve, reverse the X axis */
559 int
do_plot10p(double * x,double * y1,double * y2,double * y3,double * y4,double * y5,double * y6,double * y7,double * y8,double * y9,double * y10,int n,double * xp,double * yp,int m)560 do_plot10p(
561 double *x,	/* X coord */
562 double *y1,	/* Black */
563 double *y2,	/* Red */
564 double *y3,	/* Green */
565 double *y4,	/* Blue */
566 double *y5,	/* Yellow */
567 double *y6,	/* Purple */
568 double *y7,	/* Brown */
569 double *y8,	/* Orange */
570 double *y9,	/* Grey */
571 double *y10,/* White */
572 int n,		/* Number of values */
573 double *xp, double *yp,		/* And crosses */
574 int m) {
575 	int i, j;
576 	double xmin, xmax, ymin, ymax;
577 	int nn = abs(n);
578 	double *yy[MXGPHS];
579 
580 	for (j = 0; j < MXGPHS; j++)
581 		yy[j] = NULL;
582 
583 	yy[0] = y1;
584 	yy[1] = y2;
585 	yy[2] = y3;
586 	yy[3] = y4;
587 	yy[4] = y5;
588 	yy[5] = y6;
589 	yy[6] = y7;
590 	yy[7] = y8;
591 	yy[9] = y9;
592 	yy[5] = y10;
593 
594 	/* Determine min and max dimensions of plot */
595 	xmin = ymin = 1e6;
596 	xmax = ymax = -1e6;
597 
598 	for (i = 0; i < n; i++) {
599 		if (xmin > x[i])
600 			xmin = x[i];
601 		if (xmax < x[i])
602 			xmax = x[i];
603 
604 		for (j = 0; j < MXGPHS; j++) {
605 			if (yy[j] != NULL) {
606 				if (ymin > yy[j][i])
607 					ymin = yy[j][i];
608 				if (ymax < yy[j][i])
609 					ymax = yy[j][i];
610 			}
611 		}
612 	}
613 
614 	for (i = 0; i < m; i++) {
615 		if (xp != NULL) {
616 			if (xmin > xp[i])
617 				xmin = xp[i];
618 			if (xmax < xp[i])
619 				xmax = xp[i];
620 		}
621 		if (yp != NULL) {
622 			if (ymin > yp[i])
623 				ymin = yp[i];
624 			if (ymax < yp[i])
625 				ymax = yp[i];
626 		}
627 	}
628 
629 	/* Work out scale factors */
630 	if ((xmax - xmin) == 0.0)
631 		xmax += 0.5, xmin -= 0.5;
632 	if ((ymax - ymin) == 0.0)
633 		ymax += 0.5, ymin -= 0.5;
634 
635 	return do_plot_imp(PLOTF_NONE,
636 	                   xmin, xmax, ymin, ymax, 1.0, 1,
637 	                   x, NULL, yy, NULL, n,
638 	                   xp, yp, NULL, NULL, m,
639 	                   NULL, NULL, NULL, NULL, NULL, 0);
640 }
641 
642 
643 /* Plot a bunch of vectors + optional crosses */
644 /* return 0 on success, -1 on error */
do_plot_vec(double xmin,double xmax,double ymin,double ymax,double * x1,double * y1,double * x2,double * y2,int n,int dowait,double * x3,double * y3,plot_col * mcols,char ** mtext,int m)645 int do_plot_vec(
646 double xmin,
647 double xmax,
648 double ymin,
649 double ymax,
650 double *x1,		/* vector start */
651 double *y1,
652 double *x2,		/* vector end */
653 double *y2,
654 int n,			/* Number of vectors */
655 int dowait,
656 double *x3,		/* extra point */
657 double *y3,
658 plot_col *mcols,	/* point colors */
659 char **mtext,		/* notation */
660 int m			/* Number of points */
661 ) {
662 	int j;
663 	double *yy[MXGPHS];
664 
665 	for (j = 0; j < MXGPHS; j++)
666 		yy[j] = NULL;
667 
668 	yy[0] = y1;
669 	yy[1] = y2;
670 
671 	return do_plot_imp(PLOTF_VECCROSSES,
672 	                   xmin, xmax, ymin, ymax, 1.0, dowait,
673 	                   x1, x2, yy, NULL, n,
674 	                   x3, y3, mcols, mtext, m,
675 	                   NULL, NULL, NULL, NULL, NULL, 0);
676 }
677 
678 /* Plot a bunch of vectors & crosses + optional crosses + optional vectors*/
679 /* return 0 on success, -1 on error */
do_plot_vec2(double xmin,double xmax,double ymin,double ymax,double * x1,double * y1,double * x2,double * y2,char ** ntext,int n,int dowait,double * x3,double * y3,plot_col * mcols,char ** mtext,int m,double * x4,double * y4,double * x5,double * y5,plot_col * ocols,int o)680 int do_plot_vec2(
681 double xmin,
682 double xmax,
683 double ymin,
684 double ymax,
685 double *x1,		/* n vector start */
686 double *y1,
687 double *x2,		/* vector end and diagonal cross */
688 double *y2,
689 char **ntext,	/* text annotation at cross */
690 int n,			/* Number of vectors */
691 int dowait,
692 double *x3,		/* m extra crosses */
693 double *y3,
694 plot_col *mcols,/* cross colors */
695 char **mtext,	/* text annotation at cross */
696 int m,			/* Number of crosses */
697 double *x4,		/* o vector start */
698 double *y4,
699 double *x5,		/* o vector end */
700 double *y5,
701 plot_col *ocols,/* Vector colors */
702 int o			/* Number of vectors */
703 ) {
704 	int j;
705 	double *yy[MXGPHS];
706 
707 	for (j = 0; j < MXGPHS; j++)
708 		yy[j] = NULL;
709 
710 	yy[0] = y1;
711 	yy[1] = y2;
712 
713 	return do_plot_imp(PLOTF_VECCROSSES,
714 	                   xmin, xmax, ymin, ymax, 1.0, dowait,
715 	                   x1, x2, yy, ntext, n,
716 	                   x3, y3, mcols, mtext, m,
717 	                   x4, y4, x5, y5, ocols, o);
718 }
719 
720 /* ********************************** NT version ********************** */
721 #ifdef NT
722 
723 #include <windows.h>
724 
725 #ifdef DODEBUG
726 # define debugf(xx)	printf xx
727 #else
728 # define debugf(xx)
729 #endif
730 
731 double plot_ratio = 1.0;
732 HANDLE plot_th;              /* Thread */
733 char plot_AppName[] = "PlotWin";
734 HWND plot_hwnd  = NULL;	/* Open only one window per session */
735 int plot_signal = 0;	/* Signal a key or quit */
736 
737 static LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);
738 
739 /* Thread to handle message processing, so that there is no delay */
740 /* when the main thread is doing other things. */
plot_message_thread(LPVOID lpParameter)741 DWORD WINAPI plot_message_thread(LPVOID lpParameter) {
742 	MSG msg;
743 	WNDCLASS wc;
744 	ATOM arv;
745 	HWND _hwnd;
746 
747 	// Fill in window class structure with parameters that describe the
748 	// main window.
749 
750 	wc.style         = CS_HREDRAW | CS_VREDRAW;	// Class style(s).
751 	wc.lpfnWndProc   = MainWndProc;	// Function to retrieve messages for windows of this class.
752 	wc.cbClsExtra    = 0;			// No per-class extra data.
753 	wc.cbWndExtra    = 0;			// No per-window extra data.
754 	wc.hInstance     = NULL;		// Application that owns the class.
755 	wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
756 	wc.hCursor       = LoadCursor(NULL, IDC_CROSS);
757 	wc.hbrBackground = GetStockObject(WHITE_BRUSH);
758 	wc.lpszMenuName  = NULL;
759 	wc.lpszClassName = plot_AppName;
760 
761 	arv = RegisterClass(&wc);
762 
763 	if (!arv) {
764 		debugf(("RegisterClass failed, lasterr = %d\n",GetLastError()));
765 		return -1;
766 	}
767 
768 	_hwnd = CreateWindow(
769 		plot_AppName,
770 		"2D Diagnostic Graph Plot",
771 		WS_OVERLAPPEDWINDOW,
772 		CW_USEDEFAULT,
773 		CW_USEDEFAULT,
774 		(int)(DEFWWIDTH * plot_ratio + 0.5),
775 		DEFWHEIGHT,
776 		NULL,
777 		NULL,
778 		NULL, // hInstance,
779 		NULL);
780 
781 	if (!_hwnd) {
782 		debugf(("CreateWindow failed, lasterr = %d\n",GetLastError()));
783 		return -1;
784 	}
785 
786 	ShowWindow(_hwnd, SW_SHOW);
787 
788 	plot_hwnd = _hwnd;
789 
790 	/* Now process messages until we're done */
791 	for (;;) {
792 		if (GetMessage(&msg, NULL, 0, 0)) {
793 			TranslateMessage(&msg);
794 			DispatchMessage(&msg);
795 			if (plot_signal == 99)
796 				break;
797 		}
798 	}
799 
800 	if (UnregisterClass(plot_AppName, NULL) == 0) {
801 		debugf(("UnregisterClass failed, lasterr = %d\n",GetLastError()));
802 	}
803 
804 	plot_hwnd = NULL;		/* Signal it's been deleted */
805 
806 	return 0;
807 }
808 
809 /* Superset implementation function: */
810 /* return 0 on success, -1 on error */
811 /* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */
812 /* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */
813 /* Vector uses x1, y1 to x2, y2 as a vector with a (optional) diagonal cross at x2, y2 */
814 /* all in black with annotation ntext at the cross, */
815 /* plus a (optiona) diagonal cross at x7, y7 in yellow. The color for x7, y7 can be */
816 /* overidden by an array of colors mcols, plus optional label text mtext. (x2 != NULL) */
817 /* n = number of points/vectors. -ve for reversed X axis */
818 /* m = number of extra points (x2,y3 or x7,y7) */
819 /* x8,y8 to x9,y9 are extra optional vectors with optional colors */
do_plot_imp(int flags,double xmin,double xmax,double ymin,double ymax,double ratio,int dowait,double * x1,double * x2,double * yy[MXGPHS],char ** ntext,int n,double * x7,double * y7,plot_col * mcols,char ** mtext,int m,double * x8,double * y8,double * x9,double * y9,plot_col * ocols,int o)820 static int do_plot_imp(
821 	int flags,
822     double xmin, double xmax, double ymin, double ymax,	/* Bounding box */
823 	double ratio,	/* Aspect ratio of window, X/Y */
824 	int dowait,		/* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
825     double *x1, double *x2,
826     double *yy[MXGPHS], char **ntext,
827 	int n,
828 	double *x7, double *y7, plot_col *mcols, char **mtext,
829     int m,
830 	double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
831 	int o
832 ) {
833 	pd.flags = flags;
834 	pd.dowait = 10 * dowait;
835 	pd.ratio = ratio;
836 	{
837 		int j;
838 		double xr,yr;
839 
840 		pd.mnx = xmin;
841 		pd.mny = ymin;
842 		pd.mxx = xmax;
843 		pd.mxy = ymax;
844 
845 		/* Allow some extra around plot */
846 		xr = pd.mxx - pd.mnx;
847 		yr = pd.mxy - pd.mny;
848 		if (xr < 1e-6)
849 			xr = 1e-6;
850 		if (yr < 1e-6)
851 			yr = 1e-6;
852 		pd.mnx -= xr/10.0;
853 		pd.mxx += xr/10.0;
854 		pd.mny -= yr/10.0;
855 		pd.mxy += yr/10.0;
856 
857 		/* Transfer raw point info */
858 		if (x2 == NULL)
859 			pd.graph = 1;		/* 6 graphs + points */
860 		else
861 			pd.graph = 0;
862 		pd.x1 = x1;
863 		pd.x2 = x2;
864 		for (j = 0; j < MXGPHS; j++)
865 			pd.yy[j] = yy[j];
866 		pd.ntext = ntext;
867 		pd.n = abs(n);
868 
869 		if (n < 0) {
870 			double tt;
871 			tt = pd.mxx;
872 			pd.mxx = pd.mnx;
873 			pd.mnx = tt;
874 			pd.revx = 1;
875 		} else {
876 			pd.revx = 0;
877 		}
878 		pd.x7 = x7;
879 		pd.y7 = y7;
880 		pd.mcols = mcols;
881 		pd.mtext = mtext;
882 		pd.m = abs(m);
883 
884 		pd.x8 = x8;
885 		pd.y8 = y8;
886 		pd.x9 = x9;
887 		pd.y9 = y9;
888 		pd.ocols = ocols;
889 		pd.o = abs(o);
890 	}
891 
892 	/* ------------------------------------------- */
893 	/* Setup windows stuff */
894 	{
895 		ui_UsingGUI();
896 
897 		/* It would be nice to reduce number of globals. */
898 
899 		/* We don't clean up properly either - ie. don't delete thread etc. */
900 
901 		/* Create thread that creats window and processes window messages */
902 		if (plot_hwnd == NULL) {
903 
904 			plot_ratio = ratio;
905 
906 		    plot_th = CreateThread(NULL, 0, plot_message_thread, NULL, 0, NULL);
907 		    if (plot_th == NULL) {
908 				debugf(("new_athread failed\n"));
909 				return -1;
910 			}
911 			while (plot_hwnd == NULL)
912 				Sleep(50);
913 
914 			SetForegroundWindow(plot_hwnd);		/* Raise */
915 		}
916 
917 		plot_signal = 0;
918 
919 		if (dowait > 0)
920 			SetForegroundWindow(plot_hwnd);		/* Raise */
921 
922 		/* Force a repaint with the new data */
923 		if (!InvalidateRgn(plot_hwnd,NULL,TRUE)) {
924 			debugf(("InvalidateRgn failed, lasterr = %d\n",GetLastError()));
925 			return -1;
926 		}
927 
928 		if (dowait > 0) {		/* Wait for a space key */
929 			while(plot_signal == 0 && plot_hwnd != NULL)
930 				Sleep(50);
931 			plot_signal = 0;
932 		} else if (dowait < 0) {
933 			Sleep(-dowait * 1000);
934 		}
935 	}
936 	return 0;
937 }
938 
939 void DoPlot(HDC hdc, plot_info *pd);
940 
MainWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)941 static LRESULT CALLBACK MainWndProc(
942 	HWND hwnd,
943 	UINT message,
944 	WPARAM wParam,
945 	LPARAM lParam
946 ) {
947 	HDC hdc;
948 	PAINTSTRUCT ps;
949 	RECT rect;
950 
951 	debugf(("Handling message type 0x%x\n",message));
952 	// Could use Set/GetWindowLong() to pass window class info instead of global pd (beware NULL)
953 	switch(message) {
954 		case WM_PAINT:
955 			debugf(("It's a paint message\n"));
956 			hdc = BeginPaint(hwnd, &ps);
957 			GetClientRect(hwnd, &rect);
958 
959 			/* Setup the plot info structure for this drawing */
960 			pd.sx = rect.left;
961 			pd.sy = rect.top;
962 			pd.sw = 1 + rect.right - rect.left;
963 			pd.sh = 1 + rect.bottom - rect.top;
964 			pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx);
965 			pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny);
966 
967 			DoPlot(hdc, &pd);
968 
969 			EndPaint(hwnd, &ps);
970 
971 			return 0;
972 
973 		case WM_CHAR:
974 			debugf(("It's a char message, wParam = 0x%x\n",wParam));
975 			switch(wParam) {
976 				case '\r':
977 				case '\n':
978 				case ' ':	/* Space */
979 					debugf(("It's a SPACE, so signal it\n"));
980 					plot_signal = 1;
981 					return 0;
982 			}
983 
984 		case WM_CLOSE:
985 			debugf(("It's a close message\n"));
986 			DestroyWindow(hwnd);
987 			return 0;
988 
989 		case WM_DESTROY:
990 			debugf(("It's a destroy message\n"));
991 			plot_signal = 99;
992 		    PostQuitMessage(0);
993 			return 0;
994 	}
995 
996 	debugf(("It's a message not handled here\n"));
997 	return DefWindowProc(hwnd, message, wParam, lParam);
998 }
999 
1000 void
xtick(HDC hdc,plot_info * pdp,double x,char * lab)1001 xtick(HDC hdc, plot_info *pdp, double x, char *lab)
1002 	{
1003 	int xx,yy;
1004 	RECT rct;
1005 
1006 	xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5);
1007 	yy = pdp->sh - 10;
1008 
1009 	MoveToEx(hdc,xx, yy, NULL);
1010 	LineTo(  hdc,xx, 0);
1011 	rct.right =
1012 	rct.left = xx;
1013 	rct.top =
1014 	rct.bottom = yy;
1015 	DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
1016 	}
1017 
1018 void
ytick(HDC hdc,plot_info * pdp,double y,char * lab)1019 ytick(HDC hdc, plot_info *pdp, double y, char *lab)
1020 	{
1021 	int xx,yy;
1022 	RECT rct;
1023 
1024 	xx = 5;
1025 	yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5);
1026 	MoveToEx(hdc,xx,      yy,NULL);
1027 	LineTo(  hdc,pdp->sw, yy);
1028 	rct.right =
1029 	rct.left = xx;
1030 	rct.top =
1031 	rct.bottom = yy;
1032 	DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_NOCLIP);
1033 	}
1034 
1035 void
loose_label(HDC hdc,plot_info * pdp,double min,double max,void (* pfunc)(HDC hdc,plot_info * pdp,double,char *))1036 loose_label(HDC hdc, plot_info *pdp, double min, double max, void (*pfunc)(HDC hdc, plot_info *pdp, double, char *)
1037 ) {
1038 	char str[6], temp[20];
1039 	int nfrac;
1040 	double d;
1041 	double graphmin, graphmax;
1042 	double range,x;
1043 
1044 	range = nicenum(min-max,0);
1045 	d = nicenum(range/(NTICK-1),1);
1046 	graphmin = floor(min/d) * d;
1047 	graphmax = ceil(max/d) * d;
1048 	nfrac = (int)MAX(-floor(log10(d)),0);
1049 	sprintf(str,"%%.%df", nfrac);
1050 	for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
1051 		sprintf(temp,str,x);
1052 		pfunc(hdc,pdp,x,temp);
1053 	}
1054 }
1055 
1056 void
DoPlot(HDC hdc,plot_info * p)1057 DoPlot(
1058 HDC hdc,
1059 plot_info *p
1060 ) {
1061 	int i, j;
1062 	int lx,ly;		/* Last x,y */
1063 	HPEN pen;
1064 
1065 	pen = CreatePen(PS_DOT,0,RGB(200,200,200));
1066 
1067 	SaveDC(hdc);
1068 	SelectObject(hdc,pen);
1069 
1070 	/* Plot horizontal axis */
1071 	if (p->revx)
1072 		loose_label(hdc, p, p->mxx, p->mnx, xtick);
1073 	else
1074 		loose_label(hdc, p, p->mnx, p->mxx, xtick);
1075 
1076 	/* Plot vertical axis */
1077 	loose_label(hdc, p, p->mny, p->mxy, ytick);
1078 
1079 	RestoreDC(hdc,-1);
1080 	DeleteObject(pen);
1081 
1082 	if (p->graph) {		/* Up to MXGPHS graphs + crosses */
1083 		int gcolors[MXGPHS][3] = {
1084 			{   0,   0,   0},	/* Black */
1085 			{ 210,  30,   0},	/* Red */
1086 			{   0, 200,  90},	/* Green */
1087 			{   0,  10, 255},	/* Blue */
1088 			{ 200, 200,   0},	/* Yellow */
1089 			{ 220,   0, 255},	/* Purple */
1090 			{ 136,  86,  68},	/* Brown */
1091 			{ 248,  95,   0},	/* Orange */
1092 			{ 160, 160, 160},	/* Grey */
1093 			{ 220, 220, 220}	/* White */
1094 		};
1095 		for (j = MXGPHS-1; j >= 0; j--) {
1096 			double *yp = p->yy[j];
1097 
1098 			if (yp == NULL)
1099 				continue;
1100 
1101 			pen = CreatePen(PS_SOLID,ILTHICK,RGB(gcolors[j][0],gcolors[j][1],gcolors[j][2]));
1102 			SelectObject(hdc,pen);
1103 
1104 			lx = (int)((p->x1[0] - p->mnx) * p->scx + 0.5);
1105 			ly = (int)((     yp[0] - p->mny) * p->scy + 0.5);
1106 
1107 			for (i = 0; i < p->n; i++) {
1108 				int cx,cy;
1109 				cx = (int)((p->x1[i] - p->mnx) * p->scx + 0.5);
1110 				cy = (int)((     yp[i] - p->mny) * p->scy + 0.5);
1111 
1112 				MoveToEx(hdc, 10 + lx, p->sh - 10 - ly, NULL);
1113 				LineTo(hdc, 10 + cx, p->sh - 10 - cy);
1114 				if (p->flags & PLOTF_GRAPHCROSSES) {
1115 					MoveToEx(hdc, 10 + cx - 5, p->sh - 10 - cy - 5, NULL);
1116 					LineTo(hdc, 10 + cx + 5, p->sh - 10 - cy + 5);
1117 					LineTo(hdc, 10 + cx - 5, p->sh - 10 - cy + 5);
1118 				}
1119 				lx = cx;
1120 				ly = cy;
1121 			}
1122 			DeleteObject(pen);
1123 		}
1124 
1125 	} else {	/* Vectors with cross */
1126 
1127 		pen = CreatePen(PS_SOLID,ILTHICK,RGB(0,0,0));
1128 		SelectObject(hdc,pen);
1129 
1130 		if (p->ntext != NULL) {
1131 			HFONT fon;
1132 
1133 			fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET,
1134 			                 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1135 			                 FF_DONTCARE, NULL);
1136 
1137 			if (fon == NULL)
1138 				fprintf(stderr,"plot: CreateFont returned NULL\n");
1139 			else {
1140 				SelectObject(hdc,fon);
1141 				DeleteObject(fon);
1142 			}
1143 		}
1144 
1145 		for (i = 0; i < p->n; i++) {
1146 			int cx,cy;
1147 
1148 			lx = (int)((p->x1[i] - p->mnx) * p->scx + 0.5);
1149 			ly = (int)((p->yy[0][i] - p->mny) * p->scy + 0.5);
1150 
1151 			cx = (int)((p->x2[i] - p->mnx) * p->scx + 0.5);
1152 			cy = (int)((p->yy[1][i] - p->mny) * p->scy + 0.5);
1153 
1154 			MoveToEx(hdc, 10 + lx, p->sh - 10 - ly, NULL);
1155 			LineTo(hdc, 10 + cx, p->sh - 10 - cy);
1156 
1157 			if (p->flags & PLOTF_VECCROSSES) {
1158 				MoveToEx(hdc, 10 + cx - 5, p->sh - 10 - cy - 5, NULL);
1159 				LineTo(hdc, 10 + cx + 5, p->sh - 10 - cy + 5);
1160 				MoveToEx(hdc, 10 + cx + 5, p->sh - 10 - cy - 5, NULL);
1161 				LineTo(hdc, 10 + cx - 5, p->sh - 10 - cy + 5);
1162 			}
1163 
1164 			if (p->ntext != NULL) {
1165 				RECT rct;
1166 				rct.right =
1167 				rct.left = 10 + cx + 10;
1168 				rct.top =
1169 				rct.bottom = p->sh - 10 - cy + 10;
1170 				DrawText(hdc, p->ntext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
1171 			}
1172 		}
1173 		DeleteObject(pen);
1174 	}
1175 
1176 	/* Extra points */
1177 	if (p->x7 != NULL && p->y7 != NULL && p->m > 0 ) {
1178 		pen = CreatePen(PS_SOLID,ILTHICK,RGB(210,150,0));
1179 		SelectObject(hdc,pen);
1180 
1181 		if (p->mtext != NULL) {
1182 			HFONT fon;
1183 
1184 
1185 			fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET,
1186 			                 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
1187 			                 FF_DONTCARE, NULL);
1188 
1189 			if (fon == NULL)
1190 				fprintf(stderr,"plot: CreateFont returned NULL\n");
1191 			else {
1192 				SelectObject(hdc,fon);
1193 				DeleteObject(fon);
1194 			}
1195 		}
1196 
1197 		for (i = 0; i < p->m; i++) {
1198 			lx = (int)((p->x7[i] - p->mnx) * p->scx + 0.5);
1199 			ly = (int)((p->y7[i] - p->mny) * p->scy + 0.5);
1200 
1201 			if (p->mcols != NULL) {
1202 				int rgb[3];
1203 
1204 				for (j = 0; j < 3; j++)
1205 					rgb[j] = (int)(p->mcols[i].rgb[j] * 255.0 + 0.5);
1206 
1207 				DeleteObject(pen);
1208 				pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2]));
1209 				SelectObject(hdc,pen);
1210 
1211 				if (p->mtext != NULL)
1212 					SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2]));
1213 			}
1214 			MoveToEx(hdc, 10 + lx - 5, p->sh - 10 - ly, NULL);
1215 			LineTo(hdc, 10 + lx + 5, p->sh - 10 - ly);
1216 			MoveToEx(hdc, 10 + lx, p->sh - 10 - ly - 5, NULL);
1217 			LineTo(hdc, 10 + lx, p->sh - 10 - ly + 5);
1218 
1219 			if (p->mtext != NULL) {
1220 				RECT rct;
1221 				rct.right =
1222 				rct.left = 10 + lx + 10;
1223 				rct.top =
1224 				rct.bottom = p->sh - 10 - ly - 10;
1225 				DrawText(hdc, p->mtext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
1226 			}
1227 		}
1228 		DeleteObject(pen);
1229 	}
1230 	/* Extra vectors */
1231 	if (p->x8 != NULL && p->y8 != NULL && p->x9 != NULL && p->y9 && p->o > 0 ) {
1232 		pen = CreatePen(PS_SOLID,ILTHICK,RGB(150,255,255));
1233 		SelectObject(hdc,pen);
1234 
1235 		for (i = 0; i < p->o; i++) {
1236 			int cx,cy;
1237 
1238 			lx = (int)((p->x8[i] - p->mnx) * p->scx + 0.5);
1239 			ly = (int)((p->y8[i] - p->mny) * p->scy + 0.5);
1240 
1241 			cx = (int)((p->x9[i] - p->mnx) * p->scx + 0.5);
1242 			cy = (int)((p->y9[i] - p->mny) * p->scy + 0.5);
1243 
1244 			if (p->ocols != NULL) {
1245 				int rgb[3];
1246 
1247 				for (j = 0; j < 3; j++)
1248 					rgb[j] = (int)(p->ocols[i].rgb[j] * 255.0 + 0.5);
1249 
1250 				DeleteObject(pen);
1251 				pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2]));
1252 				SelectObject(hdc,pen);
1253 
1254 				if (p->mtext != NULL)
1255 					SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2]));
1256 			}
1257 			MoveToEx(hdc, 10 + lx, p->sh - 10 - ly, NULL);
1258 			LineTo(hdc, 10 + cx, p->sh - 10 - cy);
1259 		}
1260 		DeleteObject(pen);
1261 	}
1262 
1263 //	while(!kbhit());
1264 	}
1265 
1266 #else /* !NT */
1267 
1268 /* ************************** APPLE OSX Cocoa version ****************** */
1269 #ifdef __APPLE__
1270 
1271 #include <Foundation/Foundation.h>
1272 #include <AppKit/AppKit.h>
1273 
1274 #ifndef CGFLOAT_DEFINED
1275 #ifdef __LP64__
1276 typedef double CGFloat;
1277 #else
1278 typedef float CGFloat;
1279 #endif  /* defined(__LP64__) */
1280 #endif
1281 
1282 #ifdef DODEBUG
1283 # define debugf(xx)	printf xx
1284 #else
1285 # define debugf(xx)
1286 #endif
1287 
1288 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1289 
1290 
1291 @class PLWin;
1292 @class PLView;
1293 
1294 /* Our static instance variables */
1295 typedef struct {
1296 	PLWin *window;				/* NSWindow */
1297 	PLView *view;				/* NSTextField */
1298 	volatile int plot_signal;	/* Signal a key or quit */
1299 } cntx_t;
1300 
1301 /* Global plot instanc */
1302 
1303 cntx_t *plot_cx = NULL;
1304 
1305 // - - - - - - - - - - - - - - - - - - - - - - - - -
1306 @interface PLView : NSView {
1307 	cntx_t *cntx;
1308 }
1309 - (void)setCntx:(cntx_t *)cntx;
1310 @end
1311 
1312 @implementation PLView
1313 
1314 - (void)setCntx:(cntx_t *)val {
1315 	cntx = val;
1316 }
1317 
1318 /* This function does the work */
1319 static void DoPlot(NSRect *rect, plot_info *pdp);
1320 
1321 - (void)drawRect:(NSRect)rect {
1322 
1323 	/* Use global plot data struct for now */
1324 	DoPlot(&rect, &pd);
1325 }
1326 
1327 @end
1328 
1329 /* Function called back by main thread to trigger a drawRect */
1330 
doSetNeedsDisplay(void * cntx)1331 static void doSetNeedsDisplay(void *cntx) {
1332 	cntx_t *cx = (cntx_t *)cntx;
1333 
1334 	[cx->view setNeedsDisplay: YES ];
1335 }
1336 
1337 // - - - - - - - - - - - - - - - - - - - - - - - - -
1338 
1339 @interface PLWin : NSWindow {
1340 	cntx_t *cntx;
1341 }
1342 - (void)setCntx:(cntx_t *)cntx;
1343 @end
1344 
1345 @implementation PLWin
1346 
1347 - (void)setCntx:(cntx_t *)val {
1348 	cntx = val;
1349 }
1350 
1351 - (BOOL)canBecomeMainWindow {
1352 	return YES;
1353 }
1354 
1355 - (void)keyDown:(NSEvent *)event {
1356 	const char *chars;
1357 
1358 	chars = [[event characters] UTF8String];
1359 //	printf("Got Window KeyDown type %d char %s\n",(int)[event type], chars);
1360 
1361 	if (chars[0] == ' '
1362 	 || chars[0] == '\r') {
1363 //		printf("Set plot_signal = 1\n");
1364 		plot_cx->plot_signal = 1;
1365 	}
1366 }
1367 
1368 - (BOOL)windowShouldClose:(id)sender {
1369 //	printf("Got Window windowShouldClose\n");
1370 
1371     [NSApp terminate: nil];
1372     return YES;
1373 }
1374 
1375 @end
1376 
1377 /* Create our window */
create_my_win(void * cntx)1378 static void create_my_win(void *cntx) {
1379 	cntx_t *cx = (cntx_t *)cntx;
1380 	NSRect wRect;
1381 
1382 	/* Create Window */
1383    	wRect.origin.x = 100;
1384 	wRect.origin.y = 100;
1385 	wRect.size.width = (int)(DEFWWIDTH*pd.ratio+0.5);
1386 	wRect.size.height = DEFWHEIGHT;
1387 
1388 	cx->window = [[PLWin alloc] initWithContentRect: wRect
1389                                         styleMask: (NSTitledWindowMask |
1390 	                                                NSClosableWindowMask |
1391                                                     NSMiniaturizableWindowMask |
1392                                                     NSResizableWindowMask)
1393                                           backing: NSBackingStoreBuffered
1394                                             defer: YES
1395 	                                       screen: nil];		/* Main screen */
1396 
1397 	[cx->window setBackgroundColor: [NSColor whiteColor]];
1398 
1399 	[cx->window setLevel: NSMainMenuWindowLevel];		// ~~99
1400 
1401 	[cx->window setTitle: @"PlotWin"];
1402 
1403 	/* Use our view for the whole window to draw plot */
1404 	cx->view = [PLView new];
1405 	[cx->view setCntx:(void *)cx];
1406 	[cx->window setContentView: cx->view];
1407 
1408 	[cx->window makeKeyAndOrderFront: nil];
1409 
1410 //	[cx->window makeMainWindow];
1411 }
1412 
1413 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1414 
1415 /*
1416 	Cocoa NSApp is pretty horrible - it will only get user events
1417 	if created and run in the main thread. So the only way we can
1418 	decouble the windows from the application is to intercept
1419 	main() and create a secondary thread to run the appication while
1420 	leaving main() in reserve for creating an NSApp and windows.
1421  */
1422 
1423 /* Superset implementation function: */
1424 /* return 0 on success, -1 on error */
1425 /* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */
1426 /* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */
1427 /* Vector uses x1, y1 to x2, y2 as a vector with a (optional) diagonal cross at x2, y2 */
1428 /* all in black with annotation ntext at the cross, */
1429 /* plus a (optiona) diagonal cross at x7, y7 in yellow. The color for x7, y7 can be */
1430 /* overidden by an array of colors mcols, plus optional label text mtext. (x2 != NULL) */
1431 /* n = number of points/vectors. -ve for reversed X axis */
1432 /* m = number of extra points (x2,y3 or x7,y7) */
1433 /* x8,y8 to x9,y9 are extra optional vectors with optional colors */
do_plot_imp(int flags,double xmin,double xmax,double ymin,double ymax,double ratio,int dowait,double * x1,double * x2,double * yy[MXGPHS],char ** ntext,int n,double * x7,double * y7,plot_col * mcols,char ** mtext,int m,double * x8,double * y8,double * x9,double * y9,plot_col * ocols,int o)1434 static int do_plot_imp(
1435 	int flags,
1436     double xmin, double xmax, double ymin, double ymax,	/* Bounding box */
1437 	double ratio,	/* Aspect ratio of window, X/Y */
1438 	int dowait,		/* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
1439     double *x1, double *x2,
1440     double *yy[MXGPHS], char **ntext,
1441 	int n,
1442 	double *x7, double *y7, plot_col *mcols, char **mtext,
1443     int m,
1444 	double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
1445 	int o
1446 ) {
1447 	/* Put information in global pd */
1448 	{
1449 		int j;
1450 		double xr,yr;
1451 
1452 		pd.flags = flags;
1453 		pd.dowait = dowait;
1454 		pd.ratio = ratio;
1455 
1456 		pd.mnx = xmin;
1457 		pd.mny = ymin;
1458 		pd.mxx = xmax;
1459 		pd.mxy = ymax;
1460 
1461 		/* Allow some extra arround plot */
1462 		xr = pd.mxx - pd.mnx;
1463 		yr = pd.mxy - pd.mny;
1464 		if (xr < 1e-6)
1465 			xr = 1e-6;
1466 		if (yr < 1e-6)
1467 			yr = 1e-6;
1468 		pd.mnx -= xr/10.0;
1469 		pd.mxx += xr/10.0;
1470 		pd.mny -= yr/10.0;
1471 		pd.mxy += yr/10.0;
1472 
1473 		/* Transfer raw point info */
1474 		if (x2 == NULL)
1475 			pd.graph = 1;		/* 6 graphs + points */
1476 		else
1477 			pd.graph = 0;
1478 		pd.x1 = x1;
1479 		pd.x2 = x2;
1480 		for (j = 0; j < MXGPHS; j++)
1481 			pd.yy[j] = yy[j];
1482 		pd.ntext = ntext;
1483 		pd.n = abs(n);
1484 
1485 		if (n < 0) {
1486 			double tt;
1487 			tt = pd.mxx;
1488 			pd.mxx = pd.mnx;
1489 			pd.mnx = tt;
1490 			pd.revx = 1;
1491 		} else {
1492 			pd.revx = 0;
1493 		}
1494 		pd.x7 = x7;
1495 		pd.y7 = y7;
1496 		pd.mcols = mcols;
1497 		pd.mtext = mtext;
1498 		pd.m = abs(m);
1499 
1500 		pd.x8 = x8;
1501 		pd.y8 = y8;
1502 		pd.x9 = x9;
1503 		pd.y9 = y9;
1504 		pd.ocols = ocols;
1505 		pd.o = abs(o);
1506 	}
1507 
1508 	ui_UsingGUI();
1509 
1510 	/* If we may be in a different thread to the main thread or */
1511 	/* the application thread, establish our own pool. */
1512 	NSAutoreleasePool *tpool = nil;
1513 	if (pthread_self() != ui_thid
1514 	 && pthread_self() != ui_main_thid)
1515 		tpool = [NSAutoreleasePool new];
1516 
1517 	/* If needed, create the indow */
1518 	if (plot_cx == NULL) {
1519 
1520 		/* If there is no NSApp, then we haven't run main() in libui before */
1521 		/* main() in the application. */
1522 		if (NSApp == nil) {
1523 			fprintf(stderr,"NSApp is nil - need to rename main() to main() and link with libui !\n");
1524 			exit(1);
1525 		}
1526 
1527 		if ((plot_cx = (cntx_t *)calloc(sizeof(cntx_t), 1)) == NULL)
1528 			error("new_dispwin: Malloc failed (cntx_t)\n");
1529 
1530 		/* Prepare to wait for events */
1531 		ui_aboutToWait();
1532 
1533 		/* Run the window creation in the main thread and wait for it */
1534 		ui_runInMainThreadAndWait((void *)plot_cx, create_my_win);
1535 
1536 		/* Wait for events generated by window creation to complete */
1537 		ui_waitForEvents();
1538 
1539 	} else {	/* Trigger an update */
1540 //		[plot_cx->view setNeedsDisplay: YES ];
1541 
1542 		/* Prepare to wait for events */
1543 		ui_aboutToWait();
1544 
1545 		/* Run the window creation in the main thread and wait for it */
1546 		ui_runInMainThreadAndWait((void *)plot_cx, doSetNeedsDisplay);
1547 
1548 		/* Wait for any events generated by paint to complete */
1549 		ui_waitForEvents();
1550 	}
1551 
1552 	/* (Main thread will service events) */
1553 
1554 	/* Wait until for a key if we should */
1555 	if (dowait > 0) {		/* Wait for a space key */
1556 		for (plot_cx->plot_signal = 0; plot_cx->plot_signal == 0;) {
1557 		    struct timespec ts;
1558 
1559 		    ts.tv_sec = 100 / 1000;
1560     		ts.tv_nsec = (100 % 1000) * 1000000;
1561 		    nanosleep(&ts, NULL);
1562 	    }
1563 	} else if (dowait < 0) {
1564 	    struct timespec ts;
1565 		int msec = -dowait * 1000;
1566 
1567 	    ts.tv_sec = msec / 1000;
1568    		ts.tv_nsec = (msec % 1000) * 1000000;
1569 	    nanosleep(&ts, NULL);
1570 	}
1571 
1572 	if (tpool != nil)
1573 		[tpool release];
1574 
1575 	return 0;
1576 }
1577 
1578 /* - - - - - - - - - - - - - - - - - - - - - - - - -  */
1579 /* Cleanup code (not called) */
1580 
cleanup()1581 static void cleanup() {
1582 	[plot_cx->window release];		/* Take down the plot window */
1583 	free(plot_cx);
1584 	plot_cx = NULL;
1585 }
1586 
1587 /* - - - - - - - - - - - - - - - - - - - - - - - - - - */
1588 
1589 /* Utility to draw text in Cocoa with centering */
1590 /* Size is points */
1591 /* Flags 0x1 == horizontal center */
1592 /* Flags 0x2 == vertical center */
ADrawText(NSColor * col,float size,float x,float y,int flags,char * text)1593 static void ADrawText(NSColor *col, float size, float x, float y, int flags, char *text) {
1594 	NSFont* font = [NSFont systemFontOfSize:size];
1595 	NSDictionary *att = [NSDictionary dictionaryWithObjectsAndKeys:
1596 				font, NSFontAttributeName,
1597 	            col, NSForegroundColorAttributeName,
1598 				nil];
1599 	NSString *str = [[NSString alloc] initWithUTF8String: text];
1600 
1601 	if (flags != 0x0) {
1602 		NSSize size;
1603 
1604 		/* Figure out how big it will be */
1605 		size = [str sizeWithAttributes: att ];
1606 		if (flags & 0x1) {
1607 			double w = fabs(size.width);
1608 			x -= 0.5 * w;
1609 		}
1610 		if (flags & 0x2) {
1611 			double h = fabs(size.height);
1612 			y -= 0.5 * h;
1613 		}
1614 	}
1615 
1616 	[str drawAtPoint: NSMakePoint(x, y) withAttributes: att];
1617 	[str release];		/* Others are autorelease */
1618 }
1619 
1620 /* Draw a line */
1621 /* We re-use the same path so that we can set the dash style */
ADrawLine(NSBezierPath * path,float xs,float ys,float xe,float ye)1622 static void ADrawLine(NSBezierPath *path, float xs, float ys, float xe, float ye) {
1623 	[path removeAllPoints ];
1624 	[path moveToPoint:NSMakePoint(xs, ys)];
1625 	[path lineToPoint:NSMakePoint(xe, ye)];
1626 	[path stroke];
1627 }
1628 
1629 /* Draw X axis grid lines */
1630 void
xtick(plot_info * pdp,NSBezierPath * path,NSColor * lcol,NSColor * tcol,double x,char * lab)1631 xtick(
1632 plot_info *pdp,
1633 NSBezierPath *path,
1634 NSColor *lcol,
1635 NSColor *tcol,
1636 double x, char *lab
1637 ) {
1638 	float xx, yy;
1639 
1640 	xx = 20.0 + (x - pdp->mnx) * pdp->scx;
1641 	yy = 20.0;
1642 
1643 	[lcol setStroke];		/* There is a bug in 10.4 which resets this after each stroke */
1644 	ADrawLine(path, xx, yy, xx, (float)pdp->sh);
1645 	ADrawText(tcol, 10.0, xx, 5.0, 0x1, lab);
1646 }
1647 
1648 /* Draw Y axis grid lines */
1649 void
ytick(plot_info * pdp,NSBezierPath * path,NSColor * lcol,NSColor * tcol,double y,char * lab)1650 ytick(
1651 plot_info *pdp,
1652 NSBezierPath *path,
1653 NSColor *lcol,
1654 NSColor *tcol,
1655 double y, char *lab
1656 ) {
1657 	float xx, yy;
1658 
1659 	xx = 20.0;
1660 	yy = 20.0 + (y - pdp->mny) * pdp->scy;
1661 
1662 	[lcol setStroke];		/* There is a bug in 10.4 which resets this after each stroke */
1663 	ADrawLine(path, xx, yy, (float)pdp->sw, yy);
1664 	ADrawText(tcol, 10.0, 3.0, yy, 0x2, lab);
1665 }
1666 
1667 void
loose_label(plot_info * pdp,NSBezierPath * path,NSColor * lcol,NSColor * tcol,double min,double max,void (* pfunc)(plot_info * pdp,NSBezierPath * path,NSColor * lcol,NSColor * tcol,double,char *))1668 loose_label(
1669 plot_info *pdp,
1670 NSBezierPath *path,
1671 NSColor *lcol,
1672 NSColor *tcol,
1673 double min, double max,
1674 void (*pfunc)(plot_info *pdp, NSBezierPath *path, NSColor *lcol, NSColor *tcol, double, char *)
1675 ) {
1676 	char str[6], temp[20];
1677 	int nfrac;
1678 	double d;
1679 	double graphmin, graphmax;
1680 	double range,x;
1681 
1682 	range = nicenum(min-max,0);
1683 	d = nicenum(range/(NTICK-1),1);
1684 	graphmin = floor(min/d) * d;
1685 	graphmax = ceil(max/d) * d;
1686 	nfrac = (int)MAX(-floor(log10(d)),0);
1687 	sprintf(str,"%%.%df", nfrac);
1688 	for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
1689 		sprintf(temp,str,x);
1690 		pfunc(pdp, path, lcol, tcol, x, temp);
1691 	}
1692 }
1693 
1694 /* Called from within view to plot overall graph  */
DoPlot(NSRect * rect,plot_info * pdp)1695 static void DoPlot(NSRect *rect, plot_info *pdp) {
1696 	int i, j;
1697 	int lx,ly;		/* Last x,y */
1698 	CGFloat dash_list[2] = {7.0, 2.0};
1699 	/* Note path and tcol are autorelease */
1700 	NSBezierPath *path = [NSBezierPath bezierPath];		/* Path to use */
1701 	NSColor *lcol = nil;
1702 	NSColor *tcol = nil;
1703 
1704 	/* Setup the plot info structure for this drawing */
1705 	/* Note port rect is raster like, pdp/Quartz2D is Postscript like */
1706 	pdp->sx = rect->origin.x;
1707 	pdp->sy = rect->origin.y;
1708 	pdp->sw = rect->size.width;
1709 	pdp->sh = rect->size.height;
1710 	pdp->scx = (pdp->sw - 20)/(pdp->mxx - pdp->mnx);
1711 	pdp->scy = (pdp->sh - 20)/(pdp->mxy - pdp->mny);
1712 
1713 	/* Plot the axis lines */
1714 	[path setLineWidth:1.0];
1715 	[path setLineDash: dash_list count: 2 phase: 0.0 ];	/* Set dashed lines for axes */
1716 
1717 	/* Make sure text is black */
1718 	tcol = [NSColor colorWithCalibratedRed: 0.0
1719 	                           green: 0.0
1720 	                            blue: 0.0
1721 	                           alpha: 1.0];
1722 
1723 	lcol = [NSColor colorWithCalibratedRed:0.7 green: 0.7 blue:0.7 alpha: 1.0];	/* Grey */
1724 
1725 	/* Plot horizontal axis */
1726 	if (pdp->revx)
1727 		loose_label(pdp, path, lcol, tcol, pdp->mxx, pdp->mnx, xtick);
1728 	else
1729 		loose_label(pdp, path, lcol, tcol, pdp->mnx, pdp->mxx, xtick);
1730 
1731 	/* Plot vertical axis */
1732 	loose_label(pdp, path, lcol, tcol, pdp->mny, pdp->mxy, ytick);
1733 
1734 	/* Set to non-dashed line */
1735 	[path setLineWidth: LTHICK];
1736 	[path setLineDash: NULL count: 0 phase: 0.0 ];
1737 
1738 	if (pdp->graph) {		/* Up to 6 graphs */
1739 		int gcolors[MXGPHS][3] = {
1740 			{   0,   0,   0},	/* Black */
1741 			{ 210,  30,   0},	/* Red */
1742 			{   0, 200,  90},	/* Green */
1743 			{   0,  10, 255},	/* Blue */
1744 			{ 200, 200,   0},	/* Yellow */
1745 			{ 220,   0, 255},	/* Purple */
1746 			{ 136,  86,  68},	/* Brown */
1747 			{ 248,  95,   0},	/* Orange */
1748 			{ 160, 160, 160},	/* Grey */
1749 			{ 220, 220, 220}	/* White */
1750 		};
1751 		for (j = MXGPHS-1; j >= 0; j--) {
1752 			double *yp = pdp->yy[j];
1753 
1754 			if (yp == NULL)
1755 				continue;
1756 			[[NSColor colorWithCalibratedRed: gcolors[j][0]/255.0
1757 			                           green: gcolors[j][1]/255.0
1758 			                            blue: gcolors[j][2]/255.0
1759 			                           alpha: 1.0] setStroke];
1760 
1761 			if (pdp->n > 0) {
1762 				lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5);
1763 				ly = (int)((     yp[0] - pdp->mny) * pdp->scy + 0.5);
1764 			}
1765 
1766 			for (i = 1; i < pdp->n; i++) {
1767 				int cx,cy;
1768 				cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
1769 				cy = (int)((     yp[i] - pdp->mny) * pdp->scy + 0.5);
1770 
1771 				ADrawLine(path, 20.0 + lx, 20.0 + ly, 20 + cx, 20.0 + cy);
1772 				if (pdp->flags & PLOTF_GRAPHCROSSES) {
1773 					ADrawLine(path, 20.0 + cx - 5, 20.0 - cy - 5, 20.0 + cx + 5, 20.0 + cy + 5);
1774 					ADrawLine(path, 20.0 + cx + 5, 20.0 - cy - 5, 20.0 + cx - 5, 20.0 + cy + 5);
1775 				}
1776 				lx = cx;
1777 				ly = cy;
1778 			}
1779 		}
1780 
1781 	} else {	/* Vectors */
1782 		[[NSColor colorWithCalibratedRed: 0.0
1783 		                           green: 0.0
1784 		                            blue: 0.0
1785 		                           alpha: 1.0] setStroke];
1786 		if (pdp->ntext != NULL) {
1787 			tcol = [NSColor colorWithCalibratedRed: 0.0
1788 			                           green: 0.0
1789 			                            blue: 0.0
1790 			                           alpha: 1.0];
1791 		}
1792 		for (i = 0; i < pdp->n; i++) {
1793 			int cx,cy;
1794 
1795 			lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
1796 			ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5);
1797 
1798 			cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5);
1799 			cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5);
1800 
1801 			ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy);
1802 
1803 			if (pdp->flags & PLOTF_VECCROSSES) {
1804 				ADrawLine(path, 20.0 + cx - 5, 20.0 + cy - 5, 20.0 + cx + 5, 20.0 + cy + 5);
1805 				ADrawLine(path, 20.0 + cx + 5, 20.0 + cy - 5, 20.0 + cx - 5, 20.0 + cy + 5);
1806 			}
1807 
1808 			if (pdp->ntext != NULL)
1809 				ADrawText(tcol, 9.0, 20.0 + cx + 9, 20.0 + cy - 7, 0x1, pdp->ntext[i]);
1810 		}
1811 	}
1812 
1813 	/* Extra points */
1814 	if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) {
1815 		[[NSColor colorWithCalibratedRed: 0.82		/* Orange ? */
1816 		                           green: 0.59
1817 		                            blue: 0.0
1818 		                           alpha: 1.0] setStroke];
1819 
1820 		for (i = 0; i < pdp->m; i++) {
1821 
1822 			if (pdp->mcols != NULL) {
1823 				[[NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0]
1824 				                           green: pdp->mcols[i].rgb[1]
1825 				                            blue: pdp->mcols[i].rgb[2]
1826 				                           alpha: 1.0] setStroke];
1827 
1828 				if (pdp->mtext != NULL) {
1829 					tcol = [NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0]
1830 					                           green: pdp->mcols[i].rgb[1]
1831 					                            blue: pdp->mcols[i].rgb[2]
1832 					                           alpha: 1.0];
1833 				}
1834 			}
1835 			lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5);
1836 			ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5);
1837 
1838 			ADrawLine(path, 20.0 + lx - 5, 20.0 + ly, 20.0 + lx + 5, 20.0 + ly);
1839 			ADrawLine(path, 20.0 + lx, 20.0 + ly - 5, 20.0 + lx, 20.0 + ly + 5);
1840 
1841 			if (pdp->mtext != NULL) {
1842 				ADrawText(tcol, 9.0, 20.0 + lx + 9, 20.0 + ly + 7, 0x1, pdp->mtext[i]);
1843 			}
1844 		}
1845 	}
1846 
1847 	/* Extra vectors */
1848 	if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) {
1849 		[[NSColor colorWithCalibratedRed: 0.5		/* Light blue */
1850 		                           green: 0.9
1851 		                            blue: 0.9
1852 		                           alpha: 1.0] setStroke];
1853 
1854 		for (i = 0; i < pdp->o; i++) {
1855 			int cx,cy;
1856 
1857 			if (pdp->ocols != NULL) {
1858 				[[NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0]
1859 				                           green: pdp->ocols[i].rgb[1]
1860 				                            blue: pdp->ocols[i].rgb[2]
1861 				                           alpha: 1.0] setStroke];
1862 				if (pdp->mtext != NULL) {
1863 					tcol = [NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0]
1864 					                           green: pdp->ocols[i].rgb[1]
1865 					                            blue: pdp->ocols[i].rgb[2]
1866 					                           alpha: 1.0];
1867 				}
1868 			}
1869 			lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5);
1870 			ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5);
1871 
1872 			cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5);
1873 			cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5);
1874 
1875 			ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy);
1876 		}
1877 	}
1878 }
1879 
1880 #else /* Assume UNIX + X11 */
1881 /* ********************************** X11 version ********************** */
1882 
1883 /* !!!! There is a problem if the user closes the window - an X11 error results */
1884 /*      This seems to happen before a DestroyNotify !. How to fix ??? !!!! */
1885 
1886 #include <X11/Xlib.h>
1887 #include <X11/Xutil.h>
1888 
1889 #ifdef DODEBUG
1890 # define debugf(xx)	printf xx
1891 #else
1892 # define debugf(xx)
1893 #endif
1894 
1895 void DoPlot(Display *mydisplay, Window mywindow, GC mygc, plot_info *pdp);
1896 
1897 /* Superset implementation function: */
1898 /* return 0 on success, -1 on error */
1899 /* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */
1900 /* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */
1901 /* Vector uses x1, y1 to x2, y2 as a vector with a (optional) diagonal cross at x2, y2 */
1902 /* all in black with annotation ntext at the cross, */
1903 /* plus a (optiona) diagonal cross at x7, y7 in yellow. The color for x7, y7 can be */
1904 /* overidden by an array of colors mcols, plus optional label text mtext. (x2 != NULL) */
1905 /* n = number of points/vectors. -ve for reversed X axis */
1906 /* m = number of extra points (x2,y3 or x7,y7) */
1907 /* x8,y8 to x9,y9 are extra optional vectors with optional colors */
do_plot_imp(int flags,double xmin,double xmax,double ymin,double ymax,double ratio,int dowait,double * x1,double * x2,double * yy[MXGPHS],char ** ntext,int n,double * x7,double * y7,plot_col * mcols,char ** mtext,int m,double * x8,double * y8,double * x9,double * y9,plot_col * ocols,int o)1908 static int do_plot_imp(
1909 	int flags,
1910     double xmin, double xmax, double ymin, double ymax,	/* Bounding box */
1911 	double ratio,	/* Aspect ratio of window, X/Y */
1912 	int dowait,		/* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
1913     double *x1, double *x2,
1914     double *yy[MXGPHS], char **ntext,
1915 	int n,
1916 	double *x7, double *y7, plot_col *mcols, char **mtext,
1917     int m,
1918 	double *x8, double *y8, double *x9, double*y9, plot_col *ocols,
1919 	int o
1920 ) {
1921 	{
1922 		int j;
1923 		double xr,yr;
1924 
1925 		pd.flags = flags;
1926 		pd.dowait = dowait;
1927 		pd.ratio = ratio;
1928 
1929 		pd.mnx = xmin;
1930 		pd.mny = ymin;
1931 		pd.mxx = xmax;
1932 		pd.mxy = ymax;
1933 
1934 		/* Allow some extra arround plot */
1935 		xr = pd.mxx - pd.mnx;
1936 		yr = pd.mxy - pd.mny;
1937 		if (xr < 1e-6)
1938 			xr = 1e-6;
1939 		if (yr < 1e-6)
1940 			yr = 1e-6;
1941 		pd.mnx -= xr/10.0;
1942 		pd.mxx += xr/10.0;
1943 		pd.mny -= yr/10.0;
1944 		pd.mxy += yr/10.0;
1945 
1946 		/* Transfer raw point info */
1947 		if (x2 == NULL)
1948 			pd.graph = 1;		/* 6 graphs + points */
1949 		else
1950 			pd.graph = 0;
1951 		pd.x1 = x1;
1952 		pd.x2 = x2;
1953 		for (j = 0; j < MXGPHS; j++)
1954 			pd.yy[j] = yy[j];
1955 		pd.ntext = ntext;
1956 		pd.n = abs(n);
1957 
1958 		if (n < 0) {
1959 			double tt;
1960 			tt = pd.mxx;
1961 			pd.mxx = pd.mnx;
1962 			pd.mnx = tt;
1963 			pd.revx = 1;
1964 		} else {
1965 			pd.revx = 0;
1966 		}
1967 		pd.x7 = x7;
1968 		pd.y7 = y7;
1969 		pd.mcols = mcols;
1970 		pd.mtext = mtext;
1971 		pd.m = abs(m);
1972 
1973 		pd.x8 = x8;
1974 		pd.y8 = y8;
1975 		pd.x9 = x9;
1976 		pd.y9 = y9;
1977 		pd.ocols = ocols;
1978 		pd.o = abs(o);
1979 	}
1980 
1981 	{
1982 		/* stuff for X windows */
1983 		char plot[] = {"plot"};
1984 		static Display *mydisplay = NULL;
1985 		static Window mywindow = -1;
1986 		int dorefresh = 1;
1987 		GC mygc;
1988 		XEvent myevent;
1989 		XSizeHints myhint;
1990 		XWindowAttributes mywattributes;
1991 		int myscreen;
1992 		unsigned long myforeground,mybackground;
1993 		int done;
1994 
1995 		ui_UsingGUI();
1996 
1997 		/* open the display */
1998 		if (mydisplay == NULL) {
1999 			mydisplay = XOpenDisplay("");
2000 			if(!mydisplay)
2001 				error("Unable to open display");
2002 			dorefresh = 0;
2003 		}
2004 		myscreen = DefaultScreen(mydisplay);
2005 		mybackground = WhitePixel(mydisplay,myscreen);
2006 		myforeground = BlackPixel(mydisplay,myscreen);
2007 
2008 		myhint.x = 100;
2009 		myhint.y = 100;
2010 		myhint.width = (int)(DEFWWIDTH * ratio + 0.5);
2011 		myhint.height = DEFWHEIGHT;
2012 		myhint.flags = PPosition | USSize;
2013 
2014 		debugf(("Opened display OK\n"));
2015 
2016 		if (mywindow == -1) {
2017 			debugf(("Opening window\n"));
2018 			mywindow = XCreateSimpleWindow(mydisplay,
2019 					DefaultRootWindow(mydisplay),
2020 					myhint.x,myhint.y,myhint.width,myhint.height,
2021 					5, myforeground,mybackground);
2022 			XSetStandardProperties(mydisplay,mywindow,plot,plot,None,
2023 			       NULL,0, &myhint);
2024 		}
2025 
2026 		mygc = XCreateGC(mydisplay,mywindow,0,0);
2027 		XSetBackground(mydisplay,mygc,mybackground);
2028 		XSetForeground(mydisplay,mygc,myforeground);
2029 
2030 		XSelectInput(mydisplay,mywindow,
2031 		     KeyPressMask | ExposureMask | StructureNotifyMask);
2032 
2033 		if (dorefresh) {
2034 			XExposeEvent ev;
2035 
2036 			ev.type = Expose;
2037 			ev.display = mydisplay;
2038 			ev.send_event = True;
2039 			ev.window = mywindow;
2040 			ev.x = 0;
2041 			ev.y = 0;
2042 			ev.width = myhint.width;
2043 			ev.height = myhint.height;
2044 			ev.count = 0;
2045 
2046 			XClearWindow(mydisplay, mywindow);
2047 			XSendEvent(mydisplay, mywindow, False, ExposureMask, (XEvent *)&ev);
2048 
2049 		} else {
2050 			if (pd.dowait > 0) {
2051 				XMapRaised(mydisplay,mywindow);
2052 				debugf(("Raised window\n"));
2053 			}
2054 		}
2055 
2056 		/* Main event loop */
2057 		debugf(("About to enter main loop\n"));
2058 		done = 0;
2059 		while(done == 0) {
2060 			XNextEvent(mydisplay,&myevent);
2061 			switch(myevent.type) {
2062 				case Expose:
2063 					if(myevent.xexpose.count == 0) {	/* Repare the exposed region */
2064 						XGetWindowAttributes(mydisplay, mywindow, & mywattributes);
2065 						/* Setup the plot info structure for this drawing */
2066 						pd.sx = mywattributes.x;
2067 						pd.sy = mywattributes.y;
2068 						pd.sw = mywattributes.width;
2069 						pd.sh = mywattributes.height;
2070 						pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx);
2071 						pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny);
2072 
2073 						DoPlot(mydisplay,mywindow, mygc, &pd);
2074 
2075 						if (pd.dowait <= 0) {		/* Don't wait */
2076 							if (pd.dowait < 0)
2077 								sleep(-pd.dowait);
2078 							debugf(("Not waiting, so set done=1\n"));
2079 							done = 1;
2080 						}
2081 					}
2082 					break;
2083 				case MappingNotify:
2084 					XRefreshKeyboardMapping(&myevent.xmapping);
2085 					break;
2086 				case KeyPress:
2087 					debugf(("Got a button press\n"));
2088 					done = 1;
2089 					break;
2090 			}
2091 		}
2092 		debugf(("About to close display\n"));
2093 		XFreeGC(mydisplay,mygc);
2094 //		XDestroyWindow(mydisplay,mywindow);
2095 //		XCloseDisplay(mydisplay);
2096 		debugf(("finished\n"));
2097 	}
2098 	return 0;
2099 }
2100 
2101 /* Draw X axis grid lines */
2102 void
xtick(Display * mydisplay,Window mywindow,GC mygc,plot_info * pdp,double x,char * lab)2103 xtick(
2104 Display *mydisplay,
2105 Window mywindow,
2106 GC mygc,
2107 plot_info *pdp,
2108 double x, char *lab
2109 ) {
2110 	int xx,yy;
2111 
2112 	xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5);
2113 	yy = pdp->sh - 10;
2114 
2115 	XDrawLine(mydisplay, mywindow, mygc, xx, yy, xx, 0);
2116 	XDrawImageString(mydisplay, mywindow, mygc, xx-6, yy, lab, strlen(lab));
2117 }
2118 
2119 /* Draw Y axis grid lines */
2120 void
ytick(Display * mydisplay,Window mywindow,GC mygc,plot_info * pdp,double y,char * lab)2121 ytick(
2122 Display *mydisplay,
2123 Window mywindow,
2124 GC mygc,
2125 plot_info *pdp,
2126 double y, char *lab
2127 ) {
2128 	int xx,yy;
2129 
2130 	xx = 5;
2131 	yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5);
2132 
2133 	XDrawLine(mydisplay, mywindow, mygc, xx, yy, pdp->sw, yy);
2134 	XDrawImageString(mydisplay, mywindow, mygc, xx, yy+4, lab, strlen(lab));
2135 }
2136 
2137 void
loose_label(Display * mydisplay,Window mywindow,GC mygc,plot_info * pdp,double min,double max,void (* pfunc)(Display * mydisplay,Window mywindow,GC mygc,plot_info * pdp,double,char *))2138 loose_label(
2139 Display *mydisplay,
2140 Window mywindow,
2141 GC mygc,
2142 plot_info *pdp,
2143 double min, double max,
2144 void (*pfunc)(Display *mydisplay, Window mywindow, GC mygc, plot_info *pdp, double, char *)
2145 ) {
2146 	char str[6], temp[20];
2147 	int nfrac;
2148 	double d;
2149 	double graphmin, graphmax;
2150 	double range,x;
2151 
2152 	range = nicenum(min-max,0);
2153 	d = nicenum(range/(NTICK-1),1);
2154 	graphmin = floor(min/d) * d;
2155 	graphmax = ceil(max/d) * d;
2156 	nfrac = (int)MAX(-floor(log10(d)),0);
2157 	sprintf(str,"%%.%df", nfrac);
2158 	for (x = graphmin; x < graphmax + 0.5 * d; x += d) {
2159 		sprintf(temp,str,x);
2160 		pfunc(mydisplay, mywindow, mygc, pdp, x, temp);
2161 	}
2162 }
2163 
2164 void
DoPlot(Display * mydisplay,Window mywindow,GC mygc,plot_info * pdp)2165 DoPlot(
2166 Display *mydisplay,
2167 Window mywindow,
2168 GC mygc,
2169 plot_info *pdp
2170 ) {
2171 	int i, j;
2172 	int lx,ly;		/* Last x,y */
2173 	char dash_list[2] = {5, 1};
2174 	Colormap mycmap;
2175 	XColor col;
2176 
2177 	mycmap = DefaultColormap(mydisplay, 0);
2178 	col.red = col.green = col.blue = 150 * 256;
2179 	XAllocColor(mydisplay, mycmap, &col);
2180 	XSetForeground(mydisplay,mygc, col.pixel);
2181 
2182 	/* Set dashed lines for axes */
2183 	XSetLineAttributes(mydisplay, mygc, 1, LineOnOffDash, CapButt, JoinBevel);
2184 	XSetDashes(mydisplay, mygc, 0, dash_list, 2);
2185 	// ~~ doesn't seem to work. Why ?
2186 
2187 	/* Plot horizontal axis */
2188 	if (pdp->revx)
2189 		loose_label(mydisplay, mywindow, mygc, pdp, pdp->mxx, pdp->mnx, xtick);
2190 	else
2191 		loose_label(mydisplay, mywindow, mygc, pdp, pdp->mnx, pdp->mxx, xtick);
2192 
2193 	/* Plot vertical axis */
2194 	loose_label(mydisplay, mywindow, mygc, pdp, pdp->mny, pdp->mxy, ytick);
2195 
2196 	if (pdp->graph) {		/* Up to 10 graphs */
2197 		for (j = MXGPHS-1; j >= 0; j--) {
2198 			double *yp = pdp->yy[j];
2199 
2200 			if (yp == NULL)
2201 				continue;
2202 
2203 			col.red   = gcolors[j][0] * 256;
2204 			col.green = gcolors[j][1] * 256;
2205 			col.blue  = gcolors[j][2] * 256;
2206 			XAllocColor(mydisplay, mycmap, &col);
2207 			XSetForeground(mydisplay,mygc, col.pixel);
2208 			XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
2209 
2210 			lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5);
2211 			ly = (int)((     yp[0] - pdp->mny) * pdp->scy + 0.5);
2212 
2213 			for (i = 0; i < pdp->n; i++) {
2214 				int cx,cy;
2215 				cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
2216 				cy = (int)((     yp[i] - pdp->mny) * pdp->scy + 0.5);
2217 
2218 				XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy);
2219 				if (pdp->flags & PLOTF_GRAPHCROSSES) {
2220 					XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5);
2221 					XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5);
2222 				}
2223 				lx = cx;
2224 				ly = cy;
2225 			}
2226 		}
2227 
2228 	} else {	/* Vectors */
2229 
2230 		col.red = col.green = col.blue = 0 * 256;
2231 		XAllocColor(mydisplay, mycmap, &col);
2232 		XSetForeground(mydisplay,mygc, col.pixel);
2233 		XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
2234 
2235 		for (i = 0; i < pdp->n; i++) {
2236 			int cx,cy;
2237 
2238 			lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5);
2239 			ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5);
2240 
2241 			cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5);
2242 			cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5);
2243 
2244 			/* Vector */
2245 			XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy);
2246 
2247 			if (pdp->flags & PLOTF_VECCROSSES) {
2248 				/* Cross at end of vector */
2249 				XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5);
2250 				XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5);
2251 			}
2252 
2253 			if (pdp->ntext != NULL)
2254 				XDrawImageString(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy + 7,
2255 				                 pdp->ntext[i], strlen(pdp->ntext[i]));
2256 		}
2257 	}
2258 
2259 	/* Extra points */
2260 	if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) {
2261 		col.red = 210 * 256; col.green = 150 * 256; col.blue = 0 * 256;
2262 		XAllocColor(mydisplay, mycmap, &col);
2263 		XSetForeground(mydisplay,mygc, col.pixel);
2264 		XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
2265 
2266 		for (i = 0; i < pdp->m; i++) {
2267 			lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5);
2268 			ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5);
2269 
2270 			if (pdp->mcols != NULL) {
2271 				col.red = (int)(pdp->mcols[i].rgb[0] * 65535.0 + 0.5);
2272 				col.green = (int)(pdp->mcols[i].rgb[1] * 65535.0 + 0.5);
2273 				col.blue = (int)(pdp->mcols[i].rgb[2] * 65535.0 + 0.5);
2274 
2275 				XAllocColor(mydisplay, mycmap, &col);
2276 				XSetForeground(mydisplay,mygc, col.pixel);
2277 
2278 			}
2279 			XDrawLine(mydisplay, mywindow, mygc, 10 + lx - 5, pdp->sh - 10 - ly,
2280 			                                     10 + lx + 5, pdp->sh - 10 - ly);
2281 			XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly - 5,
2282 			                                     10 + lx, pdp->sh - 10 - ly + 5);
2283 
2284 			if (pdp->mtext != NULL)
2285 				XDrawImageString(mydisplay, mywindow, mygc, 10 + lx + 5, pdp->sh - 10 - ly - 7,
2286 				                 pdp->mtext[i], strlen(pdp->mtext[i]));
2287 		}
2288 	}
2289 
2290 	/* Extra vectors */
2291 	if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) {
2292 		col.red = 150 * 256; col.green = 255 * 256; col.blue = 255 * 256;
2293 		XAllocColor(mydisplay, mycmap, &col);
2294 		XSetForeground(mydisplay,mygc, col.pixel);
2295 		XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
2296 
2297 		for (i = 0; i < pdp->o; i++) {
2298 			int cx,cy;
2299 
2300 			lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5);
2301 			ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5);
2302 
2303 			cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5);
2304 			cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5);
2305 
2306 			if (pdp->ocols != NULL) {
2307 				col.red = (int)(pdp->ocols[i].rgb[0] * 65535.0 + 0.5);
2308 				col.green = (int)(pdp->ocols[i].rgb[1] * 65535.0 + 0.5);
2309 				col.blue = (int)(pdp->ocols[i].rgb[2] * 65535.0 + 0.5);
2310 
2311 				XAllocColor(mydisplay, mycmap, &col);
2312 				XSetForeground(mydisplay,mygc, col.pixel);
2313 
2314 			}
2315 
2316 			XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy);
2317 		}
2318 	}
2319 }
2320 
2321 #endif /* UNIX + X11 */
2322 #endif /* !NT */
2323 /***********************************************************************/
2324 
2325 
2326 /* Nice graph labeling functions */
2327 
2328 #define expt(a,n) pow(a,(double)(n))
2329 
nicenum(double x,int round)2330 double nicenum(double x, int round) {
2331 	int ex;
2332 	double f;
2333 	double nf;
2334 // printf("nocenum called with %f and %d\n",x,round);
2335 	if (x < 0.0)
2336 		x = -x;
2337 	ex = (int)floor(log10(x));
2338 // printf("ex = %d\n",ex);
2339 	f = x/expt(10.0,ex);
2340 // printf("f = %f\n",f);
2341 	if (round) {
2342 		if (f < 1.5) nf = 1.0;
2343 		else if (f < 3.0) nf = 2.0;
2344 		else if (f < 7.0) nf = 5.0;
2345 		else nf = 10.0;
2346 	} else {
2347 		if (f < 1.0) nf = 1.0;
2348 		else if (f < 2.0) nf = 2.0;
2349 		else if (f < 5.0) nf = 5.0;
2350 		else nf = 10.0;
2351 	}
2352 // printf("nf = %f\n",nf);
2353 // printf("about to return %f\n",(nf * expt(10.0, ex)));
2354 	return (nf * expt(10.0, ex));
2355 }
2356 
2357 /* ---------------------------------------------------------------- */
2358 #ifdef STANDALONE_TEST
2359 /* test code */
2360 
2361 //#include <windows.h>
2362 //#include <stdio.h>
2363 #include <fcntl.h>
2364 //#include <io.h>
2365 
2366 
2367 #ifdef NEVER
2368 /* Append debugging string to log.txt */
dprintf(char * fmt,...)2369 static void dprintf(char *fmt, ...) {
2370 	FILE *fp = NULL;
2371 	if ((fp = fopen("log.txt", "a+")) != NULL) {
2372 		va_list args;
2373 		va_start(args, fmt);
2374 		vfprintf(fp, fmt, args);
2375 		fflush(fp);
2376 	   	fclose(fp);
2377 		va_end(args);
2378 	}
2379 }
2380 #endif // NEVER
2381 
2382 #ifdef NEVER	/* Other non-working enable console output code */
2383 {
2384 	/* This clever code have been found at:
2385 	   Adding Console I/O to a Win32 GUI App
2386 	   Windows Developer Journal, December 1997
2387 	   http://dslweb.nwnexus.com/~ast/dload/guicon.htm
2388 	   Andrew Tucker's Home Page */
2389 
2390 	/* This is not so clever, since it doesn't work... */
2391 
2392 	// redirect unbuffered STDOUT to the console
2393 	long lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
2394 	int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
2395 	FILE *fp = _fdopen(hConHandle, "w");
2396 	*stdout = *fp;
2397 	setvbuf(stdout, NULL, _IONBF, 0);
2398 
2399 	// redirect unbuffered STDIN to the console
2400 	lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
2401 	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
2402 	fp = _fdopen( hConHandle, "r" );
2403 	*stdin = *fp;
2404 	setvbuf(stdin, NULL, _IONBF, 0);
2405 
2406 	// redirect unbuffered STDERR to the console
2407 	lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
2408 	hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
2409 	fp = _fdopen( hConHandle, "w" );
2410 	*stderr = *fp;
2411 	setvbuf(stderr, NULL, _IONBF, 0);
2412 
2413 
2414 }
2415 #endif // NEVER
2416 
2417 #ifdef NEVER
2418 // ~~~~~~~~~~~~~
2419 //	AllocConsole();
2420 	{
2421 		ULONG pbi[6];
2422 		ULONG ulSize = 0;
2423 		LONG (WINAPI *NtQueryInformationProcess)(HANDLE ProcessHandle,
2424 		                                         ULONG ProcessInformationClass,
2425 		                                         PVOID ProcessInformation,
2426 		                                         ULONG ProcessInformationLength,
2427 		                                         PULONG ReturnLength);
2428 
2429 		BOOL (WINAPI *AttachConsole)(DWORD dwProcessId);
2430 
2431 		*(FARPROC *)&NtQueryInformationProcess =
2432 		          GetProcAddress(LoadLibraryA("NTDLL.DLL"), "NtQueryInformationProcess");
2433 		if(NtQueryInformationProcess) {
2434 printf("~1 found NtQueryInformationProcess\n"); fflush(stdout);
2435 			if(NtQueryInformationProcess(GetCurrentProcess(), 0,
2436 			    &pbi, sizeof(pbi), &ulSize) >= 0 && ulSize == sizeof(pbi)) {
2437 printf("~1 NtQueryInformationProcess suceeded\n"); fflush(stdout);
2438 
2439 				*(FARPROC *)&AttachConsole =
2440 		          GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole");
2441 
2442 				if (AttachConsole) {
2443 printf("~1 found AttachConsole\n"); fflush(stdout);
2444 					AttachConsole(pbi[5]);
2445 printf("~1 about to freopen CONNOUT\n"); fflush(stdout);
2446 					freopen("CONOUT$","wb",stdout);
2447 				} else {
2448 printf("~1 failed to find AttachConsole\n"); fflush(stdout);
2449 				}
2450 			}
2451 		}
2452 		// AttachConsole(ID ATTACH_PARENT_CONSOLE); 	// Should work on XP ??
2453 
2454 		/* i mean OpenConsoleW - you are as picky as i am - its
2455 		   ordinal=519 and it is exported by name; the header(s)
2456 		   do not include it, which tells me there's got to be a
2457 		   reason for that.
2458 		 */
2459 	}
2460 // ~~~~~~~~~~~~~
2461 #endif // NEVER
2462 
2463 
main(int argc,char * argv[])2464 int main(int argc, char *argv[]) {
2465 	double x[10]  = {0.0, 0.5, 0.7, 1.0};
2466 	double y1[10] = {0.0, 0.5, 0.7, 1.0};
2467 	double y2[10] = {0.9, 0.8, 1.4, 1.2};
2468 	double y3[10] = {0.1, 0.8, 0.7, -0.1};
2469 
2470 	double Bx1[10] = {0.0, 0.5, 0.9, 0.5};
2471 	double By1[10] = {0.0, 0.3, 1.2, 0.2};
2472 	double Bx2[10] = {0.1, 0.8, 0.1, 0.2};
2473 	double By2[10] = {0.1, 1.8, 2.0, 0.5};
2474 
2475 	double Bx3[10] = {0.8, 0.4, 1.3, 0.5, 0.23};
2476 	double By3[10] = {0.5, 1.3, 0.4, 0.7, 0.77};
2477 
2478 	plot_col mcols[5] = {
2479 	{ 1.0, 0.0, 0.0 },
2480 	{ 0.0, 1.0, 0.0 },
2481 	{ 0.0, 0.0, 1.0 },
2482 	{ 0.6, 0.6, 0.6 },
2483 	{ 1.0, 1.0, 0.0 } };
2484 
2485 	char *ntext[5] = { "A", "B", "C", "D" };
2486 	char *mtext[5] = { "10", "20", "30", "40", "50" };
2487 
2488 	printf("Doing first plot\n");
2489 	if (do_plot(x,y1,y2,y3,4) < 0)
2490 		printf("Error - do_plot returned -1!\n");
2491 
2492 	/* Try a second plot */
2493 	printf("Doing second plot\n");
2494 	x[2] = 0.55;
2495 	if (do_plot(x,y2,y3,y1,3) < 0)
2496 		printf("Error - do_plot returned -1!\n");
2497 
2498 	/* Try vectors */
2499 	printf("Doing vector plot\n");
2500 	if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, NULL, NULL, 5))
2501 		printf("Error - do_plot_vec returned -1!\n");
2502 
2503 	printf("Doing vector plot with colors and notation\n");
2504 	if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, mcols, mtext, 5))
2505 		printf("Error - do_plot_vec returned -1!\n");
2506 
2507 	printf("Doing vector plot with colors and notation + extra vectors\n");
2508 	if (do_plot_vec2(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, ntext, 4, 1, Bx3, By3, mcols, mtext, 5,
2509 	                x,y1,y2,y3,mcols,4))
2510 		printf("Error - do_plot_vec returned -1!\n");
2511 
2512 	printf("We're done\n");
2513 	return 0;
2514 }
2515 
2516 #endif /* STANDALONE_TEST */
2517 /* ---------------------------------------------------------------- */
2518 
2519