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 #include <FL/Fl.H>
00028 #include <FL/Fl_Gl_Window.H>
00029 #include <FL/gl.h>
00030 #include <float.h>
00031 #include <time.h>
00032 #include <math.h>
00033 #include <vector>
00034 #include <string>
00035 #include <sstream>
00036 
00037 
00038 #ifndef min
00039         #define min(a,b)( (a) < (b) ) ? (a) : (b) )
00040 #endif
00041 
00042 
00043 
00044 using namespace std;
00045 
00046 enum MULTIPLOT_GRIDSTYLE
00047 {
00048         MP_NO_GRID,
00049         MP_LINEAR_GRID,
00050         MP_LOG_GRID
00051 };
00052 
00057 class PLOT_POINT
00058 {
00059         public:
00060                 float x;
00061                 float y;
00062                 float r;
00063                 float g;
00064                 float b;
00065                 PLOT_POINT();
00066                 PLOT_POINT(float xx, float yy, float rr=1, float gg=1, float bb=1);
00067 };
00068 
00073 class MULTIPLOT : public Fl_Gl_Window
00074 {
00075         public:
00080                 MULTIPLOT(int x, int y, int w, int h, const char *title="MULTIPLOT - updates on www.andre-krause.net");
00085                 void add(unsigned int trace, const PLOT_POINT &p);
00091                 void set_max_points(int mx);
00097                 void set_scrolling(int max_points_to_plot);
00105                 void set_grid(int gridx, int gridy, float gridx_step=-1, float gridy_step=-1);
00106         
00107         protected:
00108                 string title;           // stores the user-title, so we can add ranges
00109                 vector< vector<PLOT_POINT> > traces;
00110                 PLOT_POINT minimum, maximum;
00111                 PLOT_POINT scale;
00112                 PLOT_POINT offset;
00113                 unsigned int max_points;
00114                 bool scroll;
00115                 vector<unsigned int> pos;
00116 
00117                 // grid - vars
00118                 int gridx, gridy;
00119                 float gridx_step, gridy_step;
00120 
00121                 void initgl();
00122                 PLOT_POINT draw_grid();
00123                 void draw();
00124 };
00125 
00126 
00127 // implementation:
00128 
00129 inline PLOT_POINT::PLOT_POINT() { x=y=0.0;r=g=b=1; }
00130 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; }
00131 
00132 inline MULTIPLOT::MULTIPLOT(int x, int y, int w, int h, const char *ttitle) : Fl_Gl_Window(x,y,w,h,ttitle) 
00133 {       
00134         title=string(ttitle);
00135         //max.x=max.y=-FLT_MAX;
00136         maximum.x=maximum.y=-FLT_MAX;
00137         minimum.x=minimum.y=FLT_MAX;
00138         max_points=max(w,h);
00139         traces.push_back( vector<PLOT_POINT>() ); // create one trace
00140         pos.push_back(0);
00141 
00142         scroll=false;
00143         
00144         gridx=MP_NO_GRID;
00145         gridy=MP_NO_GRID;
00146         gridx_step=-1;
00147         gridy_step=-1;
00148 
00149 
00150         show();
00151 }
00152 
00153 inline void MULTIPLOT::add(unsigned int trace, const PLOT_POINT &p)
00154 { 
00155         if(traces.size()<=trace)
00156         {
00157                 int n=trace-traces.size()+1;
00158                 for(int a=0;a<n;a++)
00159                 {
00160                         traces.push_back(vector<PLOT_POINT>());
00161                         pos.push_back(0);
00162                 }
00163         }
00164 
00165         if(scroll)
00166         {
00167                 // this realises a sort of ringbuffer wich is needed for scrolling
00168                 if(pos[trace]<traces[trace].size())
00169                         traces[trace][pos[trace]]=p;
00170                 else
00171                         traces[trace].push_back(p);
00172                 pos[trace]++;
00173                 if(pos[trace]>=max_points)
00174                         pos[trace]=0;
00175         }
00176         else
00177         {
00178                 traces[trace].push_back(p);
00179         }
00180 }
00181 
00182 inline void MULTIPLOT::set_max_points(int mx)
00183 {
00184         max_points=mx;
00185 }
00186 
00187 inline void MULTIPLOT::set_scrolling(int max_points_to_plot)
00188 {
00189         if(max_points_to_plot<=0)
00190         {
00191                 scroll=false;
00192                 return;
00193         }
00194 
00195         scroll=true;
00196         max_points=max_points_to_plot;
00197         for(unsigned int t=0;t<traces.size();t++)
00198                 if(traces[t].capacity()<max_points)
00199                         traces[t].reserve(max_points);
00200         
00201 }
00202 
00203 inline void MULTIPLOT::set_grid(int ggridx, int ggridy, float ggridx_step, float ggridy_step)
00204 {
00205         gridx=ggridx;
00206         gridy=ggridy;
00207         gridx_step=ggridx_step;
00208         gridy_step=ggridy_step;
00209 }
00210 
00211 
00212 inline void MULTIPLOT::initgl()
00213 {
00214         glViewport(0 , 0,w() ,h());     // Set Up A Viewport
00215         glMatrixMode(GL_PROJECTION);                                                            // Select The Projection Matrix
00216         glLoadIdentity();                                                                                       // Reset The Projection Matrix
00217         glOrtho( 0, w(), 0, h(), -1, 1 );                                                       // Select Ortho Mode (640x480)
00218         //gluPerspective(50, (float)w()/(float)h(), 5,  2000); // Set Our Perspective
00219         glMatrixMode(GL_MODELVIEW);                                                                     // Select The Modelview Matrix
00220         glLoadIdentity();                                                                                       // Reset The Modelview Matrix
00221         glDisable(GL_DEPTH_TEST);                                                                       // Enable Depth Testing
00222         glDisable(GL_LIGHTING);
00223         glShadeModel(GL_SMOOTH);                                                                        // Select Smooth Shading
00224         glClearColor(0.0f, 0.0f, 0.0f, 1);                                              // Set The Clear Color To Medium Blue
00225         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                     // Clear The Screen And Depth Buffer
00226 }       
00227 
00228 
00229 
00230 inline PLOT_POINT MULTIPLOT::draw_grid()
00231 {
00232         double xstep,ystep;
00233         if(gridx==MP_LINEAR_GRID)
00234         {
00235                 double diff=maximum.x - minimum.x;
00236                 if(diff==0)return PLOT_POINT(0,0);
00237                 double exp=floor(log10(fabs(diff)));
00238                 double shiftscale=pow(10,exp);
00239                 // get the starting point for the grid
00240                 double startx=shiftscale*floor(minimum.x / shiftscale);
00241 
00242                 if(gridx_step>0)
00243                 {
00244                         xstep=gridx_step;
00245                 }
00246                 else    // auto grid size
00247                 {                       
00248                         xstep=shiftscale*1.0;
00249                         if(diff/xstep < 4) // draw more lines
00250                                 xstep*=0.5;
00251 
00252                         /*
00253                         xstep=floor(maximum.x / shiftscale) - floor(minimum.x / shiftscale);
00254                         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
00255                         xstep=shiftscale*xstep / 4.0;
00256                         */
00257                         
00258                 }
00259                 double x=startx;
00260                 glColor3f(0.8f,0.8f,0.8f);
00261                 glBegin(GL_LINES);
00262                 int bailout=0; // bailout is a safety to avoid endless recursions caused maybe through numerical errors..
00263                 while(x<maximum.x && bailout<100)
00264                 {
00265                         x+=xstep;
00266                         bailout++;
00267                         glVertex2f((GLfloat)(x-offset.x)*scale.x        ,0.0f  );
00268                         glVertex2f((GLfloat)(x-offset.x)*scale.x        ,(float)h());
00269                 }
00270                 glEnd();
00271         }
00272         if(gridy==MP_LINEAR_GRID)
00273         {
00274                 double diff=maximum.y - minimum.y;
00275                 if(diff==0)return PLOT_POINT(0,0);
00276                 double exp=floor(log10(fabs(diff)));
00277                 double shiftscale=pow(10,exp);
00278                 // get the starting point for the grid
00279                 double starty=shiftscale*floor(minimum.y / shiftscale);
00280 
00281                 if(gridy_step>0)
00282                 {
00283                         ystep=gridy_step;
00284                 }
00285                 else    // auto grid size
00286                 {
00287                         ystep=shiftscale*1.0;
00288                         if(diff/ystep < 4) // draw more lines
00289                                 ystep*=0.5;
00290 
00291                         /*
00292                         ystep=floor(maximum.y / shiftscale) - floor(minimum.y / shiftscale);
00293                         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
00294                         ystep=shiftscale*ystep / 4.0;
00295                         */
00296 
00297                 }
00298                 double y=starty;
00299                 glColor3f(0.8f,0.8f,0.8f);
00300                 glBegin(GL_LINES);
00301                 int bailout=0; // bailout is a safety to avoid endless recursions caused maybe through numerical errors..
00302                 while(y<maximum.y && bailout<100)
00303                 {
00304                         y+=ystep;
00305                         bailout++;
00306                         glVertex2f(0.0f                                 ,(GLfloat)(y-offset.y)*scale.y);
00307                         glVertex2f((float)w()                   ,(GLfloat)(y-offset.y)*scale.y);
00308                 }
00309                 glEnd();
00310         }
00311 
00312         return PLOT_POINT((float)xstep,(float)ystep);
00313 }
00314 
00315 inline void MULTIPLOT::draw()
00316 {
00317         if(!valid())
00318         {
00319                 initgl();
00320                 valid(1);
00321         }
00322         
00323         glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT);                 // Clear The Screen And Depth Buffer
00324 
00325 
00326 
00327         // draw the grid
00328         draw_grid();
00329 
00330         // draw the coordinate cross with center (0,0)
00331         glColor3f(1,1,1);
00332         glBegin(GL_LINES);
00333                 glVertex2f(0.0f                                 ,0-offset.y*scale.y);
00334                 glVertex2f((float)w()                   ,0-offset.y*scale.y);
00335                 glVertex2f(0-offset.x*scale.x   ,0.0f  );
00336                 glVertex2f(0-offset.x*scale.x   ,(float)h());           
00337         glEnd();
00338 
00339 
00340 
00341         maximum.x=maximum.y=-FLT_MAX;
00342         minimum.x=minimum.y=FLT_MAX;
00343         if(scroll)
00344         {
00345                 PLOT_POINT p;
00346                 for(unsigned int t=0;t<traces.size();t++)
00347                 {
00348                         glBegin(GL_LINE_STRIP);
00349                         unsigned int ps=pos[t];
00350                         unsigned int n=traces[t].size();
00351                         if(max_points<n)n=max_points;
00352                         for(unsigned int a=0;a<n;a++)
00353                         {
00354                                 if(ps>=traces[t].size())
00355                                         ps=0;
00356                                 p=traces[t][ps];
00357                                 glColor3f(p.r,p.g,p.b);
00358                                 glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
00359                                 if(p.x>maximum.x)maximum.x=p.x;
00360                                 if(p.x<minimum.x)minimum.x=p.x;
00361                                 if(p.y>maximum.y)maximum.y=p.y;
00362                                 if(p.y<minimum.y)minimum.y=p.y;         
00363         
00364                                 ps++;
00365                         }
00366                         glEnd();
00367                 }
00368 
00369         }
00370         else
00371         {
00372                 
00373                 PLOT_POINT p;
00374                 // for speedup skip points - this is useful if we have many many points
00375                 float step=1;
00376         
00377                 for(unsigned int t=0;t<traces.size();t++)
00378                 {
00379                         if(traces[t].size()>max_points)
00380                                 step=traces[t].size()/float(max_points);
00381 
00382                         glBegin(GL_LINE_STRIP);
00383                         for(float a=0;a<traces[t].size();a+=step)
00384                         {
00385                                 p=traces[t][int(a)];
00386                                 glColor3f(p.r,p.g,p.b);
00387                                 glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
00388                                 if(p.x>maximum.x)maximum.x=p.x;
00389                                 if(p.x<minimum.x)minimum.x=p.x;
00390                                 if(p.y>maximum.y)maximum.y=p.y;
00391                                 if(p.y<minimum.y)minimum.y=p.y;         
00392                         }
00393                         glEnd();
00394                 }
00395         }
00396 
00397         float diff;     
00398         diff=maximum.x-minimum.x;       if(diff!=0.0)scale.x=w()/diff;
00399         diff=maximum.y-minimum.y;       if(diff!=0.0)scale.y=h()/diff;
00400         offset.x=minimum.x;
00401         offset.y=minimum.y;
00402 
00403         
00404         stringstream ss;
00405         ss << "range: x=[" <<  minimum.x << "; " << maximum.x << "] ";
00406         ss << "y=[" <<  minimum.y << "; " << maximum.y << "] "; 
00407         this->label((ss.str() + title).c_str());
00408 
00409                 
00410 }
00411 
00412 #endif

Generated on Thu Oct 3 19:14:57 2002 for multiplot by doxygen1.2.18