X-Git-Url: http://git.kpe.io/?p=ctsim.git;a=blobdiff_plain;f=libctgraphics%2Fezplot.cpp;h=5a2ec69a34a2700a309722310ee61cc19bfb4e0c;hp=05ca13fbf856b7c07656734183b226065a4a79d2;hb=fd1d136a94a6d20013f38d6a997bdfefad0f5e98;hpb=3fba6928127cd65870bdcd96c8114ad5894247ae diff --git a/libctgraphics/ezplot.cpp b/libctgraphics/ezplot.cpp index 05ca13f..5a2ec69 100644 --- a/libctgraphics/ezplot.cpp +++ b/libctgraphics/ezplot.cpp @@ -6,7 +6,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: ezplot.cpp,v 1.5 2000/07/13 07:03:21 kevin Exp $ +** $Id: ezplot.cpp,v 1.20 2000/12/20 20:08:48 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -23,903 +23,938 @@ ******************************************************************************/ #include "ezplot.h" -#include "algo.h" +#include +#ifdef __GNUWIN32__ +int snprintf (char *, size_t, const char*, ...); +#endif -static int plot (SGP_ID *gid); -static void drawaxis(void); -static void symbol (int sym, double symwidth, double symheight); +// Defaults +static const double TICKRATIO = 0.4; // ratio of minor to major tick lengths +static const int MAXNUMFMT = 15; // maximum length of a numeric format +static const int DEF_CURVE_CLR = C_RED; -/*-------------------------------------*/ -/* GLOBAL variables for EZPLOT & EZSET */ -/*-------------------------------------*/ -bool ezplot_firstcall = TRUE; /* set to false on first call to EZSET or EZPLOT */ -struct ezplot_var ez; /* ezplot variables */ - -/*----------------*/ -/* DEFAULT values */ -/*----------------*/ - -#define TICKRATIO 0.4 /* ratio of minor to major tick lengths */ -#define MAXNUMFMT 15 /* maximum length of a numeric format */ +EZPlotCurve::EZPlotCurve (const double* xData, const double* yData, int n, int color, int linestyle, int symbol, int symfreq, const std::string& legend) + : x(NULL), y(NULL), m_sLegend (legend) +{ + x = new double [n]; + y = new double [n]; + + int copyCount = n * sizeof(double); + memcpy (x, xData, copyCount); + memcpy (y, yData, copyCount); + + m_iPointCount = n; + m_iColor = color; + m_iLineStyle = linestyle; + m_iSymbol = symbol; + m_iSymbolFreq = symfreq; +} -#define DEF_CRTMODE 0 /*GM_HIGHRES*/ /* default crt mode */ -#define DEF_CHARHEIGHT (1./43.) /* default size of characters in NDC */ -#define DEF_CHARWIDTH (1./80.) +EZPlotCurve::~EZPlotCurve () +{ + delete x; + delete y; +} -#define DEF_CURVE_CLR C_YELLOW +void +EZPlot::addCurve (const double *y, int n) +{ + double* x = new double [n]; -/*----------------------------------------------------------------------*/ -/* GLOBAL VARIABLES */ -/*----------------------------------------------------------------------*/ + for (int i = 0; i < n; i++) + x[i] = i; -static -double charwidth, charheight; /* Size of characters in NDC */ + addCurve (x, y, n); + delete x; +} -static -double xp_min, xp_max, - yp_min, yp_max; /* boundry of plot frame in NDC */ -static -double xa_min, xa_max, - ya_min, ya_max; /* extent of axes in NDC */ -static -double xgw_min, xgw_max, - ygw_min, ygw_max; /* boundary of graph in input coords */ -static -double xgn_min, xgn_max, - ygn_min, ygn_max; /* boundy of graph in NDC */ -static -double xt_min, xt_max, - yt_min, yt_max; /* boundary of axis ticks */ -static -double xl_min, xl_max, - yl_min, yl_max; /* boundary of legend box */ +void +EZPlot::addCurve (const float *y, int n) +{ + double* yDouble = new double [n]; -static double title_row; /* y-coord of title row */ + for (int i = 0; i < n; i++) + yDouble[i] = y[i]; -static double xtl_ofs; /* Offset y-coord of x tick labels from axis */ -static double ytl_ofs; /* Offset x-coord of y tick labels from axis */ + addCurve (yDouble, n); + delete yDouble; +} -static double xlbl_row; /* row of x label in world coord */ -static double ylbl_col; /* column of y label in world coord */ -static -double xw_tickinc, yw_tickinc; /* increment between major ticks in WC */ +void +EZPlot::addCurve (const float x[], const double y[], int num) +{ + double* dx = new double [num]; -static -double xn_tickinc, yn_tickinc; /* increment between major ticks in NDC */ + for (int i = 0; i < num; i++) + dx[i] = x[i]; -static int x_nint, y_nint; /* number of intervals along x & y axes */ -static int x_fldwid, x_frac; /* numeric field sizes & number of digits */ -static int y_fldwid, y_frac; /* in fraction of number, used for printf() */ + addCurve (dx, y, num); + delete dx; +} -static double xtl_wid, ytl_wid; /* length of ticks labels in NDC */ -static double tl_height; /* height of tick labels in NDC */ +void +EZPlot::addCurve (const double x[], const float y[], int num) +{ + double* dy = new double [num]; -static char x_numfmt[20]; /* format to print x tick labels */ -static char y_numfmt[20]; /* format to print y tick labels */ + for (int i = 0; i < num; i++) + dy[i] = y[i]; + addCurve (x, dy, num); -/*---------------------------------------------------------------------- - * FUNCTION IDENTICIFATION - * - * Name: EZPLOT - * Programmer: Kevin Rosenberg - * Date: 5-83 Version 1 - * 11-84 Version 2 - * - * SYNOPSIS - * ezplot (x, y, n) - * double x[] x-coordinates of point makeing up a curve - * double y[] y-coordinates of points makeing up a curve - * int n Number of points in curve - * - * DESCRIPTION - * This is a sophisticated plotting program. - * - *----------------------------------------------------------------------*/ + delete dy; +} -SGP_ID -ezplot (float x[], double y[], int num) +void +EZPlot::addCurve (const double x[], const double y[], int num) { - double dx [num]; - - for (int i = 0; i < num; i++) - dx[i] = x[i]; + if (num < 1) + return; - return ezplot (dx, y, num); + EZPlotCurve* pCurve = new EZPlotCurve (x, y, num, o_color, o_linestyle, o_symbol, o_symfreq, c_legend); + m_vecCurves.push_back (pCurve); } -SGP_ID -ezplot (double x[], double y[], int num) +EZPlot::~EZPlot () { - unsigned int size; - SGP_ID gid = NULL; - - if (ez.i_plotimmediate == TRUE) { - plot (&gid); - return (gid); - } - - if (num < 1) - return (NULL); + for (EZPlotCurveIterator i = m_vecCurves.begin(); i != m_vecCurves.end(); i++) + delete *i; +} - if (ezplot_firstcall == TRUE) - ezinit(); +void +EZPlot::clearCurves () +{ + for (EZPlotCurveIterator i = m_vecCurves.begin(); i != m_vecCurves.end(); i++) + delete *i; + m_vecCurves.erase (m_vecCurves.begin(), m_vecCurves.end()); + initPlotSettings(); +} - if (ez.o_unknowncurves == FALSE && ez.i_numcurves >= ez.o_reqcurves) - ezclear (); - if (ez.i_numcurves < MAXCURVES && - (ez.o_unknowncurves == TRUE || ez.i_numcurves < ez.o_reqcurves)) { - size = num * sizeof(double); - ez.curve[ez.i_numcurves].x = new double [size]; - ez.curve[ez.i_numcurves].y = new double [size]; - for (int i = 0; i < num; i++) { - ez.curve[ez.i_numcurves].x[i] = x[i]; - ez.curve[ez.i_numcurves].y[i] = y[i]; - } - ez.curve[ez.i_numcurves].numpts = num; - ez.curve[ez.i_numcurves].color = ez.o_color; - ez.curve[ez.i_numcurves].linestyle = ez.o_linestyle; - ez.curve[ez.i_numcurves].symbol = ez.o_symbol; - ez.curve[ez.i_numcurves].symfreq = ez.o_symfreq; - strncpy (ez.curve[ez.i_numcurves].legend, ez.c_legend, MAXLEGEND); - ++ez.i_numcurves; - } - - if (ez.o_unknowncurves == FALSE && ez.i_numcurves >= ez.o_reqcurves) { - plot (&gid); - ezclear (); - } +EZPlot::EZPlot (SGP& sgp) + : rSGP (sgp) +{ + initPlotSettings(); +} - return (gid); +void +EZPlot::initPlotSettings () +{ + charheight = rSGP.getCharHeight(); + charwidth = rSGP.getCharWidth(); + + c_xlabel = ""; + c_ylabel = ""; + c_title = ""; + c_legend = ""; + + o_xporigin = 0.0; + o_yporigin = 0.0; + o_xlength = 1.0; + o_ylength = 1.0; + + o_xaxis = LINEAR; + o_yaxis = LINEAR; + + o_grid = FALSE; + o_box = FALSE; + + o_xmajortick = 10; + o_ymajortick = 8; + o_xminortick = 4; + o_yminortick = 4; + + o_color = DEF_CURVE_CLR; + o_symfreq = 1; + o_symbol = -1; + o_linestyle = SGP::LS_SOLID; + + o_xtlabel = TRUE; + o_ytlabel = TRUE; + o_xticks = BELOW; + o_yticks = LEFT; + + o_legendbox = INSIDE; + o_tag = FALSE; + + s_xtitle = FALSE; + s_ytitle = FALSE; + s_xcross = FALSE; + s_ycross = FALSE; + s_lxfrac = FALSE; + s_lyfrac = FALSE; + s_xlegend = FALSE; + s_ylegend = FALSE; + s_textsize = FALSE; + + clr_axis = C_BLACK; // set fixed colors + clr_title = C_CYAN; + clr_label = C_CYAN; + clr_legend = C_RED; + clr_number = C_GREEN; + clr_grid = C_LTGRAY; } /* NAME - * plot INTERNAL: Plots all curves collected by ezplot() + * plot Plots all curves collected by addCurves () * * SYNOPSIS * plot() * * DESCRIPTION - * This routine plots the curves that have stored by ezplot(). - * - * CALLED BY - * EZPLOT() only + * This routine plots the curves that have stored by addCurves(). * * CALLS - * drawaxis() & make_numfmt() + * drawAxes() & make_numfmt() */ -static int plot (SGP_ID *gid) +void +EZPlot::plot () { - double xmin, xmax; /* extend of curves in world coord */ - double ymin, ymax; - double x_added_ticks; /* number of tick spaces added to axis */ - double y_added_ticks; - double symwidth, symheight; /* size of symbol in NDC */ - double leg_width, leg_height; /* size of legend box */ - int num_leg; /* number of legend titles */ - int max_leg; /* longest legend in characters */ - int i, j, ip, ic, n; - - if (ez.i_numcurves <= 0) - return (FALSE); - - if (ez.o_ustart == FALSE && *gid == NULL) { - *gid = sgp2_init (0, 0, "Ezplot"); - } - - if (ez.s_textsize == TRUE) - charheight = ez.v_textsize; - else - charheight = DEF_CHARHEIGHT; - - gp_set_aspect (CRTDEV, 1.0); + if (m_vecCurves.size() <= 0) + return; + + rSGP.setWindow (0., 0., 1., 1.); + + if (s_textsize == TRUE) { + charheight = v_textsize; + charwidth = rSGP.getCharWidth(); + } else { + charheight = rSGP.getCharHeight(); + charwidth = rSGP.getCharWidth(); + } + + const EZPlotCurve& firstCurve = *m_vecCurves[0]; + double xmin = firstCurve.x[0]; // extent of curves in world coord + double xmax = xmin; + double ymin = firstCurve.y[0]; + double ymax = ymin; + + for (EZPlotCurveConstIterator iterCurve = m_vecCurves.begin(); iterCurve != m_vecCurves.end(); iterCurve++) { + const EZPlotCurve& curve = **iterCurve; - xmin = xmax = ez.curve[0].x[0]; - ymin = ymax = ez.curve[0].y[0]; - - for (ic = 0; ic < ez.i_numcurves; ic++) { - for (ip = 0; ip < ez.curve[ic].numpts; ip++) { - if (ez.curve[ic].x[ip] > xmax) - xmax = ez.curve[ic].x[ip]; - else if (ez.curve[ic].x[ip] < xmin) - xmin = ez.curve[ic].x[ip]; - if (ez.curve[ic].y[ip] > ymax) - ymax = ez.curve[ic].y[ip]; - else if (ez.curve[ic].y[ip] < ymin) - ymin = ez.curve[ic].y[ip]; - } + for (int ip = 0; ip < curve.m_iPointCount; ip++) { + if (curve.x[ip] > xmax) + xmax = curve.x[ip]; + else if (curve.x[ip] < xmin) + xmin = curve.x[ip]; + if (curve.y[ip] > ymax) + ymax = curve.y[ip]; + else if (curve.y[ip] < ymin) + ymin = curve.y[ip]; } + } + + // extend graph limits for user defined axis cross positions + if (s_xcross == TRUE) { + if (v_xcross < xmin) + xmin = v_xcross; + else if (v_xcross > xmax) + xmax = v_xcross; + } - /* extend graph limits for user defined axis cross positions */ + if (s_ycross == TRUE) { + if (v_ycross < ymin) + ymin = v_ycross; + else if (v_ycross > ymax) + ymax = v_ycross; + } - if (ez.s_xcross == TRUE) - { - if (ez.v_xcross < xmin) - xmin = ez.v_xcross; - else if (ez.v_xcross > xmax) - xmax = ez.v_xcross; - } + // find nice endpoints for axes + if (! axis_scale (xmin, xmax, o_xmajortick - 1, &xgw_min, &xgw_max, &x_nint) || ! axis_scale (ymin, ymax, o_ymajortick - 1, &ygw_min, &ygw_max, &y_nint)) + return; - if (ez.s_ycross == TRUE) - { - if (ez.v_ycross < ymin) - ymin = ez.v_ycross; - else if (ez.v_ycross > ymax) - ymax = ez.v_ycross; - } + // check if user set x-axis extents + if (s_xmin == TRUE) { + xgw_min = v_xmin; + x_nint = o_xmajortick - 1; + } + if (s_xmax == TRUE) { + xgw_max = v_xmax; + x_nint = o_xmajortick - 1; + } + + // check if user set y-axis extents + if (s_ymin == TRUE) { + ygw_min = v_ymin; + y_nint = o_ymajortick - 1; + } + if (s_ymax == TRUE) { + ygw_max = v_ymax; + y_nint = o_ymajortick - 1; + } - /* find nice endpoints for axes */ - - axis_scale (xmin, xmax, ez.o_xmajortick - 1, &xgw_min, &xgw_max, &x_nint); - axis_scale (ymin, ymax, ez.o_ymajortick - 1, &ygw_min, &ygw_max, &y_nint); + // calculate increment between major axis in world coordinates + xw_tickinc = (xgw_max - xgw_min) / x_nint; + yw_tickinc = (ygw_max - ygw_min) / y_nint; - /* check if user set x-axis extents */ + // we have now calcuated xgw_min, xyw_max, ygw_min, & ygw_max + + // set the number of decimal point to users' setting or default + // Two formats for numbers: Fixed: -nnn.f and Exponent: -n.fffE+eee + if (s_lxfrac == TRUE) + x_frac = v_lxfrac; + else + x_frac = -1; - if (ez.s_xmin == TRUE) { - xgw_min = ez.v_xmin; - x_nint = ez.o_xmajortick - 1; - } - if (ez.s_xmax == TRUE) { - xgw_max = ez.v_xmax; - x_nint = ez.o_xmajortick - 1; - } + if (s_lyfrac == TRUE) + y_frac = v_lyfrac; + else + y_frac = -1; - /* check if user set y-axis extents */ + make_numfmt (x_numfmt, &x_fldwid, &x_frac, xgw_min, xgw_max, x_nint); + make_numfmt (y_numfmt, &y_fldwid, &y_frac, ygw_min, ygw_max, y_nint); - if (ez.s_ymin == TRUE) { - ygw_min = ez.v_ymin; - y_nint = ez.o_ymajortick - 1; - } - if (ez.s_ymax == TRUE) { - ygw_max = ez.v_ymax; - y_nint = ez.o_ymajortick - 1; + xtl_wid = x_fldwid * charwidth; // calc size of tick labels + ytl_wid = y_fldwid * charwidth; + tl_height = charheight; + + // calculate the extent of the plot frame + xp_min = o_xporigin; + yp_min = o_yporigin; + xp_max = xp_min + o_xlength; + yp_max = yp_min + o_ylength; + + xp_min = clamp (xp_min, 0., 1.); + xp_max = clamp (xp_max, 0., 1.); + yp_min = clamp (yp_min, 0., 1.); + yp_max = clamp (yp_max, 0., 1.); + + xa_min = xp_min; // extent of axes + xa_max = xp_max; + ya_min = yp_min; + ya_max = yp_max; + + // adjust frame for title + if (c_title.length() > 0) + ya_max -= 2 * charheight; + title_row = ya_max + 2 * charheight; + + // calculate legend box boundaries + int max_leg = 0; // longest legend in characters + int num_leg = 0; // number of legend titles + for (EZPlotCurveConstIterator iterCurve2 = m_vecCurves.begin(); iterCurve2 != m_vecCurves.end(); iterCurve2++) { + const EZPlotCurve& curve = **iterCurve2; + int nLegend = curve.m_sLegend.length(); + if (nLegend > 0) { + ++num_leg; + if (nLegend > max_leg) + nLegend = max_leg; } + } + + if (num_leg > 0 && o_legendbox != NOLEGEND) { + double leg_width = (max_leg + 2) * charwidth; // size of legend box + double leg_height = num_leg * 3 * charheight; - /* calculate increment between major axis in world coordinates */ - - xw_tickinc = (xgw_max - xgw_min) / x_nint; - yw_tickinc = (ygw_max - ygw_min) / y_nint; - - /* we have now calcuated xgw_min, xyw_max, ygw_min, & ygw_max */ - - /* set the number of decimal point to users' setting or default */ - /* Two formats for numbers - Fixed: -nnn.f - Exponent: -n.fffE+eee - */ - - if (ez.s_lxfrac == TRUE) - x_frac = ez.v_lxfrac; - else - x_frac = -1; + if (s_xlegend == TRUE) + xl_max = v_xlegend; + else { + xl_max = xa_max; + if (o_legendbox == OUTSIDE) + xa_max -= (leg_width + 0.5 * charwidth); + } + xl_min = xl_max - leg_width; - if (ez.s_lyfrac == TRUE) - y_frac = ez.v_lyfrac; + if (s_ylegend == TRUE) + yl_max = v_ylegend; else - y_frac = -1; - - make_numfmt (x_numfmt, &x_fldwid, &x_frac, xgw_min, xgw_max, x_nint); - make_numfmt (y_numfmt, &y_fldwid, &y_frac, ygw_min, ygw_max, y_nint); - - xtl_wid = x_fldwid * charwidth; /* calc size of tick labels */ - ytl_wid = y_fldwid * charwidth; - tl_height = charheight; - - /* calculate the extent of the plot frame */ - - xp_min = ez.o_xporigin; - yp_min = ez.o_yporigin; - xp_max = xp_min + ez.o_xlength; - yp_max = yp_min + ez.o_ylength; - - xp_min = clamp (xp_min, 0., 1.); - xp_max = clamp (xp_max, 0., 1.); - yp_min = clamp (yp_min, 0., 1.); - yp_max = clamp (yp_max, 0., 1.); - - xa_min = xp_min; /* extent of axes */ - xa_max = xp_max; - ya_min = yp_min; - ya_max = yp_max; - - /* adjust frame for title */ - - if (strlen(ez.c_title) != 0) - ya_max -= 2.5 * charheight; - title_row = ya_max + 0.5 * charheight; + yl_max = ya_max; - /* calculate legend box boundaries */ - - max_leg = 0; /* longest legend in characters */ - num_leg = 0; /* number of legend titles */ - for (i = 0; i < ez.i_numcurves; i++) - if ((n = strlen(ez.curve[i].legend)) > 0) { - ++num_leg; - max_leg = max(max_leg, n); - } - - if (num_leg > 0 && ez.o_legendbox != NOLEGEND) { - leg_width = (max_leg + 2) * charwidth; - leg_height = num_leg * 3 * charheight; - - if (ez.s_xlegend == TRUE) - xl_max = ez.v_xlegend; - else { - xl_max = xa_max; - if (ez.o_legendbox == OUTSIDE) - xa_max -= (leg_width + 0.5 * charwidth); - } - xl_min = xl_max - leg_width; - - if (ez.s_ylegend == TRUE) - yl_max = ez.v_ylegend; - else - yl_max = ya_max; - - yl_min = yl_max - leg_height; - - sgp2_window (xl_min, yl_min, xl_max, yl_max); - sgp2_viewport (xl_min, yl_min, xl_max, yl_max); - - sgp2_color (ez.clr_legend); - sgp2_draw_rect (xl_min, yl_min, xl_max, yl_max); - - n = 0; /* current legend position */ - for (i = 0; i < ez.i_numcurves; i++) { - double xmin, xmax, xinc, y; - - if (strlen(ez.curve[i].legend) == 0) - continue; - - xmin = xl_min + 1.0 * charwidth; - xmax = xl_max - 1.0 * charwidth; - y = yl_max - (2.0 + n * 3) * charheight; - - sgp2_move_abs (xmin, y + 0.5 * charheight); - sgp2_draw_text (ez.curve[i].legend); - sgp2_color (ez.curve[i].color); - if (ez.curve[i].linestyle != LS_NOLINE) { - sgp2_line_style (ez.curve[i].linestyle); - sgp2_move_abs (xmin, y); - sgp2_line_abs (xmax, y); - } - if (ez.curve[i].symbol > 0) { - xinc = (xmax - xmin) / (5 - 1); - sgp2_line_style (LS_SOLID); - for (j = 0; j < 5; j++) { - sgp2_move_abs (xmin + j * xinc, y); - symbol(ez.curve[i].symbol, - 0.5 * charwidth, 0.5 * charheight); - } - } - ++n; /* move to next legend position */ - } - } /* end legend printing */ - - /* calculate the extent of the axes */ - - /*-------------------------*/ - /* adjust frame for labels */ - /*-------------------------*/ - - /* x-label */ - - if (strlen(ez.c_xlabel) > 0) - ya_min += 3.0 * charheight; - xlbl_row = xp_min; /* put x-label on bottom of plot frame */ - - /* y-label */ + yl_min = yl_max - leg_height; - if (strlen(ez.c_ylabel) > 0) - xa_min += 3.0 * charwidth; /* reverse charsize because writing */ - /* text sideways */ - ylbl_col = xp_min + 2 * charwidth; + rSGP.setColor (clr_legend); + rSGP.drawRect (xl_min, yl_min, xl_max, yl_max); - /*------------------------------*/ - /* adjust frame for tick labels */ - /*------------------------------*/ - - /* calc offset of tick labels from axes */ - - if (ez.o_xaxis == NOAXIS || ez.o_xtlabel == FALSE) - xtl_ofs = 0.0; - else if (ez.o_xticks == BELOW) - xtl_ofs = -2.5 * charheight; - else if (ez.o_xticks == ABOVE) - xtl_ofs = 1.5 * charheight; - - if (ez.o_yaxis == NOAXIS || ez.o_ytlabel == FALSE) - ytl_ofs = 0.0; - else if (ez.o_yticks == LEFT) - ytl_ofs = -(1 + y_fldwid) * charwidth; - else if (ez.o_yticks == RIGHT) - ytl_ofs = 1.5 * charwidth; - - /* see if need to shrink axis extents and/or tick extents */ + int iLegend = 0; // current legend position + for (EZPlotCurveIterator iterCurve = m_vecCurves.begin(); iterCurve != m_vecCurves.end(); iterCurve++) { + const EZPlotCurve& curve = **iterCurve; + + if (curve.m_sLegend.length() == 0) + continue; - if (xtl_ofs != 0.0 && ez.s_ycross == FALSE) { - if (ez.o_xticks == BELOW) { - ya_min += 2.5 * charheight; - yt_min = ya_min; - } else if (ez.o_xticks == ABOVE) { - ya_min += 0.0; - yt_min = ya_min + 2.5 * charheight; + double xmin = xl_min + 1.0 * charwidth; + double xmax = xl_max - 1.0 * charwidth; + double y = yl_max - (2.0 + iLegend * 3) * charheight; + + rSGP.moveAbs (xmin, y + 0.5 * charheight); + rSGP.drawText (curve.m_sLegend); + rSGP.setColor (curve.m_iColor); + if (curve.m_iLineStyle != SGP::LS_NOLINE) { + rSGP.setLineStyle (curve.m_iLineStyle); + rSGP.moveAbs (xmin, y); + rSGP.lineAbs (xmax, y); } - } else /* noaxis, no t-labels, or user set cross */ - yt_min = ya_min; - - if (ytl_ofs != 0.0 && ez.s_xcross == FALSE) { - if (ez.o_yticks == LEFT) { - xa_min += (1 + y_fldwid) * charwidth; - xt_min = xa_min; - } else if (ez.o_yticks == RIGHT) { - xa_min += 0.0; - xt_min = xa_min + ytl_ofs + y_fldwid * charwidth; + if (curve.m_iSymbol > 0) { + double xinc = (xmax - xmin) / (5 - 1); + rSGP.setLineStyle (SGP::LS_SOLID); + for (int j = 0; j < 5; j++) { + rSGP.moveAbs (xmin + j * xinc, y); + symbol(curve.m_iSymbol, 0.5 * charwidth, 0.5 * charheight); + } } - } else - xt_min = xa_min; - - xt_max = xa_max; - yt_max = ya_max; - - /* decrease size of graph, if necessary, to accommadate space */ - /* between axis boundary and boundary of ticks */ - - x_added_ticks = -1; - y_added_ticks = -1; - - if (ez.o_xaxis == NOAXIS || ez.o_xtlabel == FALSE) - x_added_ticks = 0; - if (ez.o_yaxis == NOAXIS || ez.o_ytlabel == FALSE) - y_added_ticks = 0; - - if (ez.o_grid == TRUE) { - if (x_added_ticks < 0) - x_added_ticks = 2; - if (y_added_ticks < 0) - y_added_ticks = 2; + ++iLegend; // move to next legend position } - + } // end legend printing + + // calculate the extent of the axes + + /*-------------------------*/ + /* adjust frame for labels */ + /*-------------------------*/ + + // X-Label + if (c_xlabel.length() > 0) + ya_min += 3.0 * charheight; + xlbl_row = xp_min; // put x-label on bottom of plot frame + + // Y-Label + if (c_ylabel.length() > 0) + xa_min += 3.0 * charwidth; // reverse rSGP.setTextSize because writing text sideways + ylbl_col = xp_min + 2 * charwidth; + + /*------------------------------*/ + /* adjust frame for tick labels */ + /*------------------------------*/ + + // Calc offset of tick labels from axes + if (o_xaxis == NOAXIS || o_xtlabel == FALSE) + xtl_ofs = 0.0; + else if (o_xticks == BELOW) + xtl_ofs = -1.5 * charheight; // kr + else if (o_xticks == ABOVE) + xtl_ofs = 1.5 * charheight; + + if (o_yaxis == NOAXIS || o_ytlabel == FALSE) + ytl_ofs = 0.0; + else if (o_yticks == LEFT) + ytl_ofs = -(1 + y_fldwid) * charwidth; + else if (o_yticks == RIGHT) + ytl_ofs = 1.5 * charwidth; + + xt_min = xa_min; + yt_min = ya_min; + xt_max = xa_max; + yt_max = ya_max; + + // see if need to shrink axis extents and/or tick extents + if (xtl_ofs != 0.0 && s_ycross == FALSE) { + if (o_xticks == BELOW) { + ya_min += 2.5 * charheight; + yt_min = ya_min; + } else if (o_xticks == ABOVE) { + ya_min += 0.0; + yt_min = ya_min + 2.5 * charheight; + } + } else // noaxis, no t-labels, or user set cross + yt_min = ya_min; + + if (ytl_ofs != 0.0 && s_xcross == FALSE) { + if (o_yticks == LEFT) { + xa_min += (1 + y_fldwid) * charwidth; + xt_min = xa_min; + } else if (o_yticks == RIGHT) { + xa_min += 0.0; + xt_min = xa_min + ytl_ofs + y_fldwid * charwidth; + } + } else + xt_min = xa_min; + + // decrease size of graph, if necessary, to accommadate space + // between axis boundary and boundary of ticks + double x_added_ticks = -1; // number of tick spaces added to axis + double y_added_ticks = -1; + if (o_xaxis == NOAXIS || o_xtlabel == FALSE) + x_added_ticks = 0; + if (o_yaxis == NOAXIS || o_ytlabel == FALSE) + y_added_ticks = 0; + + if (o_grid == TRUE) { if (x_added_ticks < 0) - { - if (ez.o_yticks == LEFT || ez.s_ycross) - x_added_ticks = 1; - else - x_added_ticks = 2; - } - + x_added_ticks = 2; if (y_added_ticks < 0) - { - if (ez.o_xticks == BELOW || ez.s_xcross) - y_added_ticks = 1; - else - y_added_ticks = 2; + y_added_ticks = 2; + } + + if (x_added_ticks < 0) { + if (o_yticks == LEFT || s_ycross) + x_added_ticks = 1; + else + x_added_ticks = 2; + } + + if (y_added_ticks < 0) { + if (o_xticks == BELOW || s_xcross) + y_added_ticks = 1; + else + y_added_ticks = 2; + } + + xn_tickinc = (xt_max - xt_min) / (x_nint + x_added_ticks); + yn_tickinc = (yt_max - yt_min) / (y_nint + y_added_ticks); + + xt_min += 0.5 * x_added_ticks * xn_tickinc; + xt_max -= 0.5 * x_added_ticks * xn_tickinc; + yt_min += 0.5 * y_added_ticks * yn_tickinc; + yt_max -= 0.5 * y_added_ticks * yn_tickinc; + + xgn_min = xt_min; + xgn_max = xt_max; + ygn_min = yt_min; + ygn_max = yt_max; + + //------------------------------------------------------------------------ + + m_xWorldScale = (xgn_max - xgn_min) / (xgw_max - xgw_min); + m_yWorldScale = (ygn_max - ygn_min) / (ygw_max - ygw_min); + + // PLOT CURVES + + rSGP.setLineStyle (SGP::LS_SOLID); + drawAxes(); + + // size of symbol in NDC + double symwidth = charwidth; + double symheight = charheight; + + for (EZPlotCurveIterator iterCurve3 = m_vecCurves.begin(); iterCurve3 != m_vecCurves.end(); iterCurve3++) { + const EZPlotCurve& curve = **iterCurve3; + + rSGP.setColor (curve.m_iColor); + + if (curve.m_iLineStyle != SGP::LS_NOLINE) { + rSGP.setLineStyle (curve.m_iLineStyle); + double x = convertWorldToNDC_X (curve.x[0]); + double y = convertWorldToNDC_Y (curve.y[0]); + rSGP.moveAbs (x, y); + for (int i = 1; i < curve.m_iPointCount; i++) { + x = convertWorldToNDC_X (curve.x[i]); + y = convertWorldToNDC_Y (curve.y[i]); + rSGP.lineAbs (x, y); } + } + if (curve.m_iSymbol > 0) { + rSGP.setLineStyle (SGP::LS_SOLID); + double x = convertWorldToNDC_X (curve.x[0]); + double y = convertWorldToNDC_Y (curve.y[0]); + rSGP.moveAbs (x, y); + symbol (curve.m_iSymbol, symwidth, symheight); + for (int i = 1; i < curve.m_iPointCount; i++) + if (i % curve.m_iSymbolFreq == 0 || i == curve.m_iPointCount - 1) { + x = convertWorldToNDC_X (curve.x[i]); + y = convertWorldToNDC_Y (curve.y[i]); + rSGP.moveAbs (x, y); + symbol (curve.m_iSymbol, symwidth, symheight); + } + } + } - xn_tickinc = (xt_max - xt_min) / (x_nint + x_added_ticks); - yn_tickinc = (yt_max - yt_min) / (y_nint + y_added_ticks); - - xt_min += 0.5 * x_added_ticks * xn_tickinc; - xt_max -= 0.5 * x_added_ticks * xn_tickinc; - yt_min += 0.5 * y_added_ticks * yn_tickinc; - yt_max -= 0.5 * y_added_ticks * yn_tickinc; - - xgn_min = xt_min; - xgn_max = xt_max; - ygn_min = yt_min; - ygn_max = yt_max; - - /*---------------------------------------------------------------------------*/ - - /* PLOT CURVES */ - - sgp2_line_style (LS_SOLID); - drawaxis(); - - /* Convert WC in graph boundary to axis boundary */ - { - double xmin, xmax, ymin, ymax; - - sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max); /* Graph boundary */ - sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max); - - ndc_to_wc (xa_min, ya_min, &xmin, &ymin); /* calc WC of axis */ - ndc_to_wc (xa_max, ya_max, &xmax, &ymax); /* boundaries */ - - sgp2_window (xmin, ymin, xmax, ymax); /* Set window to axis */ - sgp2_viewport (xa_min, ya_min, xa_max, ya_max); /* boundaries */ - } - - symwidth = charwidth * (xgw_max - xgw_min); - symheight = charheight * (ygw_max - ygw_min); - - for (ic = 0; ic < ez.i_numcurves; ic++) { - sgp2_color (ez.curve[ic].color); - if (ez.curve[ic].linestyle != LS_NOLINE) { - sgp2_line_style (ez.curve[ic].linestyle); - sgp2_polyline_abs (ez.curve[ic].x, ez.curve[ic].y, ez.curve[ic].numpts); - } - if (ez.curve[ic].symbol > 0) { - sgp2_line_style(LS_SOLID); - sgp2_move_abs (ez.curve[ic].x[0], ez.curve[ic].y[0]); - symbol (ez.curve[ic].symbol, symwidth, symheight); - for (i = 1; i < ez.curve[ic].numpts; i++) - if (i % ez.curve[ic].symfreq == 0 || i == ez.curve[ic].numpts - 1) { - sgp2_move_abs (ez.curve[ic].x[i], ez.curve[ic].y[i]); - symbol (ez.curve[ic].symbol, symwidth, symheight); - } - } - } - - if (ez.o_ufinish == FALSE) - termgrf2 (); - - return (TRUE); } /* NAME - * drawaxis INTERNAL routine to draw axis & label them + * drawAxes INTERNAL routine to draw axis & label them * * SYNOPSIS - * drawaxis() + * drawAxes() */ -static void drawaxis(void) + +void +EZPlot::drawAxes() { - double xticklen = 0, yticklen = 0; /* length of ticks in NDC */ - double minorinc; /* increment between minor axes */ - double xaxispos, yaxispos; /* crossing of axes */ - double x, y, x2, y2; - bool axis_near; /* TRUE if axis too close to print t-label */ - int i, j; - char str[100]; - char *numstr; - - charsize (charwidth, charheight); - settextclr (1, -1); - - if (ez.o_xticks == ABOVE) - xticklen = charheight; - else if (ez.o_xticks == BELOW) - xticklen = -charheight; - - if (ez.o_yticks == RIGHT) - yticklen = charwidth; - else if (ez.o_yticks == LEFT) - yticklen = -charwidth; - - sgp2_window (xp_min, yp_min, xp_max, yp_max); - sgp2_viewport (xp_min, yp_min, xp_max, yp_max); - - if (strlen (ez.c_title) != 0) { - sgp2_move_abs (xa_min + (xa_max-xa_min)/2 - strlen(ez.c_title)*charwidth, title_row); - charsize (charwidth * 2.0, charheight * 2.0); - settextclr (ez.clr_title, -1); - sgp2_draw_text (ez.c_title); - charsize (charwidth, charheight); + double xticklen = 0, yticklen = 0; // length of ticks in NDC + double minorinc; // increment between minor axes + double xaxispos, yaxispos; // crossing of axes + double x, y, x2, y2; + bool axis_near; // TRUE if axis too close to print t-label + int i, j; + char str[256]; + char *numstr; + + rSGP.setTextSize (charheight); + rSGP.setTextColor (1, -1); + + if (o_xticks == ABOVE) + xticklen = charheight; + else if (o_xticks == BELOW) + xticklen = -charheight; + + if (o_yticks == RIGHT) + yticklen = charwidth; + else if (o_yticks == LEFT) + yticklen = -charwidth; + + if (c_title.length() > 0) { + double wText, hText; + rSGP.setTextSize (charheight * 2.0); + rSGP.getTextExtent (c_title.c_str(), &wText, &hText); + rSGP.moveAbs (xa_min + (xa_max-xa_min)/2 - wText/2, title_row); + rSGP.setTextColor (clr_title, -1); + rSGP.drawText (c_title); + rSGP.setTextSize (charheight); + } + + if (o_grid == TRUE || o_box == TRUE) { + rSGP.setColor (clr_axis); + rSGP.moveAbs (xa_min, ya_min); + rSGP.lineAbs (xa_max, ya_min); + rSGP.lineAbs (xa_max, ya_max); + rSGP.lineAbs (xa_min, ya_max); + rSGP.lineAbs (xa_min, ya_min); + } + + // calculate position of axes + + // x-axis + if (s_ycross == TRUE) { // convert users' world-coord + xaxispos = convertWorldToNDC_Y (v_ycross);// axis to its position in NDC + x = convertWorldToNDC_X (xgw_min); + } else + xaxispos = ya_min; + + // y-axis + if (s_xcross == TRUE) { // convert users' world-coord + yaxispos = convertWorldToNDC_X (v_xcross);// axis to its NDC position + y = convertWorldToNDC_Y (ygw_min); + } else + yaxispos = xa_min; + + /*-------------*/ + /* draw x-axis */ + /*-------------*/ + + if (o_xaxis == LINEAR) { + // draw axis line + + rSGP.setColor (clr_axis); + if (o_tag && !o_grid && !o_box && s_xcross) { + rSGP.moveAbs (xa_min, xaxispos - charheight); + rSGP.lineAbs (xa_min, xaxispos + charheight); } - - if (ez.o_grid == TRUE || ez.o_box == TRUE) { - sgp2_color (ez.clr_axis); - sgp2_move_abs (xa_min, ya_min); - sgp2_line_abs (xa_max, ya_min); - sgp2_line_abs (xa_max, ya_max); - sgp2_line_abs (xa_min, ya_max); - sgp2_line_abs (xa_min, ya_min); + rSGP.moveAbs (xa_min, xaxispos); + rSGP.lineAbs (xa_max, xaxispos); + if (o_tag && !o_grid && !o_box) { + rSGP.moveAbs (xa_max, xaxispos - charheight); + rSGP.lineAbs (xa_max, xaxispos + charheight); } - - /* calculate position of axes */ - - /* x-axis */ - if (ez.s_ycross == TRUE) { /* convert users' world-coord */ - xaxispos = ez.v_ycross; /* axis to its position in NDC */ - sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max); - sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max); - x = xgw_min; - wc_to_ndc (x, xaxispos, &x, &xaxispos); - } else - xaxispos = ya_min; - - /* y-axis */ - if (ez.s_xcross == TRUE) { /* convert users' world-coord */ - yaxispos = ez.v_xcross; /* axis to its NDC position */ - sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max); - sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max); - y = ygw_min; - wc_to_ndc (yaxispos, y, &yaxispos, &y); - } else - yaxispos = xa_min; - - /*-------------*/ - /* draw x-axis */ - /*-------------*/ - - if (ez.o_xaxis == LINEAR) { - sgp2_window (xp_min, yp_min, xp_max, yp_max); - sgp2_viewport (xp_min, yp_min, xp_max, yp_max); - - /* draw axis line */ - - sgp2_color (ez.clr_axis); - if (ez.o_tag && !ez.o_grid && !ez.o_box && ez.s_xcross) { - sgp2_move_abs (xa_min, xaxispos - charheight); - sgp2_line_abs (xa_min, xaxispos + charheight); - } - sgp2_move_abs (xa_min, xaxispos); - sgp2_line_abs (xa_max, xaxispos); - if (ez.o_tag && !ez.o_grid && !ez.o_box) { - sgp2_move_abs (xa_max, xaxispos - charheight); - sgp2_line_abs (xa_max, xaxispos + charheight); - } - - if (ez.o_grid == TRUE) { - sgp2_color (ez.clr_grid); - for (i = 0; i <= x_nint; i++) { - sgp2_move_abs (xt_min + xn_tickinc * i, ya_max); - sgp2_line_abs (xt_min + xn_tickinc * i, ya_min); - } + + if (o_grid == TRUE) { + rSGP.setColor (clr_grid); + for (i = 0; i <= x_nint; i++) { + rSGP.moveAbs (xt_min + xn_tickinc * i, ya_max); + rSGP.lineAbs (xt_min + xn_tickinc * i, ya_min); + } + } + rSGP.moveAbs (xa_min + (xa_max-xa_min)/2 - c_xlabel.length()*charwidth, xlbl_row); + rSGP.setTextSize (charheight * 2.0); + rSGP.setTextColor (clr_label, -1); + rSGP.drawText (c_xlabel); + rSGP.setTextSize (charheight); + minorinc = xn_tickinc / (o_xminortick + 1); + + for (i = 0; i <= x_nint; i++) { + x = xt_min + xn_tickinc * i; + rSGP.setColor (clr_axis); + rSGP.moveAbs (x, xaxispos); + rSGP.lineAbs (x, xaxispos + xticklen); + if (i != x_nint) + for (j = 1; j <= o_xminortick; j++) { + x2 = x + minorinc * j; + rSGP.moveAbs (x2, xaxispos); + rSGP.lineAbs (x2, xaxispos + TICKRATIO * xticklen); } - sgp2_move_abs (xa_min + (xa_max-xa_min)/2 - strlen(ez.c_xlabel)*charwidth, xlbl_row); - charsize (charwidth * 2.0, charheight * 2.0); - settextclr (ez.clr_label, -1); - sgp2_draw_text (ez.c_xlabel); - charsize (charwidth, charheight); - minorinc = xn_tickinc / (ez.o_xminortick + 1); - - for (i = 0; i <= x_nint; i++) { - x = xt_min + xn_tickinc * i; - sgp2_color (ez.clr_axis); - sgp2_move_abs (x, xaxispos); - sgp2_line_abs (x, xaxispos + xticklen); - if (i != x_nint) - for (j = 1; j <= ez.o_xminortick; j++) { - x2 = x + minorinc * j; - sgp2_move_abs (x2, xaxispos); - sgp2_line_abs (x2, xaxispos + TICKRATIO * xticklen); - } - axis_near = FALSE; - if (xaxispos + xtl_ofs > ya_min && ez.o_yaxis != NOAXIS) { - double xw, x, y, d; - - xw = xgw_min + i * xw_tickinc; - sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max); - sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max); - wc_to_ndc (xw, y, &x, &y); - sgp2_window (xp_min, yp_min, xp_max, yp_max); - sgp2_viewport (xp_min, yp_min, xp_max, yp_max); - d = x - yaxispos; - if (ez.o_yticks == RIGHT && d >= 0 && d < 0.9 * xn_tickinc) - axis_near = TRUE; - if (ez.o_yticks == LEFT && d <= 0 && d > -0.9 * xn_tickinc) - axis_near = TRUE; - } - - if (ez.o_xtlabel == TRUE && axis_near == FALSE) { - snprintf (str, sizeof(str), x_numfmt, xgw_min + xw_tickinc * i); - numstr = str_skip_head (str, " "); - sgp2_move_abs (x-strlen(numstr)*charwidth/2,xaxispos + xtl_ofs); - settextclr (ez.clr_number, -1); - sgp2_draw_text (numstr); - } + axis_near = FALSE; + if (xaxispos + xtl_ofs > ya_min && o_yaxis != NOAXIS) { + double xw = xgw_min + i * xw_tickinc; + double x = convertWorldToNDC_X (xw); + double d = x - yaxispos; + if (o_yticks == RIGHT && d >= 0 && d < 0.9 * xn_tickinc) + axis_near = TRUE; + if (o_yticks == LEFT && d <= 0 && d > -0.9 * xn_tickinc) + axis_near = TRUE; + } + + if (o_xtlabel == TRUE && axis_near == FALSE) { + snprintf (str, sizeof(str), x_numfmt, xgw_min + xw_tickinc * i); + numstr = str_skip_head (str, " "); + rSGP.moveAbs (x-strlen(numstr)*charwidth/2, xaxispos + xtl_ofs); + rSGP.setTextColor (clr_number, -1); + rSGP.drawText (numstr); + } + } + } // X - Axis + + + /*--------*/ + /* y-axis */ + /*--------*/ + + if (o_yaxis == LINEAR) { + + rSGP.setColor (clr_axis); + if (o_tag && !o_grid && !o_box && s_ycross) { + rSGP.moveAbs (yaxispos - charwidth, ya_min); + rSGP.lineAbs (yaxispos + charwidth, ya_min); + } + rSGP.moveAbs (yaxispos, ya_min); + rSGP.lineAbs (yaxispos, ya_max); + if (o_tag && !o_grid && !o_box) { + rSGP.moveAbs (yaxispos - charwidth, ya_max); + rSGP.lineAbs (yaxispos + charwidth, ya_max); + } + + if (o_grid == TRUE) { + rSGP.setColor (clr_grid); + for (i = 0; i <= y_nint; i++) { + y = yt_min + yn_tickinc * i; + rSGP.moveAbs (xa_max, y); + rSGP.lineAbs (xa_min, y); + } + } + rSGP.moveAbs (ylbl_col, ya_min + (ya_max-ya_min)/2 - c_ylabel.length()*charheight); + rSGP.setTextAngle (HALFPI); + rSGP.setTextSize (2 * charheight); + rSGP.setTextColor (clr_label, -1); + rSGP.drawText (c_ylabel); + rSGP.setTextAngle (0.0); + rSGP.setTextSize (charheight); + minorinc = yn_tickinc / (o_yminortick + 1); + + for (i = 0; i <= y_nint; i++) { + y = yt_min + yn_tickinc * i; + rSGP.setColor (clr_axis); + rSGP.moveAbs (yaxispos, y); + rSGP.lineAbs (yaxispos + yticklen, y); + if (i != y_nint) + for (j = 1; j <= o_yminortick; j++) { + y2 = y + minorinc * j; + rSGP.moveAbs (yaxispos, y2); + rSGP.lineAbs (yaxispos + TICKRATIO * yticklen, y2); } - } /* x - axis */ - + axis_near = FALSE; + if (yaxispos + ytl_ofs > xa_min && o_xaxis != NOAXIS) { + double yw = ygw_min + i * yw_tickinc; + double y = convertWorldToNDC_Y (yw); + double d = y - xaxispos; + if (o_xticks == ABOVE && d >= 0 && d < 0.9 * yn_tickinc) + axis_near = TRUE; + if (o_xticks == BELOW && d <= 0 && d > -0.9 * yn_tickinc) + axis_near = TRUE; + } + if (o_ytlabel == TRUE && axis_near == FALSE) { + snprintf (str, sizeof(str), y_numfmt, ygw_min + yw_tickinc * i); + rSGP.moveAbs (yaxispos + ytl_ofs, y + 0.5 * charheight); + rSGP.setTextColor (clr_number, -1); + rSGP.drawText (str); + } + } + } // Y - Axis +} - /*--------*/ - /* y-axis */ - /*--------*/ - if (ez.o_yaxis == LINEAR) { - sgp2_window (xp_min, yp_min, xp_max, yp_max); - sgp2_viewport (xp_min, yp_min, xp_max, yp_max); +void +EZPlot::symbol (int sym, double symwidth, double symheight) +{ + if (sym <= 0) + return; + + if (sym == SB_CROSS) { + rSGP.moveRel (-0.5 * symwidth, -0.5 * symheight); + rSGP.lineRel (symwidth, symheight); + rSGP.moveRel (-symwidth, 0.0); + rSGP.lineRel (symwidth, -symheight); + rSGP.moveRel (-0.5 * symwidth, 0.5 * symheight); + } else if (sym == SB_PLUS) { + rSGP.moveRel (-0.5 * symwidth, 0.0); + rSGP.lineRel (symwidth, 0.0); + rSGP.moveRel (-0.5 * symwidth, -0.5 * symheight); + rSGP.lineRel (0.0, symheight); + rSGP.moveRel (0.0, -0.5 * symheight); + } else if (sym == SB_BOX) { + rSGP.moveRel (-0.5 * symwidth, -0.5 * symheight); + rSGP.lineRel (symwidth, 0.0); + rSGP.lineRel (0.0, symheight); + rSGP.lineRel (-symwidth, 0.0); + rSGP.lineRel (0.0, -symheight); + rSGP.moveRel (0.5 * symwidth, 0.5 * symheight); + } else if (sym == SB_CIRCLE) { + rSGP.drawCircle (symwidth); + } else if (sym == SB_ERRORBAR) { + rSGP.moveRel (-0.5 * symwidth, 0.5 * symheight); + rSGP.lineRel (symwidth, 0.0); + rSGP.moveRel (-0.5 * symwidth, 0.0); + rSGP.lineRel (0.0, -symheight); + rSGP.moveRel (-0.5 * symwidth, 0.0); + rSGP.lineRel (symwidth, 0.0); + rSGP.moveRel (-0.5 * symwidth, 0.5 * symheight); + } +} - sgp2_color (ez.clr_axis); - if (ez.o_tag && !ez.o_grid && !ez.o_box && ez.s_ycross) { - sgp2_move_abs (yaxispos - charwidth, ya_min); - sgp2_line_abs (yaxispos + charwidth, ya_min); - } - sgp2_move_abs (yaxispos, ya_min); - sgp2_line_abs (yaxispos, ya_max); - if (ez.o_tag && !ez.o_grid && !ez.o_box) { - sgp2_move_abs (yaxispos - charwidth, ya_max); - sgp2_line_abs (yaxispos + charwidth, ya_max); - } - if (ez.o_grid == TRUE) { - sgp2_color (ez.clr_grid); - for (i = 0; i <= y_nint; i++) { - y = yt_min + yn_tickinc * i; - sgp2_move_abs (xa_max, y); - sgp2_line_abs (xa_min, y); - } - } - sgp2_move_abs (ylbl_col,ya_min + (ya_max-ya_min)/2 - strlen(ez.c_ylabel)*charheight); - textangle (HALFPI); - charsize (2 * charheight, 2 * charwidth); /* axis reversed */ - settextclr (ez.clr_label, -1); - sgp2_draw_text (ez.c_ylabel); - textangle (0.0); - charsize (charwidth, charheight); - minorinc = yn_tickinc / (ez.o_yminortick + 1); - - for (i = 0; i <= y_nint; i++) { - y = yt_min + yn_tickinc * i; - sgp2_color (ez.clr_axis); - sgp2_move_abs (yaxispos, y); - sgp2_line_abs (yaxispos + yticklen, y); - if (i != y_nint) - for (j = 1; j <= ez.o_yminortick; j++) { - y2 = y + minorinc * j; - sgp2_move_abs (yaxispos, y2); - sgp2_line_abs (yaxispos + TICKRATIO * yticklen, y2); - } - axis_near = FALSE; - if (yaxispos + ytl_ofs > xa_min && ez.o_xaxis != NOAXIS) { - double yw, x, y, d; - - yw = ygw_min + i * yw_tickinc; - sgp2_window (xgw_min, ygw_min, xgw_max, ygw_max); - sgp2_viewport (xgn_min, ygn_min, xgn_max, ygn_max); - wc_to_ndc (x, yw, &x, &y); - sgp2_window (xp_min, yp_min, xp_max, yp_max); - sgp2_viewport (xp_min, yp_min, xp_max, yp_max); - d = y - xaxispos; - if (ez.o_xticks == ABOVE && d >= 0 && d < 0.9 * yn_tickinc) - axis_near = TRUE; - if (ez.o_xticks == BELOW && d <= 0 && d > -0.9 * yn_tickinc) - axis_near = TRUE; - } - if (ez.o_ytlabel == TRUE && axis_near == FALSE) { - snprintf (str, sizeof(str), y_numfmt, ygw_min + yw_tickinc * i); - sgp2_move_abs (yaxispos + ytl_ofs, y - 0.5 * charheight); - settextclr (ez.clr_number, -1); - sgp2_draw_text (str); - } - } - } /* y - axis */ -} +/* NAME + * axis_scale calculates graph axis scaling + * + * SYNOPSIS: + * retval = axis_scale (min, max, nint, minp, maxp, nintp, + * rec_total, rec_frac) + * + * INPUT: + * double min Smallest value to plot + * double max Largest value to plot + * int nint Number of intervals desired + * + * OUTPUT: + * int retval FALSE if illegal parameters, else TRUE + * double *minp Minimum graph value + * double *maxp Maximum graph value + * int *nintp Number of intervals for graph + * int *rec_total Recommended field width for printing out the number + * int *rec_frac Recommended number of digits for print fraction + */ -static void -symbol (int sym, double symwidth, double symheight) +int +EZPlot::axis_scale (double min, double max, int nint, double *minp, double *maxp, int *nintp) { - if (sym <= 0) - return; - - if (sym == SB_CROSS) { - sgp2_move_rel (-0.5 * symwidth, -0.5 * symheight); - sgp2_line_rel (symwidth, symheight); - sgp2_move_rel (-symwidth, 0.0); - sgp2_line_rel (symwidth, -symheight); - sgp2_move_rel (-0.5 * symwidth, 0.5 * symheight); - } else if (sym == SB_PLUS) { - sgp2_move_rel (-0.5 * symwidth, 0.0); - sgp2_line_rel (symwidth, 0.0); - sgp2_move_rel (-0.5 * symwidth, -0.5 * symheight); - sgp2_line_rel (0.0, symheight); - sgp2_move_rel (0.0, -0.5 * symheight); - } else if (sym == SB_BOX) { - sgp2_move_rel (-0.5 * symwidth, -0.5 * symheight); - sgp2_line_rel (symwidth, 0.0); - sgp2_line_rel (0.0, symheight); - sgp2_line_rel (-symwidth, 0.0); - sgp2_line_rel (0.0, -symheight); - sgp2_move_rel (0.5 * symwidth, 0.5 * symheight); - } else if (sym == SB_CIRCLE) { - sgp2_draw_circle (symwidth); - } else if (sym == SB_ERRORBAR) { - sgp2_move_rel (-0.5 * symwidth, 0.5 * symheight); - sgp2_line_rel (symwidth, 0.0); - sgp2_move_rel (-0.5 * symwidth, 0.0); - sgp2_line_rel (0.0, -symheight); - sgp2_move_rel (-0.5 * symwidth, 0.0); - sgp2_line_rel (symwidth, 0.0); - sgp2_move_rel (-0.5 * symwidth, 0.5 * symheight); - } + if (min >= max || nint < 1) { + sys_error (ERR_WARNING, "Invalid params: min=%lf, max=%lf, num intervals=%d [axis_scale]", min, max, nint); + return (FALSE); + } + + double eps = 0.025; + double a = fabs(min); + if (fabs(min) < fabs(max)) + a = fabs(max); + double scale = pow (10.0, floor(log10(a))); + loop: + double mina = min / scale; + double maxa = max / scale; + double d = (maxa - mina) / nint; + double j = d * eps; + double e = floor (log10(d)); + double f = d / pow (10.0, e); + double v = 10.0; + if (f < sqrt(2.0)) + v = 1.0; + else if (f < sqrt (10.0)) + v = 2.0; + else if (f < sqrt (50.0)) + v = 5.0; + double wdt = v * pow (10.0, e); + double g = floor (mina / wdt); + if (fabs(g + 1 - mina / wdt) < j) + g = g + 1; +#if 1 + g++; +#endif + *minp = wdt * g; + double h = floor (maxa / wdt) + 1.0; + if (fabs(maxa / wdt + 1 - h) < j) + h = h - 1; +#if 1 + h--; +#endif + *maxp = wdt * h; + *nintp = static_cast(h - g); + if (fabs(*maxp) >= 10.0 || fabs(*minp) >= 10.0) { + scale = scale * 10.0; + goto loop; + } + + *minp *= scale; + *maxp *= scale; + + return (TRUE); } -void ezinit(void) -{ - /* EZPLOT Variables */ - - charwidth = DEF_CHARWIDTH; /* KR_FIX: Make these ez.o_ variables */ - charheight = DEF_CHARHEIGHT; - - /* EZPLOT & EZSET Variables */ - - strcpy (ez.c_xlabel, "X axis"); - strcpy (ez.c_ylabel, "Y axis"); - strcpy (ez.c_title, ""); - strcpy (ez.c_legend, ""); - - ezplot_firstcall = FALSE; - - ez.i_numcurves = 0; - ez.i_plotimmediate = FALSE; - - ez.o_reqcurves = 1; - ez.o_unknowncurves = FALSE; - - ez.o_ustart = FALSE; - ez.o_ufinish = FALSE; - - ez.o_xporigin = 0.0; - ez.o_yporigin = 0.0; - ez.o_xlength = 1.0; - ez.o_ylength = 1.0; - - ez.o_xaxis = LINEAR; - ez.o_yaxis = LINEAR; - - ez.o_grid = FALSE; - ez.o_box = FALSE; - - ez.o_xmajortick = 10; - ez.o_ymajortick = 8; - ez.o_xminortick = 4; - ez.o_yminortick = 4; - - ez.o_color = DEF_CURVE_CLR; - ez.o_symfreq = 1; - ez.o_symbol = -1; - ez.o_linestyle = LS_SOLID; - - ez.o_xtlabel = TRUE; - ez.o_ytlabel = TRUE; - ez.o_xticks = BELOW; - ez.o_yticks = LEFT; - - ez.o_legendbox = INSIDE; - ez.o_tag = FALSE; - - ez.s_xtitle = FALSE; - ez.s_ytitle = FALSE; - ez.s_xcross = FALSE; - ez.s_ycross = FALSE; - ez.s_lxfrac = FALSE; - ez.s_lyfrac = FALSE; - ez.s_xlegend = FALSE; - ez.s_ylegend = FALSE; - ez.s_textsize = FALSE; - - ez.d_usecrt = TRUE; - ez.d_useprt = FALSE; - ez.d_crtmode = DEF_CRTMODE; - ez.d_prtmode = PRTMODE_DEF; - ez.d_xprtbuf = XBUF_DEF; - ez.d_yprtbuf = YBUF_DEF; - - ez.clr_axis = C_WHITE; /* set fixed colors */ - ez.clr_title = (C_CYAN+8); - ez.clr_label = (C_CYAN+8); - ez.clr_legend = (C_RED+8); - ez.clr_number = (C_GREEN+8); - ez.clr_grid = (C_BLACK+8); -} +/* NAME + * make_numfmt Make a numeric format string + * + * SYNOPSIS + * make_numfmt (fmtstr, fldwid, nfrac, min, max, nint) + * char *fmtstr Returned format string for printf() + * int *fldwid Returned field width + * int *nfrac If < 0, then calculate best number of + * fraction places & return that value + * If >= 0, then use that number of places + * double min Minimum value + * double max Maximum value + * int nint Number of intervals between min & max + * + * DESCRIPTION + * This routine is written as an INTERNAL routine for EZPLOT + */ -void ezfree(void) +static inline double +trunc (double x) { - for (int i = 0; i < ez.i_numcurves; i++) { - delete ez.curve[i].x; - delete ez.curve[i].y; - } - ez.i_numcurves = 0; + double integer; + + modf (x, &integer); + + return (integer); } -void ezclear(void) +void +EZPlot::make_numfmt (char *fmtstr, int *fldwid, int *nfrac, double minval, double maxval, int nint) { - ezfree(); - ezinit(); + int wid, frac, expon; + + double delta = (maxval - minval) / nint; + double absmin = fabs(minval); + double absmax = fabs(maxval); + if (absmin > absmax) + absmax = absmin; + double logt = log10( absmax ); + + if (fabs(logt) >= 6) { // use exponential format + if (fabs(logt) > 99) + expon = 5; // E+102 + else + expon = 4; // E+00 + + if (*nfrac < 0) { // calculate frac + delta /= pow (10., floor(logt)); // scale delta + frac = static_cast(fabs(trunc(log10(delta)))) + 1; + if (frac < 1) + frac = 1; // to be safe, add decimal pt + } else // use users' frac + frac = *nfrac; + + wid = 2 + frac + expon; + if (minval < 0. || maxval < 0.) + ++wid; + sprintf (fmtstr, "%s%d%s%d%s", "%", wid, ".", frac, "g"); + } else { // use fixed format + wid = static_cast(trunc(logt)) + 1; + if (wid < 1) + wid = 1; + if (minval < 0. || maxval < 0.) + ++wid; + + if (*nfrac < 0) { // calculate frac + if (delta >= 0.999999) + frac = 1; // add a decimal pt to be safe + else + frac = static_cast(fabs(trunc(log10(delta)))) + 1; + } else // use users' frac + frac = *nfrac; + + wid += 1 + frac; + sprintf (fmtstr, "%s%d%s%d%s", "%", wid, ".", frac, "f"); + } + + *fldwid = wid; + *nfrac = frac; } +