1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Framework for mathematical graph plotting in wxWindows
4 // Author: David Schalig
7 // Copyright: (c) David Schalig
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #ifndef _MP_MATHPLOT_H_
12 #define _MP_MATHPLOT_H_
13 #define ZOOM_FACTOR 1.5
15 /* @file mathplot.h */
16 /* @mainpage wxMathPlot
17 wxMathPlot is a framework for mathematical graph plotting in wxWindows.
19 The framework is designed for convenience and ease of use.
21 @section screenshots Screenshots
22 <a href="screenshots.html">Go to the screenshots page.</a>
24 @section overview Overview
25 The heart of wxMathPlot is mpWindow, which is a 2D canvas for plot layers.
26 mpWindow can be embedded as subwindow in a wxPane, a wxFrame, or any other wxWindow.
27 mpWindow provides a zoomable and moveable view of the layers. The current view can
28 be controlled with the mouse, the scrollbars, and a context menu.
30 Plot layers are implementations of the abstract base class mpLayer. Those can
31 be function plots, scale rulers, or any other vector data visualisation. wxMathPlot provides
32 two mpLayer implementations for plotting horizontal and vertical rulers: mpScaleX and mpScaleY.
33 For convenient function plotting three more abstract base classes derived from mpLayer
34 are provided: mpFX, mpFY and mpFXY. These base classes already come with plot code, own
35 functions can be implemented by overiding just one member for retrieving a function value.
37 @section coding Coding conventions
38 wxMathPlot sticks to wxWindow's coding conventions. All entities defined by wxMathPlot
39 have the prefix <i>mp</i>.
41 @section author Author and license
42 wxMathPlot is published under the terms of the wxWindow license.
43 The author David Schalig can be contacted via the wxMathPlot's homepage at
44 http://sourceforge.net/projects/wxmathplot
48 #if defined(__GNUG__) && !defined(__APPLE__)
49 #pragma interface "mathplot.h"
58 #include "wx/scrolwin.h"
60 #include "wx/dynarray.h"
63 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
75 /** Command IDs used by mpWindow */
78 mpID_FIT = 2000, //!< Fit view to match bounding box of all layers
79 mpID_ZOOM_IN, //!< Zoom into view at clickposition / window center
80 mpID_ZOOM_OUT, //!< Zoom out
81 mpID_CENTER, //!< Center view on click position
82 mpID_LOCKASPECT, //!< Lock x/y scaling aspect
83 mpID_LINE_GUIDES, //!< Enables or disables the line guides drawing condition
86 //-----------------------------------------------------------------------------
88 //-----------------------------------------------------------------------------
90 /** Plot layer, abstract base class.
91 Any number of mpLayer implementations can be attached to mpWindow.
92 Examples for mpLayer implementations are function graphs, or scale rulers.
94 For convenience mpLayer defines a name, a font (wxFont), and a pen (wxPen)
95 as class members. These may or may not be used by implementations.
97 class mpLayer : public wxObject
102 /** Check whether this layer has a bounding box.
103 The default implementation returns \a TRUE. Overide and return
104 FALSE if your mpLayer implementation should be ignored by the calculation
105 of the global bounding box for all layers in a mpWindow.
106 @retval TRUE Has bounding box
107 @retval FALSE Has not bounding box
109 virtual bool HasBBox() { return TRUE; }
111 /** Get inclusive left border of bounding box.
114 virtual double GetMinX() { return -1.0; }
116 /** Get inclusive right border of bounding box.
119 virtual double GetMaxX() { return 1.0; }
121 /** Get inclusive bottom border of bounding box.
124 virtual double GetMinY() { return -1.0; }
126 /** Get inclusive top border of bounding box.
129 virtual double GetMaxY() { return 1.0; }
131 /** Plot given view of layer to the given device context.
132 An implementation of this function has to transform layer coordinates to
133 wxDC coordinates based on the view parameters retrievable from the mpWindow
134 passed in \a w. The passed device context \a dc has its coordinate origin set
135 to the center of the visible area. The coordinate orientation is as show in the
138 +--------------------------------------------------+
141 | (wxDC origin 0,0) |
142 | x-------------> acending X |
146 +--------------------------------------------------+
148 Note that Y ascends in downward direction, whereas the usual vertical orientation
149 for mathematical plots is vice versa. Thus Y-orientation will be swapped usually,
150 when transforming between wxDC and mpLayer coordinates.
152 <b> Rules for transformation between mpLayer and wxDC coordinates </b>
154 dc_X = (layer_X - mpWindow::GetPosX()) * mpWindow::GetScaleX()
155 dc_Y = (mpWindow::GetPosY() - layer_Y) * mpWindow::GetScaleY() // swapping Y-orientation
157 layer_X = (dc_X / mpWindow::GetScaleX()) + mpWindow::GetPosX() // scale guaranted to be not 0
158 layer_Y = mpWindow::GetPosY() - (dc_Y / mpWindow::GetScaleY()) // swapping Y-orientation
161 @param dc Device context to plot to.
162 @param w View to plot. The visible area can be retrieved from this object.
164 virtual void Plot(wxDC & dc, mpWindow & w) = 0;
169 wxString GetName() const { return m_name; }
171 /** Get font set for this layer.
174 const wxFont& GetFont() const { return m_font; }
176 /** Get pen set for this layer.
179 const wxPen& GetPen() const { return m_pen; }
182 @param name Name, will be copied to internal class member
184 void SetName(wxString name) { m_name = name; }
187 @param font Font, will be copied to internal class member
189 void SetFont(wxFont& font) { m_font = font; }
192 @param pen Pen, will be copied to internal class member
194 void SetPen(wxPen& pen) { m_pen = pen; }
197 wxFont m_font; //!< Layer's font
198 wxPen m_pen; //!< Layer's pen
199 wxString m_name; //!< Layer's name
201 DECLARE_CLASS(mpLayer)
204 //-----------------------------------------------------------------------------
205 // mpLayer implementations - functions
206 //-----------------------------------------------------------------------------
208 /** @name Label alignment constants
212 #define mpALIGNMASK 0x03
213 /** Aligns label to the right. For use with mpFX. */
214 #define mpALIGN_RIGHT 0x00
215 /** Aligns label to the center. For use with mpFX and mpFY. */
216 #define mpALIGN_CENTER 0x01
217 /** Aligns label to the left. For use with mpFX. */
218 #define mpALIGN_LEFT 0x02
219 /** Aligns label to the top. For use with mpFY. */
220 #define mpALIGN_TOP mpALIGN_RIGHT
221 /** Aligns label to the bottom. For use with mpFY. */
222 #define mpALIGN_BOTTOM mpALIGN_LEFT
223 /** Aligns label to north-east. For use with mpFXY. */
224 #define mpALIGN_NE 0x00
225 /** Aligns label to north-west. For use with mpFXY. */
226 #define mpALIGN_NW 0x01
227 /** Aligns label to south-west. For use with mpFXY. */
228 #define mpALIGN_SW 0x02
229 /** Aligns label to south-east. For use with mpFXY. */
230 #define mpALIGN_SE 0x03
234 /** @name mpLayer implementations - functions
237 /** Abstract base class providing plot and labeling functionality for functions F:X->Y.
238 Override mpFX::GetY to implement a function.
239 Optionally implement a constructor and pass a name (label) and a label alignment
240 to the constructor mpFX::mpFX. If the layer name is empty, no label will be plotted.
242 class mpFX : public mpLayer
245 /** @param name Label
246 @param flags Label alignment, pass one of #mpALIGN_RIGHT, #mpALIGN_CENTER, #mpALIGN_LEFT.
248 mpFX(wxString name = wxEmptyString, int flags = mpALIGN_RIGHT);
250 /** Get function value for argument.
251 Override this function in your implementation.
253 @return Function value
255 virtual double GetY( double x ) = 0;
257 /** Layer plot handler.
258 This implementation will plot the function in the visible area and
259 put a label according to the aligment specified.
261 virtual void Plot(wxDC & dc, mpWindow & w);
264 int m_flags; //!< Holds label alignment
269 /** Abstract base class providing plot and labeling functionality for functions F:Y->X.
270 Override mpFY::GetX to implement a function.
271 Optionally implement a constructor and pass a name (label) and a label alignment
272 to the constructor mpFY::mpFY. If the layer name is empty, no label will be plotted.
274 class mpFY : public mpLayer
277 /** @param name Label
278 @param flags Label alignment, pass one of #mpALIGN_BOTTOM, #mpALIGN_CENTER, #mpALIGN_TOP.
280 mpFY(wxString name = wxEmptyString, int flags = mpALIGN_TOP);
282 /** Get function value for argument.
283 Override this function in your implementation.
285 @return Function value
287 virtual double GetX( double y ) = 0;
289 /** Layer plot handler.
290 This implementation will plot the function in the visible area and
291 put a label according to the aligment specified.
293 virtual void Plot(wxDC & dc, mpWindow & w);
296 int m_flags; //!< Holds label alignment
301 /** Abstract base class providing plot and labeling functionality for a locus plot F:N->X,Y.
302 Locus argument N is assumed to be in range 0 .. MAX_N, and implicitely derived by enumrating
303 all locus values. Override mpFXY::Rewind and mpFXY::GetNextXY to implement a locus.
304 Optionally implement a constructor and pass a name (label) and a label alignment
305 to the constructor mpFXY::mpFXY. If the layer name is empty, no label will be plotted.
307 class mpFXY : public mpLayer
310 /** @param name Label
311 @param flags Label alignment, pass one of #mpALIGN_NE, #mpALIGN_NW, #mpALIGN_SW, #mpALIGN_SE.
313 mpFXY(wxString name = wxEmptyString, int flags = mpALIGN_NE);
315 /** Rewind value enumeration with mpFXY::GetNextXY.
316 Override this function in your implementation.
318 virtual void Rewind() = 0;
320 /** Get locus value for next N.
321 Override this function in your implementation.
322 @param x Returns X value
323 @param y Returns Y value
325 virtual bool GetNextXY(double & x, double & y) = 0;
327 /** Layer plot handler.
328 This implementation will plot the locus in the visible area and
329 put a label according to the aligment specified.
331 virtual void Plot(wxDC & dc, mpWindow & w);
334 int m_flags; //!< Holds label alignment
341 //-----------------------------------------------------------------------------
342 // mpLayer implementations - furniture (scales, ...)
343 //-----------------------------------------------------------------------------
345 /** @name mpLayer implementations - furniture (scales, ...)
348 /** Plot layer implementing a x-scale ruler.
349 The ruler is fixed at Y=0 in the coordinate system. A label is plottet at
350 the bottom-right hand of the ruler. The scale numbering automatically
351 adjusts to view and zoom factor.
353 class mpScaleX : public mpLayer
356 /** @param name Label to plot by the ruler */
357 mpScaleX(wxString name = wxT("X"));
359 /** Layer plot handler.
360 This implementation will plot the ruler adjusted to the visible area.
362 virtual void Plot(wxDC & dc, mpWindow & w);
364 /** Check whether this layer has a bounding box.
365 This implementation returns \a FALSE thus making the ruler invisible
366 to the plot layer bounding box calculation by mpWindow.
368 virtual bool HasBBox() { return FALSE; }
370 DECLARE_CLASS(mpScaleX)
373 /** Plot layer implementing a y-scale ruler.
374 The ruler is fixed at X=0 in the coordinate system. A label is plottet at
375 the top-right hand of the ruler. The scale numbering automatically
376 adjusts to view and zoom factor.
378 class mpScaleY : public mpLayer
381 /** @param name Label to plot by the ruler */
382 mpScaleY(wxString name = wxT("Y"));
384 /** Layer plot handler.
385 This implementation will plot the ruler adjusted to the visible area.
387 virtual void Plot(wxDC & dc, mpWindow & w);
389 /** Check whether this layer has a bounding box.
390 This implementation returns \a FALSE thus making the ruler invisible
391 to the plot layer bounding box calculation by mpWindow.
393 virtual bool HasBBox() { return FALSE; }
397 DECLARE_CLASS(mpScaleY)
400 //-----------------------------------------------------------------------------
402 //-----------------------------------------------------------------------------
404 /** @name Constants defining mouse modes for mpWindow
407 /** Mouse panning drags the view. Mouse mode for mpWindow. */
408 #define mpMOUSEMODE_DRAG 0
409 /** Mouse panning creates a zoom box. Mouse mode for mpWindow. */
410 #define mpMOUSEMODE_ZOOMBOX 1
414 /** Canvas for plotting mpLayer implementations.
416 This class defines a zoomable and moveable 2D plot canvas. Any number
417 of mpLayer implementations (scale rulers, function plots, ...) can be
418 attached using mpWindow::AddLayer.
420 The canvas window provides a context menu with actions for navigating the view.
421 The context menu can be retrieved with mpWindow::GetPopupMenu, e.g. for extending it
424 class mpWindow : public wxScrolledWindow
428 mpWindow( wxWindow *parent, wxWindowID id,
429 const wxPoint &pos = wxDefaultPosition,
430 const wxSize &size = wxDefaultSize,
434 /** Get reference to context menu of the plot canvas.
435 @return Pointer to menu. The menu can be modified.
437 wxMenu* GetPopupMenu() { return &m_popmenu; }
439 //-----------------------
440 // new methods for plotter
441 //-----------------------
459 set the max value in the x axis
462 void setMaxScrX(int maxX)
467 set the max value in the y axis
470 void setMaxScrY(int maxY)
476 /**Get maximum value in x
483 /**Get maximum value in y
491 returns the zoomFactor
493 float getZoomFactor()
498 set the min value in the x axis
501 void setMinScrX(int minX)
506 set the min value in the y axis
509 void setMinScrY(int minY)
515 /**Get miniimum value in x
522 /**Get minimum value in y
531 Get the x-clicked by the user
540 Get the y-clicked by the user
549 Gets the x-offset of the zoom
552 int getOffsetPixelsX()
558 Gets the offset of the zoom
561 int getOffsetPixelsY()
566 Set the x-offset of the zoom
568 void setOffsetPixelX(int offX)
573 Set the y-offset of the zoom
575 void setOffsetPixelY(int offY)
581 Gets the x-offset of the zoom
589 Gets the offset of the zoom
596 Set the x-offset of the zoom
598 void setOffsetX(int offX)
603 Set the y-offset of the zoom
605 void setOffsetY(int offY)
611 * Sets real value of the y-coord for the vertical guide line
612 * @param newX_realGuide The new value to assing for the vertical guide
614 void setRealGuideX(int newX_realGuide)
616 real_guideLine_X = newX_realGuide;
617 if(real_guideLine_X!=-1)
622 * Gets the real value of the y-coord for the vertical guide line
623 * @retval real_guideLine_X The assigned value for the vertical guide
627 return real_guideLine_X;
631 * Sets real value of the y-coord for the vertical guide line
632 * @param newY_realGuide The new value to assing for the vertical guide
634 void setRealGuideY(int newY_realGuide)
636 real_guideLine_Y = newY_realGuide;
637 if(real_guideLine_Y!=-1)
642 * Gets the real value of the y-coord for the vertical guide line
643 * @retval real_guideLine_Y The assigned value for the vertical guide
647 return real_guideLine_Y;
651 * Sets the condition for drawing or not the guide lines
652 * @param ifDrawing The new condition to assing
654 /*void setLineGuidesCondition(bool ifDrawing)
656 drawGuides = ifDrawing;
660 * Gets the condition for drawing or not the guide lines
661 * @retval drawGuides The assigned condition
663 bool drawGuideLines();
666 * Guide lines menu handler method that reacts to the mpID_LINE_GUIDES cimmand event
667 * event The corresponding event to handle
670 //void OnGuideLines (wxCommandEvent &event);
672 //----------------------------------------------------------------------------------
674 //----------------------------------------------------------------------------------
677 /** Add a plot layer to the canvas.
678 @param layer Pointer to layer. The mpLayer object will get under control of mpWindow,
679 i.e. it will be delete'd on mpWindow destruction
681 @retval FALSE Failure due to out of memory.
683 bool AddLayer( mpLayer* layer);
685 /** Remove a plot layer from the canvas.
686 @param layer Pointer to layer. The mpLayer object will be destructed using delete.
688 void DelLayer( mpLayer* layer);
690 /** Get current view's X scale.
691 See @ref mpLayer::Plot "rules for coordinate transformation"
694 double GetScaleX(void) const { return m_scaleX; }
696 /** Get current view's Y scale.
697 See @ref mpLayer::Plot "rules for coordinate transformation"
700 double GetScaleY(void) const { return m_scaleY; }
702 /** Get current view's X position.
703 See @ref mpLayer::Plot "rules for coordinate transformation"
704 @return X Position in layer coordinate system, that corresponds to the center point of the view.
706 double GetPosX(void) const { return m_posX; }
708 /** Get current view's Y position.
709 See @ref mpLayer::Plot "rules for coordinate transformation"
710 @return Y Position in layer coordinate system, that corresponds to the center point of the view.
712 double GetPosY(void) const { return m_posY; }
714 /** Get current view's X dimension in device context units.
715 Usually this is equal to wxDC::GetSize, but it might differ thus mpLayer
716 implementations should rely on the value returned by the function.
717 See @ref mpLayer::Plot "rules for coordinate transformation"
720 int GetScrX(void) const { return m_scrX; }
722 /** Get current view's Y dimension in device context units.
723 Usually this is equal to wxDC::GetSize, but it might differ thus mpLayer
724 implementations should rely on the value returned by the function.
725 See @ref mpLayer::Plot "rules for coordinate transformation"
728 int GetScrY(void) const { return m_scrY; }
729 //void SetScrY(int x) const { return m_scrY; }
731 /** Set current view's X scale and refresh display.
732 @param scaleX New scale, must not be 0.
734 void SetScaleX(double scaleX) { if (scaleX!=0) m_scaleX=scaleX; /*UpdateAll();*/ }
736 /** Set current view's Y scale and refresh display.
737 @param scaleY New scale, must not be 0.
739 void SetScaleY(double scaleY) { if (scaleY!=0) m_scaleY=scaleY; /*UpdateAll();*/ }
741 /** Set current view's X position and refresh display.
742 @param posX New position that corresponds to the center point of the view.
744 void SetPosX(double posX) { m_posX=posX; UpdateAll(); }
746 /** Set current view's Y position and refresh display.
747 @param posY New position that corresponds to the center point of the view.
749 void SetPosY(double posY) { m_posY=posY; UpdateAll(); }
751 /** Set current view's X and Y position and refresh display.
752 @param posX New position that corresponds to the center point of the view.
753 @param posY New position that corresponds to the center point of the view.
755 void SetPos( double posX, double posY) { m_posX=posX; m_posY=posY; UpdateAll(); }
757 /** Enable or disable X/Y scale aspect locking for the view.
758 @note Explicit calls to mpWindow::SetScaleX and mpWindow::SetScaleY will set
759 an unlocked apect, but any other action changing the view scale will
760 lock the aspect again.
762 void LockAspect(bool enable = TRUE);
764 /** Checks whether the X/Y scale aspect is locked.
766 @retval FALSE Unlocked
768 inline bool IsAspectLocked() { return m_lockaspect; }
770 /** Set view to fit global bounding box of all plot layers and refresh display.
771 Scale and position will be set to a show all attached mpLayers.
772 The X/Y scale aspect lock is taken into account.
776 /** Zoom into current view and refresh display */
779 /** Zoom out current view and refresh display */
782 /** Refresh display */
787 void Refresh(bool eraseBackground = true, const wxRect* rect = NULL);
788 void OnPaint (wxPaintEvent &event); //!< Paint handler, will plot all attached layers
789 void OnSize (wxSizeEvent &event); //!< Size handler, will update scroll bar sizes
790 void OnScroll2 (wxScrollWinEvent &event); //!< Scroll handler, will move canvas
791 void OnShowPopupMenu (wxMouseEvent &event); //!< Mouse handler, will show context menu
792 void OnCenter (wxCommandEvent &event); //!< Context menu handler
793 void OnFit (wxCommandEvent &event); //!< Context menu handler
794 void OnZoomIn (wxCommandEvent &event); //!< Context menu handler
795 void OnZoomOut (wxCommandEvent &event); //!< Context menu handler
796 void OnLockAspect (wxCommandEvent &event); //!< Context menu handler
799 bool UpdateBBox(); //!< Recalculate global layer bounding box
801 wxList m_layers; //!< List of attached plot layers
802 wxMenu m_popmenu; //!< Canvas' context menu
803 bool m_lockaspect;//!< Scale aspect is locked or not
805 double m_minX; //!< Global layer bounding box, left border incl.
806 double m_maxX; //!< Global layer bounding box, right border incl.
807 double m_minY; //!< Global layer bounding box, bottom border incl.
808 double m_maxY; //!< Global layer bounding box, top border incl.
809 double m_scaleX; //!< Current view's X scale
810 double m_scaleY; //!< Current view's Y scale
811 double m_posX; //!< Current view's X position
812 double m_posY; //!< Current view's Y position
813 int m_scrX; //!< Current view's X dimension
814 int m_scrY; //!< Current view's Y dimension
815 int m_clickedX; //!< Last mouse click X position, for centering and zooming the view
816 int m_clickedY; //!< Last mouse click Y position, for centering and zooming the view
818 //----------------------------------------------
819 //NEW ATTRIBUTES FOR COMPATIBILITY WITH PPlotter
820 //----------------------------------------------
822 the max value in the x axis
827 the max value in the y axis
831 the min value in the x axis
836 the min value in the y axis
847 offset in pixels where the user has clicked
848 before changing the scale (in the actual function)
853 Offsets in real value according to the actual function
859 * The real value of the y-coord for the horizontal guide line
861 int real_guideLine_X;
863 * The real value of the y-coord for the vertical guide line
865 int real_guideLine_Y;
868 * Represents the condition for drawing or not the line guides, default color is red and assigned to draw them
872 Use to know which type of plotter is
879 //bitmap of functions
880 wxBitmap *_bitmap_functions;
883 DECLARE_CLASS(mpWindow)
884 DECLARE_EVENT_TABLE()
887 #endif // _MP_MATHPLOT_H_