- cleanup of class-hierarchy of evaluated functions

- added slots for several properties of evaluated functions
- updated examples
This commit is contained in:
jkriege2 2020-09-07 20:57:25 +02:00
parent 414e12920e
commit f77bc97ca5
15 changed files with 1552 additions and 1097 deletions

View File

@ -23,6 +23,7 @@ Changes, compared to \ref page_whatsnew_V2019_11 "v2019.11" include:
<li>removed the usage of some deprecated functions and objects (e.g. QMatrix)</li>
<li>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)</li>
<li>improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)</li>
<li>improved: reworked class hirarchy of parsed function plots and declared several setters as slots.</li>
<li>new: added geometric plot objects JKQTPGeoArrow to draw arrows (aka lines with added line-end decorators, also extended JKQTPGeoLine, JKQTPGeoInfiniteLine, JKQTPGeoPolyLines to draw line-end decorator (aka arrows)</li>
<li>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</li>
<li>new: a new graph class JKQTPXYFunctionLineGraph draws parametric 2D curves ( \f$ [x,y] = f(t) \f$ ), see \ref JKQTPlotterEvalCurves for an example</li>

View File

@ -1,6 +1,8 @@
# Example (JKQTPlotter): Plotting Parametric Mathematical Curves as Line Graphs {#JKQTPlotterEvalCurves}
## Basics
This project (see `./examples/evalcurve/`) demonstrates how to plot mathematical functions as line graphs. The functions may be defined as static C functions, C++ functors or c++ inline functions.
This project (see `./examples/evalcurve/`) demonstrates how to plot mathematical functions as line graphs. The functions may be defined as static C functions, C++ functors or c++ inline functions. The functions may simply depend on the parameter `t`, or on `t` and a vector of parameters.
The class uses an adaptive algorithm, which determines by the local slope, at how many points (or how close points) the functor has to be evaluated.
[TOC]
@ -9,24 +11,55 @@ The example shows how to plot a simple C++ inline function:
```.cpp
JKQTPXYFunctionLineGraph* func1=new JKQTPXYFunctionLineGraph(plot);
func1->setPlotFunctionFunctor([](double t) -> QPointF {
const double a=5;
const double b=4;
const double delta=JKQTPSTATISTICS_PI/4.0;
return QPointF(sin(a*t+delta), sin(b*t));
func1->setPlotFunctionFunctor([](double t) ->QPointF {
return QPointF(
sin(t)*(exp(cos(t))-2.0*cos(4.0*t)-jkqtp_pow5(sin(t/12.0))),
cos(t)*(exp(cos(t))-2.0*cos(4.0*t)-jkqtp_pow5(sin(t/12.0)))
);
});
func1->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
func1->setTRange(0, 12.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function: \"Butterfly Curve\"");
plot->addGraph(func1);
```
Note that here a functor is defined, which calculates the points on a [Lissajous Curve](https://en.wikipedia.org/wiki/Lissajous_curve), i.e. a function mapping a parameter `t` to a two-dimensional point `QPointF` with `x=sin(a*t+delta)`and `y=sin(b*t)`. This function is evaluated on a range of values for `t`, set by
Note that here a functor is defined, which calculates the points on a [Butterfly Curve](https://en.wikipedia.org/wiki/Butterfly_curve_(transcendental)), i.e. a function mapping a parameter `t` to a two-dimensional point `QPointF` with complex functions for x and y. This function is evaluated on a range of values for `t`, set by
```.cpp
func1->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
```
The class uses an adaptive algorithm, which determines by the local slope, at how many points (or how close points) the functor has to be evaluated.
# Simple C++ inline function with Parameters
`JKQTPXYFunctionLineGraph` allows to use more complex functors alternatively: These depend on the variable `t`and a vector of parameters. Here is an example:
```.cpp
func2->setPlotFunctionFunctor([](double t, const QVector<double>& params) ->QPointF {
return QPointF(
3.0*sin(params[0]*t+params[2])+8.0,
3.0*sin(params[1]*t)
);
});
// now we define the 3 parameters of the function
func2->setParamsV(5, 4, JKQTPSTATISTICS_PI/4.0);
// and define the range over which to evaluate
func2->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
plot->addGraph(func1);
```
In the functor we can use the entries in the vector `param` as function parameters. The values in this vector are defined by
```.cpp
// now we define the 3 parameters of the function
func2->setParamsV(5, 4, JKQTPSTATISTICS_PI/4.0);
```
Alternatively they can also be taken from a column in the internal datastore. Then you have to call:
```.cpp
func2->setParameterColumn(ColumnID);
```
instead, where `ColumnID` is the ID of the column with the parameter values.
# Screenshot
@ -36,7 +69,6 @@ This code snippets above result in a plot like this:
# Notes
Just as shown in [examples/functionplot](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/functionplot) for JKQTPXFunctionLineGraph and JKQTPYFunctionLineGraph, different types of functions can be used to plot. Either simple C++ inline functions, that take a `double t` and return a `QPointF`, or functions that additionally take a parameter vector `void* params`. In that case, the parameters may be provided from different sources, as described in [examples/functionplot](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/functionplot) .
This example describes how to draw 2D parametric curves. For (simpler) 1D-functions f(x) or f(y), see [examples/functionplot](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/functionplot) .

View File

@ -27,14 +27,34 @@ int main(int argc, char* argv[])
// the function is defined as C++ inline function
JKQTPXYFunctionLineGraph* func1=new JKQTPXYFunctionLineGraph(plot);
func1->setPlotFunctionFunctor([](double t) ->QPointF {
const double a=5;
const double b=4;
const double delta=JKQTPSTATISTICS_PI/4.0;
return QPointF(sin(a*t+delta), sin(b*t));
return QPointF(
sin(t)*(exp(cos(t))-2.0*cos(4.0*t)-jkqtp_pow5(sin(t/12.0))),
cos(t)*(exp(cos(t))-2.0*cos(4.0*t)-jkqtp_pow5(sin(t/12.0)))
);
});
func1->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
func1->setTRange(0, 12.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function: \"Butterfly Curve\"");
plot->addGraph(func1);
// 3. a second JKQTPXYFunctionLineGraph object shows how to use functions that
// also take a parameter vector, in addition to the dependent variable t
JKQTPXYFunctionLineGraph* func2=new JKQTPXYFunctionLineGraph(plot);
func2->setPlotFunctionFunctor([](double t, const QVector<double>& params) ->QPointF {
return QPointF(
3.0*sin(params[0]*t+params[2])+8.0,
3.0*sin(params[1]*t)
);
});
// now we define the 3 parameters of the function
func2->setParamsV(5, 4, JKQTPSTATISTICS_PI/4.0);
// and define the range over which to evaluate
func2->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
func2->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
plot->addGraph(func2);
// 8. set some axis properties (we use LaTeX for nice equation rendering)
plot->getXAxis()->setAxisLabel(QObject::tr("x-axis"));
plot->getYAxis()->setAxisLabel(QObject::tr("y-axis"));
@ -42,7 +62,7 @@ int main(int argc, char* argv[])
// 4. scale the plot so the graph is contained
plot->setXY(-1.1,1.1,-1.1,1.1);
plot->setXY(-3,12,-3.2,3.2);
// show window and make it a decent size
mainWin.show();

View File

@ -108,3 +108,6 @@ All examples above use the graph class `JKQTPXFunctionLineGraph`, which plots a
![functionplot_fy](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/functionplot_fy.png)
This example describes how to draw 1D functions. For an example of how to draw 2D parametric curves `[x,y]=f(t)`, see [examples/evalcurve](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/evalcurve) .

View File

@ -290,12 +290,22 @@ inline T jkqtp_sqr(const T& v) {
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_pow4(T x) {
template <class T>
inline T jkqtp_pow4(T x) {
const T xx=x*x;
return xx*xx;
}
/*! \brief 5-th power of a number
\ingroup jkqtptools_math_basic
*/
template <class T>
inline T jkqtp_pow5(T x) {
const T xx=x*x;
return xx*xx*x;
}
/*! \brief cube of a number
\ingroup jkqtptools_math_basic

View File

@ -31,29 +31,22 @@
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTBasePlotter* parent):
JKQTPEvaluatedFunctionWithParamsGraphBase(parent)
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase(JKQTBasePlotter* parent):
JKQTPEvaluatedFunctionWithErrorsGraphBase(parent),
drawLine(true),
fillCurve(false),
drawErrorPolygons(false),
drawErrorLines(false)
{
functionType=SpecialFunction::UserFunction;
drawLine=true;
fillCurve=false;
initLineStyle(parent, parentPlotStyle);
initFillStyle(parent, parentPlotStyle);
drawErrorPolygons=false;
drawErrorLines=false;
errorParams=nullptr;
errorColor=getLineColor().lighter();
errorFillColor=getLineColor().lighter();
errorStyle=Qt::SolidLine;
errorLineWidth=1;
errorFillStyle=Qt::SolidPattern;
errorParameterColumn=-1;
if (parent && parentPlotStyle>=0) { // get style settings from parent object
//std::cout<<"got style settings from parent: "<<parentPlotStyle<<std::endl;
@ -66,120 +59,29 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTBasePlotter* parent):
errorFillColor.setAlphaF(0.5);
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPlotter* parent):
JKQTPXFunctionLineGraph(parent->getPlotter())
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase(JKQTPlotter* parent):
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase(parent->getPlotter())
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=f;
functionType=SpecialFunction::UserFunction;
data.clear();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(f, title_, parent->getPlotter())
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=std::move(f);
functionType=SpecialFunction::UserFunction;
data.clear();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(std::move(f), title_, parent->getPlotter())
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title_, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
title=title_;
functionType=type;
setParams(params);
data.clear();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(type, params, title, parent->getPlotter())
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::~JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase()
{
}
JKQTPXFunctionLineGraph::~JKQTPXFunctionLineGraph() {
data.clear();
}
void JKQTPXFunctionLineGraph::setDrawLine(bool __value)
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setDrawLine(bool __value)
{
this->drawLine = __value;
}
bool JKQTPXFunctionLineGraph::getDrawLine() const
bool JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getDrawLine() const
{
return this->drawLine;
}
void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(const jkqtpPlotFunctionType &__value)
{
simplePlotFunction=jkqtpSimplePlotFunctionType();
plotFunction = __value;
functionType=SpecialFunction::UserFunction;
data.clear();
}
void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(const jkqtpSimplePlotFunctionType &__value)
{
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=__value;
functionType=SpecialFunction::UserFunction;
data.clear();
}
void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(jkqtpPlotFunctionType &&__value)
{
simplePlotFunction=jkqtpSimplePlotFunctionType();
plotFunction = std::move(__value);
functionType=SpecialFunction::UserFunction;
data.clear();
}
void JKQTPXFunctionLineGraph::setPlotFunctionFunctor(jkqtpSimplePlotFunctionType &&__value)
{
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=std::move(__value);
functionType=SpecialFunction::UserFunction;
data.clear();
}
jkqtpPlotFunctionType JKQTPXFunctionLineGraph::getPlotFunctionFunctor() const
{
return plotFunction;
}
jkqtpSimplePlotFunctionType JKQTPXFunctionLineGraph::getSimplePlotFunction() const
{
return simplePlotFunction;
}
void JKQTPXFunctionLineGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePen(painter, parent);
p.setJoinStyle(Qt::RoundJoin);
@ -195,73 +97,110 @@ void JKQTPXFunctionLineGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRect
}
QColor JKQTPXFunctionLineGraph::getKeyLabelColor() const {
QColor JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getKeyLabelColor() const {
return getLineColor();
}
bool JKQTPXFunctionLineGraph::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero)
{
smallestGreaterZero=minx=maxx=0; return false;
QBrush JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getErrorBrush(JKQTPEnhancedPainter& /*painter*/) const {
QBrush b;
b.setColor(errorFillColor);
b.setStyle(errorFillStyle);
return b;
}
bool JKQTPXFunctionLineGraph::getYMinMax(double &miny, double &maxy, double &smallestGreaterZero)
{
smallestGreaterZero=miny=maxy=0; return false;
QPen JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getErrorLinePen(JKQTPEnhancedPainter& painter) const {
QPen p;
p.setColor(errorColor);
p.setWidthF(qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*errorLineWidth)));
p.setStyle(errorStyle);
p.setJoinStyle(Qt::RoundJoin);
p.setCapStyle(Qt::RoundCap);
return p;
}
void JKQTPXFunctionLineGraph::createPlotData(bool collectParams) {
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setErrorLineColor(const QColor &__value)
{
this->errorColor = __value;
}
QColor JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getErrorLineColor() const
{
return this->errorColor;
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setErrorFillColor(const QColor &__value)
{
this->errorFillColor = __value;
}
QColor JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getErrorFillColor() const
{
return this->errorFillColor;
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setErrorFillStyle(Qt::BrushStyle __value)
{
this->errorFillStyle = __value;
}
Qt::BrushStyle JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getErrorFillStyle() const
{
return this->errorFillStyle;
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setErrorLineStyle(Qt::PenStyle __value)
{
this->errorStyle = __value;
}
Qt::PenStyle JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getErrorLineStyle() const
{
return this->errorStyle;
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setErrorLineWidth(double __value)
{
this->errorLineWidth = __value;
}
double JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getErrorLineWidth() const
{
return this->errorLineWidth;
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setColor(QColor c)
{
setLineColor(c);
c.setAlphaF(0.5);
setHighlightingLineColor(c);
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setDrawErrorPolygons(bool __value)
{
this->drawErrorPolygons = __value;
}
bool JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getDrawErrorPolygons() const
{
return this->drawErrorPolygons;
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::setDrawErrorLines(bool __value)
{
this->drawErrorLines = __value;
}
bool JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::getDrawErrorLines() const
{
return this->drawErrorLines;
}
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::drawXGraph(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPXFunctionLineGraph[%1]::createPlotData()").arg(title));
#endif
data.clear();
if (collectParams) collectParameters();
if (parent==nullptr) return;
if (!plotFunction && !simplePlotFunction) return;
jkqtpSimplePlotFunctionType func;
if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, getInternalParams());
else if (simplePlotFunction) func=simplePlotFunction;
const double xmin=parent->getXMin();
const double xmax=parent->getXMax();
std::function<QPointF(double)> fTransformedFunc= std::bind([&](const JKQTPPlotElement* plot, double x) -> QPointF { return plot->transform(x, func(x)); }, this, std::placeholders::_1);
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
data=evaluator.evaluate(xmin, xmax);
data=JKQTPSimplyfyLineSegemnts(data, dataCleanupMaxAllowedAngleDegree);
}
void JKQTPXFunctionLineGraph::collectParameters()
{
JKQTPEvaluatedFunctionWithParamsGraphBase::collectParameters();
if (parent && errorParameterColumn>=0) {
ierrorparams.clear();
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax= static_cast<int>(datastore->getRows(errorParameterColumn));
for (int i=imin; i<imax; i++) {
double xv=datastore->get(errorParameterColumn,i);
ierrorparams<<xv;
}
int i=ierrorparams.size()-1;
while (i>=0 && !JKQTPIsOKFloat(ierrorparams[i])) {
ierrorparams.remove(i,1);
i--;
}
errorParams=&ierrorparams;
}
}
void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPXFunctionLineGraph::draw");
JKQTPAutoOutputTimer jkaaot("JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::drawXGraph");
#endif
if (parent==nullptr) return;
JKQTPDatastore* datastore=parent->getDatastore();
@ -271,6 +210,8 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
createPlotData();
//qDebug()<<"plot data created\n";
auto errorPlotFunction=buildErrorFunctorSpec();
drawErrorsBefore(painter);
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
@ -308,11 +249,11 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
if (JKQTPIsOKFloat(x) && JKQTPIsOKFloat(y)) {
double xv=backtransformX(x);
double yv=backtransformY(y);
const double xv=backtransformX(x);
const double yv=backtransformY(y);
double ype=0, yme=0;
if ((drawErrorLines || drawErrorPolygons) && (static_cast<bool>(errorPlotFunction))) {
double e=errorPlotFunction(xv, getInternalErrorParams());
const double e=errorPlotFunction(xv).y();
ype=transformY(yv+e);
yme=transformY(yv-e);
ype=qBound(yami, ype, yama);
@ -384,73 +325,9 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
//std::cout<<"plot done\n";
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPlotter *parent):
JKQTPYFunctionLineGraph(parent->getPlotter())
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(f, title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(f, title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(std::move(f), title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(std::move(f), title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPYFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title_, JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(type, params, title_, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPYFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title_, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(type, params, title_, parent->getPlotter())
{
}
void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::drawYGraph(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPYFunctionLineGraph::draw");
JKQTPAutoOutputTimer jkaaot("JKQTPYFunctionLineGraph::drawYGraph");
#endif
if (parent==nullptr) return;
JKQTPDatastore* datastore=parent->getDatastore();
@ -460,6 +337,8 @@ void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
createPlotData();
//std::cout<<"plot data created\n";
auto errorPlotFunction=buildErrorFunctorSpec();
drawErrorsBefore(painter);
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
@ -497,11 +376,11 @@ void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
//std::cout<<"(xv, yv) = ( "<<xv<<", "<<yv<<" )\n";
if (JKQTPIsOKFloat(x) && JKQTPIsOKFloat(y)) {
double xv=backtransformX(x);
double yv=backtransformY(y);
const double xv=backtransformX(x);
const double yv=backtransformY(y);
double xpe=0, xme=0;
if ((drawErrorLines || drawErrorPolygons) && (static_cast<bool>(errorPlotFunction))) {
double e=errorPlotFunction(yv, getInternalErrorParams());
const double e=errorPlotFunction(yv).x();
xpe=transformX(xv+e);
xme=transformX(xv-e);
xpe=qBound(xami, xpe, xama);
@ -573,124 +452,80 @@ void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
}
void JKQTPYFunctionLineGraph::createPlotData(bool collectParams) {
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(JKQTBasePlotter* parent):
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase(parent)
{
}
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(JKQTPlotter* parent):
JKQTPFunctorLineGraphBase(parent->getPlotter())
{
}
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(parent)
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=f;
data.clear();
if (collectParams) collectParameters();
if (parent==nullptr) return;
if (!plotFunction && !simplePlotFunction) return;
jkqtpSimplePlotFunctionType func;
if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, getInternalParams());
else if (simplePlotFunction) func=simplePlotFunction;
const double ymin=parent->getYMin();
const double ymax=parent->getYMax();
std::function<QPointF(double)> fTransformedFunc= std::bind([&](const JKQTPPlotElement* plot, double y) -> QPointF { return plot->transform(func(y), y); }, this, std::placeholders::_1);
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
data=evaluator.evaluate(ymin, ymax);
data=JKQTPSimplyfyLineSegemnts(data, dataCleanupMaxAllowedAngleDegree);
}
QBrush JKQTPXFunctionLineGraph::getErrorBrush(JKQTPEnhancedPainter& /*painter*/) const {
QBrush b;
b.setColor(errorFillColor);
b.setStyle(errorFillStyle);
return b;
}
QPen JKQTPXFunctionLineGraph::getErrorLinePen(JKQTPEnhancedPainter& painter) const {
QPen p;
p.setColor(errorColor);
p.setWidthF(qMax(JKQTPlotterDrawingTools::ABS_MIN_LINEWIDTH,parent->pt2px(painter, parent->getLineWidthMultiplier()*errorLineWidth)));
p.setStyle(errorStyle);
p.setJoinStyle(Qt::RoundJoin);
p.setCapStyle(Qt::RoundCap);
return p;
}
void JKQTPXFunctionLineGraph::setErrorParams(const QVector<double> &errorParams)
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(f, title_, parent->getPlotter())
{
ierrorparams=errorParams;
setErrorParams(&ierrorparams);
}
void JKQTPXFunctionLineGraph::setErrorParameterColumn(int __value)
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(parent)
{
this->errorParameterColumn = __value;
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=std::move(f);
data.clear();
}
int JKQTPXFunctionLineGraph::getErrorParameterColumn() const
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(std::move(f), title_, parent->getPlotter())
{
return this->errorParameterColumn;
}
void JKQTPXFunctionLineGraph::setErrorParameterColumn(size_t __value) {
this->errorParameterColumn = static_cast<int>(__value);
}
void JKQTPXFunctionLineGraph::setErrorLineColor(const QColor &__value)
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(JKQTPFunctorLineGraphBase::SpecialFunction type, const QVector<double> &params, const QString &title_, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(parent)
{
this->errorColor = __value;
title=title_;
setSpecialFunction(type);
setParams(params);
data.clear();
}
QColor JKQTPXFunctionLineGraph::getErrorLineColor() const
JKQTPFunctorLineGraphBase::JKQTPFunctorLineGraphBase(JKQTPFunctorLineGraphBase::SpecialFunction type, const QVector<double> &params, const QString &title, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(type, params, title, parent->getPlotter())
{
return this->errorColor;
}
void JKQTPXFunctionLineGraph::setErrorFillColor(const QColor &__value)
{
this->errorFillColor = __value;
JKQTPFunctorLineGraphBase::~JKQTPFunctorLineGraphBase() {
}
QColor JKQTPXFunctionLineGraph::getErrorFillColor() const
void JKQTPFunctorLineGraphBase::setSpecialFunction(JKQTPFunctorLineGraphBase::SpecialFunction function)
{
return this->errorFillColor;
}
void JKQTPXFunctionLineGraph::setErrorFillStyle(Qt::BrushStyle __value)
{
this->errorFillStyle = __value;
}
Qt::BrushStyle JKQTPXFunctionLineGraph::getErrorFillStyle() const
{
return this->errorFillStyle;
}
void JKQTPXFunctionLineGraph::setErrorLineStyle(Qt::PenStyle __value)
{
this->errorStyle = __value;
}
Qt::PenStyle JKQTPXFunctionLineGraph::getErrorLineStyle() const
{
return this->errorStyle;
}
void JKQTPXFunctionLineGraph::setErrorLineWidth(double __value)
{
this->errorLineWidth = __value;
}
double JKQTPXFunctionLineGraph::getErrorLineWidth() const
{
return this->errorLineWidth;
}
void JKQTPXFunctionLineGraph::setSpecialFunction(JKQTPXFunctionLineGraph::SpecialFunction function)
{
if (function==JKQTPXFunctionLineGraph::Polynomial) {
if (function==JKQTPFunctorLineGraphBase::Polynomial) {
setPlotFunctionFunctor([](double x, const QVector<double>& param) {
double res=0;
if (param.size()>0) {
@ -705,7 +540,7 @@ void JKQTPXFunctionLineGraph::setSpecialFunction(JKQTPXFunctionLineGraph::Specia
return res;
});
}
else if (function==JKQTPXFunctionLineGraph::Exponential) setPlotFunctionFunctor([](double x, const QVector<double>& param) {
else if (function==JKQTPFunctorLineGraphBase::Exponential) setPlotFunctionFunctor([](double x, const QVector<double>& param) {
double res=0;
if (param.size()>=3) {
res=param.value(0,0)+param.value(1,0)*exp(x/param.value(2,0));
@ -714,7 +549,7 @@ void JKQTPXFunctionLineGraph::setSpecialFunction(JKQTPXFunctionLineGraph::Specia
}
return res;
});
else if (function==JKQTPXFunctionLineGraph::PowerLaw) setPlotFunctionFunctor([](double x, const QVector<double>& param) {
else if (function==JKQTPFunctorLineGraphBase::PowerLaw) setPlotFunctionFunctor([](double x, const QVector<double>& param) {
double res=0;
if (param.size()>=3) {
res=param.value(0,0)+param.value(1,0)*pow(x, param.value(2,1));
@ -728,84 +563,279 @@ void JKQTPXFunctionLineGraph::setSpecialFunction(JKQTPXFunctionLineGraph::Specia
else throw std::runtime_error("unknown special function type");
}
JKQTPXFunctionLineGraph::SpecialFunction JKQTPXFunctionLineGraph::getFunctionType() const
{
return functionType;
}
QVector<double> JKQTPXFunctionLineGraph::getInternalErrorParams() const {
return ierrorparams;
}
void JKQTPXFunctionLineGraph::setDrawErrorPolygons(bool __value)
{
this->drawErrorPolygons = __value;
}
bool JKQTPXFunctionLineGraph::getDrawErrorPolygons() const
{
return this->drawErrorPolygons;
}
void JKQTPXFunctionLineGraph::setDrawErrorLines(bool __value)
{
this->drawErrorLines = __value;
}
bool JKQTPXFunctionLineGraph::getDrawErrorLines() const
{
return this->drawErrorLines;
}
void JKQTPXFunctionLineGraph::setErrorPlotFunction(const jkqtpPlotFunctionType &__value)
void JKQTPFunctorLineGraphBase::setErrorPlotFunction(const jkqtpPlotFunctionType &__value)
{
errorSimplePlotFunction=jkqtpSimplePlotFunctionType();
errorPlotFunction=__value;
data.clear();
}
void JKQTPXFunctionLineGraph::setErrorPlotFunction(jkqtpPlotFunctionType &&__value)
void JKQTPFunctorLineGraphBase::setErrorPlotFunction(jkqtpPlotFunctionType &&__value)
{
errorSimplePlotFunction=jkqtpSimplePlotFunctionType();
errorPlotFunction = std::move(__value);
data.clear();
}
jkqtpPlotFunctionType JKQTPXFunctionLineGraph::getErrorPlotFunction() const
jkqtpPlotFunctionType JKQTPFunctorLineGraphBase::getErrorPlotFunction() const
{
return errorPlotFunction;
}
void JKQTPXFunctionLineGraph::setErrorPlotFunction(const jkqtpSimplePlotFunctionType &__value)
void JKQTPFunctorLineGraphBase::setErrorPlotFunction(const jkqtpSimplePlotFunctionType &__value)
{
errorPlotFunction=jkqtpPlotFunctionType();
errorSimplePlotFunction=__value;
data.clear();
}
void JKQTPXFunctionLineGraph::setErrorPlotFunction(jkqtpSimplePlotFunctionType &&__value)
void JKQTPFunctorLineGraphBase::setErrorPlotFunction(jkqtpSimplePlotFunctionType &&__value)
{
errorPlotFunction=jkqtpPlotFunctionType();
errorSimplePlotFunction = std::move(__value);
data.clear();
}
jkqtpSimplePlotFunctionType JKQTPXFunctionLineGraph::getErrorSimplePlotFunction() const
jkqtpSimplePlotFunctionType JKQTPFunctorLineGraphBase::getErrorSimplePlotFunction() const
{
return errorSimplePlotFunction;
}
void JKQTPXFunctionLineGraph::setErrorParams(void *__value)
void JKQTPFunctorLineGraphBase::setPlotFunctionFunctor(const jkqtpPlotFunctionType &__value)
{
this->errorParams = __value;
simplePlotFunction=jkqtpSimplePlotFunctionType();
plotFunction = __value;
data.clear();
}
void *JKQTPXFunctionLineGraph::getErrorParams() const
void JKQTPFunctorLineGraphBase::setPlotFunctionFunctor(const jkqtpSimplePlotFunctionType &__value)
{
return this->errorParams;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=__value;
data.clear();
}
void JKQTPFunctorLineGraphBase::setPlotFunctionFunctor(jkqtpPlotFunctionType &&__value)
{
simplePlotFunction=jkqtpSimplePlotFunctionType();
plotFunction = std::move(__value);
data.clear();
}
void JKQTPFunctorLineGraphBase::setPlotFunctionFunctor(jkqtpSimplePlotFunctionType &&__value)
{
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=std::move(__value);
data.clear();
}
jkqtpPlotFunctionType JKQTPFunctorLineGraphBase::getPlotFunctionFunctor() const
{
return plotFunction;
}
jkqtpSimplePlotFunctionType JKQTPFunctorLineGraphBase::getSimplePlotFunction() const
{
return simplePlotFunction;
}
bool JKQTPFunctorLineGraphBase::isSimplePlotFunction() const
{
return !static_cast<bool>(plotFunction) && static_cast<bool>(simplePlotFunction);
}
bool JKQTPXFunctionLineGraph::usesColumn(int c) const
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTBasePlotter* parent):
JKQTPFunctorLineGraphBase(parent)
{
return JKQTPEvaluatedFunctionWithParamsGraphBase::usesColumn(c)||(c==errorParameterColumn);
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPlotter* parent):
JKQTPFunctorLineGraphBase(parent)
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(f, title_, parent)
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(f, title_, parent)
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(std::move(f), title_, parent)
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(std::move(f), title_, parent)
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title_, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(type, params, title_, parent)
{
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(type, params, title, parent)
{
}
JKQTPXFunctionLineGraph::~JKQTPXFunctionLineGraph() {
}
void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter &painter)
{
drawXGraph(painter);
}
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec JKQTPXFunctionLineGraph::buildPlotFunctorSpec()
{
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec spec;
if (parent==nullptr) return spec; // return an invalid PlotFunctorSpec
if (!plotFunction && !simplePlotFunction) return spec; // return an invalid PlotFunctorSpec
// range over which to evaluate func
spec.range_start=parent->getXMin();
spec.range_end=parent->getXMax();
// the actual function to use
if (plotFunction) spec.func=std::bind([&](double x, const QVector<double>& p) -> QPointF { return QPointF(x, plotFunction(x, p)); }, std::placeholders::_1, getInternalParams());
else if (simplePlotFunction) spec.func=[&](double x) -> QPointF { return QPointF(x, simplePlotFunction(x)); };
return spec;
}
std::function<QPointF (double)> JKQTPXFunctionLineGraph::buildErrorFunctorSpec()
{
std::function<QPointF (double)> spec;
if (parent==nullptr) return spec; // return an invalid PlotFunctorSpec
if (!plotFunction && !simplePlotFunction) return spec; // return an invalid PlotFunctorSpec
// the actual function to use
if (errorPlotFunction) spec=std::bind([&](double x, const QVector<double>& p) -> QPointF { return QPointF(0, errorPlotFunction(x, p)); }, std::placeholders::_1, getInternalParams());
else if (errorSimplePlotFunction) spec=[&](double x) -> QPointF { return QPointF(0, errorSimplePlotFunction(x)); };
return spec;
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPlotter *parent):
JKQTPYFunctionLineGraph(parent->getPlotter())
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(f, title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(f, title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(std::move(f), title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(std::move(f), title, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPYFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title_, JKQTBasePlotter *parent):
JKQTPFunctorLineGraphBase(type, params, title_, parent)
{
}
JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPYFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title_, JKQTPlotter *parent):
JKQTPFunctorLineGraphBase(type, params, title_, parent)
{
}
void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter &painter)
{
drawYGraph(painter);
}
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec JKQTPYFunctionLineGraph::buildPlotFunctorSpec()
{
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec spec;
if (parent==nullptr) return spec; // return an invalid PlotFunctorSpec
if (!plotFunction && !simplePlotFunction) return spec; // return an invalid PlotFunctorSpec
// range over which to evaluate func
spec.range_start=parent->getYMin();
spec.range_end=parent->getYMax();
// the actual function to use
if (plotFunction) spec.func=std::bind([&](double y, const QVector<double>& p) -> QPointF { return QPointF(plotFunction(y, p), y); }, std::placeholders::_1, getInternalParams());
else if (simplePlotFunction) spec.func=[&](double y) -> QPointF { return QPointF(simplePlotFunction(y), y); };
return spec;
}
std::function<QPointF (double)> JKQTPYFunctionLineGraph::buildErrorFunctorSpec()
{
std::function<QPointF (double)> spec;
if (parent==nullptr) return spec; // return an invalid PlotFunctorSpec
if (!plotFunction && !simplePlotFunction) return spec; // return an invalid PlotFunctorSpec
// the actual function to use
if (errorPlotFunction) spec=std::bind([&](double y, const QVector<double>& p) -> QPointF { return QPointF(errorPlotFunction(y, p), 0); }, std::placeholders::_1, getInternalParams());
else if (errorSimplePlotFunction) spec=[&](double y) -> QPointF { return QPointF(errorSimplePlotFunction(y), 0); };
return spec;
}

View File

@ -33,6 +33,118 @@
#define jkqtpgraphsevaluatedfunction_H
/** \brief This class extends JKQTPEvaluatedFunctionWithErrorsGraphBase with functions to draw the graphs and
* set the drawing style
* \ingroup jkqtplotter_functiongraphs
*
* \note Since this class is meant as a base for both f(x)- and f(y)-functions, it cannot
* implememt JKQTPGraph::draw(). Therefore it provides two implementations drawXGraph()
* and drawYGraph() and the user has to decide in the concrete graph class, which one to call
* (or whether to do the drawing completely different).
*
* \see e.g. JKQTPXFunctionLineGraph for a concrete implementation
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase: public JKQTPEvaluatedFunctionWithErrorsGraphBase, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase(JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase() override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/*! \copydoc drawLine */
bool getDrawLine() const;
/*! \copydoc drawErrorPolygons */
bool getDrawErrorPolygons() const;
/*! \copydoc drawErrorLines */
bool getDrawErrorLines() const;
/*! \copydoc errorColor */
virtual QColor getErrorLineColor() const;
/*! \copydoc errorFillColor */
virtual QColor getErrorFillColor() const;
/*! \copydoc errorFillStyle */
virtual Qt::BrushStyle getErrorFillStyle() const;
/*! \copydoc errorStyle */
virtual Qt::PenStyle getErrorLineStyle() const;
/*! \copydoc errorLineWidth */
virtual double getErrorLineWidth() const;
public slots:
/*! \brief set color, fill color and error color at the same time */
void setColor(QColor c);
/*! \copydoc drawLine */
void setDrawLine(bool __value);
/*! \copydoc drawErrorPolygons */
void setDrawErrorPolygons(bool __value);
/*! \copydoc drawErrorLines */
void setDrawErrorLines(bool __value);
/*! \copydoc errorColor */
virtual void setErrorLineColor(const QColor & __value);
/*! \copydoc errorFillColor */
virtual void setErrorFillColor(const QColor & __value);
/*! \copydoc errorFillStyle */
virtual void setErrorFillStyle(Qt::BrushStyle __value);
/*! \copydoc errorStyle */
virtual void setErrorLineStyle(Qt::PenStyle __value);
/*! \copydoc errorLineWidth */
virtual void setErrorLineWidth(double __value);
protected:
/** \brief plots the graph to the plotter object specified as parent */
void drawXGraph(JKQTPEnhancedPainter& painter);
/** \brief plots the graph to the plotter object specified as parent */
void drawYGraph(JKQTPEnhancedPainter& painter);
/** \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 indicates whether an error polygon should be drawn */
bool drawErrorPolygons;
/** \brief indicates whether error lines should be drawn */
bool drawErrorLines;
/** \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 getErrorBrush(JKQTPEnhancedPainter& painter) const;
QPen getErrorLinePen(JKQTPEnhancedPainter &painter) const;
};
/*! \brief type of functions that may be plotted by JKQTPXFunctionLineGraph and JKQTPYFunctionLineGraph
@ -54,84 +166,43 @@ typedef std::function<double(double, const QVector<double>&)> jkqtpPlotFunctionT
typedef std::function<double(double)> jkqtpSimplePlotFunctionType;
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ y=f(x) \f$
\ingroup jkqtplotter_functiongraphs
This class uses the intelligent plotting algorithm for functions, implemented in JKQTPAdaptiveFunctionGraphEvaluator.
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.
Finally the obtained data is cleaned up to reduce the amount of points, by deleting a point, when it leads to an
angle between consecutive line-segments of less than dataCleanupMaxAllowedAngleDegree.
The following image shows some example graphs:
\image html plot_functionplots.png
\see \ref JKQTPlotterFunctionPlots, JKQTPAdaptiveFunctionGraphEvaluator, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression()
/** \brief extends JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase with the capabilities to define functions from C++-functors
* of type jkqtpSimplePlotFunctionType or jkqtpPlotFunctionType
* \ingroup jkqtplotter_functiongraphs
*
* \see JKQTPXFunctionLineGraph and JKQTPYFunctionLineGraph for a concrete implementation
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunctionWithParamsGraphBase, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
class JKQTPLOTTER_LIB_EXPORT JKQTPFunctorLineGraphBase: public JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase {
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$ */
UserFunction, /*!< \brief no special function but the function is provided by the user */
};
/** \brief class constructor */
JKQTPXFunctionLineGraph(JKQTBasePlotter* parent=nullptr);
JKQTPFunctorLineGraphBase(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(JKQTPlotter* parent);
JKQTPFunctorLineGraphBase(JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTBasePlotter* parent=nullptr);
JKQTPFunctorLineGraphBase(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTPlotter* parent);
JKQTPFunctorLineGraphBase(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTBasePlotter* parent=nullptr);
JKQTPFunctorLineGraphBase(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTPlotter* parent);
JKQTPFunctorLineGraphBase(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTBasePlotter* parent);
JKQTPFunctorLineGraphBase(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTBasePlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTPlotter* parent);
JKQTPFunctorLineGraphBase(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPXFunctionLineGraph() override;
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/** \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) override;
/** \brief get the maximum and minimum y-value of the graph
*/
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
/*! \brief set color, fill color and error color at the same time */
void setColor(QColor c);
/*! \copydoc drawLine */
void setDrawLine(bool __value);
/*! \copydoc drawLine */
bool getDrawLine() const;
virtual ~JKQTPFunctorLineGraphBase() override;
/** \brief sets a functor to be plotted
*
@ -153,23 +224,20 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct
* \see simplePlotFunction
*/
virtual void setPlotFunctionFunctor (const jkqtpSimplePlotFunctionType & __value);
/*! \copydoc plotFunction */ \
/*! \copydoc plotFunction
*
* \see isSimplePlotFunction() */ \
virtual jkqtpPlotFunctionType getPlotFunctionFunctor () const;
/*! \copydoc simplePlotFunction */ \
/*! \copydoc simplePlotFunction
*
* \see isSimplePlotFunction() */ \
virtual jkqtpSimplePlotFunctionType getSimplePlotFunction () const;
/** \brief returns whether the plot function was defined as a jkqtpSimpleParametricCurveFunctionType (\c true ) or
* a jkqtpParametricCurveFunctionType (\c false ) */
bool isSimplePlotFunction() const;
/** \brief returns the currently set internal parameter vector */
QVector<double> getInternalErrorParams() const;
/*! \copydoc drawErrorPolygons */
void setDrawErrorPolygons(bool __value);
/*! \copydoc drawErrorPolygons */
bool getDrawErrorPolygons() const;
/*! \copydoc drawErrorLines */
void setDrawErrorLines(bool __value);
/*! \copydoc drawErrorLines */
bool getDrawErrorLines() const;
/** \brief sets a functor to be used for calculating errors
*
* \see errorPlotFunction
@ -194,100 +262,73 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct
virtual void setErrorPlotFunction (const jkqtpSimplePlotFunctionType & __value);
/*! \copydoc errorSimplePlotFunction */ \
virtual jkqtpSimplePlotFunctionType getErrorSimplePlotFunction () const;
/*! \copydoc errorParams */
virtual void setErrorParams(void* __value);
/*! \copydoc errorParams */
void *getErrorParams() const;
/** \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 setErrorParams(const QVector<double>& errorParams);
/*! \copydoc errorParameterColumn */
void setErrorParameterColumn(int __value);
/*! \copydoc errorParameterColumn */
int getErrorParameterColumn() const;
/*! \copydoc errorParameterColumn */
void setErrorParameterColumn (size_t __value);
/*! \copydoc errorColor */
virtual void setErrorLineColor(const QColor & __value);
/*! \copydoc errorColor */
virtual QColor getErrorLineColor() const;
/*! \copydoc errorFillColor */
virtual void setErrorFillColor(const QColor & __value);
/*! \copydoc errorFillColor */
virtual QColor getErrorFillColor() const;
/*! \copydoc errorFillStyle */
virtual void setErrorFillStyle(Qt::BrushStyle __value);
/*! \copydoc errorFillStyle */
virtual Qt::BrushStyle getErrorFillStyle() const;
/*! \copydoc errorStyle */
virtual void setErrorLineStyle(Qt::PenStyle __value);
/*! \copydoc errorStyle */
virtual Qt::PenStyle getErrorLineStyle() const;
/*! \copydoc errorLineWidth */
virtual void setErrorLineWidth(double __value);
/*! \copydoc errorLineWidth */
virtual double getErrorLineWidth() const;
/** \copydoc JKQTPGraph::usesColumn() */
virtual bool usesColumn(int c) const override;
/** \brief sets function to the given special function */
void setSpecialFunction(SpecialFunction function);
/** \brief returns, which special function is set (or if any is set) */
SpecialFunction getFunctionType() const;
protected:
/** \brief ensure that current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) are stored in iparams and ierrorparams */
virtual void collectParameters() override;
/** \brief fill the data array with data from the function plotFunction */
virtual void createPlotData( bool collectParams=true) override;
/** \brief if set, the values from this datatsore column are used for the parameters \c p1 , \c p2 , \c p3 , ... of the error plot function */
int errorParameterColumn;
/** \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 a simple function to be plotted, simplified form without parameters */
jkqtpSimplePlotFunctionType simplePlotFunction;
/** \brief indicates whether a special function is set (and if so, which one), or a user-supplied function */
SpecialFunction functionType;
/** \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 this function calculates the error at a given position, simplified form without parameters */
jkqtpSimplePlotFunctionType errorSimplePlotFunction;
/** \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;
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ y=f(x) \f$
\ingroup jkqtplotter_functiongraphs
This class uses the intelligent plotting algorithm for functions, implemented in JKQTPAdaptiveFunctionGraphEvaluator.
The following image shows some example graphs:
\image html plot_functionplots.png
\see \ref JKQTPlotterFunctionPlots, JKQTPAdaptiveFunctionGraphEvaluator, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression()
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPFunctorLineGraphBase {
Q_OBJECT
public:
QBrush getErrorBrush(JKQTPEnhancedPainter& painter) const;
QPen getErrorLinePen(JKQTPEnhancedPainter &painter) const;
/** \brief internal storage for the current error function parameters for errorPlotFunction (which may stem from different sources, as direct data, a datastore column ...) */
QVector<double> ierrorparams;
/** \brief class constructor */
JKQTPXFunctionLineGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType & f, const QString& title, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTBasePlotter* parent);
/** \brief class constructor */
JKQTPXFunctionLineGraph(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPXFunctionLineGraph() override;
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
protected:
/** \copydoc JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec() */
virtual PlotFunctorSpec buildPlotFunctorSpec() override;
/** \copydoc JKQTPEvaluatedFunctionWithErrorsGraphBase::buildPlotFunctorSpec() */
virtual std::function<QPointF(double)> buildErrorFunctorSpec() override;
};
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$
@ -299,7 +340,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct
\see \ref JKQTPlotterFunctionPlots , JKQTPXFunctionLineGraph, JKQTPXYFunctionLineGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPYFunctionLineGraph: public JKQTPXFunctionLineGraph {
class JKQTPLOTTER_LIB_EXPORT JKQTPYFunctionLineGraph: public JKQTPFunctorLineGraphBase {
Q_OBJECT
public:
/** \brief class constructor */
@ -323,8 +364,11 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPYFunctionLineGraph: public JKQTPXFunctionLineG
virtual void draw(JKQTPEnhancedPainter& painter) override;
protected:
/** \brief fill the data array with data from the function plotFunction */
virtual void createPlotData( bool collectParams=true) override;
/** \copydoc JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec() */
virtual PlotFunctorSpec buildPlotFunctorSpec() override;
/** \copydoc JKQTPEvaluatedFunctionWithErrorsGraphBase::buildPlotFunctorSpec() */
virtual std::function<QPointF(double)> buildErrorFunctorSpec() override;
};

View File

@ -35,16 +35,17 @@
JKQTPEvaluatedFunctionGraphBase::JKQTPEvaluatedFunctionGraphBase(JKQTBasePlotter* parent):
JKQTPGraph(parent)
JKQTPGraph(parent),
parameterColumn(-1),
minSamples(50),
maxRefinementDegree(5),
slopeTolerance(0.005),
minPixelPerSample(32),
dataCleanupMaxAllowedAngleDegree(0.2),
displaySamplePoints(false)
{
minSamples=50;
maxRefinementDegree=5;
slopeTolerance=0.005;
minPixelPerSample=32;
dataCleanupMaxAllowedAngleDegree=0.2;
displaySamplePoints=false;
data.clear();
iparams.clear();
}
JKQTPEvaluatedFunctionGraphBase::JKQTPEvaluatedFunctionGraphBase(JKQTPlotter* parent):
@ -127,6 +128,24 @@ void JKQTPEvaluatedFunctionGraphBase::setDisplaySamplePoints(bool __value)
this->displaySamplePoints = __value;
}
void JKQTPEvaluatedFunctionGraphBase::createPlotData(bool collectParams)
{
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPEvaluatedFunctionWithErrorsGraphBase[%1]::createPlotData()").arg(title));
#endif
data.clear();
if (collectParams) collectParameters();
PlotFunctorSpec plotfunc= buildPlotFunctorSpec();
if (plotfunc.isValid()) {
std::function<QPointF(double)> fTransformedFunc= std::bind([plotfunc](const JKQTPPlotElement* plot, double t) -> QPointF { return plot->transform(plotfunc.func(t)); }, this, std::placeholders::_1);
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
data=evaluator.evaluate(plotfunc.range_start, plotfunc.range_end);
data=JKQTPSimplyfyLineSegemnts(data, dataCleanupMaxAllowedAngleDegree);
}
}
bool JKQTPEvaluatedFunctionGraphBase::getDisplaySamplePoints() const
{
return this->displaySamplePoints;
@ -181,25 +200,7 @@ bool JKQTPEvaluatedFunctionGraphBase::getYMinMax(double &miny, double &maxy, dou
}
JKQTPEvaluatedFunctionWithParamsGraphBase::JKQTPEvaluatedFunctionWithParamsGraphBase(JKQTBasePlotter *parent):
parameterColumn(-1)
{
}
JKQTPEvaluatedFunctionWithParamsGraphBase::JKQTPEvaluatedFunctionWithParamsGraphBase(JKQTPlotter *parent):
JKQTPEvaluatedFunctionWithParamsGraphBase(parent->getPlotter())
{
}
JKQTPEvaluatedFunctionWithParamsGraphBase::~JKQTPEvaluatedFunctionWithParamsGraphBase()
{
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::collectParameters()
void JKQTPEvaluatedFunctionGraphBase::collectParameters()
{
if (parent && parameterColumn>=0) {
iparams.clear();
@ -221,67 +222,195 @@ void JKQTPEvaluatedFunctionWithParamsGraphBase::collectParameters()
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParams(const QVector<double> &params)
void JKQTPEvaluatedFunctionGraphBase::setParams(const QVector<double> &params)
{
iparams=params;
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setCopiedParams(const double *params, int N)
void JKQTPEvaluatedFunctionGraphBase::setCopiedParams(const double *params, int N)
{
QVector<double> v;
for (int i=0; i<N; i++) { v<<params[i]; }
setParams(v);
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParamsV(double p1) {
void JKQTPEvaluatedFunctionGraphBase::setParamsV(double p1) {
QVector<double> p;
p<<p1;
setParams(p);
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParamsV(double p1, double p2) {
void JKQTPEvaluatedFunctionGraphBase::setParamsV(double p1, double p2) {
QVector<double> p;
p<<p1<<p2;
setParams(p);
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParamsV(double p1, double p2, double p3) {
void JKQTPEvaluatedFunctionGraphBase::setParamsV(double p1, double p2, double p3) {
QVector<double> p;
p<<p1<<p2<<p3;
setParams(p);
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParamsV(double p1, double p2, double p3, double p4) {
void JKQTPEvaluatedFunctionGraphBase::setParamsV(double p1, double p2, double p3, double p4) {
QVector<double> p;
p<<p1<<p2<<p3<<p4;
setParams(p);
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParamsV(double p1, double p2, double p3, double p4, double p5) {
void JKQTPEvaluatedFunctionGraphBase::setParamsV(double p1, double p2, double p3, double p4, double p5) {
QVector<double> p;
p<<p1<<p2<<p3<<p4<<p5;
setParams(p);
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParameterColumn(int __value)
void JKQTPEvaluatedFunctionGraphBase::setParameterColumn(int __value)
{
this->parameterColumn = __value;
}
int JKQTPEvaluatedFunctionWithParamsGraphBase::getParameterColumn() const
int JKQTPEvaluatedFunctionGraphBase::getParameterColumn() const
{
return this->parameterColumn;
}
void JKQTPEvaluatedFunctionWithParamsGraphBase::setParameterColumn(size_t __value) {
void JKQTPEvaluatedFunctionGraphBase::setParameterColumn(size_t __value) {
this->parameterColumn = static_cast<int>(__value);
}
QVector<double> JKQTPEvaluatedFunctionWithParamsGraphBase::getInternalParams() const {
const QVector<double>& JKQTPEvaluatedFunctionGraphBase::getInternalParams() const {
return iparams;
}
bool JKQTPEvaluatedFunctionWithParamsGraphBase::usesColumn(int c) const
QVector<double> &JKQTPEvaluatedFunctionGraphBase::getInternalParams()
{
return iparams;
}
bool JKQTPEvaluatedFunctionGraphBase::usesColumn(int c) const
{
return (c==parameterColumn);
}
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec::PlotFunctorSpec():
func(),
range_start(0),
range_end(0)
{
}
bool JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec::isValid() const
{
return static_cast<bool>(func) && (fabs(range_end-range_start)>0);
}
JKQTPEvaluatedFunctionWithErrorsGraphBase::JKQTPEvaluatedFunctionWithErrorsGraphBase(JKQTBasePlotter *parent):
JKQTPEvaluatedFunctionGraphBase(parent),
errorParameterColumn(-1)
{
}
JKQTPEvaluatedFunctionWithErrorsGraphBase::JKQTPEvaluatedFunctionWithErrorsGraphBase(JKQTPlotter *parent):
JKQTPEvaluatedFunctionWithErrorsGraphBase(parent->getPlotter())
{
}
JKQTPEvaluatedFunctionWithErrorsGraphBase::~JKQTPEvaluatedFunctionWithErrorsGraphBase()
{
}
const QVector<double>& JKQTPEvaluatedFunctionWithErrorsGraphBase::getInternalErrorParams() const {
return ierrorparams;
}
QVector<double>& JKQTPEvaluatedFunctionWithErrorsGraphBase::getInternalErrorParams() {
return ierrorparams;
}
bool JKQTPEvaluatedFunctionWithErrorsGraphBase::usesColumn(int c) const
{
return JKQTPEvaluatedFunctionGraphBase::usesColumn(c)||(c==errorParameterColumn);
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParams(const QVector<double> &errorParams)
{
ierrorparams=errorParams;
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParameterColumn(int __value)
{
this->errorParameterColumn = __value;
}
int JKQTPEvaluatedFunctionWithErrorsGraphBase::getErrorParameterColumn() const
{
return this->errorParameterColumn;
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParameterColumn(size_t __value) {
this->errorParameterColumn = static_cast<int>(__value);
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParamsV(double p1)
{
QVector<double> p;
p<<p1;
setErrorParams(p);
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParamsV(double p1, double p2)
{
QVector<double> p;
p<<p1<<p2;
setErrorParams(p);
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParamsV(double p1, double p2, double p3)
{
QVector<double> p;
p<<p1<<p2<<p3;
setErrorParams(p);
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParamsV(double p1, double p2, double p3, double p4)
{
QVector<double> p;
p<<p1<<p2<<p3<<p4;
setErrorParams(p);
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::setErrorParamsV(double p1, double p2, double p3, double p4, double p5)
{
QVector<double> p;
p<<p1<<p2<<p3<<p4<<p5;
setErrorParams(p);
}
void JKQTPEvaluatedFunctionWithErrorsGraphBase::collectParameters()
{
JKQTPEvaluatedFunctionGraphBase::collectParameters();
if (parent && errorParameterColumn>=0) {
ierrorparams.clear();
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax= static_cast<int>(datastore->getRows(errorParameterColumn));
for (int i=imin; i<imax; i++) {
double xv=datastore->get(errorParameterColumn,i);
ierrorparams<<xv;
}
int i=ierrorparams.size()-1;
while (i>=0 && !JKQTPIsOKFloat(ierrorparams[i])) {
ierrorparams.remove(i,1);
i--;
}
}
}

View File

@ -34,10 +34,26 @@
/** \brief Base class for graph classes that evaluate a mathematical function (e.g. defined as a C-fucntion),
/** \brief Base class for graph classes that evaluate a mathematical function (e.g. defined as a C-function),
* using an adaptive plotting algorithm from JKQTPAdaptiveFunctionGraphEvaluator
* \ingroup jkqtplotter_functiongraphs
*
* This class always plots a general 2D-graph \f$ [x,y]=\vec{f}(t) \f$ , which is calculated in dependence of
* a parameter \f$ t \f$ . This parametrization is general enough to cover the cases of parametric function, as well as
* x- and y-dependent function graphs:
* - plot a function \f$ f(x) \f$ i.e. the plot points will be \f$ [x, f(x)] \f$
* and the value rage will be the x-axis range. This is implemented by e.g. JKQTPXFunctionLineGraph.
* - plot a function \f$ f(y) \f$ i.e. the plot points will be \f$ [f(y), y] \f$
* and the value rage will be the y-axis range. This is implemented by e.g. JKQTPYFunctionLineGraph.
* - plot a function \f$ [x,y]=\vec{f}(t) \f$ i.e. the plot points will be \f$ \vec{f}(t) \f$
* and the value rage will be a user-defined range for \f$ gt \f$.
* This is implemented by e.g. JKQTPXYFunctionLineGraph.
* .
*
* In order to implement a special cas, one has to override/implement buildPlotFunctorSpec(), which
* returns a functor and a value-range that can represent the cases above.
*
*
* This class uses the intelligent plotting algorithm for functions, implemented in JKQTPAdaptiveFunctionGraphEvaluator.
* 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$
@ -50,6 +66,9 @@
* angle between consecutive line-segments of less than dataCleanupMaxAllowedAngleDegree.
*
*
*
*
*
* \see JKQTPAdaptiveFunctionGraphEvaluator, JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionGraphBase: public JKQTPGraph {
@ -75,6 +94,21 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionGraphBase: public JKQTPGraph
*/
virtual bool getYMinMax(double& miny, double& maxy, double& smallestGreaterZero) override;
/** \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!!!) */
virtual void setParams(const QVector<double>& params);
/** \brief sets the params from a copy of the given array of length \a N */
void setCopiedParams(const double* params, int N);
/** \brief returns the currently set internal parameter vector */
const QVector<double>& getInternalParams() const;
/** \brief returns the currently set internal parameter vector */
QVector<double>& getInternalParams();
/** \copydoc parameterColumn */
int getParameterColumn() const;
/** \copydoc JKQTPGraph::usesColumn() */
virtual bool usesColumn(int c) const override;
/** \copydoc minSamples */
unsigned int getMinSamples() const;
@ -102,12 +136,73 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionGraphBase: public JKQTPGraph
/** \copydoc displaySamplePoints */
void setDisplaySamplePoints(bool __value);
/** \brief set an internal parameter vector as function parameters, initialized with {p1} */
void setParamsV(double p1);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2} */
void setParamsV(double p1, double p2);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2,p3} */
void setParamsV(double p1, double p2, double p3);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2,p3,p4} */
void setParamsV(double p1, double p2, double p3, double p4);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2,p3,p4,p5} */
void setParamsV(double p1, double p2, double p3, double p4, double p5);
/** \copydoc parameterColumn */
void setParameterColumn(int __value);
/** \copydoc parameterColumn */
void setParameterColumn (size_t __value);
protected:
/** \brief plot data calculated by createPlotData(), i.e. the datapoints \f$ \mbox{transform}\left(x, y=f(x, \vec{p})\right) \f$ to be plotted */
QVector<QPointF> data;
/** \brief specifies an internal plot functor \see buildPlotFunctor() */
struct PlotFunctorSpec {
/** brief construct an in-valid PlotFunctorSpec ... will become valid, by assigning a non-zero range and a plot-function */
PlotFunctorSpec();
/** \brief calculates the points \f$ [x,y] \f$ on the function graph, in dependence on
* a dependent parameter variable, could be e.g. \f$ [x, f(x)] \f$ for plotting
* a function \f$ f(x) \f$ over the x-axis. */
std::function<QPointF(double)> func;
/** \brief lower bound for the dependent parameter variable of func */
double range_start;
/** \brief upper bound for the dependent parameter variable of func */
double range_end;
bool isValid() const;
};
/** \brief this function returns a functor that is used to generate the plot data
* in coordinate space, based on a range of the dependent variable in coordinate space.
* In addition it also contains the value range over which to evaluate the functor PlotFunctorSpec::func
*
* This function has to be overridden by each class. Depending on the way that class defines
* the actual plot function, this function has to compose its return type in different ways.
* The three most common ways are:
* - plot a function \f$ f(x) \f$ i.e. the plot points will be \f$ [x, f(x)] \f$
* and the value rage will be the x-axis range. This is implemented by e.g. JKQTPXFunctionLineGraph.
* - plot a function \f$ f(y) \f$ i.e. the plot points will be \f$ [f(y), y] \f$
* and the value rage will be the y-axis range. This is implemented by e.g. JKQTPYFunctionLineGraph.
* - plot a function \f$ [x,y]=\vec{f}(t) \f$ i.e. the plot points will be \f$ \vec{f}(t) \f$
* and the value rage will be a user-defined range for \f$ gt \f$.
* This is implemented by e.g. JKQTPXYFunctionLineGraph.
* .
*/
virtual PlotFunctorSpec buildPlotFunctorSpec() =0;
/** \brief ensure that current function parameters for a plot function (which may stem from different sources, as direct data, a datastore column ...) are stored in iparams */
virtual void collectParameters();
/** \brief draw all the sample points in data as small symbols */
void drawSamplePoints(JKQTPEnhancedPainter &painter, QColor graphColor);
/** \brief fill the data array with data from the function plotFunction */
virtual void createPlotData( bool collectParams=true) =0;
virtual void createPlotData( bool collectParams=true) ;
/** \brief if set, the values from this datatsore column are used for the parameters \c p1 , \c p2 , \c p3 , ... of the plot function */
int parameterColumn;
/** \brief internal storage for the current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) */
QVector<double> iparams;
/** \brief plot data calculated by createPlotData(), i.e. the datapoints \f$ \mbox{transform}\left(x, y=f(x, \vec{p})\right) \f$ to be plotted */
QVector<QPointF> data;
/** \brief the minimum number of points to evaluate the function at */
unsigned int minSamples;
@ -127,66 +222,75 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionGraphBase: public JKQTPGraph
double dataCleanupMaxAllowedAngleDegree;
/** \brief if true [default: off] display the points where the function has been sampled */
bool displaySamplePoints;
/** \brief draw all the sample points in data as small symbols */
void drawSamplePoints(JKQTPEnhancedPainter &painter, QColor graphColor);
};
/** \brief extends JKQTPEvaluatedFunctionGraphBase with a set of functions that support function parameters
/** \brief extends JKQTPEvaluatedFunctionGraphBase with some basic properties (e.g. function parameters)
* for a second function that calculates an error (for drawing error indicators)
* \ingroup jkqtplotter_functiongraphs
*
* When implementing this, you will have to implement buildErrorFunctorSpec() in addition to
* JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec()!
*
* \see JKQTPEvaluatedFunctionGraphBase
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionWithParamsGraphBase: public JKQTPEvaluatedFunctionGraphBase {
class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionWithErrorsGraphBase: public JKQTPEvaluatedFunctionGraphBase {
Q_OBJECT
public:
/** \brief class constructor */
explicit JKQTPEvaluatedFunctionWithParamsGraphBase(JKQTBasePlotter* parent=nullptr);
explicit JKQTPEvaluatedFunctionWithErrorsGraphBase(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
explicit JKQTPEvaluatedFunctionWithParamsGraphBase(JKQTPlotter* parent);
explicit JKQTPEvaluatedFunctionWithErrorsGraphBase(JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPEvaluatedFunctionWithParamsGraphBase();
virtual ~JKQTPEvaluatedFunctionWithErrorsGraphBase();
/** \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!!!) */
virtual void setParams(const QVector<double>& params);
/** \brief sets the params from a copy of the given array of length \a N */
void setCopiedParams(const double* params, int N);
/** \copydoc errorParameterColumn */
int getErrorParameterColumn() const;
/** \brief returns the currently set internal parameter vector */
QVector<double> getInternalParams() const;
/** \copydoc parameterColumn */
int getParameterColumn() const;
const QVector<double>& getInternalErrorParams() const;
/** \brief returns the currently set internal parameter vector */
QVector<double>& getInternalErrorParams();
/** \copydoc JKQTPGraph::usesColumn() */
virtual bool usesColumn(int c) const override;
public slots:
/** \brief set an internal parameter vector as function parameters, initialized with {p1} */
void setParamsV(double p1);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2} */
void setParamsV(double p1, double p2);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2,p3} */
void setParamsV(double p1, double p2, double p3);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2,p3,p4} */
void setParamsV(double p1, double p2, double p3, double p4);
/** \brief set an internal parameter vector as function parameters, initialized with {p1,p2,p3,p4,p5} */
void setParamsV(double p1, double p2, double p3, double p4, double p5);
/** \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 setErrorParams(const QVector<double>& errorParams);
/** \copydoc errorParameterColumn */
void setErrorParameterColumn(int __value);
/** \copydoc errorParameterColumn */
void setErrorParameterColumn (size_t __value);
/** \brief set the internal error function parameters to {p1} */
void setErrorParamsV(double p1);
/** \brief set the internal error function parameters to {p1,p2} */
void setErrorParamsV(double p1, double p2);
/** \brief set the internal error function parameters to {p1,p2,p3} */
void setErrorParamsV(double p1, double p2, double p3);
/** \brief set the internal error function parameters to {p1,p2,p3,p4} */
void setErrorParamsV(double p1, double p2, double p3, double p4);
/** \brief set the internal error function parameters to {p1,p2,p3,p4,p5} */
void setErrorParamsV(double p1, double p2, double p3, double p4, double p5);
/** \copydoc parameterColumn */
void setParameterColumn(int __value);
/** \copydoc parameterColumn */
void setParameterColumn (size_t __value);
protected:
/** \brief ensure that current function parameters for a plot function (which may stem from different sources, as direct data, a datastore column ...) are stored in iparams */
virtual void collectParameters();
/** \brief ensure that current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) are stored in iparams and ierrorparams */
virtual void collectParameters() override;
/** \brief same as JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec(), but for error functions.
*
* The functor, returned by this function should calculate the error of the function (in x- and y-direction)
* for every value \f$ t \f$ of the actual function.
*
* The parameter range is the same as for JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec()
*
* \see JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec()
*/
virtual std::function<QPointF(double)> buildErrorFunctorSpec() =0;
/** \brief if set, the values from this datatsore column are used for the parameters \c p1 , \c p2 , \c p3 , ... of the plot function */
int parameterColumn;
/** \brief internal storage for the current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) */
QVector<double> iparams;
/** \brief if set, the values from this datatsore column are used for the parameters \c p1 , \c p2 , \c p3 , ... of the error plot function */
int errorParameterColumn;
/** \brief internal storage for the current error function parameters for errorPlotFunction (which may stem from different sources, as direct data, a datastore column ...) */
QVector<double> ierrorparams;
};

View File

@ -33,14 +33,125 @@
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(JKQTBasePlotter* parent):
JKQTPEvaluatedFunctionWithParamsGraphBase(parent)
JKQTPXYFunctionLineGraphBase::JKQTPXYFunctionLineGraphBase(JKQTBasePlotter* parent):
JKQTPEvaluatedFunctionGraphBase(parent),
tmin(0.0),
tmax(1.0)
{
tmin=0.0;
tmax=1.0;
initLineStyle(parent, parentPlotStyle);
setMaxRefinementDegree(8);
}
JKQTPXYFunctionLineGraphBase::JKQTPXYFunctionLineGraphBase(JKQTPlotter* parent):
JKQTPXYFunctionLineGraphBase(parent->getPlotter())
{
}
JKQTPXYFunctionLineGraphBase::~JKQTPXYFunctionLineGraphBase()
{
}
void JKQTPXYFunctionLineGraphBase::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePen(painter, parent);
p.setJoinStyle(Qt::RoundJoin);
p.setCapStyle(Qt::RoundCap);
QPen np(Qt::NoPen);
const double y=rect.top()+rect.height()/2.0;
painter.setPen(np);
painter.setPen(p);
painter.drawLine(QLineF(rect.left(), y, rect.right(), y));
}
QColor JKQTPXYFunctionLineGraphBase::getKeyLabelColor() const {
return getLineColor();
}
void JKQTPXYFunctionLineGraphBase::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPXYFunctionLineGraph::draw");
#endif
if (parent==nullptr) return;
JKQTPDatastore* datastore=parent->getDatastore();
if (datastore==nullptr) return;
//qDebug()<<"start plot\n";
createPlotData();
//qDebug()<<"plot data created\n";
drawErrorsBefore(painter);
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePen(painter, parent);
QPen np(Qt::NoPen);
{
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(p);
painter.drawPolyline(data);
}
if (displaySamplePoints) drawSamplePoints(painter, getLineColor());
}
drawErrorsAfter(painter);
//std::cout<<"plot done\n";
}
double JKQTPXYFunctionLineGraphBase::getTMin() const
{
return tmin;
}
double JKQTPXYFunctionLineGraphBase::getTMax() const
{
return tmax;
}
void JKQTPXYFunctionLineGraphBase::setTMin(double val)
{
tmin=val;
}
void JKQTPXYFunctionLineGraphBase::setTMax(double val)
{
tmax=val;
}
QPair<double, double> JKQTPXYFunctionLineGraphBase::getTRange() const
{
return QPair<double, double>(tmin,tmax);
}
void JKQTPXYFunctionLineGraphBase::setTRange(double tmin_, double tmax_)
{
tmin=tmin_;
tmax=tmax_;
}
void JKQTPXYFunctionLineGraphBase::setTRange(const QPair<double, double> &range)
{
tmin=range.first;
tmax=range.second;
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(JKQTBasePlotter* parent):
JKQTPXYFunctionLineGraphBase(parent)
{
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(JKQTPlotter* parent):
@ -54,10 +165,9 @@ JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpSimpleParametricCu
{
tmin=tmin_;
tmax=tmax_;
title=title_;
setTitle(title_);
plotFunction=jkqtpParametricCurveFunctionType();
simplePlotFunction=f;
data.clear();
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpSimpleParametricCurveFunctionType &f, const QString &title_, double tmin_, double tmax_, JKQTPlotter *parent):
@ -72,7 +182,7 @@ JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(jkqtpSimpleParametricCurveFun
{
tmin=tmin_;
tmax=tmax_;
title=title_;
setTitle(title_);
plotFunction=jkqtpParametricCurveFunctionType();
simplePlotFunction=std::move(f);
data.clear();
@ -89,7 +199,7 @@ JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(jkqtpParametricCurveFunctionT
{
tmin=tmin_;
tmax=tmax_;
title=title_;
setTitle(title_);
simplePlotFunction=jkqtpSimpleParametricCurveFunctionType();
plotFunction=std::move(f);
data.clear();
@ -106,7 +216,7 @@ JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpParametricCurveFun
{
tmin=tmin_;
tmax=tmax_;
title=title_;
setTitle(title_);
simplePlotFunction=jkqtpSimpleParametricCurveFunctionType();
plotFunction=std::move(f);
data.clear();
@ -119,7 +229,7 @@ JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpParametricCurveFun
}
JKQTPXYFunctionLineGraph::~JKQTPXYFunctionLineGraph() {
data.clear();
}
@ -162,115 +272,26 @@ jkqtpSimpleParametricCurveFunctionType JKQTPXYFunctionLineGraph::getSimplePlotFu
return simplePlotFunction;
}
void JKQTPXYFunctionLineGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) {
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePen(painter, parent);
p.setJoinStyle(Qt::RoundJoin);
p.setCapStyle(Qt::RoundCap);
QPen np(Qt::NoPen);
const double y=rect.top()+rect.height()/2.0;
painter.setPen(np);
painter.setPen(p);
painter.drawLine(QLineF(rect.left(), y, rect.right(), y));
}
QColor JKQTPXYFunctionLineGraph::getKeyLabelColor() const {
return getLineColor();
}
void JKQTPXYFunctionLineGraph::createPlotData(bool collectParams) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaat(QString("JKQTPXYFunctionLineGraph[%1]::createPlotData()").arg(title));
#endif
data.clear();
if (collectParams) collectParameters();
if (parent==nullptr) return;
if (!plotFunction && !simplePlotFunction) return;
jkqtpSimpleParametricCurveFunctionType func;
if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, getInternalParams());
else if (simplePlotFunction) func=simplePlotFunction;
jkqtpSimpleParametricCurveFunctionType fTransformedFunc= std::bind([&](const JKQTPPlotElement* plot, double t) -> QPointF { return plot->transform(func(t)); }, this, std::placeholders::_1);
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
data=evaluator.evaluate(tmin, tmax);
data=JKQTPSimplyfyLineSegemnts(data, dataCleanupMaxAllowedAngleDegree);
}
void JKQTPXYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPXYFunctionLineGraph::draw");
#endif
if (parent==nullptr) return;
JKQTPDatastore* datastore=parent->getDatastore();
if (datastore==nullptr) return;
//qDebug()<<"start plot\n";
createPlotData();
//qDebug()<<"plot data created\n";
drawErrorsBefore(painter);
{
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
QPen p=getLinePen(painter, parent);
QPen np(Qt::NoPen);
{
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
painter.setPen(p);
painter.drawPolyline(data);
}
if (displaySamplePoints) drawSamplePoints(painter, getLineColor());
}
drawErrorsAfter(painter);
//std::cout<<"plot done\n";
}
double JKQTPXYFunctionLineGraph::getTMin() const
bool JKQTPXYFunctionLineGraph::isSimplePlotFunction() const
{
return tmin;
return !static_cast<bool>(plotFunction) && static_cast<bool>(simplePlotFunction);
}
double JKQTPXYFunctionLineGraph::getTMax() const
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec JKQTPXYFunctionLineGraph::buildPlotFunctorSpec()
{
return tmax;
}
void JKQTPXYFunctionLineGraph::setTMin(double val)
{
tmin=val;
}
void JKQTPXYFunctionLineGraph::setTMax(double val)
{
tmax=val;
}
QPair<double, double> JKQTPXYFunctionLineGraph::getTRange() const
{
return QPair<double, double>(tmin,tmax);
}
void JKQTPXYFunctionLineGraph::setTRange(double tmin_, double tmax_)
{
tmin=tmin_;
tmax=tmax_;
}
void JKQTPXYFunctionLineGraph::setTRange(const QPair<double, double> &range)
{
tmin=range.first;
tmax=range.second;
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec spec;
if (!plotFunction && !simplePlotFunction) return spec; // return invalid spec!
// range over which to evaluate func
spec.range_start=tmin;
spec.range_end=tmax;
// the actual function to use
if (plotFunction) spec.func=std::bind(plotFunction, std::placeholders::_1, getInternalParams());
else if (simplePlotFunction) spec.func=simplePlotFunction;
return spec;
}

View File

@ -33,62 +33,136 @@
#define jkqtpevaluatedparametriccurve_H
/** \brief Base class for line plots where the data is taken from a user supplied function \f$ [x,y]=f(t) \f$
* The function is evaluated on a user-specified range \f$ t \in \left[t_\text{min}, t_\text{max}\right] \f$
* \ingroup jkqtplotter_functiongraphs
*
* This class uses the intelligent plotting algorithm for functions, implemented in JKQTPAdaptiveFunctionGraphEvaluator.
* 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.
*
* Finally the obtained data is cleaned up to reduce the amount of points, by deleting a point, when it leads to an
* angle between consecutive line-segments of less than dataCleanupMaxAllowedAngleDegree.
*
*
* \see JKQTPXYFunctionLineGraphBase for a concrete implementation with C++-functors as functions
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraphBase: public JKQTPEvaluatedFunctionGraphBase, public JKQTPGraphLineStyleMixin {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPXYFunctionLineGraphBase(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYFunctionLineGraphBase(JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPXYFunctionLineGraphBase() override;
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/*! \brief type of functions that may be plotted by JKQTPXYFunctionLineGraph
\ingroup jkqtplotter_functiongraphs
/** \brief returns the t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ */
QPair<double,double> getTRange() const;
/** \copydoc tmin */
double getTMin() const;
/** \copydoc tmax */
double getTMax() const;
This is the type of functions \f$ [x,y]=f(t, \vec{p}) \f$ that may be plottet by JKQTPXYFunctionLineGraph.
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.
public slots:
/** \copydoc tmin */
void setTMin(double val);
/** \copydoc tmax */
void setTMax(double val);
/** \brief set the t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ */
void setTRange(double tmin_, double tmax_);
/** \brief set the t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ */
void setTRange(const QPair<double,double>& range);
protected:
/** \brief lower bound of t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ , i.e. \f$ t_\text{min} \f$ , default is 0
*
* \see getTMin(), getTMax(), setTMin(), setTMax(), setTRange(), getTRange() */
double tmin;
/** \brief upper bound of t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ , i.e. \f$ t_\text{min} \f$ , default is 1
*
* \see getTMin(), getTMax(), setTMin(), setTMax(), setTRange(), getTRange() */
double tmax;
};
/** \brief type of functions that may be plotted by JKQTPXYFunctionLineGraph
* \ingroup jkqtplotter_functiongraphs
*
* This is the type of functions \f$ [x,y]=f(t, \vec{p}) \f$ that may be plottet by JKQTPXYFunctionLineGraph.
* 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 std::function<QPointF(double, const QVector<double>)> jkqtpParametricCurveFunctionType;
/*! \brief simplified type of functions (without parameters) that may be plotted by JKQTPXYFunctionLineGraph
\ingroup jkqtplotter_functiongraphs
This is the type of functions \f$ [x,y]=f(t) \f$ that may be plottet by JKQTPXYFunctionLineGraph
and JKQTPYFunctionLineGraph.
/** \brief simplified type of functions (without parameters) that may be plotted by JKQTPXYFunctionLineGraph
* \ingroup jkqtplotter_functiongraphs
*
* This is the type of functions \f$ [x,y]=f(t) \f$ that may be plottet by JKQTPXYFunctionLineGraph
* and JKQTPYFunctionLineGraph.
*/
typedef std::function<QPointF(double)> jkqtpSimpleParametricCurveFunctionType;
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ [x,y]=f(t) \f$
The function is evaluated on a user-specified range \f$ t \in \left[t_\text{min}, t_\text{max}\right] \f$
\ingroup jkqtplotter_functiongraphs
This class uses the intelligent plotting algorithm for functions, implemented in JKQTPAdaptiveFunctionGraphEvaluator.
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.
Finally the obtained data is cleaned up to reduce the amount of points, by deleting a point, when it leads to an
angle between consecutive line-segments of less than dataCleanupMaxAllowedAngleDegree.
the following image shows a Lissajou's fugure drawn with this function
\image html plot_evalcurve.png
The source code for this example is:
\code
JKQTPXYFunctionLineGraph* func1=new JKQTPXYFunctionLineGraph(plot);
func1->setPlotFunctionFunctor([](double t) -> QPointF {
const double a=5;
const double b=4;
const double delta=JKQTPSTATISTICS_PI/4.0;
return QPointF(sin(a*t+delta), sin(b*t));
});
func1->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
\endcode
\see \ref JKQTPlotterEvalCurves , JKQTPAdaptiveFunctionGraphEvaluator, JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph
/** \brief This implements line plots where the data is taken from a user supplied function \f$ [x,y]=f(t) \f$
* The function is evaluated on a user-specified range \f$ t \in \left[t_\text{min}, t_\text{max}\right] \f$
* \ingroup jkqtplotter_functiongraphs
*
* \see JKQTPXYFunctionLineGraphBase for details on the used plotting algorithm
*
* The following image shows a Lissajou's fugure drawn with this function
*
* \image html plot_evalcurve.png
*
* The source code for this example is:
* \code
* JKQTPXYFunctionLineGraph* func1=new JKQTPXYFunctionLineGraph(plot);
* // here we define the C++-functor for [x,y]=f(t)
* func1->setPlotFunctionFunctor([](double t) -> QPointF {
* const double a=5;
* const double b=4;
* const double delta=JKQTPSTATISTICS_PI/4.0;
* return QPointF(sin(a*t+delta), sin(b*t));
* });
* // and define the range over which to evaluate
* func1->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
* \endcode
*
* The source code for the same example, but using functions that also get a parameter vector:
* \code
* JKQTPXYFunctionLineGraph* func1=new JKQTPXYFunctionLineGraph(plot);
* // here we define the C++-functor for [x,y]=f(t)
* func1->setPlotFunctionFunctor([](double t, const QVector<double>& params) -> QPointF {
* return QPointF(3.0*sin(params[0]*t+params[2])+8.0, 3.0*sin(params[1]*t));
* });
* // now we define the 3 parameters of the function
* // parameters are a, b, delta, as in the example above (in that order)
* func1->setParamsV(5, 4, JKQTPSTATISTICS_PI/4.0);
* // and define the range over which to evaluate
* func1->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
* \endcode
*
* \see \ref JKQTPlotterEvalCurves , JKQTPAdaptiveFunctionGraphEvaluator, JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPEvaluatedFunctionWithParamsGraphBase, public JKQTPGraphLineStyleMixin {
class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPXYFunctionLineGraphBase {
Q_OBJECT
public:
@ -117,60 +191,44 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPEvaluatedFunc
/** \brief class destructor */
virtual ~JKQTPXYFunctionLineGraph() override;
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
/** \brief plots a key marker inside the specified rectangle \a rect */
virtual void drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) override;
/** \brief returns the color to be used for the key label */
virtual QColor getKeyLabelColor() const override;
/** \brief sets a functor to be plotted
*
* \see plotFunction
*/
virtual void setPlotFunctionFunctor (jkqtpParametricCurveFunctionType && __value);
void setPlotFunctionFunctor (jkqtpParametricCurveFunctionType && __value);
/** \brief sets a functor to be plotted
*
* \see plotFunction
*/
virtual void setPlotFunctionFunctor (const jkqtpParametricCurveFunctionType & __value);
void setPlotFunctionFunctor (const jkqtpParametricCurveFunctionType & __value);
/** \brief sets a functor to be plotted
*
* \see simplePlotFunction
*/
virtual void setPlotFunctionFunctor (jkqtpSimpleParametricCurveFunctionType && __value);
void setPlotFunctionFunctor (jkqtpSimpleParametricCurveFunctionType && __value);
/** \brief sets a functor to be plotted
*
* \see simplePlotFunction
*/
virtual void setPlotFunctionFunctor (const jkqtpSimpleParametricCurveFunctionType & __value);
/*! \copydoc plotFunction */ \
virtual jkqtpParametricCurveFunctionType getPlotFunctionFunctor () const;
/*! \copydoc simplePlotFunction */ \
virtual jkqtpSimpleParametricCurveFunctionType getSimplePlotFunction () const;
void setPlotFunctionFunctor (const jkqtpSimpleParametricCurveFunctionType & __value);
/** \copydoc plotFunction
*
* \see isSimplePlotFunction() */
jkqtpParametricCurveFunctionType getPlotFunctionFunctor () const;
/** \copydoc simplePlotFunction
*
* \see isSimplePlotFunction() */
jkqtpSimpleParametricCurveFunctionType getSimplePlotFunction () const;
/** \brief returns whether the plot function was defined as a jkqtpSimpleParametricCurveFunctionType (\c true ) or
* a jkqtpParametricCurveFunctionType (\c false ) */
bool isSimplePlotFunction() const;
/*! \copydoc tmin */
double getTMin() const;
/*! \copydoc tmax */
double getTMax() const;
/*! \copydoc tmin */
void setTMin(double val);
/*! \copydoc tmax */
void setTMax(double val);
/*! \brief returns the t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ */
QPair<double,double> getTRange() const;
/*! \brief set the t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ */
void setTRange(double tmin_, double tmax_);
/*! \brief set the t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ */
void setTRange(const QPair<double,double>& range);
protected:
/** \brief lower bound of t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ , i.e. \f$ t_\text{min} \f$ , default is 0 */
double tmin;
/** \brief upper bound of t-value range for \f$ [x,y]=f(t), t \in \left[t_\text{min}, t_\text{max}\right] \f$ , i.e. \f$ t_\text{min} \f$ , default is 1 */
double tmax;
/** \brief fill the data array with data from the function plotFunction */
virtual void createPlotData( bool collectParams=true) override;
/** \copydoc JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec() */
virtual PlotFunctorSpec buildPlotFunctorSpec() override;
/** \brief the function to be plotted */

View File

@ -27,131 +27,73 @@
#include <QElapsedTimer>
#include <utility>
JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraph(JKQTBasePlotter *parent):
JKQTPXFunctionLineGraph(parent)
JKQTPParsedFunctionLineGraphBase::JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName_, const QString& function_, JKQTBasePlotter *parent):
JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase(parent),
dependentVariableName(dependentVariableName_),
function(function_)
{
fdata.parser=new JKQTPMathParser();
fdata.parser=std::make_shared<JKQTPMathParser>();
fdata.node=nullptr;
fdata.varcount=0;
function="";
parameterColumn=-1;
setPlotFunctionFunctor(jkqtpPlotFunctionType(std::bind(&JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &fdata)));
efdata.parser=new JKQTPMathParser();
efdata.parser=std::make_shared<JKQTPMathParser>();
efdata.node=nullptr;
efdata.varcount=0;
errorFunction="";
errorParameterColumn=-1;
setErrorPlotFunction(jkqtpPlotFunctionType(std::bind(&JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &efdata)));
}
JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraph(JKQTPlotter *parent):
JKQTPXParsedFunctionLineGraph(parent->getPlotter())
JKQTPParsedFunctionLineGraphBase::JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName, const QString& function, JKQTPlotter *parent):
JKQTPParsedFunctionLineGraphBase(dependentVariableName, function, parent->getPlotter())
{
}
JKQTPXParsedFunctionLineGraph::~JKQTPXParsedFunctionLineGraph()
JKQTPParsedFunctionLineGraphBase::JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName, JKQTBasePlotter *parent):
JKQTPParsedFunctionLineGraphBase(dependentVariableName, QString(), parent)
{
if (fdata.node) delete fdata.node;
delete fdata.parser;
if (efdata.node) delete efdata.node;
delete efdata.parser;
}
void JKQTPXParsedFunctionLineGraph::setFunction(const QString &__value)
JKQTPParsedFunctionLineGraphBase::JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName, JKQTPlotter *parent):
JKQTPParsedFunctionLineGraphBase(dependentVariableName, QString(), parent)
{
}
JKQTPParsedFunctionLineGraphBase::~JKQTPParsedFunctionLineGraphBase()
{
}
void JKQTPParsedFunctionLineGraphBase::setFunction(const QString &__value)
{
this->function = __value;
}
QString JKQTPXParsedFunctionLineGraph::getFunction() const
QString JKQTPParsedFunctionLineGraphBase::getFunction() const
{
return this->function;
}
void JKQTPXParsedFunctionLineGraph::setErrorFunction(const QString &__value)
void JKQTPParsedFunctionLineGraphBase::setErrorFunction(const QString &__value)
{
this->errorFunction = __value;
}
QString JKQTPXParsedFunctionLineGraph::getErrorFunction() const
QString JKQTPParsedFunctionLineGraphBase::getErrorFunction() const
{
return this->errorFunction;
}
void JKQTPXParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
QString JKQTPParsedFunctionLineGraphBase::getDependentVariableName() const
{
collectParameters();
//QElapsedTimer timer;
//timer.start();
for (int i=0; i<fdata.varcount; i++) {
fdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
}
fdata.varcount=0;
try {
for (const auto& p: getInternalParams()) {
fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), p);
fdata.varcount=fdata.varcount+1;
}
fdata.parser->addVariableDouble(std::string("x"), 0.0);
if (fdata.node) delete fdata.node;
//qint64 t=timer.elapsed();
//qDebug()<<"createPlotData(): adding variables: "<<t<<"ms";
fdata.node=fdata.parser->parse(function.toStdString());
//qDebug()<<"createPlotData(): parsing: "<<timer.elapsed()-t<<"ms";
} catch(std::exception& E) {
qDebug()<<QString("parser error: %1").arg(E.what());
}
//qint64 t0=timer.elapsed();
for (int i=0; i<efdata.varcount; i++) {
efdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
}
efdata.varcount=0;
try {
QVector<double>* errorParameters=static_cast<QVector<double>*>(errorParams);
if (errorParameters) {
for (int i=0; i<errorParameters->size(); i++) {
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), errorParameters->at(i));
efdata.varcount=efdata.varcount+1;
}
}
efdata.parser->addVariableDouble(std::string("x"), 0.0);
if (efdata.node) delete efdata.node;
//qint64 t=timer.elapsed();
//qDebug()<<"createPlotData(): adding variables: "<<t-t0<<"ms";
efdata.node=efdata.parser->parse(errorFunction.toStdString());
//qDebug()<<"createPlotData(): parsing: "<<timer.elapsed()-t<<"ms";
} catch(std::exception& /*E*/) {
//qDebug()<<QString("parser error: %1").arg(E.what());
}
setPlotFunctionFunctor(jkqtpPlotFunctionType(std::bind(&JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &fdata)));
setErrorPlotFunction(jkqtpPlotFunctionType(std::bind(&JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &efdata)));
//qint64 t=timer.elapsed();
JKQTPXFunctionLineGraph::createPlotData(false);
//qDebug()<<"createPlotData(): JKQTPXFunctionLineGraph::createPlotData(): "<<timer.elapsed()-t<<"ms";
/*int count=0;
doublePair* d=data;
while (d!=nullptr) {
count++;
d=d->next;
}
qDebug()<<"refined to "<<count<<" daatapoints";*/
return dependentVariableName;
}
double JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction(double x, const QVector<double>& /*data*/, JKQTPXParsedFunctionLineGraphFunctionData *fdata) {
JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunctionData* d=fdata;//static_cast<JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunctionData*>(data);
double JKQTPParsedFunctionLineGraphBase::evaluateParsedFunction(double t, ParsedFunctionLineGraphFunctionData *fdata) {
JKQTPParsedFunctionLineGraphBase::ParsedFunctionLineGraphFunctionData* d=fdata;//static_cast<JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunctionData*>(data);
if (d && d->parser && d->node) {
try {
d->parser->addVariableDouble("x", x);
d->parser->addVariableDouble(d->dependentVariableName.toStdString(), t);
JKQTPMathParser::jkmpResult r=d->node->evaluate();
if (r.isValid) {
@ -162,8 +104,8 @@ double JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction(doub
}
}
} catch(std::exception& E) {
qDebug()<<QString("parser error: %1").arg(E.what());
/*ok= QMessageBox::critical(this, tr("QuickFit-table"),
qDebug()<<QString("parser error: %1").arg(E.what());
/*ok= QMessageBox::critical(this, tr("QuickFit-table"),
tr("An error occured while parsing the expression '%1' in cell (row, column)=(%3, %4):\n%2\n\n\"OK\" will still go on evaluating\n\"Cancel\" will cancel evaluation for the rest of the cells.").arg(dlgMathExpression->getExpression()).arg(E.what()).arg(row).arg(column),
QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Ok)==QMessageBox::Ok;*/
@ -186,79 +128,152 @@ double JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction(doub
JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraph(JKQTBasePlotter *parent):
JKQTPParsedFunctionLineGraphBase(QString("x"), parent)
{
}
JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraph(JKQTPlotter *parent):
JKQTPParsedFunctionLineGraphBase(QString("x"), parent)
{
}
JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraph(const QString& function, JKQTBasePlotter *parent):
JKQTPParsedFunctionLineGraphBase(QString("x"), function, parent)
{
}
JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraph(const QString& function, JKQTPlotter *parent):
JKQTPParsedFunctionLineGraphBase(QString("x"), function, parent)
{
}
JKQTPXParsedFunctionLineGraph::~JKQTPXParsedFunctionLineGraph()
{
}
void JKQTPXParsedFunctionLineGraph::draw(JKQTPEnhancedPainter &painter)
{
drawXGraph(painter);
}
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec JKQTPXParsedFunctionLineGraph::buildPlotFunctorSpec()
{
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec spec;
if (parent==nullptr) return spec; // return an invalid PlotFunctorSpec
for (int i=0; i<fdata.varcount; i++) {
fdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
}
fdata.varcount=0;
try {
for (const auto& p: getInternalParams()) {
fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), p);
fdata.varcount=fdata.varcount+1;
}
fdata.dependentVariableName=getDependentVariableName();
fdata.parser->addVariableDouble(getDependentVariableName().toStdString(), 0.0);
fdata.node=std::shared_ptr<JKQTPMathParser::jkmpNode>(fdata.parser->parse(function.toStdString()));
} catch(std::exception& E) {
qDebug()<<QString("parser error: %1").arg(E.what());
}
jkqtpSimplePlotFunctionType plotFunction=std::bind(&JKQTPXParsedFunctionLineGraph::evaluateParsedFunction, std::placeholders::_1, &fdata);
// the actual function to use
spec.func=std::bind([=](double x) -> QPointF { return QPointF(0, plotFunction(x)); }, std::placeholders::_1);
return spec;
}
std::function<QPointF (double)> JKQTPXParsedFunctionLineGraph::buildErrorFunctorSpec()
{
std::function<QPointF (double)> spec;
for (int i=0; i<efdata.varcount; i++) {
efdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
}
efdata.varcount=0;
try {
for (const auto& p: getInternalErrorParams()) {
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), p);
efdata.varcount=efdata.varcount+1;
}
efdata.dependentVariableName=getDependentVariableName();
efdata.parser->addVariableDouble(getDependentVariableName().toStdString(), 0.0);
efdata.node=std::shared_ptr<JKQTPMathParser::jkmpNode>(efdata.parser->parse(errorFunction.toStdString()));
} catch(std::exception& /*E*/) {
//qDebug()<<QString("parser error: %1").arg(E.what());
}
jkqtpSimplePlotFunctionType errorPlotFunction=std::bind(&JKQTPXParsedFunctionLineGraph::evaluateParsedFunction, std::placeholders::_1, &efdata);
// the actual function to use
spec=std::bind([=](double x) -> QPointF { return QPointF(0, errorPlotFunction(x)); }, std::placeholders::_1);
return spec;
}
JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraph(JKQTBasePlotter *parent):
JKQTPYFunctionLineGraph(parent)
JKQTPParsedFunctionLineGraphBase(QString("y"), parent)
{
fdata.parser=new JKQTPMathParser();
fdata.node=nullptr;
fdata.varcount=0;
function="";
parameterColumn=-1;
setPlotFunctionFunctor(jkqtpPlotFunctionType(std::bind(&JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &fdata)));
efdata.parser=new JKQTPMathParser();
efdata.node=nullptr;
efdata.varcount=0;
errorFunction="";
errorParameterColumn=-1;
setErrorPlotFunction(jkqtpPlotFunctionType(std::bind(&JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &efdata)));
}
JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraph(JKQTPlotter *parent):
JKQTPYFunctionLineGraph(parent)
JKQTPParsedFunctionLineGraphBase(QString("y"), parent)
{
fdata.parser=new JKQTPMathParser();
fdata.node=nullptr;
fdata.varcount=0;
function="";
parameterColumn=-1;
setPlotFunctionFunctor(jkqtpPlotFunctionType(std::bind(&JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &fdata)));
}
efdata.parser=new JKQTPMathParser();
efdata.node=nullptr;
efdata.varcount=0;
errorFunction="";
errorParameterColumn=-1;
setErrorPlotFunction(jkqtpPlotFunctionType(std::bind(&JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &efdata)));
JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraph(const QString& function, JKQTBasePlotter *parent):
JKQTPParsedFunctionLineGraphBase(QString("y"), function, parent)
{
}
JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraph(const QString& function, JKQTPlotter *parent):
JKQTPParsedFunctionLineGraphBase(QString("y"), function, parent)
{
}
JKQTPYParsedFunctionLineGraph::~JKQTPYParsedFunctionLineGraph()
{
if (fdata.node) delete fdata.node;
delete fdata.parser;
if (efdata.node) delete efdata.node;
delete efdata.parser;
}
void JKQTPYParsedFunctionLineGraph::setFunction(const QString &__value)
void JKQTPYParsedFunctionLineGraph::draw(JKQTPEnhancedPainter &painter)
{
this->function = __value;
drawYGraph(painter);
}
QString JKQTPYParsedFunctionLineGraph::getFunction() const
{
return this->function;
}
void JKQTPYParsedFunctionLineGraph::setErrorFunction(const QString &__value)
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec JKQTPYParsedFunctionLineGraph::buildPlotFunctorSpec()
{
this->errorFunction = __value;
}
JKQTPEvaluatedFunctionGraphBase::PlotFunctorSpec spec;
QString JKQTPYParsedFunctionLineGraph::getErrorFunction() const
{
return this->errorFunction;
}
if (parent==nullptr) return spec; // return an invalid PlotFunctorSpec
void JKQTPYParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
{
collectParameters();
//QElapsedTimer timer;
//timer.start();
for (int i=0; i<fdata.varcount; i++) {
fdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
}
@ -268,82 +283,47 @@ void JKQTPYParsedFunctionLineGraph::createPlotData(bool /*collectParams*/)
fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), p);
fdata.varcount=fdata.varcount+1;
}
fdata.parser->addVariableDouble(std::string("x"), 0.0);
fdata.parser->addVariableDouble(std::string("y"), 0.0);
if (fdata.node) delete fdata.node;
//qint64 t=timer.elapsed();
//qDebug()<<"createPlotData(): adding variables: "<<t<<"ms";
fdata.node=fdata.parser->parse(function.toStdString());
//qDebug()<<"createPlotData(): parsing: "<<timer.elapsed()-t<<"ms";
fdata.dependentVariableName=getDependentVariableName();
fdata.parser->addVariableDouble(getDependentVariableName().toStdString(), 0.0);
fdata.node=std::shared_ptr<JKQTPMathParser::jkmpNode>(fdata.parser->parse(function.toStdString()));
} catch(std::exception& E) {
qDebug()<<QString("parser error: %1").arg(E.what());
}
//qint64 t0=timer.elapsed();
jkqtpSimplePlotFunctionType plotFunction=std::bind(&JKQTPXParsedFunctionLineGraph::evaluateParsedFunction, std::placeholders::_1, &fdata);
// the actual function to use
spec.func=std::bind([=](double y) -> QPointF { return QPointF(plotFunction(y), 0); }, std::placeholders::_1);
// range over which to evaluate func
spec.range_start=parent->getXMin();
spec.range_end=parent->getXMax();
return spec;
}
std::function<QPointF (double)> JKQTPYParsedFunctionLineGraph::buildErrorFunctorSpec()
{
std::function<QPointF (double)> spec;
for (int i=0; i<efdata.varcount; i++) {
efdata.parser->deleteVariable(std::string("p")+jkqtp_inttostr(i+1));
}
efdata.varcount=0;
try {
QVector<double>* errorParameters=static_cast<QVector<double>*>(errorParams);
if (errorParameters) {
for (int i=0; i<errorParameters->size(); i++) {
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), errorParameters->at(i));
efdata.varcount=efdata.varcount+1;
}
for (const auto& p: getInternalErrorParams()) {
efdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(efdata.varcount+1), p);
efdata.varcount=efdata.varcount+1;
}
efdata.parser->addVariableDouble(std::string("x"), 0.0);
efdata.parser->addVariableDouble(std::string("y"), 0.0);
if (efdata.node) delete efdata.node;
//qint64 t=timer.elapsed();
//qDebug()<<"createPlotData(): adding variables: "<<t-t0<<"ms";
efdata.node=efdata.parser->parse(errorFunction.toStdString());
//qDebug()<<"createPlotData(): parsing: "<<timer.elapsed()-t<<"ms";
} catch(std::exception& E) {
qDebug()<<QString("parser error: %1").arg(E.what());
efdata.dependentVariableName=getDependentVariableName();
efdata.parser->addVariableDouble(getDependentVariableName().toStdString(), 0.0);
efdata.node=std::shared_ptr<JKQTPMathParser::jkmpNode>(efdata.parser->parse(errorFunction.toStdString()));
} catch(std::exception& /*E*/) {
//qDebug()<<QString("parser error: %1").arg(E.what());
}
setPlotFunctionFunctor(jkqtpPlotFunctionType(std::bind(&JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &fdata)));
setErrorPlotFunction(jkqtpPlotFunctionType(std::bind(&JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunction, std::placeholders::_1, std::placeholders::_2, &efdata)));
//qint64 t=timer.elapsed();
JKQTPYFunctionLineGraph::createPlotData(false);
//qDebug()<<"createPlotData(): JKQTPYFunctionLineGraph::createPlotData(): "<<timer.elapsed()-t<<"ms";
/*int count=0;
doublePair* d=data;
while (d!=nullptr) {
count++;
d=d->next;
}
qDebug()<<"refined to "<<count<<" daatapoints";*/
}
double JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunction(double x, const QVector<double> & /*data*/, JKQTPYParsedFunctionLineGraphFunctionData *fdata) {
JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunctionData* d=fdata;//static_cast<JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunctionData*>(data);
if (d && d->parser && d->node) {
try {
d->parser->addVariableDouble("x", x);
d->parser->addVariableDouble("y", x);
JKQTPMathParser::jkmpResult r=d->node->evaluate();
if (r.isValid) {
if (r.type==JKQTPMathParser::jkmpBool) {
return r.boolean?1.0:0.0;
} else if (r.type==JKQTPMathParser::jkmpDouble) {
return r.num;
}
}
} catch(std::exception& /*E*/) {
//qDebug()<<QString("parser error: %1").arg(E.what());
/*ok= QMessageBox::critical(this, tr("QuickFit-table"),
tr("An error occured while parsing the expression '%1' in cell (row, column)=(%3, %4):\n%2\n\n\"OK\" will still go on evaluating\n\"Cancel\" will cancel evaluation for the rest of the cells.").arg(dlgMathExpression->getExpression()).arg(E.what()).arg(row).arg(column),
QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Ok)==QMessageBox::Ok;*/
}
}
return NAN;
jkqtpSimplePlotFunctionType errorPlotFunction=std::bind(&JKQTPXParsedFunctionLineGraph::evaluateParsedFunction, std::placeholders::_1, &efdata);
// the actual function to use
spec=std::bind([=](double y) -> QPointF { return QPointF(errorPlotFunction(y), 0); }, std::placeholders::_1);
return spec;
}

View File

@ -34,6 +34,74 @@ class JKQTBasePlotter;
class JKQTPlotter;
/** \brief extends JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase with the capabilities to define functions from strings
* that are parsed by JKQTPMathParser
* \ingroup jkqtplotter_functiongraphs
*
* \see JKQTPXParsedFunctionLineGraph and JKQTPYParsedFunctionLineGraph for a concrete implementation, see also JKQTPMathParser
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPParsedFunctionLineGraphBase: public JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName, const QString& function, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPParsedFunctionLineGraphBase(const QString& dependentVariableName, const QString& function, JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPParsedFunctionLineGraphBase() override;
/** \copydoc function */
QString getFunction() const;
/** \copydoc errorFunction */
QString getErrorFunction() const;
/** \copydoc dependentVariableName */
QString getDependentVariableName() const;
public slots:
/** \copydoc errorFunction */
void setErrorFunction(const QString & __value);
/** \copydoc function */
void setFunction(const QString & __value);
protected:
/** \brief INTERNAL data structure combining a JKQTPMathParser and a JKQTPMathParser::jkmpNode
*/
struct ParsedFunctionLineGraphFunctionData {
std::shared_ptr<JKQTPMathParser> parser;
std::shared_ptr<JKQTPMathParser::jkmpNode> node;
int varcount;
QString dependentVariableName;
};
/** \brief nache of the dependent variable (e.g. x for a function f(x) ) */
QString dependentVariableName;
/** \brief the function to be evaluated for the plot. Use \c x as the free variable, e.g. \c "x^2+2" */
QString function;
/** \brief parser data structure for function */
ParsedFunctionLineGraphFunctionData fdata;
/** \brief the function to be evaluated to add error indicators to the graph. This function is evaluated to an error for every x. Use \c x as the free variable, e.g. \c "x^2+2". */
QString errorFunction;
/** \brief parser data structure for errorFunction */
ParsedFunctionLineGraphFunctionData efdata;
/** \brief implements the actual plot function */
static double evaluateParsedFunction(double x, ParsedFunctionLineGraphFunctionData* fdata) ;
};
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ y=f(x) \f$ The function is defined as a string and parsed by JKMathParser
\ingroup jkqtplotter_parsedFgraphs
@ -45,7 +113,7 @@ class JKQTPlotter;
\see \ref JKQTPlotterParsedFunctionPlot, JKQTPMathParser
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXParsedFunctionLineGraph: public JKQTPXFunctionLineGraph {
class JKQTPLOTTER_LIB_EXPORT JKQTPXParsedFunctionLineGraph: public JKQTPParsedFunctionLineGraphBase {
Q_OBJECT
public:
@ -55,49 +123,26 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXParsedFunctionLineGraph: public JKQTPXFunctio
/** \brief class constructor */
JKQTPXParsedFunctionLineGraph(JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXParsedFunctionLineGraph(const QString& function, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXParsedFunctionLineGraph(const QString& function, JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPXParsedFunctionLineGraph() override;
/*! \copydoc function */
void setFunction(const QString & __value);
/*! \copydoc function */
QString getFunction() const;
/*! \copydoc errorFunction */
void setErrorFunction(const QString & __value);
/*! \copydoc errorFunction */
QString getErrorFunction() const;
/** \brief INTERNAL data structure
* \internal
*/
struct JKQTPXParsedFunctionLineGraphFunctionData {
JKQTPMathParser* parser;
JKQTPMathParser::jkmpNode* node;
int varcount;
};
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
protected:
/** \brief the function to be evaluated for the plot. Use \c x as the free variable, e.g. \c "x^2+2" */
QString function;
JKQTPXParsedFunctionLineGraphFunctionData fdata;
/** \brief the function to be evaluated to add error indicators to the graph. This function is evaluated to an error for every x. Use \c x as the free variable, e.g. \c "x^2+2". */
QString errorFunction;
JKQTPXParsedFunctionLineGraphFunctionData efdata;
// hide functions that should not be used in this class!
using JKQTPXFunctionLineGraph::setPlotFunctionFunctor;
using JKQTPXFunctionLineGraph::setParams;
using JKQTPXFunctionLineGraph::setErrorPlotFunction;
using JKQTPXFunctionLineGraph::setErrorParams;
/** \copydoc JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec() */
virtual PlotFunctorSpec buildPlotFunctorSpec() override;
/** \brief fill the data array with data from the function plotFunction */
virtual void createPlotData(bool collectParams=true) override;
/** \brief implements the actual plot function */
static double JKQTPXParsedFunctionLineGraphFunction(double x, const QVector<double> &data, JKQTPXParsedFunctionLineGraphFunctionData* fdata) ;
/** \copydoc JKQTPEvaluatedFunctionWithErrorsGraphBase::buildPlotFunctorSpec() */
virtual std::function<QPointF(double)> buildErrorFunctorSpec() override;
};
@ -114,7 +159,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXParsedFunctionLineGraph: public JKQTPXFunctio
\see \ref JKQTPlotterParsedFunctionPlot, JKQTPMathParser
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPYParsedFunctionLineGraph: public JKQTPYFunctionLineGraph {
class JKQTPLOTTER_LIB_EXPORT JKQTPYParsedFunctionLineGraph: public JKQTPParsedFunctionLineGraphBase {
Q_OBJECT
public:
@ -124,47 +169,25 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPYParsedFunctionLineGraph: public JKQTPYFunctio
/** \brief class constructor */
JKQTPYParsedFunctionLineGraph(JKQTPlotter* parent);
/** \brief class constructor */
JKQTPYParsedFunctionLineGraph(const QString& function, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPYParsedFunctionLineGraph(const QString& function, JKQTPlotter* parent);
/** \brief class destructor */
virtual ~JKQTPYParsedFunctionLineGraph() override;
/*! \copydoc function */
void setFunction(const QString & __value);
/*! \copydoc function */
QString getFunction() const;
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
/*! \copydoc errorFunction */
void setErrorFunction(const QString & __value);
/*! \copydoc errorFunction */
QString getErrorFunction() const;
/** \brief INTERNAL data structure
* \internal
*/
struct JKQTPYParsedFunctionLineGraphFunctionData {
JKQTPMathParser* parser;
JKQTPMathParser::jkmpNode* node;
int varcount;
};
protected:
/** \brief the function to be evaluated for the plot. Use \c x as the free variable, e.g. \c "x^2+2" */
QString function;
JKQTPYParsedFunctionLineGraphFunctionData fdata;
/** \brief the function to be evaluated to add error indicators to the graph. This function is evaluated to an error for every x. Use \c x as the free variable, e.g. \c "x^2+2". */
QString errorFunction;
JKQTPYParsedFunctionLineGraphFunctionData efdata;
/** \copydoc JKQTPEvaluatedFunctionGraphBase::buildPlotFunctorSpec() */
virtual PlotFunctorSpec buildPlotFunctorSpec() override;
// hide functions that should not be used in this class!
using JKQTPXFunctionLineGraph::setPlotFunctionFunctor;
using JKQTPXFunctionLineGraph::setParams;
using JKQTPXFunctionLineGraph::setErrorPlotFunction;
using JKQTPXFunctionLineGraph::setErrorParams;
/** \brief fill the data array with data from the function plotFunction */
virtual void createPlotData(bool collectParams=true) override;
/** \brief implements the actual plot function */
static double JKQTPYParsedFunctionLineGraphFunction(double x, const QVector<double>& data, JKQTPYParsedFunctionLineGraphFunctionData* fdata);
/** \copydoc JKQTPEvaluatedFunctionWithErrorsGraphBase::buildPlotFunctorSpec() */
virtual std::function<QPointF(double)> buildErrorFunctorSpec() override;
};
#endif // jkqtpgraphsparsedfunction_H

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB