plotter.h

00001 /*************************************************************************************
00002  * MechSys - A C++ library to simulate (Continuum) Mechanical Systems                *
00003  * Copyright (C) 2005 Dorival de Moraes Pedroso <dorival.pedroso at gmail.com>       *
00004  * Copyright (C) 2005 Raul Dario Durand Farfan  <raul.durand at gmail.com>           *
00005  *                                                                                   *
00006  * This file is part of MechSys.                                                     *
00007  *                                                                                   *
00008  * MechSys is free software; you can redistribute it and/or modify it under the      *
00009  * terms of the GNU General Public License as published by the Free Software         *
00010  * Foundation; either version 2 of the License, or (at your option) any later        *
00011  * version.                                                                          *
00012  *                                                                                   *
00013  * MechSys is distributed in the hope that it will be useful, but WITHOUT ANY        *
00014  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A   *
00015  * PARTICULAR PURPOSE. See the GNU General Public License for more details.          *
00016  *                                                                                   *
00017  * You should have received a copy of the GNU General Public License along with      *
00018  * MechSys; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
00019  * Fifth Floor, Boston, MA 02110-1301, USA                                           *
00020  *************************************************************************************/
00021 
00022 #ifndef MECHSYS_LABTESTSIM_PLOTTER_H
00023 #define MECHSYS_LABTESTSIM_PLOTTER_H
00024 
00025 #ifdef HAVE_CONFIG_H
00026   #include "config.h"
00027 #else
00028   #ifndef REAL
00029     #define REAL double
00030   #endif
00031 #endif
00032 
00033 #include <gtkmm/dialog.h>
00034 #include <gtkmm/notebook.h>
00035 #include <gtkmm/table.h>
00036 #include <gtkmm/stock.h>
00037 #include <gtkmm/button.h>
00038 #include <gtkmm/statusbar.h>
00039 
00040 #include <plotmm/plot.h>
00041 #include <plotmm/scalediv.h>
00042 #include <plotmm/curve.h>
00043 #include <plotmm/errorcurve.h>
00044 #include <plotmm/symbol.h>
00045 #include <plotmm/paint.h>
00046 #include <plotmm/rectangle.h>
00047 
00048 #include "util/array.h"
00049 #include "util/string.h"
00050 #include "util/exception.h"
00051 #include "util/fileparser.h"
00052 #include "util/util.h"
00053 
00054 using Util::ToRad;
00055 using Util::Signal;
00056 
00057 namespace LabTestSim
00058 {
00059 
00060 // Structures
00061 struct PlotInfo // {{{
00062 {
00063     char const * Title;
00064     char const * X_label;
00065     char const * Y_label;
00066     char const * X_tag;
00067     char const * Y_tag;
00068     bool         X_ln;
00069     bool         Y_ln;
00070     bool         mult_Y; // use _cy?
00071     bool         Y_neg;
00072 }; // struct PlotInfo // }}}
00073 
00074 PlotInfo PlotterInfo[]={{"Stress-deviatoric strain   q versus Ed"   , "Ed (%)" , "q"       , "Ed", "q"  , false , false , true  , false },
00075                         {"Stress-volumetric strain   q versus Ev"   , "Ev (%)" , "q"       , "Ev", "q"  , false , false , true  , false },
00076                         {"Dilatancy   -Ev versus Ed"                , "Ed (%)" , "-Ev (%)" , "Ed", "Ev" , false , false , false , true  },
00077                         {"Compression/Expansion   -Ev versus ln(p)" , "ln(p)"  , "-Ev (%)" , "p" , "Ev" , true  , false , false , true  }};
00078 
00079 class Plotter : public Gtk::Dialog
00080 {
00081 public:
00082     // Constructor
00083     Plotter(Array<String>            const * a_DAT             ,
00084             Array<FileParser::Table> const * a_Data            ,
00085             bool                             use_Cy    = true  ,
00086             bool                             use_Marks = false ,
00087             Array< Array<int> >      const * a_Marks   = NULL  ,
00088             bool                             use_Calc  = false ,
00089             Array<FileParser::Table> const * a_Calc    = NULL  ,
00090             bool                             use_CMarks= false ,
00091             Array< Array<int> >      const * a_CMarks  = NULL  );
00092 
00093     // Destructor
00094     ~Plotter();
00095 
00096 private:
00097     // Data
00098     Array<String>         const * _names;
00099     bool                          _use_cy;     // coeficient to multiply Y values according to compression/extension
00100     bool                          _use_marks;  // Separate plots according to marks of different paths
00101     bool                          _use_calc;   // Plot calc values toghether to data values
00102     bool                          _use_cmarks; // Separate (calc) plots according to marks of different paths
00103     Gtk::Button                   _btn_close;
00104     Gtk::Notebook                 _nb;
00105     Gtk::Statusbar                _sbar;
00106     Array< Gtk::Table* >          _grids; 
00107     Array< Array<PlotMM::Plot*> > _plots; // 4 plots for each grid
00108 
00109     // Structures
00110     struct Coords
00111     {
00112         REAL * X;
00113         REAL * Y;
00114         int    size;
00115     }; // struct Coords
00116     
00117     // Methods
00118     void _setup_subplot            (int subplot_id, PlotMM::Plot * subplot);
00119     void _allocate_and_fill_coords (int subplot_id, FileParser::Table const & T, Coords & C);
00120     void _add_curves               (int subplot_id, Coords const & C, PlotMM::Plot * subplot, String const & color="blue");
00121     void _add_curves               (int subplot_id, Coords const & C, Array<int> const & Marks, PlotMM::Plot * subplot, String const & clr1="blue", String const & clr2="red");
00122     void _print_coords             (int subplot_id, int x, int y);
00123 
00124     // Callbacks
00125     void _on_close_clicked() { this->hide(); }
00126     void _on_switch_page(GtkNotebookPage * page, guint page_num);
00127     void _on_plot0_mouse_move(int x, int y, GdkEventMotion * ev);
00128     void _on_plot1_mouse_move(int x, int y, GdkEventMotion * ev);
00129     void _on_plot2_mouse_move(int x, int y, GdkEventMotion * ev);
00130     void _on_plot3_mouse_move(int x, int y, GdkEventMotion * ev);
00131 
00132 }; // class Plotter
00133 
00134 
00136 
00137 
00138 inline Plotter::Plotter(Array<String>            const * a_DAT     , // {{{
00139                         Array<FileParser::Table> const * a_Data    ,
00140                         bool                             use_Cy    ,
00141                         bool                             use_Marks ,
00142                         Array< Array<int> >      const * a_Marks   ,
00143                         bool                             use_Calc  ,
00144                         Array<FileParser::Table> const * a_Calc    ,
00145                         bool                             use_CMarks,
00146                         Array< Array<int> >      const * a_CMarks  )
00147     : _names     (a_DAT)     ,
00148       _use_cy    (use_Cy)    ,
00149       _use_marks (use_Marks) ,
00150       _use_calc  (use_Calc)  ,
00151       _use_cmarks(use_CMarks),
00152       _btn_close (Gtk::Stock::CLOSE)
00153 {
00154     // Check-up
00155     if (_names->size()!=a_Data->size())
00156         throw new Fatal(_("Plotter::SetData: Array with Data filenames must have size (%d) equal to the array with data (%d)"), _names->size(), a_Data->size());
00157     if (_names->size()<1)
00158         throw new Fatal(_("Plotter::SetData: The number of data filenames must be greater than 0"));
00159     if (_use_marks && a_Marks==NULL)
00160         throw new Fatal (_("Plotter::Plotter: When using Marks, the pointer to an array with marks (a_Marks) must be non-NULL"));
00161     if (_use_cmarks && a_CMarks==NULL)
00162         throw new Fatal (_("Plotter::Plotter: When using CMarks, the pointer to an array with cmarks (a_CMarks) must be non-NULL"));
00163 
00164     // Resize plots and grids
00165     _grids.resize(_names->size());
00166     _plots.resize(_names->size());
00167 
00168     // Loop along the number of plots
00169     for (size_t i=0; i<_names->size(); ++i)
00170     {
00171         // Allocate grids
00172         _grids[i] = new Gtk::Table (2,2, true); // true => homogeneous
00173 
00174         // Allocate and generate plots
00175         _plots[i].resize(4);
00176         for (int j=0; j<4; ++j)
00177         {
00178             // allocate
00179             _plots[i][j] = new PlotMM::Plot;
00180 
00181             // setup
00182             _setup_subplot(j, _plots[i][j]);
00183 
00184             // add data curves
00185             Coords D;
00186             _allocate_and_fill_coords(j, (*a_Data)[i], D);
00187             if (_use_marks) _add_curves(j, D, (*a_Marks)[i], _plots[i][j]);
00188             else            _add_curves(j, D,                _plots[i][j]);
00189             delete [] D.X;
00190             delete [] D.Y;
00191 
00192             // add calc curves
00193             if (_use_calc)
00194             {
00195                 Coords C;
00196                 _allocate_and_fill_coords(j, (*a_Calc)[i], C);
00197                 if (_use_cmarks) _add_curves(j, C, (*a_CMarks)[i], _plots[i][j], "LimeGreen", "OliveDrab");
00198                 else             _add_curves(j, C, _plots[i][j],                 "OliveDrab");
00199                 delete [] C.X;
00200                 delete [] C.Y;
00201             }
00202             
00203         }
00204 
00205         // Add plots to grid
00206         _grids[i]->attach((*_plots[i][0]),0,1,0,1);
00207         _grids[i]->attach((*_plots[i][1]),1,2,0,1);
00208         _grids[i]->attach((*_plots[i][2]),0,1,1,2);
00209         _grids[i]->attach((*_plots[i][3]),1,2,1,2);
00210         
00211         // Add plot widgets to notebook
00212         _nb.append_page((*_grids[i]), (*_names)[i]);
00213 
00214         // Set callbacks
00215         _plots[i][0]->signal_plot_mouse_move().connect(sigc::mem_fun(*this,&Plotter::_on_plot0_mouse_move));
00216         _plots[i][1]->signal_plot_mouse_move().connect(sigc::mem_fun(*this,&Plotter::_on_plot1_mouse_move));
00217         _plots[i][2]->signal_plot_mouse_move().connect(sigc::mem_fun(*this,&Plotter::_on_plot2_mouse_move));
00218         _plots[i][3]->signal_plot_mouse_move().connect(sigc::mem_fun(*this,&Plotter::_on_plot3_mouse_move));
00219     }
00220 
00221     // Add statusbar, button and notebook to dialog
00222     get_vbox()->pack_end(_sbar     , false, true);  // noexpand, fill
00223     get_vbox()->pack_end(_btn_close, false, false); // noexpand, nofill
00224     get_vbox()->pack_end(_nb,        true,  true);  // expand,   fill
00225     get_vbox()->set_homogeneous(false);
00226     show_all_children();
00227 
00228     // Set callbacks
00229     _btn_close.signal_clicked().connect(sigc::mem_fun(*this, &Plotter::_on_close_clicked));
00230     _nb.signal_switch_page()   .connect(sigc::mem_fun(*this, &Plotter::_on_switch_page));
00231 
00232 } // }}}
00233 
00234 inline Plotter::~Plotter() // {{{
00235 {
00236 #ifdef DO_DEBUG
00237     std::cout << "Plotter::~Plotter() Destructor called\n";
00238 #endif
00239     for (size_t i=0; i<_plots.size(); ++i)
00240     {
00241         // Delete grids
00242         delete _grids[i];
00243 
00244         // Delete plots
00245         for (int j=0; j<4; ++j)
00246             delete _plots[i][j];
00247     }
00248 } // }}}
00249 
00250 inline void Plotter::_setup_subplot(int subplot_id, PlotMM::Plot * subplot) // {{{
00251 {
00252     // Set title and axis labels
00253     subplot->title()->set_text(PlotterInfo[subplot_id].Title);
00254     subplot->title()->set_enabled(true);
00255     subplot->label(PlotMM::AXIS_BOTTOM)->set_text(PlotterInfo[subplot_id].X_label);
00256     subplot->label(PlotMM::AXIS_LEFT  )->set_text(PlotterInfo[subplot_id].Y_label);
00257     subplot->label(PlotMM::AXIS_BOTTOM)->set_enabled(true);
00258     subplot->label(PlotMM::AXIS_LEFT  )->set_enabled(true);
00259 
00260     // Set scale style
00261     subplot->scale(PlotMM::AXIS_TOP   )->set_enabled  (false);
00262     subplot->scale(PlotMM::AXIS_RIGHT )->set_enabled  (false);
00263     subplot->scale(PlotMM::AXIS_LEFT  )->set_enabled  (true);
00264     subplot->scale(PlotMM::AXIS_BOTTOM)->set_enabled  (true);
00265     subplot->scale(PlotMM::AXIS_LEFT  )->set_autoscale(true);
00266     subplot->scale(PlotMM::AXIS_BOTTOM)->set_autoscale(true);
00267 
00268 } // }}}
00269 
00270 inline void Plotter::_allocate_and_fill_coords(int subplot_id, FileParser::Table const & T, Coords & C) // {{{
00271 {
00272     // X values
00273     FileParser::Table::const_iterator x_it = T.find(PlotterInfo[subplot_id].X_tag);
00274     if (x_it==T.end()) throw new Fatal(_("Plotter::_allocate_and_fill_X_and_Y: Could not find tag < %s >"), PlotterInfo[subplot_id].X_tag);
00275 
00276     // Y values
00277     FileParser::Table::const_iterator y_it = T.find(PlotterInfo[subplot_id].Y_tag);
00278     if (y_it==T.end()) throw new Fatal(_("Plotter::_allocate_and_fill_X_and_Y: Could not find tag < %s >"), PlotterInfo[subplot_id].Y_tag);
00279 
00280     // Cy
00281     String cy_tag;
00282     FileParser::Table::const_iterator tmp1_it = T.find("sin3th");
00283     if (tmp1_it==T.end())
00284     {
00285         FileParser::Table::const_iterator tmp2_it = T.find("th");
00286         if (tmp2_it==T.end()) cy_tag = "sin3th_or_th_was_not_found";
00287         else                  cy_tag = "th";
00288     }
00289     else cy_tag = "sin3th";
00290     FileParser::Table::const_iterator cy_it = T.find(cy_tag);
00291 
00292     // Allocate and fill X and Y arrays
00293     C.size = x_it->second.size();
00294     C.X = new REAL [C.size];
00295     C.Y = new REAL [C.size];
00296     for (int j=0; j<C.size; ++j)
00297     {
00298         // X values
00299         if (PlotterInfo[subplot_id].X_ln) C.X[j] = log(x_it->second[j]);
00300         else                              C.X[j] =     x_it->second[j] ;
00301         // Y values
00302         if (PlotterInfo[subplot_id].Y_ln) C.Y[j] = log(y_it->second[j]);
00303         else                              C.Y[j] =     y_it->second[j] ;
00304         if (PlotterInfo[subplot_id].mult_Y)
00305         {
00306             if (cy_it==T.end()) throw new Fatal(_("Plotter::_allocate_and_fill_X_and_Y: Could not find tag < %s >"), cy_tag.c_str());
00307             REAL sgn;
00308             if (cy_tag=="sin3th") sgn = Signal(              cy_it->second[j]  , 1.0e-10);
00309             else                  sgn = Signal(sin(3.0*ToRad(cy_it->second[j])), 1.0e-10);
00310             if (fabs(sgn)>0.0) C.Y[j] = sgn * C.Y[j];
00311         }
00312         if (PlotterInfo[subplot_id].Y_neg) C.Y[j] = -C.Y[j];
00313     }
00314 } // }}}
00315 
00316 inline void Plotter::_add_curves(int subplot_id, Coords const & C, PlotMM::Plot * subplot, String const & color) // {{{
00317 {
00318     char tit[100];
00319     sprintf(tit, "%s x %s", PlotterInfo[subplot_id].Y_tag, PlotterInfo[subplot_id].X_tag);
00320     Glib::RefPtr<PlotMM::Curve> c = Glib::RefPtr<PlotMM::Curve>(new PlotMM::Curve(tit));
00321     c->set_data(C.X, C.Y, C.size);
00322     c->paint()->set_pen_color(Gdk::Color(color));
00323     subplot->add_curve(c);
00324 } // }}}
00325 
00326 inline void Plotter::_add_curves(int subplot_id, Coords const & C, Array<int> const & Marks, PlotMM::Plot * subplot, String const & clr1, String const & clr2) // {{{
00327 {
00328     int start=0; bool red=false;
00329     for (size_t j=0; j<Marks.size(); ++j)
00330     {
00331         char tit[100];
00332         sprintf(tit, "%s x %s path# %d, mrk=%d", PlotterInfo[subplot_id].Y_tag, PlotterInfo[subplot_id].X_tag, j, Marks[j]);
00333         Glib::RefPtr<PlotMM::Curve> c = Glib::RefPtr<PlotMM::Curve>(new PlotMM::Curve(tit));
00334         int len = Marks[j] - start;
00335         if (start+len>C.size) throw new Fatal(_("Plotter::_add_curves: There is an inconsistency with the array of marks"));
00336         c->set_data(&(C.X[start]),&(C.Y[start]),len);
00337         start += len - 1;
00338         if (red) { c->paint()->set_pen_color(Gdk::Color(clr1)); red=false; }
00339         else     { c->paint()->set_pen_color(Gdk::Color(clr2)); red=true;  }
00340         subplot->add_curve(c);
00341     }
00342 } // }}}
00343 
00344 inline void Plotter::_print_coords(int subplot_id, int x, int y) // {{{
00345 {
00346     int plot_id = _nb.get_current_page();
00347     char tmp[1000];
00348     sprintf(tmp, "%s  |  %s = %.3f  |  %s = %.3f", (*_names)[plot_id].c_str(),
00349         PlotterInfo[subplot_id].X_label,
00350         _plots[plot_id][subplot_id]->scale(PlotMM::AXIS_BOTTOM)->scale_map().inv_transform(x),
00351         PlotterInfo[subplot_id].Y_label,
00352         _plots[plot_id][subplot_id]->scale(PlotMM::AXIS_LEFT  )->scale_map().inv_transform(y));
00353     _sbar.pop();
00354     _sbar.push(tmp);
00355 } // }}}
00356 
00357 inline void Plotter::_on_switch_page(GtkNotebookPage * page, guint page_num) // {{{
00358 {
00359     _sbar.pop();
00360     _sbar.push((*_names)[page_num]);
00361 } // }}}
00362 
00363 inline void Plotter::_on_plot0_mouse_move(int x, int y, GdkEventMotion * ev) // {{{
00364 {
00365     _print_coords(0, x,y);
00366 } // }}}
00367 
00368 inline void Plotter::_on_plot1_mouse_move(int x, int y, GdkEventMotion * ev) // {{{
00369 {
00370     _print_coords(1, x,y);
00371 } // }}}
00372 
00373 inline void Plotter::_on_plot2_mouse_move(int x, int y, GdkEventMotion * ev) // {{{
00374 {
00375     _print_coords(2, x,y);
00376 } // }}}
00377 
00378 inline void Plotter::_on_plot3_mouse_move(int x, int y, GdkEventMotion * ev) // {{{
00379 {
00380     _print_coords(3, x,y);
00381 } // }}}
00382 
00383 }; // namespace LabTestSim
00384 
00385 #endif // MECHSYS_LABTESTSIM_PLOTTER_H
00386 
00387 // vim:fdm=marker

Generated on Wed Jan 24 15:56:26 2007 for MechSys by  doxygen 1.4.7