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 wxFont m_font; //!< Layer's font
199 wxPen m_pen; //!< Layer's pen
200 wxString m_name; //!< Layer's name
202 DECLARE_CLASS(mpLayer)
205 //-----------------------------------------------------------------------------
206 // mpLayer implementations - functions
207 //-----------------------------------------------------------------------------
209 /** @name Label alignment constants
213 #define mpALIGNMASK 0x03
214 /** Aligns label to the right. For use with mpFX. */
215 #define mpALIGN_RIGHT 0x00
216 /** Aligns label to the center. For use with mpFX and mpFY. */
217 #define mpALIGN_CENTER 0x01
218 /** Aligns label to the left. For use with mpFX. */
219 #define mpALIGN_LEFT 0x02
220 /** Aligns label to the top. For use with mpFY. */
221 #define mpALIGN_TOP mpALIGN_RIGHT
222 /** Aligns label to the bottom. For use with mpFY. */
223 #define mpALIGN_BOTTOM mpALIGN_LEFT
224 /** Aligns label to north-east. For use with mpFXY. */
225 #define mpALIGN_NE 0x00
226 /** Aligns label to north-west. For use with mpFXY. */
227 #define mpALIGN_NW 0x01
228 /** Aligns label to south-west. For use with mpFXY. */
229 #define mpALIGN_SW 0x02
230 /** Aligns label to south-east. For use with mpFXY. */
231 #define mpALIGN_SE 0x03
235 /** @name mpLayer implementations - functions
238 /** Abstract base class providing plot and labeling functionality for functions F:X->Y.
239 Override mpFX::GetY to implement a function.
240 Optionally implement a constructor and pass a name (label) and a label alignment
241 to the constructor mpFX::mpFX. If the layer name is empty, no label will be plotted.
243 class mpFX : public mpLayer
246 /** @param name Label
247 @param flags Label alignment, pass one of #mpALIGN_RIGHT, #mpALIGN_CENTER, #mpALIGN_LEFT.
249 mpFX(wxString name = wxEmptyString, int flags = mpALIGN_RIGHT);
251 /** Get function value for argument.
252 Override this function in your implementation.
254 @return Function value
256 virtual double GetY( double x ) = 0;
258 /** Layer plot handler.
259 This implementation will plot the function in the visible area and
260 put a label according to the aligment specified.
262 virtual void Plot(wxDC & dc, mpWindow & w);
265 int m_flags; //!< Holds label alignment
270 /** Abstract base class providing plot and labeling functionality for functions F:Y->X.
271 Override mpFY::GetX to implement a function.
272 Optionally implement a constructor and pass a name (label) and a label alignment
273 to the constructor mpFY::mpFY. If the layer name is empty, no label will be plotted.
275 class mpFY : public mpLayer
278 /** @param name Label
279 @param flags Label alignment, pass one of #mpALIGN_BOTTOM, #mpALIGN_CENTER, #mpALIGN_TOP.
281 mpFY(wxString name = wxEmptyString, int flags = mpALIGN_TOP);
283 /** Get function value for argument.
284 Override this function in your implementation.
286 @return Function value
288 virtual double GetX( double y ) = 0;
290 /** Layer plot handler.
291 This implementation will plot the function in the visible area and
292 put a label according to the aligment specified.
294 virtual void Plot(wxDC & dc, mpWindow & w);
297 int m_flags; //!< Holds label alignment
302 /** Abstract base class providing plot and labeling functionality for a locus plot F:N->X,Y.
303 Locus argument N is assumed to be in range 0 .. MAX_N, and implicitely derived by enumrating
304 all locus values. Override mpFXY::Rewind and mpFXY::GetNextXY to implement a locus.
305 Optionally implement a constructor and pass a name (label) and a label alignment
306 to the constructor mpFXY::mpFXY. If the layer name is empty, no label will be plotted.
308 class mpFXY : public mpLayer
311 /** @param name Label
312 @param flags Label alignment, pass one of #mpALIGN_NE, #mpALIGN_NW, #mpALIGN_SW, #mpALIGN_SE.
314 mpFXY(wxString name = wxEmptyString, int flags = mpALIGN_NE);
316 /** Rewind value enumeration with mpFXY::GetNextXY.
317 Override this function in your implementation.
319 virtual void Rewind() = 0;
321 /** Get locus value for next N.
322 Override this function in your implementation.
323 @param x Returns X value
324 @param y Returns Y value
326 virtual bool GetNextXY(double & x, double & y) = 0;
328 /** Layer plot handler.
329 This implementation will plot the locus in the visible area and
330 put a label according to the aligment specified.
332 virtual void Plot(wxDC & dc, mpWindow & w);
335 int m_flags; //!< Holds label alignment
342 //-----------------------------------------------------------------------------
343 // mpLayer implementations - furniture (scales, ...)
344 //-----------------------------------------------------------------------------
346 /** @name mpLayer implementations - furniture (scales, ...)
349 /** Plot layer implementing a x-scale ruler.
350 The ruler is fixed at Y=0 in the coordinate system. A label is plottet at
351 the bottom-right hand of the ruler. The scale numbering automatically
352 adjusts to view and zoom factor.
354 class mpScaleX : public mpLayer
357 /** @param name Label to plot by the ruler */
358 mpScaleX(wxString name = wxT("X"));
360 /** Layer plot handler.
361 This implementation will plot the ruler adjusted to the visible area.
363 virtual void Plot(wxDC & dc, mpWindow & w);
365 /** Check whether this layer has a bounding box.
366 This implementation returns \a FALSE thus making the ruler invisible
367 to the plot layer bounding box calculation by mpWindow.
369 virtual bool HasBBox() { return FALSE; }
371 DECLARE_CLASS(mpScaleX)
374 /** Plot layer implementing a y-scale ruler.
375 The ruler is fixed at X=0 in the coordinate system. A label is plottet at
376 the top-right hand of the ruler. The scale numbering automatically
377 adjusts to view and zoom factor.
379 class mpScaleY : public mpLayer
382 /** @param name Label to plot by the ruler */
383 mpScaleY(wxString name = wxT("Y"));
385 /** Layer plot handler.
386 This implementation will plot the ruler adjusted to the visible area.
388 virtual void Plot(wxDC & dc, mpWindow & w);
390 /** Check whether this layer has a bounding box.
391 This implementation returns \a FALSE thus making the ruler invisible
392 to the plot layer bounding box calculation by mpWindow.
394 virtual bool HasBBox() { return FALSE; }
398 DECLARE_CLASS(mpScaleY)
401 //-----------------------------------------------------------------------------
403 //-----------------------------------------------------------------------------
405 /** @name Constants defining mouse modes for mpWindow
408 /** Mouse panning drags the view. Mouse mode for mpWindow. */
409 #define mpMOUSEMODE_DRAG 0
410 /** Mouse panning creates a zoom box. Mouse mode for mpWindow. */
411 #define mpMOUSEMODE_ZOOMBOX 1
415 /** Canvas for plotting mpLayer implementations.
417 This class defines a zoomable and moveable 2D plot canvas. Any number
418 of mpLayer implementations (scale rulers, function plots, ...) can be
419 attached using mpWindow::AddLayer.
421 The canvas window provides a context menu with actions for navigating the view.
422 The context menu can be retrieved with mpWindow::GetPopupMenu, e.g. for extending it
425 class creaMaracasVisu_EXPORT mpWindow : public wxScrolledWindow
429 mpWindow( wxWindow *parent, wxWindowID id,
430 const wxPoint &pos = wxDefaultPosition,
431 const wxSize &size = wxDefaultSize,
435 /** Get reference to context menu of the plot canvas.
436 @return Pointer to menu. The menu can be modified.
438 wxMenu* GetPopupMenu() { return &m_popmenu; }
440 //-----------------------
441 // new methods for plotter
442 //-----------------------
460 set the max value in the x axis
463 void setMaxScrX(int maxX)
468 set the max value in the y axis
471 void setMaxScrY(int maxY)
477 /**Get maximum value in x
484 /**Get maximum value in y
492 returns the zoomFactor
494 float getZoomFactor()
499 set the min value in the x axis
502 void setMinScrX(int minX)
507 set the min value in the y axis
510 void setMinScrY(int minY)
516 /**Get miniimum value in x
523 /**Get minimum value in y
532 Get the x-clicked by the user
541 Get the y-clicked by the user
550 Gets the x-offset of the zoom
553 int getOffsetPixelsX()
559 Gets the offset of the zoom
562 int getOffsetPixelsY()
567 Set the x-offset of the zoom
569 void setOffsetPixelX(int offX)
574 Set the y-offset of the zoom
576 void setOffsetPixelY(int offY)
582 Gets the x-offset of the zoom
590 Gets the offset of the zoom
597 Set the x-offset of the zoom
599 void setOffsetX(int offX)
604 Set the y-offset of the zoom
606 void setOffsetY(int offY)
612 * Sets real value of the y-coord for the vertical guide line
613 * @param newX_realGuide The new value to assing for the vertical guide
615 void setRealGuideX(int newX_realGuide)
617 real_guideLine_X = newX_realGuide;
618 if(real_guideLine_X!=-1)
623 * Gets the real value of the y-coord for the vertical guide line
624 * @retval real_guideLine_X The assigned value for the vertical guide
628 return real_guideLine_X;
632 * Sets real value of the y-coord for the vertical guide line
633 * @param newY_realGuide The new value to assing for the vertical guide
635 void setRealGuideY(int newY_realGuide)
637 real_guideLine_Y = newY_realGuide;
638 if(real_guideLine_Y!=-1)
643 * Gets the real value of the y-coord for the vertical guide line
644 * @retval real_guideLine_Y The assigned value for the vertical guide
648 return real_guideLine_Y;
652 * Sets the condition for drawing or not the guide lines
653 * @param ifDrawing The new condition to assing
655 /*void setLineGuidesCondition(bool ifDrawing)
657 drawGuides = ifDrawing;
662 * Gets the condition for drawing or not the guide lines
663 * @retval drawGuides The assigned condition
665 bool drawGuideLines();
668 * Guide lines menu handler method that reacts to the mpID_LINE_GUIDES cimmand event
669 * event The corresponding event to handle
672 //void OnGuideLines (wxCommandEvent &event);
674 //----------------------------------------------------------------------------------
676 //----------------------------------------------------------------------------------
679 /** Add a plot layer to the canvas.
680 @param layer Pointer to layer. The mpLayer object will get under control of mpWindow,
681 i.e. it will be delete'd on mpWindow destruction
683 @retval FALSE Failure due to out of memory.
685 bool AddLayer( mpLayer* layer);
687 /** Remove a plot layer from the canvas.
688 @param layer Pointer to layer. The mpLayer object will be destructed using delete.
690 void DelLayer( mpLayer* layer);
692 /** Get current view's X scale.
693 See @ref mpLayer::Plot "rules for coordinate transformation"
696 double GetScaleX(void) const { return m_scaleX; }
698 /** Get current view's Y scale.
699 See @ref mpLayer::Plot "rules for coordinate transformation"
702 double GetScaleY(void) const { return m_scaleY; }
704 /** Get current view's X position.
705 See @ref mpLayer::Plot "rules for coordinate transformation"
706 @return X Position in layer coordinate system, that corresponds to the center point of the view.
708 double GetPosX(void) const { return m_posX; }
710 /** Get current view's Y position.
711 See @ref mpLayer::Plot "rules for coordinate transformation"
712 @return Y Position in layer coordinate system, that corresponds to the center point of the view.
714 double GetPosY(void) const { return m_posY; }
716 /** Get current view's X dimension in device context units.
717 Usually this is equal to wxDC::GetSize, but it might differ thus mpLayer
718 implementations should rely on the value returned by the function.
719 See @ref mpLayer::Plot "rules for coordinate transformation"
722 int GetScrX(void) const { return m_scrX; }
724 /** Get current view's Y 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 GetScrY(void) const { return m_scrY; }
731 //void SetScrY(int x) const { return m_scrY; }
733 /** Set current view's X scale and refresh display.
734 @param scaleX New scale, must not be 0.
736 void SetScaleX(double scaleX) { if (scaleX!=0) m_scaleX=scaleX; /*UpdateAll();*/ }
738 /** Set current view's Y scale and refresh display.
739 @param scaleY New scale, must not be 0.
741 void SetScaleY(double scaleY) { if (scaleY!=0) m_scaleY=scaleY; /*UpdateAll();*/ }
743 /** Set current view's X position and refresh display.
744 @param posX New position that corresponds to the center point of the view.
746 void SetPosX(double posX) { m_posX=posX; UpdateAll(); }
748 /** Set current view's Y position and refresh display.
749 @param posY New position that corresponds to the center point of the view.
751 void SetPosY(double posY) { m_posY=posY; UpdateAll(); }
753 /** Set current view's X and Y position and refresh display.
754 @param posX New position that corresponds to the center point of the view.
755 @param posY New position that corresponds to the center point of the view.
757 void SetPos( double posX, double posY) { m_posX=posX; m_posY=posY; UpdateAll(); }
759 /** Enable or disable X/Y scale aspect locking for the view.
760 @note Explicit calls to mpWindow::SetScaleX and mpWindow::SetScaleY will set
761 an unlocked apect, but any other action changing the view scale will
762 lock the aspect again.
764 void LockAspect(bool enable = TRUE);
766 /** Checks whether the X/Y scale aspect is locked.
768 @retval FALSE Unlocked
770 inline bool IsAspectLocked() { return m_lockaspect; }
772 /** Set view to fit global bounding box of all plot layers and refresh display.
773 Scale and position will be set to a show all attached mpLayers.
774 The X/Y scale aspect lock is taken into account.
778 /** Zoom into current view and refresh display */
781 /** Zoom out current view and refresh display */
784 /** Refresh display */
789 void Refresh(bool eraseBackground = true, const wxRect* rect = NULL);
790 void OnPaint (wxPaintEvent &event); //!< Paint handler, will plot all attached layers
791 void OnSize (wxSizeEvent &event); //!< Size handler, will update scroll bar sizes
792 void OnScroll2 (wxScrollWinEvent &event); //!< Scroll handler, will move canvas
793 void OnShowPopupMenu (wxMouseEvent &event); //!< Mouse handler, will show context menu
794 void OnCenter (wxCommandEvent &event); //!< Context menu handler
795 void OnFit (wxCommandEvent &event); //!< Context menu handler
796 void OnZoomIn (wxCommandEvent &event); //!< Context menu handler
797 void OnZoomOut (wxCommandEvent &event); //!< Context menu handler
798 void OnLockAspect (wxCommandEvent &event); //!< Context menu handler
801 bool UpdateBBox(); //!< Recalculate global layer bounding box
803 wxList m_layers; //!< List of attached plot layers
804 wxMenu m_popmenu; //!< Canvas' context menu
805 bool m_lockaspect;//!< Scale aspect is locked or not
807 double m_minX; //!< Global layer bounding box, left border incl.
808 double m_maxX; //!< Global layer bounding box, right border incl.
809 double m_minY; //!< Global layer bounding box, bottom border incl.
810 double m_maxY; //!< Global layer bounding box, top border incl.
811 double m_scaleX; //!< Current view's X scale
812 double m_scaleY; //!< Current view's Y scale
813 double m_posX; //!< Current view's X position
814 double m_posY; //!< Current view's Y position
815 int m_scrX; //!< Current view's X dimension
816 int m_scrY; //!< Current view's Y dimension
817 int m_clickedX; //!< Last mouse click X position, for centering and zooming the view
818 int m_clickedY; //!< Last mouse click Y position, for centering and zooming the view
820 //----------------------------------------------
821 //NEW ATTRIBUTES FOR COMPATIBILITY WITH PPlotter
822 //----------------------------------------------
824 the max value in the x axis
829 the max value in the y axis
833 the min value in the x axis
838 the min value in the y axis
849 offset in pixels where the user has clicked
850 before changing the scale (in the actual function)
855 Offsets in real value according to the actual function
861 * The real value of the y-coord for the horizontal guide line
863 int real_guideLine_X;
865 * The real value of the y-coord for the vertical guide line
867 int real_guideLine_Y;
870 * Represents the condition for drawing or not the line guides, default color is red and assigned to draw them
874 Use to know which type of plotter is
881 //bitmap of functions
882 wxBitmap *_bitmap_functions;
885 DECLARE_CLASS(mpWindow)
886 DECLARE_EVENT_TABLE()
889 #endif // _MP_MATHPLOT_H_