Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

bgui_graph_tableau.cxx

Go to the documentation of this file.
00001 // This is brl/bbas/bgui/bgui_graph_tableau.cxx
00002 #include <bgui/bgui_graph_tableau.h>
00003 //:
00004 // \file
00005 #include <vcl_cmath.h> //for fabs()
00006 #include <vcl_sstream.h>
00007 #include <vnl/vnl_numeric_traits.h>
00008 #include <vnl/vnl_math.h>
00009 #include <vgui/vgui.h>
00010 #include <vgui/vgui_gl.h>
00011 #include <vgui/vgui_easy2D_tableau.h>
00012 #include <vgui/vgui_viewer2D_tableau.h>
00013 #include <vgui/vgui_shell_tableau.h>
00014 
00015 void bgui_graph_tableau::init()
00016 {
00017   tt_ = vgui_text_tableau_new();
00018   tt_->set_colour(1,1,1);
00019   easy_ = vgui_easy2D_tableau_new();
00020   easy_->set_foreground(0.0, 1.0f, 0.0);
00021   easy_->set_line_width(2.0f);
00022   n_ = 0;
00023   pos_ = 0;
00024   vals_ = 0;
00025   tic_length_ = 10.0f;
00026   left_offset_ = 75;
00027   top_offset_ = 20;
00028   n_plots_ = 1;
00029 }
00030 
00031 //========================================================================
00032 // Constructors
00033 
00034 bgui_graph_tableau::bgui_graph_tableau(const unsigned gwidth,
00035                                        const unsigned gheight) :
00036   graph_width_(gwidth), graph_height_(gheight), plot_(0)
00037 {   this->init(); }
00038 
00039 // Destructor.
00040 bgui_graph_tableau::~bgui_graph_tableau()
00041 {
00042   this->rem();
00043   this->del();
00044 }
00045 
00046 //: map the x position of a graph point to display coordinates
00047 float bgui_graph_tableau::map_x_to_display(const float xpos)
00048 {
00049   return left_offset_+ (xpos - xmin_)*xscale_;
00050 }
00051 
00052 //: map the y position of a graph point to display coordinates
00053 float bgui_graph_tableau::map_y_to_display(const float ypos)
00054 {
00055   return tic_length_ + graph_height_ - (ypos - yorigin_)*yscale_ + top_offset_;
00056 }
00057 
00058 //: find the nearest discrete y value less than or equal to ymin
00059 static float find_y_origin(const float ymin, const float yinc)
00060 {
00061   if (yinc==0)
00062     return 0;
00063   float nincs = vcl_floor(ymin/yinc);
00064   return nincs*yinc;
00065 }
00066 //-----------------------------------------------------------------------------
00067 //: returns a "nice" tic mark increment, given the scale factor between user's coordinates and screen coordinates.
00068 static float find_increment(float scale, float def = 1.0)
00069 {
00070   if (scale <= 0)
00071     return def;
00072 
00073   float separation = 50.0 / scale;
00074 
00075   // Find increment > separation
00076 
00077   float inc = 1;
00078 
00079   while (inc < separation)
00080     inc *= 10;
00081 
00082   // Find increment so sep/10 <= inc < sep
00083 
00084   while (inc > separation)
00085     inc /= 10;
00086 
00087   // Find smallest multiple of 1, 2 or 5 * 10^k > separation
00088 
00089   if (2 * inc > separation)
00090     inc *= 2;
00091   else if (5 * inc > separation)
00092     inc *= 5;
00093   else
00094     inc *= 10;
00095 
00096   return inc;
00097 }
00098 
00099 void bgui_graph_tableau::compute_scale()
00100 {
00101   xscale_=1.0f; yscale_=1.0f;
00102   if (vcl_fabs(xmax_-xmin_)>0)
00103     xscale_ = (graph_width_-left_offset_)/(xmax_-xmin_);
00104   if (vcl_fabs(ymax_-ymin_)>0)
00105     yscale_ = (graph_height_-top_offset_)/(ymax_-ymin_);
00106 
00107   yinc_ = find_increment(yscale_);
00108   xinc_ = find_increment(xscale_);
00109   if (yinc_ == 0.0)
00110     yinc_ = 1;
00111   if (xinc_ == 0.0)
00112     xinc_ = 1;
00113   yorigin_ = find_y_origin(ymin_,yinc_);
00114 }
00115 
00116 void bgui_graph_tableau::update(vcl_vector<double> const& pos,
00117                                 vcl_vector<double> const & vals)
00118 {
00119   n_ = pos.size();
00120   pos_ = new float[n_];
00121   vals_ = new float[n_];
00122   xmin_ = vnl_numeric_traits<float>::maxval;
00123   xmax_ = -xmin_;
00124   ymin_ = xmin_;
00125   ymax_ = ymax_;
00126   for (unsigned i = 0; i<n_; ++i)
00127   {
00128     pos_[i]=static_cast<float>(pos[i]);
00129     xmin_ = vnl_math_min(xmin_, pos_[i]);
00130     xmax_ = vnl_math_max(xmax_, pos_[i]);
00131     vals_[i]=static_cast<float>(vals[i]);
00132     ymin_ = vnl_math_min(ymin_, vals_[i]);
00133     ymax_ = vnl_math_max(ymax_, vals_[i]);
00134   }
00135   compute_scale();
00136   draw_graph();
00137 }
00138 
00139 
00140 void bgui_graph_tableau::update(vcl_vector<float> const& pos,
00141                                 vcl_vector<float> const & vals)
00142 {
00143   n_ = pos.size();
00144   pos_ = new float[n_];
00145   vals_ = new float[n_];
00146   for (unsigned i = 0; i<n_; ++i)
00147   {
00148     pos_[i]=pos[i];
00149     xmin_ = vnl_math_min(xmin_, pos_[i]);
00150     xmax_ = vnl_math_max(xmax_, pos_[i]);
00151     vals_[i]=vals[i];
00152     ymin_ = vnl_math_min(ymin_, vals_[i]);
00153     ymax_ = vnl_math_max(ymax_, vals_[i]);
00154   }
00155   compute_scale();
00156   draw_graph();
00157 }
00158 // In the current implementation, 
00159 // all plots have to have the same number of positions and values.
00160 // The vector position input is for future development where this
00161 // class takes care of the multiple position case - JLM
00162 void bgui_graph_tableau::update(vcl_vector<vcl_vector<double> > const& pos,
00163                                 vcl_vector<vcl_vector<double> >const & vals)
00164 {
00165   n_plots_ = pos.size();
00166   if (!n_plots_)
00167     return;
00168   n_ = pos[0].size();
00169   mpos_ = pos; mvals_=vals;
00170   double xmin, ymin, xmax, ymax;
00171   xmin = vnl_numeric_traits<double>::maxval;
00172   xmax = -xmin;
00173   ymin = xmin;
00174   ymax = xmax;
00175   for (unsigned p = 0; p<n_plots_; ++p)
00176     for (unsigned i = 0; i<n_; ++i)
00177     {
00178       xmin = vnl_math_min(xmin, pos[p][i]);
00179       xmax = vnl_math_max(xmax, pos[p][i]);
00180       ymin = vnl_math_min(ymin, vals[p][i]);
00181       ymax = vnl_math_max(ymax, vals[p][i]);
00182     }
00183   xmin_ = static_cast<float>(xmin);
00184   xmax_ = static_cast<float>(xmax);
00185   ymin_ = static_cast<float>(ymin);
00186   ymax_ = static_cast<float>(ymax);
00187   compute_scale();
00188   draw_multi_graph();
00189 }
00190 
00191 // Create the graph axes with tic marks. Every other tic is red and longer.
00192 void bgui_graph_tableau::draw_tics()
00193 {
00194   float xs = xmin_;
00195   float ys = yorigin_;
00196   float tl = tic_length_;
00197   unsigned ix = 0, iy = 0;
00198   //The bottom of the display
00199   float y0 = map_y_to_display(yorigin_);
00200   //The tic marks on the horizontal axis
00201   while (xs <= xmax_+xinc_)
00202   {
00203     float xd = map_x_to_display(xs);
00204     if (ix%2!=0)
00205       xtics_.push_back(easy_->add_line(xd, y0, xd, y0-tl));
00206     else
00207     {
00208       easy_->set_foreground(1.0f, 0.0, 0.0);
00209       xtics_.push_back(easy_->add_line(xd, y0, xd, y0-1.5f*tl));
00210       easy_->set_foreground(0.0f, 1.0f, 0.0);
00211     }
00212     vcl_stringstream ts;
00213     ts<<xs;
00214     vcl_string xval = ts.str();
00215     unsigned nchars = xval.size();
00216     float offset = static_cast<float>(nchars)/2;
00217     offset *= 10.0f;
00218     tt_->add(xd-offset, y0+15, xval);
00219     xs += xinc_;
00220     ++ix;
00221   }
00222   xtics_.push_back(easy_->add_line(map_x_to_display(xmin_), y0,
00223                                    map_x_to_display(xmax_+xinc_), y0));
00224   //The tic marks on the vertical axis
00225   //the vertical axis is at one tic length from left edge of graph
00226   while (ys <= ymax_+yinc_)
00227   {
00228     float yd = map_y_to_display(ys);
00229     if (iy%2!=0)
00230       ytics_.push_back(easy_->add_line(left_offset_,yd,
00231                                        tl+left_offset_,yd));
00232     else
00233     {
00234       easy_->set_foreground(1.0f, 0.0, 0.0);
00235       ytics_.push_back(easy_->add_line(left_offset_,yd,
00236                                        1.5f*tl+left_offset_,yd));
00237       easy_->set_foreground(0.0f, 1.0f, 0.0);
00238     }
00239     vcl_stringstream ts;
00240     ts<<ys;
00241     vcl_string yval = ts.str();
00242     float len = yval.size()+1;
00243      len*= 10.0f;
00244     tt_->add(left_offset_-len, yd+5.0f, yval);
00245 
00246     ys += yinc_;
00247     ++iy;
00248   }
00249   ytics_.push_back(easy_->
00250                    add_line(left_offset_,map_y_to_display(yorigin_),
00251                             left_offset_,
00252                             map_y_to_display(ymax_+yinc_)));
00253 
00254   //Make the tics and axes unselectable
00255   for (vcl_vector<vgui_soview2D_lineseg*>::iterator cit = xtics_.begin();
00256        cit!=xtics_.end(); ++cit)
00257     (*cit)->set_selectable(false);
00258   for (vcl_vector<vgui_soview2D_lineseg*>::iterator cit = ytics_.begin();
00259        cit!=ytics_.end(); ++cit)
00260     (*cit)->set_selectable(false);
00261 }
00262 
00263 //Draw the graph including the axes and tic marks
00264 void bgui_graph_tableau::draw_graph()
00265 {
00266   if (n_ == 0)
00267     return;
00268   vcl_vector<float> x(n_), y(n_);
00269   if (m_plot_.size())
00270   {
00271     for (unsigned i =0; i<m_plot_.size(); ++i)
00272       easy_->remove(m_plot_[i]);
00273     m_plot_.clear();
00274     tt_->clear();
00275   }
00276   if (plot_)
00277   {
00278     easy_->remove(plot_);
00279     tt_->clear();
00280     delete plot_;
00281     plot_ = 0;
00282   }
00283   for (unsigned i = 0; i<n_; ++i)
00284   {
00285     x[i]=map_x_to_display(pos_[i]);
00286     y[i]=map_y_to_display(vals_[i]);
00287   }
00288   plot_ = easy_->add_linestrip(n_, &x[0], &y[0]);
00289   plot_->set_selectable(false);
00290   draw_tics();
00291  this->post_redraw();
00292 }
00293 
00294 //Draw the multiple plots including the axes and tic marks
00295 void bgui_graph_tableau::draw_multi_graph()
00296 {
00297   //graph colors, where more than 7 plots repeat colors
00298   float r[7]={1,0,0,1,0,1,1};
00299   float g[7]={0,1,0,0,1,1,1};
00300   float b[7]={0,0,1,1,1,0,1};
00301   if (n_ == 0)
00302     return;
00303   if (m_plot_.size())
00304   {
00305     for (unsigned i =0; i<m_plot_.size(); ++i)
00306       easy_->remove(m_plot_[i]);
00307     m_plot_.clear();
00308     tt_->clear();
00309   }
00310   for (unsigned p = 0; p<n_plots_; ++p)
00311   {
00312     vcl_vector<float> x(n_), y(n_);
00313     for (unsigned i = 0; i<n_; ++i)
00314     {
00315       x[i]=map_x_to_display(static_cast<float>(mpos_[p][i]));
00316       y[i]=map_y_to_display(static_cast<float>(mvals_[p][i]));
00317     }
00318     unsigned c = p%7;
00319     easy_->set_foreground(r[c], g[c], b[c]);
00320     vgui_soview2D_linestrip* ls = easy_->add_linestrip(n_, &x[0], &y[0]);
00321     ls->set_selectable(false);
00322     m_plot_.push_back(ls);
00323   }
00324   draw_tics();
00325   this->post_redraw();
00326 }
00327 
00328 //remove display items and delete the soviews
00329 void bgui_graph_tableau::rem()
00330 {
00331   if (plot_)
00332   {
00333     easy_->remove(plot_);
00334     //delete plot_;
00335     plot_ = 0;
00336   }
00337   for (vcl_vector<vgui_soview2D_lineseg*>::iterator cit = xtics_.begin();
00338        cit!=xtics_.end(); ++cit)
00339     if (*cit)
00340     {
00341       easy_->remove(*cit);
00342      // delete *cit;
00343     }
00344   for (vcl_vector<vgui_soview2D_lineseg*>::iterator cit = ytics_.begin();
00345        cit!=ytics_.end(); ++cit)
00346     if (*cit)
00347     {
00348       easy_->remove(*cit);
00349       //delete *cit;
00350     }
00351   for (unsigned i = 0; i< m_plot_.size(); ++i)
00352     easy_->remove(m_plot_[i]);
00353   m_plot_.clear();
00354 }
00355 
00356 //Delete graph point data
00357 void bgui_graph_tableau::del()
00358 {
00359   if (pos_)
00360   {
00361     delete [] pos_;
00362     pos_ =0;
00363   }
00364   if (vals_)
00365   {
00366     delete [] vals_;
00367     vals_ = 0;
00368   }
00369 }
00370 
00371 //Clear the graph
00372 void bgui_graph_tableau::clear()
00373 {
00374   this->rem();
00375   this->del();
00376   this->post_redraw();
00377 }
00378 
00379 //Provide a popup dialog that contains the graph.  The string info
00380 //contains user defined documention for the graph.
00381 vgui_dialog* bgui_graph_tableau::popup_graph(vcl_string const& info,
00382                                              const unsigned sizex,
00383                                              const unsigned sizey)
00384 {
00385   unsigned w = graph_width_+25, h = graph_height_+25;
00386   if (sizex>0)
00387     w = sizex;
00388   if (sizey>0)
00389     h = sizey;
00390   vgui_viewer2D_tableau_sptr v = vgui_viewer2D_tableau_new(this);
00391   vgui_shell_tableau_sptr s = vgui_shell_tableau_new(v);
00392   vcl_string temp = info;
00393   vcl_stringstream xinc, yinc, ymin, ymax;
00394   xinc << xinc_; yinc << yinc_; ymin << ymin_; ymax<< ymax_;
00395 #if 0
00396   temp += " xinc:" + xinc.str();
00397   temp += " yinc:" + yinc.str();
00398 #endif
00399   temp += " ymin:" + ymin.str();
00400   temp += " ymax:" + ymax.str();
00401   vgui_dialog* d = new vgui_dialog(temp.c_str());
00402   d->inline_tableau(s, w, h);
00403   return d;
00404 }
00405 
00406 //========================================================================
00407 //: Handles all events for this tableau.
00408 bool bgui_graph_tableau::handle(const vgui_event& event)
00409 {
00410   // Pass events on down to the child tableaux:
00411   if (event.type == vgui_DRAW)
00412   {
00413     vcl_cout << "Graph Handle\n";
00414     easy_->handle(event);
00415     tt_->handle(event);
00416   }
00417   return false;
00418 }
00419 

Generated on Thu Jan 10 14:52:10 2008 for contrib/brl/bbas/bgui by  doxygen 1.4.4