3994 lines
104 KiB
C
3994 lines
104 KiB
C
|
|
/*
|
|
* 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:
|
|
*
|
|
* Change plot_info contents to be a single array of draw objects.
|
|
* Object is poly type, one of three:
|
|
|
|
* 1) line: color + single point + optional pointer to array of n points
|
|
* 2) vectors: color + point pair + optional pointer to array of n point pairs.
|
|
* 3) symbols: color + point + symbol + text
|
|
*
|
|
* Change plot_g to match, and then re-implement all other functions in
|
|
* terms of these objects.
|
|
*
|
|
* 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.
|
|
*
|
|
* dowait > 0 not implemented on Windows and Mac ?
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#ifdef UNIX
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <math.h>
|
|
#include "aconfig.h"
|
|
#include "numlib.h"
|
|
#include "plot.h"
|
|
//#ifdef STANDALONE_TEST
|
|
#include "ui.h"
|
|
//#endif /* STANDALONE_TEST */
|
|
|
|
#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, Lime = Y11, Pink = Y12 */
|
|
|
|
double nicenum(double x, int round);
|
|
|
|
/* Colors of the graphs */
|
|
int plot_colors[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 */
|
|
{ 112, 255, 161}, /* Lime */
|
|
{ 255, 191, 80}, /* Pink */
|
|
|
|
{ 0, 100, 100}, /* Full Cyan */
|
|
{ 100, 0, 100}, /* Full Magenta */
|
|
{ 100, 100, 0}, /* Full Yellow */
|
|
{ 100, 0, 0} /* Full Red */
|
|
};
|
|
|
|
/* Flags */
|
|
#define PLOTF_NONE 0x0000
|
|
#define PLOTF_GRAPHCROSSES 0x0001 /* Plot crosses at each point on the graphs */
|
|
#define PLOTF_VECCROSSES 0x0002 /* Plot crosses at the end of x1,y1 -> x2,y2 */
|
|
|
|
struct _plot_info {
|
|
void *cx; /* Other Context */
|
|
|
|
int flags; /* Flags */
|
|
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; /* Graph of x1 vs yy[MXGPHS] */
|
|
double *yy[MXGPHS]; /* or vectors x1 yy[0] to x2, yy[1] if x2 != NULL */
|
|
/* Optional crosses if flags & PLOTF_VECCROSSES */
|
|
plot_col *ncols; /* Override default vector, cross, text color */
|
|
char **ntext; /* Optional text */
|
|
int n;
|
|
|
|
double *x7, *y7; /* Yellow diagonal crosses */
|
|
plot_col *mcols; /* Override cross color */
|
|
char **mtext; /* Optional text near cross */
|
|
int m; /* Number crosses */
|
|
|
|
/* Hmm. Could implement all of above using these two.. */
|
|
double *x8, *y8, *x9, *y9; /* Vectors with colors - default none */
|
|
plot_col *ocols; /* Vector colors - default light blue */
|
|
int o;
|
|
|
|
double *xp, *yp; /* Symbol position - default no symbol or text */
|
|
plot_sym *tp; /* Symbol type - default none */
|
|
plot_col *pcols; /* Symbol color - default plot colors */
|
|
char **ptext; /* Text near symbol - default none */
|
|
int p; /* Number of symbols */
|
|
|
|
/* 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 implementation funtion */
|
|
static int do_plot_imp(
|
|
int flags,
|
|
double xmin, double xmax, double ymin, double ymax, /* Bounding box */
|
|
double ratio, /* Aspect ratio of window, X/Y, 1.0 = nominal */
|
|
int dowait, /* > 0 wait for user to hit space key, < 0 delat dowait seconds. */
|
|
|
|
double *x1, double *x2,
|
|
double *yy[MXGPHS], plot_col *ncols, 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,
|
|
|
|
double *xp, double *yp, plot_sym *tp, plot_col *pcols, char **ptext,
|
|
int p
|
|
);
|
|
|
|
static int dolog = 0; /* nz if logging is active */
|
|
static int noplot = 0; /* nz if plotting is supressed */
|
|
static int checkedenv = 0; /* nz if env has been checked */
|
|
|
|
static void do_log_imp(
|
|
int flags,
|
|
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], plot_col *ncols, 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,
|
|
double *xp, double *yp, plot_sym *tp, plot_col *pcols, char **ptext, int q
|
|
);
|
|
|
|
//static void perror(char *fmt, ...);
|
|
|
|
#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(PLOTF_NONE,
|
|
xmin, xmax, ymin, ymax, 1.0, 1,
|
|
x, NULL, yy, NULL, NULL, n,
|
|
NULL, NULL, NULL, NULL, 0,
|
|
NULL, 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(PLOTF_NONE,
|
|
xmin, xmax, ymin, ymax, 1.0, 1,
|
|
x, NULL, yy, NULL, NULL, n,
|
|
x4, y4, NULL, NULL, m ,
|
|
NULL, NULL, NULL, NULL, NULL, 0,
|
|
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(PLOTF_NONE,
|
|
xmin, xmax, ymin, ymax, ratio, dowait,
|
|
x, NULL, yy, NULL, NULL, n,
|
|
NULL, NULL, NULL, NULL, 0,
|
|
NULL, 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 < nn; 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(PLOTF_NONE,
|
|
xmin, xmax, ymin, ymax, 1.0, 1,
|
|
x, NULL, yy, NULL, NULL, n,
|
|
NULL, NULL, NULL, NULL, n ,
|
|
NULL, NULL, NULL, NULL, NULL, 0,
|
|
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 < nn; 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(PLOTF_NONE,
|
|
xmin, xmax, ymin, ymax, 1.0, 1,
|
|
x, NULL, yy, NULL, NULL, n,
|
|
xp, yp, NULL, NULL, m,
|
|
NULL, NULL, NULL, NULL, NULL, 0,
|
|
NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
/* Public routines */
|
|
/* Plot up to MXGPHS graphs + optional crosses */
|
|
int
|
|
do_plotNpwz(
|
|
double *x, /* X coord */
|
|
double **yy, /* MXGPHS x Y values, NULL for none */
|
|
int n, /* Number of values, -ve for reverse X axis */
|
|
double *xp, double *yp, /* And crosses */
|
|
int m, /* Number of crosses */
|
|
int dowait, /* == 0 no wait, > 0, wait for user key, < 0 wait for secs */
|
|
int zero /* Flag - nz, make sure zero is in y range */
|
|
) {
|
|
int i, j;
|
|
double xmin, xmax, ymin, ymax;
|
|
int nn = abs(n);
|
|
|
|
/* 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];
|
|
}
|
|
}
|
|
|
|
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(PLOTF_NONE,
|
|
xmin, xmax, ymin, ymax, 1.0, dowait,
|
|
x, NULL, yy, NULL, NULL, n,
|
|
xp, yp, NULL, NULL, m,
|
|
NULL, NULL, NULL, NULL, NULL, 0,
|
|
NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
/* Public routines */
|
|
/* Plot up to 10 graphs + optional crosses */
|
|
/* if dowait > 0, wait for user key */
|
|
/* if dowait < 0, wait for no seconds */
|
|
/* return 0 on success, -1 on error */
|
|
/* If n is -ve, reverse the X axis */
|
|
/* If zero, ensure Y goes to zero */
|
|
int
|
|
do_plot10pwz(
|
|
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, -ve for reverse X axis */
|
|
double *xp, double *yp, /* And crosses */
|
|
int m, /* Number of crosses */
|
|
int dowait, /* == 0 no wait, > 0, wait for user key, < 0 wait for secs */
|
|
int zero /* Flag - nz, make sure zero is in y range */
|
|
) {
|
|
int j;
|
|
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;
|
|
|
|
return do_plotNpwz(x, yy, n, xp, yp, m, dowait, zero);
|
|
}
|
|
|
|
/* 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 */
|
|
) {
|
|
return do_plot10pwz(x, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, n, NULL, NULL, 0, 1, zero);
|
|
}
|
|
|
|
/* Plot up to 10 graphs + optional crosses */
|
|
/* if dowait > 0, wait for user key */
|
|
/* if dowait < 0, wait for no seconds */
|
|
/* return 0 on success, -1 on error */
|
|
/* If n is -ve, reverse the X axis */
|
|
int
|
|
do_plot10pw(
|
|
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 dowait) {
|
|
return do_plot10pwz(x, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, n, xp, yp, m, dowait, 0);
|
|
}
|
|
|
|
/* 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) {
|
|
return do_plot10pwz(x, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, n, xp, yp, m, 1, 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(PLOTF_VECCROSSES,
|
|
xmin, xmax, ymin, ymax, 1.0, dowait,
|
|
x1, x2, yy, NULL, NULL, n,
|
|
x3, y3, mcols, mtext, m,
|
|
NULL, NULL, NULL, NULL, NULL, 0,
|
|
NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
/* Plot a bunch of vectors & crosses + 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 crosses */
|
|
double *y3,
|
|
plot_col *mcols,/* cross colors */
|
|
char **mtext, /* text annotation at cross */
|
|
int m, /* Number of crosses */
|
|
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(PLOTF_VECCROSSES,
|
|
xmin, xmax, ymin, ymax, 1.0, dowait,
|
|
x1, x2, yy, NULL, ntext, n,
|
|
x3, y3, mcols, mtext, m,
|
|
x4, y4, x5, y5, ocols, o,
|
|
NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
/* Plot a bunch of colored vectors + points + optional colored points & notation */
|
|
/* + optional colored vectors */
|
|
/* return 0 on success, -1 on error */
|
|
/* Vectors are x1, y1 to x2, y2 with color ncols and annotated 'X' at x2, y2, */
|
|
/* Colored annotated Crosss at x3, y3. */
|
|
/* Colored vector from x4, y4 to x5, y5 */
|
|
int do_plot_vec3(
|
|
double xmin,
|
|
double xmax,
|
|
double ymin,
|
|
double ymax,
|
|
double *x1, /* n vector start */
|
|
double *y1,
|
|
double *x2, /* vector end and diagonal cross */
|
|
double *y2,
|
|
plot_col *ncols,/* Vector and cross colors */
|
|
char **ntext, /* text annotation at cross */
|
|
int n, /* Number of vectors */
|
|
int dowait,
|
|
double *x3, /* m extra crosses */
|
|
double *y3,
|
|
plot_col *mcols,/* cross colors */
|
|
char **mtext, /* text annotation at cross */
|
|
int m, /* Number of crosses */
|
|
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(PLOTF_VECCROSSES,
|
|
xmin, xmax, ymin, ymax, 1.0, dowait,
|
|
x1, x2, yy, ncols, ntext, n,
|
|
x3, y3, mcols, mtext, m,
|
|
x4, y4, x5, y5, ocols, o,
|
|
NULL, NULL, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
/* General plot */
|
|
|
|
int do_plot_gen(
|
|
double ixmin, double ixmax, double iymin, double iymax, /* Graph range, */
|
|
/* xmin == xmax, ymin == ymax for auto bound on data */
|
|
double ratio, /* X/Y graph ratio */
|
|
int zero, /* Force ymin to be zero */
|
|
int dowait, /* Wait for user key */
|
|
double *x1, double *y1, double *x2, double *y2, plot_col *ocols, int o, /* Line segments */
|
|
double *x3, double *y3, plot_sym *tp, plot_col *pcols, char **ptext, int p /* Symbols */
|
|
) {
|
|
int i, j;
|
|
double xmin, xmax, ymin, ymax;
|
|
|
|
/* Determine min and max dimensions of plot */
|
|
xmin = ymin = 1e6;
|
|
xmax = ymax = -1e6;
|
|
|
|
if (x1 != NULL && x2 != NULL
|
|
&& y1 != NULL && y2 != NULL) {
|
|
for (i = 0; i < o; i++) {
|
|
if (xmin > x1[i])
|
|
xmin = x1[i];
|
|
if (xmax < x1[i])
|
|
xmax = x1[i];
|
|
if (xmin > x2[i])
|
|
xmin = x2[i];
|
|
if (xmax < x2[i])
|
|
xmax = x2[i];
|
|
|
|
if (ymin > y1[i])
|
|
ymin = y1[i];
|
|
if (ymax < y1[i])
|
|
ymax = y1[i];
|
|
if (ymin > y2[i])
|
|
ymin = y2[i];
|
|
if (ymax < y2[i])
|
|
ymax = y2[i];
|
|
}
|
|
}
|
|
|
|
if (x3 != NULL && y3 != NULL) {
|
|
for (i = 0; i < p; i++) {
|
|
if (xmin > x3[i])
|
|
xmin = x3[i];
|
|
if (xmax < x3[i])
|
|
xmax = x3[i];
|
|
|
|
if (ymin > y3[i])
|
|
ymin = y3[i];
|
|
if (ymax < y3[i])
|
|
ymax = y3[i];
|
|
}
|
|
}
|
|
|
|
|
|
if (zero && ymin > 0.0)
|
|
ymin = 0.0;
|
|
|
|
/* Hmm. Make sure graph is not zero sized */
|
|
if ((xmax - xmin) == 0.0)
|
|
xmax += 0.5, xmin -= 0.5;
|
|
if ((ymax - ymin) == 0.0)
|
|
ymax += 0.5, ymin -= 0.5;
|
|
|
|
|
|
/* Should we use auto graphi size ? */
|
|
if (ixmin != ixmax) {
|
|
xmin = ixmin;
|
|
xmax = ixmax;
|
|
}
|
|
|
|
if (iymin != iymax) {
|
|
ymin = iymin;
|
|
ymax = iymax;
|
|
}
|
|
|
|
if (ratio == 0.0)
|
|
ratio = 1.0;
|
|
|
|
return do_plot_imp(
|
|
0,
|
|
xmin, xmax, ymin, ymax, ratio, dowait,
|
|
NULL, NULL, NULL, NULL, NULL, 0,
|
|
NULL, NULL, NULL, NULL, 0,
|
|
x1, y1, x2, y2, ocols, o,
|
|
x3, y3, tp, pcols, ptext, p);
|
|
}
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
/* General plot using allocation helper */
|
|
|
|
/* rgb, text may be NULL for default/none */
|
|
/* plot also clears gen */
|
|
void init_g(plot_g *g) {
|
|
memset((void *)g, 0, sizeof(plot_g));
|
|
}
|
|
|
|
void add_vec_g(plot_g *g, double x1, double y1, double x2, double y2, float *rgb) {
|
|
|
|
if (g->o >= g->oa) {
|
|
g->oa = 2 * g->oa + 10;
|
|
|
|
g->x1 = (double *)realloc(g->x1, sizeof(double) * g->oa);
|
|
g->y1 = (double *)realloc(g->y1, sizeof(double) * g->oa);
|
|
g->x2 = (double *)realloc(g->x2, sizeof(double) * g->oa);
|
|
g->y2 = (double *)realloc(g->y2, sizeof(double) * g->oa);
|
|
g->ocols = (plot_col *)realloc(g->ocols, sizeof(plot_col) * g->oa);
|
|
|
|
if (g->x1 == NULL || g->y1 == NULL || g->x2 == NULL || g->y2 == NULL || g->ocols == NULL)
|
|
error("add_vec_g malloc faile in %s line %d",__FILE__,__LINE__);
|
|
}
|
|
|
|
g->x1[g->o] = x1;
|
|
g->y1[g->o] = y1;
|
|
g->x2[g->o] = x2;
|
|
g->y2[g->o] = y2;
|
|
if (rgb != NULL) {
|
|
g->ocols[g->o].rgb[0] = rgb[0];
|
|
g->ocols[g->o].rgb[1] = rgb[1];
|
|
g->ocols[g->o].rgb[2] = rgb[2];
|
|
} else {
|
|
g->ocols[g->o].rgb[0] = -1.0;
|
|
g->ocols[g->o].rgb[1] = -1.0;
|
|
g->ocols[g->o].rgb[2] = -1.0;
|
|
}
|
|
g->o++;
|
|
}
|
|
|
|
void add_sym_g(plot_g *g, double x3, double y3, plot_sym st, float *rgb, char *ptext) {
|
|
|
|
if (g->p >= g->pa) {
|
|
g->pa = 2 * g->pa + 10;
|
|
|
|
g->x3 = (double *)realloc(g->x3, sizeof(double) * g->pa);
|
|
g->y3 = (double *)realloc(g->y3, sizeof(double) * g->pa);
|
|
g->tp = (plot_sym *)realloc(g->tp, sizeof(plot_sym) * g->pa);
|
|
g->pcols = (plot_col *)realloc(g->pcols, sizeof(plot_col) * g->pa);
|
|
g->ptext = (char **)realloc(g->ptext, sizeof(char *) * g->pa);
|
|
|
|
if (g->x3 == NULL || g->y3 == NULL || g->tp == NULL || g->pcols == NULL || g->ptext == NULL)
|
|
error("add_sym_g malloc faile in %s line %d",__FILE__,__LINE__);
|
|
}
|
|
|
|
g->x3[g->p] = x3;
|
|
g->y3[g->p] = y3;
|
|
g->tp[g->p] = st;
|
|
if (rgb != NULL) {
|
|
g->pcols[g->p].rgb[0] = rgb[0];
|
|
g->pcols[g->p].rgb[1] = rgb[1];
|
|
g->pcols[g->p].rgb[2] = rgb[2];
|
|
} else {
|
|
g->pcols[g->p].rgb[0] = -1.0;
|
|
g->pcols[g->p].rgb[1] = -1.0;
|
|
g->pcols[g->p].rgb[2] = -1.0;
|
|
}
|
|
if (ptext != NULL) {
|
|
g->ptext[g->p] = strdup(ptext);
|
|
if (g->ptext[g->p] == NULL)
|
|
error("add_sym_g malloc faile in %s line %d",__FILE__,__LINE__);
|
|
} else {
|
|
g->ptext[g->p] = NULL;
|
|
}
|
|
g->p++;
|
|
}
|
|
|
|
/* Fetch point at index. Return nz if out of range */
|
|
int get_xy_g(plot_g *g, double xy[2], int ix) {
|
|
if (ix < 0 || ix >= (2 * g->o + g->p))
|
|
return 1;
|
|
|
|
if (ix < (2 * g->o)) {
|
|
if (ix & 1) {
|
|
xy[0] = g->x1[ix >> 1];
|
|
xy[1] = g->y1[ix >> 1];
|
|
} else {
|
|
xy[0] = g->x2[ix >> 1];
|
|
xy[1] = g->y2[ix >> 1];
|
|
}
|
|
} else {
|
|
ix -= 2 * g->o;
|
|
xy[0] = g->x3[ix];
|
|
xy[1] = g->y3[ix];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Change point value at index. Return nz if out of range */
|
|
int set_xy_g(plot_g *g, double xy[2], int ix) {
|
|
if (ix < 0 || ix >= (2 * g->o + g->p))
|
|
return 1;
|
|
|
|
if (ix < (2 * g->o)) {
|
|
if (ix & 1) {
|
|
g->x1[ix >> 1] = xy[0];
|
|
g->y1[ix >> 1] = xy[1];
|
|
} else {
|
|
g->x2[ix >> 1] = xy[0];
|
|
g->y2[ix >> 1] = xy[1];
|
|
}
|
|
} else {
|
|
ix -= 2 * g->o;
|
|
g->x3[ix] = xy[0];
|
|
g->y3[ix] = xy[1];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Get the combined index number for current vector values */
|
|
int get_vxyix_g(plot_g *g) {
|
|
return 2 * g->o;
|
|
}
|
|
|
|
|
|
/* Start a line that will be implemented as vectors. */
|
|
void start_line_g(plot_g *g, double x, double y, float *rgb) {
|
|
g->lx = x;
|
|
g->ly = y;
|
|
g->lrgb[0] = rgb[0];
|
|
g->lrgb[1] = rgb[1];
|
|
g->lrgb[2] = rgb[2];
|
|
}
|
|
|
|
/* Continue a line that will be implemented as vectors */
|
|
void extend_line_g(plot_g *g, double x, double y) {
|
|
add_vec_g(g, g->lx, g->ly, x, y, g->lrgb);
|
|
g->lx = x;
|
|
g->ly = y;
|
|
}
|
|
|
|
/* Return the bounding box of all the current elements locations */
|
|
void get_bounds_g(plot_g *g, double *pxmin, double *pxmax, double *pymin, double *pymax) {
|
|
double xmin = 1e38, xmax = -1e38, ymin = 1e38, ymax = -1e38;
|
|
int i;
|
|
|
|
for (i = 0; i < g->o; i++) {
|
|
if (g->x1[i] < xmin)
|
|
xmin = g->x1[i];
|
|
if (g->x1[i] > xmax)
|
|
xmax = g->x1[i];
|
|
|
|
if (g->y1[i] < ymin)
|
|
ymin = g->y1[i];
|
|
if (g->y1[i] > ymax)
|
|
ymax = g->y1[i];
|
|
|
|
if (g->x2[i] < xmin)
|
|
xmin = g->x2[i];
|
|
if (g->x2[i] > xmax)
|
|
xmax = g->x2[i];
|
|
|
|
if (g->y2[i] < ymin)
|
|
ymin = g->y2[i];
|
|
if (g->y2[i] > ymax)
|
|
ymax = g->y2[i];
|
|
}
|
|
|
|
for (i = 0; i < g->p; i++) {
|
|
if (g->x3[i] < xmin)
|
|
xmin = g->x3[i];
|
|
if (g->x3[i] > xmax)
|
|
xmax = g->x3[i];
|
|
|
|
if (g->y3[i] < ymin)
|
|
ymin = g->y3[i];
|
|
if (g->y3[i] > ymax)
|
|
ymax = g->y3[i];
|
|
}
|
|
|
|
if (pxmin != NULL)
|
|
*pxmin = xmin;
|
|
if (pxmax != NULL)
|
|
*pxmax = xmax;
|
|
if (pymin != NULL)
|
|
*pymin = ymin;
|
|
if (pymax != NULL)
|
|
*pymax = xmax;
|
|
}
|
|
|
|
/* Plot, but don't clear (i.e. free) lists */
|
|
void do_plot_g(
|
|
plot_g *g,
|
|
double xmin, double xmax, double ymin, double ymax,
|
|
double ratio, int zero, int dowait
|
|
) {
|
|
do_plot_gen(xmin, xmax, ymin, ymax, ratio, zero, dowait,
|
|
g->x1, g->y1, g->x2, g->y2, g->ocols, g->o,
|
|
g->x3, g->y3, g->tp, g->pcols, g->ptext, g->p);
|
|
}
|
|
|
|
void clear_g(plot_g *g) {
|
|
int i;
|
|
|
|
free(g->x1);
|
|
free(g->y1);
|
|
free(g->x2);
|
|
free(g->y2);
|
|
free(g->ocols);
|
|
free(g->x3);
|
|
free(g->y3);
|
|
free(g->pcols);
|
|
free(g->tp);
|
|
for (i = 0; i < g->p; i++) {
|
|
free(g->ptext[i]);
|
|
}
|
|
free(g->ptext);
|
|
|
|
memset((void *)g, 0, sizeof(plot_g));
|
|
}
|
|
|
|
|
|
/* ********************************** NT version ********************** */
|
|
#ifdef NT
|
|
|
|
#include <windows.h>
|
|
|
|
#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. (This is accessed by lpszClassName match to 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 (optional) diagonal cross at x2, y2 */
|
|
/* all in black or ncols with annotation ntext at the cross, */
|
|
/* plus a (optiona) diagonal cross at x7, y7 in yellow. The color for x7, y7 can be */
|
|
/* overidden by an array of colors mcols, plus 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) */
|
|
/* x8,y8 to x9,y9 are extra optional vectors with optional colors */
|
|
static int do_plot_imp(
|
|
int flags,
|
|
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], plot_col *ncols, 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,
|
|
double *xp, double *yp, plot_sym *tp, plot_col *pcols, char **ptext,
|
|
int p
|
|
) {
|
|
if (dolog) do_log_imp(
|
|
flags,
|
|
xmin, xmax, ymin, ymax, ratio,
|
|
dowait,
|
|
x1, x2, yy, ncols, ntext, n,
|
|
x7, y7, mcols, mtext, m,
|
|
x8, y8, x9, y9, ocols, o,
|
|
xp, yp, tp, pcols, ptext, p);
|
|
|
|
if (!checkedenv) {
|
|
checkedenv = 1;
|
|
if (getenv("ARGYLL_SUPPRESS_PLOT") != NULL)
|
|
noplot = 1;
|
|
}
|
|
|
|
if (noplot)
|
|
return 0;
|
|
|
|
/* Put information in global pd */
|
|
{
|
|
int j;
|
|
double xr,yr;
|
|
|
|
pd.flags = flags;
|
|
pd.dowait = dowait;
|
|
pd.ratio = ratio;
|
|
|
|
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; /* MXGPHS graphs + points */
|
|
else
|
|
pd.graph = 0; /* vectors + optional crosses */
|
|
pd.x1 = x1;
|
|
pd.x2 = x2;
|
|
if (yy != NULL) {
|
|
for (j = 0; j < MXGPHS; j++)
|
|
pd.yy[j] = yy[j];
|
|
} else {
|
|
for (j = 0; j < MXGPHS; j++)
|
|
pd.yy[j] = NULL;
|
|
}
|
|
pd.ncols = ncols;
|
|
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);
|
|
|
|
pd.xp = xp;
|
|
pd.yp = yp;
|
|
pd.tp = tp;
|
|
pd.pcols = pcols;
|
|
pd.ptext = ptext;
|
|
pd.p = abs(p);
|
|
}
|
|
|
|
/* ------------------------------------------- */
|
|
/* Setup windows stuff */
|
|
{
|
|
ui_UsingGUI();
|
|
|
|
/* 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);
|
|
|
|
SetForegroundWindow(plot_hwnd); /* Raise */
|
|
}
|
|
|
|
plot_signal = 0;
|
|
|
|
if (dowait > 0)
|
|
SetForegroundWindow(plot_hwnd); /* Raise */
|
|
|
|
/* 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 '\r':
|
|
case '\n':
|
|
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;
|
|
|
|
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;
|
|
|
|
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 *p
|
|
) {
|
|
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 (p->revx)
|
|
loose_label(hdc, p, p->mxx, p->mnx, xtick);
|
|
else
|
|
loose_label(hdc, p, p->mnx, p->mxx, xtick);
|
|
|
|
/* Plot vertical axis */
|
|
loose_label(hdc, p, p->mny, p->mxy, ytick);
|
|
|
|
RestoreDC(hdc,-1);
|
|
DeleteObject(pen);
|
|
|
|
if (p->graph) { /* Up to MXGPHS graphs + crosses */
|
|
for (j = MXGPHS-1; j >= 0; j--) {
|
|
double *yp = p->yy[j];
|
|
|
|
if (yp == NULL)
|
|
continue;
|
|
|
|
pen = CreatePen(PS_SOLID,ILTHICK,RGB(plot_colors[j][0],plot_colors[j][1],plot_colors[j][2]));
|
|
SelectObject(hdc,pen);
|
|
|
|
lx = (int)((p->x1[0] - p->mnx) * p->scx + 0.5);
|
|
ly = (int)(( yp[0] - p->mny) * p->scy + 0.5);
|
|
|
|
for (i = 0; i < p->n; i++) {
|
|
int cx,cy;
|
|
cx = (int)((p->x1[i] - p->mnx) * p->scx + 0.5);
|
|
cy = (int)(( yp[i] - p->mny) * p->scy + 0.5);
|
|
|
|
MoveToEx(hdc, 10 + lx, p->sh - 10 - ly, NULL);
|
|
LineTo(hdc, 10 + cx, p->sh - 10 - cy);
|
|
if (p->flags & PLOTF_GRAPHCROSSES) {
|
|
MoveToEx(hdc, 10 + cx - 5, p->sh - 10 - cy - 5, NULL);
|
|
LineTo(hdc, 10 + cx + 5, p->sh - 10 - cy + 5);
|
|
LineTo(hdc, 10 + cx - 5, p->sh - 10 - cy + 5);
|
|
}
|
|
lx = cx;
|
|
ly = cy;
|
|
}
|
|
DeleteObject(pen);
|
|
}
|
|
|
|
} else { /* Vectors with cross */
|
|
|
|
/* Default is black */
|
|
pen = CreatePen(PS_SOLID,ILTHICK, RGB(0,0,0));
|
|
SelectObject(hdc, pen);
|
|
|
|
if (p->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 < p->n; i++) {
|
|
int cx,cy;
|
|
|
|
if (p->ncols != NULL) {
|
|
int rgb[3];
|
|
|
|
for (j = 0; j < 3; j++)
|
|
rgb[j] = (int)(p->ncols[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 (p->mtext != NULL)
|
|
SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2]));
|
|
}
|
|
|
|
lx = (int)((p->x1[i] - p->mnx) * p->scx + 0.5);
|
|
ly = (int)((p->yy[0][i] - p->mny) * p->scy + 0.5);
|
|
|
|
cx = (int)((p->x2[i] - p->mnx) * p->scx + 0.5);
|
|
cy = (int)((p->yy[1][i] - p->mny) * p->scy + 0.5);
|
|
|
|
MoveToEx(hdc, 10 + lx, p->sh - 10 - ly, NULL);
|
|
LineTo(hdc, 10 + cx, p->sh - 10 - cy);
|
|
|
|
if (p->flags & PLOTF_VECCROSSES) {
|
|
MoveToEx(hdc, 10 + cx - 5, p->sh - 10 - cy - 5, NULL);
|
|
LineTo(hdc, 10 + cx + 5, p->sh - 10 - cy + 5);
|
|
MoveToEx(hdc, 10 + cx + 5, p->sh - 10 - cy - 5, NULL);
|
|
LineTo(hdc, 10 + cx - 5, p->sh - 10 - cy + 5);
|
|
}
|
|
|
|
if (p->ntext != NULL) {
|
|
RECT rct;
|
|
rct.right =
|
|
rct.left = 10 + cx + 10;
|
|
rct.top =
|
|
rct.bottom = p->sh - 10 - cy + 10;
|
|
DrawText(hdc, p->ntext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
|
|
}
|
|
}
|
|
DeleteObject(pen);
|
|
}
|
|
|
|
/* Extra points */
|
|
if (p->x7 != NULL && p->y7 != NULL && p->m > 0 ) {
|
|
pen = CreatePen(PS_SOLID,ILTHICK,RGB(210,150,0)); /* Yellow */
|
|
SelectObject(hdc,pen);
|
|
|
|
if (p->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 < p->m; i++) {
|
|
lx = (int)((p->x7[i] - p->mnx) * p->scx + 0.5);
|
|
ly = (int)((p->y7[i] - p->mny) * p->scy + 0.5);
|
|
|
|
if (p->mcols != NULL) {
|
|
int rgb[3];
|
|
|
|
for (j = 0; j < 3; j++)
|
|
rgb[j] = (int)(p->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 (p->mtext != NULL)
|
|
SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2]));
|
|
}
|
|
MoveToEx(hdc, 10 + lx - 5, p->sh - 10 - ly, NULL);
|
|
LineTo(hdc, 10 + lx + 5, p->sh - 10 - ly);
|
|
MoveToEx(hdc, 10 + lx, p->sh - 10 - ly - 5, NULL);
|
|
LineTo(hdc, 10 + lx, p->sh - 10 - ly + 5);
|
|
|
|
if (p->mtext != NULL) {
|
|
RECT rct;
|
|
rct.right =
|
|
rct.left = 10 + lx + 10;
|
|
rct.top =
|
|
rct.bottom = p->sh - 10 - ly - 10;
|
|
DrawText(hdc, p->mtext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
|
|
}
|
|
}
|
|
DeleteObject(pen);
|
|
}
|
|
|
|
/* General vectors */
|
|
if (p->x8 != NULL && p->y8 != NULL && p->x9 != NULL && p->y9 && p->o > 0 ) {
|
|
pen = CreatePen(PS_SOLID,ILTHICK,RGB(150,255,255)); /* Light Blue */
|
|
SelectObject(hdc,pen);
|
|
|
|
for (i = 0; i < p->o; i++) {
|
|
int cx,cy;
|
|
|
|
lx = (int)((p->x8[i] - p->mnx) * p->scx + 0.5);
|
|
ly = (int)((p->y8[i] - p->mny) * p->scy + 0.5);
|
|
|
|
cx = (int)((p->x9[i] - p->mnx) * p->scx + 0.5);
|
|
cy = (int)((p->y9[i] - p->mny) * p->scy + 0.5);
|
|
|
|
if (p->ocols != NULL) {
|
|
int rgb[3];
|
|
|
|
for (j = 0; j < 3; j++)
|
|
rgb[j] = (int)(p->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);
|
|
}
|
|
MoveToEx(hdc, 10 + lx, p->sh - 10 - ly, NULL);
|
|
LineTo(hdc, 10 + cx, p->sh - 10 - cy);
|
|
}
|
|
DeleteObject(pen);
|
|
}
|
|
|
|
/* General symbols and text */
|
|
if (p->xp != NULL && p->yp != NULL && p->p > 0) {
|
|
|
|
if (p->ptext != 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 < p->p; i++) {
|
|
int cx,cy;
|
|
int rgb[3];
|
|
|
|
if (p->pcols != NULL &&
|
|
p->pcols[i].rgb[0] >= 0.0 &&
|
|
p->pcols[i].rgb[1] >= 0.0 &&
|
|
p->pcols[i].rgb[2] >= 0.0
|
|
) {
|
|
for (j = 0; j < 3; j++)
|
|
rgb[j] = (int)(p->pcols[i].rgb[j] * 255.0 + 0.5);
|
|
|
|
} else {
|
|
for (j = 0; j < 3; j++)
|
|
rgb[j] = plot_colors[i % MXGPHS][j];
|
|
}
|
|
|
|
DeleteObject(pen);
|
|
pen = CreatePen(PS_SOLID,ILTHICK,RGB(rgb[0],rgb[1],rgb[2]));
|
|
SelectObject(hdc,pen);
|
|
|
|
if (p->ptext != NULL)
|
|
SetTextColor(hdc, RGB(rgb[0],rgb[1],rgb[2]));
|
|
|
|
cx = (int)((p->xp[i] - p->mnx) * p->scx + 0.5);
|
|
cy = (int)((p->yp[i] - p->mny) * p->scy + 0.5);
|
|
|
|
/* Allow for margin and y being top to bottom */
|
|
cx += 10;
|
|
cy += 10;
|
|
cy = p->sh - cy;
|
|
|
|
switch (p->tp[i]) {
|
|
case plotDiagCross:
|
|
MoveToEx(hdc, cx - 5, cy - 5, NULL);
|
|
LineTo(hdc, cx + 5, cy + 5);
|
|
MoveToEx(hdc, cx + 5, cy - 5, NULL);
|
|
LineTo(hdc, cx - 5, cy + 5);
|
|
break;
|
|
case plotOrthCross:
|
|
MoveToEx(hdc, cx - 5, cy, NULL);
|
|
LineTo(hdc, cx + 5, cy);
|
|
MoveToEx(hdc, cx, cy - 5, NULL);
|
|
LineTo(hdc, cx, cy + 5);
|
|
break;
|
|
case plotSquare:
|
|
MoveToEx(hdc, cx - 5, cy - 5, NULL);
|
|
LineTo(hdc, cx + 5, cy - 5);
|
|
LineTo(hdc, cx + 5, cy + 5);
|
|
LineTo(hdc, cx - 5, cy + 5);
|
|
LineTo(hdc, cx - 5, cy - 5);
|
|
break;
|
|
case plotDiamond:
|
|
MoveToEx(hdc, cx , cy - 5, NULL);
|
|
LineTo(hdc, cx + 5, cy );
|
|
LineTo(hdc, cx , cy + 5);
|
|
LineTo(hdc, cx - 5, cy );
|
|
LineTo(hdc, cx , cy - 5);
|
|
break;
|
|
case plotUpTriang:
|
|
MoveToEx(hdc, cx - 5, cy + 5, NULL);
|
|
LineTo(hdc, cx , cy - 5);
|
|
LineTo(hdc, cx + 5, cy + 5);
|
|
LineTo(hdc, cx - 5, cy + 5);
|
|
break;
|
|
case plotDownTriang:
|
|
MoveToEx(hdc, cx - 5, cy - 5, NULL);
|
|
LineTo(hdc, cx + 5, cy - 5);
|
|
LineTo(hdc, cx , cy + 5);
|
|
LineTo(hdc, cx - 5, cy - 5);
|
|
break;
|
|
plotNoSym:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (p->ptext != NULL && p->ptext[i] != NULL) {
|
|
RECT rct;
|
|
rct.right =
|
|
rct.left = cx + 10;
|
|
rct.top =
|
|
rct.bottom = cy + 13;
|
|
DrawText(hdc, p->ptext[i], -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER | DT_NOCLIP);
|
|
}
|
|
}
|
|
DeleteObject(pen);
|
|
}
|
|
|
|
// while(!kbhit());
|
|
}
|
|
|
|
#endif /* NT */
|
|
|
|
/* ************************** APPLE OSX Cocoa version ****************** */
|
|
#ifdef __APPLE__
|
|
|
|
#include <Foundation/Foundation.h>
|
|
#include <AppKit/AppKit.h>
|
|
|
|
#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
|
|
|
|
/* Function called back by main thread to trigger a drawRect */
|
|
|
|
static void doSetNeedsDisplay(void *cntx) {
|
|
cntx_t *cx = (cntx_t *)cntx;
|
|
|
|
[cx->view setNeedsDisplay: YES ];
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
@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] == ' '
|
|
|| chars[0] == '\r') {
|
|
// 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(void *cntx) {
|
|
cntx_t *cx = (cntx_t *)cntx;
|
|
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
|
|
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
|
|
styleMask: (NSWindowStyleMaskTitled |
|
|
NSWindowStyleMaskClosable |
|
|
NSWindowStyleMaskMiniaturizable |
|
|
NSWindowStyleMaskResizable)
|
|
#else
|
|
styleMask: (NSTitledWindowMask |
|
|
NSClosableWindowMask |
|
|
NSMiniaturizableWindowMask |
|
|
NSResizableWindowMask)
|
|
#endif
|
|
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 can
|
|
decouble the windows from the application is to intercept
|
|
main() and create a secondary thread to run the appication while
|
|
leaving main() in reserve for creating an NSApp and windows.
|
|
*/
|
|
|
|
/* 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 (optional) diagonal cross at x2, y2 */
|
|
/* all in black or ncols with annotation ntext at the cross, */
|
|
/* plus a (optiona) diagonal cross at x7, y7 in yellow. The color for x7, y7 can be */
|
|
/* overidden by an array of colors mcols, plus 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) */
|
|
/* x8,y8 to x9,y9 are extra optional vectors with optional colors */
|
|
static int do_plot_imp(
|
|
int flags,
|
|
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], plot_col *ncols, 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,
|
|
double *xp, double *yp, plot_sym *tp, plot_col *pcols, char **ptext,
|
|
int p
|
|
) {
|
|
if (dolog) do_log_imp(
|
|
flags,
|
|
xmin, xmax, ymin, ymax, ratio,
|
|
dowait,
|
|
x1, x2, yy, ncols, ntext, n,
|
|
x7, y7, mcols, mtext, m,
|
|
x8, y8, x9, y9, ocols, o,
|
|
xp, yp, tp, pcols, ptext, p);
|
|
|
|
/* Put information in global pd */
|
|
{
|
|
int j;
|
|
double xr,yr;
|
|
|
|
pd.flags = flags;
|
|
pd.dowait = dowait;
|
|
pd.ratio = ratio;
|
|
|
|
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;
|
|
if (yy != NULL) {
|
|
for (j = 0; j < MXGPHS; j++)
|
|
pd.yy[j] = yy[j];
|
|
} else {
|
|
for (j = 0; j < MXGPHS; j++)
|
|
pd.yy[j] = NULL;
|
|
}
|
|
pd.ncols = ncols;
|
|
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);
|
|
|
|
pd.xp = xp;
|
|
pd.yp = yp;
|
|
pd.tp = tp;
|
|
pd.pcols = pcols;
|
|
pd.ptext = ptext;
|
|
pd.p = abs(p);
|
|
}
|
|
|
|
ui_UsingGUI();
|
|
|
|
/* If we may be in a different thread to the main thread or */
|
|
/* the application thread, establish our own pool. */
|
|
NSAutoreleasePool *tpool = nil;
|
|
if (pthread_self() != ui_thid
|
|
&& pthread_self() != ui_main_thid)
|
|
tpool = [NSAutoreleasePool new];
|
|
|
|
/* If needed, create the indow */
|
|
if (plot_cx == NULL) {
|
|
|
|
/* If there is no NSApp, then we haven't run main() in libui before */
|
|
/* main() in the application. */
|
|
if (NSApp == nil) {
|
|
fprintf(stderr,"NSApp is nil - need to rename main() to main() and link with libui !\n");
|
|
exit(1);
|
|
}
|
|
|
|
if ((plot_cx = (cntx_t *)calloc(1, sizeof(cntx_t))) == NULL)
|
|
error("new_dispwin: Malloc failed (cntx_t)\n");
|
|
|
|
/* Prepare to wait for events */
|
|
ui_aboutToWait();
|
|
|
|
/* Run the window creation in the main thread and wait for it */
|
|
ui_runInMainThreadAndWait((void *)plot_cx, create_my_win);
|
|
|
|
/* Wait for events generated by window creation to complete */
|
|
ui_waitForEvents();
|
|
|
|
} else { /* Trigger an update */
|
|
// [plot_cx->view setNeedsDisplay: YES ];
|
|
|
|
/* Prepare to wait for events */
|
|
ui_aboutToWait();
|
|
|
|
/* Run the window creation in the main thread and wait for it */
|
|
ui_runInMainThreadAndWait((void *)plot_cx, doSetNeedsDisplay);
|
|
|
|
/* Wait for any events generated by paint to complete */
|
|
ui_waitForEvents();
|
|
}
|
|
|
|
/* (Main thread will service events) */
|
|
|
|
/* Wait until for a key if we should */
|
|
if (dowait > 0) { /* Wait for a space key */
|
|
for (plot_cx->plot_signal = 0; plot_cx->plot_signal == 0;) {
|
|
struct timespec ts;
|
|
|
|
ts.tv_sec = 100 / 1000;
|
|
ts.tv_nsec = (100 % 1000) * 1000000;
|
|
nanosleep(&ts, NULL);
|
|
}
|
|
} else if (dowait < 0) {
|
|
struct timespec ts;
|
|
int msec = -dowait * 1000;
|
|
|
|
ts.tv_sec = msec / 1000;
|
|
ts.tv_nsec = (msec % 1000) * 1000000;
|
|
nanosleep(&ts, NULL);
|
|
}
|
|
|
|
if (tpool != nil)
|
|
[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;
|
|
float 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 */
|
|
for (j = MXGPHS-1; j >= 0; j--) {
|
|
double *yp = pdp->yy[j];
|
|
|
|
if (yp == NULL)
|
|
continue;
|
|
|
|
[[NSColor colorWithCalibratedRed: plot_colors[j][0]/255.0
|
|
green: plot_colors[j][1]/255.0
|
|
blue: plot_colors[j][2]/255.0
|
|
alpha: 1.0] setStroke];
|
|
|
|
if (pdp->n > 0) {
|
|
lx = (pdp->x1[0] - pdp->mnx) * pdp->scx;
|
|
ly = ( yp[0] - pdp->mny) * pdp->scy;
|
|
}
|
|
|
|
for (i = 1; i < pdp->n; i++) {
|
|
float cx,cy;
|
|
cx = (pdp->x1[i] - pdp->mnx) * pdp->scx;
|
|
cy = ( yp[i] - pdp->mny) * pdp->scy;
|
|
|
|
ADrawLine(path, 20.0 + lx, 20.0 + ly, 20 + cx, 20.0 + cy);
|
|
if (pdp->flags & PLOTF_GRAPHCROSSES) {
|
|
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);
|
|
}
|
|
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++) {
|
|
float cx,cy;
|
|
|
|
if (pdp->ncols != NULL) {
|
|
[[NSColor colorWithCalibratedRed: pdp->ncols[i].rgb[0]/255.0
|
|
green: pdp->ncols[i].rgb[1]/255.0
|
|
blue: pdp->ncols[i].rgb[2]/255.0
|
|
alpha: 1.0] setStroke];
|
|
|
|
if (pdp->ntext != NULL) {
|
|
tcol = [NSColor colorWithCalibratedRed: pdp->ncols[i].rgb[0]/255.0
|
|
green: pdp->ncols[i].rgb[1]/255.0
|
|
blue: pdp->ncols[i].rgb[2]/255.0
|
|
alpha: 1.0];
|
|
}
|
|
}
|
|
|
|
lx = (pdp->x1[i] - pdp->mnx) * pdp->scx;
|
|
ly = (pdp->yy[0][i] - pdp->mny) * pdp->scy;
|
|
|
|
cx = (pdp->x2[i] - pdp->mnx) * pdp->scx;
|
|
cy = (pdp->yy[1][i] - pdp->mny) * pdp->scy;
|
|
|
|
ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy);
|
|
|
|
if (pdp->flags & PLOTF_VECCROSSES) {
|
|
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 = (pdp->x7[i] - pdp->mnx) * pdp->scx;
|
|
ly = (pdp->y7[i] - pdp->mny) * pdp->scy;
|
|
|
|
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]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* General 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++) {
|
|
float 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 = (pdp->x8[i] - pdp->mnx) * pdp->scx;
|
|
ly = (pdp->y8[i] - pdp->mny) * pdp->scy;
|
|
|
|
cx = (pdp->x9[i] - pdp->mnx) * pdp->scx;
|
|
cy = (pdp->y9[i] - pdp->mny) * pdp->scy;
|
|
|
|
ADrawLine(path, 20.0 + lx, 20.0 + ly, 20.0 + cx, 20.0 + cy);
|
|
}
|
|
}
|
|
|
|
/* General symbols and text */
|
|
if (pdp->xp != NULL && pdp->yp != NULL && pdp->p > 0 ) {
|
|
int ss = 7;
|
|
|
|
for (i = 0; i < pdp->p; i++) {
|
|
float cx,cy;
|
|
|
|
if (pdp->pcols != NULL) {
|
|
[[NSColor colorWithCalibratedRed: pdp->pcols[i].rgb[0]
|
|
green: pdp->pcols[i].rgb[1]
|
|
blue: pdp->pcols[i].rgb[2]
|
|
alpha: 1.0] setStroke];
|
|
|
|
if (pdp->ptext != NULL) {
|
|
tcol = [NSColor colorWithCalibratedRed: pdp->pcols[i].rgb[0]
|
|
green: pdp->pcols[i].rgb[1]
|
|
blue: pdp->pcols[i].rgb[2]
|
|
alpha: 1.0];
|
|
}
|
|
} else {
|
|
[[NSColor colorWithCalibratedRed: plot_colors[i % MXGPHS][0]/255.0
|
|
green: plot_colors[i % MXGPHS][1]/255.0
|
|
blue: plot_colors[i % MXGPHS][2]/255.0
|
|
alpha: 1.0] setStroke];
|
|
if (pdp->ptext != NULL) {
|
|
tcol = [NSColor colorWithCalibratedRed: plot_colors[i % MXGPHS][0]
|
|
green: plot_colors[i % MXGPHS][1]
|
|
blue: plot_colors[i % MXGPHS][2]
|
|
alpha: 1.0];
|
|
}
|
|
}
|
|
|
|
cx = (pdp->xp[i] - pdp->mnx) * pdp->scx;
|
|
cy = (pdp->yp[i] - pdp->mny) * pdp->scy;
|
|
|
|
/* Allow for margin and y being top to bottom */
|
|
cx += 20.0;
|
|
cy += 20.0;
|
|
|
|
switch (pdp->tp[i]) {
|
|
case plotDiagCross:
|
|
ADrawLine(path, cx - ss, cy + ss, cx + ss, cy - ss);
|
|
ADrawLine(path, cx + ss, cy + ss, cx - ss, cy - ss);
|
|
break;
|
|
case plotOrthCross:
|
|
ADrawLine(path, cx - ss, cy , cx + ss, cy );
|
|
ADrawLine(path, cx, cy + ss, cx, cy - ss);
|
|
break;
|
|
case plotSquare:
|
|
ADrawLine(path, cx - ss, cy + ss, cx + ss, cy + ss);
|
|
ADrawLine(path, cx + ss, cy + ss, cx + ss, cy - ss);
|
|
ADrawLine(path, cx + ss, cy - ss, cx - ss, cy - ss);
|
|
ADrawLine(path, cx - ss, cy - ss, cx - ss, cy + ss);
|
|
break;
|
|
case plotDiamond:
|
|
ADrawLine(path, cx , cy + ss, cx + ss, cy );
|
|
ADrawLine(path, cx + ss, cy , cx , cy - ss);
|
|
ADrawLine(path, cx , cy - ss, cx - ss, cy );
|
|
ADrawLine(path, cx - ss, cy , cx , cy + ss);
|
|
break;
|
|
case plotUpTriang:
|
|
ADrawLine(path, cx - ss, cy - ss, cx , cy + ss);
|
|
ADrawLine(path, cx , cy + ss, cx + ss, cy - ss);
|
|
ADrawLine(path, cx + ss, cy - ss, cx - ss, cy - ss);
|
|
break;
|
|
case plotDownTriang:
|
|
ADrawLine(path, cx - ss, cy + ss, cx + ss, cy + ss);
|
|
ADrawLine(path, cx + ss, cy + ss, cx , cy - ss);
|
|
ADrawLine(path, cx , cy - ss, cx - ss, cy + ss);
|
|
break;
|
|
plotNoSym:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pdp->ptext != NULL && pdp->ptext[i] != NULL) {
|
|
ADrawText(tcol, 9.0, cx + 9, cy - 18, 0x1, pdp->ptext[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* __APPLE__ */
|
|
|
|
/* ********************************** X11 version ********************** */
|
|
#ifdef UNIX_X11 /* Assume UNIX + X11 */
|
|
|
|
/* !!!! 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 <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
|
|
#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 (optional) diagonal cross at x2, y2 */
|
|
/* all in black or ncols with annotation ntext at the cross, */
|
|
/* plus a (optiona) diagonal cross at x7, y7 in yellow. The color for x7, y7 can be */
|
|
/* overidden by an array of colors mcols, plus 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) */
|
|
/* x8,y8 to x9,y9 are extra optional vectors with optional colors */
|
|
static int do_plot_imp(
|
|
int flags,
|
|
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], plot_col *ncols, 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,
|
|
double *xp, double *yp, plot_sym *tp, plot_col *pcols, char **ptext,
|
|
int p
|
|
) {
|
|
if (dolog) do_log_imp(
|
|
flags,
|
|
xmin, xmax, ymin, ymax, ratio,
|
|
dowait,
|
|
x1, x2, yy, ncols, ntext, n,
|
|
x7, y7, mcols, mtext, m,
|
|
x8, y8, x9, y9, ocols, o,
|
|
xp, yp, tp, pcols, ptext, p);
|
|
|
|
/* Put information in global pd */
|
|
{
|
|
int j;
|
|
double xr,yr;
|
|
|
|
pd.flags = flags;
|
|
pd.dowait = dowait;
|
|
pd.ratio = ratio;
|
|
|
|
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; /* MXGPHS graphs + points */
|
|
else
|
|
pd.graph = 0;
|
|
pd.x1 = x1;
|
|
pd.x2 = x2;
|
|
if (yy != NULL) {
|
|
for (j = 0; j < MXGPHS; j++)
|
|
pd.yy[j] = yy[j];
|
|
} else {
|
|
for (j = 0; j < MXGPHS; j++)
|
|
pd.yy[j] = NULL;
|
|
}
|
|
pd.ncols = ncols;
|
|
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);
|
|
|
|
pd.xp = xp;
|
|
pd.yp = yp;
|
|
pd.tp = tp;
|
|
pd.pcols = pcols;
|
|
pd.ptext = ptext;
|
|
pd.p = abs(p);
|
|
}
|
|
|
|
{
|
|
/* 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;
|
|
|
|
ui_UsingGUI();
|
|
|
|
/* 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 */
|
|
XFlush(mydisplay); /* Make sure DoPlot gets to display */
|
|
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 MXGPHS graphs */
|
|
for (j = MXGPHS-1; j >= 0; j--) {
|
|
double *yp = pdp->yy[j];
|
|
|
|
if (yp == NULL)
|
|
continue;
|
|
|
|
col.red = plot_colors[j][0] * 256;
|
|
col.green = plot_colors[j][1] * 256;
|
|
col.blue = plot_colors[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);
|
|
if (pdp->flags & PLOTF_GRAPHCROSSES) {
|
|
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);
|
|
}
|
|
lx = cx;
|
|
ly = cy;
|
|
}
|
|
}
|
|
|
|
} else { /* Vectors */
|
|
|
|
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;
|
|
|
|
if (pdp->ncols != NULL) {
|
|
col.red = (int)(pdp->ncols[i].rgb[0] * 65535.0 + 0.5);
|
|
col.green = (int)(pdp->ncols[i].rgb[1] * 65535.0 + 0.5);
|
|
col.blue = (int)(pdp->ncols[i].rgb[2] * 65535.0 + 0.5);
|
|
XAllocColor(mydisplay, mycmap, &col);
|
|
XSetForeground(mydisplay,mygc, col.pixel);
|
|
XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
|
|
}
|
|
|
|
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);
|
|
|
|
/* Vector */
|
|
XDrawLine(mydisplay, mywindow, mygc, 10 + lx, pdp->sh - 10 - ly, 10 + cx, pdp->sh - 10 - cy);
|
|
|
|
if (pdp->flags & PLOTF_VECCROSSES) {
|
|
/* Cross at end of vector */
|
|
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]));
|
|
}
|
|
}
|
|
|
|
/* General 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);
|
|
}
|
|
}
|
|
|
|
/* General symbols and text */
|
|
if (pdp->xp != NULL && pdp->yp != NULL && pdp->p > 0 ) {
|
|
XSetLineAttributes(mydisplay, mygc, ILTHICK, LineSolid, CapButt, JoinBevel);
|
|
|
|
for (i = 0; i < pdp->p; i++) {
|
|
int cx,cy;
|
|
|
|
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);
|
|
|
|
} else {
|
|
col.red = plot_colors[i % MXGPHS][0] * 256;
|
|
col.green = plot_colors[i % MXGPHS][1] * 256;
|
|
col.blue = plot_colors[i % MXGPHS][2] * 256;
|
|
}
|
|
|
|
XAllocColor(mydisplay, mycmap, &col);
|
|
XSetForeground(mydisplay,mygc, col.pixel);
|
|
|
|
cx = (int)((pdp->xp[i] - pdp->mnx) * pdp->scx + 0.5);
|
|
cy = (int)((pdp->yp[i] - pdp->mny) * pdp->scy + 0.5);
|
|
|
|
/* Allow for margin and y being top to bottom */
|
|
cx += 10;
|
|
cy += 10;
|
|
cy = pdp->sh - cy;
|
|
|
|
switch (pdp->tp[i]) {
|
|
case plotDiagCross:
|
|
XDrawLine(mydisplay, mywindow, mygc, cx - 5, cy - 5, cx + 5, cy + 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx + 5, cy - 5, cx - 5, cy + 5);
|
|
break;
|
|
case plotOrthCross:
|
|
XDrawLine(mydisplay, mywindow, mygc, cx - 5, cy , cx + 5, cy);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx, cy - 5, cx, cy + 5);
|
|
break;
|
|
case plotSquare:
|
|
XDrawLine(mydisplay, mywindow, mygc, cx - 5, cy - 5, cx + 5, cy - 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx + 5, cy - 5, cx + 5, cy + 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx + 5, cy + 5, cx - 5, cy + 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx - 5, cy + 5, cx - 5, cy - 5);
|
|
break;
|
|
case plotDiamond:
|
|
XDrawLine(mydisplay, mywindow, mygc, cx , cy - 5, cx + 5, cy );
|
|
XDrawLine(mydisplay, mywindow, mygc, cx + 5, cy , cx , cy + 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx , cy + 5, cx - 5, cy );
|
|
XDrawLine(mydisplay, mywindow, mygc, cx - 5, cy , cx , cy - 5);
|
|
break;
|
|
case plotUpTriang:
|
|
XDrawLine(mydisplay, mywindow, mygc, cx - 5, cy + 5, cx , cy - 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx , cy - 5, cx + 5, cy + 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx + 5, cy + 5, cx - 5, cy + 5);
|
|
break;
|
|
case plotDownTriang:
|
|
XDrawLine(mydisplay, mywindow, mygc, cx - 5, cy - 5, cx + 5, cy - 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx + 5, cy - 5, cx , cy + 5);
|
|
XDrawLine(mydisplay, mywindow, mygc, cx , cy + 5, cx - 5, cy - 5);
|
|
break;
|
|
plotNoSym:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (pdp->ptext != NULL && pdp->ptext[i] != NULL)
|
|
XDrawImageString(mydisplay, mywindow, mygc, cx + 10, cy +13,
|
|
pdp->ptext[i], strlen(pdp->ptext[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* UNIX_X11 */
|
|
|
|
/***********************************************************************/
|
|
/* 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));
|
|
}
|
|
|
|
/***********************************************************************/
|
|
/* Plot logging support */
|
|
|
|
struct _plot_log {
|
|
char *logname;
|
|
FILE *fp;
|
|
|
|
}; typedef struct _plot_log plot_log;
|
|
|
|
static struct _plot_log plotlog;
|
|
|
|
void start_plot_log(char *filename) {
|
|
if (dolog)
|
|
return;
|
|
|
|
plotlog.logname = strdup(filename);
|
|
|
|
if ((plotlog.fp = fopen(filename, "w")) == NULL)
|
|
error("start_plot_log: failed to open '%s'",plotlog.logname);
|
|
|
|
dolog = 1;
|
|
}
|
|
|
|
void stop_plot_log() {
|
|
|
|
if (dolog) {
|
|
if ((fclose(plotlog.fp)) != 0)
|
|
warning("stop_plot_log: failed to close '%s'",plotlog.logname);
|
|
free(plotlog.logname);
|
|
}
|
|
dolog = 0;
|
|
}
|
|
|
|
/* Add an entry to the log. */
|
|
/* Mimics Superset implementation function: */
|
|
/* Graph uses x2 == NULL, x1 : yy[0] .. yy[MXGPHS-1] != NULL for up to MXGPHS graph curves + */
|
|
/* Vector uses x1, y[0] to x2, y[1] as a vector with a (optional) diagonal cross at x2, y2 */
|
|
/* all in black or ncols with annotation ntext at the cross, */
|
|
/* n = number of points/vectors. -ve for reversed X axis */
|
|
/* Diagonal crosses at x7, y7 in yellow, color can be overidden by an array of */
|
|
/* colors mcols, plus optional label text mtext. m = number of x7,y7 points. */
|
|
/* x8,y8 to x9,y9 are extra optional vectors with optional colors, o = no of points. */
|
|
/* xp,yp are extra optional symbols with optional colors, q = no of points. */
|
|
static void do_log_imp(
|
|
int flags,
|
|
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], plot_col *ncols, 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,
|
|
double *xp, double *yp, plot_sym *tp, plot_col *pcols, char **ptext, int q
|
|
) {
|
|
plot_log *p = &plotlog;
|
|
int nn, i, j;
|
|
|
|
if (dolog == 0)
|
|
return;
|
|
|
|
fprintf(p->fp, "start\n");
|
|
|
|
fprintf(p->fp, "flags %x\n",flags);
|
|
fprintf(p->fp, "minmax %f %f %f %f\n",xmin, xmax, ymin, ymax);
|
|
fprintf(p->fp, "ratio %f\n",ratio);
|
|
fprintf(p->fp, "dowait %d\n",dowait);
|
|
|
|
nn = n > 0 ? n : -n;
|
|
if (x1 != NULL && nn > 0) {
|
|
if (x2 == NULL) {
|
|
int mm;
|
|
for (mm = 0; mm < MXGPHS; mm++) {
|
|
if (yy[mm] == NULL)
|
|
break;
|
|
}
|
|
fprintf(p->fp, "ngraphs %d %d\n",nn,mm);
|
|
for (i = 0; i < nn; i++) {
|
|
fprintf(p->fp, "%f",x1[i]);
|
|
for (j = 0; j < mm; j++)
|
|
fprintf(p->fp, " %f",yy[j][i]);
|
|
fprintf(p->fp, "\n");
|
|
}
|
|
} else {
|
|
fprintf(p->fp, "nvectors %d\n",n);
|
|
for (i = 0; i < nn; i++)
|
|
fprintf(p->fp, "%f %f %f %f\n",x1[i],yy[0][i],x2[i],yy[1][i]);
|
|
}
|
|
if (ncols != NULL) {
|
|
fprintf(p->fp, "ncols\n");
|
|
for (i = 0; i < nn; i++)
|
|
fprintf(p->fp, "%f %f %f\n",ncols[i].rgb[0],ncols[i].rgb[1],ncols[i].rgb[2]);
|
|
}
|
|
if (ntext != NULL) {
|
|
fprintf(p->fp, "ntext\n");
|
|
for (i = 0; i < nn; i++)
|
|
fprintf(p->fp, "%s\n",ntext[i] == NULL ?"": ntext[i]);
|
|
}
|
|
}
|
|
|
|
if (x7 != NULL && y7 != NULL && m > 0) {
|
|
fprintf(p->fp, "mcrosses %d\n",m);
|
|
for (i = 0; i < m; i++)
|
|
fprintf(p->fp, "%f %f\n",x7[i],y7[i]);
|
|
if (mcols != NULL) {
|
|
fprintf(p->fp, "mcols\n");
|
|
for (i = 0; i < m; i++)
|
|
fprintf(p->fp, "%f %f %f\n",mcols[i].rgb[0],mcols[i].rgb[1],mcols[i].rgb[2]);
|
|
}
|
|
if (mtext != NULL) {
|
|
fprintf(p->fp, "mtext\n");
|
|
for (i = 0; i < m; i++)
|
|
fprintf(p->fp, "%s\n",mtext[i] == NULL ?"": mtext[i]);
|
|
}
|
|
}
|
|
|
|
if (x8 != NULL && y8 != NULL && x9 != NULL && y9 != NULL && o > 0) {
|
|
fprintf(p->fp, "ovectors %d\n",o);
|
|
for (i = 0; i < o; i++)
|
|
fprintf(p->fp, "%f %f %f %f\n",x8[i],y8[i],x9[i],y9[i]);
|
|
if (ocols != NULL) {
|
|
fprintf(p->fp, "ocols\n");
|
|
for (i = 0; i < o; i++)
|
|
fprintf(p->fp, "%f %f %f\n",ocols[i].rgb[0],ocols[i].rgb[1],ocols[i].rgb[2]);
|
|
}
|
|
}
|
|
|
|
if (xp != NULL && yp != NULL && q > 0) {
|
|
fprintf(p->fp, "psymbols %d\n",q);
|
|
for (i = 0; i < q; i++)
|
|
fprintf(p->fp, "%f %f\n",xp[i],yp[i]);
|
|
if (tp != NULL) {
|
|
fprintf(p->fp, "psyms\n");
|
|
for (i = 0; i < q; i++)
|
|
fprintf(p->fp, "%d\n",tp[i]);
|
|
}
|
|
if (pcols != NULL) {
|
|
fprintf(p->fp, "pcols\n");
|
|
for (i = 0; i < q; i++)
|
|
fprintf(p->fp, "%f %f %f\n",pcols[i].rgb[0],pcols[i].rgb[1],pcols[i].rgb[2]);
|
|
}
|
|
if (ptext != NULL) {
|
|
fprintf(p->fp, "ptext\n");
|
|
for (i = 0; i < q; i++)
|
|
fprintf(p->fp, "%s\n",ptext[i] == NULL ?"": ptext[i]);
|
|
}
|
|
}
|
|
|
|
fprintf(p->fp, "end\n");
|
|
}
|
|
|
|
/* - - - - - - - - - - - - - - - - - */
|
|
|
|
/* Print a message to stdout. This will be logged if logging enabled. */
|
|
void plot_msg_fmt(char *fmt, va_list args) {
|
|
int rv;
|
|
char *buf, *cp, *np;
|
|
int alen, len;
|
|
|
|
rv = 1;
|
|
alen = 100; /* Initial allocation for printf */
|
|
if ((buf = (char *)malloc(alen * sizeof(char))) == NULL)
|
|
error("plot_msg: malloc %d failed",alen);
|
|
|
|
/* We have to use the available printf functions to resize the buffer if needed. */
|
|
for (;rv != 0;) {
|
|
/* vsnprintf() either returns -1 if it doesn't fit, or */
|
|
/* returns the size-1 needed in order to fit. */
|
|
len = vsnprintf(buf, alen, fmt, args);
|
|
|
|
if (len > -1 && (len+1) <= alen) /* Fitted in current allocation */
|
|
break;
|
|
|
|
if (len > -1) /* vsnprintf returned needed size-1 */
|
|
alen = len+2; /* (In case vsnprintf returned 1 less than it needs) */
|
|
else
|
|
alen *= 2; /* We just have to guess */
|
|
|
|
/* Attempt to resize */
|
|
if ((buf = (char *)realloc(buf, alen * sizeof(char))) == NULL)
|
|
error("plot_msg: realloc %d failed",alen);
|
|
}
|
|
|
|
/* Break lines up into separate messages */
|
|
cp = buf;
|
|
for (;;) {
|
|
plot_log *p = &plotlog;
|
|
|
|
np = strchr(cp, '\n');
|
|
if (np != NULL)
|
|
*np = '\000';
|
|
|
|
printf("%s\n",cp);
|
|
|
|
if (dolog)
|
|
fprintf(p->fp, "message %s\n",cp);
|
|
|
|
if (np == NULL || *(++np) == '\000')
|
|
break;
|
|
|
|
cp = np;
|
|
}
|
|
|
|
free(buf);
|
|
}
|
|
|
|
void plot_msg(char *fmt, ...) {
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
plot_msg_fmt(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
/* - - - - - - - - - - - - - - - - - */
|
|
|
|
static void replay(char *filename) {
|
|
FILE *fp;
|
|
int flags;
|
|
double xmin, xmax, ymin, ymax;
|
|
double ratio;
|
|
int dowait;
|
|
|
|
int n = 0;
|
|
double *x1 = NULL, *x2 = NULL, *yy[MXGPHS] = { 0 };
|
|
plot_col *ncols = NULL;
|
|
char **ntext = NULL;
|
|
|
|
int m = 0;
|
|
double *x7 = NULL, *y7 = NULL;
|
|
plot_col *mcols = NULL;
|
|
char **mtext = NULL;
|
|
|
|
int o = 0;
|
|
double *x8 = NULL, *y8 = NULL, *x9 = NULL, *y9 = NULL;
|
|
plot_col *ocols = NULL;
|
|
|
|
int p = 0;
|
|
double *xp = NULL, *yp = NULL;
|
|
plot_sym *tp = NULL;
|
|
plot_col *pcols = NULL;
|
|
char **ptext = NULL;
|
|
|
|
#define MAX_LINE_SIZE 500
|
|
char line[MAX_LINE_SIZE], *cp;
|
|
int lineno = 0;
|
|
int mm, i, j;
|
|
|
|
if ((fp = fopen(filename, "r")) == NULL)
|
|
error("plot replay:: failed to open '%s'",filename);
|
|
|
|
#define NL \
|
|
lineno++; \
|
|
if (fgets(line, MAX_LINE_SIZE, fp) == NULL) \
|
|
error("plot replay:: expected line %d",lineno); \
|
|
if ((cp = strchr(line, '\n')) != NULL) *cp = '\000'
|
|
|
|
/* Make sure env supression of plots is disabled, */
|
|
/* and we don't end up in recursions... */
|
|
noplot = 0;
|
|
checkedenv = 1;
|
|
dolog = 0;
|
|
|
|
/* For each graph or message */
|
|
for (;;) {
|
|
|
|
/* Start of graph, message or end of file */
|
|
lineno++;
|
|
if (fgets(line, MAX_LINE_SIZE, fp) == NULL)
|
|
break;
|
|
if ((cp = strchr(line, '\n')) != NULL) *cp = '\000';
|
|
|
|
if (strncmp(line, "start", 5) == 0) {
|
|
|
|
NL; if (sscanf(line, "flags %x",&flags) != 1)
|
|
error("plot replay: Expected 'flags' at line %d\n",lineno);
|
|
|
|
NL; if (sscanf(line, "minmax %lf %lf %lf %lf",&xmin, &xmax, &ymin, &ymax) != 4)
|
|
error("plot replay: Expected 'minmax' at line %d\n",lineno);
|
|
|
|
NL; if (sscanf(line, "ratio %lf",&ratio) != 1)
|
|
error("plot replay: Expected 'ratio' at line %d\n",lineno);
|
|
|
|
NL; if (sscanf(line, "dowait %d",&dowait) != 1)
|
|
error("plot replay: Expected 'dowait' at line %d\n",lineno);
|
|
|
|
NL;
|
|
|
|
if (strncmp(line, "ngraphs", 7) == 0) {
|
|
int nn;
|
|
if (sscanf(line, "ngraphs %d %d",&n, &mm) != 2)
|
|
error("plot replay: Expected 'ngraphs' at line %d\n",lineno);
|
|
|
|
nn = n > 0 ? n : -n;
|
|
|
|
if ((x1 = (double *)calloc(nn,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed x1 %d\n",n);
|
|
for (j = 0; j < mm; j++) {
|
|
if ((yy[j] = (double *)calloc(nn,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed yy[%d] %d\n",mm,nn);
|
|
}
|
|
|
|
for (i = 0; i < nn; i++) {
|
|
NL;
|
|
cp = line;
|
|
x1[i] = atof(cp);
|
|
for (j = 0; j < mm; j++) {
|
|
if ((cp = strchr(cp, ' ')) == NULL)
|
|
error("plot replay: Expected 'ngraphs' y[%d] line %d\n",j,lineno);
|
|
yy[j][i] = atof(++cp);
|
|
}
|
|
}
|
|
|
|
NL;
|
|
|
|
} else if (strncmp(line, "nvectors", 8) == 0) {
|
|
if (sscanf(line, "nvectors %d",&n) != 1)
|
|
error("plot replay: Expected 'nvectors' at line %d\n",lineno);
|
|
|
|
if ((x1 = (double *)calloc(n,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed x1 %d\n",n);
|
|
if ((yy[0] = (double *)calloc(n,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed yy[0] %d\n",n);
|
|
if ((x2 = (double *)calloc(n,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed x2 %d\n",n);
|
|
if ((yy[1] = (double *)calloc(n,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed yy[1] %d\n",n);
|
|
mm = 2;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
NL;
|
|
if (sscanf(line,"%lf %lf %lf %lf",&x1[i],&yy[0][i],&x2[i],&yy[1][i]) != 4)
|
|
error("plot replay: Expected 'nvectors' x1, yy[0], x2, yy[2] at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "ncols", 5) == 0) {
|
|
if ((ncols = (plot_col *)calloc(n,sizeof(plot_col))) == NULL)
|
|
error("plot_replay: Malloc failed ncol %d\n",n);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
NL;
|
|
if (sscanf(line, "%f %f %f",&ncols[i].rgb[0],&ncols[i].rgb[1],&ncols[i].rgb[2]) != 3)
|
|
error("plot replay: Expected 'ncols' values at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "ntext", 5) == 0) {
|
|
if ((ntext = (char **)calloc(n,sizeof(char *))) == NULL)
|
|
error("plot_replay: Malloc failed ntext %d\n",n);
|
|
|
|
for (i = 0; i < n; i++) {
|
|
NL;
|
|
if ((ntext[i] = strdup(line)) == NULL)
|
|
error("plot replay: malloc failed for 'ntext' at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "mcrosses", 8) == 0) {
|
|
if (sscanf(line, "mcrosses %d",&m) != 1)
|
|
error("plot replay: Expected 'mcrosses' at line %d\n",lineno);
|
|
|
|
if ((x7 = (double *)calloc(m,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed x7 %d\n",n);
|
|
if ((y7 = (double *)calloc(m,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed y7 %d\n",n);
|
|
for (i = 0; i < m; i++) {
|
|
NL;
|
|
if (sscanf(line,"%lf %lf",&x7[i],&y7[i]) != 2)
|
|
error("plot replay: Expected 'mcrosses' x7, y7 at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "mcols", 5) == 0) {
|
|
if ((mcols = (plot_col *)calloc(m,sizeof(plot_col))) == NULL)
|
|
error("plot_replay: Malloc failed mcols %d\n",m);
|
|
|
|
for (i = 0; i < m; i++) {
|
|
NL;
|
|
if (sscanf(line, "%f %f %f",&mcols[i].rgb[0],&mcols[i].rgb[1],&mcols[i].rgb[2]) != 3)
|
|
error("plot replay: Expected 'mcols' values at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "mtext", 5) == 0) {
|
|
if ((mtext = (char **)calloc(m,sizeof(char *))) == NULL)
|
|
error("plot_replay: Malloc failed mtext %d\n",m);
|
|
|
|
for (i = 0; i < m; i++) {
|
|
NL;
|
|
if ((mtext[i] = strdup(line)) == NULL)
|
|
error("plot replay: malloc failed for 'mtext' at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "ovectors", 8) == 0) {
|
|
if (sscanf(line, "ovectors %d",&o) != 1)
|
|
error("plot replay: Expected 'ovectors' at line %d\n",lineno);
|
|
|
|
if ((x8 = (double *)calloc(o,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed x1 %d\n",n);
|
|
if ((y8 = (double *)calloc(o,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed yy[0] %d\n",n);
|
|
if ((x9 = (double *)calloc(o,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed x2 %d\n",n);
|
|
if ((y9 = (double *)calloc(o,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed yy[1] %d\n",n);
|
|
|
|
for (i = 0; i < o; i++) {
|
|
NL;
|
|
if (sscanf(line,"%lf %lf %lf %lf",&x8[i],&y8[i],&x9[i],&y9[i]) != 4)
|
|
error("plot replay: Expected 'ovectors' x8, y8, x9, y9 at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "ocols", 5) == 0) {
|
|
if ((ocols = (plot_col *)calloc(o,sizeof(plot_col))) == NULL)
|
|
error("plot_replay: Malloc failed ocols %d\n",o);
|
|
|
|
for (i = 0; i < o; i++) {
|
|
NL;
|
|
if (sscanf(line, "%f %f %f",&ocols[i].rgb[0],&ocols[i].rgb[1],&ocols[i].rgb[2]) != 3)
|
|
error("plot replay: Expected 'ocols' values at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "psymbols", 8) == 0) {
|
|
if (sscanf(line, "psymbols %d",&p) != 1)
|
|
error("plot replay: Expected 'psymbols' at line %d\n",lineno);
|
|
|
|
if ((xp = (double *)calloc(p,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed x7 %d\n",p);
|
|
if ((yp = (double *)calloc(p,sizeof(double))) == NULL)
|
|
error("plot_replay: Malloc failed y7 %d\n",p);
|
|
for (i = 0; i < p; i++) {
|
|
NL;
|
|
if (sscanf(line,"%lf %lf",&xp[i],&yp[i]) != 2)
|
|
error("plot replay: Expected 'psymbols' xp, yp at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "psyms", 5) == 0) {
|
|
if ((tp = (plot_sym *)calloc(p,sizeof(plot_sym))) == NULL)
|
|
error("plot_replay: Malloc failed psyms %d\n",p);
|
|
|
|
for (i = 0; i < p; i++) {
|
|
NL;
|
|
if (sscanf(line, "%d",(int *)&tp[i]) != 1)
|
|
error("plot replay: Expected 'psyms' values at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "pcols", 5) == 0) {
|
|
if ((pcols = (plot_col *)calloc(p,sizeof(plot_col))) == NULL)
|
|
error("plot_replay: Malloc failed pcols %d\n",p);
|
|
|
|
for (i = 0; i < p; i++) {
|
|
NL;
|
|
if (sscanf(line, "%f %f %f",&pcols[i].rgb[0],&pcols[i].rgb[1],&pcols[i].rgb[2]) != 3)
|
|
error("plot replay: Expected 'pcols' values at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "ptext", 5) == 0) {
|
|
if ((ptext = (char **)calloc(p,sizeof(char *))) == NULL)
|
|
error("plot_replay: Malloc failed ptext %d\n",p);
|
|
|
|
for (i = 0; i < p; i++) {
|
|
NL;
|
|
if ((ptext[i] = strdup(line)) == NULL)
|
|
error("plot replay: malloc failed for 'ptext' at line %d\n",lineno);
|
|
}
|
|
NL;
|
|
}
|
|
if (strncmp(line, "end", 3) == 0) {
|
|
do_plot_imp(
|
|
flags,
|
|
xmin, xmax, ymin, ymax, ratio,
|
|
dowait,
|
|
x1, x2, yy, ncols, ntext, n,
|
|
x7, y7, mcols, mtext, m,
|
|
x8, y8, x9, y9, ocols, o,
|
|
xp, yp, tp, pcols, ptext, p);
|
|
|
|
free(x1); x1 = NULL;
|
|
free(x2); x2 = NULL;
|
|
for (j = 0; j < MXGPHS; j++) {
|
|
free(yy[j]);
|
|
yy[j] = NULL;
|
|
}
|
|
free(ncols); ncols = NULL;
|
|
if (ntext != NULL) {
|
|
for (i = 0; i < n; i++)
|
|
free(ntext[i]);
|
|
free(ntext); ntext = NULL;
|
|
}
|
|
n = 0;
|
|
mm = 0;
|
|
free(x7); x7 = NULL;
|
|
free(y7); y7 = NULL;
|
|
free(mcols); mcols = NULL;
|
|
if (mtext != NULL) {
|
|
for (i = 0; i < m; i++)
|
|
free(mtext[i]);
|
|
free(mtext); mtext = NULL;
|
|
}
|
|
m = 0;
|
|
free(x8); x8 = NULL;
|
|
free(y8); y8 = NULL;
|
|
free(x9); x9 = NULL;
|
|
free(y9); y9 = NULL;
|
|
free(ocols); ocols = NULL;
|
|
o = 0;
|
|
free(xp); xp = NULL;
|
|
free(yp); yp = NULL;
|
|
free(tp);tp = NULL;
|
|
free(pcols); pcols = NULL;
|
|
if (ptext != NULL) {
|
|
for (i = 0; i < p; i++)
|
|
free(ptext[i]);
|
|
free(ptext); ptext = NULL;
|
|
}
|
|
p = 0;
|
|
} else {
|
|
error("plot replay: unknown key '%s' at line %d\n",line,lineno);
|
|
}
|
|
} /* End of plot */
|
|
|
|
if (strncmp(line, "message", 7) == 0) {
|
|
printf("%s\n",line + 8);
|
|
}
|
|
|
|
} /* End of file */
|
|
|
|
#undef MAX_LINE_SIZE
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------- */
|
|
#ifdef NEVER
|
|
static void perror(char *fmt, ...) {
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
vfprintf(fmt, args);
|
|
va_end(args);
|
|
|
|
exit(1);
|
|
}
|
|
#endif
|
|
/* ---------------------------------------------------------------- */
|
|
|
|
#ifdef STANDALONE_TEST
|
|
/* test code */
|
|
|
|
//#include <windows.h>
|
|
//#include <stdio.h>
|
|
#include <fcntl.h>
|
|
//#include <io.h>
|
|
|
|
|
|
#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 succeeded\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
|
|
|
|
void usage(char *diag) {
|
|
fprintf(stderr,"Test plot function\n");
|
|
fprintf(stderr,"usage: plot - %s\n",diag);
|
|
fprintf(stderr," -s filename save plot log to filename\n");
|
|
fprintf(stderr," -r filename replay plot log from filename\n");
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
main(int argc, char *argv[]) {
|
|
int fa,nfa,mfa; /* argument we're looking at */
|
|
static char logname[MAXNAMEL+1] = "";
|
|
int dosave = 0;
|
|
int doreplay = 0;
|
|
|
|
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, 0.3, 0.7, 0.5 };
|
|
double By3[10] = {0.5, 1.3, 0.4, 0.7, 0.77, 0.1, 0.8, 0.5 };
|
|
|
|
char *ntext[5] = { "A", "B", "C", "D" };
|
|
char *mtext[5] = { "10", "20", "30", "40", "50" };
|
|
|
|
plot_col mcols[8] = {
|
|
{ 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 },
|
|
{ 0.0, 1.0, 1.0 },
|
|
{ 1.0, 0.0, 1.0 },
|
|
{ 0.97, 0.37, 0.0 } };
|
|
|
|
plot_sym syms[8] = {
|
|
plotNoSym,
|
|
plotDiagCross,
|
|
plotOrthCross,
|
|
plotSquare,
|
|
plotDiamond,
|
|
plotUpTriang,
|
|
plotDownTriang,
|
|
plotDiagCross,
|
|
};
|
|
|
|
char *ptext[8] = { "NoSym", "DiagCross", "OrthCross", "Square", "Diamond", "UpTriang", "DownTriang", NULL };
|
|
|
|
plot_g gg = { 0 };
|
|
int i;
|
|
|
|
/* Process the arguments */
|
|
mfa = 0; /* Minimum final arguments */
|
|
for (fa = 1;fa < argc;fa++) {
|
|
nfa = fa; /* skip to nfa if next argument is used */
|
|
if (argv[fa][0] == '-') { /* Look for any flags */
|
|
char *na = NULL; /* next argument after flag, null if none */
|
|
|
|
if (argv[fa][2] != '\000')
|
|
na = &argv[fa][2]; /* next is directly after flag */
|
|
else {
|
|
if ((fa+1+mfa) < argc) {
|
|
if (argv[fa+1][0] != '-') {
|
|
nfa = fa + 1;
|
|
na = argv[nfa]; /* next is seperate non-flag argument */
|
|
}
|
|
}
|
|
}
|
|
|
|
if (argv[fa][1] == '?')
|
|
usage("Requested usage");
|
|
|
|
if (argv[fa][1] == 's') {
|
|
if (na == NULL) usage("-s needs an argument");
|
|
fa = nfa;
|
|
strncpy(logname,na,MAXNAMEL); logname[MAXNAMEL] = '\000';
|
|
dosave = 1;
|
|
doreplay = 0;
|
|
}
|
|
else if (argv[fa][1] == 'r') {
|
|
if (na == NULL) usage("-r needs an argument");
|
|
fa = nfa;
|
|
strncpy(logname,na,MAXNAMEL); logname[MAXNAMEL] = '\000';
|
|
dosave = 0;
|
|
doreplay = 1;
|
|
}
|
|
|
|
else
|
|
usage("Unknown flag");
|
|
} else
|
|
break;
|
|
}
|
|
|
|
if (doreplay) {
|
|
replay(logname);
|
|
exit(0);
|
|
}
|
|
if (dosave)
|
|
start_plot_log(logname);
|
|
|
|
printf("Doing first plot\n");
|
|
plot_msg("This is the first plot message\n");
|
|
if (do_plot(x,y1,y2,y3,4) < 0)
|
|
printf("Error - do_plot returned -1!\n");
|
|
|
|
plot_msg("Message between %s and %dnd\n","first",2);
|
|
|
|
/* 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");
|
|
|
|
plot_msg("Message between %s and %drd - first line\n - second line","second",3);
|
|
|
|
/* 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("Doing general vector plot with colors\n");
|
|
if (do_plot_gen(0.0, 0.0, 0.0, 0.0, 1.0, 0, 1,
|
|
Bx1, By1, Bx2, By2, mcols, 4,
|
|
NULL, NULL, NULL, NULL, NULL, 0))
|
|
printf("Error - do_plot_gen returned -1!\n");
|
|
|
|
printf("Doing general symbols and text\n");
|
|
if (do_plot_gen(0.0, 0.0, 0.0, 0.0, 1.0, 0, 1,
|
|
NULL, NULL, NULL, NULL, NULL, 0,
|
|
Bx3, By3, syms, mcols, ptext, 8))
|
|
printf("Error - do_plot_gen returned -1!\n");
|
|
|
|
clear_g(&gg);
|
|
|
|
printf("Doing general vector plot with colors using plot_g\n");
|
|
for (i = 0; i < 4; i++)
|
|
add_vec_g(&gg, Bx1[i], By1[i], Bx2[i], By2[i], mcols[i].rgb);
|
|
do_plot_g(&gg, 0.0, 0.0, 0.0, 0.0, 1.0, 0, 1);
|
|
|
|
printf("Doing general symbols and text using plot_g\n");
|
|
for (i = 0; i < 8; i++)
|
|
add_sym_g(&gg, Bx3[i], By3[i], syms[i], mcols[i].rgb, ptext[i]);
|
|
do_plot_g(&gg, 0.0, 0.0, 0.0, 0.0, 1.0, 0, 1);
|
|
|
|
clear_g(&gg);
|
|
|
|
printf("Doing general lines using plot_g\n");
|
|
start_line_g(&gg, 0.1, 0.1, mcols[0].rgb);
|
|
extend_line_g(&gg, 0.4, 0.2);
|
|
extend_line_g(&gg, 0.15, 0.5);
|
|
start_line_g(&gg, 0.6, 0.3, mcols[1].rgb);
|
|
extend_line_g(&gg, 0.3, 0.6);
|
|
extend_line_g(&gg, 0.7, 0.55);
|
|
do_plot_g(&gg, 0.0, 0.0, 0.0, 0.0, 1.0, 0, 1);
|
|
|
|
clear_g(&gg);
|
|
|
|
printf("We're done\n");
|
|
|
|
if (dosave)
|
|
stop_plot_log();
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* STANDALONE_TEST */
|
|
/* ---------------------------------------------------------------- */
|
|
|