MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/gui/plotxy.h
Go to the documentation of this file.
00001 /************************************************************************
00002  * MechSys - Open Library for Mechanical Systems                        *
00003  * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand                   *
00004  * Copyright (C) 2009 Sergio Galindo                                    *
00005  *                                                                      *
00006  * This program is free software: you can redistribute it and/or modify *
00007  * it under the terms of the GNU General Public License as published by *
00008  * the Free Software Foundation, either version 3 of the License, or    *
00009  * any later version.                                                   *
00010  *                                                                      *
00011  * This program is distributed in the hope that it will be useful,      *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
00014  * GNU General Public License for more details.                         *
00015  *                                                                      *
00016  * You should have received a copy of the GNU General Public License    *
00017  * along with this program. If not, see <http://www.gnu.org/licenses/>  *
00018  ************************************************************************/
00019 
00020 #ifndef MECHSYS_PLOTXY_H
00021 #define MECHSYS_PLOTXY_H
00022 
00023 // STL
00024 #include <cmath>   // for ceil and floor
00025 #include <cfloat>  // for DBL_EPSILON
00026 #include <cstring> // for strncpy
00027 #include <iostream>
00028 #include <map>
00029 
00030 // FLTK
00031 #ifdef USE_FLTK
00032   #include <FL/Fl.H>
00033   #include <FL/Fl_Group.H>
00034   #include <FL/Enumerations.H> // for Fl_Color
00035 #endif
00036 
00037 // wxWidgets
00038 #ifdef USE_WXWIDGETS
00039   #include <wx/window.h>
00040 #endif
00041 
00042 // MechSys
00043 #include <mechsys/util/fatal.h>
00044 #include <mechsys/util/array.h>
00045 #include <mechsys/gui/common.h>
00046 
00047 namespace GUI
00048 {
00049 
00050 enum CurveType { CT_POINTS, CT_LINES, CT_BOTH };
00051 
00052 struct CurveProps
00053 {
00054     CurveType Typ;      
00055     PenType   Pen;      
00056     int       Pch;      
00057     int       Psz;      
00058     bool      LstY;     
00059     char      Nam[256]; 
00060 };
00061 
00062 #if defined(USE_FLTK)
00063 class PlotXY : public Fl_Group
00064 #elif defined(USE_WXWIDGETS)
00065 class PlotXY : public wxWindow
00066 #endif
00067 {
00068 public:
00069     /* Constructor. */
00070 #if defined(USE_FLTK)
00071     PlotXY (int xmin, int ymin, int width, int height, char const * Title=NULL, char const * Xlbl=NULL, char const * Ylbl=NULL); // Screen coordinates
00072 #elif defined(USE_WXWIDGETS)
00073     PlotXY (wxWindow * Parent, char const * Title=NULL, char const * Xlbl=NULL, char const * Ylbl=NULL);
00074 #endif
00075 
00076     /* Destructor. */
00077     virtual ~PlotXY () {}
00078 
00079     // Methods
00080     CurveProps & AddCurve   (char const * Name);                                                   
00081     CurveProps & AddCurve   (Array<double> const * X, Array<double> const * Y, char const * Name); 
00082     CurveProps & SetXY      (size_t i, Array<double> const * X, Array<double> const * Y);          
00083     void         DelCurves  ();                                                                    
00084     void         Redraw     ();                                                                    
00085 
00086     // Set methods
00087     PlotXY & SetBTicksFmt (char const * Fmt="%4.1f") { strcpy (_btifmt, Fmt); return (*this); } 
00088     PlotXY & SetLTicksFmt (char const * Fmt="%3.1f") { strcpy (_ltifmt, Fmt); return (*this); } 
00089     PlotXY & SetXlbl      (char const * Xlbl)        { strcpy (_blbl,  Xlbl); return (*this); } 
00090     PlotXY & SetYlbl      (char const * Ylbl)        { strcpy (_llbl,  Ylbl); return (*this); } 
00091 
00092     // Auxiliary methods
00093     void SetMaxLegIconsPerRow (int n);
00094 
00095     // Draw methods (internal)
00096     void CalcSF     ();                   
00097     void DrawRulers (DeviceContext & DC); 
00098     void DrawLegend (DeviceContext & DC); 
00099     void DrawCurves (DeviceContext & DC); 
00100 #if defined(USE_FLTK)
00101     void draw ();                         
00102 #elif defined(USE_WXWIDGETS)
00103     void OnPaint           (wxPaintEvent & Event); 
00104     void OnEraseBackground (wxEraseEvent & Event) { /* Empty implementation to prevent flicker */ }
00105 #endif
00106 
00107     // Settings
00108     bool EqSF;      
00109     bool Grid;      
00110     bool RecSF;     
00111     bool WFrame;    
00112     int  BNumTck;   
00113     int  LNumTck;   
00114     int  TicFsz;    
00115     int  LblFsz;    
00116     int  TitFsz;    
00117     bool LegAtBot;  
00118     int  LegHei;    
00119     int  LegWid;    
00120     bool CompactBR; 
00121     int  DefPsz;    
00122     int  LRth;      
00123     int  RRth;      
00124     int  BRth;      
00125     int  TRth;      
00126     int  DelHB;     
00127     int  DelVB;     
00128     int  TicLen;    
00129     int  LinLen;    
00130     int  LinDx;     
00131     bool ShowLastY; 
00132 
00133     // Data
00134     Array<CurveProps> C;        
00135     FontType          LblFnt;   
00136     FontType          TitFnt;   
00137     FontType          TicFnt;   
00138     PenType           PLPen;    
00139     PenType           BRPen;    
00140     PenType           TRPen;    
00141     PenType           LRPen;    
00142     PenType           RRPen;    
00143     PenType           LEPen;    
00144     PenType           GrdPen;   
00145     Array<double>     BTicks;   
00146     Array<double>     LTicks;   
00147 
00148 private:
00149     // Data
00150     double _sfX;        
00151     double _sfY;        
00152     bool   _sfok;       
00153     double _Xmin;       
00154     double _Ymin;       
00155     double _Xmax;       
00156     double _Ymax;       
00157     char   _btifmt[16]; 
00158     char   _ltifmt[16]; 
00159     char   _title[256]; 
00160     char   _blbl[64];   
00161     char   _llbl[64];   
00162     int    _bhpad;      
00163     int    _bvpad;      
00164     int    _pahpad;     
00165     int    _pavpad;     
00166     int    _hlegicon;   
00167     int    _nlegicon;   
00168     int    _nlegrows;   
00169 
00170 #if defined(USE_WXWIDGETS)
00171     DECLARE_EVENT_TABLE()
00172 #endif
00173 
00174     // Curves
00175     Array<Array<double> const*> _X; 
00176     Array<Array<double> const*> _Y; 
00177 
00178 #if defined(USE_WXWIDGETS)
00179     int x() const { return 0; }
00180     int y() const { return 0; }
00181     int w() const { int wi,he; GetClientSize(&wi,&he); return wi; }
00182     int h() const { int wi,he; GetClientSize(&wi,&he); return he; }
00183 #endif
00184 
00185     // Private Methods
00186     int  _x      (double X) const { return static_cast<int>((x()+1+LRth+DelHB)              +_sfX*(X-_Xmin)); } 
00187     int  _y      (double Y) const { return static_cast<int>((y()+1+TRth+DelVB)+(h()-_pavpad)-_sfY*(Y-_Ymin)); } 
00188     int  _l      (double L) const { return static_cast<int>((_sfX>_sfY?_sfY:_sfX)*L); } 
00189     void _pretty (double Lo, double Hi, int nDiv, Array<double> & Vals);                
00190 
00191 }; // class PlotXY
00192 
00193 
00195 
00196 
00197 #if defined(USE_FLTK)
00198 inline PlotXY::PlotXY (int xmin, int ymin, int width, int height, char const * Title, char const * Xlbl, char const * Ylbl)
00199     : Fl_Group (xmin,ymin,width,height,0),
00200 #elif defined(USE_WXWIDGETS)
00201 inline PlotXY::PlotXY (wxWindow * Parent, char const * Title, char const * Xlbl, char const * Ylbl)
00202     : wxWindow (Parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE),
00203 #endif
00204       EqSF      (false),
00205       Grid      (true),
00206       RecSF     (true),
00207       WFrame    (true),
00208       BNumTck   (10),
00209       LNumTck   (10),
00210       TicFsz    (10),
00211       LblFsz    (12),
00212       TitFsz    (14),
00213       LegAtBot  (true),
00214       LegHei    (30),
00215       LegWid    (0),
00216       CompactBR (true),
00217       DefPsz    (8),
00218       LRth      (40),
00219       RRth      (5),
00220       BRth      (CompactBR ? 20 : 20+TicFsz),
00221       TRth      (18),
00222       DelHB     (6),
00223       DelVB     (6),
00224       TicLen    (9),
00225       LinLen    (40),
00226       LinDx     (20),
00227       ShowLastY (true),
00228       _sfX      (1.0),
00229       _sfY      (1.0),
00230       _sfok     (false),
00231       _Xmin     (0.0),
00232       _Ymin     (0.0),
00233       _Xmax     (1.0),
00234       _Ymax     (1.0),
00235       _hlegicon (LegHei/2),
00236       _nlegicon (-1),
00237       _nlegrows (1)
00238 {
00239 #ifdef USE_FLTK
00240     end();
00241 #endif
00242 
00243     // Set dependent constants
00244     _bhpad  = LRth+RRth+(LegAtBot ? 0 : LegWid);
00245     _bvpad  = BRth+TRth+(LegAtBot ? LegHei : 0);
00246     _pahpad = _bhpad+2+2*DelHB;
00247     _pavpad = _bvpad+2+2*DelVB;
00248 
00249     // Set tick number formats
00250     strcpy (_btifmt, "%g");
00251     strcpy (_ltifmt, "%g");
00252 
00253     // Set title
00254     if (Title==NULL) { strncpy (_title, "X-Y plot", 8); _title[8]='\0'; }
00255     else               strncpy (_title, Title, 256);
00256 
00257     // Set x-label
00258     if (Xlbl==NULL) { strncpy (_blbl, "X", 1); _blbl[1]='\0'; }
00259     else              strncpy (_blbl, Xlbl, 64);
00260 
00261     // Set y-label
00262     if (Ylbl==NULL) { strncpy (_llbl, "Y", 1);  _llbl[1]='\0'; }
00263     else              strncpy (_llbl, Ylbl, 64);
00264 
00265     // Settings
00266     LblFnt.Set ("arial", LblFsz, false, false);
00267     TitFnt.Set ("arial", TitFsz, true,  false);
00268     TicFnt.Set ("arial", TicFsz, false, false);
00269     PLPen .Set (255,255,255);
00270     LEPen .Set (205,217,222);
00271     BRPen .Set (205,217,222);
00272     TRPen .Set (205,217,222);
00273     LRPen .Set (205,217,222);
00274     RRPen .Set (205,217,222);
00275     GrdPen.Set (140,140,140, "dash");
00276 }
00277 
00278 inline CurveProps & PlotXY::AddCurve (char const * Name)
00279 {
00280     // Default properties
00281     CurveProps cp = { CT_POINTS, PenType(), /*Pch*/1, DefPsz, true };
00282     snprintf (cp.Nam, 256, "%s", Name);
00283 
00284     // Add curve
00285     _X.Push(NULL);
00286     _Y.Push(NULL);
00287      C.Push(cp);
00288 
00289     return C[C.Size()-1];
00290 }
00291 
00292 inline CurveProps & PlotXY::AddCurve (Array<double> const * X, Array<double> const * Y, char const * Name)
00293 {
00294     // Check
00295     if (X!=NULL && Y!=NULL)
00296     {
00297         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());
00298     }
00299     else throw new Fatal("PlotXY::AddCurve: X and Y must NOT be NULL");
00300 
00301     // Default properties
00302     CurveProps cp = { CT_POINTS, PenType(), /*Pch*/1, DefPsz, true };
00303     snprintf (cp.Nam, 256, "%s", Name);
00304 
00305     // Add curve
00306     _X.Push(X);
00307     _Y.Push(Y);
00308      C.Push(cp);
00309 
00310     return C[C.Size()-1];
00311 }
00312 
00313 inline CurveProps & PlotXY::SetXY (size_t i, Array<double> const * X, Array<double> const * Y)
00314 {
00315     // Check
00316     if (X!=NULL && Y!=NULL)
00317     {
00318         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());
00319     }
00320     else throw new Fatal("PlotXY::SetXY: X and Y must NOT be NULL");
00321     if (i<0 || i>=_X.Size()) throw new Fatal("PlotXY::SetXY: There is no Curve # %d added to this object",i);
00322 
00323     // Set curve
00324     _X[i] = X;
00325     _Y[i] = Y;
00326 
00327     return C[i];
00328 }
00329 
00330 inline void PlotXY::DelCurves ()
00331 {
00332     _X.Resize(0);
00333     _Y.Resize(0);
00334      C.Resize(0);
00335 }
00336 
00337 inline void PlotXY::Redraw ()
00338 {
00339 #if defined(USE_FLTK)
00340     redraw();
00341     Fl::wait(0);
00342 #elif defined(USE_WXWIDGETS)
00343     Refresh();
00344     Update();
00345 #endif
00346 }
00347 
00348 inline void PlotXY::SetMaxLegIconsPerRow (int n)
00349 {
00350     if (_X.Size()<1) return;
00351     int ncurves = static_cast<int>(_X.Size());
00352     _nlegicon = n;
00353     _nlegrows = ncurves/n + (ncurves%n>0 ? 1 : 0);
00354     LegHei    = _nlegrows*_hlegicon + _hlegicon;
00355     _bvpad    = BRth+TRth+(LegAtBot ? LegHei : 0);
00356     _pavpad   = _bvpad+2+2*DelVB;
00357 }
00358 
00359 inline void PlotXY::CalcSF ()
00360 {
00361     // initialize min/max
00362     bool found = false;
00363     for (size_t k=0; k<_X.Size(); ++k)
00364     {
00365         if (_X[k]!=NULL && _Y[k]!=NULL)
00366         {
00367             if (_X[k]->Size()>1 && _Y[k]->Size()>1)
00368             {
00369                 _Xmin = (*_X[k])[0];
00370                 _Ymin = (*_Y[k])[0];
00371                 _Xmax = (*_X[k])[1];
00372                 _Ymax = (*_Y[k])[1];
00373                 found = true;
00374                 break;
00375             }
00376         }
00377     }
00378     if (!found)
00379     {
00380         _Xmin = 0.0;
00381         _Ymin = 0.0;
00382         _Xmax = 1.0;
00383         _Ymax = 1.0;
00384     }
00385 
00386     // find min/max
00387     for (size_t k=0; k<_X.Size(); ++k)
00388     {
00389         // Check input
00390         if (_X[k]==NULL     || _Y[k]==NULL    ) continue;
00391         if (_X[k]->Size()<2 || _Y[k]->Size()<2) continue;
00392 
00393         for (size_t i=0; i<_X[k]->Size(); ++i)
00394         {
00395             if ((*_X[k])[i]<_Xmin) _Xmin = (*_X[k])[i];
00396             if ((*_Y[k])[i]<_Ymin) _Ymin = (*_Y[k])[i];
00397             if ((*_X[k])[i]>_Xmax) _Xmax = (*_X[k])[i];
00398             if ((*_Y[k])[i]>_Ymax) _Ymax = (*_Y[k])[i];
00399         }
00400     }
00401 
00402     // Scale factors
00403     if (fabs(_Xmax-_Xmin)<=DBL_EPSILON)
00404     {
00405         Array<double> lim;
00406         _pretty (_Xmin, _Xmax, 3, lim);
00407         _Xmin = lim[0];
00408         _Xmax = lim[lim.Size()-1];
00409     }
00410     if (fabs(_Ymax-_Ymin)<=DBL_EPSILON)
00411     {
00412         Array<double> lim;
00413         _pretty (_Ymin, _Ymax, 3, lim);
00414         _Ymin = lim[0];
00415         _Ymax = lim[lim.Size()-1];
00416     }
00417     _sfX = static_cast<double>((w()-_pahpad)/(_Xmax-_Xmin));
00418     _sfY = static_cast<double>((h()-_pavpad)/(_Ymax-_Ymin));
00419     if (EqSF)
00420     {
00421         double sf = (_sfX>_sfY ? _sfY : _sfX);
00422         _sfX = sf;
00423         _sfY = sf;
00424     }
00425 
00426     // ticks
00427     _pretty (_Xmin, _Xmax, BNumTck, BTicks);
00428     _pretty (_Ymin, _Ymax, LNumTck, LTicks);
00429 }
00430 
00431 inline void PlotXY::DrawRulers (DeviceContext & DC)
00432 {
00433     if (BRth>0) // bottom ruler
00434     {
00435         // variables
00436         int yi = y()+h()-BRth-LegHei;  // initial y-position (screen coordinates)
00437         int X  = x()+LRth;             // position
00438         int W  = w()-LegWid-LRth-RRth; // width
00439 
00440         // background
00441         BRPen.Activate (DC);
00442         GUI_DRAW_FRECT (DC, x(), yi, w(), BRth);
00443 
00444         // ticks
00445         char buf[256]; // buffer for ticks text
00446         Black .Activate (DC);
00447         TicFnt.Activate (DC);
00448         for (size_t i=0; i<BTicks.Size(); ++i)
00449         {
00450             int xi = _x(BTicks[i]); // tick initial x-position (screen coordinates)
00451             if (xi>=X && xi<=X+W)
00452             {
00453                 snprintf (buf, 256, _btifmt, BTicks[i]);                        // format text
00454                 GUI_DRAW_LINE (DC, xi, yi, xi, yi+TicLen);                      // draw tick mark
00455                 GUI_DRAW_TEXT (DC, buf, xi, yi+TicLen+TicFsz/2+1, /*center*/0); // draw tick text
00456             }
00457         }
00458 
00459         // label 
00460         if (!CompactBR) 
00461         {
00462             LblFnt.Activate (DC);
00463             GUI_DRAW_TEXT (DC, _blbl, X+W/2, yi+TicLen+3*TicFsz/2+1, /*center*/0); // draw label
00464         }
00465     }
00466     if (LRth>0) // left ruler
00467     {
00468         // variables
00469         int Y = y()+TRth;             // position
00470         int H = h()-TRth-BRth-LegHei; // height
00471 
00472         // background
00473         LRPen.Activate (DC);
00474         GUI_DRAW_FRECT (DC, x(), Y, LRth, H);
00475 
00476         // ticks
00477         char buf[256]; // buffer for ticks text
00478         Black .Activate (DC);
00479         TicFnt.Activate (DC);
00480         for (size_t i=0; i<LTicks.Size(); ++i)
00481         {
00482             int xi = x()+LRth-TicLen; // tick initial x-position (screen coordinates)
00483             int yi = _y(LTicks[i]);   // tick initial y-position (screen coordinates)
00484             if (yi>=Y && yi<=Y+H)
00485             {
00486                 snprintf (buf, 256, _ltifmt, LTicks[i]); // format text
00487                 GUI_DRAW_LINE (DC, xi, yi, xi+TicLen, yi); // draw tick mark
00488                 GUI_DRAW_TEXT (DC, buf, x()+LRth-TicLen-2, yi, /*right*/1); // draw tick text
00489             }
00490         }
00491     }
00492     if (TRth>0) // top ruler
00493     {
00494         // background
00495         TRPen.Activate (DC);
00496         GUI_DRAW_FRECT (DC, x(), y(), w(), TRth); // (x()+LRth, y(), w()-RRth-LRth, TRth)
00497 
00498         // draw left label
00499         Black .Activate (DC);
00500         LblFnt.Activate (DC);
00501         GUI_DRAW_TEXT (DC, _llbl, x()+2, y()+TRth-6, /*left*/-1);
00502 
00503         // left ruler label and title
00504         TitFnt.Activate (DC);
00505         GUI_DRAW_TEXT (DC, _title, x()+w()/2, y()+TRth-TitFsz/2-2, /*center*/0); // draw title
00506     }
00507     if (RRth>0) // right ruler
00508     {
00509         // background
00510         RRPen.Activate (DC);
00511         GUI_DRAW_FRECT (DC, x()+w()-RRth-LegWid, y()+TRth, RRth, h()-TRth-BRth-LegHei);
00512     }
00513 }
00514 
00515 inline void PlotXY::DrawLegend (DeviceContext & DC)
00516 {
00517     // Variables
00518     char buf[256];
00519     int  xi   = x()+5;
00520     int  yi   = y()+h()-_hlegicon*_nlegrows;
00521     int  ilen = 5+LinLen+2; // icon length
00522     int  xf   = xi+30;
00523 
00524     // Draw legend
00525     if (LegAtBot) // bottom legend
00526     {
00527         // clear background
00528         LEPen.Activate (DC);
00529         GUI_DRAW_FRECT (DC, x(), y()+h()-LegHei, w(), LegHei);
00530 
00531         // Draw legend
00532         if (_X.Size()>=1 && _Y.Size()>=1)
00533         {
00534             int legcol = 0;
00535             for (size_t k=0; k<_X.Size(); ++k)
00536             {
00537                 // Check
00538                 if (_X[k]==NULL || _Y[k]==NULL) return;
00539 
00540                 // Draw points
00541                 if (C[k].Typ==CT_POINTS || C[k].Typ==CT_BOTH)
00542                 {
00543                     C[k].Pen.Activate (DC, /*ForceSolid*/true);
00544                     if (C[k].Pch==1) // open circle
00545                     {
00546                         GUI_DRAW_CIRCLE (DC, xi+LinLen/2, yi, C[k].Psz/2)
00547                     }
00548                     else if (C[k].Pch==2) // filled circle
00549                     {
00550                         GUI_DRAW_FCIRCLE (DC, xi+LinLen/2, yi, C[k].Psz/2)
00551                     }
00552                     else if (C[k].Pch==3) // open square
00553                     {
00554                         GUI_DRAW_SQUARE (DC, xi+LinLen/2, yi, C[k].Psz)
00555                     }
00556                     else if (C[k].Pch==4) // filled square
00557                     {
00558                         GUI_DRAW_FSQUARE (DC, xi+LinLen/2, yi, C[k].Psz)
00559                     }
00560                 }
00561 
00562                 // Draw lines
00563                 if (C[k].Typ==CT_LINES || C[k].Typ==CT_BOTH)
00564                 {
00565                     C[k].Pen.Activate (DC);
00566                     GUI_DRAW_LINE (DC, xi, yi, xf, yi);
00567                 }
00568 
00569                 // Draw names
00570                 snprintf (buf, 256, "%s", C[k].Nam); // format text
00571                 Black .Activate (DC);
00572                 LblFnt.Activate (DC);
00573                 GUI_DRAW_TEXT (DC, buf, xf+2, yi, /*left*/-1);
00574 
00575                 // Next curve
00576                 GUI_DRAW_ADD_WIDTH (DC,buf,xi)
00577                 xi = xi+ilen+LinDx;
00578                 xf = xi+LinLen;
00579 
00580                 // legend row position
00581                 if (_nlegicon>0)
00582                 {
00583                     if (legcol==_nlegicon-1) { legcol=-1;  xi=x()+5;  xf=xi+LinLen;  yi+=_hlegicon; }
00584                     legcol++;
00585                 }
00586             }
00587         }
00588         if (CompactBR)
00589         {
00590             LblFnt.Activate (DC);
00591             GUI_DRAW_TEXT (DC, _blbl, x()+w()-3, y()+h()-_hlegicon*_nlegrows, /*right*/1); // draw label
00592             //GUI_DRAW_TEXT (DC, _blbl, x()+w()-3, y()+h()-TicFsz/2-3, /*right*/1); // draw label
00593         }
00594     }
00595     else
00596     {
00597         // TODO
00598     }
00599 }
00600 
00601 inline void PlotXY::DrawCurves (DeviceContext & DC)
00602 {
00603     // clear background
00604     PLPen.Activate (DC);
00605     GUI_DRAW_FRECT (DC, x()+LRth, y()+TRth, w()-_bhpad, h()-_bvpad);
00606 
00607     // draw grid
00608     if (Grid)
00609     {
00610         GrdPen.Activate (DC);
00611         for (size_t i=0; i<BTicks.Size(); ++i)
00612         {
00613             int xi = _x(BTicks[i]); // tick initial x-position (screen coordinates)
00614             GUI_DRAW_LINE (DC, xi, y()+TRth, xi, y()+h()-BRth-LegHei)
00615         }
00616         for (size_t i=0; i<LTicks.Size(); ++i)
00617         {
00618             int yi = _y(LTicks[i]); // tick initial y-position (screen coordinates)
00619             GUI_DRAW_LINE (DC, x()+LRth, yi, x()+w()-RRth, yi)
00620         }
00621     }
00622 
00623     // draw curves
00624     if (_X.Size()>=1 && _Y.Size()>=1)
00625     {
00626         for (size_t k=0; k<_X.Size(); ++k)
00627         {
00628             // Check
00629             if (_X[k]==NULL || _Y[k]==NULL) continue;
00630 
00631             // Draw points
00632             if (C[k].Typ==CT_POINTS || C[k].Typ==CT_BOTH)
00633             {
00634                 C[k].Pen.Activate (DC, /*ForceSolid*/true);
00635                 if (C[k].Pch==1) // open circle
00636                 {
00637                     for (size_t i=0; i<_X[k]->Size(); ++i)
00638                         GUI_DRAW_CIRCLE (DC, _x((*_X[k])[i]), _y((*_Y[k])[i]), C[k].Psz/2)
00639                 }
00640                 else if (C[k].Pch==2) // filled circle
00641                 {
00642                     for (size_t i=0; i<_X[k]->Size(); ++i)
00643                         GUI_DRAW_FCIRCLE (DC, _x((*_X[k])[i]), _y((*_Y[k])[i]), C[k].Psz/2)
00644                 }
00645                 else if (C[k].Pch==3) // open square
00646                 {
00647                     for (size_t i=0; i<_X[k]->Size(); ++i)
00648                         GUI_DRAW_SQUARE (DC, _x((*_X[k])[i]), _y((*_Y[k])[i]), C[k].Psz)
00649                 }
00650                 else if (C[k].Pch==4) // filled square
00651                 {
00652                     for (size_t i=0; i<_X[k]->Size(); ++i)
00653                         GUI_DRAW_FSQUARE (DC, _x((*_X[k])[i]), _y((*_Y[k])[i]), C[k].Psz)
00654                 }
00655             }
00656 
00657             // Draw lines
00658             if (C[k].Typ==CT_LINES || C[k].Typ==CT_BOTH)
00659             {
00660                 if (_X[k]->Size()>1)
00661                 {
00662                     C[k].Pen.Activate (DC);
00663                     for (size_t i=0; i<_X[k]->Size()-1; ++i)
00664                         GUI_DRAW_LINE (DC, _x((*_X[k])[i]), _y((*_Y[k])[i]), _x((*_X[k])[i+1]), _y((*_Y[k])[i+1]))
00665                 }
00666             }
00667 
00668             // Draw text
00669             if (C[k].LstY)
00670             {
00671                 if (_X[k]->Size()>1 && ShowLastY)
00672                 {
00673                     char buf[256];
00674                     //snprintf (buf, 250, "%g, %g", (*_X[k])[_X[k]->Size()-1], (*_Y[k])[_X[k]->Size()-1]);
00675                     snprintf (buf, 250, "y=%g", (*_Y[k])[_X[k]->Size()-1]);
00676                     Black .Activate (DC);
00677                     TicFnt.Activate (DC);
00678                     GUI_DRAW_TEXT (DC, buf, _x((*_X[k])[_X[k]->Size()-1]), _y((*_Y[k])[_X[k]->Size()-1]), /*right*/1)
00679                 }
00680             }
00681         }
00682     }
00683 }
00684 
00685 #if defined(USE_FLTK)
00686 inline void PlotXY::draw ()
00687 #elif defined(USE_WXWIDGETS)
00688 inline void PlotXY::OnPaint (wxPaintEvent & Event)
00689 #endif
00690 {
00691     // get device context
00692 #if defined(USE_FLTK)
00693     DeviceContext dc;
00694 #elif defined(USE_WXWIDGETS)
00695     wxBufferedPaintDC dc(this);
00696     PrepareDC (dc);
00697 #endif
00698 
00699     // Calculate scale factors and draw rulers
00700     if (RecSF || !_sfok)
00701     {
00702         CalcSF     ();
00703         DrawRulers (static_cast<DeviceContext&>(dc));
00704         DrawLegend (static_cast<DeviceContext&>(dc));
00705         _sfok = true;
00706     }
00707 
00708     // Draw Curves
00709     DrawCurves (static_cast<DeviceContext&>(dc));
00710 
00711     // Draw inner border
00712     Black.Activate (static_cast<DeviceContext&>(dc));
00713     GUI_DRAW_RECT  (dc, x()+LRth, y()+TRth, w()-_bhpad, h()-_bvpad);
00714 
00715     // Draw an all-around frame
00716     if (WFrame) GUI_DRAW_RECT (dc, x(), y(), w(), h());
00717 }
00718 
00719 #if defined(USE_WXWIDGETS)
00720 BEGIN_EVENT_TABLE(PlotXY, wxWindow)
00721     EVT_PAINT            (PlotXY::OnPaint)
00722     EVT_ERASE_BACKGROUND (PlotXY::OnEraseBackground)
00723 END_EVENT_TABLE()
00724 #endif
00725 
00726 inline void PlotXY::_pretty (double Lo, double Hi, int nDiv, Array<double> & Vals)
00727 {
00728     // Constants
00729     const double rounding_eps   = sqrt(DBL_EPSILON);
00730     const double eps_correction = 0.0;
00731     const double shrink_sml     = 0.75;
00732     const double h              = 1.5;
00733     const double h5             = 0.5+1.5*h;
00734 
00735     // Local variables
00736     int    min_n = static_cast<int>(nDiv)/static_cast<int>(3);
00737     double lo    = Lo;
00738     double hi    = Hi;
00739     double dx    = hi-lo;
00740     double cell  = 1;    // cell := "scale" here
00741     double ub    = 0;    // upper bound on cell/unit
00742     bool   isml  = true; // is small ?
00743 
00744     // Check range
00745     if (!(dx==0 && hi==0)) // hi=lo=0
00746     {
00747         cell = (fabs(lo)>fabs(hi) ? fabs(lo) : fabs(hi));
00748         ub   = (1+(h5>=1.5*h+.5) ? 1/(1+h) : 1.5/(1+h5));
00749         isml = (dx<cell*ub*(nDiv>1 ? nDiv : 1)*DBL_EPSILON*3); // added times 3, as several calculations here
00750     }
00751 
00752     // Set cell
00753     if (isml)
00754     {
00755         if (cell>10) cell = 9 + cell/10;
00756         cell *= shrink_sml;
00757         if (min_n>1) cell /= min_n;
00758     }
00759     else 
00760     {
00761         cell = dx;
00762         if (nDiv>1) cell /= nDiv;
00763     }
00764     if      (cell<20*DBL_MIN) cell = 20*DBL_MIN; // very small range.. corrected
00765     else if (cell*10>DBL_MAX) cell = .1*DBL_MAX; // very large range.. corrected
00766 
00767     // Find base and unit
00768     double base = pow(10., floor(log10(cell))); // base <= cell < 10*base
00769     double unit = base;
00770     if ((ub = 2*base)-cell <  h*(cell-unit)) { unit = ub;
00771     if ((ub = 5*base)-cell < h5*(cell-unit)) { unit = ub;
00772     if ((ub =10*base)-cell <  h*(cell-unit))   unit = ub; }}
00773 
00774     // Find number of 
00775     double ns = floor (lo/unit+rounding_eps);
00776     double nu = ceil  (hi/unit-rounding_eps);
00777     if (eps_correction && (eps_correction>1 || !isml))
00778     {
00779         if (lo) lo *= (1-DBL_EPSILON); else lo = -DBL_MIN;
00780         if (hi) hi *= (1+DBL_EPSILON); else hi = +DBL_MIN;
00781     }
00782     while (ns*unit>lo+rounding_eps*unit) ns--;
00783     while (nu*unit<hi-rounding_eps*unit) nu++;
00784 
00785     // Find number of divisions
00786     int ndiv = static_cast<int>(.5+nu-ns);
00787     if (ndiv<min_n)
00788     {
00789         int k = min_n-ndiv;
00790         if (ns>=0.0)
00791         {
00792             nu += k/2;
00793             ns -= k/2 + k%2;
00794         } 
00795         else
00796         {
00797             ns -= k/2;
00798             nu += k/2 + k%2;
00799         }
00800         ndiv = min_n;
00801     }
00802     ndiv++;
00803 
00804     // Ensure that result covers original range
00805     if (ns*unit<lo) lo = ns * unit;
00806     if (nu*unit>hi) hi = nu * unit;
00807 
00808     // Fill array
00809     const double MINZERO = sqrt(DBL_EPSILON); // Minimum value to be replaced to 0.0 in _pretty method
00810     Vals.Resize(ndiv);
00811     Vals[0] = lo;
00812     for (int i=1; i<ndiv; ++i)
00813     {
00814         Vals[i] = Vals[i-1]+unit;
00815         if (fabs(Vals[i])<MINZERO) Vals[i] = 0.0;
00816     }
00817 }
00818 
00819 }; // namespace GUI
00820 
00821 #endif // MECHSYS_PLOTXY_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines