1 /*****************************************************************************
6 ** This is part of the CTSim program
7 ** Copyright (C) 1983-2000 Kevin Rosenberg
9 ** $Id: ezplot.cpp,v 1.21 2000/12/23 18:12:35 kevin Exp $
11 ** This program is free software; you can redistribute it and/or modify
12 ** it under the terms of the GNU General Public License (version 2) as
13 ** published by the Free Software Foundation.
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ** GNU General Public License for more details.
20 ** You should have received a copy of the GNU General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 ******************************************************************************/
29 int snprintf (char *, size_t, const char*, ...);
33 static const double TICKRATIO = 0.4; // ratio of minor to major tick lengths
34 static const int MAXNUMFMT = 15; // maximum length of a numeric format
35 static const int DEF_CURVE_CLR = C_RED;
38 EZPlotCurve::EZPlotCurve (const double* xData, const double* yData, int n, int color, int linestyle, int symbol, int symfreq, const std::string& legend)
39 : x(NULL), y(NULL), m_sLegend (legend)
44 int copyCount = n * sizeof(double);
45 memcpy (x, xData, copyCount);
46 memcpy (y, yData, copyCount);
50 m_iLineStyle = linestyle;
52 m_iSymbolFreq = symfreq;
55 EZPlotCurve::~EZPlotCurve ()
63 EZPlot::addCurve (const double *y, int n)
65 double* x = new double [n];
67 for (int i = 0; i < n; i++)
76 EZPlot::addCurve (const float *y, int n)
78 double* yDouble = new double [n];
80 for (int i = 0; i < n; i++)
83 addCurve (yDouble, n);
89 EZPlot::addCurve (const float x[], const double y[], int num)
91 double* dx = new double [num];
93 for (int i = 0; i < num; i++)
96 addCurve (dx, y, num);
101 EZPlot::addCurve (const double x[], const float y[], int num)
103 double* dy = new double [num];
105 for (int i = 0; i < num; i++)
108 addCurve (x, dy, num);
115 EZPlot::addCurve (const double x[], const double y[], int num)
120 EZPlotCurve* pCurve = new EZPlotCurve (x, y, num, o_color, o_linestyle, o_symbol, o_symfreq, c_legend);
121 m_vecCurves.push_back (pCurve);
127 for (EZPlotCurveIterator i = m_vecCurves.begin(); i != m_vecCurves.end(); i++)
132 EZPlot::clearCurves ()
134 for (EZPlotCurveIterator i = m_vecCurves.begin(); i != m_vecCurves.end(); i++)
136 m_vecCurves.erase (m_vecCurves.begin(), m_vecCurves.end());
141 EZPlot::EZPlot (SGP& sgp)
148 EZPlot::initPlotSettings ()
150 charheight = rSGP.getCharHeight();
151 charwidth = rSGP.getCharWidth();
174 o_color = DEF_CURVE_CLR;
177 o_linestyle = SGP::LS_SOLID;
184 o_legendbox = INSIDE;
197 clr_axis = C_BLACK; // set fixed colors
201 clr_number = C_GREEN;
207 * plot Plots all curves collected by addCurves ()
213 * This routine plots the curves that have stored by addCurves().
216 * drawAxes() & make_numfmt()
223 wxFont* myFont = new wxFont (12, wxMODERN, wxNORMAL, wxNORMAL);
\r
224 rSGP.getDriver().idWX()->SetFont (*myFont);
\r
226 if (m_vecCurves.size() <= 0)
229 rSGP.setWindow (0., 0., 1., 1.);
231 if (s_textsize == TRUE) {
232 charheight = v_textsize;
233 charwidth = rSGP.getCharWidth();
235 charheight = rSGP.getCharHeight();
236 charwidth = rSGP.getCharWidth();
239 const EZPlotCurve& firstCurve = *m_vecCurves[0];
240 double xmin = firstCurve.x[0]; // extent of curves in world coord
242 double ymin = firstCurve.y[0];
245 for (EZPlotCurveConstIterator iterCurve = m_vecCurves.begin(); iterCurve != m_vecCurves.end(); iterCurve++) {
246 const EZPlotCurve& curve = **iterCurve;
248 for (int ip = 0; ip < curve.m_iPointCount; ip++) {
249 if (curve.x[ip] > xmax)
251 else if (curve.x[ip] < xmin)
253 if (curve.y[ip] > ymax)
255 else if (curve.y[ip] < ymin)
260 // extend graph limits for user defined axis cross positions
261 if (s_xcross == TRUE) {
264 else if (v_xcross > xmax)
268 if (s_ycross == TRUE) {
271 else if (v_ycross > ymax)
275 // find nice endpoints for axes
276 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))
279 // check if user set x-axis extents
280 if (s_xmin == TRUE) {
282 x_nint = o_xmajortick - 1;
284 if (s_xmax == TRUE) {
286 x_nint = o_xmajortick - 1;
289 // check if user set y-axis extents
290 if (s_ymin == TRUE) {
292 y_nint = o_ymajortick - 1;
294 if (s_ymax == TRUE) {
296 y_nint = o_ymajortick - 1;
299 // calculate increment between major axis in world coordinates
300 xw_tickinc = (xgw_max - xgw_min) / x_nint;
301 yw_tickinc = (ygw_max - ygw_min) / y_nint;
303 // we have now calcuated xgw_min, xyw_max, ygw_min, & ygw_max
305 // set the number of decimal point to users' setting or default
306 // Two formats for numbers: Fixed: -nnn.f and Exponent: -n.fffE+eee
307 if (s_lxfrac == TRUE)
312 if (s_lyfrac == TRUE)
317 make_numfmt (x_numfmt, &x_fldwid, &x_frac, xgw_min, xgw_max, x_nint);
318 make_numfmt (y_numfmt, &y_fldwid, &y_frac, ygw_min, ygw_max, y_nint);
320 xtl_wid = x_fldwid * charwidth; // calc size of tick labels
321 ytl_wid = y_fldwid * charwidth;
322 tl_height = charheight;
324 // calculate the extent of the plot frame
327 xp_max = xp_min + o_xlength;
328 yp_max = yp_min + o_ylength;
330 xp_min = clamp (xp_min, 0., 1.);
331 xp_max = clamp (xp_max, 0., 1.);
332 yp_min = clamp (yp_min, 0., 1.);
333 yp_max = clamp (yp_max, 0., 1.);
335 xa_min = xp_min; // extent of axes
340 // adjust frame for title
341 if (c_title.length() > 0)
342 ya_max -= 2 * charheight;
343 title_row = ya_max + 2 * charheight;
345 // calculate legend box boundaries
346 int max_leg = 0; // longest legend in characters
347 int num_leg = 0; // number of legend titles
348 for (EZPlotCurveConstIterator iterCurve2 = m_vecCurves.begin(); iterCurve2 != m_vecCurves.end(); iterCurve2++) {
349 const EZPlotCurve& curve = **iterCurve2;
350 int nLegend = curve.m_sLegend.length();
353 if (nLegend > max_leg)
\r
358 if (num_leg > 0 && o_legendbox != NOLEGEND) {
359 double leg_width = (max_leg + 2) * charwidth; // size of legend box
360 double leg_height = num_leg * 3 * charheight;
362 if (s_xlegend == TRUE)
366 if (o_legendbox == OUTSIDE)
367 xa_max -= (leg_width + 0.5 * charwidth);
369 xl_min = xl_max - leg_width;
371 if (s_ylegend == TRUE)
376 yl_min = yl_max - leg_height;
378 rSGP.setColor (clr_legend);
379 rSGP.drawRect (xl_min, yl_min, xl_max, yl_max);
381 int iLegend = 0; // current legend position
382 for (EZPlotCurveIterator iterCurve = m_vecCurves.begin(); iterCurve != m_vecCurves.end(); iterCurve++) {
383 const EZPlotCurve& curve = **iterCurve;
385 if (curve.m_sLegend.length() == 0)
388 double xmin = xl_min + 1.0 * charwidth;
389 double xmax = xl_max - 1.0 * charwidth;
390 double y = yl_max - (2.0 + iLegend * 3) * charheight;
392 rSGP.moveAbs (xmin, y + 0.5 * charheight);
393 rSGP.drawText (curve.m_sLegend);
394 rSGP.setColor (curve.m_iColor);
395 if (curve.m_iLineStyle != SGP::LS_NOLINE) {
396 rSGP.setLineStyle (curve.m_iLineStyle);
397 rSGP.moveAbs (xmin, y);
398 rSGP.lineAbs (xmax, y);
400 if (curve.m_iSymbol > 0) {
401 double xinc = (xmax - xmin) / (5 - 1);
402 rSGP.setLineStyle (SGP::LS_SOLID);
403 for (int j = 0; j < 5; j++) {
404 rSGP.moveAbs (xmin + j * xinc, y);
405 symbol(curve.m_iSymbol, 0.5 * charwidth, 0.5 * charheight);
408 ++iLegend; // move to next legend position
410 } // end legend printing
412 // calculate the extent of the axes
414 /*-------------------------*/
415 /* adjust frame for labels */
416 /*-------------------------*/
419 if (c_xlabel.length() > 0)
420 ya_min += 3.0 * charheight;
421 xlbl_row = xp_min; // put x-label on bottom of plot frame
424 if (c_ylabel.length() > 0)
425 xa_min += 3.0 * charwidth; // reverse rSGP.setTextSize because writing text sideways
426 ylbl_col = xp_min + 2 * charwidth;
428 /*------------------------------*/
429 /* adjust frame for tick labels */
430 /*------------------------------*/
432 // Calc offset of tick labels from axes
433 if (o_xaxis == NOAXIS || o_xtlabel == FALSE)
435 else if (o_xticks == BELOW)
436 xtl_ofs = -1.5 * charheight; // kr
437 else if (o_xticks == ABOVE)
438 xtl_ofs = 1.5 * charheight;
440 if (o_yaxis == NOAXIS || o_ytlabel == FALSE)
442 else if (o_yticks == LEFT)
443 ytl_ofs = -(1 + y_fldwid) * charwidth;
444 else if (o_yticks == RIGHT)
445 ytl_ofs = 1.5 * charwidth;
452 // see if need to shrink axis extents and/or tick extents
453 if (xtl_ofs != 0.0 && s_ycross == FALSE) {
454 if (o_xticks == BELOW) {
455 ya_min += 2.5 * charheight;
457 } else if (o_xticks == ABOVE) {
459 yt_min = ya_min + 2.5 * charheight;
461 } else // noaxis, no t-labels, or user set cross
464 if (ytl_ofs != 0.0 && s_xcross == FALSE) {
465 if (o_yticks == LEFT) {
466 xa_min += (1 + y_fldwid) * charwidth;
468 } else if (o_yticks == RIGHT) {
470 xt_min = xa_min + ytl_ofs + y_fldwid * charwidth;
475 // decrease size of graph, if necessary, to accommadate space
476 // between axis boundary and boundary of ticks
477 double x_added_ticks = 0; // number of tick spaces added to axis
478 double y_added_ticks = 0;
479 if (o_xaxis == NOAXIS || o_xtlabel == FALSE)
481 if (o_yaxis == NOAXIS || o_ytlabel == FALSE)
484 if (o_grid == TRUE) {
485 if (x_added_ticks < 0)
487 if (y_added_ticks < 0)
491 if (x_added_ticks < 0) {
492 if (o_yticks == LEFT || s_ycross)
498 if (y_added_ticks < 0) {
499 if (o_xticks == BELOW || s_xcross)
505 xn_tickinc = (xt_max - xt_min) / (x_nint + x_added_ticks);
506 yn_tickinc = (yt_max - yt_min) / (y_nint + y_added_ticks);
508 xt_min += 0.5 * x_added_ticks * xn_tickinc;
509 xt_max -= 0.5 * x_added_ticks * xn_tickinc;
510 yt_min += 0.5 * y_added_ticks * yn_tickinc;
511 yt_max -= 0.5 * y_added_ticks * yn_tickinc;
518 //------------------------------------------------------------------------
520 m_xWorldScale = (xgn_max - xgn_min) / (xgw_max - xgw_min);
521 m_yWorldScale = (ygn_max - ygn_min) / (ygw_max - ygw_min);
525 rSGP.setLineStyle (SGP::LS_SOLID);
528 // size of symbol in NDC
529 double symwidth = charwidth;
530 double symheight = charheight;
532 double clipRect[4];
\r
533 clipRect[0] = xgn_min; clipRect[1] = ygn_min; clipRect[2] = xgn_max; clipRect[3] = ygn_max;
\r
535 for (EZPlotCurveIterator iterCurve3 = m_vecCurves.begin(); iterCurve3 != m_vecCurves.end(); iterCurve3++) {
536 const EZPlotCurve& curve = **iterCurve3;
538 rSGP.setColor (curve.m_iColor);
540 bool bOutside = false;
541 if (curve.m_iLineStyle != SGP::LS_NOLINE) {
542 rSGP.setLineStyle (curve.m_iLineStyle);
543 double x1 = convertWorldToNDC_X (curve.x[0]);
544 double y1 = convertWorldToNDC_Y (curve.y[0]);
\r
545 for (int i = 1; i < curve.m_iPointCount; i++) {
546 double x2 = convertWorldToNDC_X (curve.x[i]);
547 double y2 = convertWorldToNDC_Y (curve.y[i]);
\r
548 double x2Clip = x2;
\r
549 double y2Clip = y2;
\r
550 if (clip_rect (x1, y1, x2Clip, y2Clip, clipRect)) {
\r
551 rSGP.moveAbs (x1, y1);
\r
552 rSGP.lineAbs (x2Clip, y2Clip);
\r
558 if (curve.m_iSymbol > 0) {
559 rSGP.setLineStyle (SGP::LS_SOLID);
560 double x = convertWorldToNDC_X (curve.x[0]);
561 double y = convertWorldToNDC_Y (curve.y[0]);
563 symbol (curve.m_iSymbol, symwidth, symheight);
564 for (int i = 1; i < curve.m_iPointCount; i++)
565 if (i % curve.m_iSymbolFreq == 0 || i == curve.m_iPointCount - 1) {
566 x = convertWorldToNDC_X (curve.x[i]);
567 y = convertWorldToNDC_Y (curve.y[i]);
\r
568 if (y >= ygn_min && y <= ygn_max) {
570 symbol (curve.m_iSymbol, symwidth, symheight);
\r
580 * drawAxes INTERNAL routine to draw axis & label them
590 double xticklen = 0, yticklen = 0; // length of ticks in NDC
591 double minorinc; // increment between minor axes
592 double xaxispos, yaxispos; // crossing of axes
594 bool axis_near; // TRUE if axis too close to print t-label
599 rSGP.setTextSize (charheight);
600 rSGP.setTextColor (1, -1);
602 if (o_xticks == ABOVE)
603 xticklen = charheight;
604 else if (o_xticks == BELOW)
605 xticklen = -charheight;
607 if (o_yticks == RIGHT)
608 yticklen = charwidth;
609 else if (o_yticks == LEFT)
610 yticklen = -charwidth;
612 if (c_title.length() > 0) {
614 rSGP.setTextSize (charheight * 2.0);
615 rSGP.getTextExtent (c_title.c_str(), &wText, &hText);
616 rSGP.moveAbs (xa_min + (xa_max-xa_min)/2 - wText/2, title_row);
617 rSGP.setTextColor (clr_title, -1);
618 rSGP.drawText (c_title);
619 rSGP.setTextSize (charheight);
622 if (o_grid == TRUE || o_box == TRUE) {
623 rSGP.setColor (clr_axis);
624 rSGP.moveAbs (xa_min, ya_min);
625 rSGP.lineAbs (xa_max, ya_min);
626 rSGP.lineAbs (xa_max, ya_max);
627 rSGP.lineAbs (xa_min, ya_max);
628 rSGP.lineAbs (xa_min, ya_min);
631 // calculate position of axes
634 if (s_ycross == TRUE) { // convert users' world-coord
635 xaxispos = convertWorldToNDC_Y (v_ycross);// axis to its position in NDC
636 x = convertWorldToNDC_X (xgw_min);
641 if (s_xcross == TRUE) { // convert users' world-coord
642 yaxispos = convertWorldToNDC_X (v_xcross);// axis to its NDC position
643 y = convertWorldToNDC_Y (ygw_min);
651 if (o_xaxis == LINEAR) {
654 rSGP.setColor (clr_axis);
655 if (o_tag && !o_grid && !o_box && s_xcross) {
656 rSGP.moveAbs (xa_min, xaxispos - charheight);
657 rSGP.lineAbs (xa_min, xaxispos + charheight);
659 rSGP.moveAbs (xa_min, xaxispos);
660 rSGP.lineAbs (xa_max, xaxispos);
661 if (o_tag && !o_grid && !o_box) {
662 rSGP.moveAbs (xa_max, xaxispos - charheight);
663 rSGP.lineAbs (xa_max, xaxispos + charheight);
666 if (o_grid == TRUE) {
667 rSGP.setColor (clr_grid);
668 for (i = 0; i <= x_nint; i++) {
669 rSGP.moveAbs (xt_min + xn_tickinc * i, ya_max);
670 rSGP.lineAbs (xt_min + xn_tickinc * i, ya_min);
673 rSGP.moveAbs (xa_min + (xa_max-xa_min)/2 - c_xlabel.length()*charwidth * 1.5, xlbl_row + charheight * 1.5);
674 rSGP.setTextSize (charheight * 1.5);
675 rSGP.setTextColor (clr_label, -1);
676 rSGP.drawText (c_xlabel);
677 rSGP.setTextSize (charheight);
678 minorinc = xn_tickinc / (o_xminortick + 1);
680 for (i = 0; i <= x_nint; i++) {
681 x = xt_min + xn_tickinc * i;
682 rSGP.setColor (clr_axis);
683 rSGP.moveAbs (x, xaxispos);
684 rSGP.lineAbs (x, xaxispos + xticklen);
686 for (j = 1; j <= o_xminortick; j++) {
687 x2 = x + minorinc * j;
688 rSGP.moveAbs (x2, xaxispos);
689 rSGP.lineAbs (x2, xaxispos + TICKRATIO * xticklen);
692 if (xaxispos + xtl_ofs > ya_min && o_yaxis != NOAXIS) {
693 double xw = xgw_min + i * xw_tickinc;
694 double x = convertWorldToNDC_X (xw);
695 double d = x - yaxispos;
696 if (o_yticks == RIGHT && d >= 0 && d < 0.9 * xn_tickinc)
698 if (o_yticks == LEFT && d <= 0 && d > -0.9 * xn_tickinc)
702 if (o_xtlabel == TRUE && axis_near == FALSE) {
703 snprintf (str, sizeof(str), x_numfmt, xgw_min + xw_tickinc * i);
704 numstr = str_skip_head (str, " ");
705 rSGP.moveAbs (x-strlen(numstr)*charwidth/2, xaxispos + xtl_ofs);
706 rSGP.setTextColor (clr_number, -1);
707 rSGP.drawText (numstr);
717 if (o_yaxis == LINEAR) {
719 rSGP.setColor (clr_axis);
720 if (o_tag && !o_grid && !o_box && s_ycross) {
721 rSGP.moveAbs (yaxispos - charwidth, ya_min);
722 rSGP.lineAbs (yaxispos + charwidth, ya_min);
724 rSGP.moveAbs (yaxispos, ya_min);
725 rSGP.lineAbs (yaxispos, ya_max);
726 if (o_tag && !o_grid && !o_box) {
727 rSGP.moveAbs (yaxispos - charwidth, ya_max);
728 rSGP.lineAbs (yaxispos + charwidth, ya_max);
731 if (o_grid == TRUE) {
732 rSGP.setColor (clr_grid);
733 for (i = 0; i <= y_nint; i++) {
734 y = yt_min + yn_tickinc * i;
735 rSGP.moveAbs (xa_max, y);
736 rSGP.lineAbs (xa_min, y);
739 rSGP.moveAbs (ylbl_col, ya_min + (ya_max-ya_min)/2 - c_ylabel.length()*charheight*1.5);
\r
740 rSGP.getDriver().idWX()->SetFont(*wxSWISS_FONT);
741 rSGP.setTextAngle (HALFPI);
742 rSGP.setTextSize (1.5 * charheight);
743 rSGP.setTextColor (clr_label, -1);
744 rSGP.setTextAngle (0.0);
745 rSGP.setTextSize (charheight);
746 minorinc = yn_tickinc / (o_yminortick + 1);
748 for (i = 0; i <= y_nint; i++) {
749 y = yt_min + yn_tickinc * i;
750 rSGP.setColor (clr_axis);
751 rSGP.moveAbs (yaxispos, y);
752 rSGP.lineAbs (yaxispos + yticklen, y);
754 for (j = 1; j <= o_yminortick; j++) {
755 y2 = y + minorinc * j;
756 rSGP.moveAbs (yaxispos, y2);
757 rSGP.lineAbs (yaxispos + TICKRATIO * yticklen, y2);
760 if (yaxispos + ytl_ofs > xa_min && o_xaxis != NOAXIS) {
761 double yw = ygw_min + i * yw_tickinc;
762 double y = convertWorldToNDC_Y (yw);
763 double d = y - xaxispos;
764 if (o_xticks == ABOVE && d >= 0 && d < 0.9 * yn_tickinc)
766 if (o_xticks == BELOW && d <= 0 && d > -0.9 * yn_tickinc)
769 if (o_ytlabel == TRUE && axis_near == FALSE) {
770 snprintf (str, sizeof(str), y_numfmt, ygw_min + yw_tickinc * i);
771 rSGP.moveAbs (yaxispos + ytl_ofs, y + 0.5 * charheight);
772 rSGP.setTextColor (clr_number, -1);
\r
781 EZPlot::symbol (int sym, double symwidth, double symheight)
786 if (sym == SB_CROSS) {
787 rSGP.moveRel (-0.5 * symwidth, -0.5 * symheight);
788 rSGP.lineRel (symwidth, symheight);
789 rSGP.moveRel (-symwidth, 0.0);
790 rSGP.lineRel (symwidth, -symheight);
791 rSGP.moveRel (-0.5 * symwidth, 0.5 * symheight);
792 } else if (sym == SB_PLUS) {
793 rSGP.moveRel (-0.5 * symwidth, 0.0);
794 rSGP.lineRel (symwidth, 0.0);
795 rSGP.moveRel (-0.5 * symwidth, -0.5 * symheight);
796 rSGP.lineRel (0.0, symheight);
797 rSGP.moveRel (0.0, -0.5 * symheight);
798 } else if (sym == SB_BOX) {
799 rSGP.moveRel (-0.5 * symwidth, -0.5 * symheight);
800 rSGP.lineRel (symwidth, 0.0);
801 rSGP.lineRel (0.0, symheight);
802 rSGP.lineRel (-symwidth, 0.0);
803 rSGP.lineRel (0.0, -symheight);
804 rSGP.moveRel (0.5 * symwidth, 0.5 * symheight);
805 } else if (sym == SB_CIRCLE) {
806 rSGP.drawCircle (symwidth);
807 } else if (sym == SB_ERRORBAR) {
808 rSGP.moveRel (-0.5 * symwidth, 0.5 * symheight);
809 rSGP.lineRel (symwidth, 0.0);
810 rSGP.moveRel (-0.5 * symwidth, 0.0);
811 rSGP.lineRel (0.0, -symheight);
812 rSGP.moveRel (-0.5 * symwidth, 0.0);
813 rSGP.lineRel (symwidth, 0.0);
814 rSGP.moveRel (-0.5 * symwidth, 0.5 * symheight);
821 * axis_scale calculates graph axis scaling
824 * retval = axis_scale (min, max, nint, minp, maxp, nintp,
825 * rec_total, rec_frac)
828 * double min Smallest value to plot
829 * double max Largest value to plot
830 * int nint Number of intervals desired
833 * int retval FALSE if illegal parameters, else TRUE
834 * double *minp Minimum graph value
835 * double *maxp Maximum graph value
836 * int *nintp Number of intervals for graph
837 * int *rec_total Recommended field width for printing out the number
838 * int *rec_frac Recommended number of digits for print fraction
842 EZPlot::axis_scale (double min, double max, int nint, double *minp, double *maxp, int *nintp)
844 if (min >= max || nint < 1) {
845 sys_error (ERR_WARNING, "Invalid params: min=%lf, max=%lf, num intervals=%d [axis_scale]", min, max, nint);
850 double a = fabs(min);
851 if (fabs(min) < fabs(max))
853 double scale = pow (10.0, floor(log10(a)));
855 double mina = min / scale;
856 double maxa = max / scale;
857 double d = (maxa - mina) / nint;
859 double e = floor (log10(d));
860 double f = d / pow (10.0, e);
864 else if (f < sqrt (10.0))
866 else if (f < sqrt (50.0))
868 double wdt = v * pow (10.0, e);
869 double g = floor (mina / wdt);
870 if (fabs(g + 1 - mina / wdt) < j)
877 double h = floor (maxa / wdt) + 1.0;
878 if (fabs(maxa / wdt + 1 - h) < j)
884 *nintp = static_cast<int>(h - g);
885 if (fabs(*maxp) >= 10.0 || fabs(*minp) >= 10.0) {
886 scale = scale * 10.0;
898 * make_numfmt Make a numeric format string
901 * make_numfmt (fmtstr, fldwid, nfrac, min, max, nint)
902 * char *fmtstr Returned format string for printf()
903 * int *fldwid Returned field width
904 * int *nfrac If < 0, then calculate best number of
905 * fraction places & return that value
906 * If >= 0, then use that number of places
907 * double min Minimum value
908 * double max Maximum value
909 * int nint Number of intervals between min & max
912 * This routine is written as an INTERNAL routine for EZPLOT
926 EZPlot::make_numfmt (char *fmtstr, int *fldwid, int *nfrac, double minval, double maxval, int nint)
928 int wid, frac, expon;
930 double delta = (maxval - minval) / nint;
931 double absmin = fabs(minval);
932 double absmax = fabs(maxval);
\r
933 if (absmin > absmax)
\r
935 double logt = log10( absmax );
937 if (fabs(logt) >= 6) { // use exponential format
943 if (*nfrac < 0) { // calculate frac
944 delta /= pow (10., floor(logt)); // scale delta
945 frac = static_cast<int>(fabs(trunc(log10(delta)))) + 1;
947 frac = 1; // to be safe, add decimal pt
948 } else // use users' frac
951 wid = 2 + frac + expon;
952 if (minval < 0. || maxval < 0.)
954 sprintf (fmtstr, "%s%d%s%d%s", "%", wid, ".", frac, "g");
955 } else { // use fixed format
956 wid = static_cast<int>(trunc(logt)) + 1;
959 if (minval < 0. || maxval < 0.)
962 if (*nfrac < 0) { // calculate frac
963 if (delta >= 0.999999)
964 frac = 1; // add a decimal pt to be safe
966 frac = static_cast<int>(fabs(trunc(log10(delta)))) + 1;
967 } else // use users' frac
971 sprintf (fmtstr, "%s%d%s%d%s", "%", wid, ".", frac, "f");