From 22f703cab05b7cd368f4de9e03991b7664dc5022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Mon, 1 Sep 2014 13:56:46 +0200 Subject: Initial import of argyll version 1.5.1-8 --- plot/plot.c | 2511 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2511 insertions(+) create mode 100644 plot/plot.c (limited to 'plot/plot.c') diff --git a/plot/plot.c b/plot/plot.c new file mode 100644 index 0000000..c5ca910 --- /dev/null +++ b/plot/plot.c @@ -0,0 +1,2511 @@ + +/* + * Copyright 1998 - 2004 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + */ + +/* This is a simple 2d graph plotter that runs on MSWindows/OSX/X11 */ +/* The code is in three sections, one for each GUI environment. */ +/* (Perhaps common code could be consolidated ?) */ + + +/* + * TTBD: + * + * Allow for a window title for each plot. + * + * Put all state information in plot_info (window handles etc.) + * Create thread to handle events, so it updates correctly. + * (Will have to lock plot info updates or ping pong them); + * Have call to destroy window. + * (Could then move to having multiple instances of plot). + * + * OS X Cocoa code doesn't get window focus. No idea why. + * + */ + +#include +#include +#include +#include +#ifdef UNIX +#include +#endif +#include +#include "numlib.h" +#include "plot.h" + +#undef DODEBUG /* Print error messages & progress reports */ +//#define STANDALONE_TEST /* Defined by build script */ + +#define NTICK 10 +#define LTHICK 1.2 /* Plot line thickness */ +#define ILTHICK ((int)(LTHICK+0.5)) /* Integer line thickness */ +//#define ILTHICK 2 +#undef CROSSES /* Mark input points with crosses */ + +#define DEFWWIDTH 500 +#define DEFWHEIGHT 500 + +/* Graph order is Black = Y1, Red = Y2, Green = Y3, Blue = Y4, Yellow = Y5, Purple = Y6 */ +/* Brown = Y7, Orange = Y8, Grey = Y9, Magenta = Y10 */ + +double nicenum(double x, int round); + +#define MXGPHS 10 /* Number of graphs with common X axis */ + +/* Colors of the graphs */ +static int gcolors[MXGPHS][3] = { + { 0, 0, 0}, /* Black */ + { 210, 30, 0}, /* Red */ + { 0, 200, 90}, /* Green */ + { 0, 10, 255}, /* Blue */ + { 200, 200, 0}, /* Yellow */ + { 220, 0, 255}, /* Purple */ + { 136, 86, 68}, /* Brown */ + { 248, 95, 0}, /* Orange */ + { 160, 160, 160}, /* Grey */ + { 220, 30, 220} /* Magenta */ +}; + +/* Information defining plot */ +/* There is one global instance of this. */ +struct _plot_info { + void *cx; /* Other Context */ + + int dowait; /* Wait for user key if > 0, wait for n secs if < 0 */ + double ratio; /* Aspect ratio of window, X/Y */ + + /* Plot point information */ + double mnx, mxx, mny, mxy; /* Extrema of values to be plotted */ + int graph; /* NZ if graph, Z if vectors */ + int revx; /* reversed X axis */ + + double *x1, *x2; + double *yy[MXGPHS]; /* y1 - y10 */ + char **ntext; + int n; + + double *x7, *y7; + plot_col *mcols; + char **mtext; + int m; + + double *x8, *y8, *x9, *y9; + plot_col *ocols; + int o; + + /* Plot instance information */ + int sx,sy; /* Screen offset */ + int sw,sh; /* Screen width and height */ + double scx, scy; /* Scale from input values to screen pixels */ + + }; typedef struct _plot_info plot_info; + +/* Global to transfer info to window callback */ +static plot_info pd; + +/* Declaration of superset */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + 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 +); + + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +/* Public routines */ +/* Plot up to 3 graphs. Wait for key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot( +double *x, +double *y1, /* Up to 3 graphs */ +double *y2, +double *y3, +int n) { + int i, j; + double xmin, xmax, ymin, ymax; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, 0, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 3 graphs + crosses. Wait for key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot_p( +double *x, +double *y1, /* Up to 3 graphs */ +double *y2, +double *y3, +int n, +double *x4, double *y4, /* And crosses */ +int m) { + int i, j; + double xmin, xmax, ymin, ymax; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + for (i = 0; i < m; i++) { + if (x4 != NULL) { + if (xmin > x4[i]) + xmin = x4[i]; + if (xmax < x4[i]) + xmax = x4[i]; + } + if (y4 != NULL) { + if (ymin > y4[i]) + ymin = y4[i]; + if (ymax < y4[i]) + ymax = y4[i]; + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + x4, y4, NULL, NULL, m , + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Plot up to 3 graphs with specified window size. */ +/* if dowait > 0, wait for user key */ +/* if dowait < 0, wait for no seconds */ +/* If xmax > xmin, use as x scale, else auto. */ +/* If ymax > ymin, use as y scale, else auto. */ +/* ratio is window X / Y */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +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 +) { + int i, j; + double xmin, xmax, ymin, ymax; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + if (pxmax > pxmin) { + xmax = pxmax; + xmin = pxmin; + } + if (pymax > pymin) { + ymax = pymax; + ymin = pymin; + } + + return do_plot_imp(xmin, xmax, ymin, ymax, ratio, dowait, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, 0, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 6 graphs. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot6( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +int n) { /* Number of values */ + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, n , + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 6 graphs + optional crosses. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot6p( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +int n, /* Number of values */ +double *xp, double *yp, /* And crosses */ +int m) { + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + for (i = 0; i < m; i++) { + if (xp != NULL) { + if (xmin > xp[i]) + xmin = xp[i]; + if (xmax < xp[i]) + xmax = xp[i]; + } + if (yp != NULL) { + if (ymin > yp[i]) + ymin = yp[i]; + if (ymax < yp[i]) + ymax = yp[i]; + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + xp, yp, NULL, NULL, m, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 10 graphs. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot10( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +double *y7, /* Brown */ +double *y8, /* Orange */ +double *y9, /* Grey */ +double *y10,/* White */ +int n, /* Number of values */ +int zero /* Flag - make sure zero is in y range */ +) { + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + yy[6] = y7; + yy[7] = y8; + yy[8] = y9; + yy[9] = y10; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + if (zero && ymin > 0.0) + ymin = 0.0; + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + NULL, NULL, NULL, NULL, n , + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Public routines */ +/* Plot up to 10 graphs + optional crosses. Wait for a key */ +/* return 0 on success, -1 on error */ +/* If n is -ve, reverse the X axis */ +int +do_plot10p( +double *x, /* X coord */ +double *y1, /* Black */ +double *y2, /* Red */ +double *y3, /* Green */ +double *y4, /* Blue */ +double *y5, /* Yellow */ +double *y6, /* Purple */ +double *y7, /* Brown */ +double *y8, /* Orange */ +double *y9, /* Grey */ +double *y10,/* White */ +int n, /* Number of values */ +double *xp, double *yp, /* And crosses */ +int m) { + int i, j; + double xmin, xmax, ymin, ymax; + int nn = abs(n); + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + yy[2] = y3; + yy[3] = y4; + yy[4] = y5; + yy[5] = y6; + yy[6] = y7; + yy[7] = y8; + yy[9] = y9; + yy[5] = y10; + + /* Determine min and max dimensions of plot */ + xmin = ymin = 1e6; + xmax = ymax = -1e6; + + for (i = 0; i < n; i++) { + if (xmin > x[i]) + xmin = x[i]; + if (xmax < x[i]) + xmax = x[i]; + + for (j = 0; j < MXGPHS; j++) { + if (yy[j] != NULL) { + if (ymin > yy[j][i]) + ymin = yy[j][i]; + if (ymax < yy[j][i]) + ymax = yy[j][i]; + } + } + } + + for (i = 0; i < m; i++) { + if (xp != NULL) { + if (xmin > xp[i]) + xmin = xp[i]; + if (xmax < xp[i]) + xmax = xp[i]; + } + if (yp != NULL) { + if (ymin > yp[i]) + ymin = yp[i]; + if (ymax < yp[i]) + ymax = yp[i]; + } + } + + /* Work out scale factors */ + if ((xmax - xmin) == 0.0) + xmax += 0.5, xmin -= 0.5; + if ((ymax - ymin) == 0.0) + ymax += 0.5, ymin -= 0.5; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, 1, + x, NULL, yy, NULL, n, + xp, yp, NULL, NULL, m, + NULL, NULL, NULL, NULL, NULL, 0); +} + + +/* Plot a bunch of vectors + optional crosses */ +/* return 0 on success, -1 on error */ +int do_plot_vec( +double xmin, +double xmax, +double ymin, +double ymax, +double *x1, /* vector start */ +double *y1, +double *x2, /* vector end */ +double *y2, +int n, /* Number of vectors */ +int dowait, +double *x3, /* extra point */ +double *y3, +plot_col *mcols, /* point colors */ +char **mtext, /* notation */ +int m /* Number of points */ +) { + int j; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, dowait, + x1, x2, yy, NULL, n, + x3, y3, mcols, mtext, m, + NULL, NULL, NULL, NULL, NULL, 0); +} + +/* Plot a bunch of vectors + optional crosses + optional vectors*/ +/* return 0 on success, -1 on error */ +int do_plot_vec2( +double xmin, +double xmax, +double ymin, +double ymax, +double *x1, /* n vector start */ +double *y1, +double *x2, /* vector end and diagonal cross */ +double *y2, +char **ntext, /* text annotation at cross */ +int n, /* Number of vectors */ +int dowait, +double *x3, /* m extra point */ +double *y3, +plot_col *mcols,/* point colors */ +char **mtext, /* text annotation */ +int m, /* Number of points */ +double *x4, /* o vector start */ +double *y4, +double *x5, /* o vector end */ +double *y5, +plot_col *ocols,/* Vector colors */ +int o /* Number of vectors */ +) { + int j; + double *yy[MXGPHS]; + + for (j = 0; j < MXGPHS; j++) + yy[j] = NULL; + + yy[0] = y1; + yy[1] = y2; + + return do_plot_imp(xmin, xmax, ymin, ymax, 1.0, dowait, + x1, x2, yy, ntext, n, + x3, y3, mcols, mtext, m, + x4, y4, x5, y5, ocols, o); +} +/* ********************************** NT version ********************** */ +#ifdef NT + +#include + +#ifdef DODEBUG +# define debugf(xx) printf xx +#else +# define debugf(xx) +#endif + +double plot_ratio = 1.0; +HANDLE plot_th; /* Thread */ +char plot_AppName[] = "PlotWin"; +HWND plot_hwnd = NULL; /* Open only one window per session */ +int plot_signal = 0; /* Signal a key or quit */ + +static LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM); + +/* Thread to handle message processing, so that there is no delay */ +/* when the main thread is doing other things. */ +DWORD WINAPI plot_message_thread(LPVOID lpParameter) { + MSG msg; + WNDCLASS wc; + ATOM arv; + HWND _hwnd; + + // Fill in window class structure with parameters that describe the + // main window. + + wc.style = CS_HREDRAW | CS_VREDRAW; // Class style(s). + wc.lpfnWndProc = MainWndProc; // Function to retrieve messages for windows of this class. + wc.cbClsExtra = 0; // No per-class extra data. + wc.cbWndExtra = 0; // No per-window extra data. + wc.hInstance = NULL; // Application that owns the class. + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_CROSS); + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = plot_AppName; + + arv = RegisterClass(&wc); + + if (!arv) { + debugf(("RegisterClass failed, lasterr = %d\n",GetLastError())); + return -1; + } + + _hwnd = CreateWindow( + plot_AppName, + "2D Diagnostic Graph Plot", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + (int)(DEFWWIDTH * plot_ratio + 0.5), + DEFWHEIGHT, + NULL, + NULL, + NULL, // hInstance, + NULL); + + if (!_hwnd) { + debugf(("CreateWindow failed, lasterr = %d\n",GetLastError())); + return -1; + } + + ShowWindow(_hwnd, SW_SHOW); + + plot_hwnd = _hwnd; + + /* Now process messages until we're done */ + for (;;) { + if (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + if (plot_signal == 99) + break; + } + } + + if (UnregisterClass(plot_AppName, NULL) == 0) { + debugf(("UnregisterClass failed, lasterr = %d\n",GetLastError())); + } + + plot_hwnd = NULL; /* Signal it's been deleted */ + + return 0; +} + +/* Superset implementation function: */ +/* return 0 on success, -1 on error */ +/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */ +/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */ +/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */ +/* with annotation ntext at the cross, */ +/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */ +/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */ +/* n = number of points/vectors. -ve for reversed X axis */ +/* m = number of extra points (x2,y3 or x7,y7) */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + 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 +) { + pd.dowait = 10 * dowait; + pd.ratio = ratio; + { + int j; + double xr,yr; + + pd.mnx = xmin; + pd.mny = ymin; + pd.mxx = xmax; + pd.mxy = ymax; + + /* Allow some extra around plot */ + xr = pd.mxx - pd.mnx; + yr = pd.mxy - pd.mny; + if (xr < 1e-6) + xr = 1e-6; + if (yr < 1e-6) + yr = 1e-6; + pd.mnx -= xr/10.0; + pd.mxx += xr/10.0; + pd.mny -= yr/10.0; + pd.mxy += yr/10.0; + + /* Transfer raw point info */ + if (x2 == NULL) + pd.graph = 1; /* 6 graphs + points */ + else + pd.graph = 0; + pd.x1 = x1; + pd.x2 = x2; + for (j = 0; j < MXGPHS; j++) + pd.yy[j] = yy[j]; + pd.ntext = ntext; + pd.n = abs(n); + + if (n < 0) { + double tt; + tt = pd.mxx; + pd.mxx = pd.mnx; + pd.mnx = tt; + pd.revx = 1; + } else { + pd.revx = 0; + } + pd.x7 = x7; + pd.y7 = y7; + pd.mcols = mcols; + pd.mtext = mtext; + pd.m = abs(m); + + pd.x8 = x8; + pd.y8 = y8; + pd.x9 = x9; + pd.y9 = y9; + pd.ocols = ocols; + pd.o = abs(o); + } + + /* ------------------------------------------- */ + /* Setup windows stuff */ + { + + /* It would be nice to reduce number of globals. */ + + /* We don't clean up properly either - ie. don't delete thread etc. */ + + /* Create thread that creats window and processes window messages */ + if (plot_hwnd == NULL) { + + plot_ratio = ratio; + + plot_th = CreateThread(NULL, 0, plot_message_thread, NULL, 0, NULL); + if (plot_th == NULL) { + debugf(("new_athread failed\n")); + return -1; + } + while (plot_hwnd == NULL) + Sleep(50); + } + + plot_signal = 0; + + SetForegroundWindow(plot_hwnd); + + /* Force a repaint with the new data */ + if (!InvalidateRgn(plot_hwnd,NULL,TRUE)) { + debugf(("InvalidateRgn failed, lasterr = %d\n",GetLastError())); + return -1; + } + + if (dowait > 0) { /* Wait for a space key */ + while(plot_signal == 0 && plot_hwnd != NULL) + Sleep(50); + plot_signal = 0; + } else if (dowait < 0) { + Sleep(-dowait * 1000); + } + } + return 0; +} + +void DoPlot(HDC hdc, plot_info *pd); + +static LRESULT CALLBACK MainWndProc( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam +) { + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + + debugf(("Handling message type 0x%x\n",message)); + // Could use Set/GetWindowLong() to pass window class info instead of global pd (beware NULL) + switch(message) { + case WM_PAINT: + debugf(("It's a paint message\n")); + hdc = BeginPaint(hwnd, &ps); + GetClientRect(hwnd, &rect); + + /* Setup the plot info structure for this drawing */ + pd.sx = rect.left; + pd.sy = rect.top; + pd.sw = 1 + rect.right - rect.left; + pd.sh = 1 + rect.bottom - rect.top; + pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx); + pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny); + + DoPlot(hdc, &pd); + + EndPaint(hwnd, &ps); + + return 0; + + case WM_CHAR: + debugf(("It's a char message, wParam = 0x%x\n",wParam)); + switch(wParam) { + case ' ': /* Space */ + debugf(("It's a SPACE, so signal it\n")); + plot_signal = 1; + return 0; + } + + case WM_CLOSE: + debugf(("It's a close message\n")); + DestroyWindow(hwnd); + return 0; + + case WM_DESTROY: + debugf(("It's a destroy message\n")); + plot_signal = 99; + PostQuitMessage(0); + return 0; + } + + debugf(("It's a message not handled here\n")); + return DefWindowProc(hwnd, message, wParam, lParam); +} + +void +xtick(HDC hdc, plot_info *pdp, double x, char *lab) + { + int xx,yy; + RECT rct; +// GrLine(10 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 - 5, +// 10 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 + 5, 1); +// GrTextXY(5 + (int)((x - pdp->mnx) * scx + 0.5), sh - 10 - 10, lab, 1, 0); + + xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5); + yy = pdp->sh - 10; + + MoveToEx(hdc,xx, yy, NULL); + LineTo( hdc,xx, 0); + rct.right = + rct.left = xx; + rct.top = + rct.bottom = yy; + DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP); + } + +void +ytick(HDC hdc, plot_info *pdp, double y, char *lab) + { + int xx,yy; + RECT rct; +// GrLine(5, 10 + (int)((y - pdp->mny) * pdp->scy + 0.5), +// 15, 10 + (int)((y - pdp->mny) * pdp->scy + 0.5), 1); +// GrTextXY(5, pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5), lab, 1, 0); + + xx = 5; + yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5); + MoveToEx(hdc,xx, yy,NULL); + LineTo( hdc,pdp->sw, yy); + rct.right = + rct.left = xx; + rct.top = + rct.bottom = yy; + DrawText(hdc, lab, -1, &rct, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_NOCLIP); + } + +void +loose_label(HDC hdc, plot_info *pdp, double min, double max, void (*pfunc)(HDC hdc, plot_info *pdp, double, char *) +) { + char str[6], temp[20]; + int nfrac; + double d; + double graphmin, graphmax; + double range,x; + + range = nicenum(min-max,0); + d = nicenum(range/(NTICK-1),1); + graphmin = floor(min/d) * d; + graphmax = ceil(max/d) * d; + nfrac = (int)MAX(-floor(log10(d)),0); + sprintf(str,"%%.%df", nfrac); + for (x = graphmin; x < graphmax + 0.5 * d; x += d) { + sprintf(temp,str,x); + pfunc(hdc,pdp,x,temp); + } +} + +void +DoPlot( +HDC hdc, +plot_info *pdp +) { + int i, j; + int lx,ly; /* Last x,y */ + HPEN pen; + + pen = CreatePen(PS_DOT,0,RGB(200,200,200)); + + SaveDC(hdc); + SelectObject(hdc,pen); + + /* Plot horizontal axis */ + if (pdp->revx) + loose_label(hdc, pdp, pdp->mxx, pdp->mnx, xtick); + else + loose_label(hdc, pdp, pdp->mnx, pdp->mxx, xtick); + + /* Plot vertical axis */ + loose_label(hdc, pdp, pdp->mny, pdp->mxy, ytick); + + RestoreDC(hdc,-1); + DeleteObject(pen); + + if (pdp->graph) { /* Up to MXGPHS graphs + crosses */ + int gcolors[MXGPHS][3] = { + { 0, 0, 0}, /* Black */ + { 210, 30, 0}, /* Red */ + { 0, 200, 90}, /* Green */ + { 0, 10, 255}, /* Blue */ + { 200, 200, 0}, /* Yellow */ + { 220, 0, 255}, /* Purple */ + { 136, 86, 68}, /* Brown */ + { 248, 95, 0}, /* Orange */ + { 160, 160, 160}, /* Grey */ + { 220, 220, 220} /* White */ + }; + for (j = MXGPHS-1; j >= 0; j--) { + double *yp = pdp->yy[j]; + + if (yp == NULL) + continue; + + pen = CreatePen(PS_SOLID,ILTHICK,RGB(gcolors[j][0],gcolors[j][1],gcolors[j][2])); + SelectObject(hdc,pen); + + lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5); + + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + cx, pdp->sh - 10 - cy); +#ifdef CROSSES + MoveToEx(hdc, 10 + cx - 5, pdp->sh - 10 - cy - 5, NULL); + LineTo(hdc, 10 + cx + 5, pdp->sh - 10 - cy + 5); + GrLine(10 + cx + 5, pdp->sh - 10 - cy - 5); + LineTo(hdc, 10 + cx - 5, pdp->sh - 10 - cy + 5); +#endif + lx = cx; + ly = cy; + } + DeleteObject(pen); + } + + } else { /* Vectors with cross */ + + pen = CreatePen(PS_SOLID,ILTHICK,RGB(0,0,0)); + SelectObject(hdc,pen); + + if (pdp->ntext != NULL) { + HFONT fon; + + fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + FF_DONTCARE, NULL); + + if (fon == NULL) + fprintf(stderr,"plot: CreateFont returned NULL\n"); + else { + SelectObject(hdc,fon); + DeleteObject(fon); + } + } + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + + lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5); + + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + cx, pdp->sh - 10 - cy); + + MoveToEx(hdc, 10 + cx - 5, pdp->sh - 10 - cy - 5, NULL); + LineTo(hdc, 10 + cx + 5, pdp->sh - 10 - cy + 5); + MoveToEx(hdc, 10 + cx + 5, pdp->sh - 10 - cy - 5, NULL); + LineTo(hdc, 10 + cx - 5, pdp->sh - 10 - cy + 5); + + if (pdp->ntext != NULL) { + RECT rct; + rct.right = + rct.left = 10 + cx + 10; + rct.top = + rct.bottom = pdp->sh - 10 - cy + 10; + DrawText(hdc, pdp->ntext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP); + } + } + DeleteObject(pen); + } + + /* Extra points */ + if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) { + pen = CreatePen(PS_SOLID,ILTHICK,RGB(210,150,0)); + SelectObject(hdc,pen); + + if (pdp->mtext != NULL) { + HFONT fon; + + + fon = CreateFont(12, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, ANSI_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, + FF_DONTCARE, NULL); + + if (fon == NULL) + fprintf(stderr,"plot: CreateFont returned NULL\n"); + else { + SelectObject(hdc,fon); + DeleteObject(fon); + } + } + + for (i = 0; i < pdp->m; i++) { + lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->mcols != NULL) { + int rgb[3]; + + for (j = 0; j < 3; j++) + rgb[j] = (int)(pdp->mcols[i].rgb[j] * 255.0 + 0.5); + + DeleteObject(pen); + pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2])); + SelectObject(hdc,pen); + + if (pdp->mtext != NULL) + SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2])); + } + MoveToEx(hdc, 10 + lx - 5, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + lx + 5, pdp->sh - 10 - ly); + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly - 5, NULL); + LineTo(hdc, 10 + lx, pdp->sh - 10 - ly + 5); + + if (pdp->mtext != NULL) { + RECT rct; + rct.right = + rct.left = 10 + lx + 10; + rct.top = + rct.bottom = pdp->sh - 10 - ly - 10; + DrawText(hdc, pdp->mtext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP); + } + } + DeleteObject(pen); + } + /* Extra vectors */ + if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) { + pen = CreatePen(PS_SOLID,ILTHICK,RGB(150,255,255)); + SelectObject(hdc,pen); + + for (i = 0; i < pdp->o; i++) { + int cx,cy; + + lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->ocols != NULL) { + int rgb[3]; + + for (j = 0; j < 3; j++) + rgb[j] = (int)(pdp->ocols[i].rgb[j] * 255.0 + 0.5); + + DeleteObject(pen); + pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2])); + SelectObject(hdc,pen); + + if (pdp->mtext != NULL) + SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2])); + } + MoveToEx(hdc, 10 + lx, pdp->sh - 10 - ly, NULL); + LineTo(hdc, 10 + cx, pdp->sh - 10 - cy); + } + DeleteObject(pen); + } + +// while(!kbhit()); + } + +#else /* !NT */ + +/* ************************** APPLE OSX Cocoa version ****************** */ +#ifdef __APPLE__ + +#include +#include + +#ifndef CGFLOAT_DEFINED +#ifdef __LP64__ +typedef double CGFloat; +#else +typedef float CGFloat; +#endif /* defined(__LP64__) */ +#endif + +#ifdef DODEBUG +# define debugf(xx) printf xx +#else +# define debugf(xx) +#endif + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +@class PLWin; +@class PLView; + +/* Our static instance variables */ +typedef struct { + PLWin *window; /* NSWindow */ + PLView *view; /* NSTextField */ + volatile int plot_signal; /* Signal a key or quit */ +} cntx_t; + +/* Global plot instanc */ + +cntx_t *plot_cx = NULL; + +// - - - - - - - - - - - - - - - - - - - - - - - - - +@interface PLView : NSView { + cntx_t *cntx; +} +- (void)setCntx:(cntx_t *)cntx; +@end + +@implementation PLView + +- (void)setCntx:(cntx_t *)val { + cntx = val; +} + +/* This function does the work */ +static void DoPlot(NSRect *rect, plot_info *pdp); + +- (void)drawRect:(NSRect)rect { + + /* Use global plot data struct for now */ + DoPlot(&rect, &pd); +} + +@end + +// - - - - - - - - - - - - - - - - - - - - - - - - - + +@interface PLWin : NSWindow { + cntx_t *cntx; +} +- (void)setCntx:(cntx_t *)cntx; +@end + +@implementation PLWin + +- (void)setCntx:(cntx_t *)val { + cntx = val; +} + +- (BOOL)canBecomeMainWindow { + return YES; +} + +- (void)keyDown:(NSEvent *)event { + const char *chars; + + chars = [[event characters] UTF8String]; +// printf("Got Window KeyDown type %d char %s\n",(int)[event type], chars); + + if (chars[0] == ' ') { +// printf("Set plot_signal = 1\n"); + plot_cx->plot_signal = 1; + } +} + +- (BOOL)windowShouldClose:(id)sender { +// printf("Got Window windowShouldClose\n"); + + [NSApp terminate: nil]; + return YES; +} + +@end + +/* Create our window */ +static void create_my_win(cntx_t *cx) { + NSRect wRect; + + /* Create Window */ + wRect.origin.x = 100; + wRect.origin.y = 100; + wRect.size.width = (int)(DEFWWIDTH*pd.ratio+0.5); + wRect.size.height = DEFWHEIGHT; + + cx->window = [[PLWin alloc] initWithContentRect: wRect + styleMask: (NSTitledWindowMask | + NSClosableWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask) + backing: NSBackingStoreBuffered + defer: YES + screen: nil]; /* Main screen */ + + [cx->window setBackgroundColor: [NSColor whiteColor]]; + + [cx->window setLevel: NSMainMenuWindowLevel]; // ~~99 + + [cx->window setTitle: @"PlotWin"]; + + /* Use our view for the whole window to draw plot */ + cx->view = [PLView new]; + [cx->view setCntx:(void *)cx]; + [cx->window setContentView: cx->view]; + + [cx->window makeKeyAndOrderFront: nil]; + +// [cx->window makeMainWindow]; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* + Cocoa NSApp is pretty horrible - it will only get user events + if created and run in the main thread. So the only way we could + decouble the windows from the application would be to intercept + main() and create a secondary thread to run the appication while + leaving main() in reserve for creating an NSApp and windows. + + Instead we poll events for a while and then go back to the main application. + */ + +/* Superset implementation function: */ +/* return 0 on success, -1 on error */ +/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */ +/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */ +/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */ +/* with annotation ntext at the cross, */ +/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */ +/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */ +/* n = number of points/vectors. -ve for reversed X axis */ +/* m = number of extra points (x2,y3 or x7,y7) */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + 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 +) { + /* Put information in global pd */ + { + int j; + double xr,yr; + + pd.dowait = dowait; + pd.ratio = ratio; + + pd.mnx = xmin; + pd.mny = ymin; + pd.mxx = xmax; + pd.mxy = ymax; + + /* Allow some extra arround plot */ + xr = pd.mxx - pd.mnx; + yr = pd.mxy - pd.mny; + if (xr < 1e-6) + xr = 1e-6; + if (yr < 1e-6) + yr = 1e-6; + pd.mnx -= xr/10.0; + pd.mxx += xr/10.0; + pd.mny -= yr/10.0; + pd.mxy += yr/10.0; + + /* Transfer raw point info */ + if (x2 == NULL) + pd.graph = 1; /* 6 graphs + points */ + else + pd.graph = 0; + pd.x1 = x1; + pd.x2 = x2; + for (j = 0; j < MXGPHS; j++) + pd.yy[j] = yy[j]; + pd.ntext = ntext; + pd.n = abs(n); + + if (n < 0) { + double tt; + tt = pd.mxx; + pd.mxx = pd.mnx; + pd.mnx = tt; + pd.revx = 1; + } else { + pd.revx = 0; + } + pd.x7 = x7; + pd.y7 = y7; + pd.mcols = mcols; + pd.mtext = mtext; + pd.m = abs(m); + + pd.x8 = x8; + pd.y8 = y8; + pd.x9 = x9; + pd.y9 = y9; + pd.ocols = ocols; + pd.o = abs(o); + } + + /* If needed, create the indow */ + if (plot_cx == NULL) { + + /* If there is no NSApp */ + /* (This should go in a common library) */ + /* Note that we don't actually clean this up on exit - */ + /* possibly we can't. */ + if (NSApp == nil) { + static NSAutoreleasePool *pool = nil; + ProcessSerialNumber psn = { 0, 0 }; + + /* Transform the process so that the desktop interacts with it properly. */ + /* We don't need resources or a bundle if we do this. */ + if (GetCurrentProcess(&psn) == noErr) { + OSStatus stat; + if (psn.lowLongOfPSN != 0 && (stat = TransformProcessType(&psn, + kProcessTransformToForegroundApplication)) != noErr) { +// fprintf(stderr,"TransformProcess failed with code %d\n",stat); + } else { +// fprintf(stderr,"TransformProcess suceeded\n"); + } + } + + + pool = [NSAutoreleasePool new]; + [NSApplication sharedApplication]; /* Creates NSApp */ + [NSApp finishLaunching]; + + /* We seem to need this, because otherwise we don't get focus automatically */ + [NSApp activateIgnoringOtherApps: YES]; + } + + if ((plot_cx = (cntx_t *)calloc(sizeof(cntx_t), 1)) == NULL) + error("new_dispwin: Malloc failed (cntx_t)\n"); + + create_my_win(plot_cx); + + } else { /* Trigger an update */ + [plot_cx->view setNeedsDisplay: YES ]; + } + + /* Wait until the events are done */ + { + NSEvent *event; + double tot; + NSDate *to; + /* We're creating and draining a pool here to ensure that all the */ + /* auto release objects get drained when we're finished (?) */ + NSAutoreleasePool *tpool = [NSAutoreleasePool new]; + + if (dowait > 0) { /* Wait for a space key */ + tot = 24.0 * 60.0 * 60.0; + } else if (dowait < 0) { + tot = (double)-dowait; + } else { + tot = 0.1; + } + to = [NSDate dateWithTimeIntervalSinceNow:tot]; /* autorelease ? */ + plot_cx->plot_signal = 0; + for (;plot_cx->plot_signal == 0;) { + /* Hmm. Assume event is autorelease */ + if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:to inMode:NSDefaultRunLoopMode dequeue:YES]) != nil) { + [NSApp sendEvent:event]; + } else { + break; + } + } + [tpool release]; + } + return 0; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* Cleanup code (not called) */ + +static void cleanup() { + [plot_cx->window release]; /* Take down the plot window */ + free(plot_cx); + plot_cx = NULL; +} + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* Utility to draw text in Cocoa with centering */ +/* Size is points */ +/* Flags 0x1 == horizontal center */ +/* Flags 0x2 == vertical center */ +static void ADrawText(NSColor *col, float size, float x, float y, int flags, char *text) { + NSFont* font = [NSFont systemFontOfSize:size]; + NSDictionary *att = [NSDictionary dictionaryWithObjectsAndKeys: + font, NSFontAttributeName, + col, NSForegroundColorAttributeName, + nil]; + NSString *str = [[NSString alloc] initWithUTF8String: text]; + + if (flags != 0x0) { + NSSize size; + + /* Figure out how big it will be */ + size = [str sizeWithAttributes: att ]; + if (flags & 0x1) { + double w = fabs(size.width); + x -= 0.5 * w; + } + if (flags & 0x2) { + double h = fabs(size.height); + y -= 0.5 * h; + } + } + + [str drawAtPoint: NSMakePoint(x, y) withAttributes: att]; + [str release]; /* Others are autorelease */ +} + +/* Draw a line */ +/* We re-use the same path so that we can set the dash style */ +static void ADrawLine(NSBezierPath *path, float xs, float ys, float xe, float ye) { + [path removeAllPoints ]; + [path moveToPoint:NSMakePoint(xs, ys)]; + [path lineToPoint:NSMakePoint(xe, ye)]; + [path stroke]; +} + +/* Draw X axis grid lines */ +void +xtick( +plot_info *pdp, +NSBezierPath *path, +NSColor *lcol, +NSColor *tcol, +double x, char *lab +) { + float xx, yy; + + xx = 20.0 + (x - pdp->mnx) * pdp->scx; + yy = 20.0; + + [lcol setStroke]; /* There is a bug in 10.4 which resets this after each stroke */ + ADrawLine(path, xx, yy, xx, (float)pdp->sh); + ADrawText(tcol, 10.0, xx, 5.0, 0x1, lab); +} + +/* Draw Y axis grid lines */ +void +ytick( +plot_info *pdp, +NSBezierPath *path, +NSColor *lcol, +NSColor *tcol, +double y, char *lab +) { + float xx, yy; + + xx = 20.0; + yy = 20.0 + (y - pdp->mny) * pdp->scy; + + [lcol setStroke]; /* There is a bug in 10.4 which resets this after each stroke */ + ADrawLine(path, xx, yy, (float)pdp->sw, yy); + ADrawText(tcol, 10.0, 3.0, yy, 0x2, lab); +} + +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 *) +) { + char str[6], temp[20]; + int nfrac; + double d; + double graphmin, graphmax; + double range,x; + + range = nicenum(min-max,0); + d = nicenum(range/(NTICK-1),1); + graphmin = floor(min/d) * d; + graphmax = ceil(max/d) * d; + nfrac = (int)MAX(-floor(log10(d)),0); + sprintf(str,"%%.%df", nfrac); + for (x = graphmin; x < graphmax + 0.5 * d; x += d) { + sprintf(temp,str,x); + pfunc(pdp, path, lcol, tcol, x, temp); + } +} + +/* Called from within view to plot overall graph */ +static void DoPlot(NSRect *rect, plot_info *pdp) { + int i, j; + int lx,ly; /* Last x,y */ + CGFloat dash_list[2] = {7.0, 2.0}; + /* Note path and tcol are autorelease */ + NSBezierPath *path = [NSBezierPath bezierPath]; /* Path to use */ + NSColor *lcol = nil; + NSColor *tcol = nil; + + /* Setup the plot info structure for this drawing */ + /* Note port rect is raster like, pdp/Quartz2D is Postscript like */ + pdp->sx = rect->origin.x; + pdp->sy = rect->origin.y; + pdp->sw = rect->size.width; + pdp->sh = rect->size.height; + pdp->scx = (pdp->sw - 20)/(pdp->mxx - pdp->mnx); + pdp->scy = (pdp->sh - 20)/(pdp->mxy - pdp->mny); + + /* Plot the axis lines */ + [path setLineWidth:1.0]; + [path setLineDash: dash_list count: 2 phase: 0.0 ]; /* Set dashed lines for axes */ + + /* Make sure text is black */ + tcol = [NSColor colorWithCalibratedRed: 0.0 + green: 0.0 + blue: 0.0 + alpha: 1.0]; + + lcol = [NSColor colorWithCalibratedRed:0.7 green: 0.7 blue:0.7 alpha: 1.0]; /* Grey */ + + /* Plot horizontal axis */ + if (pdp->revx) + loose_label(pdp, path, lcol, tcol, pdp->mxx, pdp->mnx, xtick); + else + loose_label(pdp, path, lcol, tcol, pdp->mnx, pdp->mxx, xtick); + + /* Plot vertical axis */ + loose_label(pdp, path, lcol, tcol, pdp->mny, pdp->mxy, ytick); + + /* Set to non-dashed line */ + [path setLineWidth: LTHICK]; + [path setLineDash: NULL count: 0 phase: 0.0 ]; + + if (pdp->graph) { /* Up to 6 graphs */ + int gcolors[MXGPHS][3] = { + { 0, 0, 0}, /* Black */ + { 210, 30, 0}, /* Red */ + { 0, 200, 90}, /* Green */ + { 0, 10, 255}, /* Blue */ + { 200, 200, 0}, /* Yellow */ + { 220, 0, 255}, /* Purple */ + { 136, 86, 68}, /* Brown */ + { 248, 95, 0}, /* Orange */ + { 160, 160, 160}, /* Grey */ + { 220, 220, 220} /* White */ + }; + for (j = MXGPHS-1; j >= 0; j--) { + double *yp = pdp->yy[j]; + + if (yp == NULL) + continue; + [[NSColor colorWithCalibratedRed: gcolors[j][0]/255.0 + green: gcolors[j][1]/255.0 + blue: gcolors[j][2]/255.0 + alpha: 1.0] setStroke]; + + lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx, 20.0 + ly, 20 + cx, 20.0 + cy); +#ifdef CROSSES + ADrawLine(path, 20.0 + cx - 5, 20.0 - cy - 5, 20.0 + cx + 5, 20.0 + cy + 5); + ADrawLine(path, 20.0 + cx + 5, 20.0 - cy - 5, 20.0 + cx - 5, 20.0 + cy + 5); +#endif + lx = cx; + ly = cy; + } + } + + } else { /* Vectors */ + [[NSColor colorWithCalibratedRed: 0.0 + green: 0.0 + blue: 0.0 + alpha: 1.0] setStroke]; + if (pdp->ntext != NULL) { + tcol = [NSColor colorWithCalibratedRed: 0.0 + green: 0.0 + blue: 0.0 + alpha: 1.0]; + } + for (i = 0; i < pdp->n; i++) { + int cx,cy; + + lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy); + + ADrawLine(path, 20.0 + cx - 5, 20.0 + cy - 5, 20.0 + cx + 5, 20.0 + cy + 5); + ADrawLine(path, 20.0 + cx + 5, 20.0 + cy - 5, 20.0 + cx - 5, 20.0 + cy + 5); + + if (pdp->ntext != NULL) + ADrawText(tcol, 9.0, 20.0 + cx + 9, 20.0 + cy - 7, 0x1, pdp->ntext[i]); + } + } + + /* Extra points */ + if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) { + [[NSColor colorWithCalibratedRed: 0.82 /* Orange ? */ + green: 0.59 + blue: 0.0 + alpha: 1.0] setStroke]; + + for (i = 0; i < pdp->m; i++) { + + if (pdp->mcols != NULL) { + [[NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0] + green: pdp->mcols[i].rgb[1] + blue: pdp->mcols[i].rgb[2] + alpha: 1.0] setStroke]; + + if (pdp->mtext != NULL) { + tcol = [NSColor colorWithCalibratedRed: pdp->mcols[i].rgb[0] + green: pdp->mcols[i].rgb[1] + blue: pdp->mcols[i].rgb[2] + alpha: 1.0]; + } + } + lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx - 5, 20.0 + ly, 20.0 + lx + 5, 20.0 + ly); + ADrawLine(path, 20.0 + lx, 20.0 + ly - 5, 20.0 + lx, 20.0 + ly + 5); + + if (pdp->mtext != NULL) { + ADrawText(tcol, 9.0, 20.0 + lx + 9, 20.0 + ly + 7, 0x1, pdp->mtext[i]); + } + } + } + + /* Extra vectors */ + if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) { + [[NSColor colorWithCalibratedRed: 0.5 /* Light blue */ + green: 0.9 + blue: 0.9 + alpha: 1.0] setStroke]; + + for (i = 0; i < pdp->o; i++) { + int cx,cy; + + if (pdp->ocols != NULL) { + [[NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0] + green: pdp->ocols[i].rgb[1] + blue: pdp->ocols[i].rgb[2] + alpha: 1.0] setStroke]; + if (pdp->mtext != NULL) { + tcol = [NSColor colorWithCalibratedRed: pdp->ocols[i].rgb[0] + green: pdp->ocols[i].rgb[1] + blue: pdp->ocols[i].rgb[2] + alpha: 1.0]; + } + } + lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5); + + ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy); + } + } +} + +#else /* Assume UNIX + X11 */ +/* ********************************** X11 version ********************** */ + +/* !!!! There is a problem if the user closes the window - an X11 error results */ +/* This seems to happen before a DestroyNotify !. How to fix ??? !!!! */ + +#include +#include + +#ifdef DODEBUG +# define debugf(xx) printf xx +#else +# define debugf(xx) +#endif + +void DoPlot(Display *mydisplay, Window mywindow, GC mygc, plot_info *pdp); + +/* Superset implementation function: */ +/* return 0 on success, -1 on error */ +/* Hybrid Graph uses x1 : y1, y2, y3, y4, y5, y6 for up to 6 graph curves + */ +/* optional diagonal crosses at x7, y7 in yellow (x2 == NULL). */ +/* Vector uses x1, y1 to x2, y2 as a vector with a diagonal cross at x2, y2 all in black, */ +/* with annotation ntext at the cross, */ +/* plus a diagonal cross at x7, y7 in yellow. The color for x7, y7 can be overidden by an */ +/* array of colors mcols, and augmented by optional label text mtext. (x2 != NULL) */ +/* n = number of points/vectors. -ve for reversed X axis */ +/* m = number of extra points (x2,y3 or x7,y7) */ +static int do_plot_imp( + double xmin, double xmax, double ymin, double ymax, /* Bounding box */ + double ratio, /* Aspect ratio of window, X/Y */ + int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */ + 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 +) { + { + int j; + double xr,yr; + + pd.dowait = dowait; + pd.ratio = ratio; + + pd.mnx = xmin; + pd.mny = ymin; + pd.mxx = xmax; + pd.mxy = ymax; + + /* Allow some extra arround plot */ + xr = pd.mxx - pd.mnx; + yr = pd.mxy - pd.mny; + if (xr < 1e-6) + xr = 1e-6; + if (yr < 1e-6) + yr = 1e-6; + pd.mnx -= xr/10.0; + pd.mxx += xr/10.0; + pd.mny -= yr/10.0; + pd.mxy += yr/10.0; + + /* Transfer raw point info */ + if (x2 == NULL) + pd.graph = 1; /* 6 graphs + points */ + else + pd.graph = 0; + pd.x1 = x1; + pd.x2 = x2; + for (j = 0; j < MXGPHS; j++) + pd.yy[j] = yy[j]; + pd.ntext = ntext; + pd.n = abs(n); + + if (n < 0) { + double tt; + tt = pd.mxx; + pd.mxx = pd.mnx; + pd.mnx = tt; + pd.revx = 1; + } else { + pd.revx = 0; + } + pd.x7 = x7; + pd.y7 = y7; + pd.mcols = mcols; + pd.mtext = mtext; + pd.m = abs(m); + + pd.x8 = x8; + pd.y8 = y8; + pd.x9 = x9; + pd.y9 = y9; + pd.ocols = ocols; + pd.o = abs(o); + } + + { + /* stuff for X windows */ + char plot[] = {"plot"}; + static Display *mydisplay = NULL; + static Window mywindow = -1; + int dorefresh = 1; + GC mygc; + XEvent myevent; + XSizeHints myhint; + XWindowAttributes mywattributes; + int myscreen; + unsigned long myforeground,mybackground; + int done; + + /* open the display */ + if (mydisplay == NULL) { + mydisplay = XOpenDisplay(""); + if(!mydisplay) + error("Unable to open display"); + dorefresh = 0; + } + myscreen = DefaultScreen(mydisplay); + mybackground = WhitePixel(mydisplay,myscreen); + myforeground = BlackPixel(mydisplay,myscreen); + + myhint.x = 100; + myhint.y = 100; + myhint.width = (int)(DEFWWIDTH * ratio + 0.5); + myhint.height = DEFWHEIGHT; + myhint.flags = PPosition | USSize; + + debugf(("Opened display OK\n")); + + if (mywindow == -1) { + debugf(("Opening window\n")); + mywindow = XCreateSimpleWindow(mydisplay, + DefaultRootWindow(mydisplay), + myhint.x,myhint.y,myhint.width,myhint.height, + 5, myforeground,mybackground); + XSetStandardProperties(mydisplay,mywindow,plot,plot,None, + NULL,0, &myhint); + } + + mygc = XCreateGC(mydisplay,mywindow,0,0); + XSetBackground(mydisplay,mygc,mybackground); + XSetForeground(mydisplay,mygc,myforeground); + + XSelectInput(mydisplay,mywindow, + KeyPressMask | ExposureMask | StructureNotifyMask); + + if (dorefresh) { + XExposeEvent ev; + + ev.type = Expose; + ev.display = mydisplay; + ev.send_event = True; + ev.window = mywindow; + ev.x = 0; + ev.y = 0; + ev.width = myhint.width; + ev.height = myhint.height; + ev.count = 0; + + XClearWindow(mydisplay, mywindow); + XSendEvent(mydisplay, mywindow, False, ExposureMask, (XEvent *)&ev); + + } else { + XMapRaised(mydisplay,mywindow); + debugf(("Raised window\n")); + } + + /* Main event loop */ + debugf(("About to enter main loop\n")); + done = 0; + while(done == 0) { + XNextEvent(mydisplay,&myevent); + switch(myevent.type) { + case Expose: + if(myevent.xexpose.count == 0) { /* Repare the exposed region */ + XGetWindowAttributes(mydisplay, mywindow, & mywattributes); + /* Setup the plot info structure for this drawing */ + pd.sx = mywattributes.x; + pd.sy = mywattributes.y; + pd.sw = mywattributes.width; + pd.sh = mywattributes.height; + pd.scx = (pd.sw - 10)/(pd.mxx - pd.mnx); + pd.scy = (pd.sh - 10)/(pd.mxy - pd.mny); + + DoPlot(mydisplay,mywindow, mygc, &pd); + + if (pd.dowait <= 0) { /* Don't wait */ + if (pd.dowait < 0) + sleep(-pd.dowait); + debugf(("Not waiting, so set done=1\n")); + done = 1; + } + } + break; + case MappingNotify: + XRefreshKeyboardMapping(&myevent.xmapping); + break; + case KeyPress: + debugf(("Got a button press\n")); + done = 1; + break; + } + } + debugf(("About to close display\n")); + XFreeGC(mydisplay,mygc); +// XDestroyWindow(mydisplay,mywindow); +// XCloseDisplay(mydisplay); + debugf(("finished\n")); + } + return 0; +} + +/* Draw X axis grid lines */ +void +xtick( +Display *mydisplay, +Window mywindow, +GC mygc, +plot_info *pdp, +double x, char *lab +) { + int xx,yy; + + xx = 10 + (int)((x - pdp->mnx) * pdp->scx + 0.5); + yy = pdp->sh - 10; + + XDrawLine(mydisplay, mywindow, mygc, xx, yy, xx, 0); + XDrawImageString(mydisplay, mywindow, mygc, xx-6, yy, lab, strlen(lab)); +} + +/* Draw Y axis grid lines */ +void +ytick( +Display *mydisplay, +Window mywindow, +GC mygc, +plot_info *pdp, +double y, char *lab +) { + int xx,yy; + + xx = 5; + yy = pdp->sh - 10 - (int)((y - pdp->mny) * pdp->scy + 0.5); + + XDrawLine(mydisplay, mywindow, mygc, xx, yy, pdp->sw, yy); + XDrawImageString(mydisplay, mywindow, mygc, xx, yy+4, lab, strlen(lab)); +} + +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 *) +) { + char str[6], temp[20]; + int nfrac; + double d; + double graphmin, graphmax; + double range,x; + + range = nicenum(min-max,0); + d = nicenum(range/(NTICK-1),1); + graphmin = floor(min/d) * d; + graphmax = ceil(max/d) * d; + nfrac = (int)MAX(-floor(log10(d)),0); + sprintf(str,"%%.%df", nfrac); + for (x = graphmin; x < graphmax + 0.5 * d; x += d) { + sprintf(temp,str,x); + pfunc(mydisplay, mywindow, mygc, pdp, x, temp); + } +} + +void +DoPlot( +Display *mydisplay, +Window mywindow, +GC mygc, +plot_info *pdp +) { + int i, j; + int lx,ly; /* Last x,y */ + char dash_list[2] = {5, 1}; + Colormap mycmap; + XColor col; + + mycmap = DefaultColormap(mydisplay, 0); + col.red = col.green = col.blue = 150 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + + /* Set dashed lines for axes */ + XSetLineAttributes(mydisplay, mygc, 1, LineOnOffDash, CapButt, JoinBevel); + XSetDashes(mydisplay, mygc, 0, dash_list, 2); + // ~~ doesn't seem to work. Why ? + + /* Plot horizontal axis */ + if (pdp->revx) + loose_label(mydisplay, mywindow, mygc, pdp, pdp->mxx, pdp->mnx, xtick); + else + loose_label(mydisplay, mywindow, mygc, pdp, pdp->mnx, pdp->mxx, xtick); + + /* Plot vertical axis */ + loose_label(mydisplay, mywindow, mygc, pdp, pdp->mny, pdp->mxy, ytick); + + if (pdp->graph) { /* Up to 10 graphs */ + for (j = MXGPHS-1; j >= 0; j--) { + double *yp = pdp->yy[j]; + + if (yp == NULL) + continue; + + col.red = gcolors[j][0] * 256; + col.green = gcolors[j][1] * 256; + col.blue = gcolors[j][2] * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + lx = (int)((pdp->x1[0] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)(( yp[0] - pdp->mny) * pdp->scy + 0.5); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + cx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)(( yp[i] - pdp->mny) * pdp->scy + 0.5); + + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy); +#ifdef CROSSES + + XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5); + XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5); +#endif + lx = cx; + ly = cy; + } + } + + } else { /* Vectors */ + + col.red = col.green = col.blue = 0 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + for (i = 0; i < pdp->n; i++) { + int cx,cy; + + lx = (int)((pdp->x1[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->yy[0][i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x2[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->yy[1][i] - pdp->mny) * pdp->scy + 0.5); + + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy); + + XDrawLine(mydisplay, mywindow, mygc, 10 + cx - 5, pdp->sh - 10 - cy - 5, 10 + cx + 5, pdp->sh - 10 - cy + 5); + XDrawLine(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy - 5, 10 + cx - 5, pdp->sh - 10 - cy + 5); + + if (pdp->ntext != NULL) + XDrawImageString(mydisplay, mywindow, mygc, 10 + cx + 5, pdp->sh - 10 - cy + 7, + pdp->ntext[i], strlen(pdp->ntext[i])); + } + } + + /* Extra points */ + if (pdp->x7 != NULL && pdp->y7 != NULL && pdp->m > 0 ) { + col.red = 210 * 256; col.green = 150 * 256; col.blue = 0 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + for (i = 0; i < pdp->m; i++) { + lx = (int)((pdp->x7[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y7[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->mcols != NULL) { + col.red = (int)(pdp->mcols[i].rgb[0] * 65535.0 + 0.5); + col.green = (int)(pdp->mcols[i].rgb[1] * 65535.0 + 0.5); + col.blue = (int)(pdp->mcols[i].rgb[2] * 65535.0 + 0.5); + + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + + } + XDrawLine(mydisplay, mywindow, mygc, 10 + lx - 5, pdp->sh - 10 - ly, + 10 + lx + 5, pdp->sh - 10 - ly); + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly - 5, + 10 + lx, pdp->sh - 10 - ly + 5); + + if (pdp->mtext != NULL) + XDrawImageString(mydisplay, mywindow, mygc, 10 + lx + 5, pdp->sh - 10 - ly - 7, + pdp->mtext[i], strlen(pdp->mtext[i])); + } + } + + /* Extra vectors */ + if (pdp->x8 != NULL && pdp->y8 != NULL && pdp->x9 != NULL && pdp->y9 && pdp->o > 0 ) { + col.red = 150 * 256; col.green = 255 * 256; col.blue = 255 * 256; + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel); + + for (i = 0; i < pdp->o; i++) { + int cx,cy; + + lx = (int)((pdp->x8[i] - pdp->mnx) * pdp->scx + 0.5); + ly = (int)((pdp->y8[i] - pdp->mny) * pdp->scy + 0.5); + + cx = (int)((pdp->x9[i] - pdp->mnx) * pdp->scx + 0.5); + cy = (int)((pdp->y9[i] - pdp->mny) * pdp->scy + 0.5); + + if (pdp->ocols != NULL) { + col.red = (int)(pdp->ocols[i].rgb[0] * 65535.0 + 0.5); + col.green = (int)(pdp->ocols[i].rgb[1] * 65535.0 + 0.5); + col.blue = (int)(pdp->ocols[i].rgb[2] * 65535.0 + 0.5); + + XAllocColor(mydisplay, mycmap, &col); + XSetForeground(mydisplay,mygc, col.pixel); + + } + + XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy); + } + } +} + +#endif /* UNIX + X11 */ +#endif /* !NT */ +/***********************************************************************/ + + +/* Nice graph labeling functions */ + +#define expt(a,n) pow(a,(double)(n)) + +double nicenum(double x, int round) { + int ex; + double f; + double nf; +// printf("nocenum called with %f and %d\n",x,round); + if (x < 0.0) + x = -x; + ex = (int)floor(log10(x)); +// printf("ex = %d\n",ex); + f = x/expt(10.0,ex); +// printf("f = %f\n",f); + if (round) { + if (f < 1.5) nf = 1.0; + else if (f < 3.0) nf = 2.0; + else if (f < 7.0) nf = 5.0; + else nf = 10.0; + } else { + if (f < 1.0) nf = 1.0; + else if (f < 2.0) nf = 2.0; + else if (f < 5.0) nf = 5.0; + else nf = 10.0; + } +// printf("nf = %f\n",nf); +// printf("about to return %f\n",(nf * expt(10.0, ex))); + return (nf * expt(10.0, ex)); +} + +/* ---------------------------------------------------------------- */ +#ifdef STANDALONE_TEST +/* test code */ + +// ~~99 +#define TEST_NON_CONSOLE /* Version that works from command line and GUI */ +// May have to add link flag -Wl,-subsystem,windows +// since MingW is stupid about noticing WinMain or pragma + +//#include +//#include +#include +//#include + + +#ifdef NEVER +/* Append debugging string to log.txt */ +static void dprintf(char *fmt, ...) { + FILE *fp = NULL; + if ((fp = fopen("log.txt", "a+")) != NULL) { + va_list args; + va_start(args, fmt); + vfprintf(fp, fmt, args); + fflush(fp); + fclose(fp); + va_end(args); + } +} +#endif // NEVER + +#ifdef NEVER /* Other non-working enable console output code */ +{ + /* This clever code have been found at: + Adding Console I/O to a Win32 GUI App + Windows Developer Journal, December 1997 + http://dslweb.nwnexus.com/~ast/dload/guicon.htm + Andrew Tucker's Home Page */ + + /* This is not so clever, since it doesn't work... */ + + // redirect unbuffered STDOUT to the console + long lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + int hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + FILE *fp = _fdopen(hConHandle, "w"); + *stdout = *fp; + setvbuf(stdout, NULL, _IONBF, 0); + + // redirect unbuffered STDIN to the console + lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "r" ); + *stdin = *fp; + setvbuf(stdin, NULL, _IONBF, 0); + + // redirect unbuffered STDERR to the console + lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE); + hConHandle = _open_osfhandle(lStdHandle, _O_TEXT); + fp = _fdopen( hConHandle, "w" ); + *stderr = *fp; + setvbuf(stderr, NULL, _IONBF, 0); + + +} +#endif // NEVER + +#ifdef NEVER +// ~~~~~~~~~~~~~ +// AllocConsole(); + { + ULONG pbi[6]; + ULONG ulSize = 0; + LONG (WINAPI *NtQueryInformationProcess)(HANDLE ProcessHandle, + ULONG ProcessInformationClass, + PVOID ProcessInformation, + ULONG ProcessInformationLength, + PULONG ReturnLength); + + BOOL (WINAPI *AttachConsole)(DWORD dwProcessId); + + *(FARPROC *)&NtQueryInformationProcess = + GetProcAddress(LoadLibraryA("NTDLL.DLL"), "NtQueryInformationProcess"); + if(NtQueryInformationProcess) { +printf("~1 found NtQueryInformationProcess\n"); fflush(stdout); + if(NtQueryInformationProcess(GetCurrentProcess(), 0, + &pbi, sizeof(pbi), &ulSize) >= 0 && ulSize == sizeof(pbi)) { +printf("~1 NtQueryInformationProcess suceeded\n"); fflush(stdout); + + *(FARPROC *)&AttachConsole = + GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole"); + + if (AttachConsole) { +printf("~1 found AttachConsole\n"); fflush(stdout); + AttachConsole(pbi[5]); +printf("~1 about to freopen CONNOUT\n"); fflush(stdout); + freopen("CONOUT$","wb",stdout); + } else { +printf("~1 failed to find AttachConsole\n"); fflush(stdout); + } + } + } + // AttachConsole(ID ATTACH_PARENT_CONSOLE); // Should work on XP ?? + + /* i mean OpenConsoleW - you are as picky as i am - its + ordinal=519 and it is exported by name; the header(s) + do not include it, which tells me there's got to be a + reason for that. + */ + } +// ~~~~~~~~~~~~~ +#endif // NEVER + +#if defined(TEST_NON_CONSOLE) && defined(NT) +# pragma comment( linker, "/subsystem:windows" ) + +APIENTRY WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow +) { + { /* Only works on >= XP though */ + BOOL (WINAPI *AttachConsole)(DWORD dwProcessId); + + *(FARPROC *)&AttachConsole = + GetProcAddress(LoadLibraryA("kernel32.dll"), "AttachConsole"); + + if (AttachConsole != NULL && AttachConsole(((DWORD)-1))) + { + if (_fileno(stdout) < 0) + freopen("CONOUT$","wb",stdout); + if (_fileno(stderr) < 0) + freopen("CONOUT$","wb",stderr); + if (_fileno(stdin) < 0) + freopen("CONIN$","rb",stdin); +#ifdef __cplusplus + // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well + std::ios::sync_with_stdio(); +#endif + } + } + + return main(__argc, __argv); +} +#endif /* TEST_NON_CONSOLE && NT */ + +int main(int argc, char *argv[]) { + double x[10] = {0.0, 0.5, 0.7, 1.0}; + double y1[10] = {0.0, 0.5, 0.7, 1.0}; + double y2[10] = {0.9, 0.8, 1.4, 1.2}; + double y3[10] = {0.1, 0.8, 0.7, -0.1}; + + double Bx1[10] = {0.0, 0.5, 0.9, 0.5}; + double By1[10] = {0.0, 0.3, 1.2, 0.2}; + double Bx2[10] = {0.1, 0.8, 0.1, 0.2}; + double By2[10] = {0.1, 1.8, 2.0, 0.5}; + + double Bx3[10] = {0.8, 0.4, 1.3, 0.5, 0.23}; + double By3[10] = {0.5, 1.3, 0.4, 0.7, 0.77}; + + plot_col mcols[5] = { + { 1.0, 0.0, 0.0 }, + { 0.0, 1.0, 0.0 }, + { 0.0, 0.0, 1.0 }, + { 0.6, 0.6, 0.6 }, + { 1.0, 1.0, 0.0 } }; + + char *ntext[5] = { "A", "B", "C", "D" }; + char *mtext[5] = { "10", "20", "30", "40", "50" }; + + printf("Doing first plot\n"); + if (do_plot(x,y1,y2,y3,4) < 0) + printf("Error - do_plot returned -1!\n"); + + /* Try a second plot */ + printf("Doing second plot\n"); + x[2] = 0.55; + if (do_plot(x,y2,y3,y1,3) < 0) + printf("Error - do_plot returned -1!\n"); + + /* Try vectors */ + printf("Doing vector plot\n"); + if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, NULL, NULL, 5)) + printf("Error - do_plot_vec returned -1!\n"); + + printf("Doing vector plot with colors and notation\n"); + if (do_plot_vec(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, 4, 1, Bx3, By3, mcols, mtext, 5)) + printf("Error - do_plot_vec returned -1!\n"); + + printf("Doing vector plot with colors and notation + extra vectors\n"); + if (do_plot_vec2(0.0, 1.4, 0.0, 2.0, Bx1, By1, Bx2, By2, ntext, 4, 1, Bx3, By3, mcols, mtext, 5, + x,y1,y2,y3,mcols,4)) + printf("Error - do_plot_vec returned -1!\n"); + + printf("We're done\n"); + return 0; +} + +#endif /* STANDALONE_TEST */ +/* ---------------------------------------------------------------- */ + -- cgit v1.2.3