Main Page   Compound List   File List   Compound Members  

multiplot.h

00001 /*
00002  * multiplot.h
00003  * Copyright 2002 by Andre Krause.
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public
00016  * License along with this library; if not, write to the Free Software
00017  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00018  * USA.
00019  *
00020  * Please report all bugs and problems to "post@andre-krause.net".
00021  * New versions and bug-fixes under http://www.andre-krause.net
00022  *      
00023  */
00024 #ifndef __MULTIPLOT__
00025 #define __MULTIPLOT__
00026 
00027 
00028 #include <FL/Fl.H>
00029 #include <FL/Fl_Gl_Window.H>
00030 #include <FL/gl.h>
00031 #include <float.h>
00032 #include <time.h>
00033 #include <math.h>
00034 #include <vector>
00035 #include <string>
00036 #include <sstream>
00037 
00038 
00039 #ifndef min
00040         #define min(a,b)( (a) < (b) ) ? (a) : (b) )
00041 #endif
00042 
00043 
00044 
00045 using namespace std;
00046 
00047 enum MULTIPLOT_GRIDSTYLE
00048 {
00049         MP_NO_GRID,
00050         MP_LINEAR_GRID,
00051         MP_LOG_GRID
00052 };
00053 
00058 class PLOT_POINT
00059 {
00060         public:
00061                 float x;
00062                 float y;
00063                 float r;
00064                 float g;
00065                 float b;
00066                 PLOT_POINT();
00067                 PLOT_POINT(float xx, float yy, float rr=1, float gg=1, float bb=1);
00068 };
00069 
00074 class MULTIPLOT : public Fl_Gl_Window
00075 {
00076         public:
00081                 MULTIPLOT(int x, int y, int w, int h, const char *title="MULTIPLOT - updates on www.andre-krause.net");
00086                 void add(unsigned int trace, const PLOT_POINT &p);
00092                 void set_max_points(int mx);
00098                 void set_scrolling(int max_points_to_plot);
00099                 
00108                 void set_grid(int gridx, int gridy, float gridx_step=-1.0, float gridy_step=-1.0, float w=1.0);
00109                 
00115                 void set_pointsize(unsigned int trace, float s);
00116                 
00122                 void set_linewidth(unsigned int trace, float w);
00123                 
00127                 void set_bg_color(float r, float g, float b);
00128 
00132                 void set_grid_color(float r, float g, float b);
00133 
00137                 void clear();
00138                 
00142                 void clear(unsigned int t);
00143         protected:
00144                 string title;           // stores the user-title, so we can add ranges
00145                 vector< vector<PLOT_POINT> > traces;
00146                 PLOT_POINT minimum, maximum;
00147                 PLOT_POINT scale;
00148                 PLOT_POINT offset;
00149                 PLOT_POINT bg_color;
00150                 PLOT_POINT grid_color;
00151                 unsigned int max_points;
00152                 bool scroll;
00153 
00154                 // this struct stores information
00155                 // about the traces like line_width, the current pos 
00156                 // in the ring-buffer and the point-size.
00157                 class TRACE
00158                 {
00159                         public:
00160                                 unsigned int pos;
00161                                 float point_size;
00162                                 float line_width;
00163                                 TRACE(){ pos=0; point_size=0.0; line_width=1; }
00164                 };
00165                 vector< TRACE > tsettings;
00166 
00167                 // grid - vars
00168                 int gridx, gridy;
00169                 float gridx_step, gridy_step, grid_linewidth;           
00170 
00171                 void initgl();
00172                 PLOT_POINT draw_grid();
00173                 void draw();
00174 };
00175 
00176 
00177 // implementation:
00178 inline PLOT_POINT::PLOT_POINT() { x=y=0.0;r=g=b=1; }
00179 inline PLOT_POINT::PLOT_POINT(float xx, float yy, float rr, float gg, float bb) { x=xx;y=yy;r=rr;g=gg;b=bb; }
00180 
00181 inline MULTIPLOT::MULTIPLOT(int x, int y, int w, int h, const char *ttitle) : Fl_Gl_Window(x,y,w,h,ttitle) 
00182 {       
00183         title=string(ttitle);
00184         //max.x=max.y=-FLT_MAX;
00185         maximum.x=maximum.y=-FLT_MAX;
00186         minimum.x=minimum.y=FLT_MAX;
00187         max_points=max(w,h);
00188         traces.push_back( vector<PLOT_POINT>() ); // create one trace
00189         tsettings.push_back(TRACE());
00190 
00191         scroll=false;
00192         
00193         gridx=MP_NO_GRID;
00194         gridy=MP_NO_GRID;
00195         gridx_step=-1;
00196         gridy_step=-1;
00197 
00198         bg_color.r=0.0f;
00199         bg_color.g=0.0f;
00200         bg_color.b=0.0f;
00201         
00202         grid_color.r=0.8f;
00203         grid_color.g=0.8f;
00204         grid_color.b=0.8f;
00205         grid_linewidth=1.0f;
00206 
00207         show();
00208 }
00209 
00210 inline void MULTIPLOT::add(unsigned int trace, const PLOT_POINT &p)
00211 { 
00212         if(traces.size()<=trace)
00213         {
00214                 int n=trace-traces.size()+1;
00215                 for(int a=0;a<n;a++)
00216                 {
00217                         traces.push_back(vector<PLOT_POINT>());
00218                         tsettings.push_back(TRACE());                   
00219                 }
00220         }
00221 
00222         if(scroll)
00223         {
00224                 // this realises a sort of ringbuffer wich is needed for scrolling
00225                 if(tsettings[trace].pos<traces[trace].size())
00226                         traces[trace][tsettings[trace].pos]=p;
00227                 else
00228                         traces[trace].push_back(p);
00229                 tsettings[trace].pos++;
00230                 if(tsettings[trace].pos>=max_points)
00231                         tsettings[trace].pos=0;
00232         }
00233         else
00234         {
00235                 traces[trace].push_back(p);
00236         }
00237 }
00238 
00239 inline void MULTIPLOT::set_pointsize(unsigned int trace, float psize)
00240 {
00241         if(tsettings.size()<=trace)
00242         {
00243                 int n=trace-tsettings.size()+1;
00244                 for(int a=0;a<n;a++)
00245                 {
00246                         tsettings.push_back(TRACE());                   
00247                 }
00248         }
00249         tsettings[trace].point_size=psize;
00250 }
00251 
00252 inline void MULTIPLOT::set_linewidth(unsigned int trace, float width)
00253 {
00254         if(tsettings.size()<=trace)
00255         {
00256                 int n=trace-tsettings.size()+1;
00257                 for(int a=0;a<n;a++)
00258                 {
00259                         tsettings.push_back(TRACE());                   
00260                 }
00261         }
00262         tsettings[trace].line_width=width;
00263 }
00264 
00265 inline void MULTIPLOT::clear()
00266 {
00267         for(unsigned int a=0;a<traces.size();a++)
00268         {
00269                 traces[a].clear();
00270                 tsettings[a].pos=0;
00271         }       
00272 }
00273 
00274 inline void MULTIPLOT::clear(unsigned int trace)
00275 {
00276                 traces[trace].clear();
00277                 tsettings[trace].pos=0;
00278 }
00279 
00280 
00281 inline void MULTIPLOT::set_max_points(int mx)
00282 {
00283         max_points=mx;
00284 }
00285 
00286 inline void MULTIPLOT::set_grid_color(float r, float g, float b)
00287 {
00288         grid_color.r=r;
00289         grid_color.g=g;
00290         grid_color.b=b;
00291 }
00292 
00293 inline void MULTIPLOT::set_bg_color(float r, float g, float b)
00294 {
00295         bg_color.r=r;
00296         bg_color.g=g;
00297         bg_color.b=b;
00298         glClearColor(bg_color.r, bg_color.g, bg_color.b, 1);            // Set The background color
00299 }
00300 
00301 
00302 inline void MULTIPLOT::set_scrolling(int max_points_to_plot)
00303 {
00304         if(max_points_to_plot<=0)
00305         {
00306                 scroll=false;
00307                 return;
00308         }
00309 
00310         scroll=true;
00311         max_points=max_points_to_plot;
00312         for(unsigned int t=0;t<traces.size();t++)
00313                 if(traces[t].capacity()<max_points)
00314                         traces[t].reserve(max_points);
00315         
00316 }
00317 
00318 inline void MULTIPLOT::set_grid(int ggridx, int ggridy, float ggridx_step, float ggridy_step, float w)
00319 {
00320         gridx=ggridx;
00321         gridy=ggridy;
00322         gridx_step=ggridx_step;
00323         gridy_step=ggridy_step;
00324         grid_linewidth=w;
00325 }
00326 
00327 
00328 inline void MULTIPLOT::initgl()
00329 {
00330         glViewport(0 , 0,w() ,h());     // Set Up A Viewport
00331         glMatrixMode(GL_PROJECTION);                                                            // Select The Projection Matrix
00332         glLoadIdentity();                                                                                       // Reset The Projection Matrix
00333         glOrtho( 0, w(), 0, h(), -1, 1 );                                                       // Select Ortho Mode (640x480)
00334         //gluPerspective(50, (float)w()/(float)h(), 5,  2000); // Set Our Perspective
00335         glMatrixMode(GL_MODELVIEW);                                                                     // Select The Modelview Matrix
00336         glLoadIdentity();                                                                                       // Reset The Modelview Matrix
00337         glDisable(GL_DEPTH_TEST);                                                                       // Enable Depth Testing
00338         glDisable(GL_LIGHTING);
00339         glShadeModel(GL_SMOOTH);                                                                        // Select Smooth Shading
00340         glClearColor(bg_color.r, bg_color.g, bg_color.b, 1);            // Set The background color
00341         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                     // Clear The Screen And Depth Buffer
00342 }       
00343 
00344 
00345 
00346 inline PLOT_POINT MULTIPLOT::draw_grid()
00347 {
00348         double xstep,ystep;
00349         if(gridx==MP_LINEAR_GRID)
00350         {
00351                 double diff=maximum.x - minimum.x;
00352                 if(diff==0)return PLOT_POINT(0,0);
00353                 double exp=floor(log10(fabs(diff)));
00354                 double shiftscale=pow(10,exp);
00355                 // get the starting point for the grid
00356                 double startx=shiftscale*floor(minimum.x / shiftscale);
00357 
00358                 if(gridx_step>0)
00359                 {
00360                         xstep=gridx_step;
00361                 }
00362                 else    // auto grid size
00363                 {                       
00364                         xstep=shiftscale*1.0;
00365                         if(diff/xstep < 4) // draw more lines
00366                                 xstep*=0.5;
00367 
00368                         /*
00369                         xstep=floor(maximum.x / shiftscale) - floor(minimum.x / shiftscale);
00370                         xstep=2*floor(0.5*xstep);// if uneven, make even, because uneven stepsizes will cause uneven distributed lines around the (0,0) koordinate frame axis
00371                         xstep=shiftscale*xstep / 4.0;
00372                         */
00373                         
00374                 }
00375                 double x=startx;
00376                 
00377                 glLineWidth(grid_linewidth);
00378                 glColor3f(grid_color.r, grid_color.g, grid_color.b);
00379                 glBegin(GL_LINES);
00380                 int bailout=0; // bailout is a safety to avoid endless recursions caused maybe through numerical errors..
00381                 while(x<maximum.x && bailout<100)
00382                 {
00383                         x+=xstep;
00384                         bailout++;
00385                         glVertex2f((GLfloat)(x-offset.x)*scale.x        ,0.0f  );
00386                         glVertex2f((GLfloat)(x-offset.x)*scale.x        ,(float)h());
00387                 }
00388                 glEnd();
00389         }
00390         if(gridy==MP_LINEAR_GRID)
00391         {
00392                 double diff=maximum.y - minimum.y;
00393                 if(diff==0)return PLOT_POINT(0,0);
00394                 double exp=floor(log10(fabs(diff)));
00395                 double shiftscale=pow(10,exp);
00396                 // get the starting point for the grid
00397                 double starty=shiftscale*floor(minimum.y / shiftscale);
00398 
00399                 if(gridy_step>0)
00400                 {
00401                         ystep=gridy_step;
00402                 }
00403                 else    // auto grid size
00404                 {
00405                         ystep=shiftscale*1.0;
00406                         if(diff/ystep < 4) // draw more lines
00407                                 ystep*=0.5;
00408 
00409                         /*
00410                         ystep=floor(maximum.y / shiftscale) - floor(minimum.y / shiftscale);
00411                         ystep=2*floor(0.5*ystep); // if uneven, make even, because uneven stepsizes will cause uneven distributed lines around the (0,0) koordinate frame axis
00412                         ystep=shiftscale*ystep / 4.0;
00413                         */
00414 
00415                 }
00416                 double y=starty;
00417                 glLineWidth(1.0);
00418                 glColor3f(grid_color.r, grid_color.g, grid_color.b);
00419                 glBegin(GL_LINES);
00420                 int bailout=0; // bailout is a safety to avoid endless recursions caused maybe through numerical errors..
00421                 while(y<maximum.y && bailout<100)
00422                 {
00423                         y+=ystep;
00424                         bailout++;
00425                         glVertex2f(0.0f                                 ,(GLfloat)(y-offset.y)*scale.y);
00426                         glVertex2f((float)w()                   ,(GLfloat)(y-offset.y)*scale.y);
00427                 }
00428                 glEnd();
00429         }
00430 
00431         return PLOT_POINT((float)xstep,(float)ystep);
00432 }
00433 
00434 inline void MULTIPLOT::draw()
00435 {
00436         if(!valid())
00437         {
00438                 initgl();
00439                 valid(1);
00440         }
00441         
00442         glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);                 // Clear The Screen And Depth Buffer
00443 
00444 
00445 
00446         // draw the grid
00447         PLOT_POINT grid_spacing=draw_grid();
00448 
00449         // draw the coordinate cross with center (0,0)
00450         glLineWidth(2.0f*grid_linewidth);
00451         glColor3f(grid_color.r, grid_color.g, grid_color.b);
00452         glBegin(GL_LINES);
00453                 glVertex2f(0.0f                                 ,0-offset.y*scale.y);
00454                 glVertex2f((float)w()                   ,0-offset.y*scale.y);
00455                 glVertex2f(0-offset.x*scale.x   ,0.0f  );
00456                 glVertex2f(0-offset.x*scale.x   ,(float)h());           
00457         glEnd();
00458 
00459 
00460 
00461         maximum.x=maximum.y=-FLT_MAX;
00462         minimum.x=minimum.y=FLT_MAX;
00463 
00464 
00465         if(scroll)
00466         {
00467                 PLOT_POINT p;
00468                 for(unsigned int t=0;t<traces.size();t++)
00469                 {
00470                         glLineWidth(tsettings[t].line_width);
00471                         glBegin(GL_LINE_STRIP);
00472                         unsigned int ps=tsettings[t].pos;
00473                         unsigned int n=(unsigned int)traces[t].size();
00474                         if(max_points<n)n=max_points;
00475                         for(unsigned int a=0;a<n;a++)
00476                         {
00477                                 if(ps>=traces[t].size())
00478                                         ps=0;
00479                                 p=traces[t][ps];
00480                                 if(tsettings[t].line_width>0)
00481                                 {
00482                                         glColor3f(p.r,p.g,p.b);
00483                                         glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
00484                                 }
00485                                 if(p.x>maximum.x)maximum.x=p.x;
00486                                 if(p.x<minimum.x)minimum.x=p.x;
00487                                 if(p.y>maximum.y)maximum.y=p.y;
00488                                 if(p.y<minimum.y)minimum.y=p.y;         
00489         
00490                                 ps++;
00491                         }
00492                         glEnd();
00493                         glLineWidth(1.0);
00494 
00495                         
00496                         ps=tsettings[t].pos;
00497                         n=(unsigned int)traces[t].size();
00498                         glPointSize(tsettings[t].point_size);
00499                         glBegin(GL_POINTS);
00500                         for(a=0;a<n;a++)
00501                         {
00502                                 if(ps>=traces[t].size())
00503                                         ps=0;
00504                                 p=traces[t][ps];
00505                                 if(tsettings[t].point_size>0)
00506                                 {
00507                                         glColor3f(p.r,p.g,p.b);
00508                                         glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
00509                                 }
00510                                 ps++;
00511                         }
00512                         glEnd();
00513                 }
00514 
00515         }
00516         else
00517         {
00518                 PLOT_POINT p;
00519                 // for speedup skip points - this is useful if we have many many points
00520                 float step=1;
00521         
00522                 for(unsigned int t=0;t<traces.size();t++)
00523                 {
00524                         if(traces[t].size()>max_points)
00525                                 step=traces[t].size()/float(max_points);
00526 
00527                         glLineWidth(tsettings[t].line_width);
00528                         glBegin(GL_LINE_STRIP);
00529                         for(float a=0;a<traces[t].size();a+=step)
00530                         {
00531                                 p=traces[t][int(a)];
00532                                 if(tsettings[t].line_width>0)
00533                                 {
00534                                         glColor3f(p.r,p.g,p.b);
00535                                         glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
00536                                 }
00537                                 if(p.x>maximum.x)maximum.x=p.x;
00538                                 if(p.x<minimum.x)minimum.x=p.x;
00539                                 if(p.y>maximum.y)maximum.y=p.y;
00540                                 if(p.y<minimum.y)minimum.y=p.y;         
00541                         }
00542                         glEnd();
00543                         
00544                         if(tsettings[t].point_size>0)
00545                         {
00546                                 glPointSize(tsettings[t].point_size);
00547                                 glBegin(GL_POINTS);
00548                                 for(float a=0;a<traces[t].size();a+=step)
00549                                 {
00550                                         p=traces[t][int(a)];
00551                                         glColor3f(p.r,p.g,p.b);
00552                                         glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
00553                                 }
00554                                 glEnd();
00555                         }
00556                 }
00557         }
00558 
00559         float diff;     
00560         diff=maximum.x-minimum.x;       if(diff!=0.0)scale.x=w()/diff;
00561         diff=maximum.y-minimum.y;       if(diff!=0.0)scale.y=h()/diff;
00562         offset.x=minimum.x;
00563         offset.y=minimum.y;
00564 
00565         
00566         stringstream ss;
00567         ss << "range: x=[" <<  minimum.x << "; " << maximum.x << "] ";
00568         ss << "y=[" <<  minimum.y << "; " << maximum.y << "] "; 
00569         ss << "grid: w=[" <<  grid_spacing.x << "] ";
00570         ss << "h=[" <<  grid_spacing.y << "] ";
00571         this->label((ss.str() + title).c_str());
00572 
00573                 
00574 }
00575 
00576 #endif

Generated on Fri Oct 18 15:06:44 2002 for multiplot by doxygen1.2.18