00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
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;
00071 bool Y_neg;
00072 };
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
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
00094 ~Plotter();
00095
00096 private:
00097
00098 Array<String> const * _names;
00099 bool _use_cy;
00100 bool _use_marks;
00101 bool _use_calc;
00102 bool _use_cmarks;
00103 Gtk::Button _btn_close;
00104 Gtk::Notebook _nb;
00105 Gtk::Statusbar _sbar;
00106 Array< Gtk::Table* > _grids;
00107 Array< Array<PlotMM::Plot*> > _plots;
00108
00109
00110 struct Coords
00111 {
00112 REAL * X;
00113 REAL * Y;
00114 int size;
00115 };
00116
00117
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
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 };
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
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
00165 _grids.resize(_names->size());
00166 _plots.resize(_names->size());
00167
00168
00169 for (size_t i=0; i<_names->size(); ++i)
00170 {
00171
00172 _grids[i] = new Gtk::Table (2,2, true);
00173
00174
00175 _plots[i].resize(4);
00176 for (int j=0; j<4; ++j)
00177 {
00178
00179 _plots[i][j] = new PlotMM::Plot;
00180
00181
00182 _setup_subplot(j, _plots[i][j]);
00183
00184
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
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
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
00212 _nb.append_page((*_grids[i]), (*_names)[i]);
00213
00214
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
00222 get_vbox()->pack_end(_sbar , false, true);
00223 get_vbox()->pack_end(_btn_close, false, false);
00224 get_vbox()->pack_end(_nb, true, true);
00225 get_vbox()->set_homogeneous(false);
00226 show_all_children();
00227
00228
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
00242 delete _grids[i];
00243
00244
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
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
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
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
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
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
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
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
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 };
00384
00385 #endif // MECHSYS_LABTESTSIM_PLOTTER_H
00386
00387