mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-11-16 02:25:50 +08:00
291 lines
13 KiB
C
291 lines
13 KiB
C
|
/*
|
||
|
Copyright (c) 2008-2018 Jan W. Krieger (<jan@jkrieger.de>)
|
||
|
|
||
|
|
||
|
|
||
|
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
|
||
|
the Free Software Foundation, either version 2 of the License, or
|
||
|
(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/>.
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* \defgroup jkqtplotter_elements Plot Elements
|
||
|
* \ingroup jkqtplotter
|
||
|
* \defgroup jkqtplotter_plots Graphs
|
||
|
* \ingroup jkqtplotter_elements
|
||
|
*/
|
||
|
|
||
|
/** \file jkqtpelements.h
|
||
|
* \ingroup jkqtplotter
|
||
|
*/
|
||
|
|
||
|
#include <QString>
|
||
|
#include <QPainter>
|
||
|
#include <QPair>
|
||
|
#include "jkqtpelements.h"
|
||
|
#include "jkqtp_imexport.h"
|
||
|
|
||
|
#ifndef JKQTPEVALUATEDFUNCTIONELEMENTS_H
|
||
|
#define JKQTPEVALUATEDFUNCTIONELEMENTS_H
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*! \brief type of functions that may be plottet
|
||
|
\ingroup jkqtplotter_plots
|
||
|
|
||
|
This is the type of functions \f$ y=f(x, \vec{p}) \f$ that may be plottet by JKQTPxFunctionLineGraph
|
||
|
and JKQTPyFunctionLineGraph. It is possible to supply parameters \f$ \vec{p} \f$ to the function that
|
||
|
influence its result. Parameters are given as a pointer to some memory location. The function has to
|
||
|
know on its own how to interpret these.
|
||
|
*/
|
||
|
typedef double(*jkqtpPlotFunctionType)(double, void*);
|
||
|
|
||
|
|
||
|
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ y=f(x) \f$
|
||
|
\ingroup jkqtplotter_plots
|
||
|
|
||
|
This class implements an intelligent plotting algorithm for functions. It starts by sampling
|
||
|
the function at minSamples positions. Then each function interval is bisected recursively if
|
||
|
necessary. To do so the function is evaluated at the mid point and the slopes \f$ \alpha_{\mbox{left}} \f$
|
||
|
and \f$ \alpha_{\mbox{right}} \f$ of the two linear segments are compared. the midpoint is added
|
||
|
to the graph if \f[ \left|\alpha_{\mbox{right}}-\alpha_{\mbox{left}}\right|>\mbox{slopeTolerance} \f]
|
||
|
In addition all sampling points except minimum and maximum are beeing shifted by a random fraction their
|
||
|
distance to the other points. This helps to prevent beats when sampling periodic functions.
|
||
|
|
||
|
the following image
|
||
|
\image html plot_functionplots.png
|
||
|
*/
|
||
|
class LIB_EXPORT JKQTPxFunctionLineGraph: public JKQTPgraph {
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
|
||
|
enum SpecialFunction {
|
||
|
Polynomial, /*!< \brief a polynomial \f$ f(x)=p_0+p_1x+p_2x^2+p_3x^3+... \f$ The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||
|
Line=Polynomial, /*!< \brief a polynomial \f$ f(x)=p_0+p_1x \f$ The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||
|
Exponential, /*!< \brief an exponential function \f$ f(x)=p_0+p_1\cdot\exp(x/p_2) \f$ or \f$ f(x)=p_0\cdot\exp(x/p_1) \f$ (depending on the number of parameters). The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||
|
PowerLaw /*!< \brief an exponential function \f$ f(x)=p_0+p_1\cdot x^{p_3} \f$ or \f$ f(x)=p_0\cdot x^{p_1} \f$ or \f$ f(x)= x^{p_0} \f$ (depending on the number of parameters) The parameters \a params have to be point to a QVector<double> and contain the parameters \f$ p_0, p_1, ... \f$ */
|
||
|
};
|
||
|
|
||
|
/** \brief class constructor */
|
||
|
JKQTPxFunctionLineGraph(JKQtBasePlotter* parent=nullptr);
|
||
|
|
||
|
/** \brief class constructor */
|
||
|
JKQTPxFunctionLineGraph(JKQtPlotter* parent);
|
||
|
|
||
|
/** \brief class destructor */
|
||
|
virtual ~JKQTPxFunctionLineGraph();
|
||
|
|
||
|
/** \brief plots the graph to the plotter object specified as parent */
|
||
|
virtual void draw(JKQTPEnhancedPainter& painter);
|
||
|
/** \brief plots a key marker inside the specified rectangle \a rect */
|
||
|
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect);
|
||
|
/** \brief returns the color to be used for the key label */
|
||
|
virtual QColor getKeyLabelColor();
|
||
|
|
||
|
/** \brief get the maximum and minimum x-value of the graph
|
||
|
*
|
||
|
* This functions returns 0 for both parameters, so that the plotter uses the predefined
|
||
|
* min and max values.
|
||
|
*/
|
||
|
virtual bool getXMinMax(double& minx, double& maxx, double& smallestGreaterZero);
|
||
|
/** \brief get the maximum and minimum y-value of the graph
|
||
|
*/
|
||
|
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero);
|
||
|
|
||
|
/** \brief clear the data sampled from the function. */
|
||
|
void clearData();
|
||
|
|
||
|
JKQTPGET_SET_MACRO(QColor, color)
|
||
|
JKQTPGET_SET_MACRO(QColor, fillColor)
|
||
|
JKQTPGET_SET_MACRO(Qt::BrushStyle, fillStyle)
|
||
|
JKQTPGET_SET_MACRO(Qt::PenStyle, style)
|
||
|
JKQTPGET_SET_MACRO(double, lineWidth)
|
||
|
JKQTPGET_SET_MACRO(bool, drawLine)
|
||
|
JKQTPGET_SET_MACRO_I(jkqtpPlotFunctionType, plotFunction, clearData())
|
||
|
JKQTPGET_SET_MACRO_I(void*, params, clearData())
|
||
|
/** \brief sets the params as a pointer to an internal COPY of the given vector (not the data of the vector, as then the size would be unknown!!!) */
|
||
|
void set_params(const QVector<double>& params);
|
||
|
/** \brief sets the params from a copy of the given array of length \a N */
|
||
|
void set_copiedParams(const double* params, int N);
|
||
|
inline void set_paramsV(double p1) {
|
||
|
QVector<double> p;
|
||
|
p<<p1;
|
||
|
set_params(p);
|
||
|
}
|
||
|
inline void set_paramsV(double p1, double p2) {
|
||
|
QVector<double> p;
|
||
|
p<<p1<<p2;
|
||
|
set_params(p);
|
||
|
}
|
||
|
inline void set_paramsV(double p1, double p2, double p3) {
|
||
|
QVector<double> p;
|
||
|
p<<p1<<p2<<p3;
|
||
|
set_params(p);
|
||
|
}
|
||
|
inline void set_paramsV(double p1, double p2, double p3, double p4) {
|
||
|
QVector<double> p;
|
||
|
p<<p1<<p2<<p3<<p4;
|
||
|
set_params(p);
|
||
|
}
|
||
|
inline void set_paramsV(double p1, double p2, double p3, double p4, double p5) {
|
||
|
QVector<double> p;
|
||
|
p<<p1<<p2<<p3<<p4<<p5;
|
||
|
set_params(p);
|
||
|
}
|
||
|
|
||
|
QVector<double> get_internalParams() const;
|
||
|
QVector<double> get_internalErrorParams() const;
|
||
|
JKQTPGET_SET_MACRO(unsigned int, minSamples)
|
||
|
JKQTPGET_SET_MACRO(unsigned int, maxRefinementDegree)
|
||
|
JKQTPGET_SET_MACRO(double, slopeTolerance)
|
||
|
JKQTPGET_SET_MACRO(double, minPixelPerSample)
|
||
|
JKQTPGET_SET_MACRO(bool, plotRefinement)
|
||
|
JKQTPGET_SET_MACRO(bool, displaySamplePoints)
|
||
|
JKQTPGET_SET_MACRO(bool, drawErrorPolygons)
|
||
|
JKQTPGET_SET_MACRO(bool, drawErrorLines)
|
||
|
JKQTPGET_SET_MACRO(jkqtpPlotFunctionType, errorPlotFunction)
|
||
|
JKQTPGET_SET_MACRO(void*, errorParams)
|
||
|
/** \brief sets the error params as a pointer to an internal COPY of the given vector (not the data of the vector, as then the size would be unknown!!!) */
|
||
|
void set_errorParams(const QVector<double>& errorParams);
|
||
|
|
||
|
JKQTPGET_SET_MACRO(int, parameterColumn)
|
||
|
JKQTPSET_CAST_MACRO(size_t, int, parameterColumn)
|
||
|
JKQTPGET_SET_MACRO(int, errorParameterColumn)
|
||
|
JKQTPSET_CAST_MACRO(size_t, int, errorParameterColumn)
|
||
|
|
||
|
JKQTPGET_SET_MACRO(QColor, errorColor)
|
||
|
JKQTPGET_SET_MACRO(QColor, errorFillColor)
|
||
|
JKQTPGET_SET_MACRO(Qt::BrushStyle, errorFillStyle)
|
||
|
JKQTPGET_SET_MACRO(Qt::PenStyle, errorStyle)
|
||
|
JKQTPGET_SET_MACRO(double, errorLineWidth)
|
||
|
|
||
|
/** \copydoc JKQTPgraph::usesColumn() */
|
||
|
virtual bool usesColumn(int c);
|
||
|
|
||
|
|
||
|
/** \brief sets function to the given special function */
|
||
|
void setSpecialFunction(SpecialFunction function);
|
||
|
protected:
|
||
|
/** \brief which plot style to use from the parent plotter (via JKQtPlotterBase::getPlotStyle() and JKQtPlotterBase::getNextStyle() ) */
|
||
|
int parentPlotStyle;
|
||
|
|
||
|
struct doublePair {
|
||
|
double x;
|
||
|
double f;
|
||
|
doublePair* next;
|
||
|
};
|
||
|
/** \brief a linked list holding the datapoints \f$ \left(x, y=f(x, \vec{p})\right) \f$ to be plotted */
|
||
|
doublePair* data;
|
||
|
|
||
|
/** \brief fill the data array with data from the function plotFunction */
|
||
|
virtual void createPlotData( bool collectParams=true);
|
||
|
|
||
|
virtual void collectParameters();
|
||
|
|
||
|
void refine(doublePair* a, doublePair* b, unsigned int degree=0);
|
||
|
|
||
|
int parameterColumn;
|
||
|
int errorParameterColumn;
|
||
|
|
||
|
/** \brief color of the graph */
|
||
|
QColor color;
|
||
|
/** \brief color of the graph fill */
|
||
|
QColor fillColor;
|
||
|
/** \brief linestyle of the graph lines */
|
||
|
Qt::PenStyle style;
|
||
|
/** \brief width (pixels) of the graph */
|
||
|
double lineWidth;
|
||
|
/** \brief fill style, if the curve should be filled */
|
||
|
Qt::BrushStyle fillStyle;
|
||
|
/** \brief indicates whether to draw a line or not */
|
||
|
bool drawLine;
|
||
|
/** \brief indicates whether to fill the space between the curve and the x-axis */
|
||
|
bool fillCurve;
|
||
|
/** \brief the function to be plotted */
|
||
|
jkqtpPlotFunctionType plotFunction;
|
||
|
/** \brief pointer to the parameters supplied to the plotting funtion */
|
||
|
void* params;
|
||
|
/** \brief the minimum number of points to evaluate the function at */
|
||
|
unsigned int minSamples;
|
||
|
/** \brief the maximum number of recursive refinement steps
|
||
|
*
|
||
|
* each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
|
||
|
* of points plotted at all are thus:
|
||
|
* \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
|
||
|
*/
|
||
|
unsigned int maxRefinementDegree;
|
||
|
/** \brief the tolerance for the difference of two subsequent slopes */
|
||
|
double slopeTolerance;
|
||
|
/** \brief create one sample at least every \a minPixelPerSample pixels */
|
||
|
double minPixelPerSample;
|
||
|
/** \brief switch on or off [default: on] the plot refinement algorithm */
|
||
|
bool plotRefinement;
|
||
|
/** \brief if true [default: off] display the points where the function has been sampled */
|
||
|
bool displaySamplePoints;
|
||
|
/** \brief indicates whether an error polygon should be drawn */
|
||
|
bool drawErrorPolygons;
|
||
|
/** \brief indicates whether error lines should be drawn */
|
||
|
bool drawErrorLines;
|
||
|
/** \brief this function calculates the error at a given position */
|
||
|
jkqtpPlotFunctionType errorPlotFunction;
|
||
|
/** \brief parameters for errorFunction */
|
||
|
void* errorParams;
|
||
|
/** \brief color of the error graph */
|
||
|
QColor errorColor;
|
||
|
/** \brief color of the error graph fill */
|
||
|
QColor errorFillColor;
|
||
|
/** \brief linestyle of the error graph lines */
|
||
|
Qt::PenStyle errorStyle;
|
||
|
/** \brief width (pixels) of the error graph */
|
||
|
double errorLineWidth;
|
||
|
/** \brief fill style, if the error curve should be filled */
|
||
|
Qt::BrushStyle errorFillStyle;
|
||
|
|
||
|
|
||
|
QBrush getBrush(JKQTPEnhancedPainter& painter) const;
|
||
|
QPen getLinePen(JKQTPEnhancedPainter& painter) const;
|
||
|
|
||
|
QBrush getErrorBrush(JKQTPEnhancedPainter& painter) const;
|
||
|
QPen getErrorLinePen(JKQTPEnhancedPainter &painter) const;
|
||
|
|
||
|
QVector<double> iparams, ierrorparams;
|
||
|
};
|
||
|
|
||
|
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$
|
||
|
\ingroup jkqtplotter_plots
|
||
|
|
||
|
*/
|
||
|
class LIB_EXPORT JKQTPyFunctionLineGraph: public JKQTPxFunctionLineGraph {
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
/** \brief class constructor */
|
||
|
inline JKQTPyFunctionLineGraph(JKQtBasePlotter* parent=nullptr):JKQTPxFunctionLineGraph(parent) {}
|
||
|
/** \brief class constructor */
|
||
|
inline JKQTPyFunctionLineGraph(JKQtPlotter* parent):JKQTPxFunctionLineGraph(parent) {}
|
||
|
|
||
|
/** \brief plots the graph to the plotter object specified as parent */
|
||
|
virtual void draw(JKQTPEnhancedPainter& painter);
|
||
|
protected:
|
||
|
|
||
|
/** \brief fill the data array with data from the function plotFunction */
|
||
|
virtual void createPlotData( bool collectParams=true);
|
||
|
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#endif // JKQTPEVALUATEDFUNCTIONELEMENTS_H
|