plotter.cpp
Go to the documentation of this file.
00001 /* This file is part of the Pangolin Project.
00002  * http://github.com/stevenlovegrove/Pangolin
00003  *
00004  * Copyright (c) 2011 Steven Lovegrove
00005  *
00006  * Permission is hereby granted, free of charge, to any person
00007  * obtaining a copy of this software and associated documentation
00008  * files (the "Software"), to deal in the Software without
00009  * restriction, including without limitation the rights to use,
00010  * copy, modify, merge, publish, distribute, sublicense, and/or sell
00011  * copies of the Software, and to permit persons to whom the
00012  * Software is furnished to do so, subject to the following
00013  * conditions:
00014  *
00015  * The above copyright notice and this permission notice shall be
00016  * included in all copies or substantial portions of the Software.
00017  *
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00019  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
00020  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00021  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
00022  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
00023  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00024  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00025  * OTHER DEALINGS IN THE SOFTWARE.
00026  */
00027 
00028 #include "plotter.h"
00029 #include "display_internal.h"
00030 
00031 #include <limits>
00032 #include <iostream>
00033 #include <fstream>
00034 #include <iomanip>
00035 #include <boost/unordered_map.hpp>
00036 
00037 using namespace std;
00038 
00039 namespace pangolin
00040 {
00041 
00042 extern __thread PangolinGl* context;
00043 
00044 static void* font = GLUT_BITMAP_HELVETICA_12;
00045 
00046 DataSequence::DataSequence(unsigned int buffer_size, unsigned size, float val )
00047     : y(buffer_size,size,val), n(0), sum_y(0), sum_y_sq(0),
00048       min_y(numeric_limits<float>::max()),
00049       max_y(numeric_limits<float>::min())
00050 {
00051 
00052 }
00053 
00054 void DataSequence::Add(float val)
00055 {
00056     y.push_back(val);
00057     ++n;
00058     firstn = n-y.size();
00059     min_y = std::min(min_y,val);
00060     max_y = std::max(max_y,val);
00061     sum_y += val;
00062     sum_y_sq += val*val;
00063 }
00064 
00065 void DataSequence::Clear()
00066 {
00067     y.clear();
00068     n = 0;
00069     firstn = 0;
00070     sum_y = 0;
00071     sum_y_sq = 0;
00072     min_y = numeric_limits<float>::max();
00073     max_y = numeric_limits<float>::min();
00074 }
00075 
00076 float DataSequence::operator[](unsigned int i) const
00077 {
00078     if( !HasData(i) )
00079     {
00080         throw DataUnavailableException("Out of range");
00081     }
00082     return y[(i-firstn) % y.size()];
00083 }
00084 
00085 DataLog::DataLog(unsigned int buffer_size)
00086     : buffer_size(buffer_size), x(0)
00087 {
00088 }
00089 
00090 void DataLog::Clear()
00091 {
00092     x = 0;
00093     sequences.clear();
00094 }
00095 
00096 void DataLog::Save(std::string filename)
00097 {
00098     if( sequences.size() > 0 )
00099     {
00100         ofstream f(filename.c_str());
00101         for( int n=sequences[0].firstn; n < sequences[0].n; ++n )
00102         {
00103             f << setprecision(12) << sequences[0][n];
00104             for( unsigned s=1; s < sequences.size(); ++s )
00105                 f << ", " << sequences[s][n];
00106             f << endl;
00107         }
00108         f.close();
00109     }
00110 }
00111 
00112 void DataLog::Log(const vector<float> & vals)
00113 {
00114     Log(vals.size(), &vals[0]);
00115 }
00116 
00117 void DataLog::Log(unsigned int N, const float * vals)
00118 {
00119     // Create new plots if needed
00120     for( unsigned int i= sequences.size(); i < N; ++i )
00121         sequences.push_back(DataSequence(buffer_size,x,0));
00122 
00123     // Add data to existing plots
00124     for( unsigned int i=0; i<sequences.size(); ++i )
00125         sequences[i].Add(vals[i]);
00126 
00127     // Fill missing data
00128     for( unsigned int i=N; i<sequences.size(); ++i )
00129         sequences[i].Add(0.0f);
00130 
00131     ++x;
00132 }
00133 
00134 void DataLog::SetLabels(const std::vector<std::string> & new_labels)
00135 {
00136     // Create new labels if needed
00137     for( unsigned int i= labels.size(); i < new_labels.size(); ++i )
00138         labels.push_back(std::string("N/A"));
00139 
00140     // Add data to existing plots
00141     for( unsigned int i=0; i<labels.size(); ++i )
00142         labels[i] = new_labels[i];
00143 }
00144 
00145 void DataLog::Log(float v)
00146 {
00147     const float vs[] = {v};
00148     Log(1,vs);
00149 }
00150 
00151 void DataLog::Log(float v1, float v2)
00152 {
00153     const float vs[] = {v1,v2};
00154     Log(2,vs);
00155 }
00156 
00157 void DataLog::Log(float v1, float v2, float v3)
00158 {
00159     const float vs[] = {v1,v2,v3};
00160     Log(3,vs);
00161 }
00162 void DataLog::Log(float v1, float v2, float v3, float v4)
00163 {
00164     const float vs[] = {v1,v2,v3,v4};
00165     Log(4,vs);
00166 }
00167 void DataLog::Log(float v1, float v2, float v3, float v4, float v5)
00168 {
00169     const float vs[] = {v1,v2,v3,v4,v5};
00170     Log(5,vs);
00171 }
00172 void DataLog::Log(float v1, float v2, float v3, float v4, float v5, float v6)
00173 {
00174     const float vs[] = {v1,v2,v3,v4,v5,v6};
00175     Log(6,vs);
00176 }
00177 
00178 Plotter::Plotter(DataLog* log, float left, float right, float bottom, float top, float tickx, float ticky)
00179     : log(log), track_front(true), draw_mode(0), plot_mode(TIME_SERIES)
00180 {
00181     this->handler = this;
00182     int_x[0] = int_x_dflt[0] = left;
00183     int_x[1] = int_x_dflt[1] = right;
00184     int_y[0] = int_y_dflt[0] = bottom;
00185     int_y[1] = int_y_dflt[1] = top;
00186     ticks[0] = tickx;
00187     ticks[1] = ticky;
00188 
00189     for( unsigned int i=0; i<show_n; ++i )
00190         show[i] = true;
00191 }
00192 
00193 void Plotter::DrawTicks()
00194 {
00195     glColor3fv(colour_tk);
00196     const int tx[2] =
00197     {
00198         (int)ceil(int_x[0] / ticks[0]),
00199         (int)ceil(int_x[1] / ticks[0])
00200     };
00201     const int ty[2] =
00202     {
00203         (int)ceil(int_y[0] / ticks[1]),
00204         (int)ceil(int_y[1] / ticks[1])
00205     };
00206 
00207     if( tx[1] - tx[0] < v.w/4 )
00208     {
00209         for( int i=tx[0]; i<tx[1]; ++i )
00210         {
00211             glBegin(GL_LINE_STRIP);
00212             glVertex2f(i*ticks[0], int_y[0]);
00213             glVertex2f(i*ticks[0], int_y[1]);
00214             glEnd();
00215         }
00216     }
00217 
00218     if( ty[1] - ty[0] < v.h/4 )
00219     {
00220         for( int i=ty[0]; i<ty[1]; ++i )
00221         {
00222             glBegin(GL_LINE_STRIP);
00223             glVertex2f(int_x[0], i*ticks[1]);
00224             glVertex2f(int_x[1], i*ticks[1]);
00225             glEnd();
00226         }
00227     }
00228 
00229     glColor3fv(colour_ax);
00230     glBegin(GL_LINE_STRIP);
00231     glVertex2f(0, int_y[0]);
00232     glVertex2f(0, int_y[1]);
00233     glEnd();
00234     glBegin(GL_LINE_STRIP);
00235     glVertex2f(int_x[0],0);
00236     glVertex2f(int_x[1],0);
00237     glEnd();
00238 }
00239 
00240 void Plotter::DrawSequence(const DataSequence& seq)
00241 {
00242     const int seqint_x[2] = {seq.firstn, seq.n };
00243     const int valid_int_x[2] =
00244     {
00245         std::max(seqint_x[0],(int)int_x[0]),
00246         std::min(seqint_x[1],(int)int_x[1])
00247     };
00248     glBegin(draw_modes[draw_mode]);
00249     for( int x=valid_int_x[0]; x<valid_int_x[1]; ++x )
00250         glVertex2f(x,seq[x]);
00251     glEnd();
00252 }
00253 
00254 void Plotter::DrawSequenceHistogram(const std::vector<DataSequence>& seq)
00255 {
00256     size_t vec_size
00257     = std::min((unsigned)log->x, log->buffer_size);
00258     int idx_subtract
00259     = std::max(0,(int)(log->x)-(int)(log->buffer_size));
00260     vector<float> accum_vec(vec_size,0);
00261 
00262     for(int s=log->sequences.size()-1; s >=0; --s )
00263     {
00264         if( (s > 9) ||  show[s] )
00265         {
00266 
00267             const int seqint_x[2] = {seq.at(s).firstn, seq.at(s).n };
00268             const int valid_int_x[2] =
00269             {
00270                 std::max(seqint_x[0],(int)int_x[0]),
00271                 std::min(seqint_x[1],(int)int_x[1])
00272             };
00273 
00274 
00275             glBegin(GL_TRIANGLE_STRIP);
00276             glColor3fv(plot_colours[s%num_plot_colours]);
00277 
00278 
00279             for( int x=valid_int_x[0]; x<valid_int_x[1]; ++x )
00280             {
00281                 float val = seq.at(s)[x];
00282 
00283                 float & accum = accum_vec.at(x-idx_subtract);
00284                 float before_val = accum;
00285                 accum += val;
00286                 glVertex2f(x-0.5,before_val);
00287                 glVertex2f(x-0.5,accum);
00288                 glVertex2f(x+0.5,before_val);
00289                 glVertex2f(x+0.5,accum);
00290             }
00291             glEnd();
00292         }
00293     }
00294 }
00295 
00296 void Plotter::DrawSequence(const DataSequence& x,const DataSequence& y)
00297 {
00298     const unsigned minn = max(x.firstn,y.firstn);
00299     const unsigned maxn = min(x.n,y.n);
00300 
00301     glBegin(draw_modes[draw_mode]);
00302     for( unsigned n=minn; n < maxn; ++n )
00303         glVertex2f(x[n],y[n]);
00304     glEnd();
00305 }
00306 
00307 void Plotter::Render()
00308 {
00309     if( track_front )
00310     {
00311         const float d = int_x[1] - log->x;
00312         int_x[0] -= d;
00313         int_x[1] -= d;
00314     }
00315 
00316     ActivateScissorAndClear();
00317     glMatrixMode(GL_PROJECTION);
00318     glLoadIdentity();
00319     gluOrtho2D(int_x[0], int_x[1], int_y[0], int_y[1]);
00320     glMatrixMode(GL_MODELVIEW);
00321     glLoadIdentity();
00322     glEnable(GL_LINE_SMOOTH);
00323 
00324     DrawTicks();
00325 
00326     if( log && log->sequences.size() > 0 )
00327     {
00328         if( plot_mode==XY )
00329         {
00330             for( unsigned int s=0; s < log->sequences.size() / 2; ++s )
00331             {
00332                 if( (s > 9) ||  show[s] )
00333                 {
00334                     glColor3fv(plot_colours[s%num_plot_colours]);
00335                     DrawSequence(log->sequences[2*s],log->sequences[2*s+1]);
00336                 }
00337             }
00338         }
00339         else if( plot_mode==TIME_SERIES)
00340         {
00341             for( unsigned int s=0; s < log->sequences.size(); ++s )
00342             {
00343                 if( (s > 9) ||  show[s] )
00344                 {
00345                     glColor3fv(plot_colours[s%num_plot_colours]);
00346                     DrawSequence(log->sequences[s]);
00347                 }
00348             }
00349         }
00350         else if( plot_mode==STACKED_HISTOGRAM )
00351         {
00352 
00353 
00354             DrawSequenceHistogram(log->sequences);
00355 
00356         }
00357         else
00358         {
00359             assert(false);
00360         }
00361     }
00362 
00363     if( mouse_state & MouseButtonLeft )
00364     {
00365         if( plot_mode==XY )
00366         {
00367             glColor3fv(colour_ms);
00368             glBegin(GL_LINE_STRIP);
00369             glVertex2f(mouse_xy[0],int_y[0]);
00370             glVertex2f(mouse_xy[0],int_y[1]);
00371             glEnd();
00372             glBegin(GL_LINE_STRIP);
00373             glVertex2f(int_x[0],mouse_xy[1]);
00374             glVertex2f(int_x[1],mouse_xy[1]);
00375             glEnd();
00376             stringstream ss;
00377             ss << "(" << mouse_xy[0] << "," << mouse_xy[1] << ")";
00378             glColor3f(1.0,1.0,1.0);
00379             OpenGlRenderState::ApplyWindowCoords();
00380             glRasterPos2f( v.l+5,v.b+5 );
00381             glutBitmapString(font,(unsigned char*)ss.str().c_str());
00382         }
00383         else
00384         {
00385             int xu = (int)mouse_xy[0];
00386             glColor3fv(colour_ms);
00387             glBegin(GL_LINE_STRIP);
00388             glVertex2f(xu,int_y[0]);
00389             glVertex2f(xu,int_y[1]);
00390             glEnd();
00391             stringstream ss;
00392             glColor3f(1.0,1.0,1.0);
00393             ss << "x=" << xu << " ";
00394             OpenGlRenderState::ApplyWindowCoords();
00395             int tx = v.l+5;
00396             glRasterPos2f( tx,v.b+5 );
00397             glutBitmapString(font,(unsigned char*)ss.str().c_str());
00398             tx += glutBitmapLength(font,(unsigned char*)ss.str().c_str());
00399             for( unsigned int s=0; s<log->sequences.size(); ++s )
00400             {
00401                 if( (s > show_n || show[s]) && log->sequences[s].HasData(xu) )
00402                 {
00403                     stringstream ss;
00404                     ss << " " << log->sequences[s][xu];
00405                     glColor3fv(plot_colours[s%num_plot_colours]);
00406                     glRasterPos2f( tx,v.b+5 );
00407                     glutBitmapString(font,(unsigned char*)ss.str().c_str());
00408                     tx += glutBitmapLength(font,(unsigned char*)ss.str().c_str());
00409                 }
00410             }
00411         }
00412     }
00413 
00414     float ty = v.h-15;
00415     for (size_t i=0; i<log->labels.size(); ++i)
00416     {
00417         glColor3fv(plot_colours[i%num_plot_colours]);
00418 
00419         OpenGlRenderState::ApplyWindowCoords();
00420         glRasterPos2f( v.l+5,ty);
00421         glutBitmapString(font,(unsigned char*)log->labels[i].c_str());
00422         ty -= 15;
00423     }
00424 }
00425 
00426 void Plotter::ResetView()
00427 {
00428     track_front = true;
00429     int_x[0] = int_x_dflt[0];
00430     int_x[1] = int_x_dflt[1];
00431     int_y[0] = int_y_dflt[0];
00432     int_y[1] = int_y_dflt[1];
00433     for( unsigned int i=0; i<show_n; ++i )
00434         show[i] = true;
00435 }
00436 
00437 void Plotter::Keyboard(View&, unsigned char key, int x, int y, bool pressed)
00438 {
00439     if( pressed )
00440     {
00441         if( key == 't' )
00442         {
00443             track_front = !track_front;
00444         }
00445         else if( key == 'c' )
00446         {
00447             log->Clear();
00448             cout << "Plotter: Clearing data" << endl;
00449         }
00450         else if( key == 's' )
00451         {
00452             log->Save("./log.csv");
00453             cout << "Plotter: Saving to log.csv" << endl;
00454         }
00455         else if( key == 'm' )
00456         {
00457             draw_mode = (draw_mode+1)%draw_modes_n;
00458         }
00459         else if( key == 'p' )
00460         {
00461             plot_mode = (plot_mode+1)%modes_n;
00462             ResetView();
00463             if( plot_mode==XY )
00464             {
00465                 int_x[0] = int_y[0];
00466                 int_x[1] = int_y[1];
00467                 track_front = false;
00468             }
00469         }
00470         else if( key == 'r' )
00471         {
00472             cout << "Plotter: Reset viewing range" << endl;
00473             ResetView();
00474         }
00475         else if( key == 'a' || key == ' ' )
00476         {
00477             cout << "Plotter: Auto scale" << endl;
00478             if( plot_mode==XY && log->sequences.size() >= 2)
00479             {
00480                 int_x[0] = log->sequences[0].min_y;
00481                 int_x[1] = log->sequences[0].max_y;
00482                 int_y[0] = log->sequences[1].min_y;
00483                 int_y[1] = log->sequences[1].max_y;
00484             }
00485             else
00486             {
00487                 float min_y = numeric_limits<float>::max();
00488                 float max_y = numeric_limits<float>::min();
00489                 for( unsigned int i=0; i<log->sequences.size(); ++i )
00490                 {
00491                     if( i>=show_n || show[i] )
00492                     {
00493                         min_y = std::min(min_y,log->sequences[i].min_y);
00494                         max_y = std::max(max_y,log->sequences[i].max_y);
00495                     }
00496                 }
00497                 if( min_y < max_y )
00498                 {
00499                     int_y[0] = min_y;
00500                     int_y[1] = max_y;
00501                 }
00502             }
00503         }
00504         else if( '1' <= key && key <= '9' )
00505         {
00506             show[key-'1'] = !show[key-'1'];
00507         }
00508     }
00509 }
00510 
00511 void Plotter::ScreenToPlot(int x, int y)
00512 {
00513     mouse_xy[0] = int_x[0] + (int_x[1]-int_x[0]) * (x - v.l) / (float)v.w;
00514     mouse_xy[1] = int_y[0] + (int_y[1]-int_y[0]) * (y - v.b) / (float)v.h;
00515 }
00516 
00517 void Plotter::Mouse(View&, MouseButton button, int x, int y, bool pressed, int button_state)
00518 {
00519     last_mouse_pos[0] = x;
00520     last_mouse_pos[1] = y;
00521     mouse_state = button_state;
00522 
00523     if(button == MouseWheelUp || button == MouseWheelDown)
00524     {
00525         //const float mean = (int_y[0] + int_y[1])/2.0;
00526         const float scale = 1.0f + ((button == MouseWheelDown) ? 0.1 : -0.1);
00527 //    int_y[0] = scale*(int_y[0] - mean) + mean;
00528 //    int_y[1] = scale*(int_y[1] - mean) + mean;
00529         int_y[0] = scale*(int_y[0]) ;
00530         int_y[1] = scale*(int_y[1]) ;
00531     }
00532 
00533     ScreenToPlot(x,y);
00534 }
00535 
00536 void Plotter::MouseMotion(View&, int x, int y, int button_state)
00537 {
00538     mouse_state = button_state;
00539     const int d[2] = {x-last_mouse_pos[0],y-last_mouse_pos[1]};
00540     const float is[2] = {int_x[1]-int_x[0],int_y[1]-int_y[0]};
00541     const float df[2] = {is[0]*d[0]/(float)v.w, is[1]*d[1]/(float)v.h};
00542 
00543     if( button_state == MouseButtonLeft )
00544     {
00545         track_front = false;
00546         int_x[0] -= df[0];
00547         int_x[1] -= df[0];
00548         //    interval_y[0] -= df[1];
00549         //    interval_y[1] -= df[1];
00550     }
00551     else if(button_state == MouseButtonMiddle )
00552     {
00553         int_y[0] -= df[1];
00554         int_y[1] -= df[1];
00555     }
00556     else if(button_state == MouseButtonRight )
00557     {
00558         const double c[2] =
00559         {
00560             track_front ? int_x[1] : (int_x[0] + int_x[1])/2.0,
00561             (int_y[0] + int_y[1])/2.0
00562         };
00563         const float scale[2] =
00564         {
00565             1.0f + (float)d[0] / (float)v.w,
00566             1.0f - (float)d[1] / (float)v.h,
00567         };
00568         int_x[0] = scale[0]*(int_x[0] - c[0]) + c[0];
00569         int_x[1] = scale[0]*(int_x[1] - c[0]) + c[0];
00570         int_y[0] = scale[1]*(int_y[0] - c[1]) + c[1];
00571         int_y[1] = scale[1]*(int_y[1] - c[1]) + c[1];
00572     }
00573 
00574     last_mouse_pos[0] = x;
00575     last_mouse_pos[1] = y;
00576 }
00577 
00578 Plotter& CreatePlotter(const string& name, DataLog* log)
00579 {
00580     Plotter* v = new Plotter(log);
00581     //context->all_views[name] = v;
00582     bool inserted = context->named_managed_views.insert(name,v).second;
00583     if(!inserted) throw exception();
00584     context->base.views.push_back(v);
00585     return *v;
00586 }
00587 
00588 } // namespace pangolin
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines


pangolin_wrapper
Author(s): Todor Stoyanov
autogenerated on Wed Feb 13 2013 14:03:25