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"
59 #include "wx/scrolwin.h"
61 #include "wx/dynarray.h"
64 //-----------------------------------------------------------------------------
66 //-----------------------------------------------------------------------------
76 /** Command IDs used by mpWindow */
79 mpID_FIT = 2000, //!< Fit view to match bounding box of all layers
80 mpID_ZOOM_IN, //!< Zoom into view at clickposition / window center
81 mpID_ZOOM_OUT, //!< Zoom out
82 mpID_CENTER, //!< Center view on click position
83 mpID_LOCKASPECT, //!< Lock x/y scaling aspect
84 mpID_LINE_GUIDES, //!< Enables or disables the line guides drawing condition
87 //-----------------------------------------------------------------------------
89 //-----------------------------------------------------------------------------
91 /** Plot layer, abstract base class.
92 Any number of mpLayer implementations can be attached to mpWindow.
93 Examples for mpLayer implementations are function graphs, or scale rulers.
95 For convenience mpLayer defines a name, a font (wxFont), and a pen (wxPen)
96 as class members. These may or may not be used by implementations.
98 class creaMaracasVisu_EXPORT mpLayer : public wxObject
103 /** Check whether this layer has a bounding box.
104 The default implementation returns \a TRUE. Overide and return
105 FALSE if your mpLayer implementation should be ignored by the calculation
106 of the global bounding box for all layers in a mpWindow.
107 @retval TRUE Has bounding box
108 @retval FALSE Has not bounding box
110 virtual bool HasBBox() { return TRUE; }
112 /** Get inclusive left border of bounding box.
115 virtual double GetMinX() { return -1.0; }
117 /** Get inclusive right border of bounding box.
120 virtual double GetMaxX() { return 1.0; }
122 /** Get inclusive bottom border of bounding box.
125 virtual double GetMinY() { return -1.0; }
127 /** Get inclusive top border of bounding box.
130 virtual double GetMaxY() { return 1.0; }
132 /** Plot given view of layer to the given device context.
133 An implementation of this function has to transform layer coordinates to
134 wxDC coordinates based on the view parameters retrievable from the mpWindow
135 passed in \a w. The passed device context \a dc has its coordinate origin set
136 to the center of the visible area. The coordinate orientation is as show in the
139 +--------------------------------------------------+
142 | (wxDC origin 0,0) |
143 | x-------------> acending X |
147 +--------------------------------------------------+
149 Note that Y ascends in downward direction, whereas the usual vertical orientation
150 for mathematical plots is vice versa. Thus Y-orientation will be swapped usually,
151 when transforming between wxDC and mpLayer coordinates.
153 <b> Rules for transformation between mpLayer and wxDC coordinates </b>
155 dc_X = (layer_X - mpWindow::GetPosX()) * mpWindow::GetScaleX()
156 dc_Y = (mpWindow::GetPosY() - layer_Y) * mpWindow::GetScaleY() // swapping Y-orientation
158 layer_X = (dc_X / mpWindow::GetScaleX()) + mpWindow::GetPosX() // scale guaranted to be not 0
159 layer_Y = mpWindow::GetPosY() - (dc_Y / mpWindow::GetScaleY()) // swapping Y-orientation
162 @param dc Device context to plot to.
163 @param w View to plot. The visible area can be retrieved from this object.
165 virtual void Plot(wxDC & dc, mpWindow & w) = 0;
170 wxString GetName() const { return m_name; }
172 /** Get font set for this layer.
175 const wxFont& GetFont() const { return m_font; }
177 /** Get pen set for this layer.
180 const wxPen& GetPen() const { return m_pen; }
183 @param name Name, will be copied to internal class member
185 void SetName(wxString name) { m_name = name; }
188 @param font Font, will be copied to internal class member
190 void SetFont(wxFont& font) { m_font = font; }
193 @param pen Pen, will be copied to internal class member
195 void SetPen(wxPen& pen) { m_pen = pen; }
198 ** Get the translation of the Y coordinate acoording to the new orientation of the axis du to the problem
199 ** identified in MACOS with the funtion 'SetAxisOrientation'
201 int GetYTranslated(double sizey, double y){
206 wxFont m_font; //!< Layer's font
207 wxPen m_pen; //!< Layer's pen
208 wxString m_name; //!< Layer's name
210 DECLARE_CLASS(mpLayer)
213 //-----------------------------------------------------------------------------
214 // mpLayer implementations - functions
215 //-----------------------------------------------------------------------------
217 /** @name Label alignment constants
221 #define mpALIGNMASK 0x03
222 /** Aligns label to the right. For use with mpFX. */
223 #define mpALIGN_RIGHT 0x00
224 /** Aligns label to the center. For use with mpFX and mpFY. */
225 #define mpALIGN_CENTER 0x01
226 /** Aligns label to the left. For use with mpFX. */
227 #define mpALIGN_LEFT 0x02
228 /** Aligns label to the top. For use with mpFY. */
229 #define mpALIGN_TOP mpALIGN_RIGHT
230 /** Aligns label to the bottom. For use with mpFY. */
231 #define mpALIGN_BOTTOM mpALIGN_LEFT
232 /** Aligns label to north-east. For use with mpFXY. */
233 #define mpALIGN_NE 0x00
234 /** Aligns label to north-west. For use with mpFXY. */
235 #define mpALIGN_NW 0x01
236 /** Aligns label to south-west. For use with mpFXY. */
237 #define mpALIGN_SW 0x02
238 /** Aligns label to south-east. For use with mpFXY. */
239 #define mpALIGN_SE 0x03
243 /** @name mpLayer implementations - functions
246 /** Abstract base class providing plot and labeling functionality for functions F:X->Y.
247 Override mpFX::GetY to implement a function.
248 Optionally implement a constructor and pass a name (label) and a label alignment
249 to the constructor mpFX::mpFX. If the layer name is empty, no label will be plotted.
251 class mpFX : public mpLayer
254 /** @param name Label
255 @param flags Label alignment, pass one of #mpALIGN_RIGHT, #mpALIGN_CENTER, #mpALIGN_LEFT.
257 mpFX(wxString name = wxEmptyString, int flags = mpALIGN_RIGHT);
259 /** Get function value for argument.
260 Override this function in your implementation.
262 @return Function value
264 virtual double GetY( double x ) = 0;
266 /** Layer plot handler.
267 This implementation will plot the function in the visible area and
268 put a label according to the aligment specified.
270 virtual void Plot(wxDC & dc, mpWindow & w);
273 int m_flags; //!< Holds label alignment
278 /** Abstract base class providing plot and labeling functionality for functions F:Y->X.
279 Override mpFY::GetX to implement a function.
280 Optionally implement a constructor and pass a name (label) and a label alignment
281 to the constructor mpFY::mpFY. If the layer name is empty, no label will be plotted.
283 class mpFY : public mpLayer
286 /** @param name Label
287 @param flags Label alignment, pass one of #mpALIGN_BOTTOM, #mpALIGN_CENTER, #mpALIGN_TOP.
289 mpFY(wxString name = wxEmptyString, int flags = mpALIGN_TOP);
291 /** Get function value for argument.
292 Override this function in your implementation.
294 @return Function value
296 virtual double GetX( double y ) = 0;
298 /** Layer plot handler.
299 This implementation will plot the function in the visible area and
300 put a label according to the aligment specified.
302 virtual void Plot(wxDC & dc, mpWindow & w);
305 int m_flags; //!< Holds label alignment
310 /** Abstract base class providing plot and labeling functionality for a locus plot F:N->X,Y.
311 Locus argument N is assumed to be in range 0 .. MAX_N, and implicitely derived by enumrating
312 all locus values. Override mpFXY::Rewind and mpFXY::GetNextXY to implement a locus.
313 Optionally implement a constructor and pass a name (label) and a label alignment
314 to the constructor mpFXY::mpFXY. If the layer name is empty, no label will be plotted.
316 class mpFXY : public mpLayer
319 /** @param name Label
320 @param flags Label alignment, pass one of #mpALIGN_NE, #mpALIGN_NW, #mpALIGN_SW, #mpALIGN_SE.
322 mpFXY(wxString name = wxEmptyString, int flags = mpALIGN_NE);
324 /** Rewind value enumeration with mpFXY::GetNextXY.
325 Override this function in your implementation.
327 virtual void Rewind() = 0;
329 /** Get locus value for next N.
330 Override this function in your implementation.
331 @param x Returns X value
332 @param y Returns Y value
334 virtual bool GetNextXY(double & x, double & y) = 0;
336 /** Layer plot handler.
337 This implementation will plot the locus in the visible area and
338 put a label according to the aligment specified.
340 virtual void Plot(wxDC & dc, mpWindow & w);
343 int m_flags; //!< Holds label alignment
350 //-----------------------------------------------------------------------------
351 // mpLayer implementations - furniture (scales, ...)
352 //-----------------------------------------------------------------------------
354 /** @name mpLayer implementations - furniture (scales, ...)
357 /** Plot layer implementing a x-scale ruler.
358 The ruler is fixed at Y=0 in the coordinate system. A label is plottet at
359 the bottom-right hand of the ruler. The scale numbering automatically
360 adjusts to view and zoom factor.
362 class mpScaleX : public mpLayer
365 /** @param name Label to plot by the ruler */
366 mpScaleX(wxString name = wxT("X"));
368 /** Layer plot handler.
369 This implementation will plot the ruler adjusted to the visible area.
371 virtual void Plot(wxDC & dc, mpWindow & w);
373 /** Check whether this layer has a bounding box.
374 This implementation returns \a FALSE thus making the ruler invisible
375 to the plot layer bounding box calculation by mpWindow.
377 virtual bool HasBBox() { return FALSE; }
379 DECLARE_CLASS(mpScaleX)
382 /** Plot layer implementing a y-scale ruler.
383 The ruler is fixed at X=0 in the coordinate system. A label is plottet at
384 the top-right hand of the ruler. The scale numbering automatically
385 adjusts to view and zoom factor.
387 class mpScaleY : public mpLayer
390 /** @param name Label to plot by the ruler */
391 mpScaleY(wxString name = wxT("Y"));
393 /** Layer plot handler.
394 This implementation will plot the ruler adjusted to the visible area.
396 virtual void Plot(wxDC & dc, mpWindow & w, int orgy);
398 /** Check whether this layer has a bounding box.
399 This implementation returns \a FALSE thus making the ruler invisible
400 to the plot layer bounding box calculation by mpWindow.
402 virtual bool HasBBox() { return FALSE; }
406 DECLARE_CLASS(mpScaleY)
409 //-----------------------------------------------------------------------------
411 //-----------------------------------------------------------------------------
413 /** @name Constants defining mouse modes for mpWindow
416 /** Mouse panning drags the view. Mouse mode for mpWindow. */
417 #define mpMOUSEMODE_DRAG 0
418 /** Mouse panning creates a zoom box. Mouse mode for mpWindow. */
419 #define mpMOUSEMODE_ZOOMBOX 1
423 /** Canvas for plotting mpLayer implementations.
425 This class defines a zoomable and moveable 2D plot canvas. Any number
426 of mpLayer implementations (scale rulers, function plots, ...) can be
427 attached using mpWindow::AddLayer.
429 The canvas window provides a context menu with actions for navigating the view.
430 The context menu can be retrieved with mpWindow::GetPopupMenu, e.g. for extending it
433 class creaMaracasVisu_EXPORT mpWindow : public wxScrolledWindow
437 mpWindow( wxWindow *parent, wxWindowID id,
438 const wxPoint &pos = wxDefaultPosition,
439 const wxSize &size = wxDefaultSize,
443 /** Get reference to context menu of the plot canvas.
444 @return Pointer to menu. The menu can be modified.
446 wxMenu* GetPopupMenu() { return &m_popmenu; }
448 //-----------------------
449 // new methods for plotter
450 //-----------------------
468 set the max value in the x axis
471 void setMaxScrX(int maxX)
476 set the max value in the y axis
479 void setMaxScrY(int maxY)
485 /**Get maximum value in x
492 /**Get maximum value in y
500 returns the zoomFactor
502 float getZoomFactor()
507 set the min value in the x axis
510 void setMinScrX(int minX)
515 set the min value in the y axis
518 void setMinScrY(int minY)
524 /**Get miniimum value in x
531 /**Get minimum value in y
540 Get the x-clicked by the user
549 Get the y-clicked by the user
558 Gets the x-offset of the zoom
561 int getOffsetPixelsX()
567 Gets the offset of the zoom
570 int getOffsetPixelsY()
575 Set the x-offset of the zoom
577 void setOffsetPixelX(int offX)
582 Set the y-offset of the zoom
584 void setOffsetPixelY(int offY)
590 Gets the x-offset of the zoom
598 Gets the offset of the zoom
605 Set the x-offset of the zoom
607 void setOffsetX(int offX)
612 Set the y-offset of the zoom
614 void setOffsetY(int offY)
620 * Sets real value of the y-coord for the vertical guide line
621 * @param newX_realGuide The new value to assing for the vertical guide
623 void setRealGuideX(int newX_realGuide)
625 real_guideLine_X = newX_realGuide;
626 if(real_guideLine_X!=-1)
631 * Gets the real value of the y-coord for the vertical guide line
632 * @retval real_guideLine_X The assigned value for the vertical guide
636 return real_guideLine_X;
640 * Sets real value of the y-coord for the vertical guide line
641 * @param newY_realGuide The new value to assing for the vertical guide
643 void setRealGuideY(int newY_realGuide)
645 real_guideLine_Y = newY_realGuide;
646 if(real_guideLine_Y!=-1)
651 * Gets the real value of the y-coord for the vertical guide line
652 * @retval real_guideLine_Y The assigned value for the vertical guide
656 return real_guideLine_Y;
660 * Sets the condition for drawing or not the guide lines
661 * @param ifDrawing The new condition to assing
663 /*void setLineGuidesCondition(bool ifDrawing)
665 drawGuides = ifDrawing;
670 * Gets the condition for drawing or not the guide lines
671 * @retval drawGuides The assigned condition
673 bool drawGuideLines();
676 * Guide lines menu handler method that reacts to the mpID_LINE_GUIDES cimmand event
677 * event The corresponding event to handle
680 //void OnGuideLines (wxCommandEvent &event);
682 //----------------------------------------------------------------------------------
684 //----------------------------------------------------------------------------------
687 /** Add a plot layer to the canvas.
688 @param layer Pointer to layer. The mpLayer object will get under control of mpWindow,
689 i.e. it will be delete'd on mpWindow destruction
691 @retval FALSE Failure due to out of memory.
693 bool AddLayer( mpLayer* layer);
695 /** Remove a plot layer from the canvas.
696 @param layer Pointer to layer. The mpLayer object will be destructed using delete.
698 void DelLayer( mpLayer* layer);
700 /** Get current view's X scale.
701 See @ref mpLayer::Plot "rules for coordinate transformation"
704 double GetScaleX(void) const { return m_scaleX; }
706 /** Get current view's Y scale.
707 See @ref mpLayer::Plot "rules for coordinate transformation"
710 double GetScaleY(void) const { return m_scaleY; }
712 /** Get current view's X position.
713 See @ref mpLayer::Plot "rules for coordinate transformation"
714 @return X Position in layer coordinate system, that corresponds to the center point of the view.
716 double GetPosX(void) const { return m_posX; }
718 /** Get current view's Y position.
719 See @ref mpLayer::Plot "rules for coordinate transformation"
720 @return Y Position in layer coordinate system, that corresponds to the center point of the view.
722 double GetPosY(void) const { return m_posY; }
724 /** Get current view's X dimension in device context units.
725 Usually this is equal to wxDC::GetSize, but it might differ thus mpLayer
726 implementations should rely on the value returned by the function.
727 See @ref mpLayer::Plot "rules for coordinate transformation"
730 int GetScrX(void) const { return m_scrX; }
732 /** Get current view's Y dimension in device context units.
733 Usually this is equal to wxDC::GetSize, but it might differ thus mpLayer
734 implementations should rely on the value returned by the function.
735 See @ref mpLayer::Plot "rules for coordinate transformation"
738 int GetScrY(void) const { return m_scrY; }
739 //void SetScrY(int x) const { return m_scrY; }
741 /** Set current view's X scale and refresh display.
742 @param scaleX New scale, must not be 0.
744 void SetScaleX(double scaleX) { if (scaleX!=0) m_scaleX=scaleX; /*UpdateAll();*/ }
746 /** Set current view's Y scale and refresh display.
747 @param scaleY New scale, must not be 0.
749 void SetScaleY(double scaleY) { if (scaleY!=0) m_scaleY=scaleY; /*UpdateAll();*/ }
751 /** Set current view's X position and refresh display.
752 @param posX New position that corresponds to the center point of the view.
754 void SetPosX(double posX) { m_posX=posX; UpdateAll(); }
756 /** Set current view's Y position and refresh display.
757 @param posY New position that corresponds to the center point of the view.
759 void SetPosY(double posY) { m_posY=posY; UpdateAll(); }
761 /** Set current view's X and Y position and refresh display.
762 @param posX New position that corresponds to the center point of the view.
763 @param posY New position that corresponds to the center point of the view.
765 void SetPos( double posX, double posY) { m_posX=posX; m_posY=posY; UpdateAll(); }
767 /** Enable or disable X/Y scale aspect locking for the view.
768 @note Explicit calls to mpWindow::SetScaleX and mpWindow::SetScaleY will set
769 an unlocked apect, but any other action changing the view scale will
770 lock the aspect again.
772 void LockAspect(bool enable = TRUE);
774 /** Checks whether the X/Y scale aspect is locked.
776 @retval FALSE Unlocked
778 inline bool IsAspectLocked() { return m_lockaspect; }
780 /** Set view to fit global bounding box of all plot layers and refresh display.
781 Scale and position will be set to a show all attached mpLayers.
782 The X/Y scale aspect lock is taken into account.
786 /** Zoom into current view and refresh display */
789 /** Zoom out current view and refresh display */
792 /** Refresh display */
796 ** Get the translation of the Y coordinate
798 int GetYTranslated(wxSize size, double y){
799 return size.GetHeight()-y;
804 void Refresh(bool eraseBackground = true, const wxRect* rect = NULL);
805 void OnPaint (wxPaintEvent &event); //!< Paint handler, will plot all attached layers
806 void OnSize (wxSizeEvent &event); //!< Size handler, will update scroll bar sizes
807 void OnScroll2 (wxScrollWinEvent &event); //!< Scroll handler, will move canvas
808 void OnShowPopupMenu (wxMouseEvent &event); //!< Mouse handler, will show context menu
809 void OnCenter (wxCommandEvent &event); //!< Context menu handler
810 void OnFit (wxCommandEvent &event); //!< Context menu handler
811 void OnZoomIn (wxCommandEvent &event); //!< Context menu handler
812 void OnZoomOut (wxCommandEvent &event); //!< Context menu handler
813 void OnLockAspect (wxCommandEvent &event); //!< Context menu handler
816 bool UpdateBBox(); //!< Recalculate global layer bounding box
818 wxList m_layers; //!< List of attached plot layers
819 wxMenu m_popmenu; //!< Canvas' context menu
820 bool m_lockaspect;//!< Scale aspect is locked or not
822 double m_minX; //!< Global layer bounding box, left border incl.
823 double m_maxX; //!< Global layer bounding box, right border incl.
824 double m_minY; //!< Global layer bounding box, bottom border incl.
825 double m_maxY; //!< Global layer bounding box, top border incl.
826 double m_scaleX; //!< Current view's X scale
827 double m_scaleY; //!< Current view's Y scale
828 double m_posX; //!< Current view's X position
829 double m_posY; //!< Current view's Y position
830 int m_scrX; //!< Current view's X dimension
831 int m_scrY; //!< Current view's Y dimension
832 int m_clickedX; //!< Last mouse click X position, for centering and zooming the view
833 int m_clickedY; //!< Last mouse click Y position, for centering and zooming the view
835 //----------------------------------------------
836 //NEW ATTRIBUTES FOR COMPATIBILITY WITH PPlotter
837 //----------------------------------------------
839 the max value in the x axis
844 the max value in the y axis
848 the min value in the x axis
853 the min value in the y axis
864 offset in pixels where the user has clicked
865 before changing the scale (in the actual function)
870 Offsets in real value according to the actual function
876 * The real value of the y-coord for the horizontal guide line
878 int real_guideLine_X;
880 * The real value of the y-coord for the vertical guide line
882 int real_guideLine_Y;
885 * Represents the condition for drawing or not the line guides, default color is red and assigned to draw them
889 Use to know which type of plotter is
896 //bitmap of functions
897 wxBitmap *_bitmap_functions;
900 DECLARE_CLASS(mpWindow)
901 DECLARE_EVENT_TABLE()
904 #endif // _MP_MATHPLOT_H_