![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
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