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