00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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;
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
00155
00156
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
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
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
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>() );
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
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);
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());
00331 glMatrixMode(GL_PROJECTION);
00332 glLoadIdentity();
00333 glOrtho( 0, w(), 0, h(), -1, 1 );
00334
00335 glMatrixMode(GL_MODELVIEW);
00336 glLoadIdentity();
00337 glDisable(GL_DEPTH_TEST);
00338 glDisable(GL_LIGHTING);
00339 glShadeModel(GL_SMOOTH);
00340 glClearColor(bg_color.r, bg_color.g, bg_color.b, 1);
00341 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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
00356 double startx=shiftscale*floor(minimum.x / shiftscale);
00357
00358 if(gridx_step>0)
00359 {
00360 xstep=gridx_step;
00361 }
00362 else
00363 {
00364 xstep=shiftscale*1.0;
00365 if(diff/xstep < 4)
00366 xstep*=0.5;
00367
00368
00369
00370
00371
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;
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
00397 double starty=shiftscale*floor(minimum.y / shiftscale);
00398
00399 if(gridy_step>0)
00400 {
00401 ystep=gridy_step;
00402 }
00403 else
00404 {
00405 ystep=shiftscale*1.0;
00406 if(diff/ystep < 4)
00407 ystep*=0.5;
00408
00409
00410
00411
00412
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;
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);
00443
00444
00445
00446
00447 PLOT_POINT grid_spacing=draw_grid();
00448
00449
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
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