Multiplot  0.5.5
multiplot.h
1 #pragma once
2 /*
3  * multiplot.h
4  * Copyright 2002-2016 by Andre Frank Krause.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA.
20  *
21  * Please report all bugs and problems to "post@andre-krause.net".
22  * New versions and bug-fixes under http://www.andre-krause.net
23  *
24  */
25 
26  /*
27 INSTALL
28  if you want to try multiplot, create with your favourite c++compiler/ide
29  a simple hello world:
30 
31  main.cpp:
32 
33  1 int main(int argc, char**argv){ cout<<"hello world";return 1;}
34 
35 
36  if that works, remove the above line and type (remove the line numbers):
37 
38  1 #define __TEST_THIS_MODULE__
39  2 #define MULTIPLOT_WIN32 // if you have FLTK: #define MULTIPLOT_FLTK
40  3 #include "multiplot.h"
41  4 int main(int argc, char ** argv) { test_module(); }
42 
43  and compile that. this gives you some demos on what you can do with multiplot (see end
44  of that file for the demo - code)
45  - Hints:
46  * Linux:
47  try the following line:
48  gcc -lfltk -lfltk_gl -o testplot testplots.cpp
49  * Windows:
50  visual studio:
51  1. start visual studio. create a new project (file->new->project..).
52  2. select: win32 -> win32 console application
53  3. press ok, then select "application settings", there choos "empty project"
54  4. add a new c++ file in the solution explorer and type the above
55  devcpp:
56  there seems to be a compiler bug with rtti, so
57  1. disable rtti with the c++ compiler flag "-fno-rtti" (project options->parameters)
58  2. include the following libraries for opengl:
59  -lglu32 -lglaux -lgdi32 -lglu32 -lopengl32 -lfltk_gl -lfltk -lole32 -luuid -lcomctl32 -lwsock32 -lm
60 
61 
62 CHANGELOG
63  20160608:
64  - several small c++ 'modernizations' of the code
65  - title can now be a wide string (std::wstring). if you prefer a normal string s, convert it using "wstring(s.begin(), s.end())"
66  20090910:
67  - added plotting of values stored in a std::vector - plot(const std::vector<T>& v)
68  20090621:
69  - added different scaling behaviours (auto, auto with equally scaled axes, fixed)
70  20061031:
71  - redesigned interface. parameters like current drawing color and current trace
72  can be set in an opengl-manner ( example: first, select a trace with m.trace(1),
73  the set the color of that trace with m.color3f(r,g,b) )
74  OR by accessing the wanted trace with m[1].color3f(r,g,b); m[1].plot(x,y)
75  - now, you can set for each individual plot point the pointsize and line-width.
76  - decoupled from FLTK - library. under win32 you no longer need to have FLTK. just load
77  multiplot.h, create an Instance Multiplot myplot(10,10,300,300) and you will get a nice
78  window at 10,10 with size 300.
79 
80  20050304:
81  compiling under devc++ (there seems to be a compiler bug with rtti)
82  1. disable rtti with the c++ compiler flag "-fno-rtti" (project options->parameters)
83  2. include the following libraries for opengl:
84  -lglu32 -lglaux -lgdi32 -lglu32 -lopengl32 -lfltk_gl -lfltk -lole32 -luuid -lcomctl32 -lwsock32 -lm
85 
86  20041139
87  - Andre Krause <post@andre-krause.net>
88  - updated visual studio project files
89 
90  - Thorsten Roggendorf / Sven Hartmeier
91  - Linux bugfixes
92  - added a simple build script instead of automake and configure
93 
94  20021018
95  - Andre Krause <post@andre-krause.net>
96  - now you can specify the color of the background and the grid-lines
97  - you can define the line-width of the traces and grid-lines
98  - you can plot points in combination with lines in your traces, or points only (scatter-plot)
99 
100  20021003
101  - Thorsten Roggendorf
102  - linux configure - script
103  - Andre Krause <post@andre-krause.net>
104  - moved implementation of member functions back to the header file as inline functions to simplify usage. now you simply need to include "multiplot.h".
105  - autoscaling grid (linear spacing only at the moment, log spacing will follow)
106  20020729
107  - Andre Krause <post@andre-krause.net>
108  - initial release
109 */
110 
111 
112 #if defined(MULTIPLOT_FLTK) || defined(MULTIPLOT_WIN32)
113 #else
114  #ifdef Fl_Object
115  #define MULTIPLOT_FLTK
116  #else
117  #define MULTIPLOT_WIN32
118  //#pragma(warning, "Please define either MULTIPLOT_FLTK or MULTIPLOT_WIN32 before including multiplot.h .")
119  #endif
120 #endif
121 
122 
123 #include <iostream>
124 #include <sstream>
125 #include <float.h>
126 #include <time.h>
127 #include <math.h>
128 #include <vector>
129 #include <string>
130 #include <algorithm>
131 #include <locale> // to convert wstring to string
132 #include <codecvt> // to convert wstring to string
133 
134 
135 #ifdef MULTIPLOT_FLTK // tell multiplot to use Fltk to create an Opengl-Window
136  #include <FL/gl.h>
137  #include <FL/Fl.H>
138  #include <FL/Fl_Gl_Window.H>
139  #include <FL/fl_draw.H>
140 #endif
141 
142 
143 
144 #if defined(_WIN32) && !defined(APIENTRY)
145  #define WIN32_LEAN_AND_MEAN 1
146  #include <windows.h>
147 #endif
148 
149 #ifndef MULTIPLOT_FLTK // don't include default gl.h, if using fltk, because fltk comes with its own gl.h
150  #include <GL/gl.h>
151 #endif
152 
153 
154 namespace multiplot
155 {
156 
160 enum MP_GRIDSTYLE
161 {
162  MP_NO_GRID,
163  MP_LINEAR_GRID,
164  MP_LOG_GRID
165 };
166 
167 enum MP_SCALING
168 {
169  MP_AUTO_SCALE,
170  MP_AUTO_SCALE_EQUAL,
171  MP_FIXED_SCALE
172 };
173 
174 
175 
177 // now comes platform specific code for opening a window to draw in
178 
179 #ifdef MULTIPLOT_FLTK
180 
181 class Multiplot_base : public Fl_Gl_Window
182 {
183 protected:
184  unsigned int width = 0;
185  unsigned int height = 0;
186  std::string caption;
187 public:
192  Multiplot_base(int x, int y, int w, int h, const std::wstring& title_, bool fullscreen_) : Fl_Gl_Window(x,y,w,h)
193  {
194  width = w;
195  height = h;
196  resizable(*this);
197  set_caption(title_);
198  if(fullscreen_)
199  fullscreen();
200  }
201 
202  bool check()
203  {
204  return (bool)Fl::check();
205  }
206 
207  void draw()
208  {
209  if(!valid())
210  {
211  valid(1);
212  }
213 
214 
215  Fl_Gl_Window::draw();
216 
217 
218  }
219 
220  void set_caption(const std::string& t)
221  {
222  caption = t;
223  this->label(caption.c_str());
224  }
225  void set_caption(const std::wstring& t)
226  {
227  //setup converter
228  using convert_type = std::codecvt_utf8<wchar_t>;
229  caption = std::wstring_convert<convert_type, wchar_t>().to_bytes(t);
230  this->label(caption.c_str());
231  }
232 
233 };
234 #endif
235 
236 #ifdef MULTIPLOT_WIN32
237 
238 #ifdef _WIN32
239 #pragma message(" _Adding library: opengl32.lib" )
240 #pragma comment ( lib, "opengl32.lib")
241 #endif
242 
248 {
249 protected:
250 
251  unsigned int width; // window - width
252  unsigned int height; // window - height
253  bool valid_;
254 
255  bool active;
256  bool fullscreen;
257  HDC hDC; // Private GDI Device Context
258  HGLRC hRC; // Permanent Rendering Context
259  HWND hWnd; // Holds Our Window Handle
260  HINSTANCE hInstance; // Holds The Instance Of The Application
261 
262  static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
263  {
264  Multiplot_base* pParent;
265 
266  // Get pointer to window
267  if(uMsg == WM_CREATE)
268  {
269  pParent = (Multiplot_base*)((LPCREATESTRUCT)lParam)->lpCreateParams;
270  SetWindowLongPtr(hWnd, GWLP_USERDATA,(LONG_PTR)pParent);
271  }
272  else
273  {
274  pParent = (Multiplot_base*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
275  if(!pParent) return DefWindowProc(hWnd,uMsg,wParam,lParam);
276  }
277 
278  pParent->hWnd = hWnd;
279  return pParent->WndProc(uMsg,wParam,lParam);
280  }
281 
282  LRESULT WndProc( // Handle For This Window
283  UINT uMsg, // Message For This Window
284  WPARAM wParam, // Additional Message Information
285  LPARAM lParam) // Additional Message Information
286  {
287 
288  switch (uMsg) // Check For Windows Messages
289  {
290  case WM_ACTIVATE: // Watch For Window Activate Message
291  {
292  if (!HIWORD(wParam)) // Check Minimization State
293  {
294  active=TRUE; // Program Is Active
295  }
296  else
297  {
298  active=FALSE; // Program Is No Longer Active
299  }
300 
301  return 0; // Return To The Message Loop
302  }
303 
304  case WM_SYSCOMMAND: // Intercept System Commands
305  {
306  switch (wParam) // Check System Calls
307  {
308  case SC_SCREENSAVE: // Screensaver Trying To Start?
309  case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
310  return 0; // Prevent From Happening
311  }
312  break; // Exit
313  }
314 
315  case WM_CLOSE: // Did We Receive A Close Message?
316  {
317  PostQuitMessage(0); // Send A Quit Message
318  return 0; // Jump Back
319  }
320 
321  case WM_KEYDOWN: // Is A Key Being Held Down?
322  {
323  //keys[wParam] = TRUE; // If So, Mark It As TRUE
324  return 0; // Jump Back
325  }
326 
327  case WM_KEYUP: // Has A Key Been Released?
328  {
329  //keys[wParam] = FALSE; // If So, Mark It As FALSE
330  return 0; // Jump Back
331  }
332 
333  case WM_SIZE: // Resize The OpenGL Window
334  {
335  width = LOWORD(lParam);
336  height = HIWORD(lParam);
337  valid_ = false; // set flag to tell we need to re-init opengl
338  return 0; // Jump Back
339  }
340  }
341 
342  // Pass All Unhandled Messages To DefWindowProc
343  return DefWindowProc(hWnd,uMsg,wParam,lParam);
344  }
345 
346 
347 
348 
349 
350  /* This Code Creates Our OpenGL Window. Parameters Are: *
351  * width - Width Of The GL Window Or Fullscreen Mode *
352  * height - Height Of The GL Window Or Fullscreen Mode *
353  * bits - Number Of Bits To Use For Color (8/16/24/32) *
354  */
355  bool CreateGLWindow(int x, int y, int width, int height, const std::wstring& title, BYTE bits=0, bool fullscreenflag=false)
356  {
357  GLuint PixelFormat; // Holds The Results After Searching For A Match
358  WNDCLASS wc; // Windows Class Structure
359  DWORD dwExStyle; // Window Extended Style
360  DWORD dwStyle; // Window Style
361  RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values
362  WindowRect.left=(long)0; // Set Left Value To 0
363  WindowRect.right=(long)width; // Set Right Value To Requested Width
364  WindowRect.top=(long)0; // Set Top Value To 0
365  WindowRect.bottom=(long)height; // Set Bottom Value To Requested Height
366 
367  fullscreen=fullscreenflag; // Set The Global Fullscreen Flag
368 
369  hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window
370  wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Size, And Own DC For Window.
371  wc.lpfnWndProc = (WNDPROC) (Multiplot_base::StaticWndProc);// window_handler Handles Messages
372  wc.cbClsExtra = 0; // No Extra Window Data
373  wc.cbWndExtra = 0; // No Extra Window Data
374  wc.hInstance = hInstance; // Set The Instance
375  wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
376  wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
377  wc.hbrBackground = NULL; // No Background Required For GL
378  wc.lpszMenuName = NULL; // We Don't Want A Menu
379  wc.lpszClassName = L"OpenGL"; // Set The Class Name
380 
381 
382  if (!RegisterClass(&wc)) // Attempt To Register The Window Class
383  {
384  throw(std::exception("Failed To Register The Window Class."));
385  }
386 
387  if (fullscreen) // Attempt Fullscreen Mode?
388  {
389  DEVMODE dmScreenSettings; // Device Mode
390  memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); // Makes Sure Memory's Cleared
391  dmScreenSettings.dmSize=sizeof(dmScreenSettings); // Size Of The Devmode Structure
392  dmScreenSettings.dmPelsWidth = width; // Selected Screen Width
393  dmScreenSettings.dmPelsHeight = height; // Selected Screen Height
394  dmScreenSettings.dmBitsPerPel = bits; // Selected Bits Per Pixel
395  dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
396 
397  // Try To Set Selected Mode And Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
398  if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
399  {
400  // If The Mode Fails, Offer Two Options. Quit Or Use Windowed Mode.
401  std::cerr << "The Requested Fullscreen Mode is not supported by your Video Card. Using Windowed Mode instead." << std::endl;
402  fullscreen=false; // Windowed Mode Selected. Fullscreen = FALSE
403  }
404  }
405 
406  if (fullscreen) // Are We Still In Fullscreen Mode?
407  {
408  dwExStyle=WS_EX_APPWINDOW; // Window Extended Style
409  dwStyle=WS_POPUP; // Windows Style
410  ShowCursor(FALSE); // Hide Mouse Pointer
411  }
412  else
413  {
414  dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
415  dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style
416  }
417 
418  AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requested Size
419 
420  // Create The Window
421  if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window
422  L"OpenGL", // Class Name
423  title.c_str(), // Window Title
424  dwStyle | // Defined Window Style
425  WS_CLIPSIBLINGS | // Required Window Style
426  WS_CLIPCHILDREN, // Required Window Style
427  x, y, // Window Position
428  WindowRect.right-WindowRect.left, // Calculate Window Width
429  WindowRect.bottom-WindowRect.top, // Calculate Window Height
430  NULL, // No Parent Window
431  NULL, // No Menu
432  hInstance, // Instance
433  this))) // Dont Pass Anything To WM_CREATE
434  {
435  //KillGLWindow(); // Reset The Display
436  throw(std::exception("Window Creation Error."));
437  }
438 
439  static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
440  {
441  sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
442  1, // Version Number
443  PFD_DRAW_TO_WINDOW | // Format Must Support Window
444  PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
445  PFD_DOUBLEBUFFER, // Must Support Double Buffering
446  PFD_TYPE_RGBA, // Request An RGBA Format
447  bits, // Select Our Color Depth
448  0, 0, 0, 0, 0, 0, // Color Bits Ignored
449  0, // No Alpha Buffer
450  0, // Shift Bit Ignored
451  0, // No Accumulation Buffer
452  0, 0, 0, 0, // Accumulation Bits Ignored
453  16, // 16Bit Z-Buffer (Depth Buffer)
454  0, // No Stencil Buffer
455  0, // No Auxiliary Buffer
456  PFD_MAIN_PLANE, // Main Drawing Layer
457  0, // Reserved
458  0, 0, 0 // Layer Masks Ignored
459  };
460 
461  if (!(hDC=GetDC(hWnd))) // Did We Get A Device Context?
462  {
463  //KillGLWindow(); // Reset The Display
464  throw(std::exception("Can't Create A GL Device Context."));
465  }
466 
467  if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd))) // Did Windows Find A Matching Pixel Format?
468  {
469  //KillGLWindow(); // Reset The Display
470  throw(std::exception("Can't Find A Suitable PixelFormat."));
471  }
472 
473  if(!SetPixelFormat(hDC,PixelFormat,&pfd)) // Are We Able To Set The Pixel Format?
474  {
475  //KillGLWindow(); // Reset The Display
476  throw(std::exception("Can't Set The PixelFormat."));
477  }
478 
479  if (!(hRC=wglCreateContext(hDC))) // Are We Able To Get A Rendering Context?
480  {
481  throw(std::exception("Can't Create A GL Rendering Context."));
482  }
483 
484  if(!wglMakeCurrent(hDC,hRC)) // Try To Activate The Rendering Context
485  {
486  throw(std::exception("Can't Activate The GL Rendering Context."));
487  }
488 
489  ShowWindow(hWnd,SW_SHOW); // Show The Window
490  SetForegroundWindow(hWnd); // Slightly Higher Priority
491  SetFocus(hWnd); // Sets Keyboard Focus To The Window
492  //ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen
493 
494  /*if (!InitGL()) // Initialize Our Newly Created GL Window
495  {
496  KillGLWindow(); // Reset The Display
497  MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
498  return FALSE; // Return FALSE
499  }*/
500 
501  return true; // Success
502  }
503 
504  void DestroyGLWindow()
505  {
506  // destroy the window and rendering context
507  if (fullscreen) // Are We In Fullscreen Mode?
508  {
509  ChangeDisplaySettings(NULL,0); // If So Switch Back To The Desktop
510  ShowCursor(TRUE); // Show Mouse Pointer
511  }
512 
513  if (hRC) // Do We Have A Rendering Context?
514  {
515  if (!wglMakeCurrent(NULL,NULL)) // Are We Able To Release The DC And RC Contexts?
516  {
517  throw(std::exception("Release Of DC And RC Failed."));
518  }
519 
520  if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC?
521  {
522  throw(std::exception("Release Rendering Context Failed."));
523  }
524  hRC=NULL; // Set RC To NULL
525  }
526 
527  if (hDC && !ReleaseDC(hWnd,hDC)) // Are We Able To Release The DC
528  {
529  throw(std::exception("Release Device Context Failed."));
530  hDC=NULL; // Set DC To NULL
531  }
532 
533  if (hWnd && !DestroyWindow(hWnd)) // Are We Able To Destroy The Window?
534  {
535  throw(std::exception("Could Not Release hWnd."));
536  hWnd=NULL; // Set hWnd To NULL
537  }
538 
539  if (!UnregisterClass(L"OpenGL",hInstance)) // Are We Able To Unregister Class
540  {
541  throw(std::exception("Could Not Unregister Class."));
542  hInstance=NULL; // Set hInstance To NULL
543  }
544  }
545 
546  static LRESULT CALLBACK window_handler( HWND hWnd, // Handle For This Window
547  UINT uMsg, // Message For This Window
548  WPARAM wParam, // Additional Message Information
549  LPARAM lParam) // Additional Message Information
550  {
551  switch (uMsg) // Check For Windows Messages
552  {
553  case WM_ACTIVATE: // Watch For Window Activate Message
554  {
555  if (!HIWORD(wParam)) // Check Minimization State
556  {
557  //active=TRUE; // Program Is Active
558  }
559  else
560  {
561  //active=FALSE; // Program Is No Longer Active
562  }
563 
564  return 0; // Return To The Message Loop
565  }
566 
567  case WM_SYSCOMMAND: // Intercept System Commands
568  {
569  switch (wParam) // Check System Calls
570  {
571  case SC_SCREENSAVE: // Screensaver Trying To Start?
572  case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
573  return 0; // Prevent From Happening
574  }
575  break; // Exit
576  }
577 
578  case WM_CLOSE: // Did We Receive A Close Message?
579  {
580  PostQuitMessage(0); // Send A Quit Message
581  return 0; // Jump Back
582  }
583 
584  case WM_KEYDOWN: // Is A Key Being Held Down?
585  {
586  //keys[wParam] = TRUE; // If So, Mark It As TRUE
587  return 0; // Jump Back
588  }
589 
590  case WM_KEYUP: // Has A Key Been Released?
591  {
592  //keys[wParam] = FALSE; // If So, Mark It As FALSE
593  return 0; // Jump Back
594  }
595 
596  case WM_SIZE: // Resize The OpenGL Window
597  {
598  LPARAM x = lParam;
599  int xx = LOWORD(lParam);
600  //((Multiplot*)x)->width =x;
601  // todo... problem with member function pointer
602  /*((Multiplot*)wParam)->width = LOWORD(lParam); // LoWord=Width, HiWord=Height
603  ((Multiplot*)wParam)->height = HIWORD(lParam);
604  ((Multiplot*)wParam)->initgl();*/
605  return 0; // Jump Back
606  }
607  }
608 
609  // Pass All Unhandled Messages To DefWindowProc
610  return DefWindowProc(hWnd,uMsg,wParam,lParam);
611  }
612 
613 
614 
615 public:
616  virtual ~Multiplot_base(){ DestroyGLWindow(); }
617 
622  Multiplot_base(int x, int y, int w, int h, const std::wstring& ttitle, bool fullscreen)
623  {
624  hDC=NULL;
625  CreateGLWindow(x, y, w, h, ttitle, 32, fullscreen);
626  }
627 
632  void show()
633  {
634  }
635 
636  bool check()
637  {
638  MSG msg;
639  bool ok=true;
640 
641  if(GetAsyncKeyState(VK_ESCAPE) & 0x8000)
642  ok=false;
643 
644  // now, check any messages, so win32 is happy
645  if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))//GetMessage( &msg, NULL, 0, 0 ) )
646  {
647  TranslateMessage(&msg);
648  DispatchMessage(&msg);
649  }
650  //else
651  // ok=false;
652 
653  return ok;
654  }
655 
656  unsigned int w() { return width; }
657  unsigned int h() { return height; }
658  bool valid() { return valid_; }
659  void valid(bool v) { valid_=v; }
660 
661  virtual void draw()
662  {
663  }
664 
665  void set_caption(const std::wstring& t)
666  {
667  // TODO
668  }
669 
673  void redraw()
674  {
675  draw();
676  check();
677  SwapBuffers(hDC);
678  }
679 };
680 
681 #endif
682 
687 class Multiplot : public Multiplot_base
688 {
689 protected:
690  class Point2d
691  {
692  public:
693  float x = 0.0f;
694  float y = 0.0f;
695  float r = 1.0f;
696  float g = 1.0f;
697  float b = 1.0f;
698  float point_size = 0.0f;
699  float line_width = 1.0f; // width of the line from this point to the next point
700 
701  Point2d() {}
702  Point2d(float xx, float yy, float rr=1, float gg=1, float bb=1, float _lwidth=1.0, float _point_size=0.0)
703  {
704  x=xx;y=yy;
705  r=rr;g=gg;b=bb;
706  point_size=_point_size;
707  line_width=_lwidth;
708  }
709  };
710 
711 public:
712  // class Trace describes a single trace
713  // if scroll=true it works as a ringbuffer.
714  // the ringbuffer is filled till max_points.
715  // pos stores the actual read/write position in the ringbuffer
716 
721  class Trace : public std::vector<Point2d>
722  {
723  public:
724  unsigned int max_points;
725  bool scroll;
726  unsigned int pos; // current position in the ringbuffer
727  float cur_col[3];
728  float cur_line_width;
729  float cur_point_size;
730  void draw(Point2d& minimum, Point2d& maximum, Point2d& scale, Point2d& offset)
731  {
732  if(size()==0)return;
733 
734  Point2d p,p1,p2;
735  int start=0;
736  if(scroll)
737  start = pos;
738 
739  float line_width=at(start%size()).line_width;
740  glLineWidth(line_width);
741  glBegin(GL_LINES);
742  for(unsigned int a=start;a<start+size()-1;a++)
743  {
744  //if(ps>=size())
745  // ps=0;
746  p1=(*this)[a % size()];
747  p2=(*this)[(a+1) % size()];
748 
749  // TODO: if distance between two points is smaller than a pixel, then
750  // skip and interpolate till we have at least a line with length=1pixel
751 
752  if(p1.line_width>0)
753  {
754 
755  // reduce number of opengl state changes. so begin a new GL_LINES block
756  // only if line_width has changed.
757  if(p1.line_width != line_width)
758  {
759  glEnd();
760  line_width = p1.line_width;
761  glLineWidth(line_width);
762  glBegin(GL_LINES);
763  }
764  glColor3f(p1.r,p1.g,p1.b);
765  glVertex2f((p1.x-offset.x)*scale.x,(p1.y-offset.y)*scale.y);
766  glColor3f(p2.r,p2.g,p2.b);
767  glVertex2f((p2.x-offset.x)*scale.x,(p2.y-offset.y)*scale.y);
768  }
769  if(p1.x>maximum.x)maximum.x=p1.x;
770  if(p1.x<minimum.x)minimum.x=p1.x;
771  if(p1.y>maximum.y)maximum.y=p1.y;
772  if(p1.y<minimum.y)minimum.y=p1.y;
773  }
774  glEnd();
775  if(p2.x>maximum.x)maximum.x=p2.x;
776  if(p2.x<minimum.x)minimum.x=p2.x;
777  if(p2.y>maximum.y)maximum.y=p2.y;
778  if(p2.y<minimum.y)minimum.y=p2.y;
779 
780 
781  float point_size=at(start%size()).line_width;
782  glPointSize(point_size);
783  glBegin(GL_POINTS);
784  for(unsigned int a=start;a<start+size();a++)
785  {
786  p=(*this)[a%size()];
787  if(p.point_size>0.0)
788  {
789  // reduce number of opengl state changes.
790  if(p.point_size != point_size)
791  {
792  glEnd();
793  point_size = p.point_size;
794  glPointSize(point_size);
795  glBegin(GL_POINTS);
796  }
797  glColor3f(p.r,p.g,p.b);
798  glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
799  }
800  glEnd();
801  }
802 
803  /*
804  {
805  Point2d p;
806  // for speedup skip points - this is useful if we have many many points
807  float step=1;
808 
809  for(unsigned int t=0;t<size();t++)
810  {
811  if(size()>max_points)
812  step=size()/float(max_points);
813 
814  glLineWidth(p.line_width);
815  glBegin(GL_LINE_STRIP);
816  for(float a=0;a<size();a+=step)
817  {
818  p=(*this)[int(a)];
819  if(p.line_width>0)
820  {
821  glColor3f(p.r,p.g,p.b);
822  glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
823  }
824  if(p.x>maximum.x)maximum.x=p.x;
825  if(p.x<minimum.x)minimum.x=p.x;
826  if(p.y>maximum.y)maximum.y=p.y;
827  if(p.y<minimum.y)minimum.y=p.y;
828  }
829  glEnd();
830 
831  //glBegin(GL_POINTS);
832  for(float a=0;a<size();a+=step)
833  {
834  p=(*this)[int(a)];
835  if(p.point_size>0.0)
836  {
837  glPointSize(p.point_size);
838  glColor3f(p.r,p.g,p.b);
839  glBegin(GL_POINTS);
840  glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
841  glEnd();
842  }
843 
844  //glColor3f(p.r,p.g,p.b);
845  //glVertex2f((p.x-offset.x)*scale.x,(p.y-offset.y)*scale.y);
846  }
847  }
848  }*/
849  }
850 
851  public:
852  Trace()
853  {
854  cur_col[0]=cur_col[1]=cur_col[2]=1.0;
855  cur_line_width=1.0;
856  cur_point_size=0.0;
857  scroll=false;
858  pos=0;
859  max_points=10000;//max(w,h); <- setting max_points that low gives problems with scatter plots
860  }
861 
866  void plot(const float x, const float y)
867  {
868 
869  Point2d p(x,y, cur_col[0], cur_col[1], cur_col[2], cur_line_width, cur_point_size);
870  if(scroll)
871  {
872  // this realises a sort of ringbuffer wich is needed for scrolling
873  if(pos<size())
874  (*this)[pos]=p;
875  else
876  push_back(p);
877  pos++;
878 
879  if(pos>=max_points)
880  pos=0;
881  }
882  else
883  push_back(p);
884  }
885 
886 
887 
888 
893  void color3f(float r, float g, float b)
894  {
895  cur_col[0]=r;
896  cur_col[1]=g;
897  cur_col[2]=b;
898  }
899 
905  void set_linewidth(float width){ cur_line_width=width; }
906 
912  void set_pointsize(float psize){ cur_point_size = psize; }
913 
914 
920  void set_max_points(int mx){ max_points=mx;}
921 
927  void set_scrolling(int max_points_to_plot)
928  {
929  if(max_points_to_plot<=0)
930  {
931  scroll=false;
932  return;
933  }
934 
935  scroll=true;
936  max_points=max_points_to_plot;
937  //if(traces[cur_trace].capacity()<max_points)
938  // traces[cur_trace].reserve(max_points);
939 
940  }
941 
947  void clear() { std::vector<Point2d>::clear(); pos=0; }
948  };
949 
950 
951  virtual ~Multiplot() {}
952  // warning: unused parameter 'x'
953  // warning: unused parameter 'y'
954  Multiplot(const int x,const int y,const int w,const int h, const std::wstring& ttitle=L"Multiplot - updates on www.andre-krause.net", bool fullscreen=false) : Multiplot_base(x,y,w,h,ttitle,fullscreen)
955  {
956  cur_point_size=0.0;
957  cur_trace=0;
958 
959  title=ttitle;
960 
961  // auto scaling vars
962  scaling_ = MP_AUTO_SCALE;
963  maximum.x=maximum.y=-FLT_MAX;
964  minimum.x=minimum.y=FLT_MAX;
965  Point2d range_min, range_max;
966 
967  traces.push_back( Trace() ); // create one trace
968 
969  gridx=MP_NO_GRID;
970  gridy=MP_NO_GRID;
971  gridx_step=-1;
972  gridy_step=-1;
973 
974  bg_color.r=0.0f;
975  bg_color.g=0.0f;
976  bg_color.b=0.0f;
977 
978  grid_color.r=0.8f;
979  grid_color.g=0.8f;
980  grid_color.b=0.8f;
981  grid_linewidth=1.0f;
982 
983  }
984 
985 
989  Trace& operator[](int _trace) { return trace(_trace); }
993  Trace& operator()(int _trace) { return trace(_trace); }
994 
999  Trace& trace(int _trace)
1000  {
1001  cur_trace = _trace;
1002  if (cur_trace < 0) { cur_trace = 0; }
1003  if(traces.size() <= cur_trace )
1004  {
1005  for(size_t a = 0; a < cur_trace - traces.size() + 1; a++)
1006  traces.push_back(Trace());
1007  }
1008  return traces[_trace];
1009  }
1010 
1015  void plot(const float x, const float y) { traces[cur_trace].plot(x,y); }
1016 
1022  template<class T> void plot(const std::vector<T>& v)
1023  {
1024  for(size_t x=0;x<v.size();x++)
1025  {
1026  traces[cur_trace].plot(float(x), float(v[x]));
1027  }
1028  }
1029 
1033  void color3f(float r, float g, float b) { traces[cur_trace].color3f(r,g,b); }
1034 
1038  void set_title(const std::wstring& title_){ title=title_; }
1039 
1043  void set_linewidth(float width){ traces[cur_trace].set_linewidth(width); }
1047  void set_pointsize(float psize){ traces[cur_trace].set_pointsize(psize); }
1051  void set_scrolling(int max_points_to_plot){ traces[cur_trace].set_scrolling(max_points_to_plot); }
1052 
1059  void set_scaling(enum MP_SCALING sc, float x_min=-10, float x_max= 10, float y_min=-10, float y_max=10)
1060  {
1061  scaling_ = sc;
1062  range_min.x = x_min;
1063  range_min.y = y_min;
1064  range_max.x = x_max;
1065  range_max.y = y_max;
1066  }
1067 
1068 
1077  void set_grid(enum MP_GRIDSTYLE ggridx=MP_LINEAR_GRID, enum MP_GRIDSTYLE ggridy=MP_LINEAR_GRID, float ggridx_step=-1.0, float ggridy_step=-1.0, float w=1.0)
1078  {
1079  gridx=ggridx;
1080  gridy=ggridy;
1081  gridx_step=ggridx_step;
1082  gridy_step=ggridy_step;
1083  grid_linewidth=w;
1084  }
1085 
1089  void set_bg_color(float r, float g, float b)
1090  {
1091  bg_color.r=r;
1092  bg_color.g=g;
1093  bg_color.b=b;
1094  glClearColor(bg_color.r, bg_color.g, bg_color.b, 1); // Set The background color
1095  }
1096 
1097 
1101  void set_grid_color(float r, float g, float b)
1102  {
1103  grid_color.r=r;
1104  grid_color.g=g;
1105  grid_color.b=b;
1106  }
1107 
1108 
1112  void clear_all()
1113  {
1114  for(unsigned int a=0;a<traces.size();a++)
1115  traces[a].clear();
1116  }
1117 
1118 
1122  void clear(int trace) { traces[trace].clear(); traces[trace].pos=0; }
1123  protected:
1124  float cur_point_size;
1125  unsigned int cur_trace;
1126  std::wstring title; // stores the user-title, so we can add ranges
1127  Point2d bg_color;
1128  Point2d grid_color;
1129 
1130  // scaling behaviour
1131  int scaling_;
1132  Point2d range_min, range_max;
1133  Point2d minimum, maximum;
1134  Point2d scale;
1135  Point2d offset;
1136 
1137 
1138  std::vector< Trace > traces;
1139 
1140  // grid - vars
1141  int gridx;
1142  int gridy;
1143  float gridx_step, gridy_step, grid_linewidth;
1144  Point2d grid_spacing;
1145 
1146  void initgl()
1147  {
1148  glViewport(0 , 0,width ,height); // Set Up A Viewport
1149  glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
1150  glLoadIdentity(); // Reset The Projection Matrix
1151  glOrtho( 0, width, 0, height, -1, 1 ); // Select Ortho Mode (640x480)
1152  //gluPerspective(50, (float)w()/(float)h(), 5, 2000); // Set Our Perspective
1153  glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
1154  glLoadIdentity(); // Reset The Modelview Matrix
1155  glDisable(GL_DEPTH_TEST); // Enable Depth Testing
1156  glDisable(GL_LIGHTING);
1157  glShadeModel(GL_SMOOTH); // Select Smooth Shading
1158  glClearColor(bg_color.r, bg_color.g, bg_color.b, 1); // Set The background color
1159  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And Depth Buffer
1160  }
1161 
1162  Point2d draw_grid()
1163  {
1164  double xstep=0;
1165  double ystep=0;
1166  if(gridx==MP_LINEAR_GRID)
1167  {
1168  double diff=maximum.x - minimum.x;
1169  if(diff==0)return Point2d(0,0);
1170  double exp=floor(log10(fabs(diff)));
1171  double shiftscale=pow(10.0,exp);
1172  // get the starting point for the grid
1173  double startx=shiftscale*floor(minimum.x / shiftscale);
1174 
1175  if(gridx_step>0)
1176  {
1177  xstep=gridx_step;
1178  }
1179  else // auto grid size
1180  {
1181  xstep=shiftscale*1.0;
1182  if(diff/xstep < 4) // draw more lines
1183  xstep*=0.5;
1184 
1185  /*
1186  xstep=floor(maximum.x / shiftscale) - floor(minimum.x / shiftscale);
1187  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
1188  xstep=shiftscale*xstep / 4.0;
1189  */
1190 
1191  }
1192  double x=startx;
1193 
1194  glLineWidth(grid_linewidth);
1195  glColor3f(grid_color.r, grid_color.g, grid_color.b);
1196  glBegin(GL_LINES);
1197  int bailout=0; // bailout is a safety to avoid endless recursions caused maybe through numerical errors..
1198  while(x<maximum.x && bailout<100)
1199  {
1200  x+=xstep;
1201  bailout++;
1202  glVertex2f((GLfloat)(x-offset.x)*scale.x ,0.0f );
1203  glVertex2f((GLfloat)(x-offset.x)*scale.x ,(float)height);
1204  }
1205  glEnd();
1206  }
1207  if(gridy==MP_LINEAR_GRID)
1208  {
1209  double diff=maximum.y - minimum.y;
1210  if(diff==0)return Point2d(0,0);
1211  double exp=floor(log10(fabs(diff)));
1212  double shiftscale=pow(10.0,exp);
1213  // get the starting point for the grid
1214  double starty=shiftscale*floor(minimum.y / shiftscale);
1215 
1216  if(gridy_step>0)
1217  {
1218  ystep=gridy_step;
1219  }
1220  else // auto grid size
1221  {
1222  ystep=shiftscale*1.0;
1223  if(diff/ystep < 4) // draw more lines
1224  ystep*=0.5;
1225 
1226  /*
1227  ystep=floor(maximum.y / shiftscale) - floor(minimum.y / shiftscale);
1228  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
1229  ystep=shiftscale*ystep / 4.0;
1230  */
1231 
1232  }
1233  double y=starty;
1234  glLineWidth(1.0);
1235  glColor3f(grid_color.r, grid_color.g, grid_color.b);
1236  glBegin(GL_LINES);
1237  int bailout=0; // bailout is a safety to avoid endless recursions caused maybe through numerical errors..
1238  while(y<maximum.y && bailout<100)
1239  {
1240  y+=ystep;
1241  bailout++;
1242  glVertex2f(0.0f ,(GLfloat)(y-offset.y)*scale.y);
1243  glVertex2f((float)width ,(GLfloat)(y-offset.y)*scale.y);
1244  }
1245  glEnd();
1246 
1247  #ifdef MULTIPLOT_FLTK // gl_font is only available with fltk...
1248  //********************************************************************
1249  // I don't know why I can't just stick the below
1250  // glRasterPos2f() && gl_draw() calls in the above loop, but
1251  // It doesn't work if I do. Must be due to the glBegin() thingy?
1252  // So, I'm left to do the above loop again (for now)!
1253  // This hack also has the undesireable side effect of putting
1254  // The Axis Label in the Plot area itself, not in a so-called margin.
1255  //********************************************************************
1256  gl_font(1, 10);
1257  y=starty;
1258  bailout=0;
1259  std::string s;
1260  while(y<maximum.y && bailout<100)
1261  {
1262  y+=ystep;
1263  bailout++;
1264  s = std::to_string(y);
1265  glRasterPos2f(0.5f, (GLfloat)(y-offset.y)*scale.y + 1 );
1266  gl_draw(s.c_str(), int(s.length()));
1267  }
1268  //********************************************************************
1269  #endif
1270  }
1271 
1272  return Point2d((float)xstep,(float)ystep);
1273  }
1274 
1275  virtual void draw()
1276  {
1277  if(!valid() )
1278  {
1279  width=w();
1280  height=h();
1281  initgl();
1282  valid(true);
1283  }
1284 
1285  Multiplot_base::draw();
1286 
1287  glClear(GL_COLOR_BUFFER_BIT);// | GL_DEPTH_BUFFER_BIT); // Clear The Screen And Depth Buffer
1288 
1289 
1290  // draw the grid
1291  grid_spacing=draw_grid();
1292 
1293  // draw the coordinate cross with center (0,0)
1294  glLineWidth(2.0f*grid_linewidth);
1295  glColor3f(grid_color.r, grid_color.g, grid_color.b);
1296  glBegin(GL_LINES);
1297  glVertex2f(0.0f ,0-offset.y*scale.y);
1298  glVertex2f((float)width ,0-offset.y*scale.y);
1299  glVertex2f(0-offset.x*scale.x ,0.0f );
1300  glVertex2f(0-offset.x*scale.x ,(float)height);
1301  glEnd();
1302 
1303 
1304 
1305  maximum.x=maximum.y=-FLT_MAX;
1306  minimum.x=minimum.y=FLT_MAX;
1307 
1308  for(unsigned int t=0;t<traces.size();t++)
1309  {
1310  traces[t].draw(minimum, maximum, scale, offset);
1311  }
1312 
1313 
1314 
1315  // do the (auto-) scaling
1316  offset.x=minimum.x;
1317  offset.y=minimum.y;
1318  float diff_x = maximum.x-minimum.x;
1319  float diff_y = maximum.y-minimum.y;
1320  switch(scaling_)
1321  {
1322  case MP_AUTO_SCALE:
1323  if(diff_x!=0.0)scale.x=width/diff_x;
1324  if(diff_y!=0.0)scale.y=height/diff_y;
1325  break;
1326  case MP_AUTO_SCALE_EQUAL:
1327  if(max(diff_x, diff_y) != 0)
1328  {
1329  scale.x=scale.y=min(width, height) / max(diff_x, diff_y);
1330  //scale.y=height/diff;
1331  }
1332  break;
1333  case MP_FIXED_SCALE:
1334  scale.x = width /(range_max.x - range_min.x);
1335  scale.y = height/(range_max.y - range_min.y);
1336  offset.x = range_min.x;
1337  offset.y = range_min.y;
1338  break;
1339  }
1340 
1341 
1342  // possible performance issue?
1343  std::wstringstream ss;
1344  ss << "x=[" << minimum.x << "; " << maximum.x << "] ";
1345  ss << "y=[" << minimum.y << "; " << maximum.y << "] ";
1346  if(gridx != MP_NO_GRID || gridy != MP_NO_GRID)
1347  {
1348  ss << "dx=[" << grid_spacing.x << "] ";
1349  ss << "dy=[" << grid_spacing.y << "] ";
1350  }
1351  set_caption( (ss.str() + title).c_str() );
1352  }
1353 };
1354 
1355 } // end namespace
1356 
1357 
1358 
1359 #ifdef __TEST_THIS_MODULE__
1360 // some tests and demos for multiplot
1361 
1362 #include <vector>
1363 #include <iostream>
1364 
1365 #include <math.h>
1366 
1367 using namespace std;
1368 using namespace multiplot;
1369 
1370 // These are compiler directives that includes libraries (For Visual Studio)
1371 // You can manually include the libraries in the "Project->settings" menu under
1372 // the "Link" tab. You need these libraries to compile this program.
1373 // this project file is configured in "multithreaded dll" mode. if your fltk was build using
1374 // "multithreaded" mode, you must change the code generation compiler settings.
1375 
1376 #ifdef MULTIPLOT_FLTK
1377 #ifdef _DEBUG
1378 #pragma comment(lib, "fltk14/bin/lib/Debug/fltkd.lib")
1379 #pragma comment(lib, "fltk14/bin/lib/Debug/fltk_gld.lib")
1380 //#pragma comment(lib, "fltk14/bin/lib/Debug/fltk_imaged.lib")
1381 #else
1382 #pragma comment(lib, "fltk14/bin/lib/Release/fltk.lib")
1383 #pragma comment(lib, "fltk14/bin/lib/Release/fltk_gl.lib")
1384 #endif
1385 #endif
1386 
1387 #ifdef _WIN32
1388 #pragma comment(lib, "wsock32.lib")
1389 #pragma comment(lib, "comctl32.lib")
1390 #pragma comment(lib, "glu32.lib")
1391 #pragma comment(lib, "opengl32.lib")
1392 #pragma comment(lib, "Ws2_32.lib")
1393 #pragma comment(lib, "User32.lib")
1394 //#if (_MSC_VER > 1700)
1395 //#pragma comment (lib, "legacy_stdio_definitions.lib")
1396 //#endif
1397 #endif
1398 
1399 
1400 
1401 
1402 
1403 // most simple usage of Multiplot
1404 void demo1()
1405 {
1406  using namespace multiplot;
1407 
1408  // create a multiplot window
1409  // at position (x,y)=(10,10) and with
1410  // a width and height of 300 pixels
1411  Multiplot m(10, 10, 600, 300);
1412 
1413  // make it visible
1414  m.show();
1415 
1416  // and plot a nice sine wave
1417  for(int x=0;x<300;x++)
1418  {
1419  // add point at (x,y) coordinates
1420  m.plot(float(x), 0.1f*x*sin(0.1f*x));
1421 
1422  m.redraw();
1423 
1424  // force event propagation thus redrawing
1425  if (!m.check()) { break; }
1426  }
1427 
1428  // wait till window is closed by user
1429  while(m.check())
1430  {
1431  m.redraw();
1432  }
1433 
1434 }
1435 
1436 
1437 
1438 // plot two scrolling traces in a window,
1439 // set colors and draw a background grid
1440 void demo2()
1441 {
1442  Multiplot m(10,10,600,300);
1443 
1444  // draw a linear spaced grid for x and y-axis
1445  m.set_grid(MP_LINEAR_GRID,MP_LINEAR_GRID);
1446 
1447  // set background color
1448  m.set_bg_color(0,0,0.5);
1449 
1450  // enable scrolling for both traces:
1451  m[0].set_scrolling(100); // the last 100 added points of the plot will be drawn
1452  m[1].set_scrolling(100); // the last 100 added points of the plot will be drawn
1453 
1454  m.show();
1455 
1456 
1457  for(int x=0;x<300;x++)
1458  {
1459  // set trace to draw to and drawing color:
1460  m.trace(0);
1461  m.color3f(1,1,0);
1462  m.plot(float(x), 0.1f*x*sin(x/5.0f));
1463 
1464  m.trace(1);
1465  m.color3f(1,0,0);
1466  m.plot(float(x), 0.1f*x*sin(x/6.0f));
1467 
1468 
1469  m.redraw();
1470  if (!m.check()) { break; }
1471  }
1472 
1473  while(m.check())
1474  {
1475  m.redraw();
1476  }
1477 
1478 }
1479 
1480 
1481 // demo3 shows more advanced settings
1482 void demo3()
1483 {
1484  Multiplot m(10,10,600,600);
1485 
1486  m.set_grid(MP_LINEAR_GRID, MP_LOG_GRID);
1487 
1488  m.set_scrolling(100); // the last 50 added points of the plot will be drawn
1489  m.set_linewidth(2); // first trace has line-width of 2
1490  m.set_pointsize(4); // set the point size of the first trace to 4
1491 
1492  m.show();
1493 
1494 
1495  for(int x=0;x<1000;x++)
1496  {
1497  // instead of calling m.trace(0), you may also
1498  // use the brackets operator to access individual traces
1499  m[0].set_pointsize(4.0f + (x%10));
1500  m[0].color3f(1, 0.01f*(x%100), 0.05f*(x%20) );
1501  m[0].plot(0.1f*x*cos(x/5.0f), 0.1f*x*sin(x/5.0f));
1502 
1503  m[1].color3f(0.1f*(x%10), 0.05f*(x%20), 0.01f*(x%100) );
1504  m[1].plot(0.1f*x*cos(x/20.0f), 0.1f*x*sin(x/5.0f));
1505 
1506  m.redraw();
1507  if (!m.check()) { break; }
1508  }
1509 
1510  while(m.check())
1511  {
1512  m.redraw();
1513  }
1514 }
1515 
1516 // demo4: how to do scatter-plots
1517 void demo4()
1518 {
1519  Multiplot m(10,10,600,600);
1520  m.show();
1521 
1522  m.set_linewidth(0.0); // disable lines by setting line width to zero
1523 
1524  for(int x=0;x<3000;x++)
1525  {
1526  m.color3f(1, 0.01f*(x%100), 0.05f*(x%20) );
1527 
1528 
1529 
1530  for(int b=0;b<10;b++)
1531  {
1532  // two dimensional gauss - distribution
1533  float rx = -5 + 10.0f*rand()/RAND_MAX;
1534  float ry = -5 + 10.0f*rand()/RAND_MAX;
1535 
1536  float gval = exp(-(rx*rx + ry*ry));
1537  if(1.0*rand()/RAND_MAX < gval)
1538  {
1539  m.set_pointsize(1 + 5*gval);
1540  m.plot(rx, ry);
1541  }
1542  }
1543 
1544  m.redraw();
1545  if (!m.check()) { break; }
1546  }
1547  while(m.check())
1548  {
1549  m.redraw();
1550  }
1551 }
1552 
1553 // fullscreen (win32 only)
1554 void demo5()
1555 {
1556  // create a multiplot window
1557  // last parameter says if fullscreen or not
1558  Multiplot m(0, 0, 800, 600, L"", true);
1559  m.show();
1560  for(int x=0;x<1000;x++)
1561  {
1562  m.plot(float(x), 0.1f*x*sin(0.1f*x));
1563  m.redraw();
1564  if (!m.check()) { break; }
1565  }
1566 
1567  while(m.check())
1568  {
1569  m.redraw();
1570  }
1571 }
1572 
1573 void demo6()
1574 {
1575  vector<float> v1,v2;
1576  for(int a=0;a<100;a++)
1577  {
1578  v1.push_back( sin(0.3f*a) );
1579  v2.push_back( cos(0.3f*a)+2.5f );
1580  }
1581  Multiplot mp(20,20,500,500);
1582  mp.show();
1583  mp.plot(v1);
1584  mp.trace(1);
1585  mp.plot(v2);
1586  while(mp.check())
1587  {
1588  mp.redraw();
1589  }
1590 }
1591 
1592 void demo7()
1593 {
1594  Multiplot m(10, 10, 600, 300);
1595  m.set_scaling(MP_FIXED_SCALE, 0, 300, -20, 20);
1596  m.show();
1597 
1598  for (int x = 0; x < 300; x++)
1599  {
1600  m.plot(float(x), 0.1f*x*sin(0.1f*x));
1601  m.redraw();
1602  if (!m.check()) { break; }
1603  }
1604  while (m.check()) { m.redraw(); }
1605 }
1606 
1607 
1608 #include <FL/Fl.H>
1609 #include <FL/Fl_Gl_Window.H>
1610 #include <FL/Fl_Button.H>
1611 void test_module()
1612 {
1613  /*
1614  Multiplot_base w(10, 10, 400, 400, L"hallo",false);
1615  //Fl_Gl_Window w(50, 50, 640, 480, "Hallo GL FENSTER");
1616  //w.end();
1617  Fl_Button b(10, 10, 100, 25, "Hallo Button");
1618  w.show();
1619  w.add(&b);
1620  while (true)
1621  {
1622  Fl::check();
1623  //mp.check();
1624  }
1625  return;
1626  */
1627 
1628  std::cout << "Several multiplot demos. press ESC inside the multiplot window to stop a demo and test the next demo." << std::endl << std::endl;
1629 
1630  int demo_number = 0;
1631 menu:
1632  std::cout << "\n(1) demo: most basic/ simple usage. plots a sine wave.";
1633  std::cout << "\n(2) demo: two traces in a multiplot window with colors and scrolling.";
1634  std::cout << "\n(3) demo: more settings (point size, line-width and grid).";
1635  std::cout << "\n(4) demo: how to do a scatter plot (random gauss distribution).";
1636  std::cout << "\n(5) demo: fullscreen (win32 only at the moment)";
1637  std::cout << "\n(6) demo: plot values in a std::vector<float>";
1638  std::cout << "\n(7) demo: no auto-scaling, set fixed scaling of both x and y axis.";
1639  std::cout << "\n(8) exit.";
1640  std::cout << "\nenter number of demo (1..6):";
1641  std::cin >> demo_number;
1642  switch (demo_number)
1643  {
1644  case 1:demo1(); break;
1645  case 2:demo2(); break;
1646  case 3:demo3(); break;
1647  case 4:demo4(); break;
1648  case 5:demo5(); break;
1649  case 6:demo6(); break;
1650  case 7:demo7(); break;
1651  case 8:return; break;
1652  default:demo1(); break;
1653  }
1654  goto menu; // goto is not evil. at least in this case...
1655  return;
1656 }
1657 
1658 
1659 #endif
void plot(const std::vector< T > &v)
Definition: multiplot.h:1022
void clear_all()
Definition: multiplot.h:1112
void set_max_points(int mx)
Definition: multiplot.h:920
void set_scaling(enum MP_SCALING sc, float x_min=-10, float x_max=10, float y_min=-10, float y_max=10)
Definition: multiplot.h:1059
void plot(const float x, const float y)
Definition: multiplot.h:1015
Multiplot_base(int x, int y, int w, int h, const std::wstring &ttitle, bool fullscreen)
Definition: multiplot.h:622
Definition: multiplot.h:687
void plot(const float x, const float y)
Definition: multiplot.h:866
void color3f(float r, float g, float b)
Definition: multiplot.h:1033
Definition: multiplot.h:690
void clear()
Definition: multiplot.h:947
void set_pointsize(float psize)
Definition: multiplot.h:1047
void set_linewidth(float width)
Definition: multiplot.h:1043
void set_grid_color(float r, float g, float b)
Definition: multiplot.h:1101
void set_scrolling(int max_points_to_plot)
Definition: multiplot.h:927
Trace & operator[](int _trace)
Definition: multiplot.h:989
Trace & trace(int _trace)
Definition: multiplot.h:999
void color3f(float r, float g, float b)
Definition: multiplot.h:893
void clear(int trace)
Definition: multiplot.h:1122
void set_grid(enum MP_GRIDSTYLE ggridx=MP_LINEAR_GRID, enum MP_GRIDSTYLE ggridy=MP_LINEAR_GRID, float ggridx_step=-1.0, float ggridy_step=-1.0, float w=1.0)
Definition: multiplot.h:1077
void set_bg_color(float r, float g, float b)
Definition: multiplot.h:1089
void set_pointsize(float psize)
Definition: multiplot.h:912
void set_title(const std::wstring &title_)
Definition: multiplot.h:1038
Definition: multiplot.h:247
void redraw()
Definition: multiplot.h:673
void set_linewidth(float width)
Definition: multiplot.h:905
void show()
Definition: multiplot.h:632
Trace & operator()(int _trace)
Definition: multiplot.h:993
Definition: multiplot.h:721
void set_scrolling(int max_points_to_plot)
Definition: multiplot.h:1051