2018-11-25 21:53:26 +08:00
/*
2020-08-26 18:58:23 +08:00
Copyright ( c ) 2008 - 2020 Jan W . Krieger ( < jan @ jkrieger . de > )
2018-11-25 21:53:26 +08:00
This software is free software : you can redistribute it and / or modify
it under the terms of the GNU Lesser General Public License ( LGPL ) as published by
2019-02-08 00:24:46 +08:00
the Free Software Foundation , either version 2.1 of the License , or
2018-11-25 21:53:26 +08:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Lesser General Public License ( LGPL ) for more details .
You should have received a copy of the GNU Lesser General Public License ( LGPL )
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <QString>
# include <QPainter>
# include <QPair>
2018-12-28 05:52:00 +08:00
# include "jkqtplotter/jkqtpbaseelements.h"
# include "jkqtplotter/jkqtpbaseplotter.h"
2019-05-30 04:40:02 +08:00
# include "jkqtplotter/jkqtptools.h"
2019-06-22 20:21:32 +08:00
# include "jkqtplotter/jkqtplotter_imexport.h"
2019-05-30 04:40:02 +08:00
# include "jkqtplotter/jkqtpimagetools.h"
2018-11-25 21:53:26 +08:00
2019-02-08 00:24:46 +08:00
# ifndef JKQTPGRAPHSBASE_H
# define JKQTPGRAPHSBASE_H
2018-11-25 21:53:26 +08:00
// forward declarations
2019-01-20 23:15:10 +08:00
class JKQTPlotter ;
2019-01-20 17:49:29 +08:00
class JKQTPDatastore ;
2019-05-06 01:31:20 +08:00
class JKQTPGraphErrorStyleMixin ;
2018-11-25 21:53:26 +08:00
2019-01-20 23:15:10 +08:00
/** \brief this virtual base class of every element, which is part of a JKQTPlotter plot and may appear in its key
2018-12-28 05:52:00 +08:00
* ( basically any type of graph , except overlay elements ! )
2019-01-13 01:53:16 +08:00
* \ ingroup jkqtplotter_basegraphs
2018-11-25 21:53:26 +08:00
*
2018-12-28 05:52:00 +08:00
* Each possible graph is represented by a child of this class . So additional plots may be created by
2019-01-20 17:49:29 +08:00
* deriving new JKQTPGraph classes . To do so implement / overwrite these functions :
2018-11-25 21:53:26 +08:00
* - void draw ( JKQTPEnhancedPainter & painter ) ;
* - void drawKeyMarker ( JKQTPEnhancedPainter & painter , QRectF & rect ) ;
* - bool getXMinMax ( double & minx , double & maxx , double & smallestGreaterZero ) ;
2019-02-03 21:04:48 +08:00
* - bool getYMinMax ( double & miny , double & maxy , double & smallestGreaterZero ) ;
2019-04-22 19:27:50 +08:00
* - QColor getKeyLabelColor ( ) const = 0 ;
2019-02-03 21:04:48 +08:00
* .
2018-12-28 05:52:00 +08:00
*
* Optionally you may also overwrite these functions to draw elements outside the actual plot area ( like e . g . colorbars ) :
* - void getOutsideSize ( JKQTPEnhancedPainter & painter , int & leftSpace , int & rightSpace , int & topSpace , int & bottomSpace ) ;
* - void drawOutside ( JKQTPEnhancedPainter & painter , QRect leftSpace , QRect rightSpace , QRect topSpace , QRect bottomSpace ) ;
2018-11-25 21:53:26 +08:00
* .
*
2019-02-03 21:04:48 +08:00
* In addition this class provudes protected
* functions that do coordinate transforms based on the current coordinate system , of the paren
* JKQTPlotter ( i . e . using the axes JKQTPLott : xAxis and JKQTPlotter : : yAxis as basis for the plotting ) .
*
* \ see \ ref jkqtplotter_graphsgroup_classstructure
2018-11-25 21:53:26 +08:00
*/
2019-06-22 20:21:32 +08:00
class JKQTPLOTTER_LIB_EXPORT JKQTPPlotElement : public QObject {
2018-11-25 21:53:26 +08:00
Q_OBJECT
public :
2019-05-06 01:31:20 +08:00
2018-11-25 21:53:26 +08:00
/** \brief class constructor */
2019-01-20 17:49:29 +08:00
explicit JKQTPPlotElement ( JKQTBasePlotter * parent = nullptr ) ;
2018-11-25 21:53:26 +08:00
/** \brief default wirtual destructor */
2019-02-03 21:04:48 +08:00
virtual ~ JKQTPPlotElement ( ) = default ;
2018-11-25 21:53:26 +08:00
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw ( JKQTPEnhancedPainter & painter ) = 0 ;
2018-12-28 05:52:00 +08:00
2018-11-25 21:53:26 +08:00
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker ( JKQTPEnhancedPainter & painter , QRectF & rect ) = 0 ;
2018-12-28 05:52:00 +08:00
2018-11-25 21:53:26 +08:00
/** \brief returns an image with a key marker inside */
QImage generateKeyMarker ( QSize size = QSize ( 16 , 16 ) ) ;
/** \brief get the maximum and minimum x-value of the graph
*
* The result is given in the two parameters which are call - by - reference parameters !
*/
virtual bool getXMinMax ( double & minx , double & maxx , double & smallestGreaterZero ) = 0 ;
/** \brief get the maximum and minimum y-value of the graph
*
* The result is given in the two parameters which are call - by - reference parameters !
*/
virtual bool getYMinMax ( double & miny , double & maxy , double & smallestGreaterZero ) = 0 ;
/** \brief returns the color to be used for the key label */
2019-04-22 19:27:50 +08:00
virtual QColor getKeyLabelColor ( ) const = 0 ;
2018-11-25 21:53:26 +08:00
2019-02-03 21:04:48 +08:00
/** \brief sets the title of the plot (for display in key!).
*
* \ note If no title is supplied , no key entry is drawn . */
virtual void setTitle ( const QString & __value ) ;
/*! \brief returns the the title of the plot */
virtual QString getTitle ( ) const ;
/*! \brief sets whether the graph is visible in the plot */
void virtual setVisible ( bool __value ) ;
/*! \brief returns whether the graph is visible in the plot */
bool virtual isVisible ( ) const ;
2019-04-22 19:27:50 +08:00
/*! \brief sets whether the graph is drawn in a highlighted style in the plot */
void virtual setHighlighted ( bool __value ) ;
/*! \brief returns whether the graph is shown in a highlighted style in the plot */
bool virtual isHighlighted ( ) const ;
2018-11-25 21:53:26 +08:00
/** \brief returns the parent painter class */
2019-01-20 17:49:29 +08:00
inline JKQTBasePlotter * getParent ( ) { return parent ; }
2018-11-25 21:53:26 +08:00
/** \brief sets the parent painter class */
2019-01-20 17:49:29 +08:00
virtual void setParent ( JKQTBasePlotter * parent ) ;
2018-11-25 21:53:26 +08:00
/** \brief sets the parent painter class */
2019-01-20 23:15:10 +08:00
virtual void setParent ( JKQTPlotter * parent ) ;
2018-11-25 21:53:26 +08:00
/*! \brief if the graph plots outside the actual plot field of view (e.g. color bars, scale bars, ...)
\ note If you want to draw outside , then you ' ll also have to implement drawOutside ( )
*/
virtual void getOutsideSize ( JKQTPEnhancedPainter & painter , int & leftSpace , int & rightSpace , int & topSpace , int & bottomSpace ) ;
/*! \brief plots outside the actual plot field of view (e.g. color bars, scale bars, ...)
\ note If you want to draw outside , then you ' ll also have to implement getOutsideSize ( ) , so enough space is reserved
The four value supplied tell the method where to draw ( inside one of the rectangles ) .
*/
virtual void drawOutside ( JKQTPEnhancedPainter & painter , QRect leftSpace , QRect rightSpace , QRect topSpace , QRect bottomSpace ) ;
2019-05-06 01:31:20 +08:00
/** \brief modes of operation for the function hitTest() */
enum HitTestMode {
HitTestXY , /*!< \brief find closest point in x- and y-direction simulatneously (i.e. measure direct distance) */
HitTestXOnly , /*!< \brief find closest point in x-direction only */
HitTestYOnly , /*!< \brief find closest point in y-direction only */
} ;
/*! \brief returns the closest distance of the plot element to the (screen pixel) position \a pos, or \c NAN
This function is used to implement hit tests , i . e . to test whether a graph is close to a given position \ a posSystem .
The function will then return the distance of the closes graph - point and a label for this point . An example of what
can be done with this function is the tooltip tool that JKQTPlotter provides via its context - menu / toolbar . This tool
uses just the information of the closest point and its label to display a tooltip for that datapoint :
\ see jkqtpmdaToolTipForClosestDataPoint for details .
\ param posSystem position to test in system coordinates
\ param [ out ] closestSpotSystem optional output of the closest point found on the plot element in system coordinates
\ param [ out ] label optional output of a label for the closest point ( that might e . g . be used in a tooltip )
\ param mode search mode , i . e . use sqrt ( dx * dx + dy * dy ) as distance , or just the absoulte values along one of the
two coordinate axes . Note that the returned distance depends on this parameter !
\ return NAN if not implemented , or if \ a pos is very far from the plot element , or the closest distance ( in screen pixels )
of \ a pos from the plot element . Note that the returned distance depends on the choosen \ a mode ! ! !
You can use JKQTPIsOKFloat ( ) to check whether a valid distance was returned !
Since tha graph base class does not have any knowledge about how to perform a hit test on you specific graph , there is only a
very general implementation in this class , which does not actually search through the graph itself , but searches through
extra data that hs to be written during draw ( ) and is stored in m_hitTestData . The implentation this base - class only searches this
list of points + metadata to implement a basic hit - test . If the list is empty , of no close - by points are found ( default ) , then
hitTest ( ) will simply return \ a NAN .
When writing a new graph , you can therefore implement hitTest ( ) in one of these ways :
# You simply fill m_hitTestData with appropriate data and rely on the implementation in JKQTPPlotElement to do the work for you:
You then need to call clearHitTestData ( ) at the start of your draw ( ) function and whenever you draw a datapoint , you add
2019-05-18 02:46:52 +08:00
its location and metadata to the internal storage with addHitTestData ( )
2019-05-06 01:31:20 +08:00
# You derive from a graph class that already has an implementation. JKQTPXYGraph is an example of this. That class searches
through all x - / y - coordinates in the internally known columns and even takes into account possible graph errors in the label ,
when the graph is also derived from JKQTPXGraphErrorData or JKQTPYGraphErrorData . This implementation therefore covers
2019-05-18 02:46:52 +08:00
most graph types pre - packaged with JKQTPlotter
# You implement the function from scratch
2019-05-06 01:31:20 +08:00
.
\ see addHitTestData ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation
*/
virtual double hitTest ( const QPointF & posSystem , QPointF * closestSpotSystem = nullptr , QString * label = nullptr , HitTestMode mode = HitTestXY ) const ;
/** \brief Dataset for a single point on the graph, associated with its data-column index and a label that can be used by a basic implementation of hitTest()
*
* \ see hitTest ( )
*/
struct HitTestLocation {
2019-05-11 21:56:11 +08:00
inline HitTestLocation ( ) : pos ( JKQTP_NAN , JKQTP_NAN ) , index ( - 1 ) , label ( " " ) { }
2019-05-06 01:31:20 +08:00
inline HitTestLocation ( double x_ , double y_ , const QString & label_ ) : pos ( x_ , y_ ) , index ( - 1 ) , label ( label_ ) { }
inline HitTestLocation ( const QPointF & pos_ , const QString & label_ ) : pos ( pos_ ) , index ( - 1 ) , label ( label_ ) { }
inline HitTestLocation ( double x_ , double y_ , int index_ , const QString & label_ ) : pos ( x_ , y_ ) , index ( index_ ) , label ( label_ ) { }
inline HitTestLocation ( const QPointF & pos_ , int index_ , const QString & label_ ) : pos ( pos_ ) , index ( index_ ) , label ( label_ ) { }
/** \brief position of the hit-test point */
QPointF pos ;
/** \brief index of the hit-test point in the linked data-columns (or -1) */
int index ;
/** \brief label for that specific hit-test point */
QString label ;
} ;
2018-11-25 21:53:26 +08:00
2019-02-03 21:04:48 +08:00
/** \brief tool routine that transforms an x-coordinate (plot coordinate --> pixels) for this plot element */
2018-12-28 05:52:00 +08:00
virtual double transformX ( double x ) const ;
2019-02-03 21:04:48 +08:00
/** \brief tool routine that transforms a y-coordinate (plot coordinate --> pixels) for this plot element */
2018-12-28 05:52:00 +08:00
virtual double transformY ( double y ) const ;
2019-02-03 21:04:48 +08:00
/** \brief tool routine that backtransforms an x-coordinate (pixels --> plot coordinate) for this plot element */
2018-12-28 05:52:00 +08:00
virtual double backtransformX ( double x ) const ;
2019-02-03 21:04:48 +08:00
/** \brief tool routine that backtransforms a y-coordinate (pixels --> plot coordinate) for this plot element */
2018-12-28 05:52:00 +08:00
virtual double backtransformY ( double y ) const ;
2019-02-03 21:04:48 +08:00
/** \brief tool routine that transforms a QPointF according to the parent's transformation rules (plot coordinate --> pixels) */
2019-05-06 01:31:20 +08:00
inline QPointF transform ( const QPointF & x ) const {
2018-12-28 05:52:00 +08:00
return QPointF ( transformX ( x . x ( ) ) , transformY ( x . y ( ) ) ) ;
}
2018-11-25 21:53:26 +08:00
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
2019-02-03 21:04:48 +08:00
/** \brief tool routine that back-transforms a QPointF according to the parent's transformation rules (pixels --> plot coordinate) */
2019-05-06 01:31:20 +08:00
inline QPointF backTransform ( const QPointF & x ) const {
2018-12-28 05:52:00 +08:00
return QPointF ( backtransformX ( x . x ( ) ) , backtransformY ( x . y ( ) ) ) ;
}
2018-11-25 21:53:26 +08:00
2019-02-03 21:04:48 +08:00
/** \brief tool routine that transforms a QPointF according to the parent's transformation rules (plot coordinate --> pixels) */
2019-05-06 01:31:20 +08:00
inline QPointF transform ( double x , double y ) const {
2018-11-25 21:53:26 +08:00
return transform ( QPointF ( x , y ) ) ;
}
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
2019-02-03 21:04:48 +08:00
/** \brief tool routine that back-transforms a QPointF according to the parent's transformation rules (pixels --> plot coordinate) */
2019-05-06 01:31:20 +08:00
inline QPointF backTransform ( double x , double y ) const {
2018-11-25 21:53:26 +08:00
return backTransform ( QPointF ( x , y ) ) ;
}
2019-02-03 21:04:48 +08:00
/** \brief tool routine that transforms a QVector<QPointF> according to the parent's transformation rules (plot coordinate --> pixels) */
2019-05-06 01:31:20 +08:00
QVector < QPointF > transform ( const QVector < QPointF > & x ) const ;
2018-11-25 21:53:26 +08:00
/** \brief tool routine that transforms a QVector<QPointF> according to the parent's transformation rules
2019-02-03 21:04:48 +08:00
* and returns a ( non - closed ) path consisting of lines ( plot coordinate - - > pixels ) */
2019-05-06 01:31:20 +08:00
QPainterPath transformToLinePath ( const QVector < QPointF > & x ) const ;
2018-11-25 21:53:26 +08:00
/** \brief tool routine that transforms a QVector<QPointF> according to the parent's transformation rules
2019-02-03 21:04:48 +08:00
* and returns a polygon ( plot coordinate - - > pixels ) */
2019-05-06 01:31:20 +08:00
inline QPolygonF transformToPolygon ( const QVector < QPointF > & x ) const {
2018-11-25 21:53:26 +08:00
return QPolygonF ( transform ( x ) ) ;
}
2019-02-03 21:04:48 +08:00
2019-06-17 01:15:07 +08:00
/** \brief transform all x-coordinates in a vector \a x */
QVector < double > transformX ( const QVector < double > & x ) const ;
/** \brief transform all y-coordinates in a vector \a x */
QVector < double > transformY ( const QVector < double > & x ) const ;
2019-05-06 01:31:20 +08:00
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
protected :
2019-05-06 01:31:20 +08:00
/** \brief clear the internal datastore for hitTest()
*
* \ note This function has to be called at the start of draw ( )
* \ see hitTest ( ) , addHitTestData ( ) , m_hitTestData , HitTestLocation
*/
inline void clearHitTestData ( ) { m_hitTestData . clear ( ) ; }
/** \brief reserve list entries for up to \a points graph points in the internal datastore for hitTest()
*
* \ note Call this after clearHitTestData ( ) for improved speed of subsequent addHitTestData ( ) calls !
* \ see hitTest ( ) , addHitTestData ( ) , m_hitTestData , HitTestLocation
*/
inline void reserveHitTestData ( int points ) { m_hitTestData . reserve ( qMax ( 10 , abs ( points ) ) ) ; }
/** \brief clear the internal datastore for hitTest()
*
* \ note This function has to be called at the start of draw ( )
* \ see hitTest ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation , reserveHitTestData ( )
*/
inline void addHitTestData ( const HitTestLocation & loc ) { m_hitTestData < < loc ; }
/** \brief add a new point on the graph to the internal datastore for hitTest()
*
* \ param x_ x - position of the graph point in system coordinates
* \ param y_ y - position of the graph point in system coordinates
* \ param label_ a label for this datapoint , that can e . g . be displayed in a tooltip for this point
*
* \ see hitTest ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation , reserveHitTestData ( )
*/
inline void addHitTestData ( double x_ , double y_ , const QString & label_ ) { addHitTestData ( HitTestLocation ( x_ , y_ , label_ ) ) ; }
/** \brief clear the internal datastore for hitTest()
*
* \ param pos_ position of the graph point in system coordinates
* \ param label_ a label for this datapoint , that can e . g . be displayed in a tooltip for this point
*
* \ see hitTest ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation , reserveHitTestData ( )
*/
inline void addHitTestData ( const QPointF & pos_ , const QString & label_ ) { addHitTestData ( HitTestLocation ( pos_ , label_ ) ) ; }
/** \brief add a new point on the graph to the internal datastore for hitTest(),
* this variant uses formatHitTestDefaultLabel ( ) to auto - generate the label
*
* \ param x_ x - position of the graph point in system coordinates
* \ param y_ y - position of the graph point in system coordinates
* \ param index_ index of the graph point in the internal data columns , or - 1
* \ param datastore datastore for formatHitTestDefaultLabel ( )
*
* \ see hitTest ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation , reserveHitTestData ( )
*/
inline void addHitTestData ( double x_ , double y_ , int index_ = - 1 , JKQTPDatastore * datastore = nullptr ) { addHitTestData ( HitTestLocation ( x_ , y_ , formatHitTestDefaultLabel ( x_ , y_ , index_ , datastore ) ) ) ; }
/** \brief clear the internal datastore for hitTest(),
* this variant uses formatHitTestDefaultLabel ( ) to auto - generate the label
*
* \ param pos_ position of the graph point in system coordinates
* \ param index_ index of the graph point in the internal data columns , or - 1
* \ param datastore datastore for formatHitTestDefaultLabel ( )
*
* \ see hitTest ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation , reserveHitTestData ( )
*/
inline void addHitTestData ( const QPointF & pos_ , int index_ = - 1 , JKQTPDatastore * datastore = nullptr ) { addHitTestData ( HitTestLocation ( pos_ , formatHitTestDefaultLabel ( pos_ . x ( ) , pos_ . y ( ) , index_ , datastore ) ) ) ; }
/** \brief clear the internal datastore for hitTest()
*
* \ param x_ x - position of the graph point in system coordinates
* \ param y_ y - position of the graph point in system coordinates
* \ param index_ index of the graph point in the internal data columns
* \ param label_ a label for this datapoint , that can e . g . be displayed in a tooltip for this point
*
* \ see hitTest ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation , reserveHitTestData ( )
*/
inline void addHitTestData ( double x_ , double y_ , int index_ , const QString & label_ ) { addHitTestData ( HitTestLocation ( x_ , y_ , index_ , label_ ) ) ; }
/** \brief clear the internal datastore for hitTest()
*
* \ param pos_ position of the graph point in system coordinates
* \ param index_ index of the graph point in the internal data columns
* \ param label_ a label for this datapoint , that can e . g . be displayed in a tooltip for this point
*
* \ see hitTest ( ) , clearHitTestData ( ) , m_hitTestData , HitTestLocation , reserveHitTestData ( )
*/
inline void addHitTestData ( const QPointF & pos_ , int index_ , const QString & label_ ) { addHitTestData ( HitTestLocation ( pos_ , index_ , label_ ) ) ; }
/** \brief tool-function for hitTest(), which formats a default label, taking into account the x- and y-position (both provided)
* and optionally the errors of these positions .
*
* \ param x x - position of the datapoint in system coordinates
* \ param y y - position of the datapoint in system coordinates
* \ param index the index of the data point in the associated data column ( s ) , or - 1 ( optional ! )
* \ param datastore The datastore to read error data from ( optional ! )
* \ returns a LaTeX formatted label
*/
virtual QString formatHitTestDefaultLabel ( double x , double y , int index = - 1 , JKQTPDatastore * datastore = nullptr ) const ;
2019-02-03 21:04:48 +08:00
/** \brief the plotter object this object belongs to */
JKQTBasePlotter * parent ;
/** \brief title of the plot (for display in key!). If no title is supplied, no key entry is drawn. */
QString title ;
/** \brief indicates whether the graph is visible in the plot */
bool visible ;
2019-04-22 19:27:50 +08:00
/** \brief indicates whether the graph is shown in a "highlghted" in the plot */
bool highlighted ;
/** \brief internal storage for the used parent plot style */
int parentPlotStyle ;
2019-05-06 01:31:20 +08:00
/** \brief dataset with graph-points and associated data fro the function hitTest()
* \ see hitTest ( ) , HitTestLocation
*/
QVector < HitTestLocation > m_hitTestData ;
2018-12-28 05:52:00 +08:00
} ;
/** \brief this virtual base class of the (data-column based) graphs,
2019-01-20 23:15:10 +08:00
* which are part of a JKQTPlotter plot and which use the coordinate system
2019-01-26 03:16:04 +08:00
* of the JKQTPlotter ( i . e . the two coordinate axes getXAxis ( ) and getYAxis ( ) )
2018-12-28 05:52:00 +08:00
* as basis for the graphs
2019-01-13 01:53:16 +08:00
* \ ingroup jkqtplotter_basegraphs
2018-12-28 05:52:00 +08:00
*
2019-02-03 21:04:48 +08:00
* This class adds features to work with data columns .
* - There are two properties datarange_start and datarange_end . By default they are - 1 and therefore ignored .
* if they are ! = - 1 the plotter only displays the datapoints with the indexes [ datarange_start . . datarange_end ]
* although there might be more data points available ( range [ 0 . . maxDataPoints ] ) . The datarange is cut at the
* full range , i . e . if datarange_end > maxDataPoints the plotter displays [ datarange_start . . maxDataPoints ] .
* - Also there is a virtual function usesColumn ( ) which checks whether a given column is used by this graph .
* Override this function in your derived graphs to indicate to JKQTPlotter / JKQTBasePlotter , which columns
* from the internal JKQTPDatastore are actually used . This information can be used e . g . for graph - specific data - export .
* .
2018-12-28 05:52:00 +08:00
*
2019-02-03 21:04:48 +08:00
* \ see \ ref jkqtplotter_graphsgroup_classstructure
2018-12-28 05:52:00 +08:00
*/
2019-06-22 20:21:32 +08:00
class JKQTPLOTTER_LIB_EXPORT JKQTPGraph : public JKQTPPlotElement {
2018-12-28 05:52:00 +08:00
Q_OBJECT
public :
/** \brief class constructor */
2019-01-20 17:49:29 +08:00
explicit JKQTPGraph ( JKQTBasePlotter * parent = nullptr ) ;
2018-12-28 05:52:00 +08:00
/** \brief default wirtual destructor */
2019-02-03 21:04:48 +08:00
virtual ~ JKQTPGraph ( ) = default ;
2018-12-28 05:52:00 +08:00
2019-02-03 21:04:48 +08:00
/** \brief returns \c true if the given column is used by the graph
*
* This virtual function indicates whether a given column is used by this graph .
* Override this function in your derived graphs to indicate to JKQTPlotter / JKQTBasePlotter , which columns
* from the internal JKQTPDatastore are actually used . This information can be used e . g . for graph - specific data - export .
*/
2018-12-28 05:52:00 +08:00
virtual bool usesColumn ( int column ) const ;
protected :
/** \brief this function is used to plot error inidcators before plotting the graphs.
*
* By default this function does nothing . But children of this class may overwrite it to implement
* drawing error indicators .
*/
virtual void drawErrorsBefore ( JKQTPEnhancedPainter & /*painter*/ ) ;
/** \brief this function is used to plot error inidcators after plotting the graphs.
*
* By default this function does nothing . But children of this class may overwrite it to implement
* drawing error indicators .
*/
virtual void drawErrorsAfter ( JKQTPEnhancedPainter & /*painter*/ ) ;
2018-11-25 21:53:26 +08:00
/** \brief get the maximum and minimum value of the given column
*
* The result is given in the two parameters which are call - by - reference parameters !
*/
bool getDataMinMax ( int column , double & minx , double & maxx , double & smallestGreaterZero ) ;
2019-02-03 21:04:48 +08:00
protected :
2019-05-06 01:31:20 +08:00
friend class JKQTPGraphErrorStyleMixin ;
2018-11-25 21:53:26 +08:00
} ;
2019-01-20 23:15:10 +08:00
/** \brief this is the virtual base class of all JKQTPPlotElement's in a JKQTPlotter plot that
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
* represent geometric forms or annotations .
* \ ingroup jkqtplotter_basegraphs
2018-12-28 05:52:00 +08:00
*
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
* \ see \ ref jkqtplotter_graphsgroup_classstructure , \ ref JKQTPlotterGeometricGraphs
*
* \ section JKQTPPlotObject_coordinates Coordinate Systems
* JKQTPPlotObject ' s have extended coordinate transform capabilities , because in addition to using
* the plot coordinates , you can also choose to use different other coordinate systems .
*
* \ section JKQTPPlotObject_DrawMode Draw Modes
2019-02-03 21:04:48 +08:00
*
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
* \ copydetails m_drawMode
2018-12-28 05:52:00 +08:00
*/
2019-06-22 20:21:32 +08:00
class JKQTPLOTTER_LIB_EXPORT JKQTPPlotObject : public JKQTPPlotElement {
2018-12-28 05:52:00 +08:00
Q_OBJECT
public :
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
/** \brief indicates how to draw the geometric object */
enum DrawMode {
DrawAsGraphicElement , /*!< \brief draw lines as lines (i.e. graphic elements) \image html JKQTPPlotObject_DrawAsGraphicElement.png */
DrawAsMathematicalCurve /*!< \brief draw lines as the mathematically correct curve \image html JKQTPPlotObject_DrawAsMathematicalCurve.png */
} ;
Q_ENUM ( DrawMode )
2018-12-28 05:52:00 +08:00
/** \brief class constructor */
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
explicit JKQTPPlotObject ( DrawMode drawMode = DrawAsGraphicElement , JKQTBasePlotter * parent = nullptr ) ;
2018-12-28 05:52:00 +08:00
/** \brief default wirtual destructor */
2019-01-20 17:49:29 +08:00
virtual ~ JKQTPPlotObject ( ) ;
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
/** \copybrief m_drawMode
*
* \ return the currently set DrawMode
* \ see m_drawMode , DrawMode
*/
DrawMode getDrawMode ( ) const ;
public slots :
/** \copybrief m_drawMode
*
* \ param mode the DrawMode to use from now on
* \ see m_drawMode , DrawMode
*/
void setDrawMode ( DrawMode mode ) ;
2018-12-28 05:52:00 +08:00
protected :
- improved: geometric objects now use an adaptive drawing algorithm to represent curves (before e.g. ellipses were always separated into a fixed number of line-segments)
- improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
- new: all geometric objects can either be drawn as graphic element (i.e. lines are straight line, even on non-linear axes), or as mathematical curve (i.e. on non-linear axes, lines become the appropriate curve representing the linear function, connecting the given start/end-points). The only exceptions are ellipses (and the derived arcs,pies,chords), which are always drawn as mathematical curves
2020-09-04 05:08:52 +08:00
/** \brief indicated whether to draw lines as graphic elements (even on non-linear coordinate systems),
* or as mathematically correct curves
*
* It is possible to define in which ways the forms shall be treated / drawn into non - linear
* coordinate systems ( e . g . semi - log or log - log plots ) . Imagine drawing a line from ( x1 , y1 ) to ( x2 , y2 )
* In a linear coordinate system , this is always a line , but in a non - linear system , the line might
* have to be represented by a curve instead . Depending on how you want to use the JKQTPPlotObject you
* can choose to still draw it as a line connecting the points ( x1 , y1 ) and ( x2 , y2 ) , or as the -
* mathematically correct - curve connecting these two points :
*
* \ image html JKQTPPlotObject_DrawAsMathematicalCurve . png
*
* \ image html JKQTPPlotObject_DrawAsGraphicElement . png
*
* \ see DrawMode , setDrawMode ( ) , getDrawMode ( )
*/
DrawMode m_drawMode ;
2018-12-28 05:52:00 +08:00
} ;
2019-01-20 17:49:29 +08:00
/*! \brief This virtual JKQTPGraph descendent may be used as base for all graphs that use at least two columns
2018-11-25 21:53:26 +08:00
that specify x and y coordinates for the single plot points .
2019-01-13 01:53:16 +08:00
\ ingroup jkqtplotter_basegraphs
2018-11-25 21:53:26 +08:00
2019-02-03 21:04:48 +08:00
This class implements basic management facilities for the data columns :
- setXColumn ( ) , setYColumn ( ) to set the columns to be used for the graph data
- setDataSortOrder ( ) to specify whether and how the data should be sorted before drawing
\ image html jkqtplotter_unsorted . png " Unsorted Data "
\ image html jkqtplotter_sortedx . png " Data sorted along x-axis (DataSortOrder::SortedX) "
.
. . . and overrides / implements the functions :
- getXMinMax ( )
- getYMinMax ( )
- usesColumn ( )
2018-11-25 21:53:26 +08:00
.
*/
2019-06-22 20:21:32 +08:00
class JKQTPLOTTER_LIB_EXPORT JKQTPXYGraph : public JKQTPGraph {
2018-11-25 21:53:26 +08:00
Q_OBJECT
public :
2019-02-03 21:04:48 +08:00
/** \brief specifies how to sort the data in a JKQTPXYGraph before drawing
*
* \ image html jkqtplotter_unsorted . png " Unsorted Data "
*
* \ image html jkqtplotter_sortedx . png " Data sorted along x-axis (DataSortOrder::SortedX) "
*/
2018-11-25 21:53:26 +08:00
enum DataSortOrder {
2019-02-03 21:04:48 +08:00
Unsorted = 0 , /*!< \brief the data for a JKQTPXYGraph is not sorted before drawing */
SortedX = 1 , /*!< \brief the data for a JKQTPXYGraph is sorted so the x-values appear in ascending before drawing */
SortedY = 2 /*!< \brief the data for a JKQTPXYGraph is sorted so the y-values appear in ascending before drawing */
2018-11-25 21:53:26 +08:00
} ;
/** \brief class constructor */
2019-01-20 17:49:29 +08:00
JKQTPXYGraph ( JKQTBasePlotter * parent = nullptr ) ;
2018-11-25 21:53:26 +08:00
/** \brief get the maximum and minimum x-value of the graph
*
* The result is given in the two parameters which are call - by - reference parameters !
*/
2018-12-28 05:52:00 +08:00
virtual bool getXMinMax ( double & minx , double & maxx , double & smallestGreaterZero ) override ;
2018-11-25 21:53:26 +08:00
/** \brief get the maximum and minimum y-value of the graph
*
* The result is given in the two parameters which are call - by - reference parameters !
*/
2018-12-28 05:52:00 +08:00
virtual bool getYMinMax ( double & miny , double & maxy , double & smallestGreaterZero ) override ;
2018-11-25 21:53:26 +08:00
2019-01-20 17:49:29 +08:00
/** \copydoc JKQTPGraph::usesColumn() */
2018-12-28 05:52:00 +08:00
virtual bool usesColumn ( int column ) const override ;
2018-11-25 21:53:26 +08:00
2019-05-19 04:41:38 +08:00
/*! \copydoc xColumn */
2019-05-06 01:31:20 +08:00
void setXColumn ( int __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc xColumn */
2019-05-06 01:31:20 +08:00
int getXColumn ( ) const ;
2019-05-19 04:41:38 +08:00
/*! \copydoc xColumn */
2019-05-06 01:31:20 +08:00
void setXColumn ( size_t __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc yColumn */
2019-05-06 01:31:20 +08:00
void setYColumn ( int __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc yColumn */
2019-05-06 01:31:20 +08:00
int getYColumn ( ) const ;
2019-05-19 04:41:38 +08:00
/*! \copydoc yColumn */
2019-05-06 01:31:20 +08:00
void setYColumn ( size_t __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc sortData */
2019-05-06 01:31:20 +08:00
void setDataSortOrder ( DataSortOrder __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc sortData */
2019-05-06 01:31:20 +08:00
DataSortOrder getDataSortOrder ( ) const ;
2019-05-19 04:41:38 +08:00
/*! \copydoc sortData */
2019-02-03 21:04:48 +08:00
void setDataSortOrder ( int __value ) ;
2018-11-25 21:53:26 +08:00
2019-05-13 04:22:48 +08:00
/** \brief sets xColumn and yColumn at the same time */
void setXYColumns ( size_t xCol , size_t yCol ) ;
/** \brief sets xColumn and yColumn at the same time */
void setXYColumns ( int xCol , int yCol ) ;
/** \brief sets xColumn and yColumn at the same time */
void setXYColumns ( std : : pair < int , int > xyColPair ) ;
/** \brief sets xColumn and yColumn at the same time */
void setXYColumns ( std : : pair < size_t , size_t > xyColPair ) ;
/** \brief sets xColumn and yColumn at the same time */
void setXYColumns ( QPair < int , int > xyColPair ) ;
/** \brief sets xColumn and yColumn at the same time */
void setXYColumns ( QPair < size_t , size_t > xyColPair ) ;
2019-05-06 01:31:20 +08:00
/** \brief Implmentation of JKQTPPlotElement::hitTest(), which searches through all graph points defined by xColumn and yColumn
* and returns a general x / y - label , also taking into account possibly known errors to the graphs ( if it is derived
* from JKQTPXGraphErrorData and / or JKQTPYGraphErrorData
*
* \ note This function first checks whether JKQTPPlotElement : : hitTest ( ) returns any result , so you can use the basic implementation
* in JKQTPPlotElement to override the behaviour here , by simply calling addHitTestData ( ) during your draw ( ) implementation
*
* \ see See JKQTPPlotElement : : hitTest ( ) for details on the function definition !
*/
virtual double hitTest ( const QPointF & posSystem , QPointF * closestSpotSystem = nullptr , QString * label = nullptr , HitTestMode mode = HitTestXY ) const override ;
2018-11-25 21:53:26 +08:00
protected :
/** \brief the column that contains the x-component of the datapoints */
int xColumn ;
/** \brief the column that contains the y-component of the datapoints */
int yColumn ;
/** \brief if \c !=Unsorted, the data is sorted before plotting */
DataSortOrder sortData ;
/** \brief this array contains the order of indices, in which to access the data in the data columns */
QVector < int > sortedIndices ;
virtual void intSortData ( ) ;
2018-12-28 05:52:00 +08:00
/** \brief returns the index of the i-th datapoint (where i is an index into the SORTED datapoints)
*
* This function can beu used to get the correct datapoint after sorting the datapoints ,
* As sorting is done by sorting an index and not reordering the data in the columns themselves .
2019-02-03 21:04:48 +08:00
*
* \ see setDataSortOrder ( ) , getDataSortOrder ( )
2018-12-28 05:52:00 +08:00
* */
2019-02-03 21:04:48 +08:00
inline int getDataIndex ( int i ) {
2018-11-25 21:53:26 +08:00
if ( sortData = = Unsorted ) return i ;
return sortedIndices . value ( i , i ) ;
}
2019-05-06 01:31:20 +08:00
/** \brief determines the range of row indexes available in the data columns of this graph
*
* \ param [ out ] imin first usable row - index
* \ param [ out ] imax last usable row - index
* \ return \ c true on success and \ c false if the information is not available
*/
virtual bool getIndexRange ( int & imin , int & imax ) const ;
2018-11-25 21:53:26 +08:00
} ;
2019-01-20 17:49:29 +08:00
/*! \brief This virtual JKQTPGraph descendent may be used as base for all graphs that use at least one column
2018-11-25 21:53:26 +08:00
of data
2019-01-13 01:53:16 +08:00
\ ingroup jkqtplotter_basegraphs
2018-11-25 21:53:26 +08:00
2019-02-03 21:04:48 +08:00
\ see \ ref jkqtplotter_graphsgroup_classstructure
2018-11-25 21:53:26 +08:00
*/
2019-06-22 20:21:32 +08:00
class JKQTPLOTTER_LIB_EXPORT JKQTPSingleColumnGraph : public JKQTPGraph {
2018-11-25 21:53:26 +08:00
Q_OBJECT
public :
2019-02-03 21:04:48 +08:00
/** \brief specifies how to sort the data for a JKQTPSingleColumnGraph before drawing
*
* \ image html jkqtplotter_unsorted . png " Unsorted Data "
*
* \ image html jkqtplotter_sortedx . png " Data sorted along x-axis (DataSortOrder::SortedX) "
*/
2018-11-25 21:53:26 +08:00
enum DataSortOrder {
2019-02-03 21:04:48 +08:00
Unsorted = 0 , /*!< \brief the data for a JKQTPSingleColumnGraph is not sorted before drawing */
Sorted = 1 /*!< \brief the data for a JKQTPSingleColumnGraph is sorted (in ascending order) before drawing */
2018-11-25 21:53:26 +08:00
} ;
2019-01-20 23:15:10 +08:00
2019-02-03 21:04:48 +08:00
/** \brief specifies whether the data for a JKQTPSingleColumnGraph represent x-axis or y-axis values */
2019-01-20 23:15:10 +08:00
enum class DataDirection {
2019-02-03 21:04:48 +08:00
X , /*!< \brief the data for a JKQTPSingleColumnGraph is data belonging to the x-axis of the plot */
Y /*!< \brief the data for a JKQTPSingleColumnGraph is data belonging to the y-axis of the plot */
2019-01-20 23:15:10 +08:00
} ;
2018-11-25 21:53:26 +08:00
/** \brief class constructor */
2019-01-20 17:49:29 +08:00
JKQTPSingleColumnGraph ( JKQTBasePlotter * parent = nullptr ) ;
2018-11-25 21:53:26 +08:00
2019-05-19 04:41:38 +08:00
/*! \copydoc dataColumn */
2019-04-22 19:27:50 +08:00
void setDataColumn ( int __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc dataColumn */
2019-04-22 19:27:50 +08:00
int getDataColumn ( ) const ;
2019-05-19 04:41:38 +08:00
/*! \copydoc dataColumn */
2019-04-22 19:27:50 +08:00
void setDataColumn ( size_t __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc sortData */
2019-04-22 23:19:52 +08:00
void setDataSortOrder ( DataSortOrder __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc sortData */
2019-04-22 19:27:50 +08:00
DataSortOrder getDataSortOrder ( ) const ;
2019-05-19 04:41:38 +08:00
/*! \copydoc sortData */
2019-02-03 21:04:48 +08:00
void setDataSortOrder ( int __value ) ;
2018-11-25 21:53:26 +08:00
2019-04-22 19:27:50 +08:00
2019-05-19 04:41:38 +08:00
/*! \copydoc dataDirection */
2019-04-22 19:27:50 +08:00
void setDataDirection ( DataDirection __value ) ;
2019-05-19 04:41:38 +08:00
/*! \copydoc dataDirection */
2019-04-22 19:27:50 +08:00
DataDirection getDataDirection ( ) const ;
2019-01-20 17:49:29 +08:00
/** \copydoc JKQTPGraph::usesColumn() */
2018-12-28 05:52:00 +08:00
virtual bool usesColumn ( int c ) const override ;
2018-11-25 21:53:26 +08:00
protected :
/** \brief the column that contains the datapoints */
int dataColumn ;
2019-04-22 19:27:50 +08:00
/** \brief interpret the data from dataColumn either as X- or Y-data */
DataDirection dataDirection ;
2018-11-25 21:53:26 +08:00
/** \brief if \c !=Unsorted, the data is sorted before plotting */
DataSortOrder sortData ;
/** \brief this array contains the order of indices, in which to access the data in the data columns */
QVector < int > sortedIndices ;
virtual void intSortData ( ) ;
2018-12-28 05:52:00 +08:00
/** \brief returns the index of the i-th datapoint (where i is an index into the SORTED datapoints)
*
* This function can beu used to get the correct datapoint after sorting the datapoints ,
* As sorting is done by sorting an index and not reordering the data in the columns themselves .
* */
2019-04-22 19:27:50 +08:00
inline int getDataIndex ( int i ) {
2018-11-25 21:53:26 +08:00
if ( sortData = = Unsorted ) return i ;
return sortedIndices . value ( i , i ) ;
}
2019-05-06 01:31:20 +08:00
/** \brief determines the range of row indexes available in the data columns of this graph
*
* \ param [ out ] imin first usable row - index
* \ param [ out ] imax last usable row - index
* \ return \ c true on success and \ c false if the information is not available
*/
virtual bool getIndexRange ( int & imin , int & imax ) const ;
2018-12-28 05:52:00 +08:00
2018-11-25 21:53:26 +08:00
} ;
2019-02-08 00:24:46 +08:00
# endif // JKQTPGRAPHSBASE_H