From 414e12920eda5fc72716a31e77e9b55b83ce5b90 Mon Sep 17 00:00:00 2001 From: jkriege2 Date: Sat, 5 Sep 2020 13:47:46 +0200 Subject: [PATCH] - added further base-class JKQTPEvaluatedFunctionWithParamsGraphBase, which extends JKQTPEvaluatedFunctionGraphBase with parameters - modified plot-function with parameters, as the old unsafe way of giving a void* for parameters is no longer necessary with C++-lambdas and std::bind() --- examples/functionplot/README.md | 23 +-- examples/functionplot/functionplot.cpp | 29 +-- .../graphs/jkqtpevaluatedfunction.cpp | 152 +++------------- .../graphs/jkqtpevaluatedfunction.h | 41 +---- .../graphs/jkqtpevaluatedfunctionbase.cpp | 153 ++++++++++++++++ .../graphs/jkqtpevaluatedfunctionbase.h | 131 ++++++++++---- .../graphs/jkqtpevaluatedparametriccurve.cpp | 166 +----------------- .../graphs/jkqtpevaluatedparametriccurve.h | 57 +----- .../graphs/jkqtpparsedfunction.cpp | 22 +-- lib/jkqtplotter/graphs/jkqtpparsedfunction.h | 4 +- 10 files changed, 302 insertions(+), 476 deletions(-) diff --git a/examples/functionplot/README.md b/examples/functionplot/README.md index a4cd1876ee..e854a10b58 100644 --- a/examples/functionplot/README.md +++ b/examples/functionplot/README.md @@ -18,31 +18,14 @@ The first example shows how to plot a C++ inline function: In any such plot function, you can also use parameters, provided via the second parameter. Usually these are "internal parameters", defined by `func2->setParamsV(p0, p1, ...)`: ```.cpp JKQTPXFunctionLineGraph* func2=new JKQTPXFunctionLineGraph(plot); - func2->setPlotFunctionFunctor([](double x, void* params) { - QVector* p=static_cast*>(params); - return p->at(0)*sin(2.0*M_PI*x*p->at(1)); - }); - // here we set the parameters p0, p1 + func2->setPlotFunctionFunctor([](double x, const QVector& p) { + return p.at(0)*sin(2.0*JKQTPSTATISTICS_PI*x*p.at(1)); + }); // here we set the parameters p0, p1 func2->setParamsV(5, 0.2); func2->setTitle("C++-inline function with int. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$"); plot->addGraph(func2); ``` -... but generally any pointer can be used as parameter (the set by `setParameter(static_cast(myDataObject))`): -```.cpp - JKQTPXFunctionLineGraph* func3=new JKQTPXFunctionLineGraph(plot); - func3->setPlotFunctionFunctor([](double x, void* params) { - QMap* p=static_cast*>(params); - return p->value("amplitude")*sin(2.0*M_PI*x*p->value("frequency")); - }); - // here we set the parameters p0, p1 - QMap params3; - params3["amplitude"]=-3; - params3["frequency"]=0.3; - func3->setParams(¶ms3); - func3->setTitle("C++-inline function with ext. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$"); - plot->addGraph(func3); -``` # C++ functors as plot functions diff --git a/examples/functionplot/functionplot.cpp b/examples/functionplot/functionplot.cpp index 93d10d22a2..7698c8a1c3 100644 --- a/examples/functionplot/functionplot.cpp +++ b/examples/functionplot/functionplot.cpp @@ -55,9 +55,8 @@ void drawExample(QApplication& app, const QString& name) { // the function is again defined as C++ inline function, but now uses internal // parameters (handed over to the function as a pointer to QVector TFUNCGRAPH* func2=new TFUNCGRAPH(plot); - func2->setPlotFunctionFunctor([](double x, void* params) { - QVector* p=static_cast*>(params); - return p->at(0)*sin(2.0*JKQTPSTATISTICS_PI*x*p->at(1)); + func2->setPlotFunctionFunctor([](double x, const QVector& p) { + return p.at(0)*sin(2.0*JKQTPSTATISTICS_PI*x*p.at(1)); }); // here we set the parameters p0, p1 func2->setParamsV(5, 0.2); @@ -68,23 +67,7 @@ void drawExample(QApplication& app, const QString& name) { }); plot->addGraph(func2); - // 4. now we add a JKQTPXFunctionLineGraph object, which will draw a simple function - // the function is again defined as C++ inline function, but now uses external - // parameters, which may have any type (here QMapsetPlotFunctionFunctor([](double x, void* params) { - QMap* p=static_cast*>(params); - return p->value("amplitude")*sin(2.0*JKQTPSTATISTICS_PI*x*p->value("frequency")); - }); - // here we set the parameters p0, p1 - QMap params3; - params3["amplitude"]=-3; - params3["frequency"]=0.3; - func3->setParams(¶ms3); - func3->setTitle("C++-inline function with ext. params $p_0\\cdot\\sin(x*2.0*\\pi\\cdot p_1)$"); - plot->addGraph(func3);*/ - - // 5. of course the function may also be any C+ funtor object: + // 4. of course the function may also be any C+ funtor object: TFUNCGRAPH* func4=new TFUNCGRAPH(plot); func4->setPlotFunctionFunctor(SincSqr(-8)); func4->setTitle("C++ functor $-8*\\sin^2(x)/x^2$"); @@ -95,7 +78,7 @@ void drawExample(QApplication& app, const QString& name) { plot->addGraph(func4); - // 6. now we use a JKQTPXFunctionLineGraph to draw a static C function + // 5. now we use a JKQTPXFunctionLineGraph to draw a static C function TFUNCGRAPH* func5=new TFUNCGRAPH(plot); func5->setPlotFunctionFunctor(&sinc); func5->setTitle("static C function $10*\\sin(x)/x$"); @@ -105,7 +88,7 @@ void drawExample(QApplication& app, const QString& name) { }); plot->addGraph(func5); - // 7. finally JKQTPXFunctionLineGraph defines a small set of common functions + // 6. finally JKQTPXFunctionLineGraph defines a small set of common functions TFUNCGRAPH* func6=new TFUNCGRAPH(plot); func6->setSpecialFunction(TFUNCGRAPH::Line); // here we set offset p0=-1 and slope p1=1.5 of the line p0+p1*x @@ -140,7 +123,7 @@ void drawExample(QApplication& app, const QString& name) { plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideBottomLeft); - // 4. scale the plot so the graph is contained + // 9. scale the plot so the graph is contained plot->setXY(-10,10,-10,10); plot->redrawPlot(); diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp index c920752352..4f25373fee 100644 --- a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp +++ b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp @@ -34,12 +34,11 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTBasePlotter* parent): - JKQTPEvaluatedFunctionGraphBase(parent) + JKQTPEvaluatedFunctionWithParamsGraphBase(parent) { functionType=SpecialFunction::UserFunction; drawLine=true; fillCurve=false; - params=nullptr; initLineStyle(parent, parentPlotStyle); initFillStyle(parent, parentPlotStyle); @@ -53,7 +52,6 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTBasePlotter* parent): errorLineWidth=1; errorFillStyle=Qt::SolidPattern; - parameterColumn=-1; errorParameterColumn=-1; @@ -181,20 +179,6 @@ jkqtpSimplePlotFunctionType JKQTPXFunctionLineGraph::getSimplePlotFunction() con return simplePlotFunction; } -void JKQTPXFunctionLineGraph::setParams(void *__value) -{ - if (this->params != __value) { - this->params = __value; - data.clear(); - } -} - -void *JKQTPXFunctionLineGraph::getParams() const -{ - return this->params; -} - - void JKQTPXFunctionLineGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); QPen p=getLinePen(painter, parent); @@ -236,7 +220,7 @@ void JKQTPXFunctionLineGraph::createPlotData(bool collectParams) { if (!plotFunction && !simplePlotFunction) return; jkqtpSimplePlotFunctionType func; - if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, params); + if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, getInternalParams()); else if (simplePlotFunction) func=simplePlotFunction; const double xmin=parent->getXMin(); @@ -251,29 +235,8 @@ void JKQTPXFunctionLineGraph::createPlotData(bool collectParams) { void JKQTPXFunctionLineGraph::collectParameters() { - if (parent && parameterColumn>=0) { - iparams.clear(); - JKQTPDatastore* datastore=parent->getDatastore(); - int imin=0; - int imax=static_cast(datastore->getRows(parameterColumn)); + JKQTPEvaluatedFunctionWithParamsGraphBase::collectParameters(); - for (int i=imin; iget(parameterColumn,i); - iparams<=0 && !JKQTPIsOKFloat(iparams[i])) { - iparams.remove(i,1); - i--; - } - - //qDebug()<<"iparams:"; - //for (i=0; i=0) { ierrorparams.clear(); JKQTPDatastore* datastore=parent->getDatastore(); @@ -349,7 +312,7 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) { double yv=backtransformY(y); double ype=0, yme=0; if ((drawErrorLines || drawErrorPolygons) && (static_cast(errorPlotFunction))) { - double e=errorPlotFunction(xv, errorParams); + double e=errorPlotFunction(xv, getInternalErrorParams()); ype=transformY(yv+e); yme=transformY(yv-e); ype=qBound(yami, ype, yama); @@ -538,7 +501,7 @@ void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) { double yv=backtransformY(y); double xpe=0, xme=0; if ((drawErrorLines || drawErrorPolygons) && (static_cast(errorPlotFunction))) { - double e=errorPlotFunction(yv, errorParams); + double e=errorPlotFunction(yv, getInternalErrorParams()); xpe=transformX(xv+e); xme=transformX(xv-e); xpe=qBound(xami, xpe, xama); @@ -618,7 +581,7 @@ void JKQTPYFunctionLineGraph::createPlotData(bool collectParams) { if (!plotFunction && !simplePlotFunction) return; jkqtpSimplePlotFunctionType func; - if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, params); + if (plotFunction) func=std::bind(plotFunction, std::placeholders::_1, getInternalParams()); else if (simplePlotFunction) func=simplePlotFunction; const double ymin=parent->getYMin(); @@ -654,48 +617,6 @@ QPen JKQTPXFunctionLineGraph::getErrorLinePen(JKQTPEnhancedPainter& painter) con } -void JKQTPXFunctionLineGraph::setParams(const QVector ¶ms) -{ - iparams=params; - setParams(&iparams); -} - -void JKQTPXFunctionLineGraph::setCopiedParams(const double *params, int N) -{ - QVector v; - for (int i=0; i p; - p< p; - p< p; - p< p; - p< p; - p< &errorParams) { @@ -703,20 +624,6 @@ void JKQTPXFunctionLineGraph::setErrorParams(const QVector &errorParams) setErrorParams(&ierrorparams); } -void JKQTPXFunctionLineGraph::setParameterColumn(int __value) -{ - this->parameterColumn = __value; -} - -int JKQTPXFunctionLineGraph::getParameterColumn() const -{ - return this->parameterColumn; -} - -void JKQTPXFunctionLineGraph::setParameterColumn(size_t __value) { - this->parameterColumn = static_cast(__value); -} - void JKQTPXFunctionLineGraph::setErrorParameterColumn(int __value) { this->errorParameterColumn = __value; @@ -784,14 +691,13 @@ double JKQTPXFunctionLineGraph::getErrorLineWidth() const void JKQTPXFunctionLineGraph::setSpecialFunction(JKQTPXFunctionLineGraph::SpecialFunction function) { if (function==JKQTPXFunctionLineGraph::Polynomial) { - setPlotFunctionFunctor([](double x, void* param) { + setPlotFunctionFunctor([](double x, const QVector& param) { double res=0; - QVector* d=static_cast*>(param); - if (d && d->size()>0) { - res=d->value(0,0); + if (param.size()>0) { + res=param.value(0,0); double xx=x; - for (int i=1; isize(); i++) { - res=res+d->value(i,0)*xx; + for (int i=1; i& param) { double res=0; - QVector* d=static_cast*>(param); - if (d) { - if (d->size()>=3) { - res=d->value(0,0)+d->value(1,0)*exp(x/d->value(2,0)); - } else if (d->size()>=2) { - res=d->value(0,0)*exp(x/d->value(1,0)); - } + if (param.size()>=3) { + res=param.value(0,0)+param.value(1,0)*exp(x/param.value(2,0)); + } else if (param.size()>=2) { + res=param.value(0,0)*exp(x/param.value(1,0)); } return res; }); - else if (function==JKQTPXFunctionLineGraph::PowerLaw) setPlotFunctionFunctor([](double x, void* param) { + else if (function==JKQTPXFunctionLineGraph::PowerLaw) setPlotFunctionFunctor([](double x, const QVector& param) { double res=0; - QVector* d=static_cast*>(param); - if (d) { - if (d->size()>=3) { - res=d->value(0,0)+d->value(1,0)*pow(x, d->value(2,1)); - } else if (d->size()>=2) { - res=d->value(0,0)*pow(x, d->value(1,1)); - } else if (d->size()>=1) { - res=pow(x, d->value(0,1)); - } - + if (param.size()>=3) { + res=param.value(0,0)+param.value(1,0)*pow(x, param.value(2,1)); + } else if (param.size()>=2) { + res=param.value(0,0)*pow(x, param.value(1,1)); + } else if (param.size()>=1) { + res=pow(x, param.value(0,1)); } return res; }); @@ -834,9 +733,6 @@ JKQTPXFunctionLineGraph::SpecialFunction JKQTPXFunctionLineGraph::getFunctionTyp return functionType; } -QVector JKQTPXFunctionLineGraph::getInternalParams() const { - return iparams; -} QVector JKQTPXFunctionLineGraph::getInternalErrorParams() const { return ierrorparams; } @@ -910,6 +806,6 @@ void *JKQTPXFunctionLineGraph::getErrorParams() const bool JKQTPXFunctionLineGraph::usesColumn(int c) const { - return (c==parameterColumn)||(c==errorParameterColumn); + return JKQTPEvaluatedFunctionWithParamsGraphBase::usesColumn(c)||(c==errorParameterColumn); } diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h index d26e38f48c..246227409c 100644 --- a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h +++ b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h @@ -43,7 +43,7 @@ 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 jkqtpPlotFunctionType; +typedef std::function&)> jkqtpPlotFunctionType; /*! \brief simplified type of functions (without parameters) that may be plotted by JKQTPXFunctionLineGraph and JKQTPYFunctionLineGraph \ingroup jkqtplotter_functiongraphs @@ -74,7 +74,7 @@ typedef std::function jkqtpSimplePlotFunctionType; \see \ref JKQTPlotterFunctionPlots, JKQTPAdaptiveFunctionGraphEvaluator, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression() */ -class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunctionGraphBase, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin { +class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunctionWithParamsGraphBase, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin { Q_OBJECT public: @@ -158,27 +158,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct /*! \copydoc simplePlotFunction */ \ virtual jkqtpSimplePlotFunctionType getSimplePlotFunction () const; - /*! \copydoc params */ - virtual void setParams(void* __value); - /*! \copydoc params */ - void* getParams() const; - /** \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& params); - /** \brief sets the params from a copy of the given array of length \a N */ - void setCopiedParams(const double* params, int N); - /** \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 returns the currently set internal parameter vector */ - QVector getInternalParams() const; /** \brief returns the currently set internal parameter vector */ QVector getInternalErrorParams() const; @@ -220,13 +200,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct 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& errorParams); - - /*! \copydoc parameterColumn */ - void setParameterColumn(int __value); - /*! \copydoc parameterColumn */ - int getParameterColumn() const; - /*! \copydoc parameterColumn */ - void setParameterColumn (size_t __value); /*! \copydoc errorParameterColumn */ void setErrorParameterColumn(int __value); /*! \copydoc errorParameterColumn */ @@ -264,16 +237,14 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct /** \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 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(); - /** \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 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; @@ -287,8 +258,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct jkqtpSimplePlotFunctionType simplePlotFunction; /** \brief indicates whether a special function is set (and if so, which one), or a user-supplied function */ SpecialFunction functionType; - /** \brief pointer to the parameters supplied to the plotting funtion */ - void* params; /** \brief indicates whether an error polygon should be drawn */ @@ -317,8 +286,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPEvaluatedFunct QBrush getErrorBrush(JKQTPEnhancedPainter& painter) const; QPen getErrorLinePen(JKQTPEnhancedPainter &painter) const; - /** \brief internal storage for the current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) */ - QVector iparams; /** \brief internal storage for the current error function parameters for errorPlotFunction (which may stem from different sources, as direct data, a datastore column ...) */ QVector ierrorparams; }; diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.cpp b/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.cpp index 66b339cc8d..103362b109 100644 --- a/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.cpp +++ b/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.cpp @@ -29,6 +29,7 @@ #include "jkqtplotter/jkqtpbaseelements.h" #include "jkqtplotter/jkqtplotter.h" +#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgzdisplaySamplePoints; } +bool JKQTPEvaluatedFunctionGraphBase::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero) +{ + if (data.size()==0) createPlotData(); + if (data.size()>0){ + bool start=true; + minx=0; + maxx=0; + smallestGreaterZero=0; + for (auto const& d: data) { + if (JKQTPIsOKFloat(d.x())) { + if (start || d.x()>maxx) maxx=d.x(); + if (start || d.x()0){ + bool start=true; + miny=0; + maxy=0; + smallestGreaterZero=0; + + for (auto const& d: data) { + if (JKQTPIsOKFloat(d.y())) { + if (start || d.y()>maxy) maxy=d.y(); + if (start || d.y()getPlotter()) +{ + +} + +JKQTPEvaluatedFunctionWithParamsGraphBase::~JKQTPEvaluatedFunctionWithParamsGraphBase() +{ + +} + +void JKQTPEvaluatedFunctionWithParamsGraphBase::collectParameters() +{ + if (parent && parameterColumn>=0) { + iparams.clear(); + JKQTPDatastore* datastore=parent->getDatastore(); + int imin=0; + int imax=static_cast(datastore->getRows(parameterColumn)); + + for (int i=imin; iget(parameterColumn,i); + iparams<=0 && !JKQTPIsOKFloat(iparams[i])) { + iparams.remove(i,1); + i--; + } + + } +} + + +void JKQTPEvaluatedFunctionWithParamsGraphBase::setParams(const QVector ¶ms) +{ + iparams=params; +} + +void JKQTPEvaluatedFunctionWithParamsGraphBase::setCopiedParams(const double *params, int N) +{ + QVector v; + for (int i=0; i p; + p< p; + p< p; + p< p; + p< p; + p<parameterColumn = __value; +} + +int JKQTPEvaluatedFunctionWithParamsGraphBase::getParameterColumn() const +{ + return this->parameterColumn; +} + +void JKQTPEvaluatedFunctionWithParamsGraphBase::setParameterColumn(size_t __value) { + this->parameterColumn = static_cast(__value); +} + +QVector JKQTPEvaluatedFunctionWithParamsGraphBase::getInternalParams() const { + return iparams; +} + +bool JKQTPEvaluatedFunctionWithParamsGraphBase::usesColumn(int c) const +{ + return (c==parameterColumn); +} diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h b/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h index 7ac273c470..728220b28f 100644 --- a/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h +++ b/lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h @@ -34,67 +34,75 @@ -/*! \brief Base class for graph classes that evaluate a mathematical function (e.g. defined as a C-fucntion), - using an adaptive plotting algorithm from JKQTPAdaptiveFunctionGraphEvaluator - \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 JKQTPAdaptiveFunctionGraphEvaluator, JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph +/** \brief Base class for graph classes that evaluate a mathematical function (e.g. defined as a C-fucntion), + * using an adaptive plotting algorithm from JKQTPAdaptiveFunctionGraphEvaluator + * \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 JKQTPAdaptiveFunctionGraphEvaluator, JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph */ class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionGraphBase: public JKQTPGraph { Q_OBJECT public: /** \brief class constructor */ - JKQTPEvaluatedFunctionGraphBase(JKQTBasePlotter* parent=nullptr); + explicit JKQTPEvaluatedFunctionGraphBase(JKQTBasePlotter* parent=nullptr); /** \brief class constructor */ - JKQTPEvaluatedFunctionGraphBase(JKQTPlotter* parent); + explicit JKQTPEvaluatedFunctionGraphBase(JKQTPlotter* parent); /** \brief class destructor */ virtual ~JKQTPEvaluatedFunctionGraphBase() ; + /** \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; - /*! \copydoc minSamples */ + + /** \copydoc minSamples */ unsigned int getMinSamples() const; - /*! \copydoc maxRefinementDegree */ + /** \copydoc maxRefinementDegree */ unsigned int getMaxRefinementDegree() const; - /*! \copydoc slopeTolerance */ + /** \copydoc slopeTolerance */ double getSlopeTolerance() const; - /*! \copydoc minPixelPerSample */ + /** \copydoc minPixelPerSample */ double getMinPixelPerSample() const; - /*! \copydoc dataCleanupMaxAllowedAngleDegree */ + /** \copydoc dataCleanupMaxAllowedAngleDegree */ double getDataCleanupMaxAllowedAngleDegree() const; - /*! \copydoc displaySamplePoints */ + /** \copydoc displaySamplePoints */ bool getDisplaySamplePoints() const; public slots: - /*! \copydoc minSamples */ + /** \copydoc minSamples */ void setMinSamples(const unsigned int & __value); - /*! \copydoc maxRefinementDegree */ + /** \copydoc maxRefinementDegree */ void setMaxRefinementDegree(const unsigned int & __value); - /*! \copydoc slopeTolerance */ + /** \copydoc slopeTolerance */ void setSlopeTolerance(double __value); - /*! \copydoc minPixelPerSample */ + /** \copydoc minPixelPerSample */ void setMinPixelPerSample(double __value); - /*! \copydoc dataCleanupMaxAllowedAngleDegree */ + /** \copydoc dataCleanupMaxAllowedAngleDegree */ void setDataCleanupMaxAllowedAngleDegree(double __value); - /*! \copydoc displaySamplePoints */ + /** \copydoc displaySamplePoints */ void setDisplaySamplePoints(bool __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 data; @@ -125,4 +133,61 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionGraphBase: public JKQTPGraph }; +/** \brief extends JKQTPEvaluatedFunctionGraphBase with a set of functions that support function parameters + * \ingroup jkqtplotter_functiongraphs + * + * \see JKQTPEvaluatedFunctionGraphBase + */ +class JKQTPLOTTER_LIB_EXPORT JKQTPEvaluatedFunctionWithParamsGraphBase: public JKQTPEvaluatedFunctionGraphBase { + Q_OBJECT +public: + /** \brief class constructor */ + explicit JKQTPEvaluatedFunctionWithParamsGraphBase(JKQTBasePlotter* parent=nullptr); + /** \brief class constructor */ + explicit JKQTPEvaluatedFunctionWithParamsGraphBase(JKQTPlotter* parent); + /** \brief class destructor */ + virtual ~JKQTPEvaluatedFunctionWithParamsGraphBase(); + + + /** \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& 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 */ + QVector getInternalParams() const; + /** \copydoc parameterColumn */ + int getParameterColumn() const; + + /** \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); + + /** \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 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 iparams; +}; + + #endif // jkqtpevaluatedfunctionbase_H diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp index 99394d522c..df0d57f314 100644 --- a/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp +++ b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp @@ -29,22 +29,18 @@ #include "jkqtplotter/jkqtpbaseelements.h" #include "jkqtplotter/jkqtplotter.h" -#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgzparams != __value) { - this->params = __value; - data.clear(); - } -} - -void *JKQTPXYFunctionLineGraph::getParams() const -{ - return this->params; -} - void JKQTPXYFunctionLineGraph::drawKeyMarker(JKQTPEnhancedPainter& painter, QRectF& rect) { painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();}); @@ -196,53 +179,6 @@ QColor JKQTPXYFunctionLineGraph::getKeyLabelColor() const { return getLineColor(); } -bool JKQTPXYFunctionLineGraph::getXMinMax(double &minx, double &maxx, double &smallestGreaterZero) -{ - if (data.size()==0) createPlotData(); - if (data.size()>0){ - bool start=true; - minx=0; - maxx=0; - smallestGreaterZero=0; - - for (auto const& d: data) { - if (JKQTPIsOKFloat(d.x())) { - if (start || d.x()>maxx) maxx=d.x(); - if (start || d.x()0){ - bool start=true; - miny=0; - maxy=0; - smallestGreaterZero=0; - - for (auto const& d: data) { - if (JKQTPIsOKFloat(d.y())) { - if (start || d.y()>maxy) maxy=d.y(); - if (start || d.y() QPointF { return plot->transform(func(t)); }, this, std::placeholders::_1); @@ -265,33 +201,6 @@ void JKQTPXYFunctionLineGraph::createPlotData(bool collectParams) { data=JKQTPSimplyfyLineSegemnts(data, dataCleanupMaxAllowedAngleDegree); } -void JKQTPXYFunctionLineGraph::collectParameters() -{ - if (parent && parameterColumn>=0) { - iparams.clear(); - JKQTPDatastore* datastore=parent->getDatastore(); - int imin=0; - int imax=static_cast(datastore->getRows(parameterColumn)); - - for (int i=imin; iget(parameterColumn,i); - iparams<=0 && !JKQTPIsOKFloat(iparams[i])) { - iparams.remove(i,1); - i--; - } - - //qDebug()<<"iparams:"; - //for (i=0; i ¶ms) -{ - iparams=params; - setParams(&iparams); -} - -void JKQTPXYFunctionLineGraph::setCopiedParams(const double *params, int N) -{ - QVector v; - for (int i=0; i p; - p< p; - p< p; - p< p; - p< p; - p<parameterColumn = __value; -} - -int JKQTPXYFunctionLineGraph::getParameterColumn() const -{ - return this->parameterColumn; -} - -void JKQTPXYFunctionLineGraph::setParameterColumn(size_t __value) { - this->parameterColumn = static_cast(__value); -} - - -QVector JKQTPXYFunctionLineGraph::getInternalParams() const { - return iparams; -} - - -bool JKQTPXYFunctionLineGraph::usesColumn(int c) const -{ - return (c==parameterColumn); -} - double JKQTPXYFunctionLineGraph::getTMin() const { return tmin; diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h index 904f567176..6835ead8de 100644 --- a/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h +++ b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h @@ -43,7 +43,7 @@ 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 jkqtpParametricCurveFunctionType; +typedef std::function)> jkqtpParametricCurveFunctionType; /*! \brief simplified type of functions (without parameters) that may be plotted by JKQTPXYFunctionLineGraph \ingroup jkqtplotter_functiongraphs @@ -88,7 +88,7 @@ typedef std::function jkqtpSimpleParametricCurveFunctionType; \see \ref JKQTPlotterEvalCurves , JKQTPAdaptiveFunctionGraphEvaluator, JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph */ -class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPEvaluatedFunctionGraphBase, public JKQTPGraphLineStyleMixin { +class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPEvaluatedFunctionWithParamsGraphBase, public JKQTPGraphLineStyleMixin { Q_OBJECT public: @@ -124,16 +124,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPEvaluatedFunc /** \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 sets a functor to be plotted * * \see plotFunction @@ -159,41 +149,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPEvaluatedFunc /*! \copydoc simplePlotFunction */ \ virtual jkqtpSimpleParametricCurveFunctionType getSimplePlotFunction () const; - /*! \copydoc params */ - virtual void setParams(void* __value); - /*! \copydoc params */ - void* getParams() const; - /** \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& params); - /** \brief sets the params from a copy of the given array of length \a N */ - void setCopiedParams(const double* params, int N); - /** \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 returns the currently set internal parameter vector */ - QVector getInternalParams() const; - - - - /*! \copydoc parameterColumn */ - void setParameterColumn(int __value); - /*! \copydoc parameterColumn */ - int getParameterColumn() const; - /*! \copydoc parameterColumn */ - void setParameterColumn (size_t __value); - - - /** \copydoc JKQTPGraph::usesColumn() */ - virtual bool usesColumn(int c) const override; - /*! \copydoc tmin */ double getTMin() const; @@ -216,21 +171,13 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPEvaluatedFunc double tmax; /** \brief fill the data array with data from the function plotFunction */ virtual void createPlotData( bool collectParams=true) override; - /** \brief ensure that current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) are stored in iparams */ - virtual void collectParameters() ; - /** \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 the function to be plotted */ jkqtpParametricCurveFunctionType plotFunction; /** \brief a simple function to be plotted, simplified form without parameters */ jkqtpSimpleParametricCurveFunctionType simplePlotFunction; - /** \brief pointer to the parameters supplied to the plotting funtion */ - void* params; - /** \brief internal storage for the current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) */ - QVector iparams; }; #endif // jkqtpevaluatedparametriccurve_H diff --git a/lib/jkqtplotter/graphs/jkqtpparsedfunction.cpp b/lib/jkqtplotter/graphs/jkqtpparsedfunction.cpp index f6e74968dc..86dd7e8870 100644 --- a/lib/jkqtplotter/graphs/jkqtpparsedfunction.cpp +++ b/lib/jkqtplotter/graphs/jkqtpparsedfunction.cpp @@ -91,12 +91,9 @@ void JKQTPXParsedFunctionLineGraph::createPlotData(bool /*collectParams*/) } fdata.varcount=0; try { - QVector* parameters=static_cast*>(params); - if (parameters) { - for (int i=0; isize(); i++) { - fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), parameters->at(i)); - fdata.varcount=fdata.varcount+1; - } + 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; @@ -150,7 +147,7 @@ void JKQTPXParsedFunctionLineGraph::createPlotData(bool /*collectParams*/) } -double JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction(double x, void* /*data*/, JKQTPXParsedFunctionLineGraphFunctionData *fdata) { +double JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunction(double x, const QVector& /*data*/, JKQTPXParsedFunctionLineGraphFunctionData *fdata) { JKQTPXParsedFunctionLineGraph::JKQTPXParsedFunctionLineGraphFunctionData* d=fdata;//static_cast(data); if (d && d->parser && d->node) { try { @@ -267,12 +264,9 @@ void JKQTPYParsedFunctionLineGraph::createPlotData(bool /*collectParams*/) } fdata.varcount=0; try { - QVector* parameters=static_cast*>(params); - if (parameters) { - for (int i=0; isize(); i++) { - fdata.parser->addVariableDouble(std::string("p")+jkqtp_inttostr(fdata.varcount+1), parameters->at(i)); - fdata.varcount=fdata.varcount+1; - } + 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); fdata.parser->addVariableDouble(std::string("y"), 0.0); @@ -327,7 +321,7 @@ void JKQTPYParsedFunctionLineGraph::createPlotData(bool /*collectParams*/) qDebug()<<"refined to "< & /*data*/, JKQTPYParsedFunctionLineGraphFunctionData *fdata) { JKQTPYParsedFunctionLineGraph::JKQTPYParsedFunctionLineGraphFunctionData* d=fdata;//static_cast(data); if (d && d->parser && d->node) { try { diff --git a/lib/jkqtplotter/graphs/jkqtpparsedfunction.h b/lib/jkqtplotter/graphs/jkqtpparsedfunction.h index a0735e09fa..9f0b6608a2 100644 --- a/lib/jkqtplotter/graphs/jkqtpparsedfunction.h +++ b/lib/jkqtplotter/graphs/jkqtpparsedfunction.h @@ -97,7 +97,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXParsedFunctionLineGraph: public JKQTPXFunctio virtual void createPlotData(bool collectParams=true) override; /** \brief implements the actual plot function */ - static double JKQTPXParsedFunctionLineGraphFunction(double x, void *data, JKQTPXParsedFunctionLineGraphFunctionData* fdata) ; + static double JKQTPXParsedFunctionLineGraphFunction(double x, const QVector &data, JKQTPXParsedFunctionLineGraphFunctionData* fdata) ; }; @@ -165,6 +165,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPYParsedFunctionLineGraph: public JKQTPYFunctio /** \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, void *data, JKQTPYParsedFunctionLineGraphFunctionData* fdata); + static double JKQTPYParsedFunctionLineGraphFunction(double x, const QVector& data, JKQTPYParsedFunctionLineGraphFunctionData* fdata); }; #endif // jkqtpgraphsparsedfunction_H