1 /////////////////////////////////////////////////////////////////////////////
2 // Name:            mathplot.cpp
3 // Purpose:         Framework for plotting in wxWindows
4 // Original Author: David Schalig
5 // Maintainer:      Davide Rondini
6 // Contributors:    Jose Luis Blanco, Val Greene, Maciej Suminski, Tomasz Wlostowski
7 // Created:         21/07/2003
8 // Last edit:       05/08/2016
9 // Copyright:       (c) David Schalig, Davide Rondini
10 // Licence:         wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12 
13 #ifndef _MP_MATHPLOT_H_
14 #define _MP_MATHPLOT_H_
15 
16 /** @file mathplot.h */
17 /**
18  *  wxMathPlot is a framework for mathematical graph plotting in wxWindows.
19  *
20  *  The framework is designed for convenience and ease of use.
21  *
22  *  @section screenshots Screenshots
23  *  <a href="http://wxmathplot.sourceforge.net/screenshot.shtml">Go to the screenshots page.</a>
24  *
25  *  @section overview Overview
26  *  The heart of wxMathPlot is mpWindow, which is a 2D canvas for plot layers.
27  *  mpWindow can be embedded as subwindow in a wxPane, a wxFrame, or any other wxWindow.
28  *  mpWindow provides a zoomable and moveable view of the layers. The current view can
29  *  be controlled with the mouse, the scrollbars, and a context menu.
30  *
31  *  Plot layers are implementations of the abstract base class mpLayer. Those can
32  *  be function plots, scale rulers, or any other vector data visualisation.
33  *  wxMathPlot provides two mpLayer implementations for plotting horizontal and vertical rulers: mpScaleX and mpScaleY.
34  *  For convenient function plotting a series of classes derived from mpLayer are provided,
35  *  like mpFX, mpProfile, mpLegend and so on.
36  *  These base classes already come with plot code, user's own functions can be implemented by overriding just one member for retrieving a function value.
37  *
38  *  mpWindow has built-in support for mouse-based pan and zoom through intuitive combinations of buttons and the mouse wheel. It also incorporates an optional double buffering mechanism to avoid flicker. Plots can be easily sent to printer evices or exported in bitmap formats like PNG, BMP or JPEG.
39  *
40  *  @section coding Coding conventions
41  *  wxMathPlot sticks to wxWindow's coding conventions.
42  *  All entities defined by wxMathPlot have the prefix <i>mp</i>.
43  *
44  *  @section author Author and license
45  *  wxMathPlot is published under the terms of the wxWindow license.<br>
46  *  The original author is David Schalig <mrhill@users.sourceforge.net>.<br>
47  *  From June 2007 the project is maintained by Davide Rondini <cdron77@users.sourceforge.net>.<br>
48  *  Authors can be contacted via the wxMathPlot's homepage at
49  *  https://sourceforge.net/projects/wxmathplot<br>
50  *  Contributors:<br>
51  *  Jose Luis Blanco, Val Greene.<br>
52  */
53 
54 // this definition uses windows dll to export function.
55 // WXDLLIMPEXP_MATHPLOT definition definition changed to WXDLLIMPEXP_MATHPLOT
56 // mathplot_EXPORTS will be defined by cmake
57 #ifdef mathplot_EXPORTS
58 #define WXDLLIMPEXP_MATHPLOT WXEXPORT
59 #define WXDLLIMPEXP_DATA_MATHPLOT( type ) WXEXPORT type
60 #else    // not making DLL
61 #define WXDLLIMPEXP_MATHPLOT
62 #define WXDLLIMPEXP_DATA_MATHPLOT( type ) type
63 #endif
64 
65 #include <vector>
66 
67 #include <wx/defs.h>
68 #include <wx/menu.h>
69 #include <wx/scrolwin.h>
70 #include <wx/event.h>
71 #include <wx/dynarray.h>
72 #include <wx/pen.h>
73 #include <wx/dcmemory.h>
74 #include <wx/string.h>
75 #include <wx/print.h>
76 #include <wx/image.h>
77 
78 
79 #include <deque>
80 
81 #include <algorithm>
82 
83 // For memory leak debug
84 #ifdef _WINDOWS
85 #ifdef _DEBUG
86 #include <crtdbg.h>
87 #define DEBUG_NEW   new (_NORMAL_BLOCK, __FILE__, __LINE__)
88 #else
89 #define DEBUG_NEW   new
90 #endif      // _DEBUG
91 #endif      // _WINDOWS
92 
93 // Separation for axes when set close to border
94 #define X_BORDER_SEPARATION 40
95 #define Y_BORDER_SEPARATION 60
96 
97 // -----------------------------------------------------------------------------
98 // classes
99 // -----------------------------------------------------------------------------
100 
101 class WXDLLIMPEXP_MATHPLOT mpLayer;
102 class WXDLLIMPEXP_MATHPLOT mpFX;
103 class WXDLLIMPEXP_MATHPLOT mpFY;
104 class WXDLLIMPEXP_MATHPLOT mpFXY;
105 class WXDLLIMPEXP_MATHPLOT mpFXYVector;
106 class WXDLLIMPEXP_MATHPLOT mpScaleX;
107 class WXDLLIMPEXP_MATHPLOT mpScaleY;
108 class WXDLLIMPEXP_MATHPLOT mpWindow;
109 class WXDLLIMPEXP_MATHPLOT mpText;
110 class WXDLLIMPEXP_MATHPLOT mpPrintout;
111 
112 /** Command IDs used by mpWindow */
113 enum
114 {
115     mpID_FIT = 2000,    // !< Fit view to match bounding box of all layers
116     mpID_ZOOM_IN,       // !< Zoom into view at clickposition / window center
117     mpID_ZOOM_OUT,      // !< Zoom out
118     mpID_CENTER,        // !< Center view on click position
119     mpID_LOCKASPECT,    // !< Lock x/y scaling aspect
120 };
121 
122 // -----------------------------------------------------------------------------
123 // mpLayer
124 // -----------------------------------------------------------------------------
125 
126 typedef enum __mp_Layer_Type
127 {
128     mpLAYER_UNDEF,      // !< Layer type undefined
129     mpLAYER_AXIS,       // !< Axis type layer
130     mpLAYER_PLOT,       // !< Plot type layer
131     mpLAYER_INFO,       // !< Info box type layer
132     mpLAYER_BITMAP      // !< Bitmap type layer
133 } mpLayerType;
134 
135 /** Plot layer, abstract base class.
136  *  Any number of mpLayer implementations can be attached to mpWindow.
137  *  Examples for mpLayer implementations are function graphs, or scale rulers.
138  *
139  *  For convenience mpLayer defines a name, a font (wxFont), a pen (wxPen),
140  *  and a continuity property (bool) as class members.
141  *  The default values at constructor are the default font, a black pen, and
142  *  continuity set to false (draw separate points).
143  *  These may or may not be used by implementations.
144  */
145 class mpScaleBase;
146 
147 class WXDLLIMPEXP_MATHPLOT mpLayer : public wxObject
148 {
149 public:
150     mpLayer();
151 
~mpLayer()152     virtual ~mpLayer() {};
153 
154     /** Check whether this layer has a bounding box.
155      *  The default implementation returns \a true. Override and return
156      *  false if your mpLayer implementation should be ignored by the calculation
157      *  of the global bounding box for all layers in a mpWindow.
158      *  @retval true Has bounding box
159      *  @retval false Has not bounding box
160      */
HasBBox()161     virtual bool HasBBox() const { return true; }
162 
163     /** Check whether the layer is an info box.
164      *  The default implementation returns \a false. It is overridden to \a true for mpInfoLayer
165      *  class and its derivative. It is necessary to define mouse actions behaviour over
166      *  info boxes.
167      *  @return whether the layer is an info boxes
168      *  @sa mpInfoLayer::IsInfo
169      */
IsInfo()170     virtual bool IsInfo() const { return false; };
171 
172     /** Get inclusive left border of bounding box.
173      *  @return Value
174      */
GetMinX()175     virtual double GetMinX() const { return -1.0; }
176 
177     /** Get inclusive right border of bounding box.
178      *  @return Value
179      */
GetMaxX()180     virtual double GetMaxX() const { return 1.0; }
181 
182     /** Get inclusive bottom border of bounding box.
183      *  @return Value
184      */
GetMinY()185     virtual double GetMinY() const { return -1.0; }
186 
187     /** Get inclusive top border of bounding box.
188      *  @return Value
189      */
GetMaxY()190     virtual double GetMaxY() const { return 1.0; }
191 
192     /** Plot given view of layer to the given device context.
193      *  An implementation of this function has to transform layer coordinates to
194      *  wxDC coordinates based on the view parameters retrievable from the mpWindow
195      *  passed in \a w.
196      *  Note that the public methods of mpWindow: x2p,y2p and p2x,p2y are already provided
197      *  which transform layer coordinates to DC pixel coordinates, and <b>user code should rely
198      *  on them</b> for portability and future changes to be applied transparently, instead of
199      *  implementing the following formulas manually.
200      *
201      *  The passed device context \a dc has its coordinate origin set to the top-left corner
202      *  of the visible area (the default). The coordinate orientation is as shown in the
203      *  following picture:
204      *  <pre>
205      *  (wxDC origin 0,0)
206      *  x-------------> ascending X ----------------+
207      *  |                                           |
208      *  |                                           |
209      *  |  V ascending Y                            |
210      *  |                                           |
211      *  |                                           |
212      *  |                                           |
213      *  |+------------------------------------------+  <-- right-bottom corner of the mpWindow visible area.
214      *  </pre>
215      *  Note that Y ascends in downward direction, whereas the usual vertical orientation
216      *  for mathematical plots is vice versa. Thus Y-orientation will be swapped usually,
217      *  when transforming between wxDC and mpLayer coordinates. This change of coordinates
218      *  is taken into account in the methods p2x,p2y,x2p,y2p.
219      *
220      *  <b> Rules for transformation between mpLayer and wxDC coordinates </b>
221      *  @code
222      *  dc_X = (layer_X - mpWindow::GetPosX()) * mpWindow::GetScaleX()
223      *  dc_Y = (mpWindow::GetPosY() - layer_Y) * mpWindow::GetScaleY() // swapping Y-orientation
224      *
225      *  layer_X = (dc_X / mpWindow::GetScaleX()) + mpWindow::GetPosX() // scale guaranteed to be not 0
226      *  layer_Y = mpWindow::GetPosY() - (dc_Y / mpWindow::GetScaleY()) // swapping Y-orientation
227      *  @endcode
228      *
229      *  @param dc Device context to plot to.
230      *  @param w  View to plot. The visible area can be retrieved from this object.
231      *  @sa mpWindow::p2x,mpWindow::p2y,mpWindow::x2p,mpWindow::y2p
232      */
233     virtual void Plot( wxDC& dc, mpWindow& w ) = 0;
234 
235     /** Get layer name.
236      *  @return Name
237      */
GetName()238     const wxString& GetName() const { return m_name; }
239 
240     /** Get font set for this layer.
241      *  @return Font
242      */
GetFont()243     const wxFont& GetFont() const { return m_font; }
244 
245     /** Get pen set for this layer.
246      *  @return Pen
247      */
GetPen()248     const wxPen& GetPen() const { return m_pen; }
249 
250     /** Set the 'continuity' property of the layer (true:draws a continuous line, false:draws separate points).
251      * @sa GetContinuity
252      */
SetContinuity(bool continuity)253     void SetContinuity( bool continuity ) { m_continuous = continuity; }
254 
255     /** Gets the 'continuity' property of the layer.
256      * @sa SetContinuity
257      */
GetContinuity()258     bool GetContinuity() const { return m_continuous; }
259 
260     /** Shows or hides the text label with the name of the layer (default is visible).
261      */
ShowName(bool show)262     void ShowName( bool show ) { m_showName = show; };
263 
264     /** Set layer name
265      *  @param name Name, will be copied to internal class member
266      */
SetName(wxString name)267     void SetName( wxString name ) { m_name = name; }
268 
269     /** Set layer font
270      *  @param font Font, will be copied to internal class member
271      */
SetFont(wxFont & font)272     void SetFont( wxFont& font )  { m_font = font; }
273 
274     /** Set layer pen
275      *  @param pen Pen, will be copied to internal class member
276      */
SetPen(wxPen pen)277     void SetPen( wxPen pen )     { m_pen = pen;  }
278 
279     /** Set Draw mode: inside or outside margins. Default is outside, which allows the layer to draw up to the mpWindow border.
280      *  @param drawModeOutside The draw mode to be set */
SetDrawOutsideMargins(bool drawModeOutside)281     void SetDrawOutsideMargins( bool drawModeOutside ) { m_drawOutsideMargins = drawModeOutside; };
282 
283     /** Get Draw mode: inside or outside margins.
284      *  @return The draw mode */
GetDrawOutsideMargins()285     bool GetDrawOutsideMargins() { return m_drawOutsideMargins; };
286 
287     /** Get a small square bitmap filled with the colour of the pen used in the layer. Useful to create legends or similar reference to the layers.
288      *  @param side side length in pixels
289      *  @return a wxBitmap filled with layer's colour */
290     wxBitmap GetColourSquare( int side = 16 ) const;
291 
292     /** Get layer type: a Layer can be of different types: plot lines, axis, info boxes, etc, this method returns the right value.
293      *  @return An integer indicating layer type */
GetLayerType()294     mpLayerType GetLayerType() const { return m_type; };
295 
296     /** Checks whether the layer is visible or not.
297      *  @return \a true if visible */
IsVisible()298     bool IsVisible() const { return m_visible; };
299 
300     /** Sets layer visibility.
301      *  @param show visibility bool. */
SetVisible(bool show)302     void SetVisible( bool show ) { m_visible = show; };
303 
304     /** Get brush set for this layer.
305      *  @return brush. */
GetBrush()306     const wxBrush& GetBrush() const { return m_brush; };
307 
308     /** Set layer brush
309      *  @param brush brush, will be copied to internal class member */
SetBrush(wxBrush brush)310     void SetBrush( wxBrush brush ) { m_brush = brush; };
311 
312 protected:
313 
314     wxFont m_font;                  // !< Layer's font
315     wxPen m_pen;                    // !< Layer's pen
316     wxBrush m_brush;                // !< Layer's brush
317     wxString    m_name;             // !< Layer's name
318     bool    m_continuous;           // !< Specify if the layer will be plotted as a continuous line or a set of points.
319     bool    m_showName;             // !< States whether the name of the layer must be shown (default is true).
320     bool    m_drawOutsideMargins;   // !< select if the layer should draw only inside margins or over all DC
321     mpLayerType m_type;             // !< Define layer type, which is assigned by constructor
322     bool m_visible;                 // !< Toggles layer visibility
323     DECLARE_DYNAMIC_CLASS( mpLayer )
324 };
325 
326 
327 // -----------------------------------------------------------------------------
328 // mpInfoLayer
329 // -----------------------------------------------------------------------------
330 
331 /** @class mpInfoLayer
332  *  @brief Base class to create small rectangular info boxes
333  *  mpInfoLayer is the base class to create a small rectangular info box in transparent overlay over plot layers. It is used to implement objects like legends.
334  */
335 class WXDLLIMPEXP_MATHPLOT mpInfoLayer : public mpLayer
336 {
337 public:
338     /** Default constructor. */
339     mpInfoLayer();
340 
341     /** Complete constructor.
342      *  @param rect Sets the initial size rectangle of the layer.
343      *  @param brush pointer to a fill brush. Default is transparent */
344     mpInfoLayer( wxRect rect, const wxBrush* brush = wxTRANSPARENT_BRUSH );
345 
346     /** Destructor */
347     virtual ~mpInfoLayer();
348 
349     /** Updates the content of the info box. Should be overridden by derived classes.
350      *  Update may behave in different ways according to the type of event which called it.
351      *  @param w parent mpWindow from which to obtain information
352      *  @param event The event which called the update. */
353     virtual void UpdateInfo( mpWindow& w, wxEvent& event );
354 
355     /** mpInfoLayer has not bounding box. @sa mpLayer::HasBBox
356      *  @return always \a false */
HasBBox()357     virtual bool HasBBox() const override { return false; }
358 
359     /** Plot method. Can be overridden by derived classes.
360      *  @param dc the device content where to plot
361      *  @param w the window to plot
362      *  @sa mpLayer::Plot */
363     virtual void Plot( wxDC& dc, mpWindow& w ) override;
364 
365     /** Specifies that this is an Info box layer.
366      *  @return always \a true
367      *  @sa mpLayer::IsInfo */
IsInfo()368     virtual bool IsInfo() const override { return true; }
369 
370     /** Checks whether a point is inside the info box rectangle.
371      *  @param point The point to be checked
372      *  @return \a true if the point is inside the bounding box */
373     virtual bool Inside( wxPoint& point );
374 
375     /** Moves the layer rectangle of given pixel deltas.
376      *  @param delta The wxPoint container for delta coordinates along x and y. Units are in pixels. */
377     virtual void Move( wxPoint delta );
378 
379     /** Updates the rectangle reference point. Used by internal methods of mpWindow to correctly move mpInfoLayers. */
380     virtual void UpdateReference();
381 
382     /** Returns the position of the upper left corner of the box (in pixels)
383      *  @return The rectangle position */
384     wxPoint GetPosition() const;
385 
386     /** Returns the size of the box (in pixels)
387      *  @return The rectangle size */
388     wxSize GetSize() const;
389 
390     /** Returns the current rectangle coordinates.
391      *  @return The info layer rectangle */
GetRectangle()392     const wxRect& GetRectangle() const { return m_dim; };
393 
394 protected:
395     wxRect m_dim;               // !< The bounding rectangle of the box. It may be resized dynamically by the Plot method.
396     wxPoint m_reference;        // !< Holds the reference point for movements
397     wxBrush m_brush;            // !< The brush to be used for the background
398     int m_winX, m_winY;         // !< Holds the mpWindow size. Used to rescale position when window is resized.
399 
400     DECLARE_DYNAMIC_CLASS( mpInfoLayer )
401 };
402 
403 /** @class mpInfoCoords
404  *  @brief Implements an overlay box which shows the mouse coordinates in plot units.
405  *  When an mpInfoCoords layer is activated, when mouse is moved over the mpWindow, its coordinates (in mpWindow units, not pixels) are continuously reported inside the layer box. */
406 class WXDLLIMPEXP_MATHPLOT mpInfoCoords : public mpInfoLayer
407 {
408 public:
409     /** Default constructor */
410     mpInfoCoords();
411     /** Complete constructor, setting initial rectangle and background brush.
412      *  @param rect The initial bounding rectangle.
413      *  @param brush The wxBrush to be used for box background: default is transparent */
414     mpInfoCoords( wxRect rect, const wxBrush* brush = wxTRANSPARENT_BRUSH );
415 
416     /** Default destructor */
417     ~mpInfoCoords();
418 
419     /** Updates the content of the info box. It is used to update coordinates.
420      *  @param w parent mpWindow from which to obtain information
421      *  @param event The event which called the update. */
422     virtual void UpdateInfo( mpWindow& w, wxEvent& event ) override;
423 
424     /** Plot method.
425      *  @param dc the device content where to plot
426      *  @param w the window to plot
427      *  @sa mpLayer::Plot */
428     virtual void Plot( wxDC& dc, mpWindow& w ) override;
429 
430 protected:
431     wxString m_content;     // !< string holding the coordinates to be drawn.
432 };
433 
434 /** @class mpInfoLegend
435  *  @brief Implements the legend to be added to the plot
436  *  This layer allows you to add a legend to describe the plots in the window. The legend uses the layer name as a label, and displays only layers of type mpLAYER_PLOT. */
437 class WXDLLIMPEXP_MATHPLOT mpInfoLegend : public mpInfoLayer
438 {
439 public:
440     /** Default constructor */
441     mpInfoLegend();
442 
443     /** Complete constructor, setting initial rectangle and background brush.
444      *  @param rect The initial bounding rectangle.
445      *  @param brush The wxBrush to be used for box background: default is transparent
446      *  @sa mpInfoLayer::mpInfoLayer */
447     mpInfoLegend( wxRect rect, const wxBrush* brush = wxTRANSPARENT_BRUSH );
448 
449     /**  Default destructor */
450     ~mpInfoLegend();
451 
452     /** Updates the content of the info box. Unused in this class.
453      *  @param w parent mpWindow from which to obtain information
454      *  @param event The event which called the update. */
455     virtual void UpdateInfo( mpWindow& w, wxEvent& event ) override;
456 
457     /** Plot method.
458      *  @param dc the device content where to plot
459      *  @param w the window to plot
460      *  @sa mpLayer::Plot */
461     virtual void Plot( wxDC& dc, mpWindow& w ) override;
462 
463 protected:
464 };
465 
466 
467 // -----------------------------------------------------------------------------
468 // mpLayer implementations - functions
469 // -----------------------------------------------------------------------------
470 
471 /** @name Label alignment constants
472  *  @{*/
473 
474 /** @internal */
475 #define mpALIGNMASK             0x03
476 /** Aligns label to the right. For use with mpFX. */
477 #define mpALIGN_RIGHT           0x00
478 /** Aligns label to the center. For use with mpFX and mpFY. */
479 #define mpALIGN_CENTER          0x01
480 /** Aligns label to the left. For use with mpFX. */
481 #define mpALIGN_LEFT            0x02
482 /** Aligns label to the top. For use with mpFY. */
483 #define mpALIGN_TOP             mpALIGN_RIGHT
484 /** Aligns label to the bottom. For use with mpFY. */
485 #define mpALIGN_BOTTOM          mpALIGN_LEFT
486 /** Aligns X axis to bottom border. For mpScaleX */
487 #define mpALIGN_BORDER_BOTTOM   0x04
488 /** Aligns X axis to top border. For mpScaleX */
489 #define mpALIGN_BORDER_TOP      0x05
490 /** Set label for X axis in normal mode */
491 #define mpX_NORMAL              0x00
492 /** Set label for X axis in time mode: the value is represented as minutes:seconds.milliseconds if time is less than 2 minutes, hours:minutes:seconds otherwise. */
493 #define mpX_TIME                0x01
494 /** Set label for X axis in hours mode: the value is always represented as hours:minutes:seconds. */
495 #define mpX_HOURS               0x02
496 /** Set label for X axis in date mode: the value is always represented as yyyy-mm-dd. */
497 #define mpX_DATE                0x03
498 /** Set label for X axis in datetime mode: the value is always represented as yyyy-mm-ddThh:mm:ss. */
499 #define mpX_DATETIME            0x04
500 /** Aligns Y axis to left border. For mpScaleY */
501 #define mpALIGN_BORDER_LEFT     mpALIGN_BORDER_BOTTOM
502 /** Aligns Y axis to right border. For mpScaleY */
503 #define mpALIGN_BORDER_RIGHT    mpALIGN_BORDER_TOP
504 /** Aligns label to north-east. For use with mpFXY. */
505 #define mpALIGN_NE              0x00
506 /** Aligns label to north-west. For use with mpFXY. */
507 #define mpALIGN_NW              0x01
508 /** Aligns label to south-west. For use with mpFXY. */
509 #define mpALIGN_SW              0x02
510 /** Aligns label to south-east. For use with mpFXY. */
511 #define mpALIGN_SE              0x03
512 
513 /*@}*/
514 
515 /** @name mpLayer implementations - functions
516  *  @{*/
517 
518 /** Abstract base class providing plot and labeling functionality for functions F:X->Y.
519  *  Override mpFX::GetY to implement a function.
520  *  Optionally implement a constructor and pass a name (label) and a label alignment
521  *  to the constructor mpFX::mpFX. If the layer name is empty, no label will be plotted.
522  */
523 class WXDLLIMPEXP_MATHPLOT mpFX : public mpLayer
524 {
525 public:
526     /** @param name  Label
527      *  @param flags Label alignment, pass one of #mpALIGN_RIGHT, #mpALIGN_CENTER, #mpALIGN_LEFT.
528      */
529     mpFX( const wxString& name = wxEmptyString, int flags = mpALIGN_RIGHT );
530 
531     /** Get function value for argument.
532      *  Override this function in your implementation.
533      *  @param x Argument
534      *  @return Function value
535      */
536     virtual double GetY( double x ) const = 0;
537 
538     /** Layer plot handler.
539      *  This implementation will plot the function in the visible area and
540      *  put a label according to the alignment specified.
541      */
542     virtual void Plot( wxDC& dc, mpWindow& w ) override;
543 
544 protected:
545     int m_flags;     // !< Holds label alignment
546 
547     DECLARE_DYNAMIC_CLASS( mpFX )
548 };
549 
550 /** Abstract base class providing plot and labeling functionality for functions F:Y->X.
551  *  Override mpFY::GetX to implement a function.
552  *  Optionally implement a constructor and pass a name (label) and a label alignment
553  *  to the constructor mpFY::mpFY. If the layer name is empty, no label will be plotted.
554  */
555 class WXDLLIMPEXP_MATHPLOT mpFY : public mpLayer
556 {
557 public:
558     /** @param name  Label
559      *  @param flags Label alignment, pass one of #mpALIGN_BOTTOM, #mpALIGN_CENTER, #mpALIGN_TOP.
560      */
561     mpFY( const wxString& name = wxEmptyString, int flags = mpALIGN_TOP );
562 
563     /** Get function value for argument.
564      *  Override this function in your implementation.
565      *  @param y Argument
566      *  @return Function value
567      */
568     virtual double GetX( double y ) const = 0;
569 
570     /** Layer plot handler.
571      *  This implementation will plot the function in the visible area and
572      *  put a label according to the alignment specified.
573      */
574     virtual void Plot( wxDC& dc, mpWindow& w ) override;
575 
576 protected:
577     int m_flags;     // !< Holds label alignment
578 
579     DECLARE_DYNAMIC_CLASS( mpFY )
580 };
581 
582 /** Abstract base class providing plot and labeling functionality for a locus plot F:N->X,Y.
583  *  Locus argument N is assumed to be in range 0 .. MAX_N, and implicitly derived by enumerating
584  *  all locus values. Override mpFXY::Rewind and mpFXY::GetNextXY to implement a locus.
585  *  Optionally implement a constructor and pass a name (label) and a label alignment
586  *  to the constructor mpFXY::mpFXY. If the layer name is empty, no label will be plotted.
587  */
588 
589 class WXDLLIMPEXP_MATHPLOT mpFXY : public mpLayer
590 {
591 public:
592     /** @param name  Label
593      *  @param flags Label alignment, pass one of #mpALIGN_NE, #mpALIGN_NW, #mpALIGN_SW, #mpALIGN_SE.
594      */
595     mpFXY( const wxString& name = wxEmptyString, int flags = mpALIGN_NE );
596 
597     /** Rewind value enumeration with mpFXY::GetNextXY.
598      *  Override this function in your implementation.
599      */
600     virtual void Rewind() = 0;
601 
602     /** Get locus value for next N.
603      *  Override this function in your implementation.
604      *  @param x Returns X value
605      *  @param y Returns Y value
606      */
607     virtual bool GetNextXY( double& x, double& y ) = 0;
608 
609     virtual size_t GetCount() const = 0;
610 
611     /** Layer plot handler.
612      *  This implementation will plot the locus in the visible area and
613      *  put a label according to the alignment specified.
614      */
615     virtual void Plot( wxDC& dc, mpWindow& w ) override;
616 
617     virtual void SetScale( mpScaleBase* scaleX, mpScaleBase* scaleY );
618 
619     void UpdateScales();
620 
621     double  s2x( double plotCoordX ) const;
622     double  s2y( double plotCoordY ) const;
623 
624     double  x2s( double x ) const;
625     double  y2s( double y ) const;
626 
627 protected:
628     int m_flags;     // !< Holds label alignment
629 
630     // Data to calculate label positioning
631     wxCoord maxDrawX, minDrawX, maxDrawY, minDrawY;
632     // int drawnPoints;
633     mpScaleBase* m_scaleX, * m_scaleY;
634 
635     /** Update label positioning data
636      *  @param xnew New x coordinate
637      *  @param ynew New y coordinate
638      */
639     void UpdateViewBoundary( wxCoord xnew, wxCoord ynew );
640 
641     DECLARE_DYNAMIC_CLASS( mpFXY )
642 };
643 
644 /** Abstract base class providing plot and labeling functionality for functions F:Y->X.
645  *  Override mpProfile::GetX to implement a function.
646  *  This class is similar to mpFY, but the Plot method is different. The plot is in fact represented by lines instead of points, which gives best rendering of rapidly-varying functions, and in general, data which are not so close one to another.
647  *  Optionally implement a constructor and pass a name (label) and a label alignment
648  *  to the constructor mpProfile::mpProfile. If the layer name is empty, no label will be plotted.
649  */
650 class WXDLLIMPEXP_MATHPLOT mpProfile : public mpLayer
651 {
652 public:
653     /** @param name  Label
654      *  @param flags Label alignment, pass one of #mpALIGN_BOTTOM, #mpALIGN_CENTER, #mpALIGN_TOP.
655      */
656     mpProfile( const wxString& name = wxEmptyString, int flags = mpALIGN_TOP );
657 
658     /** Get function value for argument.
659      *  Override this function in your implementation.
660      *  @param x Argument
661      *  @return Function value
662      */
663     virtual double GetY( double x ) const = 0;
664 
665     /** Layer plot handler.
666      *  This implementation will plot the function in the visible area and
667      *  put a label according to the alignment specified.
668      */
669     virtual void Plot( wxDC& dc, mpWindow& w ) override;
670 
671 protected:
672     int m_flags;     // !< Holds label alignment
673 
674     DECLARE_DYNAMIC_CLASS( mpProfile )
675 };
676 
677 /*@}*/
678 
679 // -----------------------------------------------------------------------------
680 // mpLayer implementations - furniture (scales, ...)
681 // -----------------------------------------------------------------------------
682 
683 /** @name mpLayer implementations - furniture (scales, ...)
684  *  @{*/
685 
686 /** Plot layer implementing a x-scale ruler.
687  *  The ruler is fixed at Y=0 in the coordinate system. A label is plotted at
688  *  the bottom-right hand of the ruler. The scale numbering automatically
689  *  adjusts to view and zoom factor.
690  */
691 
692 
693 class WXDLLIMPEXP_MATHPLOT mpScaleBase : public mpLayer
694 {
695 public:
696     mpScaleBase();
~mpScaleBase()697     virtual ~mpScaleBase() {};
698 
699     virtual bool IsHorizontal() const = 0;
700 
HasBBox()701     bool HasBBox() const override { return false; }
702 
703     /** Set X axis alignment.
704      *  @param align alignment (choose between mpALIGN_BORDER_BOTTOM, mpALIGN_BOTTOM, mpALIGN_CENTER,
705      * mpALIGN_TOP, mpALIGN_BORDER_TOP
706      */
SetAlign(int align)707     void SetAlign( int align ) { m_flags = align; };
708 
SetNameAlign(int align)709     void SetNameAlign( int align ) { m_nameFlags = align; }
710 
711     /** Set X axis ticks or grid
712      *  @param enable = true to plot axis ticks, false to plot grid.
713      */
SetTicks(bool enable)714     void SetTicks( bool enable ) { m_ticks = enable; };
715 
716     /** Get X axis ticks or grid
717      *  @return true if plot is drawing axis ticks, false if the grid is active.
718      */
GetTicks()719     bool GetTicks() const { return m_ticks; };
720 
721 
722     // virtual double X2p( mpWindow &w, double x ) = 0;
723     // virtual double P2x( mpWindow &w, double x ) = 0;
724 
SetDataRange(double minV,double maxV)725     void SetDataRange( double minV, double maxV )
726     {
727         m_rangeSet = true;
728         m_minV  = minV;
729         m_maxV  = maxV;
730     }
731 
GetDataRange(double & minV,double & maxV)732     void GetDataRange( double& minV, double& maxV ) const
733     {
734         minV = m_minV;
735         maxV = m_maxV;
736     }
737 
ExtendDataRange(double minV,double maxV)738     void ExtendDataRange( double minV, double maxV )
739     {
740         if( !m_rangeSet )
741         {
742             m_minV  = minV;
743             m_maxV  = maxV;
744             m_rangeSet = true;
745         }
746         else
747         {
748             m_minV  = std::min( minV, m_minV );
749             m_maxV  = std::max( maxV, m_maxV );
750         }
751 
752         if( m_minV == m_maxV )
753         {
754             m_minV = m_minV - 1.0;
755             m_maxV = m_maxV + 1.0;
756         }
757     }
758 
ResetDataRange()759     void ResetDataRange()
760     {
761         m_rangeSet = 0;
762     }
763 
AbsMaxValue()764     double AbsMaxValue() const
765     {
766         return std::max( std::abs( m_maxV ), std::abs( m_minV ) );
767     }
768 
AbsVisibleMaxValue()769     double AbsVisibleMaxValue() const
770     {
771         return m_absVisibleMaxV;
772     }
773 
TransformToPlot(double x)774     virtual double TransformToPlot( double x ) const { return 0.0; };
TransformFromPlot(double xplot)775     virtual double TransformFromPlot( double xplot ) const { return 0.0; };
776 
777     struct TickLabel
778     {
779         TickLabel( double pos_ = 0.0, const wxString& label_ = wxT("") ) :
posTickLabel780             pos( pos_ ), label( label_ ), pixelPos( 0 ), visible( true )
781         {}
782 
783         double pos;
784         wxString label;
785         int pixelPos;
786         bool visible;
787     };
788 
TickLabels()789     std::vector<TickLabel>& TickLabels() { return m_tickLabels; };
790 
791 protected:
792 
793     void    updateTickLabels( wxDC& dc, mpWindow& w );
794     void    computeLabelExtents( wxDC& dc, mpWindow& w );
795 
796     // virtual int getLabelDecimalDigits(int maxDigits) const;
getVisibleDataRange(mpWindow & w,double & minV,double & maxV)797     virtual void getVisibleDataRange( mpWindow& w, double& minV, double& maxV ) {};
recalculateTicks(wxDC & dc,mpWindow & w)798     virtual void recalculateTicks( wxDC& dc, mpWindow& w ) {};
799 
tickCount()800     int tickCount() const
801     {
802         return m_tickValues.size();
803     }
804 
labelCount()805     virtual int labelCount() const
806     {
807         return m_tickLabels.size();
808     }
809 
formatLabel(double value,int nDigits)810     virtual const wxString formatLabel( double value, int nDigits ) { return wxT( "" ); }
formatLabels()811     virtual void formatLabels() {};
812 
getTickPos(int n)813     virtual double getTickPos( int n ) const
814     {
815         return m_tickValues[n];
816     }
817 
getLabelPos(int n)818     virtual double getLabelPos( int n ) const
819     {
820         return m_tickLabels[n].pos;
821     }
822 
getLabel(int n)823     virtual wxString getLabel( int n ) const
824     {
825         return m_tickLabels[n].label;
826     }
827 
828     std::vector<double> m_tickValues;
829     std::vector<TickLabel> m_tickLabels;
830 
831     double m_offset, m_scale;
832     double m_absVisibleMaxV;
833     int m_flags;        // !< Flag for axis alignment
834     int m_nameFlags;
835     bool m_ticks;       // !< Flag to toggle between ticks or grid
836     double m_minV, m_maxV;
837     bool    m_rangeSet;
838     int m_maxLabelHeight;
839     int m_maxLabelWidth;
840 };
841 
842 class WXDLLIMPEXP_MATHPLOT mpScaleXBase : public mpScaleBase
843 {
844 public:
845     /** Full constructor.
846      *  @param name Label to plot by the ruler
847      *  @param flags Set the position of the scale with respect to the window.
848      *  @param ticks Select ticks or grid. Give true (default) for drawing axis ticks, false for drawing the grid.
849      *  @param type mpX_NORMAL for normal labels, mpX_TIME for time axis in hours, minutes, seconds.
850      */
851     mpScaleXBase( const wxString& name = wxT("X"), int flags = mpALIGN_CENTER,
852                   bool ticks = true, unsigned int type = mpX_NORMAL );
~mpScaleXBase()853     virtual ~mpScaleXBase() {};
854 
IsHorizontal()855     virtual bool IsHorizontal() const override { return true; }
856     /** Layer plot handler.
857      *  This implementation will plot the ruler adjusted to the visible area. */
858     virtual void Plot( wxDC& dc, mpWindow& w ) override;
859 
860     virtual void getVisibleDataRange( mpWindow& w, double& minV, double& maxV ) override;
861 
862     // unsigned int m_labelType; //!< Select labels mode: mpX_NORMAL for normal labels, mpX_TIME for time axis in hours, minutes, seconds
863     // wxString m_labelFormat; //!< Format string used to print labels
864 
865     DECLARE_DYNAMIC_CLASS( mpScaleXBase )
866 };
867 
868 
869 class WXDLLIMPEXP_MATHPLOT mpScaleX : public mpScaleXBase
870 {
871 public:
872     /** Full constructor.
873      *  @param name Label to plot by the ruler
874      *  @param flags Set the position of the scale with respect to the window.
875      *  @param ticks Select ticks or grid. Give true (default) for drawing axis ticks, false for drawing the grid.
876      *  @param type mpX_NORMAL for normal labels, mpX_TIME for time axis in hours, minutes, seconds. */
877     mpScaleX( const wxString& name = wxT("X"), int flags = mpALIGN_CENTER,
878               bool ticks = true, unsigned int type = mpX_NORMAL );
879 
880     /** Layer plot handler.
881      *  This implementation will plot the ruler adjusted to the visible area. */
882     // virtual void Plot(wxDC & dc, mpWindow & w);
883 
884     // virtual double X2p( mpWindow &w, double x );
885     // virtual double P2x( mpWindow &w, double x );
886     virtual double TransformToPlot( double x ) const override;
887     virtual double TransformFromPlot( double xplot ) const override;
888 
889 protected:
890     virtual void recalculateTicks( wxDC& dc, mpWindow& w ) override;
891 
892 
893     DECLARE_DYNAMIC_CLASS( mpScaleX )
894 };
895 
896 
897 class WXDLLIMPEXP_MATHPLOT mpScaleXLog : public mpScaleXBase
898 {
899 public:
900     /** Full constructor.
901      *  @param name Label to plot by the ruler
902      *  @param flags Set the position of the scale with respect to the window.
903      *  @param ticks Select ticks or grid. Give true (default) for drawing axis ticks, false for drawing the grid.
904      *  @param type mpX_NORMAL for normal labels, mpX_TIME for time axis in hours, minutes, seconds.
905      */
906     mpScaleXLog( const wxString& name = wxT("log(X)"), int flags = mpALIGN_CENTER,
907                  bool ticks = true, unsigned int type = mpX_NORMAL );
908 
909     virtual double TransformToPlot( double x ) const override;
910     virtual double TransformFromPlot( double xplot ) const override;
911 
912     /** Layer plot handler.
913      *  This implementation will plot the ruler adjusted to the visible area.
914      */
915     // virtual double X2p( mpWindow &w, double x );
916     // virtual double P2x( mpWindow &w, double x );
917 
918 protected:
919     void recalculateTicks( wxDC& dc, mpWindow& w ) override;
920 
921     // int tickCount() const;
922     // int labelCount() const;
923     // const wxString getLabel( int n );
924     // double getTickPos( int n );
925     // double getLabelPos( int n );
926 
927     void computeLabelExtents( wxDC& dc, mpWindow& w );
928 
929 
930     DECLARE_DYNAMIC_CLASS( mpScaleXLog )
931 };
932 
933 
934 /** Plot layer implementing a y-scale ruler.
935  *  If align is set to mpALIGN_CENTER, the ruler is fixed at X=0 in the coordinate system.
936  *  If the align is set to mpALIGN_TOP or mpALIGN_BOTTOM, the axis is always
937  *  drawn respectively at top or bottom of the window. A label is plotted at
938  *  the top-right hand of the ruler.
939  *  The scale numbering automatically adjusts to view and zoom factor.
940  */
941 class WXDLLIMPEXP_MATHPLOT mpScaleY : public mpScaleBase
942 {
943 public:
944     /** @param name Label to plot by the ruler
945      *  @param flags Set position of the scale respect to the window.
946      *  @param ticks Select ticks or grid. Give true (default) for drawing axis ticks, false for drawing the grid
947      */
948     mpScaleY( const wxString& name = wxT( "Y" ), int flags = mpALIGN_CENTER, bool ticks = true );
949 
IsHorizontal()950     virtual bool IsHorizontal() const override { return false; }
951 
952     /** Layer plot handler.
953      *  This implementation will plot the ruler adjusted to the visible area.
954      */
955     virtual void Plot( wxDC& dc, mpWindow& w ) override;
956 
957     /** Check whether this layer has a bounding box.
958      *  This implementation returns \a false thus making the ruler invisible
959      *  to the plot layer bounding box calculation by mpWindow.
960      */
HasBBox()961     virtual bool HasBBox() const override { return false; }
962 
963     /** Set Y axis alignment.
964      *  @param align alignment (choose between mpALIGN_BORDER_LEFT, mpALIGN_LEFT, mpALIGN_CENTER, mpALIGN_RIGHT, mpALIGN_BORDER_RIGHT) */
SetAlign(int align)965     void SetAlign( int align ) { m_flags = align; };
966 
967     /** Set Y axis ticks or grid
968      *  @param ticks true to plot axis ticks, false to plot grid. */
SetTicks(bool ticks)969     void SetTicks( bool ticks ) { m_ticks = ticks; };
970 
971     /** Get Y axis ticks or grid
972      *  @return true if plot is drawing axis ticks, false if the grid is active. */
GetTicks()973     bool GetTicks() const { return m_ticks; };
974 
975     virtual double  TransformToPlot( double x ) const override;
976     virtual double  TransformFromPlot( double xplot ) const override;
977 
978 
SetMasterScale(mpScaleY * masterScale)979     void SetMasterScale( mpScaleY* masterScale )
980     {
981         m_masterScale = masterScale;
982     }
983 
984 protected:
985     virtual void    getVisibleDataRange( mpWindow& w, double& minV, double& maxV ) override;
986     virtual void    recalculateTicks( wxDC& dc, mpWindow& w ) override;
987 
988     // virtual int tickCount() const;
989     // virtual int labelCount() const;
990     // virtual const wxString getLabel( int n );
991     // virtual double getTickPos( int n );
992     // virtual double getLabelPos( int n );
993     void    computeLabelExtents( wxDC& dc, mpWindow& w );
994     void    computeSlaveTicks( mpWindow& w );
995 
996     mpScaleY* m_masterScale;
997 
998     // double m_minV, m_maxV;
999 
1000     int m_flags;        // !< Flag for axis alignment
1001     bool m_ticks;       // !< Flag to toggle between ticks or grid
1002     // wxString m_labelFormat; //!< Format string used to print labels
1003 
1004     DECLARE_DYNAMIC_CLASS( mpScaleY )
1005 };
1006 
1007 // -----------------------------------------------------------------------------
1008 // mpWindow
1009 // -----------------------------------------------------------------------------
1010 
1011 /** @name Constants defining mouse modes for mpWindow
1012  *  @{*/
1013 
1014 /** Mouse panning drags the view. Mouse mode for mpWindow. */
1015 #define mpMOUSEMODE_DRAG    0
1016 /** Mouse panning creates a zoom box. Mouse mode for mpWindow. */
1017 #define mpMOUSEMODE_ZOOMBOX 1
1018 
1019 /*@}*/
1020 /** Define the type for the list of layers inside mpWindow */
1021 // WX_DECLARE_HASH_MAP( int, mpLayer*, wxIntegerHash, wxIntegerEqual, wxLayerList );
1022 typedef std::deque<mpLayer*> wxLayerList;
1023 
1024 /** Canvas for plotting mpLayer implementations.
1025  *
1026  *  This class defines a zoomable and moveable 2D plot canvas. Any number
1027  *  of mpLayer implementations (scale rulers, function plots, ...) can be
1028  *  attached using mpWindow::AddLayer.
1029  *
1030  *  The canvas window provides a context menu with actions for navigating the view.
1031  *  The context menu can be retrieved with mpWindow::GetPopupMenu, e.g. for extending it
1032  *  externally.
1033  *
1034  *  Since wxMathPlot version 0.03, the mpWindow incorporates the following features:
1035  *  - DoubleBuffering (Default=disabled): Can be set with EnableDoubleBuffer
1036  *  - Mouse based pan/zoom (Default=enabled): Can be set with EnableMousePanZoom.
1037  *
1038  *  The mouse commands can be visualized by the user through the popup menu, and are:
1039  *  - Mouse Move+CTRL: Pan (Move)
1040  *  - Mouse Wheel: Vertical scroll
1041  *  - Mouse Wheel+SHIFT: Horizontal scroll
1042  *  - Mouse Wheel UP+CTRL: Zoom in
1043  *  - Mouse Wheel DOWN+CTRL: Zoom out
1044  *
1045  */
1046 class WXDLLIMPEXP_MATHPLOT mpWindow : public wxWindow
1047 {
1048 public:
1049     mpWindow();
1050     mpWindow( wxWindow* parent, wxWindowID id,
1051               const wxPoint& pos = wxDefaultPosition,
1052               const wxSize& size = wxDefaultSize,
1053               long flags = 0 );
1054     ~mpWindow();
1055 
1056     /** Get reference to context menu of the plot canvas.
1057      *  @return Pointer to menu. The menu can be modified.
1058      */
GetPopupMenu()1059     wxMenu* GetPopupMenu() { return &m_popmenu; }
1060 
1061     /** Add a plot layer to the canvas.
1062      *  @param layer Pointer to layer. The mpLayer object will get under control of mpWindow,
1063      *  i.e. it will be delete'd on mpWindow destruction
1064      *  @param refreshDisplay States whether to refresh the display (UpdateAll) after adding the layer.
1065      *  @retval true Success
1066      *  @retval false Failure due to out of memory.
1067      */
1068     bool AddLayer( mpLayer* layer, bool refreshDisplay = true );
1069 
1070     /** Remove a plot layer from the canvas.
1071      *  @param layer Pointer to layer. The mpLayer object will be destructed using delete.
1072      *  @param alsoDeleteObject If set to true, the mpLayer object will be also "deleted", not just removed from the internal list.
1073      *  @param refreshDisplay States whether to refresh the display (UpdateAll) after removing the layer.
1074      *  @return true if layer is deleted correctly
1075      *
1076      *  N.B. Only the layer reference in the mpWindow is deleted, the layer object still exists!
1077      */
1078     bool DelLayer( mpLayer* layer, bool alsoDeleteObject = false, bool refreshDisplay = true );
1079 
1080     /** Remove all layers from the plot.
1081      *  @param alsoDeleteObject If set to true, the mpLayer objects will be also "deleted", not just removed from the internal list.
1082      *  @param refreshDisplay States whether to refresh the display (UpdateAll) after removing the layers.
1083      */
1084     void DelAllLayers( bool alsoDeleteObject, bool refreshDisplay = true );
1085 
1086 
1087     /*! Get the layer in list position indicated.
1088      *  N.B. You <i>must</i> know the index of the layer inside the list!
1089      *  @param position position of the layer in the layers list
1090      *  @return pointer to mpLayer
1091      */
1092     mpLayer* GetLayer( int position ) const;
1093 
1094     /*! Get the layer by its name (case sensitive).
1095      *  @param name The name of the layer to retrieve
1096      *  @return A pointer to the mpLayer object, or NULL if not found.
1097      */
1098     const mpLayer* GetLayerByName( const wxString& name ) const;
GetLayerByName(const wxString & name)1099     mpLayer* GetLayerByName( const wxString& name )
1100     {
1101         return const_cast<mpLayer*>( static_cast<const mpWindow*>( this )->GetLayerByName( name ) );
1102     }
1103 
1104     /** Get current view's X scale.
1105      *  See @ref mpLayer::Plot "rules for coordinate transformation"
1106      *  @return Scale
1107      */
GetXscl()1108     double GetXscl() const { return m_scaleX; }
GetScaleX(void)1109     double GetScaleX( void ) const { return m_scaleX; };  // Schaling's method: maybe another method exists with the same name
1110 
1111     /** Get current view's Y scale.
1112      *  See @ref mpLayer::Plot "rules for coordinate transformation"
1113      *  @return Scale
1114      */
GetYscl()1115     double GetYscl() const { return m_scaleY; }
GetScaleY(void)1116     double GetScaleY( void ) const { return m_scaleY; }   // Schaling's method: maybe another method exists with the same name
1117 
1118     /** Get current view's X position.
1119      *  See @ref mpLayer::Plot "rules for coordinate transformation"
1120      *  @return X Position in layer coordinate system, that corresponds to the center point of the view.
1121      */
GetXpos()1122     double GetXpos() const { return m_posX; }
GetPosX(void)1123     double GetPosX( void ) const { return m_posX; }
1124 
1125     /** Get current view's Y position.
1126      *  See @ref mpLayer::Plot "rules for coordinate transformation"
1127      *  @return Y Position in layer coordinate system, that corresponds to the center point of the view.
1128      */
GetYpos()1129     double GetYpos() const { return m_posY; }
GetPosY(void)1130     double GetPosY( void ) const { return m_posY; }
1131 
1132     /** Get current view's X dimension in device context units.
1133      *  Usually this is equal to wxDC::GetSize, but it might differ thus mpLayer
1134      *  implementations should rely on the value returned by the function.
1135      *  See @ref mpLayer::Plot "rules for coordinate transformation"
1136      *  @return X dimension.
1137      */
GetScrX(void)1138     int GetScrX( void ) const { return m_scrX; }
GetXScreen(void)1139     int GetXScreen( void ) const { return m_scrX; }
1140 
1141     /** Get current view's Y dimension in device context units.
1142      *  Usually this is equal to wxDC::GetSize, but it might differ thus mpLayer
1143      *  implementations should rely on the value returned by the function.
1144      *  See @ref mpLayer::Plot "rules for coordinate transformation"
1145      *  @return Y dimension.
1146      */
GetScrY(void)1147     int GetScrY( void ) const { return m_scrY; }
GetYScreen(void)1148     int GetYScreen( void ) const { return m_scrY; }
1149 
1150     /** Set current view's X scale and refresh display.
1151      *  @param scaleX New scale, must not be 0.
1152      */
1153     void SetScaleX( double scaleX );
1154 
1155     /** Set current view's Y scale and refresh display.
1156      *  @param scaleY New scale, must not be 0.
1157      */
SetScaleY(double scaleY)1158     void SetScaleY( double scaleY )
1159     {
1160         if( scaleY != 0 )
1161             m_scaleY = scaleY;
1162 
1163         UpdateAll();
1164     }
1165 
1166     /** Set current view's X position and refresh display.
1167      *  @param posX New position that corresponds to the center point of the view.
1168      */
SetPosX(double posX)1169     void SetPosX( double posX ) { m_posX = posX; UpdateAll(); }
1170 
1171     /** Set current view's Y position and refresh display.
1172      *  @param posY New position that corresponds to the center point of the view.
1173      */
SetPosY(double posY)1174     void SetPosY( double posY ) { m_posY = posY; UpdateAll(); }
1175 
1176     /** Set current view's X and Y position and refresh display.
1177      *  @param posX New position that corresponds to the center point of the view.
1178      *  @param posY New position that corresponds to the center point of the view.
1179      */
SetPos(double posX,double posY)1180     void SetPos( double posX, double posY ) { m_posX = posX; m_posY = posY; UpdateAll(); }
1181 
1182     /** Set current view's dimensions in device context units.
1183      *  Needed by plotting functions. It doesn't refresh display.
1184      *  @param scrX New position that corresponds to the center point of the view.
1185      *  @param scrY New position that corresponds to the center point of the view.
1186      */
SetScr(int scrX,int scrY)1187     void SetScr( int scrX, int scrY ) { m_scrX = scrX; m_scrY = scrY; }
1188 
1189     /** Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates, using current mpWindow position and scale.
1190      * @sa p2y,x2p,y2p */
1191     // double p2x(wxCoord pixelCoordX, bool drawOutside = true ); // { return m_posX + pixelCoordX/m_scaleX; }
p2x(wxCoord pixelCoordX)1192     inline double p2x( wxCoord pixelCoordX ) { return m_posX + pixelCoordX / m_scaleX; }
1193 
1194     /** Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates, using current mpWindow position and scale.
1195      * @sa p2x,x2p,y2p */
1196     // double p2y(wxCoord pixelCoordY, bool drawOutside = true ); //{ return m_posY - pixelCoordY/m_scaleY; }
p2y(wxCoord pixelCoordY)1197     inline double p2y( wxCoord pixelCoordY ) { return m_posY - pixelCoordY / m_scaleY; }
1198 
1199     /** Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates, using current mpWindow position and scale.
1200      * @sa p2x,p2y,y2p */
1201     // wxCoord x2p(double x, bool drawOutside = true); // { return (wxCoord) ( (x-m_posX) * m_scaleX); }
x2p(double x)1202     inline wxCoord x2p( double x ) { return (wxCoord) ( (x - m_posX) * m_scaleX ); }
1203 
1204     /** Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates, using current mpWindow position and scale.
1205      * @sa p2x,p2y,x2p */
1206     // wxCoord y2p(double y, bool drawOutside = true); // { return (wxCoord) ( (m_posY-y) * m_scaleY); }
y2p(double y)1207     inline wxCoord y2p( double y ) { return (wxCoord) ( (m_posY - y) * m_scaleY ); }
1208 
1209 
1210     /** Enable/disable the double-buffering of the window, eliminating the flicker (default=disabled).
1211      */
EnableDoubleBuffer(bool enabled)1212     void EnableDoubleBuffer( bool enabled ) { m_enableDoubleBuffer = enabled; }
1213 
1214     /** Enable/disable the feature of pan/zoom with the mouse (default=enabled)
1215      */
EnableMousePanZoom(bool enabled)1216     void EnableMousePanZoom( bool enabled ) { m_enableMouseNavigation = enabled; }
1217 
1218     /** Enable/disable trackpad friendly panning (2-axis scroll wheel)
1219      */
EnableMouseWheelPan(bool enabled)1220     void EnableMouseWheelPan( bool enabled ) { m_enableMouseWheelPan = enabled; }
1221 
1222     /** Enable or disable X/Y scale aspect locking for the view.
1223      *  @note Explicit calls to mpWindow::SetScaleX and mpWindow::SetScaleY will set
1224      *  an unlocked aspect, but any other action changing the view scale will
1225      *  lock the aspect again.
1226      */
1227     void LockAspect( bool enable = true );
1228 
1229     /** Checks whether the X/Y scale aspect is locked.
1230      *  @retval true Locked
1231      *  @retval false Unlocked
1232      */
IsAspectLocked()1233     inline bool IsAspectLocked() const { return m_lockaspect; }
1234 
1235     /** Set view to fit global bounding box of all plot layers and refresh display.
1236      *  Scale and position will be set to show all attached mpLayers.
1237      *  The X/Y scale aspect lock is taken into account.
1238      */
1239     void Fit() override;
1240 
1241     /** Set view to fit a given bounding box and refresh display.
1242      *  The X/Y scale aspect lock is taken into account.
1243      *  If provided, the parameters printSizeX and printSizeY are taken as the DC size, and the
1244      *  pixel scales are computed accordingly. Also, in this case the passed borders are not saved
1245      *  as the "desired borders", since this use will be invoked only when printing.
1246      */
1247     void Fit( double xMin, double xMax, double yMin, double yMax,
1248               wxCoord* printSizeX = NULL, wxCoord* printSizeY = NULL );
1249 
1250     /** Zoom into current view and refresh display
1251      * @param centerPoint The point (pixel coordinates) that will stay in the same
1252      * position on the screen after the zoom (by default, the center of the mpWindow).
1253      */
1254     void ZoomIn( const wxPoint& centerPoint = wxDefaultPosition );
1255     void ZoomIn( const wxPoint& centerPoint, double zoomFactor );
1256 
1257     /** Zoom out current view and refresh display
1258      * @param centerPoint The point (pixel coordinates) that will stay in the same
1259      * position on the screen after the zoom (by default, the center of the mpWindow).
1260      */
1261     void ZoomOut( const wxPoint& centerPoint = wxDefaultPosition );
1262     void ZoomOut( const wxPoint& centerPoint, double zoomFactor );
1263 
1264     /** Zoom in current view along X and refresh display */
1265     void ZoomInX();
1266 
1267     /** Zoom out current view along X and refresh display */
1268     void ZoomOutX();
1269 
1270     /** Zoom in current view along Y and refresh display */
1271     void ZoomInY();
1272 
1273     /** Zoom out current view along Y and refresh display */
1274     void ZoomOutY();
1275 
1276     /** Zoom view fitting given coordinates to the window (p0 and p1 do not need to be in any specific order)
1277      */
1278     void ZoomRect( wxPoint p0, wxPoint p1 );
1279 
1280     /** Refresh display */
1281     void UpdateAll();
1282 
1283     // Added methods by Davide Rondini
1284 
1285     /** Counts the number of plot layers, excluding axes or text: this is to count only the layers
1286      * which have a bounding box.
1287      *  \return The number of profiles plotted.
1288      */
1289     unsigned int CountLayers() const;
1290 
1291     /** Counts the number of plot layers, whether or not they have a bounding box.
1292      *  \return The number of layers in the mpWindow. */
CountAllLayers()1293     unsigned int CountAllLayers() const { return m_layers.size(); };
1294 
1295 #if 0
1296     /** Draws the mpWindow on a page for printing
1297      *  \param print the mpPrintout where to print the graph
1298      */
1299     void PrintGraph(mpPrintout *print);
1300 #endif
1301 
1302     /** Returns the left-border layer coordinate that the user wants the mpWindow to show
1303      * (it may be not exactly the actual shown coordinate in the case of locked aspect ratio).
1304      * @sa Fit
1305      */
GetDesiredXmin()1306     double GetDesiredXmin() const { return m_desiredXmin; }
1307 
1308     /** Returns the right-border layer coordinate that the user wants the mpWindow to show
1309      * (it may be not exactly the actual shown coordinate in the case of locked aspect ratio).
1310      * @sa Fit
1311      */
GetDesiredXmax()1312     double GetDesiredXmax() const { return m_desiredXmax; }
1313 
1314     /** Returns the bottom-border layer coordinate that the user wants the mpWindow to show
1315      * (it may be not exactly the actual shown coordinate in the case of locked aspect ratio).
1316      * @sa Fit
1317      */
GetDesiredYmin()1318     double GetDesiredYmin() const { return m_desiredYmin; }
1319 
1320     /** Returns the top layer-border coordinate that the user wants the mpWindow to show
1321      * (it may be not exactly the actual shown coordinate in the case of locked aspect ratio).
1322      * @sa Fit
1323      */
GetDesiredYmax()1324     double GetDesiredYmax() const { return m_desiredYmax; }
1325 
1326     /** Returns the bounding box coordinates
1327      *  @param bbox Pointer to a 6-element double array where to store bounding box coordinates.
1328      */
1329     void GetBoundingBox( double* bbox ) const;
1330 
1331     /** Enable/disable scrollbars
1332      *  @param status Set to true to show scrollbars */
1333     void SetMPScrollbars( bool status );
1334 
1335     /** Get scrollbars status.
1336      *  @return true if scrollbars are visible */
GetMPScrollbars()1337     bool GetMPScrollbars() const { return m_enableScrollBars; };
1338 
1339     /** Draw the window on a wxBitmap, then save it to a file.
1340      *  @param filename File name where to save the screenshot
1341      *  @param type image type to be saved: see wxImage output file types for flags
1342      *  @param imageSize Set a size for the output image. Default is the same as the screen size
1343      *  @param fit Decide whether to fit the plot into the size*/
1344     bool SaveScreenshot( const wxString& filename, wxBitmapType type = wxBITMAP_TYPE_BMP,
1345                          wxSize imageSize = wxDefaultSize, bool fit = false );
1346 
1347     /** This value sets the zoom steps whenever the user clicks "Zoom in/out" or performs zoom with the mouse wheel.
1348      *  It must be a number above unity. This number is used for zoom in, and its inverse for zoom out.
1349      * Set to 1.5 by default.
1350      */
1351     static double zoomIncrementalFactor;
1352 
1353     /** Set window margins, creating a blank area where some kinds of layers cannot draw.
1354      * This is useful for example to draw axes outside the area where the plots are drawn.
1355      *  @param top Top border
1356      *  @param right Right border
1357      *  @param bottom Bottom border
1358      *  @param left Left border */
1359     void SetMargins( int top, int right, int bottom, int left );
1360 
1361     /** Set the top margin. @param top Top Margin */
SetMarginTop(int top)1362     void SetMarginTop( int top ) { m_marginTop = top; };
1363     /** Set the right margin. @param right Right Margin */
SetMarginRight(int right)1364     void SetMarginRight( int right ) { m_marginRight = right; };
1365     /** Set the bottom margin. @param bottom Bottom Margin */
SetMarginBottom(int bottom)1366     void SetMarginBottom( int bottom ) { m_marginBottom = bottom; };
1367     /** Set the left margin. @param left Left Margin */
SetMarginLeft(int left)1368     void SetMarginLeft( int left ) { m_marginLeft = left; };
1369 
1370     /** @return the top margin. */
GetMarginTop()1371     int GetMarginTop() const { return m_marginTop; };
1372     /** @return the right margin. */
GetMarginRight()1373     int GetMarginRight() const { return m_marginRight; };
1374     /** @return the bottom margin. */
GetMarginBottom()1375     int GetMarginBottom() const { return m_marginBottom; };
1376     /** @return the left margin. */
GetMarginLeft()1377     int GetMarginLeft() const { return m_marginLeft; };
1378 
1379 #if 0
1380     /** Sets whether to show coordinate tooltip when mouse passes over the plot.
1381      * \param value true for enable, false for disable
1382      */
1383     // void EnableCoordTooltip(bool value = true);
1384 
1385     /** Gets coordinate tooltip status.
1386      * \return true for enable, false for disable
1387      */
1388     // bool GetCoordTooltip() { return m_coordTooltip; };
1389 #endif
1390 
1391     /** Check if a given point is inside the area of a mpInfoLayer and eventually returns its pointer.
1392      *  @param point The position to be checked
1393      *  @return If an info layer is found, returns its pointer, NULL otherwise */
1394     mpInfoLayer* IsInsideInfoLayer( wxPoint& point );
1395 
1396     /** Sets the visibility of a layer by its name.
1397      *  @param name The layer name to set visibility
1398      *  @param viewable the view status to be set */
1399     void SetLayerVisible( const wxString& name, bool viewable );
1400 
1401     /** Check whether a layer with given name is visible
1402      *  @param name The layer name
1403      *  @return layer visibility status */
1404     bool IsLayerVisible( const wxString& name ) const;
1405 
1406     /** Sets the visibility of a layer by its position in layer list.
1407      *  @param position The layer position in layer list
1408      *  @param viewable the view status to be set */
1409     void SetLayerVisible( const unsigned int position, bool viewable );
1410 
1411     /** Check whether the layer at given position is visible
1412      *  @param position The layer position in layer list
1413      *  @return layer visibility status */
1414     bool IsLayerVisible( unsigned int position ) const;
1415 
1416     /** Set Color theme. Provide colours to set a new colour theme.
1417      *  @param bgColour Background colour
1418      *  @param drawColour The colour used to draw all elements in foreground, axes excluded
1419      *  @param axesColour The colour used to draw axes (but not their labels) */
1420     void SetColourTheme( const wxColour& bgColour,
1421                          const wxColour& drawColour,
1422                          const wxColour& axesColour );
1423 
1424     /** Get axes draw colour
1425      *  @return reference to axis colour used in theme */
GetAxesColour()1426     const wxColour& GetAxesColour() { return m_axColour; };
1427 
1428     /** Limit zooming & panning to the area used by the plots */
LimitView(bool aEnable)1429     void LimitView( bool aEnable )
1430     {
1431         m_enableLimitedView = aEnable;
1432     }
1433 
1434 protected:
1435     void    OnPaint( wxPaintEvent& event );             // !< Paint handler, will plot all attached layers
1436     void    OnSize( wxSizeEvent& event );               // !< Size handler, will update scroll bar sizes
1437 
1438     // void OnScroll2       (wxScrollWinEvent &event); //!< Scroll handler, will move canvas
1439     void    OnShowPopupMenu( wxMouseEvent& event );     // !< Mouse handler, will show context menu
1440     void    OnMouseMiddleDown( wxMouseEvent& event );   // !< Mouse handler, for detecting when the user
1441 
1442     // !< drags with the middle button or just "clicks" for the menu
1443     void    OnCenter( wxCommandEvent& event );              // !< Context menu handler
1444     void    OnFit( wxCommandEvent& event );                 // !< Context menu handler
1445     void    OnZoomIn( wxCommandEvent& event );              // !< Context menu handler
1446     void    OnZoomOut( wxCommandEvent& event );             // !< Context menu handler
1447     void    OnLockAspect( wxCommandEvent& event );          // !< Context menu handler
1448     void    OnMouseWheel( wxMouseEvent& event );            // !< Mouse handler for the wheel
1449     void    OnMagnify( wxMouseEvent& event );               // !< Pinch zoom handler
1450     void    OnMouseMove( wxMouseEvent& event );             // !< Mouse handler for mouse motion (for pan)
1451     void    OnMouseLeftDown( wxMouseEvent& event );         // !< Mouse left click (for rect zoom)
1452     void    OnMouseLeftRelease( wxMouseEvent& event );      // !< Mouse left click (for rect zoom)
1453     void    OnScrollThumbTrack( wxScrollWinEvent& event );  // !< Scroll thumb on scroll bar moving
1454     void    OnScrollPageUp( wxScrollWinEvent& event );      // !< Scroll page up
1455     void    OnScrollPageDown( wxScrollWinEvent& event );    // !< Scroll page down
1456     void    OnScrollLineUp( wxScrollWinEvent& event );      // !< Scroll line up
1457     void    OnScrollLineDown( wxScrollWinEvent& event );    // !< Scroll line down
1458     void    OnScrollTop( wxScrollWinEvent& event );         // !< Scroll to top
1459     void    OnScrollBottom( wxScrollWinEvent& event );      // !< Scroll to bottom
1460 
1461     void DoScrollCalc( const int position, const int orientation );
1462 
1463     void    DoZoomInXCalc( const int staticXpixel );
1464     void    DoZoomInYCalc( const int staticYpixel );
1465     void    DoZoomOutXCalc( const int staticXpixel );
1466     void    DoZoomOutYCalc( const int staticYpixel );
1467 
CheckXLimits(double & desiredMax,double & desiredMin)1468     bool CheckXLimits( double& desiredMax, double& desiredMin ) const
1469     {
1470         return !( m_enableLimitedView
1471                   && (desiredMax > m_maxX - m_marginRight / m_scaleX
1472                       || desiredMin < m_minX - m_marginLeft / m_scaleX) );
1473     }
1474 
CheckYLimits(double & desiredMax,double & desiredMin)1475     bool CheckYLimits( double& desiredMax, double& desiredMin ) const
1476     {
1477         return !( m_enableLimitedView
1478                   && (desiredMax > m_maxY + m_marginBottom / m_scaleY
1479                       || desiredMin < m_minY + m_marginTop / m_scaleY) );
1480     }
1481 
1482     void AdjustLimitedView();
1483 
1484     /** Recalculate global layer bounding box, and save it in m_minX,...
1485      * \return true if there is any valid BBox information.
1486      */
1487     virtual bool UpdateBBox();
1488 
1489     /** Applies new X view coordinates depending on the settings
1490      * \return true if the changes were applied
1491      */
1492     virtual bool SetXView( double pos, double desiredMax, double desiredMin );
1493 
1494     /** Applies new Y view coordinates depending on the settings
1495      * \return true if the changes were applied
1496      */
1497     virtual bool SetYView( double pos, double desiredMax, double desiredMin );
1498 
1499     // wxList m_layers;    //!< List of attached plot layers
1500     wxLayerList m_layers;   // !< List of attached plot layers
1501     wxMenu m_popmenu;       // !< Canvas' context menu
1502     bool m_lockaspect;      // !< Scale aspect is locked or not
1503     // bool   m_coordTooltip; //!< Selects whether to show coordinate tooltip
1504     wxColour m_bgColour;    // !< Background Colour
1505     wxColour m_fgColour;    // !< Foreground Colour
1506     wxColour m_axColour;    // !< Axes Colour
1507 
1508     double m_minX;          // !< Global layer bounding box, left border incl.
1509     double m_maxX;          // !< Global layer bounding box, right border incl.
1510     double m_minY;          // !< Global layer bounding box, bottom border incl.
1511     double m_maxY;          // !< Global layer bounding box, top border incl.
1512     double m_scaleX;        // !< Current view's X scale
1513     double m_scaleY;        // !< Current view's Y scale
1514     double m_posX;          // !< Current view's X position
1515     double m_posY;          // !< Current view's Y position
1516     int m_scrX;             // !< Current view's X dimension
1517     int m_scrY;             // !< Current view's Y dimension
1518     int m_clickedX;         // !< Last mouse click X position, for centering and zooming the view
1519     int m_clickedY;         // !< Last mouse click Y position, for centering and zooming the view
1520 
1521     /** These are updated in Fit() only, and may be different from the real borders
1522      * (layer coordinates) only if lock aspect ratio is true.
1523      */
1524     double m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax;
1525 
1526     int m_marginTop, m_marginRight, m_marginBottom, m_marginLeft;
1527 
1528     int m_last_lx, m_last_ly;               // !< For double buffering
1529     wxMemoryDC m_buff_dc;                   // !< For double buffering
1530     wxBitmap*   m_buff_bmp;                 // !< For double buffering
1531     bool    m_enableDoubleBuffer;           // !< For double buffering
1532     bool    m_enableMouseNavigation;        // !< For pan/zoom with the mouse.
1533     bool    m_enableMouseWheelPan;          // !< Trackpad pan/zoom
1534     bool    m_enableLimitedView;
1535     wxPoint m_mouseMClick;                  // !< For the middle button "drag" feature
1536     wxPoint m_mouseLClick;                  // !< Starting coords for rectangular zoom selection
1537     bool    m_enableScrollBars;
1538     wxPoint m_scroll;
1539     mpInfoLayer* m_movingInfoLayer;          // !< For moving info layers over the window area
1540     bool m_zooming;
1541     wxRect m_zoomRect;
1542     DECLARE_DYNAMIC_CLASS( mpWindow )
1543     DECLARE_EVENT_TABLE()
1544 };
1545 
1546 // -----------------------------------------------------------------------------
1547 // mpFXYVector - provided by Jose Luis Blanco
1548 // -----------------------------------------------------------------------------
1549 
1550 /** A class providing graphs functionality for a 2D plot (either continuous or a set of points), from vectors of data.
1551  *  This class can be used directly, the user does not need to derive any new class. Simply pass the data as two vectors
1552  *  with the same length containing the X and Y coordinates to the method SetData.
1553  *
1554  *  To generate a graph with a set of points, call
1555  *  \code
1556  *  layerVar->SetContinuity(false)
1557  *  \endcode
1558  *
1559  *  or
1560  *
1561  *  \code
1562  *  layerVar->SetContinuity(true)
1563  *  \endcode
1564  *
1565  *  to render the sequence of coordinates as a continuous line.
1566  *
1567  *  (Added: Jose Luis Blanco, AGO-2007)
1568  */
1569 class WXDLLIMPEXP_MATHPLOT mpFXYVector : public mpFXY
1570 {
1571 public:
1572     /** @param name  Label
1573      *  @param flags Label alignment, pass one of #mpALIGN_NE, #mpALIGN_NW, #mpALIGN_SW, #mpALIGN_SE.
1574      */
1575     mpFXYVector( const wxString& name = wxEmptyString, int flags = mpALIGN_NE );
1576 
~mpFXYVector()1577     virtual ~mpFXYVector() {}
1578 
1579     /** Changes the internal data: the set of points to draw.
1580      *  Both vectors MUST be of the same length. This method DOES NOT refresh the mpWindow; do it manually.
1581      * @sa Clear
1582      */
1583     virtual void SetData( const std::vector<double>& xs, const std::vector<double>& ys );
1584 
1585     /** Clears all the data, leaving the layer empty.
1586      * @sa SetData
1587      */
1588     void Clear();
1589 
1590 protected:
1591     /** The internal copy of the set of data to draw.
1592      */
1593     std::vector<double> m_xs, m_ys;
1594 
1595     /** The internal counter for the "GetNextXY" interface
1596      */
1597     size_t m_index;
1598 
1599     /** Loaded at SetData
1600      */
1601     double m_minX, m_maxX, m_minY, m_maxY;
1602 
1603     /** Rewind value enumeration with mpFXY::GetNextXY.
1604      *  Overridden in this implementation.
1605      */
1606     void Rewind() override;
1607 
1608     /** Get locus value for next N.
1609      *  Overridden in this implementation.
1610      *  @param x Returns X value
1611      *  @param y Returns Y value
1612      */
1613     bool GetNextXY( double& x, double& y ) override;
1614 
1615     size_t GetCount() const override;
1616 
1617 public:
1618     /** Returns the actual minimum X data (loaded in SetData).
1619      */
GetMinX()1620     double GetMinX() const override { return m_minX; }
1621 
1622     /** Returns the actual minimum Y data (loaded in SetData).
1623      */
GetMinY()1624     double GetMinY() const override { return m_minY; }
1625 
1626     /** Returns the actual maximum X data (loaded in SetData).
1627      */
GetMaxX()1628     double GetMaxX() const override { return m_maxX; }
1629 
1630     /** Returns the actual maximum Y data (loaded in SetData).
1631      */
GetMaxY()1632     double GetMaxY() const override { return m_maxY; }
1633 
1634 protected:
1635 
1636     DECLARE_DYNAMIC_CLASS( mpFXYVector )
1637 };
1638 
1639 
1640 #if 0
1641 
1642 class WXDLLIMPEXP_MATHPLOT mpFSemiLogXVector : public mpFXYVector
1643 {
1644 public:
1645     /** @param name  Label
1646      *  @param flags Label alignment, pass one of #mpALIGN_NE, #mpALIGN_NW, #mpALIGN_SW, #mpALIGN_SE.
1647      */
1648     mpFSemiLogXVector( wxString name = wxEmptyString, int flags = mpALIGN_NE );
1649 
1650     virtual ~mpFSemiLogXVector() {}
1651 
1652     /** Changes the internal data: the set of points to draw.
1653      *  Both vectors MUST be of the same length. This method DOES NOT refresh the mpWindow; do it manually.
1654      * @sa Clear
1655      */
1656 
1657     DECLARE_DYNAMIC_CLASS( mpFSemiLogXVector )
1658 };
1659 #endif
1660 
1661 // -----------------------------------------------------------------------------
1662 // mpText - provided by Val Greene
1663 // -----------------------------------------------------------------------------
1664 
1665 /** Plot layer implementing a text string.
1666  *  The text is plotted using a percentage system 0-100%, so the actual
1667  *  coordinates for the location are not required, and the text stays
1668  *  on the plot regardless of the other layers location and scaling
1669  *  factors.
1670  */
1671 class WXDLLIMPEXP_MATHPLOT mpText : public mpLayer
1672 {
1673 public:
1674     /** @param name text to be drawn in the plot
1675      *  @param offsetx holds offset for the X location in percentage (0-100)
1676      *  @param offsety holds offset for the Y location in percentage (0-100) */
1677     mpText( const wxString& name = wxT("Title"), int offsetx = 5, int offsety = 50 );
1678 
1679     /** Text Layer plot handler.
1680      *  This implementation will plot text adjusted to the visible area. */
1681     virtual void Plot( wxDC& dc, mpWindow& w ) override;
1682 
1683     /** mpText should not be used for scaling decisions. */
HasBBox()1684     virtual bool HasBBox() const override { return false; }
1685 
1686 protected:
1687     int m_offsetx;      // !< Holds offset for X in percentage
1688     int m_offsety;      // !< Holds offset for Y in percentage
1689 
1690     DECLARE_DYNAMIC_CLASS( mpText )
1691 };
1692 
1693 
1694 // -----------------------------------------------------------------------------
1695 // mpPrintout - provided by Davide Rondini
1696 // -----------------------------------------------------------------------------
1697 
1698 /** Printout class used by mpWindow to draw in the objects to be printed.
1699  *  The object itself can then used by the default wxWidgets printing system
1700  *  to print mppWindow objects.
1701  */
1702 class WXDLLIMPEXP_MATHPLOT mpPrintout : public wxPrintout
1703 {
1704 public:
1705     mpPrintout( mpWindow* drawWindow, const wxChar* title = _T("wxMathPlot print output") );
~mpPrintout()1706     virtual ~mpPrintout() {};
1707 
SetDrawState(bool drawState)1708     void SetDrawState( bool drawState ) { drawn = drawState; };
1709     bool    OnPrintPage( int page ) override;
1710     bool    HasPage( int page ) override;
1711 
1712 private:
1713     bool drawn;
1714     mpWindow* plotWindow;
1715 };
1716 
1717 
1718 // -----------------------------------------------------------------------------
1719 // mpMovableObject  - provided by Jose Luis Blanco
1720 // -----------------------------------------------------------------------------
1721 /** This virtual class represents objects that can be moved to an arbitrary 2D location+rotation.
1722  *  The current transformation is set through SetCoordinateBase.
1723  *  To ease the implementation of descendent classes, mpMovableObject will
1724  *  be in charge of Bounding Box computation and layer rendering, assuming that
1725  *  the object updates its shape in m_shape_xs & m_shape_ys.
1726  */
1727 class WXDLLIMPEXP_MATHPLOT mpMovableObject : public mpLayer
1728 {
1729 public:
1730     /** Default constructor (sets location and rotation to (0,0,0))
1731      */
mpMovableObject()1732     mpMovableObject() :
1733         m_flags( 0 ),
1734         m_reference_x( 0 ),
1735         m_reference_y( 0 ),
1736         m_reference_phi( 0 ),
1737         m_shape_xs( 0 ),
1738         m_shape_ys( 0 ),
1739         m_bbox_min_x( 0 ),
1740         m_bbox_max_x( 0 ),
1741         m_bbox_min_y( 0 ),
1742         m_bbox_max_y( 0 )
1743     {
1744         m_type = mpLAYER_PLOT;
1745     }
1746 
~mpMovableObject()1747     virtual ~mpMovableObject() {};
1748 
1749     /** Get the current coordinate transformation.
1750      */
GetCoordinateBase(double & x,double & y,double & phi)1751     void GetCoordinateBase( double& x, double& y, double& phi ) const
1752     {
1753         x = m_reference_x;
1754         y = m_reference_y;
1755         phi = m_reference_phi;
1756     }
1757 
1758     /** Set the coordinate transformation (phi in radians, 0 means no rotation).
1759      */
1760     void SetCoordinateBase( double x, double y, double phi = 0 )
1761     {
1762         m_reference_x = x;
1763         m_reference_y = y;
1764         m_reference_phi = phi;
1765         m_flags = mpALIGN_NE;
1766         ShapeUpdated();
1767     }
1768 
HasBBox()1769     virtual bool HasBBox() const override { return m_trans_shape_xs.size()!=0; }
1770 
1771     /** Get inclusive left border of bounding box.
1772      */
GetMinX()1773     virtual double GetMinX() const override { return m_bbox_min_x; }
1774 
1775     /** Get inclusive right border of bounding box.
1776      */
GetMaxX()1777     virtual double GetMaxX() const override { return m_bbox_max_x; }
1778 
1779     /** Get inclusive bottom border of bounding box.
1780      */
GetMinY()1781     virtual double GetMinY() const override { return m_bbox_min_y; }
1782 
1783     /** Get inclusive top border of bounding box.
1784      */
GetMaxY()1785     virtual double GetMaxY() const override { return m_bbox_max_y; }
1786 
1787     virtual void Plot( wxDC& dc, mpWindow& w ) override;
1788 
1789     /** Set label axis alignment.
1790      *  @param align alignment (choose between mpALIGN_NE, mpALIGN_NW, mpALIGN_SW, mpALIGN_SE
1791      */
SetAlign(int align)1792     void SetAlign( int align ) { m_flags = align; };
1793 
1794 protected:
1795     int m_flags;     // !< Holds label alignment
1796 
1797     /** The coordinates of the object (orientation "phi" is in radians).
1798      */
1799     double m_reference_x, m_reference_y, m_reference_phi;
1800 
1801     /** A method for 2D translation and rotation, using the current transformation
1802      * stored in m_reference_x,m_reference_y,m_reference_phi.
1803      */
1804     void TranslatePoint( double x, double y, double& out_x, double& out_y );
1805 
1806     /** This contains the object points, in local coordinates
1807      * (to be transformed by the current transformation).
1808      */
1809     std::vector<double> m_shape_xs, m_shape_ys;
1810 
1811     /** The buffer for the translated & rotated points (to avoid recomputing them with each mpWindow refresh).
1812      *
1813      */
1814     std::vector<double> m_trans_shape_xs, m_trans_shape_ys;
1815 
1816     /** The precomputed bounding box:
1817      * @sa ShapeUpdated
1818      */
1819     double m_bbox_min_x, m_bbox_max_x, m_bbox_min_y, m_bbox_max_y;
1820 
1821     /** Must be called by the descendent class after updating the shape (m_shape_xs/ys),
1822      * or when the transformation changes.
1823      *  This method updates the buffers m_trans_shape_xs/ys, and the precomputed bounding box.
1824      */
1825     void ShapeUpdated();
1826 };
1827 
1828 // -----------------------------------------------------------------------------
1829 // mpCovarianceEllipse  - provided by Jose Luis Blanco
1830 // -----------------------------------------------------------------------------
1831 /** A 2D ellipse, described by a 2x2 covariance matrix.
1832  *  The relation between the multivariate Gaussian confidence interval and
1833  *   the "quantiles" in this class is:
1834  *     - 1 : 68.27% confidence interval
1835  *     - 2 : 95.45%
1836  *     - 3 : 99.73%
1837  *     - 4 : 99.994%
1838  * For example, see http://en.wikipedia.org/wiki/Normal_distribution#Standard_deviation_and_confidence_intervals
1839  *
1840  * The ellipse will be always centered at the origin. Use mpMovableObject::SetCoordinateBase to move it.
1841  */
1842 class WXDLLIMPEXP_MATHPLOT mpCovarianceEllipse : public mpMovableObject
1843 {
1844 public:
1845     /** Default constructor.
1846      * Initializes to a unity diagonal covariance matrix, a 95% confidence interval (2 sigmas),
1847      * 32 segments, and a continuous plot (m_continuous=true).
1848      */
1849     mpCovarianceEllipse( double cov_00 = 1,
1850             double cov_11 = 1,
1851             double cov_01 = 0,
1852             double quantiles = 2,
1853             int segments = 32,
1854             const wxString& layerName = wxT("") ) :
m_cov_00(cov_00)1855         m_cov_00( cov_00 ),
1856         m_cov_11( cov_11 ),
1857         m_cov_01( cov_01 ),
1858         m_quantiles( quantiles ),
1859         m_segments( segments )
1860     {
1861         m_continuous = true;
1862         m_name = layerName;
1863         RecalculateShape();
1864         m_type = mpLAYER_PLOT;
1865     }
1866 
~mpCovarianceEllipse()1867     virtual ~mpCovarianceEllipse() {}
1868 
GetQuantiles()1869     double GetQuantiles() const { return m_quantiles; }
1870 
1871     /** Set how many "quantiles" to draw, that is, the confidence interval of the ellipse (see above).
1872      */
SetQuantiles(double q)1873     void SetQuantiles( double q )
1874     {
1875         m_quantiles = q;
1876         RecalculateShape();
1877     }
1878 
SetSegments(int segments)1879     void SetSegments( int segments ) { m_segments = segments; }
GetSegments()1880     int GetSegments() const { return m_segments; }
1881 
1882     /** Returns the elements of the current covariance matrix:
1883      */
GetCovarianceMatrix(double & cov_00,double & cov_01,double & cov_11)1884     void GetCovarianceMatrix( double& cov_00, double& cov_01, double& cov_11 ) const
1885     {
1886         cov_00  = m_cov_00;
1887         cov_01  = m_cov_01;
1888         cov_11  = m_cov_11;
1889     }
1890 
1891     /** Changes the covariance matrix:
1892      */
SetCovarianceMatrix(double cov_00,double cov_01,double cov_11)1893     void SetCovarianceMatrix( double cov_00, double cov_01, double cov_11 )
1894     {
1895         m_cov_00 = cov_00;
1896         m_cov_01 = cov_01;
1897         m_cov_11 = cov_11;
1898         RecalculateShape();
1899     }
1900 
1901 protected:
1902     /** The elements of the matrix (only 3 since cov(0,1)=cov(1,0) in any positive definite matrix).
1903      */
1904     double m_cov_00, m_cov_11, m_cov_01;
1905     double m_quantiles;
1906 
1907     /** The number of line segments that build up the ellipse.
1908      */
1909     int m_segments;
1910 
1911     /** Called to update the m_shape_xs, m_shape_ys vectors, whenever a parameter changes.
1912      */
1913     void RecalculateShape();
1914 };
1915 
1916 // -----------------------------------------------------------------------------
1917 // mpPolygon - provided by Jose Luis Blanco
1918 // -----------------------------------------------------------------------------
1919 /** An arbitrary polygon, descendant of mpMovableObject.
1920  *  Use "setPoints" to set the list of N points. This class also can draw non-closed polygons by
1921  *   passing the appropriate parameters to "setPoints". To draw a point-cloud, call "SetContinuity(false)".
1922  */
1923 class WXDLLIMPEXP_MATHPLOT mpPolygon : public mpMovableObject
1924 {
1925 public:
1926     /** Default constructor.
1927      */
1928     mpPolygon( const wxString& layerName = wxT("") )
1929     {
1930         m_continuous = true;
1931         m_name = layerName;
1932     }
1933 
~mpPolygon()1934     virtual ~mpPolygon() {}
1935 
1936     /** Set the points in the polygon.
1937      * @param points_xs  The X coordinates of the points.
1938      * @param points_ys  The Y coordinates of the points.
1939      * @param closedShape If set to true, an additional segment will be added from the last to the first point.
1940      */
1941     void setPoints( const std::vector<double>& points_xs,
1942             const std::vector<double>& points_ys,
1943             bool closedShape = true );
1944 };
1945 
1946 // -----------------------------------------------------------------------------
1947 // mpMovableObject  - provided by Jose Luis Blanco
1948 // -----------------------------------------------------------------------------
1949 /** This virtual class represents objects that can be moved to an arbitrary 2D location+rotation.
1950  *  The current transformation is set through SetCoordinateBase.
1951  *  To ease the implementation of descendent classes, mpMovableObject will
1952  *  be in charge of Bounding Box computation and layer render, assuming that
1953  *  the object updates its shape in m_shape_xs & m_shape_ys.
1954  */
1955 class WXDLLIMPEXP_MATHPLOT mpBitmapLayer : public mpLayer
1956 {
1957 public:
1958     /** Default constructor.
1959      */
mpBitmapLayer()1960     mpBitmapLayer()
1961     {
1962         m_min_x = m_max_x =
1963                       m_min_y = m_max_y = 0;
1964         m_scaledBitmap_offset_x = 0;
1965         m_scaledBitmap_offset_y = 0;
1966         m_validImg = false;
1967         m_type = mpLAYER_BITMAP;
1968     }
1969 
~mpBitmapLayer()1970     virtual ~mpBitmapLayer() {};
1971 
1972     /** Returns a copy of the current bitmap assigned to the layer.
1973      */
1974     void GetBitmapCopy( wxImage& outBmp ) const;
1975 
1976     /** Change the bitmap associated with the layer (to update the screen, refresh the mpWindow).
1977      *  @param inBmp The bitmap to associate. A copy is made, thus it can be released after calling this.
1978      *  @param x The left corner X coordinate (in plot units).
1979      *  @param y The top corner Y coordinate (in plot units).
1980      *  @param lx The width in plot units.
1981      *  @param ly The height in plot units.
1982      */
1983     void SetBitmap( const wxImage& inBmp, double x, double y, double lx, double ly );
1984 
HasBBox()1985     virtual bool HasBBox() const override { return true; }
1986 
1987     /** Get inclusive left border of bounding box.
1988      */
GetMinX()1989     virtual double GetMinX() const override { return m_min_x; }
1990 
1991     /** Get inclusive right border of bounding box.
1992      */
GetMaxX()1993     virtual double GetMaxX() const override { return m_max_x; }
1994 
1995     /** Get inclusive bottom border of bounding box.
1996      */
GetMinY()1997     virtual double GetMinY() const override { return m_min_y; }
1998 
1999     /** Get inclusive top border of bounding box.
2000      */
GetMaxY()2001     virtual double GetMaxY() const override { return m_max_y; }
2002 
2003     virtual void Plot( wxDC& dc, mpWindow& w ) override;
2004 
2005     /** Set label axis alignment.
2006      *  @param align alignment (choose between mpALIGN_NE, mpALIGN_NW, mpALIGN_SW, mpALIGN_SE
2007      */
SetAlign(int align)2008     void SetAlign( int align ) { m_flags = align; };
2009 
2010 protected:
2011     int m_flags;     // !< Holds label alignment
2012 
2013     /** The internal copy of the Bitmap:
2014      */
2015     wxImage m_bitmap;
2016     wxBitmap m_scaledBitmap;
2017     wxCoord m_scaledBitmap_offset_x, m_scaledBitmap_offset_y;
2018 
2019     bool m_validImg;
2020 
2021     /** The shape of the bitmap:
2022      */
2023     double m_min_x, m_max_x, m_min_y, m_max_y;
2024 };
2025 
2026 /*@}*/
2027 
2028 #endif    // _MP_MATHPLOT_H_
2029