MRPT  1.9.9
CDisplayWindowPlots.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "gui-precomp.h" // Precompiled headers
11 
12 #include <mrpt/config.h>
14 #include <mrpt/gui/WxSubsystem.h>
15 #include <mrpt/gui/WxUtils.h>
16 #include <mrpt/img/CImage.h>
17 #include <mrpt/math/utils.h>
18 #include <mrpt/system/os.h>
19 #include <cstring>
20 
21 using namespace mrpt;
22 using namespace mrpt::gui;
23 using namespace mrpt::math;
24 using namespace mrpt::system;
25 using namespace std;
27 
28 #if MRPT_HAS_WXWIDGETS
29 
30 BEGIN_EVENT_TABLE(CWindowDialogPlots, wxFrame)
31 
32 END_EVENT_TABLE()
33 
34 const long CWindowDialogPlots::ID_PLOT = wxNewId();
35 const long CWindowDialogPlots::ID_MENU_PRINT = wxNewId();
36 const long ID_MENUITEM1 = wxNewId();
37 const long ID_MENUITEM2 = wxNewId();
38 
40  CDisplayWindowPlots* winPlots, WxSubsystem::CWXMainFrame* parent,
41  wxWindowID id, const std::string& caption, wxSize initialSize)
42  : m_winPlots(winPlots), m_mainFrame(parent), m_firstSubmenu(true)
43 {
44  Create(
45  parent, id, caption.c_str(), wxDefaultPosition, initialSize,
46  wxDEFAULT_FRAME_STYLE, _T("id"));
47 
48  SetClientSize(initialSize);
49 
50  wxIcon FrameIcon;
51  FrameIcon.CopyFromBitmap(mrpt::gui::WxSubsystem::getMRPTDefaultIcon());
52  SetIcon(FrameIcon);
53 
54  // Create the mpWindow object:
55  m_plot = new mpWindow(this, ID_PLOT);
56  m_plot->AddLayer(new mpScaleX());
57  m_plot->AddLayer(new mpScaleY());
58  m_plot->LockAspect(false);
59  m_plot->EnableDoubleBuffer(true);
60 
61  m_plot->Fit(-10, 10, -10, 10);
62 
63  // Menu:
64  auto* MenuBar1 = new wxMenuBar();
65 
66  auto* Menu1 = new wxMenu();
67  wxMenuItem* MenuItem1 =
68  new wxMenuItem(Menu1, ID_MENUITEM1, _("Close"), _(""), wxITEM_NORMAL);
69  Menu1->Append(MenuItem1);
70 
71  wxMenuItem* MenuItemPrint = new wxMenuItem(
72  Menu1, ID_MENU_PRINT, _("Print..."), _(""), wxITEM_NORMAL);
73  Menu1->Append(MenuItemPrint);
74 
75  MenuBar1->Append(Menu1, _("&File"));
76 
77  auto* Menu2 = new wxMenu();
78  wxMenuItem* MenuItem2 = new wxMenuItem(
79  Menu2, ID_MENUITEM2, _("About..."), _(""), wxITEM_NORMAL);
80  Menu2->Append(MenuItem2);
81  MenuBar1->Append(Menu2, _("&Help"));
82 
83  SetMenuBar(MenuBar1);
84 
85  // Events:
86  Bind(wxEVT_CLOSE_WINDOW, &CWindowDialogPlots::OnClose, this, wxID_ANY);
87  Bind(wxEVT_MENU, &CWindowDialogPlots::OnMenuClose, this, ID_MENUITEM1);
88  Bind(wxEVT_MENU, &CWindowDialogPlots::OnMenuPrint, this, ID_MENU_PRINT);
89  Bind(wxEVT_MENU, &CWindowDialogPlots::OnMenuAbout, this, ID_MENUITEM2);
90 
91  Bind(wxEVT_SIZE, &CWindowDialogPlots::OnResize, this, wxID_ANY);
92 
93  Bind(wxEVT_CHAR, &CWindowDialogPlots::OnChar, this, wxID_ANY);
94  m_plot->Bind(wxEVT_CHAR, &CWindowDialogPlots::OnChar, this);
95  m_plot->Bind(wxEVT_MOTION, &CWindowDialogPlots::OnMouseMove, this);
96 
97  m_plot->Bind(wxEVT_LEFT_DOWN, &CWindowDialogPlots::OnMouseDown, this);
98  m_plot->Bind(wxEVT_RIGHT_DOWN, &CWindowDialogPlots::OnMouseDown, this);
99 
100  // Increment number of windows:
101  // int winCount =
103  // this->Iconize(false);
104 
105 #if 0
106  // JL: TEST CODE: This is the seed of the future new implementation based on wxFreeChart...
107  double data[][2] = {
108  { 10, 20, },
109  { 13, 16, },
110  { 7, 30, },
111  { 15, 34, },
112  { 25, 4, },
113  };
114  // first step: create plot
115  XYPlot *plot = new XYPlot();
116  // create dataset
117  XYSimpleDataset *dataset = new XYSimpleDataset();
118  // and add serie to it
119  dataset->AddSerie((double *) data, WXSIZEOF(data));
120  // set line renderer to dataset
121  dataset->SetRenderer(new XYLineRenderer());
122  // add our dataset to plot
123  plot->AddDataset(dataset);
124  // create left and bottom number axes
125  NumberAxis *leftAxis = new NumberAxis(AXIS_LEFT);
126  NumberAxis *bottomAxis = new NumberAxis(AXIS_BOTTOM);
127  // optional: set axis titles
128  leftAxis->SetTitle(wxT("X"));
129  bottomAxis->SetTitle(wxT("Y"));
130  // add axes to plot
131  plot->AddAxis(leftAxis);
132  plot->AddAxis(bottomAxis);
133  // link axes and dataset
134  plot->LinkDataVerticalAxis(0, 0);
135  plot->LinkDataHorizontalAxis(0, 0);
136  // and finally create chart
137  Chart* chart = new Chart(plot, wxT("my title"));
138  wxChartPanel *m_chartPanel = new wxChartPanel( this ); //, ID_PLOT );
139  m_chartPanel->SetChart( chart );
140 #endif
141 }
142 
143 // Destructor
145 // OnClose event:
146 void CWindowDialogPlots::OnClose(wxCloseEvent& event)
147 {
148  // Send the event:
149  bool allow_close = true;
150  try
151  {
152  mrptEventWindowClosed ev(m_winPlots, true /* allow close */);
153  m_winPlots->publishEvent(ev);
154  allow_close = ev.allow_close;
155  }
156  catch (...)
157  {
158  }
159  if (!allow_close) return; // Don't process this close event.
160 
161  // Set the m_hwnd=nullptr in our parent object.
162  m_winPlots->notifyChildWindowDestruction();
163 
164  // Decrement number of windows:
166 
167  // Signal we are destroyed:
168  m_winPlots->m_windowDestroyed.set_value();
169 
170  event.Skip(); // keep processing by parent classes.
171 }
172 
173 void CWindowDialogPlots::OnChar(wxKeyEvent& event)
174 {
175  if (m_winPlots)
176  {
177  const int code = event.GetKeyCode();
179 
180  m_winPlots->m_keyPushedCode = code;
181  m_winPlots->m_keyPushedModifier = mod;
182  m_winPlots->m_keyPushed = true;
183  // Send the event:
184  try
185  {
186  m_winPlots->publishEvent(
187  mrptEventWindowChar(m_winPlots, code, mod));
188  }
189  catch (...)
190  {
191  }
192  }
193  event.Skip();
194 }
195 
196 void CWindowDialogPlots::OnResize(wxSizeEvent& event)
197 {
198  // Send the event:
199  if (m_winPlots)
200  {
201  try
202  {
203  m_winPlots->publishEvent(mrptEventWindowResize(
204  m_winPlots, event.GetSize().GetWidth(),
205  event.GetSize().GetHeight()));
206  }
207  catch (...)
208  {
209  }
210  }
211  event.Skip(); // so it's processed by the wx system!
212 }
213 
214 void CWindowDialogPlots::OnMouseDown(wxMouseEvent& event)
215 {
216  // Send the event:
217  if (m_winPlots)
218  {
219  try
220  {
221  m_winPlots->publishEvent(mrptEventMouseDown(
222  m_winPlots, TPixelCoord(event.GetX(), event.GetY()),
223  event.LeftDown(), event.RightDown()));
224  }
225  catch (...)
226  {
227  }
228  }
229  event.Skip(); // so it's processed by the wx system!
230 }
231 
232 // Menu: Close
233 void CWindowDialogPlots::OnMenuClose(wxCommandEvent& event) { Close(); }
234 // Menu: Print
235 void CWindowDialogPlots::OnMenuPrint(wxCommandEvent& event)
236 {
237  m_plot->ShowPrintDialog();
238 }
239 // Menu: About
240 void CWindowDialogPlots::OnMenuAbout(wxCommandEvent& event)
241 {
242  ::wxMessageBox(
243  _("Plot viewer\n Class gui::CDisplayWindowPlots\n MRPT C++ & "
244  "wxMathPlot library"),
245  _("About..."));
246 }
247 
248 void CWindowDialogPlots::OnMenuSelected(wxCommandEvent& ev)
249 {
250  auto it = m_ID2ID.find(ev.GetId());
251  if (it != m_ID2ID.end())
252  {
253  if (m_winPlots && m_winPlots->m_callback)
254  m_winPlots->m_callback(
255  it->second, d2f(m_curCursorPos.x), d2f(m_curCursorPos.y),
256  m_winPlots->m_callback_param);
257  }
258 }
259 
260 void CWindowDialogPlots::OnMouseMove(wxMouseEvent& event)
261 {
262  int X, Y;
263  event.GetPosition(&X, &Y);
264  m_curCursorPos.x = m_plot->p2x(X);
265  m_curCursorPos.y = m_plot->p2y(Y);
266  m_last_mouse_point.x = X;
267  m_last_mouse_point.y = Y;
268 
269  // Send the event:
270  if (m_winPlots && m_winPlots->hasSubscribers())
271  {
272  try
273  {
274  m_winPlots->publishEvent(mrptEventMouseMove(
275  m_winPlots, mrpt::img::TPixelCoord(event.GetX(), event.GetY()),
276  event.LeftDown(), event.RightDown()));
277  }
278  catch (...)
279  {
280  }
281  }
282  event.Skip(); // so it's processed by the wx system!
283 }
284 
285 // Add / Modify a 2D plot using a MATLAB-like format string
287  const CVectorFloat& x, const CVectorFloat& y, const std::string& lineFormat,
288  const std::string& plotName)
289 {
290  mpFXYVector* theLayer;
291 
292  wxString lyName = plotName.c_str();
293  bool updateAtTheEnd = false; // If we update an existing layer, update
294  // manually to refresh the changes!
295 
296  // Already existing layer?
297  mpLayer* existingLy = m_plot->GetLayerByName(lyName);
298 
299  if (existingLy)
300  {
301  // Assure the class:
302  auto* lyPlot2D = dynamic_cast<mpFXYVector*>(existingLy);
303 
304  if (!lyPlot2D)
305  {
306  cerr << "[CWindowDialogPlots::plot] Plot name '" << plotName
307  << "' is not of expected class mpFXYVector!." << endl;
308  return;
309  }
310 
311  // Ok:
312  theLayer = lyPlot2D;
313  updateAtTheEnd = true;
314  }
315  else
316  {
317  // Create it:
318  theLayer = new mpFXYVector(lyName);
319  m_plot->AddLayer(theLayer);
320  }
321 
322  // Set data:
323  {
324  std::vector<float> x_(x.size()), y_(x.size());
325  std::memcpy(&x_[0], &x[0], sizeof(x[0]) * x_.size());
326  std::memcpy(&y_[0], &y[0], sizeof(y[0]) * y_.size());
327  theLayer->SetData(x_, y_);
328  }
329 
330  // Line style:
331  // -------------------
332  bool isContinuous = true;
333  int lineColor[] = {0, 0, 255};
334  int lineWidth = 1;
335  wxPenStyle lineStyle = wxPENSTYLE_SOLID;
336 
337  // parse string:
338  if (string::npos != lineFormat.find("."))
339  {
340  isContinuous = false;
341  }
342  if (string::npos != lineFormat.find("-"))
343  {
344  isContinuous = true;
345  lineStyle = wxPENSTYLE_SOLID;
346  }
347  if (string::npos != lineFormat.find(":"))
348  {
349  isContinuous = true;
350  lineStyle = wxPENSTYLE_LONG_DASH;
351  }
352 
353  if (string::npos != lineFormat.find("r"))
354  {
355  lineColor[0] = 0xFF;
356  lineColor[1] = 0x00;
357  lineColor[2] = 0x00;
358  }
359  if (string::npos != lineFormat.find("g"))
360  {
361  lineColor[0] = 0x00;
362  lineColor[1] = 0xFF;
363  lineColor[2] = 0x00;
364  }
365  if (string::npos != lineFormat.find("b"))
366  {
367  lineColor[0] = 0x00;
368  lineColor[1] = 0x00;
369  lineColor[2] = 0xFF;
370  }
371  if (string::npos != lineFormat.find("k"))
372  {
373  lineColor[0] = 0x00;
374  lineColor[1] = 0x00;
375  lineColor[2] = 0x00;
376  }
377  if (string::npos != lineFormat.find("m"))
378  {
379  lineColor[0] = 192;
380  lineColor[1] = 0;
381  lineColor[2] = 192;
382  }
383  if (string::npos != lineFormat.find("c"))
384  {
385  lineColor[0] = 0;
386  lineColor[1] = 192;
387  lineColor[2] = 192;
388  }
389 
390  if (string::npos != lineFormat.find("1"))
391  {
392  lineWidth = 1;
393  }
394  if (string::npos != lineFormat.find("2"))
395  {
396  lineWidth = 2;
397  }
398  if (string::npos != lineFormat.find("3"))
399  {
400  lineWidth = 3;
401  }
402  if (string::npos != lineFormat.find("4"))
403  {
404  lineWidth = 4;
405  }
406  if (string::npos != lineFormat.find("5"))
407  {
408  lineWidth = 5;
409  }
410  if (string::npos != lineFormat.find("6"))
411  {
412  lineWidth = 6;
413  }
414  if (string::npos != lineFormat.find("7"))
415  {
416  lineWidth = 7;
417  }
418  if (string::npos != lineFormat.find("8"))
419  {
420  lineWidth = 8;
421  }
422  if (string::npos != lineFormat.find("9"))
423  {
424  lineWidth = 9;
425  }
426 
427  theLayer->SetContinuity(isContinuous);
428 
429  wxPen pen(
430  wxColour(lineColor[0], lineColor[1], lineColor[2]), lineWidth,
431  lineStyle);
432  theLayer->SetPen(pen);
433 
434  theLayer->ShowName(false);
435 
436  if (updateAtTheEnd) m_plot->Refresh(false);
437 }
438 
439 // Add / Modify a 2D ellipse
440 // x[0,1]: Mean
441 // y[0,1,2]: Covariance matrix (0,0),(1,1),(0,1)
443  const CVectorFloat& x, const CVectorFloat& y, const std::string& lineFormat,
444  const std::string& plotName, bool showName)
445 {
446  mpCovarianceEllipse* theLayer;
447 
448  if (x.size() != 3 || y.size() != 3)
449  {
450  cerr << "[CWindowDialogPlots::plotEllipse] vectors do not have "
451  "expected size!!"
452  << endl;
453  return;
454  }
455 
456  wxString lyName = plotName.c_str();
457  bool updateAtTheEnd = false; // If we update an existing layer, update
458  // manually to refresh the changes!
459 
460  // Already existing layer?
461  mpLayer* existingLy = m_plot->GetLayerByName(lyName);
462 
463  if (existingLy)
464  {
465  // Assure the class:
466  auto* lyPlotEllipse = dynamic_cast<mpCovarianceEllipse*>(existingLy);
467 
468  if (!lyPlotEllipse)
469  {
470  cerr << "[CWindowDialogPlots::plotEllipse] Plot name '" << plotName
471  << "' is not of expected class mpCovarianceEllipse!." << endl;
472  return;
473  }
474 
475  // Ok:
476  theLayer = lyPlotEllipse;
477  updateAtTheEnd = true;
478  }
479  else
480  {
481  // Create it:
482  theLayer = new mpCovarianceEllipse(1, 1, 0, 2, 32, lyName);
483  m_plot->AddLayer(theLayer);
484  }
485 
486  // Set data:
487  theLayer->SetCovarianceMatrix(y[0], y[2], y[1]);
488  theLayer->SetCoordinateBase(x[0], x[1]);
489  theLayer->SetQuantiles(x[2]);
490  theLayer->ShowName(showName);
491 
492  // Line style:
493  // -------------------
494  bool isContinuous = true;
495  int lineColor[] = {0, 0, 255};
496  int lineWidth = 1;
497  wxPenStyle lineStyle = wxPENSTYLE_SOLID;
498 
499  // parse string:
500  if (string::npos != lineFormat.find("."))
501  {
502  isContinuous = false;
503  }
504  if (string::npos != lineFormat.find("-"))
505  {
506  isContinuous = true;
507  lineStyle = wxPENSTYLE_SOLID;
508  }
509  if (string::npos != lineFormat.find(":"))
510  {
511  isContinuous = true;
512  lineStyle = wxPENSTYLE_LONG_DASH;
513  }
514 
515  if (string::npos != lineFormat.find("r"))
516  {
517  lineColor[0] = 0xFF;
518  lineColor[1] = 0x00;
519  lineColor[2] = 0x00;
520  }
521  if (string::npos != lineFormat.find("g"))
522  {
523  lineColor[0] = 0x00;
524  lineColor[1] = 0xFF;
525  lineColor[2] = 0x00;
526  }
527  if (string::npos != lineFormat.find("b"))
528  {
529  lineColor[0] = 0x00;
530  lineColor[1] = 0x00;
531  lineColor[2] = 0xFF;
532  }
533  if (string::npos != lineFormat.find("k"))
534  {
535  lineColor[0] = 0x00;
536  lineColor[1] = 0x00;
537  lineColor[2] = 0x00;
538  }
539  if (string::npos != lineFormat.find("m"))
540  {
541  lineColor[0] = 192;
542  lineColor[1] = 0;
543  lineColor[2] = 192;
544  }
545  if (string::npos != lineFormat.find("c"))
546  {
547  lineColor[0] = 0;
548  lineColor[1] = 192;
549  lineColor[2] = 192;
550  }
551 
552  if (string::npos != lineFormat.find("1"))
553  {
554  lineWidth = 1;
555  }
556  if (string::npos != lineFormat.find("2"))
557  {
558  lineWidth = 2;
559  }
560  if (string::npos != lineFormat.find("3"))
561  {
562  lineWidth = 3;
563  }
564  if (string::npos != lineFormat.find("4"))
565  {
566  lineWidth = 4;
567  }
568  if (string::npos != lineFormat.find("5"))
569  {
570  lineWidth = 5;
571  }
572  if (string::npos != lineFormat.find("6"))
573  {
574  lineWidth = 6;
575  }
576  if (string::npos != lineFormat.find("7"))
577  {
578  lineWidth = 7;
579  }
580  if (string::npos != lineFormat.find("8"))
581  {
582  lineWidth = 8;
583  }
584  if (string::npos != lineFormat.find("9"))
585  {
586  lineWidth = 9;
587  }
588 
589  theLayer->SetContinuity(isContinuous);
590 
591  wxPen pen(
592  wxColour(lineColor[0], lineColor[1], lineColor[2]), lineWidth,
593  lineStyle);
594  theLayer->SetPen(pen);
595 
596  if (updateAtTheEnd) m_plot->Refresh(false);
597 }
598 
600  void* theWxImage, float x0, float y0, float w, float h,
601  const std::string& plotName)
602 {
603  mpBitmapLayer* theLayer;
604 
605  wxString lyName = plotName.c_str();
606  bool updateAtTheEnd = false; // If we update an existing layer, update
607  // manually to refresh the changes!
608 
609  // Already existing layer?
610  mpLayer* existingLy = m_plot->GetLayerByName(lyName);
611 
612  if (existingLy)
613  {
614  // Assure the class:
615  auto* ly = dynamic_cast<mpBitmapLayer*>(existingLy);
616 
617  if (!ly)
618  {
619  cerr << "[CWindowDialogPlots::image] Plot name '" << plotName
620  << "' is not of expected class mpBitmapLayer!." << endl;
621  return;
622  }
623 
624  // Ok:
625  theLayer = ly;
626  updateAtTheEnd = true;
627  }
628  else
629  {
630  // Create it:
631  theLayer = new mpBitmapLayer();
632  m_plot->AddLayer(theLayer);
633  }
634 
635  // Set data:
636  auto* ii = static_cast<wxImage*>(theWxImage);
637  theLayer->SetBitmap(*ii, x0, y0, w, h);
638 
639  delete ii;
640  theWxImage = nullptr;
641 
642  if (updateAtTheEnd) m_plot->Refresh();
643 }
644 
645 #endif
646 
648  const std::string& windowCaption, unsigned int initialWindowWidth,
649  unsigned int initialWindowHeight)
650 {
651  return std::make_shared<CDisplayWindowPlots>(
652  windowCaption, initialWindowWidth, initialWindowHeight);
653 }
654 /*---------------------------------------------------------------
655  Constructor
656  ---------------------------------------------------------------*/
658  const std::string& windowCaption, unsigned int initialWidth,
659  unsigned int initialHeight)
660  : CBaseGUIWindow(static_cast<void*>(this), 400, 499, windowCaption)
661 
662 {
663  CBaseGUIWindow::createWxWindow(initialWidth, initialHeight);
664 }
665 
666 /*---------------------------------------------------------------
667  Destructor
668  ---------------------------------------------------------------*/
670 {
672 }
673 
674 /** Set cursor style to default (cursorIsCross=false) or to a cross
675  * (cursorIsCross=true) */
676 void CDisplayWindowPlots::setCursorCross(bool cursorIsCross)
677 {
678 #if MRPT_HAS_WXWIDGETS && MRPT_HAS_OPENGL_GLUT
679  const auto* win = (const CWindowDialogPlots*)m_hwnd.get();
680  if (!win) return;
681  win->m_plot->SetCursor(
682  *(cursorIsCross ? wxCROSS_CURSOR : wxSTANDARD_CURSOR));
683 #else
684  MRPT_UNUSED_PARAM(cursorIsCross);
685 #endif
686 }
687 
688 /*---------------------------------------------------------------
689  getLastMousePosition
690  ---------------------------------------------------------------*/
692 {
693 #if MRPT_HAS_WXWIDGETS && MRPT_HAS_OPENGL_GLUT
694  const auto* win = (const CWindowDialogPlots*)m_hwnd.get();
695  if (!win) return false;
696  x = win->m_last_mouse_point.x;
697  y = win->m_last_mouse_point.y;
698  return true;
699 #else
702  return false;
703 #endif
704 }
705 
706 /*---------------------------------------------------------------
707  resize
708  ---------------------------------------------------------------*/
709 void CDisplayWindowPlots::resize(unsigned int width, unsigned int height)
710 {
711 #if MRPT_HAS_WXWIDGETS
712  if (!isOpen())
713  {
714  cerr << "[CDisplayWindowPlots::resize] Window closed!: " << m_caption
715  << endl;
716  return;
717  }
718 
719  // Send a request to destroy this object:
720  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
721  REQ->sourcePlots = this;
722  REQ->OPCODE = 403;
723  REQ->x = width;
724  REQ->y = height;
726 #else
727  MRPT_UNUSED_PARAM(width);
728  MRPT_UNUSED_PARAM(height);
729 #endif
730 }
731 
732 /*---------------------------------------------------------------
733  setPos
734  ---------------------------------------------------------------*/
735 void CDisplayWindowPlots::setPos(int x, int y)
736 {
737 #if MRPT_HAS_WXWIDGETS
738  if (!isOpen())
739  {
740  cerr << "[CDisplayWindowPlots::setPos] Window closed!: " << m_caption
741  << endl;
742  return;
743  }
744 
745  // Send a request to destroy this object:
746  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
747  REQ->sourcePlots = this;
748  REQ->OPCODE = 402;
749  REQ->x = x;
750  REQ->y = y;
752 #else
755 #endif
756 }
757 
758 /*---------------------------------------------------------------
759  setWindowTitle
760  ---------------------------------------------------------------*/
761 void CDisplayWindowPlots::setWindowTitle(const std::string& str)
762 {
763 #if MRPT_HAS_WXWIDGETS
764  if (!isOpen())
765  {
766  cerr << "[CDisplayWindowPlots::setWindowTitle] Window closed!: "
767  << m_caption << endl;
768  return;
769  }
770 
771  // Send a request to destroy this object:
772  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
773  REQ->sourcePlots = this;
774  REQ->OPCODE = 404;
775  REQ->str = str;
777 #else
778  MRPT_UNUSED_PARAM(str);
779 #endif
780 }
781 
782 /*---------------------------------------------------------------
783  enableMousePanZoom
784  ---------------------------------------------------------------*/
786 {
787 #if MRPT_HAS_WXWIDGETS
788  if (!isOpen()) return;
789 
790  // Send a request to destroy this object:
791  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
792  REQ->sourcePlots = this;
793  REQ->OPCODE = 410;
794  REQ->boolVal = enabled;
796 #else
797  MRPT_UNUSED_PARAM(enabled);
798 #endif
799 }
800 
801 /*---------------------------------------------------------------
802  axis_equal
803  ---------------------------------------------------------------*/
805 {
806 #if MRPT_HAS_WXWIDGETS
807  if (!isOpen()) return;
808 
809  // Send a request to destroy this object:
810  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
811  REQ->sourcePlots = this;
812  REQ->OPCODE = 411;
813  REQ->boolVal = enabled;
815 #else
816  MRPT_UNUSED_PARAM(enabled);
817 #endif
818 }
819 
820 /*---------------------------------------------------------------
821  axis
822  ---------------------------------------------------------------*/
824  float x_min, float x_max, float y_min, float y_max, bool aspectRatioFix)
825 {
826 #if MRPT_HAS_WXWIDGETS
827  if (!isOpen()) return;
828 
829  // Send a request to destroy this object:
830  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
831  REQ->sourcePlots = this;
832  REQ->OPCODE = 412;
833  REQ->vector_x.resize(2);
834  REQ->vector_x[0] = x_min;
835  REQ->vector_x[1] = x_max;
836  REQ->vector_y.resize(2);
837  REQ->vector_y[0] = y_min;
838  REQ->vector_y[1] = y_max;
839  REQ->boolVal = aspectRatioFix;
841 #else
842  MRPT_UNUSED_PARAM(x_min);
843  MRPT_UNUSED_PARAM(x_max);
844  MRPT_UNUSED_PARAM(y_min);
845  MRPT_UNUSED_PARAM(y_max);
846  MRPT_UNUSED_PARAM(aspectRatioFix);
847 #endif
848 }
849 
850 /*---------------------------------------------------------------
851  axis_fit
852  ---------------------------------------------------------------*/
853 void CDisplayWindowPlots::axis_fit(bool aspectRatioFix)
854 {
855 #if MRPT_HAS_WXWIDGETS
856  if (!isOpen()) return;
857 
858  // Send a request to destroy this object:
859  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
860  REQ->sourcePlots = this;
861  REQ->OPCODE = 413;
862  REQ->boolVal = aspectRatioFix;
864 #else
865  MRPT_UNUSED_PARAM(aspectRatioFix);
866 #endif
867 }
868 
869 /*---------------------------------------------------------------
870  plotEllipse
871  ---------------------------------------------------------------*/
872 template <typename T>
874  const T mean_x, const T mean_y, const CMatrixDynamic<T>& cov22,
875  const float quantiles, const std::string& lineFormat,
876  const std::string& plotName, bool showName)
877 {
878 #if MRPT_HAS_WXWIDGETS
879  MRPT_START
880  if (!isOpen()) return;
881 
882  ASSERT_(cov22.cols() == 2 && cov22.rows() == 2);
883  ASSERT_(cov22(0, 0) >= 0);
884  ASSERT_(cov22(1, 1) >= 0);
885  ASSERT_(cov22(0, 1) == cov22(1, 0));
886 
888  {
889  m_holdon_just_disabled = false;
890  this->clf();
891  }
892  std::string holdon_post;
893  if (m_holdon)
894  holdon_post =
895  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
896 
897  // Send a request to destroy this object:
898  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
899  REQ->sourcePlots = this;
900  REQ->OPCODE = 421;
901  // 421: Add/update a 2D ellipse: format string=str, plot name =plotName,
902  // vector_x[0,1]:X/Y center, vector_y[0,1,2]: Covariance matrix entries
903  // 00,11,01.
904  REQ->str = lineFormat;
905  REQ->plotName = plotName + holdon_post;
906 
907  REQ->vector_x.resize(3);
908  REQ->vector_x[0] = d2f(mean_x);
909  REQ->vector_x[1] = d2f(mean_y);
910  REQ->vector_x[2] = quantiles;
911 
912  REQ->vector_y.resize(3);
913  REQ->vector_y[0] = d2f(cov22(0, 0));
914  REQ->vector_y[1] = d2f(cov22(1, 1));
915  REQ->vector_y[2] = d2f(cov22(0, 1));
916 
917  REQ->boolVal = showName;
918 
920  MRPT_END
921 #else
922  MRPT_UNUSED_PARAM(mean_x);
923  MRPT_UNUSED_PARAM(mean_y);
924  MRPT_UNUSED_PARAM(cov22);
925  MRPT_UNUSED_PARAM(quantiles);
926  MRPT_UNUSED_PARAM(lineFormat);
927  MRPT_UNUSED_PARAM(plotName);
928  MRPT_UNUSED_PARAM(showName);
929 #endif
930 }
931 
932 // Explicit instantations:
934  const float mean_x, const float mean_y, const CMatrixDynamic<float>& cov22,
935  const float quantiles, const std::string& lineFormat,
936  const std::string& plotName, bool showName);
938  const double mean_x, const double mean_y,
939  const CMatrixDynamic<double>& cov22, const float quantiles,
940  const std::string& lineFormat, const std::string& plotName, bool showName);
941 
942 /*---------------------------------------------------------------
943  plotEllipse
944  ---------------------------------------------------------------*/
945 template <typename T>
947  const T mean_x, const T mean_y, const CMatrixFixed<T, 2, 2>& cov22,
948  const float quantiles, const std::string& lineFormat,
949  const std::string& plotName, bool showName)
950 {
951 #if MRPT_HAS_WXWIDGETS
952  MRPT_START
953  if (!isOpen()) return;
954 
955  ASSERT_(cov22(0, 0) >= 0);
956  ASSERT_(cov22(1, 1) >= 0);
957  ASSERT_(cov22(0, 1) == cov22(1, 0));
958 
960  {
961  m_holdon_just_disabled = false;
962  this->clf();
963  }
964  std::string holdon_post;
965  if (m_holdon)
966  holdon_post =
967  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
968 
969  // Send a request to destroy this object:
970  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
971  REQ->sourcePlots = this;
972  REQ->OPCODE = 421;
973  // 421: Add/update a 2D ellipse: format string=str, plot name =plotName,
974  // vector_x[0,1]:X/Y center, vector_y[0,1,2]: Covariance matrix entries
975  // 00,11,01.
976  REQ->str = lineFormat;
977  REQ->plotName = plotName + holdon_post;
978 
979  REQ->vector_x.resize(3);
980  REQ->vector_x[0] = d2f(mean_x);
981  REQ->vector_x[1] = d2f(mean_y);
982  REQ->vector_x[2] = quantiles;
983 
984  REQ->vector_y.resize(3);
985  REQ->vector_y[0] = d2f(cov22(0, 0));
986  REQ->vector_y[1] = d2f(cov22(1, 1));
987  REQ->vector_y[2] = d2f(cov22(0, 1));
988 
989  REQ->boolVal = showName;
990 
992  MRPT_END
993 #else
994  MRPT_UNUSED_PARAM(mean_x);
995  MRPT_UNUSED_PARAM(mean_y);
996  MRPT_UNUSED_PARAM(cov22);
997  MRPT_UNUSED_PARAM(quantiles);
998  MRPT_UNUSED_PARAM(lineFormat);
999  MRPT_UNUSED_PARAM(plotName);
1000  MRPT_UNUSED_PARAM(showName);
1001 #endif
1002 }
1003 
1004 // Explicit instantations:
1005 template void CDisplayWindowPlots::plotEllipse(
1006  const float mean_x, const float mean_y,
1007  const CMatrixFixed<float, 2, 2>& cov22, const float quantiles,
1008  const std::string& lineFormat, const std::string& plotName, bool showName);
1009 template void CDisplayWindowPlots::plotEllipse(
1010  const double mean_x, const double mean_y,
1011  const CMatrixFixed<double, 2, 2>& cov22, const float quantiles,
1012  const std::string& lineFormat, const std::string& plotName, bool showName);
1013 
1014 /*---------------------------------------------------------------
1015  image
1016  ---------------------------------------------------------------*/
1018  const mrpt::img::CImage& img, float x_left, float y_bottom, float x_width,
1019  float y_height, const std::string& plotName)
1020 {
1021 #if MRPT_HAS_WXWIDGETS
1022  MRPT_START
1023  if (!isOpen()) return;
1024 
1026  {
1027  m_holdon_just_disabled = false;
1028  this->clf();
1029  }
1030  std::string holdon_post;
1031  if (m_holdon)
1032  holdon_post =
1033  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
1034 
1035  // Send a request to destroy this object:
1036  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1037  REQ->sourcePlots = this;
1038  REQ->OPCODE = 422;
1039 
1040  // 422: Add/update a bitmap: plot name =plotName, vector_x[0,1]:X/Y corner,
1041  // vector_x[2,3]: X/Y widths, voidPtr2: pointer to a newly created wxImage
1042  // with the bitmap.
1043  REQ->plotName = plotName + holdon_post;
1044 
1045  REQ->vector_x.resize(4);
1046  REQ->vector_x[0] = x_left;
1047  REQ->vector_x[1] = y_bottom;
1048  REQ->vector_x[2] = x_width;
1049  REQ->vector_x[3] = y_height;
1050 
1051  REQ->voidPtr2 = mrpt::gui::MRPTImage2wxImage(img);
1052 
1054  MRPT_END
1055 #else
1056  MRPT_UNUSED_PARAM(img);
1057  MRPT_UNUSED_PARAM(x_left);
1058  MRPT_UNUSED_PARAM(y_bottom);
1059  MRPT_UNUSED_PARAM(x_width);
1060  MRPT_UNUSED_PARAM(y_height);
1061  MRPT_UNUSED_PARAM(plotName);
1062 #endif
1063 }
1064 
1065 /*---------------------------------------------------------------
1066  internal_plot
1067  ---------------------------------------------------------------*/
1069  CVectorFloat& x, CVectorFloat& y, const std::string& lineFormat,
1070  const std::string& plotName)
1071 {
1072 #if MRPT_HAS_WXWIDGETS
1073  MRPT_START
1074  if (!isOpen()) return;
1075 
1076  ASSERT_EQUAL_(x.size(), y.size());
1077 
1079  {
1080  m_holdon_just_disabled = false;
1081  this->clf();
1082  }
1083 
1084  if (x.empty()) return;
1085 
1086  std::string holdon_post;
1087  if (m_holdon)
1088  holdon_post =
1089  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
1090 
1091  // Send a request to destroy this object:
1092  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1093  REQ->sourcePlots = this;
1094  REQ->OPCODE = 420;
1095  REQ->str = lineFormat;
1096  REQ->plotName = plotName + holdon_post;
1097  REQ->vector_x.swap(x);
1098  REQ->vector_y.swap(y);
1099 
1101  MRPT_END
1102 #else
1103  MRPT_UNUSED_PARAM(x);
1104  MRPT_UNUSED_PARAM(y);
1105  MRPT_UNUSED_PARAM(lineFormat);
1106  MRPT_UNUSED_PARAM(plotName);
1107 #endif
1108 }
1109 
1110 /*---------------------------------------------------------------
1111  clear
1112  ---------------------------------------------------------------*/
1114 {
1115  MRPT_START
1116 #if MRPT_HAS_WXWIDGETS
1117  if (!isOpen()) return;
1118 
1119  // Send a request to destroy this object:
1120  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1121  REQ->sourcePlots = this;
1122  REQ->OPCODE = 414;
1123 
1124  // 414: Clear all plot objects.
1125 
1127 #endif
1128  MRPT_END
1129 }
1130 
1131 /*---------------------------------------------------------------
1132  hold_on
1133  ---------------------------------------------------------------*/
1135 /*---------------------------------------------------------------
1136  hold_off
1137  ---------------------------------------------------------------*/
1139 {
1140  if (m_holdon)
1141  {
1142  m_holdon = false;
1143  m_holdon_just_disabled = true;
1144  }
1145 }
1146 
1147 /*---------------------------------------------------------------
1148  addPopupMenuEntry
1149  ---------------------------------------------------------------*/
1151  const std::string& label, int menuID)
1152 {
1153 #if MRPT_HAS_WXWIDGETS
1154  MRPT_START
1155  if (!isOpen()) return;
1156 
1157  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1158  REQ->sourcePlots = this;
1159  REQ->OPCODE = 440;
1160  REQ->plotName = label;
1161  REQ->x = menuID;
1162  // 440: Inser submenu in the popup menu.
1163 
1165  MRPT_END
1166 #else
1167  MRPT_UNUSED_PARAM(label);
1168  MRPT_UNUSED_PARAM(menuID);
1169 #endif
1170 }
1171 
1172 /*---------------------------------------------------------------
1173  setMenuCallback
1174  ---------------------------------------------------------------*/
1176  TCallbackMenu userFunction, void* userParam)
1177 {
1178  ASSERT_(userFunction != nullptr);
1179  m_callback = userFunction;
1180  m_callback_param = userParam;
1181 }
An event sent by a window upon resize.
static void pushPendingWxRequest(TRequestToWxMainThread *data)
Thread-safe method to insert a new pending request (The memory must be dinamically allocated with "ne...
~CDisplayWindowPlots() override
Destructor.
An event sent by a window upon a mouse click, giving the (x,y) pixel coordinates. ...
A compile-time fixed-size numeric matrix container.
Definition: CMatrixFixed.h:33
#define MRPT_START
Definition: exceptions.h:241
The data structure for each inter-thread request:
Definition: WxSubsystem.h:189
const long ID_MENUITEM1
Template for column vectors of dynamic size, compatible with Eigen.
Create a GUI window and display plots with MATLAB-like interfaces and commands.
mrpt::void_ptr_noncopy m_hwnd
The window handle.
std::string std::string format(std::string_view fmt, ARGS &&... args)
Definition: format.h:26
void enableMousePanZoom(bool enabled)
Enable/disable the feature of pan/zoom with the mouse (default=enabled)
std::string m_caption
The caption of the window.
static int notifyWindowCreation()
Atomically increments the number of windows created with the main frame as parent.
void OnMenuClose(wxCommandEvent &event)
size_type size() const
Get a 2-vector with [NROWS NCOLS] (as in MATLAB command size(x))
The wx dialog for gui::CDisplayWindowPlots.
Definition: WxSubsystem.h:413
mrptKeyModifier
Definition: keycodes.h:156
void setPos(int x, int y) override
Changes the position of the window on the screen.
static wxBitmap getMRPTDefaultIcon()
bool m_holdon
Whether hold_on is enabled.
STL namespace.
void axis(float x_min, float x_max, float y_min, float y_max, bool aspectRatioFix=false)
Set the view area according to the passed coordinated.
void internal_plot(mrpt::math::CVectorFloat &x, mrpt::math::CVectorFloat &y, const std::string &lineFormat, const std::string &plotName)
void hold_off()
Disables keeping all the graphs (this is the default behavior).
wxImage * MRPTImage2wxImage(const mrpt::img::CImage &img)
Create a wxImage from a MRPT image.
Definition: WxUtils.cpp:24
An event sent by a window upon when it&#39;s about to be closed, either manually by the user or programma...
An event sent by a window when the mouse is moved over it.
void axis_equal(bool enable=true)
Enable/disable the fixed X/Y aspect ratio fix feature (default=disabled).
CDisplayWindowPlots(const std::string &windowCaption=std::string(), unsigned int initialWidth=350, unsigned int initialHeight=300)
Constructor.
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
float d2f(const double d)
shortcut for static_cast<float>(double)
void OnMenuSelected(wxCommandEvent &ev)
This base provides a set of functions for maths stuff.
uint32_t m_holdon_cnt
Counter for hold_on.
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
Definition: exceptions.h:137
bool isOpen()
Returns false if the user has already closed the window.
void plot(const mrpt::math::CVectorFloat &x, const mrpt::math::CVectorFloat &y, const std::string &lineFormat, const std::string &plotName)
Redirected from CDisplayWindowPlots::plot.
bool getLastMousePosition(int &x, int &y) const override
Gets the last x,y pixel coordinates of the mouse.
A pair (x,y) of pixel coordinates (integer resolution).
Definition: TPixelCoord.h:40
void(*)(int menuID, float cursor_x, float cursor_y, void *userParam) TCallbackMenu
Type for the callback function used in setMenuCallback.
const long ID_MENUITEM2
An event sent by a window upon a char pressed by the user.
void addPopupMenuEntry(const std::string &label, int menuID)
Disables keeping all the graphs (this is the default behavior).
mrpt::gui::CDisplayWindow3D::Ptr win
size_type rows() const
Number of rows in the matrix.
mrptKeyModifier keyEventToMrptKeyModifier(const wxKeyEvent &ev)
Extracts the key modifiers from a wxKeyEvent.
Definition: WxUtils.cpp:939
size_type cols() const
Number of columns in the matrix.
void OnMouseMove(wxMouseEvent &event)
void clear()
Remove all plot objects in the display.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void axis_fit(bool aspectRatioFix=false)
Fix automatically the view area according to existing graphs.
void OnResize(wxSizeEvent &event)
This class implements the GUI thread required for the wxWidgets-based GUI.
Definition: WxSubsystem.h:96
void hold_on()
Enables keeping all the graphs, instead of overwritting them.
void clf()
Remove all plot objects in the display (clear and clf do exactly the same).
void setWindowTitle(const std::string &str) override
Changes the window title text.
void plotEllipse(const mrpt::math::CVectorFloat &x, const mrpt::math::CVectorFloat &y, const std::string &lineFormat, const std::string &plotName, bool showName=false)
Redirected from CDisplayWindowPlots::plotEllipse.
#define MRPT_END
Definition: exceptions.h:245
static CDisplayWindowPlots::Ptr Create(const std::string &windowCaption, unsigned int initialWindowWidth=400, unsigned int initialWindowHeight=300)
Class factory returning a smart pointer.
void OnMouseDown(wxMouseEvent &event)
mrpt::gui::CDisplayWindowPlots * sourcePlots
Only one of source* can be non-nullptr, indicating the class that generated the request.
Definition: WxSubsystem.h:203
void destroyWxWindow()
Must be called by child classes in their destructors.
void setCursorCross(bool cursorIsCross) override
Set cursor style to default (cursorIsCross=false) or to a cross (cursorIsCross=true) ...
void OnClose(wxCloseEvent &event)
void image(void *theWxImage, float x0, float y0, float w, float h, const std::string &plotName)
Redirected from CDisplayWindowPlots::image.
Classes for creating GUI windows for 2D and 3D visualization.
Definition: about_box.h:14
void OnMenuPrint(wxCommandEvent &event)
void createWxWindow(unsigned int initialWidth, unsigned int initialHeight)
Must be called by child classes just within the constructor.
void plotEllipse(const T mean_x, const T mean_y, const mrpt::math::CMatrixDynamic< T > &cov22, const float quantiles, const std::string &lineFormat=std::string("b-"), const std::string &plotName=std::string("plotEllipse"), bool showName=false)
Plots a 2D ellipse given its mean, covariance matrix, and Each call to this function creates a new pl...
void image(const mrpt::img::CImage &img, float x_left, float y_bottom, float x_width, float y_height, const std::string &plotName=std::string("image"))
Adds a bitmap image layer.
void OnMenuAbout(wxCommandEvent &event)
This template class provides the basic functionality for a general 2D any-size, resizable container o...
The base class for GUI window classes based on wxWidgets.
void setMenuCallback(TCallbackMenu userFunction, void *userParam=nullptr)
Must be called to have a callback when the user selects one of the user-defined entries in the popup ...
void resize(unsigned int width, unsigned int height) override
Resizes the window, stretching the image to fit into the display area.
static int notifyWindowDestruction()
Atomically decrements the number of windows created with the main frame as parent.
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:148
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
Definition: os.cpp:358
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
Definition: common.h:186
static struct FontData data
Definition: gltext.cpp:144



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 3a26b90fd Wed Mar 25 20:17:03 2020 +0100 at miƩ mar 25 23:05:41 CET 2020