mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-25 01:51:49 +08:00
created common base class JKQTPFunctionLineGraphBase for all graphs that display evaluated functions
This commit is contained in:
parent
48a24a85d0
commit
29ee1aa376
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QVector>
|
||||
#include <QMap>
|
||||
#include "jkqtplotter/jkqtplotter.h"
|
||||
@ -26,7 +27,7 @@ private:
|
||||
|
||||
template <class TFUNCGRAPH>
|
||||
void drawExample(QApplication& app, const QString& name) {
|
||||
// 1. create a window that contains a line-edit to edit a function
|
||||
// 1.1 create a window that contains a line-edit to edit a function
|
||||
// and a JKQTPlotter to display the function, combine everything in a layout
|
||||
QWidget* mainWin=new QWidget();
|
||||
mainWin->setWindowTitle(name);
|
||||
@ -34,12 +35,20 @@ void drawExample(QApplication& app, const QString& name) {
|
||||
QVBoxLayout* layout=new QVBoxLayout;
|
||||
mainWin->setLayout(layout);
|
||||
layout->addWidget(plot);
|
||||
// 1.2 add checkbox that allows to switch the display of sample points
|
||||
QCheckBox* chkShowSamples=new QCheckBox(app.tr("display sample points"));
|
||||
chkShowSamples->setChecked(false);
|
||||
layout->addWidget(chkShowSamples);
|
||||
|
||||
// 2. now we add a JKQTPXFunctionLineGraph object, which will draw a simple function
|
||||
// the function is defined as C++ inline function
|
||||
TFUNCGRAPH* func1=new TFUNCGRAPH(plot);
|
||||
func1->setPlotFunctionFunctor([](double x) { return 0.2*x*x-0.015*x*x*x; });
|
||||
func1->setTitle("C++-inline function $0.2x^2-0.015x^3$");
|
||||
QObject::connect(chkShowSamples, &QCheckBox::toggled, [=](bool en) {
|
||||
func1->setDisplaySamplePoints(en);
|
||||
plot->redrawPlot();
|
||||
});
|
||||
plot->addGraph(func1);
|
||||
|
||||
// 3. now we add a JKQTPXFunctionLineGraph object, which will draw a simple function
|
||||
@ -53,6 +62,10 @@ void drawExample(QApplication& app, const QString& name) {
|
||||
// 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)$");
|
||||
QObject::connect(chkShowSamples, &QCheckBox::toggled, [=](bool en) {
|
||||
func2->setDisplaySamplePoints(en);
|
||||
plot->redrawPlot();
|
||||
});
|
||||
plot->addGraph(func2);
|
||||
|
||||
// 4. now we add a JKQTPXFunctionLineGraph object, which will draw a simple function
|
||||
@ -75,6 +88,10 @@ void drawExample(QApplication& app, const QString& name) {
|
||||
TFUNCGRAPH* func4=new TFUNCGRAPH(plot);
|
||||
func4->setPlotFunctionFunctor(SincSqr(-8));
|
||||
func4->setTitle("C++ functor $-8*\\sin^2(x)/x^2$");
|
||||
QObject::connect(chkShowSamples, &QCheckBox::toggled, [=](bool en) {
|
||||
func4->setDisplaySamplePoints(en);
|
||||
plot->redrawPlot();
|
||||
});
|
||||
plot->addGraph(func4);
|
||||
|
||||
|
||||
@ -82,6 +99,10 @@ void drawExample(QApplication& app, const QString& name) {
|
||||
TFUNCGRAPH* func5=new TFUNCGRAPH(plot);
|
||||
func5->setPlotFunctionFunctor(&sinc);
|
||||
func5->setTitle("static C function $10*\\sin(x)/x$");
|
||||
QObject::connect(chkShowSamples, &QCheckBox::toggled, [=](bool en) {
|
||||
func5->setDisplaySamplePoints(en);
|
||||
plot->redrawPlot();
|
||||
});
|
||||
plot->addGraph(func5);
|
||||
|
||||
// 7. finally JKQTPXFunctionLineGraph defines a small set of common functions
|
||||
@ -90,6 +111,10 @@ void drawExample(QApplication& app, const QString& name) {
|
||||
// here we set offset p0=-1 and slope p1=1.5 of the line p0+p1*x
|
||||
func6->setParamsV(-1,1.5);
|
||||
func6->setTitle("special function: linear p_0=-1, p_1=1.5");
|
||||
QObject::connect(chkShowSamples, &QCheckBox::toggled, [=](bool en) {
|
||||
func6->setDisplaySamplePoints(en);
|
||||
plot->redrawPlot();
|
||||
});
|
||||
plot->addGraph(func6);
|
||||
|
||||
// 7. finally JKQTPXFunctionLineGraph defines a small set of common functions
|
||||
@ -102,6 +127,10 @@ void drawExample(QApplication& app, const QString& name) {
|
||||
size_t paramCol=plot->getDatastore()->addCopiedColumn(params);
|
||||
func7->setParameterColumn(paramCol);
|
||||
func7->setTitle("special function: linear p_0=1, p_1=-1.5");
|
||||
QObject::connect(chkShowSamples, &QCheckBox::toggled, [=](bool en) {
|
||||
func7->setDisplaySamplePoints(en);
|
||||
plot->redrawPlot();
|
||||
});
|
||||
plot->addGraph(func7);
|
||||
|
||||
|
||||
|
@ -27,6 +27,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
|
||||
$$PWD/jkqtplotter/jkqtpoverlaysbase.h \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpboxplot.h \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpboxplotstylingmixins.h \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpevaluatedfunction.h \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpfilledcurve.h \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpgeometric.h \
|
||||
@ -77,6 +78,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
|
||||
$$PWD/jkqtplotter/jkqtpoverlaysbase.cpp \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpboxplot.cpp \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpboxplotstylingmixins.cpp \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.cpp \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpfilledcurve.cpp \
|
||||
$$PWD/jkqtplotter/graphs/jkqtpgeometric.cpp \
|
||||
|
@ -44,6 +44,7 @@ set(SOURCES_GRAPHS
|
||||
graphs/jkqtpbarchart.cpp
|
||||
graphs/jkqtpboxplot.cpp
|
||||
graphs/jkqtpboxplotstylingmixins.cpp
|
||||
graphs/jkqtpevaluatedfunctionbase.cpp
|
||||
graphs/jkqtpevaluatedfunction.cpp
|
||||
graphs/jkqtpfilledcurve.cpp
|
||||
graphs/jkqtpgeometric.cpp
|
||||
@ -97,6 +98,7 @@ set(HEADERS
|
||||
set(HEADERS_GRAPHS
|
||||
graphs/jkqtpboxplot.h
|
||||
graphs/jkqtpboxplotstylingmixins.h
|
||||
graphs/jkqtpevaluatedfunctionbase.h
|
||||
graphs/jkqtpevaluatedfunction.h
|
||||
graphs/jkqtpfilledcurve.h
|
||||
graphs/jkqtpgeometric.h
|
||||
|
@ -34,19 +34,12 @@
|
||||
|
||||
|
||||
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTBasePlotter* parent):
|
||||
JKQTPGraph(parent)
|
||||
JKQTPFunctionLineGraphBase(parent)
|
||||
{
|
||||
functionType=SpecialFunction::UserFunction;
|
||||
drawLine=true;
|
||||
fillCurve=false;
|
||||
params=nullptr;
|
||||
minSamples=50;
|
||||
maxRefinementDegree=5;
|
||||
slopeTolerance=0.005;
|
||||
minPixelPerSample=32;
|
||||
dataCleanupMaxAllowedAngleDegree=0.2;
|
||||
displaySamplePoints=false;
|
||||
data.clear();
|
||||
|
||||
initLineStyle(parent, parentPlotStyle);
|
||||
initFillStyle(parent, parentPlotStyle);
|
||||
@ -301,16 +294,6 @@ void JKQTPXFunctionLineGraph::collectParameters()
|
||||
}
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::drawSamplePoints(JKQTPEnhancedPainter& painter) {
|
||||
QColor c=getLineColor();
|
||||
c.setHsv(fmod(c.hue()+90, 360), c.saturation(), c.value());
|
||||
painter.save(); auto __finalpaintsamplepoints=JKQTPFinally([&painter]() {painter.restore();});
|
||||
for (const auto& d: data) {
|
||||
if (JKQTPIsOKFloat(d.x()) && JKQTPIsOKFloat(d.y())) {
|
||||
JKQTPPlotSymbol(painter, d.x(), d.y(), JKQTPCross, 6,1*parent->getLineWidthMultiplier(), c, QColor(Qt::transparent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
@ -432,7 +415,7 @@ void JKQTPXFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
}
|
||||
|
||||
|
||||
if (displaySamplePoints) drawSamplePoints(painter);
|
||||
if (displaySamplePoints) drawSamplePoints(painter, getLineColor());
|
||||
}
|
||||
drawErrorsAfter(painter);
|
||||
//std::cout<<"plot done\n";
|
||||
@ -620,7 +603,7 @@ void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
}
|
||||
|
||||
|
||||
if (displaySamplePoints) drawSamplePoints(painter);
|
||||
if (displaySamplePoints) drawSamplePoints(painter, getLineColor());
|
||||
}
|
||||
drawErrorsAfter(painter);
|
||||
//std::cout<<"plot done\n";
|
||||
@ -858,66 +841,6 @@ QVector<double> JKQTPXFunctionLineGraph::getInternalErrorParams() const {
|
||||
return ierrorparams;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setMinSamples(const unsigned int &__value)
|
||||
{
|
||||
this->minSamples = __value;
|
||||
}
|
||||
|
||||
unsigned int JKQTPXFunctionLineGraph::getMinSamples() const
|
||||
{
|
||||
return this->minSamples;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setMaxRefinementDegree(const unsigned int &__value)
|
||||
{
|
||||
this->maxRefinementDegree = __value;
|
||||
}
|
||||
|
||||
unsigned int JKQTPXFunctionLineGraph::getMaxRefinementDegree() const
|
||||
{
|
||||
return this->maxRefinementDegree;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setSlopeTolerance(double __value)
|
||||
{
|
||||
this->slopeTolerance = __value;
|
||||
}
|
||||
|
||||
double JKQTPXFunctionLineGraph::getSlopeTolerance() const
|
||||
{
|
||||
return this->slopeTolerance;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setMinPixelPerSample(double __value)
|
||||
{
|
||||
this->minPixelPerSample = __value;
|
||||
}
|
||||
|
||||
double JKQTPXFunctionLineGraph::getMinPixelPerSample() const
|
||||
{
|
||||
return this->minPixelPerSample;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setDataCleanupMaxAllowedAngleDegree(double __value)
|
||||
{
|
||||
dataCleanupMaxAllowedAngleDegree=__value;
|
||||
}
|
||||
|
||||
double JKQTPXFunctionLineGraph::getDataCleanupMaxAllowedAngleDegree() const
|
||||
{
|
||||
return dataCleanupMaxAllowedAngleDegree;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setDisplaySamplePoints(bool __value)
|
||||
{
|
||||
this->displaySamplePoints = __value;
|
||||
}
|
||||
|
||||
bool JKQTPXFunctionLineGraph::getDisplaySamplePoints() const
|
||||
{
|
||||
return this->displaySamplePoints;
|
||||
}
|
||||
|
||||
void JKQTPXFunctionLineGraph::setDrawErrorPolygons(bool __value)
|
||||
{
|
||||
this->drawErrorPolygons = __value;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
|
||||
#include "jkqtplotter/jkqtplotter_imexport.h"
|
||||
#include "jkqtcommon/jkqtpgeometrytools.h"
|
||||
#include "jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h"
|
||||
#include <functional>
|
||||
|
||||
#ifndef jkqtpgraphsevaluatedfunction_H
|
||||
@ -73,7 +74,7 @@ typedef std::function<double(double)> jkqtpSimplePlotFunctionType;
|
||||
|
||||
\see \ref JKQTPlotterFunctionPlots, JKQTPAdaptiveFunctionGraphEvaluator, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression()
|
||||
*/
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPFunctionLineGraphBase, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@ -180,30 +181,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
|
||||
QVector<double> getInternalParams() const;
|
||||
/** \brief returns the currently set internal parameter vector */
|
||||
QVector<double> getInternalErrorParams() const;
|
||||
/*! \copydoc minSamples */
|
||||
void setMinSamples(const unsigned int & __value);
|
||||
/*! \copydoc minSamples */
|
||||
unsigned int getMinSamples() const;
|
||||
/*! \copydoc maxRefinementDegree */
|
||||
void setMaxRefinementDegree(const unsigned int & __value);
|
||||
/*! \copydoc maxRefinementDegree */
|
||||
unsigned int getMaxRefinementDegree() const;
|
||||
/*! \copydoc slopeTolerance */
|
||||
void setSlopeTolerance(double __value);
|
||||
/*! \copydoc slopeTolerance */
|
||||
double getSlopeTolerance() const;
|
||||
/*! \copydoc minPixelPerSample */
|
||||
void setMinPixelPerSample(double __value);
|
||||
/*! \copydoc minPixelPerSample */
|
||||
double getMinPixelPerSample() const;
|
||||
/*! \copydoc dataCleanupMaxAllowedAngleDegree */
|
||||
void setDataCleanupMaxAllowedAngleDegree(double __value);
|
||||
/*! \copydoc dataCleanupMaxAllowedAngleDegree */
|
||||
double getDataCleanupMaxAllowedAngleDegree() const;
|
||||
/*! \copydoc displaySamplePoints */
|
||||
void setDisplaySamplePoints(bool __value);
|
||||
/*! \copydoc displaySamplePoints */
|
||||
bool getDisplaySamplePoints() const;
|
||||
|
||||
/*! \copydoc drawErrorPolygons */
|
||||
void setDrawErrorPolygons(bool __value);
|
||||
/*! \copydoc drawErrorPolygons */
|
||||
@ -288,11 +266,8 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
|
||||
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 fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true);
|
||||
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();
|
||||
|
||||
@ -314,24 +289,8 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
|
||||
SpecialFunction functionType;
|
||||
/** \brief pointer to the parameters supplied to the plotting funtion */
|
||||
void* params;
|
||||
/** \brief the minimum number of points to evaluate the function at */
|
||||
unsigned int minSamples;
|
||||
/** \brief the maximum number of recursive refinement steps
|
||||
*
|
||||
* each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
|
||||
* of points plotted at all are thus:
|
||||
* \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
|
||||
*/
|
||||
unsigned int maxRefinementDegree;
|
||||
/** \brief the tolerance for the difference of two subsequent slopes */
|
||||
double slopeTolerance;
|
||||
/** \brief create one sample at least every \a minPixelPerSample pixels */
|
||||
double minPixelPerSample;
|
||||
/** \brief in the clean-up step of plot-data creation, a point is removed from the data, if
|
||||
* it caused its neighboring line-segments to form an angle less than this value, given in degrees. */
|
||||
double dataCleanupMaxAllowedAngleDegree;
|
||||
/** \brief if true [default: off] display the points where the function has been sampled */
|
||||
bool displaySamplePoints;
|
||||
|
||||
|
||||
/** \brief indicates whether an error polygon should be drawn */
|
||||
bool drawErrorPolygons;
|
||||
/** \brief indicates whether error lines should be drawn */
|
||||
@ -362,8 +321,6 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
|
||||
QVector<double> 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<double> ierrorparams;
|
||||
/** \brief draw all the sample points in data as small symbols */
|
||||
void drawSamplePoints(JKQTPEnhancedPainter &painter);
|
||||
};
|
||||
|
||||
/*! \brief This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$
|
||||
|
134
lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.cpp
Normal file
134
lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
Copyright (c) 2008-2020 Jan W. Krieger (<jan@jkrieger.de>)
|
||||
|
||||
|
||||
|
||||
This software is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
||||
the Free Software Foundation, either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License (LGPL) for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h"
|
||||
#include "jkqtplotter/jkqtpbaseplotter.h"
|
||||
#include <stdlib.h>
|
||||
#include <QDebug>
|
||||
#include <iostream>
|
||||
#include "jkqtplotter/jkqtptools.h"
|
||||
#include "jkqtplotter/graphs/jkqtpimage.h"
|
||||
#include "jkqtplotter/jkqtpbaseelements.h"
|
||||
#include "jkqtplotter/jkqtplotter.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
JKQTPFunctionLineGraphBase::JKQTPFunctionLineGraphBase(JKQTBasePlotter* parent):
|
||||
JKQTPGraph(parent)
|
||||
{
|
||||
minSamples=50;
|
||||
maxRefinementDegree=5;
|
||||
slopeTolerance=0.005;
|
||||
minPixelPerSample=32;
|
||||
dataCleanupMaxAllowedAngleDegree=0.2;
|
||||
displaySamplePoints=false;
|
||||
data.clear();
|
||||
|
||||
}
|
||||
|
||||
JKQTPFunctionLineGraphBase::JKQTPFunctionLineGraphBase(JKQTPlotter* parent):
|
||||
JKQTPFunctionLineGraphBase(parent->getPlotter())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
JKQTPFunctionLineGraphBase::~JKQTPFunctionLineGraphBase()
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
|
||||
|
||||
void JKQTPFunctionLineGraphBase::drawSamplePoints(JKQTPEnhancedPainter& painter, QColor graphColor) {
|
||||
QColor c=graphColor;
|
||||
c.setHsv(fmod(c.hue()+90, 360), c.saturation(), c.value());
|
||||
painter.save(); auto __finalpaintsamplepoints=JKQTPFinally([&painter]() {painter.restore();});
|
||||
for (const auto& d: data) {
|
||||
if (JKQTPIsOKFloat(d.x()) && JKQTPIsOKFloat(d.y())) {
|
||||
JKQTPPlotSymbol(painter, d.x(), d.y(), JKQTPCross, 6,1*parent->getLineWidthMultiplier(), c, QColor(Qt::transparent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void JKQTPFunctionLineGraphBase::setMinSamples(const unsigned int &__value)
|
||||
{
|
||||
this->minSamples = __value;
|
||||
}
|
||||
|
||||
unsigned int JKQTPFunctionLineGraphBase::getMinSamples() const
|
||||
{
|
||||
return this->minSamples;
|
||||
}
|
||||
|
||||
void JKQTPFunctionLineGraphBase::setMaxRefinementDegree(const unsigned int &__value)
|
||||
{
|
||||
this->maxRefinementDegree = __value;
|
||||
}
|
||||
|
||||
unsigned int JKQTPFunctionLineGraphBase::getMaxRefinementDegree() const
|
||||
{
|
||||
return this->maxRefinementDegree;
|
||||
}
|
||||
|
||||
void JKQTPFunctionLineGraphBase::setSlopeTolerance(double __value)
|
||||
{
|
||||
this->slopeTolerance = __value;
|
||||
}
|
||||
|
||||
double JKQTPFunctionLineGraphBase::getSlopeTolerance() const
|
||||
{
|
||||
return this->slopeTolerance;
|
||||
}
|
||||
|
||||
void JKQTPFunctionLineGraphBase::setMinPixelPerSample(double __value)
|
||||
{
|
||||
this->minPixelPerSample = __value;
|
||||
}
|
||||
|
||||
double JKQTPFunctionLineGraphBase::getMinPixelPerSample() const
|
||||
{
|
||||
return this->minPixelPerSample;
|
||||
}
|
||||
|
||||
void JKQTPFunctionLineGraphBase::setDataCleanupMaxAllowedAngleDegree(double __value)
|
||||
{
|
||||
dataCleanupMaxAllowedAngleDegree=__value;
|
||||
}
|
||||
|
||||
double JKQTPFunctionLineGraphBase::getDataCleanupMaxAllowedAngleDegree() const
|
||||
{
|
||||
return dataCleanupMaxAllowedAngleDegree;
|
||||
}
|
||||
|
||||
void JKQTPFunctionLineGraphBase::setDisplaySamplePoints(bool __value)
|
||||
{
|
||||
this->displaySamplePoints = __value;
|
||||
}
|
||||
|
||||
bool JKQTPFunctionLineGraphBase::getDisplaySamplePoints() const
|
||||
{
|
||||
return this->displaySamplePoints;
|
||||
}
|
||||
|
||||
|
128
lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h
Normal file
128
lib/jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
Copyright (c) 2008-2020 Jan W. Krieger (<jan@jkrieger.de>)
|
||||
|
||||
|
||||
|
||||
This software is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License (LGPL) as published by
|
||||
the Free Software Foundation, either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License (LGPL) for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License (LGPL)
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <QString>
|
||||
#include <QPainter>
|
||||
#include <QPair>
|
||||
#include "jkqtplotter/graphs/jkqtpscatter.h"
|
||||
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
|
||||
#include "jkqtplotter/jkqtplotter_imexport.h"
|
||||
#include "jkqtcommon/jkqtpgeometrytools.h"
|
||||
#include <functional>
|
||||
|
||||
#ifndef jkqtpevaluatedfunctionbase_H
|
||||
#define jkqtpevaluatedfunctionbase_H
|
||||
|
||||
|
||||
|
||||
|
||||
/*! \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 JKQTPFunctionLineGraphBase: public JKQTPGraph {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
/** \brief class constructor */
|
||||
JKQTPFunctionLineGraphBase(JKQTBasePlotter* parent=nullptr);
|
||||
|
||||
/** \brief class constructor */
|
||||
JKQTPFunctionLineGraphBase(JKQTPlotter* parent);
|
||||
|
||||
/** \brief class destructor */
|
||||
virtual ~JKQTPFunctionLineGraphBase() ;
|
||||
|
||||
|
||||
/*! \copydoc minSamples */
|
||||
unsigned int getMinSamples() const;
|
||||
/*! \copydoc maxRefinementDegree */
|
||||
unsigned int getMaxRefinementDegree() const;
|
||||
/*! \copydoc slopeTolerance */
|
||||
double getSlopeTolerance() const;
|
||||
/*! \copydoc minPixelPerSample */
|
||||
double getMinPixelPerSample() const;
|
||||
/*! \copydoc dataCleanupMaxAllowedAngleDegree */
|
||||
double getDataCleanupMaxAllowedAngleDegree() const;
|
||||
/*! \copydoc displaySamplePoints */
|
||||
bool getDisplaySamplePoints() const;
|
||||
public slots:
|
||||
/*! \copydoc minSamples */
|
||||
void setMinSamples(const unsigned int & __value);
|
||||
/*! \copydoc maxRefinementDegree */
|
||||
void setMaxRefinementDegree(const unsigned int & __value);
|
||||
/*! \copydoc slopeTolerance */
|
||||
void setSlopeTolerance(double __value);
|
||||
/*! \copydoc minPixelPerSample */
|
||||
void setMinPixelPerSample(double __value);
|
||||
/*! \copydoc dataCleanupMaxAllowedAngleDegree */
|
||||
void setDataCleanupMaxAllowedAngleDegree(double __value);
|
||||
/*! \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<QPointF> data;
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true) =0;
|
||||
|
||||
/** \brief the minimum number of points to evaluate the function at */
|
||||
unsigned int minSamples;
|
||||
/** \brief the maximum number of recursive refinement steps
|
||||
*
|
||||
* each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
|
||||
* of points plotted at all are thus:
|
||||
* \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
|
||||
*/
|
||||
unsigned int maxRefinementDegree;
|
||||
/** \brief the tolerance for the difference of two subsequent slopes */
|
||||
double slopeTolerance;
|
||||
/** \brief create one sample at least every \a minPixelPerSample pixels */
|
||||
double minPixelPerSample;
|
||||
/** \brief in the clean-up step of plot-data creation, a point is removed from the data, if
|
||||
* it caused its neighboring line-segments to form an angle less than this value, given in degrees. */
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif // jkqtpevaluatedfunctionbase_H
|
@ -35,17 +35,11 @@
|
||||
|
||||
|
||||
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(JKQTBasePlotter* parent):
|
||||
JKQTPGraph(parent)
|
||||
JKQTPFunctionLineGraphBase(parent)
|
||||
{
|
||||
tmin=0.0;
|
||||
tmax=1.0;
|
||||
params=nullptr;
|
||||
minSamples=100;
|
||||
maxRefinementDegree=7;
|
||||
slopeTolerance=0.005;
|
||||
minPixelPerSample=32;
|
||||
plotRefinement=true;
|
||||
displaySamplePoints=false;
|
||||
|
||||
initLineStyle(parent, parentPlotStyle);
|
||||
|
||||
@ -268,7 +262,7 @@ void JKQTPXYFunctionLineGraph::createPlotData(bool collectParams) {
|
||||
|
||||
JKQTPAdaptiveFunctionGraphEvaluator evaluator(fTransformedFunc, minSamples, maxRefinementDegree, slopeTolerance, minPixelPerSample);
|
||||
data=evaluator.evaluate(tmin, tmax);
|
||||
|
||||
data=JKQTPSimplyfyLineSegemnts(data, dataCleanupMaxAllowedAngleDegree);
|
||||
}
|
||||
|
||||
void JKQTPXYFunctionLineGraph::collectParameters()
|
||||
@ -326,17 +320,7 @@ void JKQTPXYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
}
|
||||
|
||||
|
||||
QColor c=getLineColor();
|
||||
c.setHsv(fmod(c.hue()+90, 360), c.saturation(), c.value());
|
||||
if (displaySamplePoints) {
|
||||
painter.save(); auto __finalpaintsamplepoints=JKQTPFinally([&painter]() {painter.restore();});
|
||||
for (const auto& d: data) {
|
||||
if (JKQTPIsOKFloat(d.x()) && JKQTPIsOKFloat(d.x())) {
|
||||
JKQTPPlotSymbol(painter, d.x(), d.y(), JKQTPCross, 6,1*parent->getLineWidthMultiplier(), c, QColor(Qt::transparent));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (displaySamplePoints) drawSamplePoints(painter, getLineColor());
|
||||
}
|
||||
drawErrorsAfter(painter);
|
||||
//std::cout<<"plot done\n";
|
||||
@ -409,66 +393,6 @@ QVector<double> JKQTPXYFunctionLineGraph::getInternalParams() const {
|
||||
return iparams;
|
||||
}
|
||||
|
||||
void JKQTPXYFunctionLineGraph::setMinSamples(const unsigned int &__value)
|
||||
{
|
||||
this->minSamples = __value;
|
||||
}
|
||||
|
||||
unsigned int JKQTPXYFunctionLineGraph::getMinSamples() const
|
||||
{
|
||||
return this->minSamples;
|
||||
}
|
||||
|
||||
void JKQTPXYFunctionLineGraph::setMaxRefinementDegree(const unsigned int &__value)
|
||||
{
|
||||
this->maxRefinementDegree = __value;
|
||||
}
|
||||
|
||||
unsigned int JKQTPXYFunctionLineGraph::getMaxRefinementDegree() const
|
||||
{
|
||||
return this->maxRefinementDegree;
|
||||
}
|
||||
|
||||
void JKQTPXYFunctionLineGraph::setSlopeTolerance(double __value)
|
||||
{
|
||||
this->slopeTolerance = __value;
|
||||
}
|
||||
|
||||
double JKQTPXYFunctionLineGraph::getSlopeTolerance() const
|
||||
{
|
||||
return this->slopeTolerance;
|
||||
}
|
||||
|
||||
void JKQTPXYFunctionLineGraph::setMinPixelPerSample(double __value)
|
||||
{
|
||||
this->minPixelPerSample = __value;
|
||||
}
|
||||
|
||||
double JKQTPXYFunctionLineGraph::getMinPixelPerSample() const
|
||||
{
|
||||
return this->minPixelPerSample;
|
||||
}
|
||||
|
||||
void JKQTPXYFunctionLineGraph::setPlotRefinement(bool __value)
|
||||
{
|
||||
this->plotRefinement = __value;
|
||||
}
|
||||
|
||||
bool JKQTPXYFunctionLineGraph::getPlotRefinement() const
|
||||
{
|
||||
return this->plotRefinement;
|
||||
}
|
||||
|
||||
void JKQTPXYFunctionLineGraph::setDisplaySamplePoints(bool __value)
|
||||
{
|
||||
this->displaySamplePoints = __value;
|
||||
}
|
||||
|
||||
bool JKQTPXYFunctionLineGraph::getDisplaySamplePoints() const
|
||||
{
|
||||
return this->displaySamplePoints;
|
||||
}
|
||||
|
||||
|
||||
bool JKQTPXYFunctionLineGraph::usesColumn(int c) const
|
||||
{
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
|
||||
#include "jkqtplotter/jkqtplotter_imexport.h"
|
||||
#include "jkqtcommon/jkqtpgeometrytools.h"
|
||||
#include "jkqtplotter/graphs/jkqtpevaluatedfunctionbase.h"
|
||||
#include <functional>
|
||||
|
||||
#ifndef jkqtpevaluatedparametriccurve_H
|
||||
@ -57,14 +58,17 @@ typedef std::function<QPointF(double)> jkqtpSimpleParametricCurveFunctionType;
|
||||
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 implements an intelligent plotting algorithm for functions. It starts by sampling
|
||||
the function at minSamples positions. Then each function interval is bisected recursively if
|
||||
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
|
||||
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
|
||||
@ -84,7 +88,7 @@ typedef std::function<QPointF(double)> jkqtpSimpleParametricCurveFunctionType;
|
||||
|
||||
\see \ref JKQTPlotterEvalCurves , JKQTPAdaptiveFunctionGraphEvaluator, JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph
|
||||
*/
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPGraph, public JKQTPGraphLineStyleMixin {
|
||||
class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPFunctionLineGraphBase, public JKQTPGraphLineStyleMixin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
@ -177,30 +181,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPGraph, public
|
||||
/** \brief returns the currently set internal parameter vector */
|
||||
QVector<double> getInternalParams() const;
|
||||
|
||||
/*! \copydoc minSamples */
|
||||
void setMinSamples(const unsigned int & __value);
|
||||
/*! \copydoc minSamples */
|
||||
unsigned int getMinSamples() const;
|
||||
/*! \copydoc maxRefinementDegree */
|
||||
void setMaxRefinementDegree(const unsigned int & __value);
|
||||
/*! \copydoc maxRefinementDegree */
|
||||
unsigned int getMaxRefinementDegree() const;
|
||||
/*! \copydoc slopeTolerance */
|
||||
void setSlopeTolerance(double __value);
|
||||
/*! \copydoc slopeTolerance */
|
||||
double getSlopeTolerance() const;
|
||||
/*! \copydoc minPixelPerSample */
|
||||
void setMinPixelPerSample(double __value);
|
||||
/*! \copydoc minPixelPerSample */
|
||||
double getMinPixelPerSample() const;
|
||||
/*! \copydoc plotRefinement */
|
||||
void setPlotRefinement(bool __value);
|
||||
/*! \copydoc plotRefinement */
|
||||
bool getPlotRefinement() const;
|
||||
/*! \copydoc displaySamplePoints */
|
||||
void setDisplaySamplePoints(bool __value);
|
||||
/*! \copydoc displaySamplePoints */
|
||||
bool getDisplaySamplePoints() const;
|
||||
|
||||
|
||||
/*! \copydoc parameterColumn */
|
||||
void setParameterColumn(int __value);
|
||||
@ -233,14 +214,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPGraph, public
|
||||
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 plot data calculated by createPlotData() */
|
||||
QVector<QPointF> data;
|
||||
|
||||
/** \brief fill the data array with data from the function plotFunction */
|
||||
virtual void createPlotData( bool collectParams=true);
|
||||
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();
|
||||
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;
|
||||
@ -251,23 +228,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPGraph, public
|
||||
jkqtpSimpleParametricCurveFunctionType simplePlotFunction;
|
||||
/** \brief pointer to the parameters supplied to the plotting funtion */
|
||||
void* params;
|
||||
/** \brief the minimum number of points to evaluate the function at */
|
||||
unsigned int minSamples;
|
||||
/** \brief the maximum number of recursive refinement steps
|
||||
*
|
||||
* each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
|
||||
* of points plotted at all are thus:
|
||||
* \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
|
||||
*/
|
||||
unsigned int maxRefinementDegree;
|
||||
/** \brief the tolerance for the difference of two subsequent slopes */
|
||||
double slopeTolerance;
|
||||
/** \brief create one sample at least every \a minPixelPerSample pixels */
|
||||
double minPixelPerSample;
|
||||
/** \brief switch on or off [default: on] the plot refinement algorithm */
|
||||
bool plotRefinement;
|
||||
/** \brief if true [default: off] display the points where the function has been sampled */
|
||||
bool displaySamplePoints;
|
||||
|
||||
/** \brief internal storage for the current function parameters for plotFunction (which may stem from different sources, as direct data, a datastore column ...) */
|
||||
QVector<double> iparams;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user