MRPT  2.0.0
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([[maybe_unused]] 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 #endif
684 }
685 
686 /*---------------------------------------------------------------
687  getLastMousePosition
688  ---------------------------------------------------------------*/
690  [[maybe_unused]] int& x, [[maybe_unused]] int& y) const
691 {
692 #if MRPT_HAS_WXWIDGETS && MRPT_HAS_OPENGL_GLUT
693  const auto* win = (const CWindowDialogPlots*)m_hwnd.get();
694  if (!win) return false;
695  x = win->m_last_mouse_point.x;
696  y = win->m_last_mouse_point.y;
697  return true;
698 #else
699  return false;
700 #endif
701 }
702 
703 /*---------------------------------------------------------------
704  resize
705  ---------------------------------------------------------------*/
707  [[maybe_unused]] unsigned int width, [[maybe_unused]] unsigned int height)
708 {
709 #if MRPT_HAS_WXWIDGETS
710  if (!isOpen())
711  {
712  cerr << "[CDisplayWindowPlots::resize] Window closed!: " << m_caption
713  << endl;
714  return;
715  }
716 
717  // Send a request to destroy this object:
718  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
719  REQ->sourcePlots = this;
720  REQ->OPCODE = 403;
721  REQ->x = width;
722  REQ->y = height;
724 #endif
725 }
726 
727 /*---------------------------------------------------------------
728  setPos
729  ---------------------------------------------------------------*/
730 void CDisplayWindowPlots::setPos([[maybe_unused]] int x, [[maybe_unused]] int y)
731 {
732 #if MRPT_HAS_WXWIDGETS
733  if (!isOpen())
734  {
735  cerr << "[CDisplayWindowPlots::setPos] Window closed!: " << m_caption
736  << endl;
737  return;
738  }
739 
740  // Send a request to destroy this object:
741  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
742  REQ->sourcePlots = this;
743  REQ->OPCODE = 402;
744  REQ->x = x;
745  REQ->y = y;
747 #endif
748 }
749 
750 /*---------------------------------------------------------------
751  setWindowTitle
752  ---------------------------------------------------------------*/
754  [maybe_unused]] const std::string& str)
755 {
756 #if MRPT_HAS_WXWIDGETS
757  if (!isOpen())
758  {
759  cerr << "[CDisplayWindowPlots::setWindowTitle] Window closed!: "
760  << m_caption << endl;
761  return;
762  }
763 
764  // Send a request to destroy this object:
765  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
766  REQ->sourcePlots = this;
767  REQ->OPCODE = 404;
768  REQ->str = str;
770 #endif
771 }
772 
773 /*---------------------------------------------------------------
774  enableMousePanZoom
775  ---------------------------------------------------------------*/
776 void CDisplayWindowPlots::enableMousePanZoom([[maybe_unused]] bool enabled)
777 {
778 #if MRPT_HAS_WXWIDGETS
779  if (!isOpen()) return;
780 
781  // Send a request to destroy this object:
782  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
783  REQ->sourcePlots = this;
784  REQ->OPCODE = 410;
785  REQ->boolVal = enabled;
787 #endif
788 }
789 
790 /*---------------------------------------------------------------
791  axis_equal
792  ---------------------------------------------------------------*/
793 void CDisplayWindowPlots::axis_equal([[maybe_unused]] bool enabled)
794 {
795 #if MRPT_HAS_WXWIDGETS
796  if (!isOpen()) return;
797 
798  // Send a request to destroy this object:
799  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
800  REQ->sourcePlots = this;
801  REQ->OPCODE = 411;
802  REQ->boolVal = enabled;
804 #endif
805 }
806 
807 /*---------------------------------------------------------------
808  axis
809  ---------------------------------------------------------------*/
811  [[maybe_unused]] float x_min, [[maybe_unused]] float x_max,
812  [[maybe_unused]] float y_min, [[maybe_unused]] float y_max,
813  [[maybe_unused]] bool aspectRatioFix)
814 {
815 #if MRPT_HAS_WXWIDGETS
816  if (!isOpen()) return;
817 
818  // Send a request to destroy this object:
819  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
820  REQ->sourcePlots = this;
821  REQ->OPCODE = 412;
822  REQ->vector_x.resize(2);
823  REQ->vector_x[0] = x_min;
824  REQ->vector_x[1] = x_max;
825  REQ->vector_y.resize(2);
826  REQ->vector_y[0] = y_min;
827  REQ->vector_y[1] = y_max;
828  REQ->boolVal = aspectRatioFix;
830 #endif
831 }
832 
833 /*---------------------------------------------------------------
834  axis_fit
835  ---------------------------------------------------------------*/
836 void CDisplayWindowPlots::axis_fit([[maybe_unused]] bool aspectRatioFix)
837 {
838 #if MRPT_HAS_WXWIDGETS
839  if (!isOpen()) return;
840 
841  // Send a request to destroy this object:
842  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
843  REQ->sourcePlots = this;
844  REQ->OPCODE = 413;
845  REQ->boolVal = aspectRatioFix;
847 #endif
848 }
849 
850 /*---------------------------------------------------------------
851  plotEllipse
852  ---------------------------------------------------------------*/
853 template <typename T>
855  [[maybe_unused]] const T mean_x, [[maybe_unused]] const T mean_y,
856  [[maybe_unused]] const CMatrixDynamic<T>& cov22,
857  [[maybe_unused]] const float quantiles,
858  [[maybe_unused]] const std::string& lineFormat,
859  [[maybe_unused]] const std::string& plotName,
860  [[maybe_unused]] bool showName)
861 {
862 #if MRPT_HAS_WXWIDGETS
863  MRPT_START
864  if (!isOpen()) return;
865 
866  ASSERT_(cov22.cols() == 2 && cov22.rows() == 2);
867  ASSERT_(cov22(0, 0) >= 0);
868  ASSERT_(cov22(1, 1) >= 0);
869  ASSERT_(cov22(0, 1) == cov22(1, 0));
870 
872  {
873  m_holdon_just_disabled = false;
874  this->clf();
875  }
876  std::string holdon_post;
877  if (m_holdon)
878  holdon_post =
879  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
880 
881  // Send a request to destroy this object:
882  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
883  REQ->sourcePlots = this;
884  REQ->OPCODE = 421;
885  // 421: Add/update a 2D ellipse: format string=str, plot name =plotName,
886  // vector_x[0,1]:X/Y center, vector_y[0,1,2]: Covariance matrix entries
887  // 00,11,01.
888  REQ->str = lineFormat;
889  REQ->plotName = plotName + holdon_post;
890 
891  REQ->vector_x.resize(3);
892  REQ->vector_x[0] = d2f(mean_x);
893  REQ->vector_x[1] = d2f(mean_y);
894  REQ->vector_x[2] = quantiles;
895 
896  REQ->vector_y.resize(3);
897  REQ->vector_y[0] = d2f(cov22(0, 0));
898  REQ->vector_y[1] = d2f(cov22(1, 1));
899  REQ->vector_y[2] = d2f(cov22(0, 1));
900 
901  REQ->boolVal = showName;
902 
904  MRPT_END
905 #endif
906 }
907 
908 // Explicit instantations:
910  const float mean_x, const float mean_y, const CMatrixDynamic<float>& cov22,
911  const float quantiles, const std::string& lineFormat,
912  const std::string& plotName, bool showName);
914  const double mean_x, const double mean_y,
915  const CMatrixDynamic<double>& cov22, const float quantiles,
916  const std::string& lineFormat, const std::string& plotName, bool showName);
917 
918 /*---------------------------------------------------------------
919  plotEllipse
920  ---------------------------------------------------------------*/
921 template <typename T>
923  [[maybe_unused]] const T mean_x, [[maybe_unused]] const T mean_y,
924  [[maybe_unused]] const CMatrixFixed<T, 2, 2>& cov22,
925  [[maybe_unused]] const float quantiles,
926  [[maybe_unused]] const std::string& lineFormat,
927  [[maybe_unused]] const std::string& plotName,
928  [[maybe_unused]] bool showName)
929 {
930 #if MRPT_HAS_WXWIDGETS
931  MRPT_START
932  if (!isOpen()) return;
933 
934  ASSERT_(cov22(0, 0) >= 0);
935  ASSERT_(cov22(1, 1) >= 0);
936  ASSERT_(cov22(0, 1) == cov22(1, 0));
937 
939  {
940  m_holdon_just_disabled = false;
941  this->clf();
942  }
943  std::string holdon_post;
944  if (m_holdon)
945  holdon_post =
946  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
947 
948  // Send a request to destroy this object:
949  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
950  REQ->sourcePlots = this;
951  REQ->OPCODE = 421;
952  // 421: Add/update a 2D ellipse: format string=str, plot name =plotName,
953  // vector_x[0,1]:X/Y center, vector_y[0,1,2]: Covariance matrix entries
954  // 00,11,01.
955  REQ->str = lineFormat;
956  REQ->plotName = plotName + holdon_post;
957 
958  REQ->vector_x.resize(3);
959  REQ->vector_x[0] = d2f(mean_x);
960  REQ->vector_x[1] = d2f(mean_y);
961  REQ->vector_x[2] = quantiles;
962 
963  REQ->vector_y.resize(3);
964  REQ->vector_y[0] = d2f(cov22(0, 0));
965  REQ->vector_y[1] = d2f(cov22(1, 1));
966  REQ->vector_y[2] = d2f(cov22(0, 1));
967 
968  REQ->boolVal = showName;
969 
971  MRPT_END
972 #endif
973 }
974 
975 // Explicit instantations:
977  const float mean_x, const float mean_y,
978  const CMatrixFixed<float, 2, 2>& cov22, const float quantiles,
979  const std::string& lineFormat, const std::string& plotName, bool showName);
981  const double mean_x, const double mean_y,
982  const CMatrixFixed<double, 2, 2>& cov22, const float quantiles,
983  const std::string& lineFormat, const std::string& plotName, bool showName);
984 
985 /*---------------------------------------------------------------
986  image
987  ---------------------------------------------------------------*/
989  [[maybe_unused]] const mrpt::img::CImage& img,
990  [[maybe_unused]] float x_left, [[maybe_unused]] float y_bottom,
991  [[maybe_unused]] float x_width, [[maybe_unused]] float y_height,
992  [[maybe_unused]] const std::string& plotName)
993 {
994 #if MRPT_HAS_WXWIDGETS
995  MRPT_START
996  if (!isOpen()) return;
997 
999  {
1000  m_holdon_just_disabled = false;
1001  this->clf();
1002  }
1003  std::string holdon_post;
1004  if (m_holdon)
1005  holdon_post =
1006  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
1007 
1008  // Send a request to destroy this object:
1009  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1010  REQ->sourcePlots = this;
1011  REQ->OPCODE = 422;
1012 
1013  // 422: Add/update a bitmap: plot name =plotName, vector_x[0,1]:X/Y corner,
1014  // vector_x[2,3]: X/Y widths, voidPtr2: pointer to a newly created wxImage
1015  // with the bitmap.
1016  REQ->plotName = plotName + holdon_post;
1017 
1018  REQ->vector_x.resize(4);
1019  REQ->vector_x[0] = x_left;
1020  REQ->vector_x[1] = y_bottom;
1021  REQ->vector_x[2] = x_width;
1022  REQ->vector_x[3] = y_height;
1023 
1024  REQ->voidPtr2 = mrpt::gui::MRPTImage2wxImage(img);
1025 
1027  MRPT_END
1028 #endif
1029 }
1030 
1031 /*---------------------------------------------------------------
1032  internal_plot
1033  ---------------------------------------------------------------*/
1035  [[maybe_unused]] CVectorFloat& x, [[maybe_unused]] CVectorFloat& y,
1036  [[maybe_unused]] const std::string& lineFormat,
1037  [[maybe_unused]] const std::string& plotName)
1038 {
1039 #if MRPT_HAS_WXWIDGETS
1040  MRPT_START
1041  if (!isOpen()) return;
1042 
1043  ASSERT_EQUAL_(x.size(), y.size());
1044 
1046  {
1047  m_holdon_just_disabled = false;
1048  this->clf();
1049  }
1050 
1051  if (x.empty()) return;
1052 
1053  std::string holdon_post;
1054  if (m_holdon)
1055  holdon_post =
1056  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
1057 
1058  // Send a request to destroy this object:
1059  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1060  REQ->sourcePlots = this;
1061  REQ->OPCODE = 420;
1062  REQ->str = lineFormat;
1063  REQ->plotName = plotName + holdon_post;
1064  REQ->vector_x.swap(x);
1065  REQ->vector_y.swap(y);
1066 
1068  MRPT_END
1069 #endif
1070 }
1071 
1072 /*---------------------------------------------------------------
1073  clear
1074  ---------------------------------------------------------------*/
1076 {
1077  MRPT_START
1078 #if MRPT_HAS_WXWIDGETS
1079  if (!isOpen()) return;
1080 
1081  // Send a request to destroy this object:
1082  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1083  REQ->sourcePlots = this;
1084  REQ->OPCODE = 414;
1085 
1086  // 414: Clear all plot objects.
1087 
1089 #endif
1090  MRPT_END
1091 }
1092 
1093 /*---------------------------------------------------------------
1094  hold_on
1095  ---------------------------------------------------------------*/
1097 /*---------------------------------------------------------------
1098  hold_off
1099  ---------------------------------------------------------------*/
1101 {
1102  if (m_holdon)
1103  {
1104  m_holdon = false;
1105  m_holdon_just_disabled = true;
1106  }
1107 }
1108 
1109 /*---------------------------------------------------------------
1110  addPopupMenuEntry
1111  ---------------------------------------------------------------*/
1113  [[maybe_unused]] const std::string& label, [[maybe_unused]] int menuID)
1114 {
1115 #if MRPT_HAS_WXWIDGETS
1116  MRPT_START
1117  if (!isOpen()) return;
1118 
1119  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1120  REQ->sourcePlots = this;
1121  REQ->OPCODE = 440;
1122  REQ->plotName = label;
1123  REQ->x = menuID;
1124  // 440: Inser submenu in the popup menu.
1125 
1127  MRPT_END
1128 #endif
1129 }
1130 
1131 /*---------------------------------------------------------------
1132  setMenuCallback
1133  ---------------------------------------------------------------*/
1135  TCallbackMenu userFunction, void* userParam)
1136 {
1137  ASSERT_(userFunction != nullptr);
1138  m_callback = userFunction;
1139  m_callback_param = userParam;
1140 }
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
mrptKeyModifier keyEventToMrptKeyModifier(const wxKeyEvent &ev)
Extracts the key modifiers from a wxKeyEvent.
Definition: WxUtils.cpp:939
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 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)
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...
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".
static struct FontData data
Definition: gltext.cpp:144



Page generated by Doxygen 1.8.14 for MRPT 2.0.0 Git: b38439d21 Tue Mar 31 19:58:06 2020 +0200 at miƩ abr 1 00:50:30 CEST 2020