?? plotxy.h
字號:
/* 2008 (c) Dorival M. Pedroso */#ifndef MPM_PLOTXY_H#define MPM_PLOTXY_H// STL#include <cmath> // for ceil and floor#include <cfloat> // for DBL_EPSILON#include <iostream>// FLTK#include <FL/Fl.H>#include <FL/Fl_Group.H>#include <FL/fl_draw.H>#include <FL/Enumerations.H> // for Fl_Color// Local#include "defs.h"#include "fatal.h"#include "array.h"/* Plot XY. */class PlotXY : public Fl_Group{public: // Constants static double MINZERO; ///< Minimum value to be replaced to 0.0 in _pretty method /* Constructor. */ PlotXY (int xmin, int ymin, int width, int height, char const * Title=NULL, char const * Xlbl=NULL, char const * Ylbl=NULL); // Screen coordinates /* Destructor. */ virtual ~PlotXY () {} // Methods void AddCurve (char const * Name); ///< Add curve (x-y values) void AddCurve (Array<double> const * X, Array<double> const * Y, char const * Name); ///< Add curve (x-y values) void SetXY (size_t i, Array<double> const * X, Array<double> const * Y); ///< Set X and Y pointers void DelCurve (size_t i); ///< Remove curve (x-y values) CurveProps & SetCurve (size_t i); void CalcSF (); ///< Calculate scale factors void DrawRulers (); ///< Draw rulers void DrawLegend (); ///< Draw legend // Set methods PlotXY & EqScales (bool EQScales=true) { _eqsf=EQScales; return (*this); } ///< Set equal scale factors PlotXY & RecalcSF (bool REcalcSF=true) { _recsf=REcalcSF; return (*this); } ///< Recalculate scale factors during draw ? PlotXY & WithFrame (bool WFrame =true) { _wframe=WFrame; return (*this); } ///< Draw an all-around frame ? PlotXY & BRuler (bool Visible =true, int nTicks=10); ///< Set bottom ruler PlotXY & LRuler (bool Visible =true, int nTicks=10); ///< Set left ruler PlotXY & SetBTicksFmt (char const * Fmt="%4.1f", int Size=5); ///< Set bottom ruler ticks format, ex.: "%4.1f" => Size==5 PlotXY & SetLTicksFmt (char const * Fmt="%3.1f", int Size=5); ///< Set left ruler ticks format, ex.: "%3.1f" => Size==5 /* Draw method (internal). */ void draw ();private: // Data double _sfX; ///< Scale factor: x=xmin+(X-Xmin)*sf and y=ymin+ymax-(Y-Ymin)*sf, where x and y are screen coordinates double _sfY; ///< Scale factor: x=xmin+(X-Xmin)*sf and y=ymin+ymax-(Y-Ymin)*sf, where x and y are screen coordinates bool _eqsf; ///< Equal scale factors ? bool _recsf; ///< Recalculate scale factors during draw ? bool _sfok; ///< Is scale factor ok (set true after a first time calculation) ? bool _wframe; ///< With frame? draw an all-around frame ? double _Xmin; ///< Minimum x value (real coordinates) double _Ymin; ///< Minimum y value (real coordinates) double _Xmax; ///< Maximum x value (real coordinates) double _Ymax; ///< Maximum y value (real coordinates) int _lrt; ///< Left ruler tickness (screen coordinates) int _rrt; ///< Right ruler tickness (screen coordinates) int _brt; ///< Bottom ruler tickness (screen coordinates) int _trt; ///< Top ruler tickness (screen coordinates) int _hb; ///< Increment for horizontal borders (to the inside) (screen coordinates) int _vb; ///< Increment for vertical borders (to the inside) (screen coordinates) int _bnt; ///< Bottom ruler number of ticks int _lnt; ///< Left ruler number of ticks int _ticfsz; ///< Ticks font size int _lblfsz; ///< Labels font size int _titfsz; ///< Title font size char _btifmt[16]; ///< Bottom ruler ticks number format char _ltifmt[16]; ///< Left ruler ticks number format char _title[256]; ///< The title char _blbl[64]; ///< Bottom ruler label char _llbl[64]; ///< Left ruler lable int _blegh; ///< Bottom legend height int _rlegw; ///< Right legend width int _bhpad; ///< Border horizontal padding int _bvpad; ///< Border vertical padding int _pahpad; ///< Plot area horizontal padding int _pavpad; ///< Plot area vertical padding bool _legatbot; ///< Legend at bottom ? bool _cptbr; ///< Compact bottom ruler ? // Curves Array<Array<double> const*> _X; ///< X curves (real coordinates) Array<Array<double> const*> _Y; ///< Y curves (real coordinates) Array<CurveProps> _C; ///< Curve properties // Private Methods int _x (double X) const { return static_cast<int>((x()+1+_lrt+_hb) +_sfX*(X-_Xmin)); } ///< X in screen coordinates int _y (double Y) const { return static_cast<int>((y()+1+_trt+_vb)+(h()-_pavpad)-_sfY*(Y-_Ymin)); } ///< Y in screen coordinates int _l (double L) const { return static_cast<int>((_sfX>_sfY?_sfY:_sfX)*L); } ///< Length in screen coordinates void _pretty (double Lo, double Hi, int nDiv, Array<double> & Vals); ///< Return a pretty serie of numbers between Lo and HI}; // class PlotXYdouble PlotXY::MINZERO = sqrt(DBL_EPSILON);/////////////////////////////////////////////////////////////////////////////////////////// Implementation //////* public */inline PlotXY::PlotXY(int xmin, int ymin, int width, int height, char const * Title, char const * Xlbl, char const * Ylbl) : Fl_Group (xmin,ymin,width,height,0), _sfX (1.0), _sfY (1.0), _eqsf (false), _recsf (true), _sfok (false), _wframe (true), _Xmin (0.0), _Ymin (0.0), _Xmax (1.0), _Ymax (1.0), _hb (6), _vb (6), _bnt (5), _lnt (5), _ticfsz (10), _lblfsz (12), _titfsz (14), _blegh (16), _rlegw (0), _legatbot (true), _cptbr (true){ end(); // Set dependent constants _lrt = 40; // left ruler _rrt = 0+5; // +5 to account for the width of the bottom tick text _brt = (_cptbr?20:20+_ticfsz); // +_ticfsz to account for the label _trt = 18; // area for the title _bhpad = _lrt+_rrt+_rlegw; // border horizontal padding _bvpad = _brt+_trt+_blegh; // border vertical padding _pahpad = _bhpad+2+2*_hb; // plot-area horizontal padding _pavpad = _bvpad+2+2*_vb; // plot-area vertical padding // Set tick number formats strncpy (_btifmt, "%g", 2); _btifmt[2]='\0'; strncpy (_ltifmt, "%g", 2); _ltifmt[2]='\0'; // Set title if (Title==NULL) { strncpy (_title, "X-Y plot", 8); _title[8]='\0'; } else strncpy (_title, Title, 256); // Set x-label if (Xlbl==NULL) { strncpy (_blbl, "X", 1); _blbl[1]='\0'; } else strncpy (_blbl, Xlbl, 64); // Set y-label if (Ylbl==NULL) { strncpy (_llbl, "Y", 1); _llbl[1]='\0'; } else strncpy (_llbl, Ylbl, 64); }inline void PlotXY::AddCurve(char const * Name){ // Default properties CurveProps cp = { CT_POINTS, FL_BLACK, FL_SOLID, 1, 1, _hb*2 }; snprintf (cp.Nam, 256, "%s", Name); // Add curve _X.Push(NULL); _Y.Push(NULL); _C.Push(cp);}inline void PlotXY::AddCurve(Array<double> const * X, Array<double> const * Y, char const * Name){ // Check if (Y->Size()!=X->Size()) throw new Fatal("PlotXY::AddCurve: X (sz=%d) and Y (sz=%d) arrays must have the same size",X->Size(), Y->Size()); // Default properties CurveProps cp = { CT_POINTS, FL_BLACK, FL_SOLID, 1, 1, _hb*2 }; snprintf (cp.Nam, 256, "%s", Name); // Add curve _X.Push(X); _Y.Push(Y); _C.Push(cp);}inline void PlotXY::SetXY(size_t i, Array<double> const * X, Array<double> const * Y){ // Check if (i<0 || i>=_X.Size()) throw new Fatal("PlotXY::SetXY: There is no Curve # %d added to this object",i); // Check if (X!=NULL && Y!=NULL) { if (Y->Size()!=X->Size()) throw new Fatal("PlotXY::SetXY: X (sz=%d) and Y (sz=%d) arrays must have the same size",X->Size(), Y->Size()); } // Set curve _X[i] = X; _Y[i] = Y;}inline void PlotXY::DelCurve(size_t i){ // Check if (i<0 || i>=_X.Size()) throw new Fatal("PlotXY::DelCurve: There is no Curve # %d added to this object",i); // Remove _X.Remove(i); _Y.Remove(i); _C.Remove(i);}inline CurveProps & PlotXY::SetCurve(size_t i){ // Check if (i<0 || i>=_X.Size()) throw new Fatal("PlotXY::SetCurve: There is no Curve # %d added to this object",i); // Return properties return _C[i];}inline void PlotXY::CalcSF(){ _Xmin = 0.0; _Ymin = 0.0; _Xmax = 1.0; _Ymax = 1.0; size_t k = 0; while (k<_X.Size()) { // Check input if (_X[k]==NULL) break; if (_Y[k]==NULL) break; if (_X[k]->Size()<2) break; if (_Y[k]->Size()<2) break; // Bounding box if (k==0) { _Xmin = (*_X[k])[0]; _Ymin = (*_Y[k])[0]; _Xmax = (*_X[k])[1]; _Ymax = (*_Y[k])[1]; } for (size_t i=0; i<_X[k]->Size(); ++i) { if ((*_X[k])[i]<_Xmin) _Xmin = (*_X[k])[i]; if ((*_Y[k])[i]<_Ymin) _Ymin = (*_Y[k])[i]; if ((*_X[k])[i]>_Xmax) _Xmax = (*_X[k])[i]; if ((*_Y[k])[i]>_Ymax) _Ymax = (*_Y[k])[i]; } // Next curve k++; } // Scale factors if (fabs(_Xmax-_Xmin)<=DBL_EPSILON) { Array<double> lim; _pretty (_Xmin, _Xmax, 3, lim); _Xmin = lim[0]; _Xmax = lim[lim.Size()-1]; } if (fabs(_Ymax-_Ymin)<=DBL_EPSILON) { Array<double> lim; _pretty (_Ymin, _Ymax, 3, lim); _Ymin = lim[0]; _Ymax = lim[lim.Size()-1]; } _sfX = static_cast<double>((w()-_pahpad)/(_Xmax-_Xmin)); _sfY = static_cast<double>((h()-_pavpad)/(_Ymax-_Ymin)); if (_eqsf) { double sf = (_sfX>_sfY ? _sfY : _sfX); _sfX = sf; _sfY = sf; }}inline void PlotXY::DrawRulers(){ if (_brt>0) // bottom ruler { // variables int yi = y()+h()-_brt-_blegh; // initial y-position (screen coordinates) int X = x()+_lrt; // position int W = w()-_rlegw-_lrt-_rrt; // width // background fl_color (FL_WHITE); fl_rectf (x(), yi, w(), _brt); // ticks const int len = 9; // tick length Array<double> ticks; // ticks position char buf[256]; // buffer for ticks text _pretty (_Xmin, _Xmax, _bnt, ticks); // find ticks position fl_color (FL_BLACK); // set color fl_line_style (FL_SOLID, 1); // set line style fl_font (0,_ticfsz); // set font for ticks for (size_t i=0; i<ticks.Size(); ++i) { int xi = _x(ticks[i]); // tick initial x-position (screen coordinates) if (xi>=X && xi<=X+W) { snprintf (buf, 256, _btifmt, ticks[i]); // format text fl_line (xi, yi, xi, yi+len); // draw tick mark fl_draw (buf, xi, yi+len+_ticfsz/2+1, 0, 0, FL_ALIGN_CENTER); // draw tick text } } // label
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -