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