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-2019, 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  Connect(
87  wxID_ANY, wxEVT_CLOSE_WINDOW,
88  (wxObjectEventFunction)&CWindowDialogPlots::OnClose);
89  Connect(
90  ID_MENUITEM1, wxEVT_COMMAND_MENU_SELECTED,
91  (wxObjectEventFunction)&CWindowDialogPlots::OnMenuClose);
92  Connect(
93  ID_MENU_PRINT, wxEVT_COMMAND_MENU_SELECTED,
94  (wxObjectEventFunction)&CWindowDialogPlots::OnMenuPrint);
95  Connect(
96  ID_MENUITEM2, wxEVT_COMMAND_MENU_SELECTED,
97  (wxObjectEventFunction)&CWindowDialogPlots::OnMenuAbout);
98 
99  Connect(
100  wxID_ANY, wxEVT_SIZE,
101  (wxObjectEventFunction)&CWindowDialogPlots::OnResize);
102 
103  Connect(
104  wxID_ANY, wxEVT_CHAR,
105  (wxObjectEventFunction)&CWindowDialogPlots::OnChar);
106  m_plot->Connect(
107  wxEVT_CHAR, (wxObjectEventFunction)&CWindowDialogPlots::OnChar, nullptr,
108  this);
109  m_plot->Connect(
110  wxEVT_MOTION, (wxObjectEventFunction)&CWindowDialogPlots::OnMouseMove,
111  nullptr, this);
112 
113  m_plot->Connect(
114  wxEVT_LEFT_DOWN,
115  (wxObjectEventFunction)&CWindowDialogPlots::OnMouseDown, nullptr, this);
116  m_plot->Connect(
117  wxEVT_RIGHT_DOWN,
118  (wxObjectEventFunction)&CWindowDialogPlots::OnMouseDown, nullptr, this);
119 
120  // Increment number of windows:
121  // int winCount =
123  // cout << "[CWindowDialogPlots] Notifying new window: " << winCount <<
124  // endl;
125 
126  // this->Iconize(false);
127 
128 #if 0
129  // JL: TEST CODE: This is the seed of the future new implementation based on wxFreeChart...
130  double data[][2] = {
131  { 10, 20, },
132  { 13, 16, },
133  { 7, 30, },
134  { 15, 34, },
135  { 25, 4, },
136  };
137  // first step: create plot
138  XYPlot *plot = new XYPlot();
139  // create dataset
140  XYSimpleDataset *dataset = new XYSimpleDataset();
141  // and add serie to it
142  dataset->AddSerie((double *) data, WXSIZEOF(data));
143  // set line renderer to dataset
144  dataset->SetRenderer(new XYLineRenderer());
145  // add our dataset to plot
146  plot->AddDataset(dataset);
147  // create left and bottom number axes
148  NumberAxis *leftAxis = new NumberAxis(AXIS_LEFT);
149  NumberAxis *bottomAxis = new NumberAxis(AXIS_BOTTOM);
150  // optional: set axis titles
151  leftAxis->SetTitle(wxT("X"));
152  bottomAxis->SetTitle(wxT("Y"));
153  // add axes to plot
154  plot->AddAxis(leftAxis);
155  plot->AddAxis(bottomAxis);
156  // link axes and dataset
157  plot->LinkDataVerticalAxis(0, 0);
158  plot->LinkDataHorizontalAxis(0, 0);
159  // and finally create chart
160  Chart* chart = new Chart(plot, wxT("my title"));
161  wxChartPanel *m_chartPanel = new wxChartPanel( this ); //, ID_PLOT );
162  m_chartPanel->SetChart( chart );
163 #endif
164 }
165 
166 // Destructor
168 // OnClose event:
169 void CWindowDialogPlots::OnClose(wxCloseEvent& event)
170 {
171  // Send the event:
172  bool allow_close = true;
173  try
174  {
175  mrptEventWindowClosed ev(m_winPlots, true /* allow close */);
176  m_winPlots->publishEvent(ev);
177  allow_close = ev.allow_close;
178  }
179  catch (...)
180  {
181  }
182  if (!allow_close) return; // Don't process this close event.
183 
184  // Set the m_hwnd=nullptr in our parent object.
185  m_winPlots->notifyChildWindowDestruction();
186 
187  // Decrement number of windows:
189 
190  // Signal we are destroyed:
191  m_winPlots->m_windowDestroyed.set_value();
192 
193  event.Skip(); // keep processing by parent classes.
194 }
195 
196 void CWindowDialogPlots::OnChar(wxKeyEvent& event)
197 {
198  if (m_winPlots)
199  {
200  const int code = event.GetKeyCode();
202 
203  m_winPlots->m_keyPushedCode = code;
204  m_winPlots->m_keyPushedModifier = mod;
205  m_winPlots->m_keyPushed = true;
206  // Send the event:
207  try
208  {
209  m_winPlots->publishEvent(
210  mrptEventWindowChar(m_winPlots, code, mod));
211  }
212  catch (...)
213  {
214  }
215  }
216  event.Skip();
217 }
218 
219 void CWindowDialogPlots::OnResize(wxSizeEvent& event)
220 {
221  // Send the event:
222  if (m_winPlots)
223  {
224  try
225  {
226  m_winPlots->publishEvent(mrptEventWindowResize(
227  m_winPlots, event.GetSize().GetWidth(),
228  event.GetSize().GetHeight()));
229  }
230  catch (...)
231  {
232  }
233  }
234  event.Skip(); // so it's processed by the wx system!
235 }
236 
237 void CWindowDialogPlots::OnMouseDown(wxMouseEvent& event)
238 {
239  // Send the event:
240  if (m_winPlots)
241  {
242  try
243  {
244  m_winPlots->publishEvent(mrptEventMouseDown(
245  m_winPlots, TPixelCoord(event.GetX(), event.GetY()),
246  event.LeftDown(), event.RightDown()));
247  }
248  catch (...)
249  {
250  }
251  }
252  event.Skip(); // so it's processed by the wx system!
253 }
254 
255 // Menu: Close
256 void CWindowDialogPlots::OnMenuClose(wxCommandEvent& event) { Close(); }
257 // Menu: Print
258 void CWindowDialogPlots::OnMenuPrint(wxCommandEvent& event)
259 {
260  m_plot->ShowPrintDialog();
261 }
262 // Menu: About
263 void CWindowDialogPlots::OnMenuAbout(wxCommandEvent& event)
264 {
265  ::wxMessageBox(
266  _("Plot viewer\n Class gui::CDisplayWindowPlots\n MRPT C++ & "
267  "wxMathPlot library"),
268  _("About..."));
269 }
270 
271 void CWindowDialogPlots::OnMenuSelected(wxCommandEvent& ev)
272 {
273  auto it = m_ID2ID.find(ev.GetId());
274  if (it != m_ID2ID.end())
275  {
276  if (m_winPlots && m_winPlots->m_callback)
277  m_winPlots->m_callback(
278  it->second, m_curCursorPos.x, m_curCursorPos.y,
279  m_winPlots->m_callback_param);
280  }
281 }
282 
283 void CWindowDialogPlots::OnMouseMove(wxMouseEvent& event)
284 {
285  int X, Y;
286  event.GetPosition(&X, &Y);
287  m_curCursorPos.x = m_plot->p2x(X);
288  m_curCursorPos.y = m_plot->p2y(Y);
289  m_last_mouse_point.x = X;
290  m_last_mouse_point.y = Y;
291 
292  // Send the event:
293  if (m_winPlots && m_winPlots->hasSubscribers())
294  {
295  try
296  {
297  m_winPlots->publishEvent(mrptEventMouseMove(
298  m_winPlots, mrpt::img::TPixelCoord(event.GetX(), event.GetY()),
299  event.LeftDown(), event.RightDown()));
300  }
301  catch (...)
302  {
303  }
304  }
305  event.Skip(); // so it's processed by the wx system!
306 }
307 
308 // Add / Modify a 2D plot using a MATLAB-like format string
310  const CVectorFloat& x, const CVectorFloat& y, const std::string& lineFormat,
311  const std::string& plotName)
312 {
313  mpFXYVector* theLayer;
314 
315  wxString lyName = plotName.c_str();
316  bool updateAtTheEnd = false; // If we update an existing layer, update
317  // manually to refresh the changes!
318 
319  // Already existing layer?
320  mpLayer* existingLy = m_plot->GetLayerByName(lyName);
321 
322  if (existingLy)
323  {
324  // Assure the class:
325  auto* lyPlot2D = dynamic_cast<mpFXYVector*>(existingLy);
326 
327  if (!lyPlot2D)
328  {
329  cerr << "[CWindowDialogPlots::plot] Plot name '" << plotName
330  << "' is not of expected class mpFXYVector!." << endl;
331  return;
332  }
333 
334  // Ok:
335  theLayer = lyPlot2D;
336  updateAtTheEnd = true;
337  }
338  else
339  {
340  // Create it:
341  theLayer = new mpFXYVector(lyName);
342  m_plot->AddLayer(theLayer);
343  }
344 
345  // Set data:
346  {
347  std::vector<float> x_(x.size()), y_(x.size());
348  std::memcpy(&x_[0], &x[0], sizeof(x[0]) * x_.size());
349  std::memcpy(&y_[0], &y[0], sizeof(y[0]) * y_.size());
350  theLayer->SetData(x_, y_);
351  }
352 
353  // Line style:
354  // -------------------
355  bool isContinuous = true;
356  int lineColor[] = {0, 0, 255};
357  int lineWidth = 1;
358  wxPenStyle lineStyle = wxPENSTYLE_SOLID;
359 
360  // parse string:
361  if (string::npos != lineFormat.find("."))
362  {
363  isContinuous = false;
364  }
365  if (string::npos != lineFormat.find("-"))
366  {
367  isContinuous = true;
368  lineStyle = wxPENSTYLE_SOLID;
369  }
370  if (string::npos != lineFormat.find(":"))
371  {
372  isContinuous = true;
373  lineStyle = wxPENSTYLE_LONG_DASH;
374  }
375 
376  if (string::npos != lineFormat.find("r"))
377  {
378  lineColor[0] = 0xFF;
379  lineColor[1] = 0x00;
380  lineColor[2] = 0x00;
381  }
382  if (string::npos != lineFormat.find("g"))
383  {
384  lineColor[0] = 0x00;
385  lineColor[1] = 0xFF;
386  lineColor[2] = 0x00;
387  }
388  if (string::npos != lineFormat.find("b"))
389  {
390  lineColor[0] = 0x00;
391  lineColor[1] = 0x00;
392  lineColor[2] = 0xFF;
393  }
394  if (string::npos != lineFormat.find("k"))
395  {
396  lineColor[0] = 0x00;
397  lineColor[1] = 0x00;
398  lineColor[2] = 0x00;
399  }
400  if (string::npos != lineFormat.find("m"))
401  {
402  lineColor[0] = 192;
403  lineColor[1] = 0;
404  lineColor[2] = 192;
405  }
406  if (string::npos != lineFormat.find("c"))
407  {
408  lineColor[0] = 0;
409  lineColor[1] = 192;
410  lineColor[2] = 192;
411  }
412 
413  if (string::npos != lineFormat.find("1"))
414  {
415  lineWidth = 1;
416  }
417  if (string::npos != lineFormat.find("2"))
418  {
419  lineWidth = 2;
420  }
421  if (string::npos != lineFormat.find("3"))
422  {
423  lineWidth = 3;
424  }
425  if (string::npos != lineFormat.find("4"))
426  {
427  lineWidth = 4;
428  }
429  if (string::npos != lineFormat.find("5"))
430  {
431  lineWidth = 5;
432  }
433  if (string::npos != lineFormat.find("6"))
434  {
435  lineWidth = 6;
436  }
437  if (string::npos != lineFormat.find("7"))
438  {
439  lineWidth = 7;
440  }
441  if (string::npos != lineFormat.find("8"))
442  {
443  lineWidth = 8;
444  }
445  if (string::npos != lineFormat.find("9"))
446  {
447  lineWidth = 9;
448  }
449 
450  theLayer->SetContinuity(isContinuous);
451 
452  wxPen pen(
453  wxColour(lineColor[0], lineColor[1], lineColor[2]), lineWidth,
454  lineStyle);
455  theLayer->SetPen(pen);
456 
457  theLayer->ShowName(false);
458 
459  if (updateAtTheEnd) m_plot->Refresh(false);
460 }
461 
462 // Add / Modify a 2D ellipse
463 // x[0,1]: Mean
464 // y[0,1,2]: Covariance matrix (0,0),(1,1),(0,1)
466  const CVectorFloat& x, const CVectorFloat& y, const std::string& lineFormat,
467  const std::string& plotName, bool showName)
468 {
469  mpCovarianceEllipse* theLayer;
470 
471  if (x.size() != 3 || y.size() != 3)
472  {
473  cerr << "[CWindowDialogPlots::plotEllipse] vectors do not have "
474  "expected size!!"
475  << endl;
476  return;
477  }
478 
479  wxString lyName = plotName.c_str();
480  bool updateAtTheEnd = false; // If we update an existing layer, update
481  // manually to refresh the changes!
482 
483  // Already existing layer?
484  mpLayer* existingLy = m_plot->GetLayerByName(lyName);
485 
486  if (existingLy)
487  {
488  // Assure the class:
489  auto* lyPlotEllipse = dynamic_cast<mpCovarianceEllipse*>(existingLy);
490 
491  if (!lyPlotEllipse)
492  {
493  cerr << "[CWindowDialogPlots::plotEllipse] Plot name '" << plotName
494  << "' is not of expected class mpCovarianceEllipse!." << endl;
495  return;
496  }
497 
498  // Ok:
499  theLayer = lyPlotEllipse;
500  updateAtTheEnd = true;
501  }
502  else
503  {
504  // Create it:
505  theLayer = new mpCovarianceEllipse(1, 1, 0, 2, 32, lyName);
506  m_plot->AddLayer(theLayer);
507  }
508 
509  // Set data:
510  theLayer->SetCovarianceMatrix(y[0], y[2], y[1]);
511  theLayer->SetCoordinateBase(x[0], x[1]);
512  theLayer->SetQuantiles(x[2]);
513  theLayer->ShowName(showName);
514 
515  // Line style:
516  // -------------------
517  bool isContinuous = true;
518  int lineColor[] = {0, 0, 255};
519  int lineWidth = 1;
520  wxPenStyle lineStyle = wxPENSTYLE_SOLID;
521 
522  // parse string:
523  if (string::npos != lineFormat.find("."))
524  {
525  isContinuous = false;
526  }
527  if (string::npos != lineFormat.find("-"))
528  {
529  isContinuous = true;
530  lineStyle = wxPENSTYLE_SOLID;
531  }
532  if (string::npos != lineFormat.find(":"))
533  {
534  isContinuous = true;
535  lineStyle = wxPENSTYLE_LONG_DASH;
536  }
537 
538  if (string::npos != lineFormat.find("r"))
539  {
540  lineColor[0] = 0xFF;
541  lineColor[1] = 0x00;
542  lineColor[2] = 0x00;
543  }
544  if (string::npos != lineFormat.find("g"))
545  {
546  lineColor[0] = 0x00;
547  lineColor[1] = 0xFF;
548  lineColor[2] = 0x00;
549  }
550  if (string::npos != lineFormat.find("b"))
551  {
552  lineColor[0] = 0x00;
553  lineColor[1] = 0x00;
554  lineColor[2] = 0xFF;
555  }
556  if (string::npos != lineFormat.find("k"))
557  {
558  lineColor[0] = 0x00;
559  lineColor[1] = 0x00;
560  lineColor[2] = 0x00;
561  }
562  if (string::npos != lineFormat.find("m"))
563  {
564  lineColor[0] = 192;
565  lineColor[1] = 0;
566  lineColor[2] = 192;
567  }
568  if (string::npos != lineFormat.find("c"))
569  {
570  lineColor[0] = 0;
571  lineColor[1] = 192;
572  lineColor[2] = 192;
573  }
574 
575  if (string::npos != lineFormat.find("1"))
576  {
577  lineWidth = 1;
578  }
579  if (string::npos != lineFormat.find("2"))
580  {
581  lineWidth = 2;
582  }
583  if (string::npos != lineFormat.find("3"))
584  {
585  lineWidth = 3;
586  }
587  if (string::npos != lineFormat.find("4"))
588  {
589  lineWidth = 4;
590  }
591  if (string::npos != lineFormat.find("5"))
592  {
593  lineWidth = 5;
594  }
595  if (string::npos != lineFormat.find("6"))
596  {
597  lineWidth = 6;
598  }
599  if (string::npos != lineFormat.find("7"))
600  {
601  lineWidth = 7;
602  }
603  if (string::npos != lineFormat.find("8"))
604  {
605  lineWidth = 8;
606  }
607  if (string::npos != lineFormat.find("9"))
608  {
609  lineWidth = 9;
610  }
611 
612  theLayer->SetContinuity(isContinuous);
613 
614  wxPen pen(
615  wxColour(lineColor[0], lineColor[1], lineColor[2]), lineWidth,
616  lineStyle);
617  theLayer->SetPen(pen);
618 
619  if (updateAtTheEnd) m_plot->Refresh(false);
620 }
621 
623  void* theWxImage, const float& x0, const float& y0, const float& w,
624  const float& h, const std::string& plotName)
625 {
626  mpBitmapLayer* theLayer;
627 
628  wxString lyName = plotName.c_str();
629  bool updateAtTheEnd = false; // If we update an existing layer, update
630  // manually to refresh the changes!
631 
632  // Already existing layer?
633  mpLayer* existingLy = m_plot->GetLayerByName(lyName);
634 
635  if (existingLy)
636  {
637  // Assure the class:
638  auto* ly = dynamic_cast<mpBitmapLayer*>(existingLy);
639 
640  if (!ly)
641  {
642  cerr << "[CWindowDialogPlots::image] Plot name '" << plotName
643  << "' is not of expected class mpBitmapLayer!." << endl;
644  return;
645  }
646 
647  // Ok:
648  theLayer = ly;
649  updateAtTheEnd = true;
650  }
651  else
652  {
653  // Create it:
654  theLayer = new mpBitmapLayer();
655  m_plot->AddLayer(theLayer);
656  }
657 
658  // Set data:
659  auto* ii = static_cast<wxImage*>(theWxImage);
660  theLayer->SetBitmap(*ii, x0, y0, w, h);
661 
662  delete ii;
663  theWxImage = nullptr;
664 
665  if (updateAtTheEnd) m_plot->Refresh();
666 }
667 
668 #endif
669 
671  const std::string& windowCaption, unsigned int initialWindowWidth,
672  unsigned int initialWindowHeight)
673 {
674  return std::make_shared<CDisplayWindowPlots>(
675  windowCaption, initialWindowWidth, initialWindowHeight);
676 }
677 /*---------------------------------------------------------------
678  Constructor
679  ---------------------------------------------------------------*/
681  const std::string& windowCaption, unsigned int initialWidth,
682  unsigned int initialHeight)
683  : CBaseGUIWindow(static_cast<void*>(this), 400, 499, windowCaption)
684 
685 {
686  CBaseGUIWindow::createWxWindow(initialWidth, initialHeight);
687 }
688 
689 /*---------------------------------------------------------------
690  Destructor
691  ---------------------------------------------------------------*/
693 {
695 }
696 
697 /** Set cursor style to default (cursorIsCross=false) or to a cross
698  * (cursorIsCross=true) */
699 void CDisplayWindowPlots::setCursorCross(bool cursorIsCross)
700 {
701 #if MRPT_HAS_WXWIDGETS && MRPT_HAS_OPENGL_GLUT
702  const auto* win = (const CWindowDialogPlots*)m_hwnd.get();
703  if (!win) return;
704  win->m_plot->SetCursor(
705  *(cursorIsCross ? wxCROSS_CURSOR : wxSTANDARD_CURSOR));
706 #else
707  MRPT_UNUSED_PARAM(cursorIsCross);
708 #endif
709 }
710 
711 /*---------------------------------------------------------------
712  getLastMousePosition
713  ---------------------------------------------------------------*/
715 {
716 #if MRPT_HAS_WXWIDGETS && MRPT_HAS_OPENGL_GLUT
717  const auto* win = (const CWindowDialogPlots*)m_hwnd.get();
718  if (!win) return false;
719  x = win->m_last_mouse_point.x;
720  y = win->m_last_mouse_point.y;
721  return true;
722 #else
725  return false;
726 #endif
727 }
728 
729 /*---------------------------------------------------------------
730  resize
731  ---------------------------------------------------------------*/
732 void CDisplayWindowPlots::resize(unsigned int width, unsigned int height)
733 {
734 #if MRPT_HAS_WXWIDGETS
735  if (!isOpen())
736  {
737  cerr << "[CDisplayWindowPlots::resize] Window closed!: " << m_caption
738  << endl;
739  return;
740  }
741 
742  // Send a request to destroy this object:
743  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
744  REQ->sourcePlots = this;
745  REQ->OPCODE = 403;
746  REQ->x = width;
747  REQ->y = height;
749 #else
752 #endif
753 }
754 
755 /*---------------------------------------------------------------
756  setPos
757  ---------------------------------------------------------------*/
759 {
760 #if MRPT_HAS_WXWIDGETS
761  if (!isOpen())
762  {
763  cerr << "[CDisplayWindowPlots::setPos] Window closed!: " << m_caption
764  << endl;
765  return;
766  }
767 
768  // Send a request to destroy this object:
769  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
770  REQ->sourcePlots = this;
771  REQ->OPCODE = 402;
772  REQ->x = x;
773  REQ->y = y;
775 #else
778 #endif
779 }
780 
781 /*---------------------------------------------------------------
782  setWindowTitle
783  ---------------------------------------------------------------*/
785 {
786 #if MRPT_HAS_WXWIDGETS
787  if (!isOpen())
788  {
789  cerr << "[CDisplayWindowPlots::setWindowTitle] Window closed!: "
790  << m_caption << endl;
791  return;
792  }
793 
794  // Send a request to destroy this object:
795  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
796  REQ->sourcePlots = this;
797  REQ->OPCODE = 404;
798  REQ->str = str;
800 #else
801  MRPT_UNUSED_PARAM(str);
802 #endif
803 }
804 
805 /*---------------------------------------------------------------
806  enableMousePanZoom
807  ---------------------------------------------------------------*/
809 {
810 #if MRPT_HAS_WXWIDGETS
811  if (!isOpen()) return;
812 
813  // Send a request to destroy this object:
814  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
815  REQ->sourcePlots = this;
816  REQ->OPCODE = 410;
817  REQ->boolVal = enabled;
819 #else
820  MRPT_UNUSED_PARAM(enabled);
821 #endif
822 }
823 
824 /*---------------------------------------------------------------
825  axis_equal
826  ---------------------------------------------------------------*/
828 {
829 #if MRPT_HAS_WXWIDGETS
830  if (!isOpen()) return;
831 
832  // Send a request to destroy this object:
833  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
834  REQ->sourcePlots = this;
835  REQ->OPCODE = 411;
836  REQ->boolVal = enabled;
838 #else
839  MRPT_UNUSED_PARAM(enabled);
840 #endif
841 }
842 
843 /*---------------------------------------------------------------
844  axis
845  ---------------------------------------------------------------*/
847  float x_min, float x_max, float y_min, float y_max, bool aspectRatioFix)
848 {
849 #if MRPT_HAS_WXWIDGETS
850  if (!isOpen()) return;
851 
852  // Send a request to destroy this object:
853  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
854  REQ->sourcePlots = this;
855  REQ->OPCODE = 412;
856  REQ->vector_x.resize(2);
857  REQ->vector_x[0] = x_min;
858  REQ->vector_x[1] = x_max;
859  REQ->vector_y.resize(2);
860  REQ->vector_y[0] = y_min;
861  REQ->vector_y[1] = y_max;
862  REQ->boolVal = aspectRatioFix;
864 #else
865  MRPT_UNUSED_PARAM(x_min);
866  MRPT_UNUSED_PARAM(x_max);
867  MRPT_UNUSED_PARAM(y_min);
868  MRPT_UNUSED_PARAM(y_max);
869  MRPT_UNUSED_PARAM(aspectRatioFix);
870 #endif
871 }
872 
873 /*---------------------------------------------------------------
874  axis_fit
875  ---------------------------------------------------------------*/
876 void CDisplayWindowPlots::axis_fit(bool aspectRatioFix)
877 {
878 #if MRPT_HAS_WXWIDGETS
879  if (!isOpen()) return;
880 
881  // Send a request to destroy this object:
882  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
883  REQ->sourcePlots = this;
884  REQ->OPCODE = 413;
885  REQ->boolVal = aspectRatioFix;
887 #else
888  MRPT_UNUSED_PARAM(aspectRatioFix);
889 #endif
890 }
891 
892 /*---------------------------------------------------------------
893  plotEllipse
894  ---------------------------------------------------------------*/
895 template <typename T>
897  const T mean_x, const T mean_y, const CMatrixDynamic<T>& cov22,
898  const float quantiles, const std::string& lineFormat,
899  const std::string& plotName, bool showName)
900 {
901 #if MRPT_HAS_WXWIDGETS
902  MRPT_START
903  if (!isOpen()) return;
904 
905  ASSERT_(cov22.cols() == 2 && cov22.rows() == 2);
906  ASSERT_(cov22(0, 0) >= 0);
907  ASSERT_(cov22(1, 1) >= 0);
908  ASSERT_(cov22(0, 1) == cov22(1, 0));
909 
911  {
912  m_holdon_just_disabled = false;
913  this->clf();
914  }
915  std::string holdon_post;
916  if (m_holdon)
917  holdon_post =
918  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
919 
920  // Send a request to destroy this object:
921  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
922  REQ->sourcePlots = this;
923  REQ->OPCODE = 421;
924  // 421: Add/update a 2D ellipse: format string=str, plot name =plotName,
925  // vector_x[0,1]:X/Y center, vector_y[0,1,2]: Covariance matrix entries
926  // 00,11,01.
927  REQ->str = lineFormat;
928  REQ->plotName = plotName + holdon_post;
929 
930  REQ->vector_x.resize(3);
931  REQ->vector_x[0] = mean_x;
932  REQ->vector_x[1] = mean_y;
933  REQ->vector_x[2] = quantiles;
934 
935  REQ->vector_y.resize(3);
936  REQ->vector_y[0] = cov22(0, 0);
937  REQ->vector_y[1] = cov22(1, 1);
938  REQ->vector_y[2] = cov22(0, 1);
939 
940  REQ->boolVal = showName;
941 
943  MRPT_END
944 #else
945  MRPT_UNUSED_PARAM(mean_x);
946  MRPT_UNUSED_PARAM(mean_y);
947  MRPT_UNUSED_PARAM(cov22);
948  MRPT_UNUSED_PARAM(quantiles);
949  MRPT_UNUSED_PARAM(lineFormat);
950  MRPT_UNUSED_PARAM(plotName);
951  MRPT_UNUSED_PARAM(showName);
952 #endif
953 }
954 
955 // Explicit instantations:
957  const float mean_x, const float mean_y, const CMatrixDynamic<float>& cov22,
958  const float quantiles, const std::string& lineFormat,
959  const std::string& plotName, bool showName);
961  const double mean_x, const double mean_y,
962  const CMatrixDynamic<double>& cov22, const float quantiles,
963  const std::string& lineFormat, const std::string& plotName, bool showName);
964 
965 /*---------------------------------------------------------------
966  plotEllipse
967  ---------------------------------------------------------------*/
968 template <typename T>
970  const T mean_x, const T mean_y, const CMatrixFixed<T, 2, 2>& cov22,
971  const float quantiles, const std::string& lineFormat,
972  const std::string& plotName, bool showName)
973 {
974 #if MRPT_HAS_WXWIDGETS
975  MRPT_START
976  if (!isOpen()) return;
977 
978  ASSERT_(cov22(0, 0) >= 0);
979  ASSERT_(cov22(1, 1) >= 0);
980  ASSERT_(cov22(0, 1) == cov22(1, 0));
981 
983  {
984  m_holdon_just_disabled = false;
985  this->clf();
986  }
987  std::string holdon_post;
988  if (m_holdon)
989  holdon_post =
990  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
991 
992  // Send a request to destroy this object:
993  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
994  REQ->sourcePlots = this;
995  REQ->OPCODE = 421;
996  // 421: Add/update a 2D ellipse: format string=str, plot name =plotName,
997  // vector_x[0,1]:X/Y center, vector_y[0,1,2]: Covariance matrix entries
998  // 00,11,01.
999  REQ->str = lineFormat;
1000  REQ->plotName = plotName + holdon_post;
1001 
1002  REQ->vector_x.resize(3);
1003  REQ->vector_x[0] = mean_x;
1004  REQ->vector_x[1] = mean_y;
1005  REQ->vector_x[2] = quantiles;
1006 
1007  REQ->vector_y.resize(3);
1008  REQ->vector_y[0] = cov22(0, 0);
1009  REQ->vector_y[1] = cov22(1, 1);
1010  REQ->vector_y[2] = cov22(0, 1);
1011 
1012  REQ->boolVal = showName;
1013 
1015  MRPT_END
1016 #else
1017  MRPT_UNUSED_PARAM(mean_x);
1018  MRPT_UNUSED_PARAM(mean_y);
1019  MRPT_UNUSED_PARAM(cov22);
1020  MRPT_UNUSED_PARAM(quantiles);
1021  MRPT_UNUSED_PARAM(lineFormat);
1022  MRPT_UNUSED_PARAM(plotName);
1023  MRPT_UNUSED_PARAM(showName);
1024 #endif
1025 }
1026 
1027 // Explicit instantations:
1028 template void CDisplayWindowPlots::plotEllipse(
1029  const float mean_x, const float mean_y,
1030  const CMatrixFixed<float, 2, 2>& cov22, const float quantiles,
1031  const std::string& lineFormat, const std::string& plotName, bool showName);
1032 template void CDisplayWindowPlots::plotEllipse(
1033  const double mean_x, const double mean_y,
1034  const CMatrixFixed<double, 2, 2>& cov22, const float quantiles,
1035  const std::string& lineFormat, const std::string& plotName, bool showName);
1036 
1037 /*---------------------------------------------------------------
1038  image
1039  ---------------------------------------------------------------*/
1041  const mrpt::img::CImage& img, const float& x_left, const float& y_bottom,
1042  const float& x_width, const float& y_height, const std::string& plotName)
1043 {
1044 #if MRPT_HAS_WXWIDGETS
1045  MRPT_START
1046  if (!isOpen()) return;
1047 
1049  {
1050  m_holdon_just_disabled = false;
1051  this->clf();
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 = 422;
1062 
1063  // 422: Add/update a bitmap: plot name =plotName, vector_x[0,1]:X/Y corner,
1064  // vector_x[2,3]: X/Y widths, voidPtr2: pointer to a newly created wxImage
1065  // with the bitmap.
1066  REQ->plotName = plotName + holdon_post;
1067 
1068  REQ->vector_x.resize(4);
1069  REQ->vector_x[0] = x_left;
1070  REQ->vector_x[1] = y_bottom;
1071  REQ->vector_x[2] = x_width;
1072  REQ->vector_x[3] = y_height;
1073 
1074  REQ->voidPtr2 = mrpt::gui::MRPTImage2wxImage(img);
1075 
1077  MRPT_END
1078 #else
1080  MRPT_UNUSED_PARAM(x_left);
1081  MRPT_UNUSED_PARAM(y_bottom);
1082  MRPT_UNUSED_PARAM(x_width);
1083  MRPT_UNUSED_PARAM(y_height);
1084  MRPT_UNUSED_PARAM(plotName);
1085 #endif
1086 }
1087 
1088 /*---------------------------------------------------------------
1089  internal_plot
1090  ---------------------------------------------------------------*/
1092  CVectorFloat& x, CVectorFloat& y, const std::string& lineFormat,
1093  const std::string& plotName)
1094 {
1095 #if MRPT_HAS_WXWIDGETS
1096  MRPT_START
1097  if (!isOpen()) return;
1098 
1099  ASSERT_EQUAL_(x.size(), y.size());
1100 
1102  {
1103  m_holdon_just_disabled = false;
1104  this->clf();
1105  }
1106 
1107  if (x.empty()) return;
1108 
1109  std::string holdon_post;
1110  if (m_holdon)
1111  holdon_post =
1112  format("_fig_%u", static_cast<unsigned int>(m_holdon_cnt++));
1113 
1114  // Send a request to destroy this object:
1115  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1116  REQ->sourcePlots = this;
1117  REQ->OPCODE = 420;
1118  REQ->str = lineFormat;
1119  REQ->plotName = plotName + holdon_post;
1120  REQ->vector_x.swap(x);
1121  REQ->vector_y.swap(y);
1122 
1124  MRPT_END
1125 #else
1128  MRPT_UNUSED_PARAM(lineFormat);
1129  MRPT_UNUSED_PARAM(plotName);
1130 #endif
1131 }
1132 
1133 /*---------------------------------------------------------------
1134  clear
1135  ---------------------------------------------------------------*/
1137 {
1138  MRPT_START
1139 #if MRPT_HAS_WXWIDGETS
1140  if (!isOpen()) return;
1141 
1142  // Send a request to destroy this object:
1143  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1144  REQ->sourcePlots = this;
1145  REQ->OPCODE = 414;
1146 
1147  // 414: Clear all plot objects.
1148 
1150 #endif
1151  MRPT_END
1152 }
1153 
1154 /*---------------------------------------------------------------
1155  hold_on
1156  ---------------------------------------------------------------*/
1158 /*---------------------------------------------------------------
1159  hold_off
1160  ---------------------------------------------------------------*/
1162 {
1163  if (m_holdon)
1164  {
1165  m_holdon = false;
1166  m_holdon_just_disabled = true;
1167  }
1168 }
1169 
1170 /*---------------------------------------------------------------
1171  addPopupMenuEntry
1172  ---------------------------------------------------------------*/
1174  const std::string& label, int menuID)
1175 {
1176 #if MRPT_HAS_WXWIDGETS
1177  MRPT_START
1178  if (!isOpen()) return;
1179 
1180  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1181  REQ->sourcePlots = this;
1182  REQ->OPCODE = 440;
1183  REQ->plotName = label;
1184  REQ->x = menuID;
1185  // 440: Inser submenu in the popup menu.
1186 
1188  MRPT_END
1189 #else
1190  MRPT_UNUSED_PARAM(label);
1191  MRPT_UNUSED_PARAM(menuID);
1192 #endif
1193 }
1194 
1195 /*---------------------------------------------------------------
1196  setMenuCallback
1197  ---------------------------------------------------------------*/
1199  TCallbackMenu userFunction, void* userParam)
1200 {
1201  ASSERT_(userFunction != nullptr);
1202  m_callback = userFunction;
1203  m_callback_param = userParam;
1204 }
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)
The wx dialog for gui::CDisplayWindowPlots.
Definition: WxSubsystem.h:428
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.
GLenum GLsizei width
Definition: glext.h:3535
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:4199
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
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
GLint GLvoid * img
Definition: glext.h:3769
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:39
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
GLsizei const GLchar ** string
Definition: glext.h:4116
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:944
size_type cols() const
Number of columns in the matrix.
void image(void *theWxImage, const float &x0, const float &y0, const float &w, const float &h, const std::string &plotName)
Redirected from CDisplayWindowPlots::image.
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
Definition: inftrees.h:28
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 image(const mrpt::img::CImage &img, const float &x_left, const float &y_bottom, const float &x_width, const float &y_height, const std::string &plotName=std::string("image"))
Adds a bitmap image layer.
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.
GLenum GLint GLint y
Definition: glext.h:3542
void setCursorCross(bool cursorIsCross) override
Set cursor style to default (cursorIsCross=false) or to a cross (cursorIsCross=true) ...
void OnClose(wxCloseEvent &event)
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
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...
GLenum GLint x
Definition: glext.h:3542
void OnMenuAbout(wxCommandEvent &event)
GLenum GLsizei GLsizei height
Definition: glext.h:3558
This template class provides the basic functionality for a general 2D any-size, resizable container o...
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:3550
The base class for GUI window classes.
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:147
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



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 9b18308f3 Mon Nov 18 23:39:25 2019 +0100 at lun nov 18 23:45:12 CET 2019