new: a new graph class JKQTPXYFunctionLineGraph draws parametric 2D curves (f(t) -> [x,y])

This commit is contained in:
jkriege2 2020-09-04 23:41:23 +02:00
parent 33a9cb5b2d
commit c57c672f78
22 changed files with 1051 additions and 36 deletions

View File

@ -86,6 +86,7 @@ addSimpleTest(datastore_regression)
addSimpleTest(datastore_groupedstat)
addSimpleTest(contourplot)
addSimpleTest(violinplot)
addSimpleTest(evalcurve)
#addSimpleTest(rgbimageplot_opencv)
#addSimpleTest(imageplot_opencv)

View File

@ -56,6 +56,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
<tr><td> \image html parsedfunctionplot_small.png
<td> \subpage JKQTPlotterParsedFunctionPlot
<td> `JKQTPXParsedFunctionLineGraph` <br> plotting functions with the internal math equation parser/evaluator
<tr><td> \image html evalcurve_small.png
<td> \subpage JKQTPlotterEvalCurves
<td> `JKQTPXYFunctionLineGraph`
<tr><td> \image html boxplot_small.png
<td> \subpage JKQTPlotterBoxplotsGraphs
<td> `JKQTPBoxplotVerticalGraph`, `JKQTPBoxplotHorizontalGraph`, ...

View File

@ -356,7 +356,10 @@ This group assembles graphs that show their data with symbols and optionally wit
<th> Classes
<tr>
<td>\image html functionplot_small.png
<td> JKQTPXParsedFunctionLineGraph, JKQTPYParsedFunctionLineGraph
<td> JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph
<tr>
<td>\image html evalcurve_small.png
<td> JKQTPXYFunctionLineGraph
</table>
\defgroup jkqtplotter_parsedFgraphs Parsed Function Graphs
@ -368,7 +371,7 @@ This group assembles graphs that show their data with symbols and optionally wit
<th> Classes
<tr>
<td>\image html functionplot_small.png
<td> JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph
<td> JKQTPXParsedFunctionLineGraph, JKQTPYParsedFunctionLineGraph
</table>
\defgroup jkqtplotter_barssticks Barcharts, Impulse-Charts, ...

View File

@ -25,6 +25,7 @@ Changes, compared to \ref page_whatsnew_V2019_11 "v2019.11" include:
<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>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>
</ul>
\subsection page_whatsnew_TRUNK_DOWNLOAD trunk: Download

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -58,5 +58,6 @@ add_subdirectory(symbols_and_styles)
add_subdirectory(ui)
add_subdirectory(user_interaction)
add_subdirectory(violinplot)
add_subdirectory(evalcurve)

View File

@ -22,6 +22,7 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/parametriccurve_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/parametriccurve) | [Plotting Parametric Curves](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/parametriccurve) | `JKQTPXYLineGraph` and `JKQTPXYParametrizedScatterGraph` <br> C++-style QVector as plot data <br> parametric curve plotting |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/functionplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/functionplot) | [Plotting Mathematical Functions as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/functionplot) | `JKQTPXFunctionLineGraph` <br> diretly plotting C/C++-functions |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/parsedfunctionplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/parsedfunctionplot) | [Plotting Parsed Mathematical Functions as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/parsedfunctionplot) | `JKQTPXParsedFunctionLineGraph` <br> plotting functions with the internal math equation parser/evaluator |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/evalcurve_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/evalcurve) | [Plotting Parametric Mathematical Curves as Line Graphs](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/evalcurve) | `JKQTPXYFunctionLineGraph` |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/boxplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/boxplot) | [Plotting Box Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/boxplot) | `JKQTPBoxplotVerticalGraph`, `JKQTPBoxplotHorizontalGraph` |
| [![](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/violinplot_small.png)](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/violinplot) | [Plotting Violin Plots](https://github.com/jkriege2/JKQtPlotter/tree/master/examples/violinplot) | `JKQTPViolinplotVerticalElement`, `JKQTPViolinplotHorizontalElement` |

View File

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.0)
set(EXAMPLE_NAME evalcurve)
set(EXENAME jkqtptest_${EXAMPLE_NAME})
message( STATUS ".. Building Example ${EXAMPLE_NAME}" )
# Set up source files
set(SOURCES ${EXAMPLE_NAME}.cpp)
set(HEADERS )
set(RESOURCES )
set(UIS )
add_executable(${EXENAME} WIN32 ${SOURCES} ${HEADERS} ${RESOURCES} ${UIS})
target_include_directories(${EXENAME} PRIVATE ../../lib)
if(JKQtPlotter_BUILD_STATIC_LIBS)
target_link_libraries(${EXENAME} JKQTPlotterLib)
elseif(JKQtPlotter_BUILD_SHARED_LIBS)
target_link_libraries(${EXENAME} JKQTPlotterSharedLib)
endif()
# Installation
install(TARGETS ${EXENAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
#Installation of Qt DLLs on Windows
jkqtplotter_deployqt(${EXENAME})

View File

@ -0,0 +1,42 @@
# 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.
[TOC]
# Simple C++ inline function
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->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
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
```.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.
# Screenshot
This code snippets above result in a plot like this:
![evalcurve](https://raw.githubusercontent.com/jkriege2/JKQtPlotter/master/screenshots/evalcurve.png)
# 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) .

View File

@ -0,0 +1,52 @@
/** \example evalcurve.cpp
* Shows how to plot Mathematical Functions as Line Graphs with JKQTPlotter (as evaluated C/C++ functions)
*
* \ref JKQTPlotterEvalCurves
*/
#include <QApplication>
#include <QVector>
#include <QMap>
#include "jkqtplotter/jkqtplotter.h"
#include "jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// 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;
JKQTPlotter* plot=new JKQTPlotter(&mainWin);
QVBoxLayout* layout=new QVBoxLayout;
mainWin.setLayout(layout);
layout->addWidget(plot);
// 2. now we add a JKQTPXYFunctionLineGraph object, which will draw a simple function
// 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));
});
func1->setTRange(0, 2.0*JKQTPSTATISTICS_PI);
func1->setTitle("C++-inline function $[ sin(5{\\cdot}t+\\pi/4), sin(4{\\cdot}t) ]$");
plot->addGraph(func1);
// 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"));
plot->getPlotter()->setKeyPosition(JKQTPKeyOutsideBottomLeft);
// 4. scale the plot so the graph is contained
plot->setXY(-1.1,1.1,-1.1,1.1);
// show window and make it a decent size
mainWin.show();
mainWin.resize(800,800);
return app.exec();
}

View File

@ -0,0 +1,28 @@
# source code for this simple demo
SOURCES = evalcurve.cpp
# configure Qt
CONFIG += link_prl qt
QT += core gui xml svg
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets printsupport
# output executable name
TARGET = evalcurve
# include JKQTPlotter source code
DEPENDPATH += ../../lib ../../qmake/staticlib/jkqtplotterlib
INCLUDEPATH += ../../lib
CONFIG (debug, debug|release) {
LIBS += -L../../qmake/staticlib/jkqtplotterlib/debug -ljkqtplotterlib_debug
} else {
LIBS += -L../../qmake/staticlib/jkqtplotterlib/release -ljkqtplotterlib
}
message("LIBS = $$LIBS")
win32-msvc*: DEFINES += _USE_MATH_DEFINES
win32-msvc*: DEFINES += NOMINMAX

View File

@ -0,0 +1,8 @@
TEMPLATE = subdirs
SUBDIRS += jkqtplotterlib evalcurve
jkqtplotterlib.file = ../../qmake/staticlib/jkqtplotterlib/jkqtplotterlib.pro
evalcurve.file=$$PWD/evalcurve.pro
evalcurve.depends = jkqtplotterlib

View File

@ -69,13 +69,10 @@ QVector<QPointF> JKQTPSplitEllipseIntoPoints(std::function<QPointF (QPointF)> fT
std::function<QPointF(double)> fell=[&](double t)->QPointF {
return QPointF(x+a*cos(t)*cosa-b*sin(t)*sina, y+a*cos(t)*sina+b*sin(t)*cosa);
};
std::function<double(double)> fx = [&](double t) ->double {
return fTransform(fell(t)).x();
std::function<QPointF(double)> fxy = [&](double t) ->QPointF {
return fTransform(fell(t));
};
std::function<double(double)> fy = [&](double t) ->double {
return fTransform(fell(t)).y();
};
JKQTPAdaptiveFunctionGraphEvaluator eval(fx, fy);
JKQTPAdaptiveFunctionGraphEvaluator eval(fxy);
const QVector<QPointF> points=eval.evaluate(angle_start*JKQTPSTATISTICS_PI/180.0, angle_end*JKQTPSTATISTICS_PI/180.0);
if (points.size()>0) {
@ -238,6 +235,17 @@ QVector<QPointF> JKQTPSimplyfyLineSegemnts(const QVector<QPointF> &points, doubl
JKQTPAdaptiveFunctionGraphEvaluator::JKQTPAdaptiveFunctionGraphEvaluator(const std::function<double (double)> &fx_, const std::function<double (double)> &fy_, unsigned int minSamples_, unsigned int maxRefinementDegree_, double slopeTolerance_, double minPixelPerSample_):
fx(fx_),
fy(fy_),
fxy([&](double t)->QPointF { return QPointF(fx(t), fy(t)); }),
minSamples(minSamples_),
maxRefinementDegree(maxRefinementDegree_),
slopeTolerance(slopeTolerance_),
minPixelPerSample(minPixelPerSample_)
{
}
JKQTPAdaptiveFunctionGraphEvaluator::JKQTPAdaptiveFunctionGraphEvaluator(const std::function<QPointF (double)> &fxy_, unsigned int minSamples_, unsigned int maxRefinementDegree_, double slopeTolerance_, double minPixelPerSample_):
fxy(fxy_),
minSamples(minSamples_),
maxRefinementDegree(maxRefinementDegree_),
slopeTolerance(slopeTolerance_),
@ -252,19 +260,19 @@ QVector<QPointF> JKQTPAdaptiveFunctionGraphEvaluator::evaluate(double tmin, doub
double delta_t0=(tmax-tmin)/static_cast<double>(minSamples);
intData.push_front(std::pair<double, QPointF>(tmin, QPointF(fx(tmin), fy(tmin))));
intData.push_front(std::pair<double, QPointF>(tmin, fxy(tmin)));
InternalList::iterator a=intData.begin();
//qDebug()<<"**************************************************";
for (double t=tmin+delta_t0; t<tmax; t=t+delta_t0) {
const double treal=t;
intData.insert_after(a, std::pair<double, QPointF>(treal, QPointF(fx(treal), fy(treal))));
intData.insert_after(a, std::pair<double, QPointF>(treal, fxy(treal)));
InternalList::iterator b=a; b++;
//qDebug()<<"t="<<t<<", dist(a,b)="<<std::distance(a,b);
refine(intData, a, b, 0);
//qDebug()<<" after refine: dist(a,b)="<<std::distance(a,b);
a=b;
}
intData.insert_after(a, std::pair<double, QPointF>(tmax, QPointF(fx(tmax), fy(tmax))));
intData.insert_after(a, std::pair<double, QPointF>(tmax, fxy(tmax)));
auto b=a; b++;
refine(intData, a, b, 0);
// copy data to output data structure
@ -284,7 +292,7 @@ void JKQTPAdaptiveFunctionGraphEvaluator::refine(JKQTPAdaptiveFunctionGraphEvalu
const double tmid=ta+(tb-ta)/2.0;
const QPointF pa=a->second;
const QPointF pb=b->second;
const QPointF pmid(fx(tmid), fy(tmid));
const QPointF pmid(fxy(tmid));
const double delta=QLineF(pa, pb).length();
const double slope_a_mid=(pmid.y()-pa.y())/(pmid.x()-pa.x());
@ -299,13 +307,10 @@ void JKQTPAdaptiveFunctionGraphEvaluator::refine(JKQTPAdaptiveFunctionGraphEvalu
QVector<QPointF> JKQTPSplitLineIntoPoints(const QLineF &line, std::function<QPointF (QPointF)> fTransform)
{
std::function<double(double)> fx = [&line, &fTransform](double t) ->double {
return fTransform(line.p1()+t*(line.p2()-line.p1())).x();
std::function<QPointF(double)> fxy = [&line, &fTransform] (double t) ->QPointF {
return fTransform(line.p1()+t*(line.p2()-line.p1()));
};
std::function<double(double)> fy = [&line, &fTransform](double t) ->double {
return fTransform(line.p1()+t*(line.p2()-line.p1())).y();
};
JKQTPAdaptiveFunctionGraphEvaluator eval(fx, fy);
JKQTPAdaptiveFunctionGraphEvaluator eval(fxy);
return eval.evaluate(0.0,1.0);
}

View File

@ -62,6 +62,19 @@ public:
*/
JKQTPAdaptiveFunctionGraphEvaluator(const std::function<double(double)>& fx_, const std::function<double(double)>& fy_, unsigned int minSamples_=10, unsigned int maxRefinementDegree_=5, double slopeTolerance_=0.005, double minPixelPerSample_=32);
/** \brief class constructor
*
* \param fxy function \f$ [x,y]=f_{xy}(t) \f$
* \param minSamples the minimum number of points to evaluate the function at
* \param maxRefinementDegree 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]
* \param slopeTolerance the tolerance for the difference of two subsequent slopes
* \param minPixelPerSample create one sample at least every \a minPixelPerSample pixels
*/
JKQTPAdaptiveFunctionGraphEvaluator(const std::function<QPointF(double)>& fxy_, unsigned int minSamples_=10, unsigned int maxRefinementDegree_=5, double slopeTolerance_=0.005, double minPixelPerSample_=32);
/** \brief evaluate the function specified in the constructor over the given parameter range \a tmin ... \a tmax
*
* \param tmin lower parameter range limit \f$ t_\text{min} \f$
@ -77,6 +90,8 @@ protected:
std::function<double(double)> fx;
/** \brief function \f$ f_y(t) \f$ */
std::function<double(double)> fy;
/** \brief function \f$ [x,y]=f_{xy}(t) \f$ */
std::function<QPointF(double)> fxy;
/** \brief the minimum number of points to evaluate the function at */
unsigned int minSamples;
/** \brief the maximum number of recursive refinement steps

View File

@ -49,6 +49,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtprange.h \
$$PWD/jkqtplotter/graphs/jkqtpspecialline.h \
$$PWD/jkqtplotter/graphs/jkqtpbarchart.h \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h \
$$PWD/jkqtplotter/overlays/jkqtpbasicoverlays.h \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.h \
$$PWD/jkqtplotter/gui/jkqtpenhancedspinboxes.h \
@ -98,6 +99,7 @@ isEmpty(JKQTP_PLOTTER_PRI_INCLUDED) {
$$PWD/jkqtplotter/graphs/jkqtprange.cpp \
$$PWD/jkqtplotter/graphs/jkqtpspecialline.cpp \
$$PWD/jkqtplotter/graphs/jkqtpbarchart.cpp \
$$PWD/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp \
$$PWD/jkqtplotter/overlays/jkqtpbasicoverlays.cpp \
$$PWD/jkqtplotter/gui/jkqtpcomboboxes.cpp \
$$PWD/jkqtplotter/gui/jkqtpenhancedspinboxes.cpp \

View File

@ -51,7 +51,7 @@ set(SOURCES_GRAPHS
graphs/jkqtpgeobase.cpp
graphs/jkqtpgeolines.cpp
graphs/jkqtpgeoshapes.cpp
graphs/jkqtpimage.cpp
graphs/jkqtpimage.cpp
graphs/jkqtpimpulses.cpp
graphs/jkqtpparsedfunction.cpp
graphs/jkqtppeakstream.cpp
@ -62,6 +62,7 @@ set(SOURCES_GRAPHS
graphs/jkqtpviolinplot.cpp
graphs/jkqtpviolinplotstylingmixins.cpp
graphs/jkqtpstatisticsadaptors.cpp
graphs/jkqtpevaluatedparametriccurve.cpp
)
set(SOURCES_OVERLAYS
overlays/jkqtpbasicoverlays.cpp
@ -118,6 +119,7 @@ set(HEADERS_GRAPHS
graphs/jkqtprange.h
graphs/jkqtpspecialline.h
graphs/jkqtpbarchart.h
graphs/jkqtpevaluatedparametriccurve.h
)
set(HEADERS_OVERLAY
overlays/jkqtpbasicoverlays.h

View File

@ -92,13 +92,8 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionTy
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(const jkqtpSimplePlotFunctionType &f, const QString &title_, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(parent)
JKQTPXFunctionLineGraph(f, title_, parent->getPlotter())
{
title=title_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=f;
functionType=SpecialFunction::UserFunction;
clearData();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f, const QString &title_, JKQTBasePlotter *parent):
@ -112,15 +107,26 @@ JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(jkqtpSimplePlotFunctionType &&f
}
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_;
plotFunction=jkqtpPlotFunctionType();
simplePlotFunction=std::move(f);
functionType=SpecialFunction::UserFunction;
functionType=type;
setParams(params);
clearData();
}
JKQTPXFunctionLineGraph::JKQTPXFunctionLineGraph(JKQTPXFunctionLineGraph::SpecialFunction type, const QVector<double> &params, const QString &title, JKQTPlotter *parent):
JKQTPXFunctionLineGraph(type, params, title, parent->getPlotter())
{
}
JKQTPXFunctionLineGraph::~JKQTPXFunctionLineGraph() {
clearData();
@ -592,6 +598,18 @@ JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType &&f
}
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) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPYFunctionLineGraph::draw");

View File

@ -33,7 +33,7 @@
/*! \brief type of functions that may be plottet
/*! \brief type of functions that may be plotted by JKQTPXFunctionLineGraph and JKQTPYFunctionLineGraph
\ingroup jkqtplotter_functiongraphs
This is the type of functions \f$ y=f(x, \vec{p}) \f$ that may be plottet by JKQTPXFunctionLineGraph
@ -43,7 +43,7 @@
*/
typedef std::function<double(double, void*)> jkqtpPlotFunctionType;
/*! \brief simplified type of functions (without parameters) that may be plottet
/*! \brief simplified type of functions (without parameters) that may be plotted by JKQTPXFunctionLineGraph and JKQTPYFunctionLineGraph
\ingroup jkqtplotter_functiongraphs
This is the type of functions \f$ y=f(x) \f$ that may be plottet by JKQTPXFunctionLineGraph
@ -63,10 +63,11 @@ typedef std::function<double(double)> jkqtpSimplePlotFunctionType;
In addition all sampling points except minimum and maximum are beeing shifted by a random fraction their
distance to the other points. This helps to prevent beats when sampling periodic functions.
the following image
The following image shows some example graphs:
\image html plot_functionplots.png
\see \ref JKQTPlotterFunctionPlots, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression()
\see \ref JKQTPlotterFunctionPlots, JKQTPYFunctionLineGraph, JKQTPXYFunctionLineGraph, jkqtpstatAddPolyFit(), jkqtpstatAddWeightedRegression(), jkqtpstatAddRobustIRLSRegression(), jkqtpstatAddRegression(), jkqtpstatAddLinearWeightedRegression(), jkqtpstatAddRobustIRLSLinearRegression(), jkqtpstatAddLinearRegression()
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public JKQTPGraphLineStyleMixin, public JKQTPGraphFillStyleMixin {
Q_OBJECT
@ -94,6 +95,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
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;
@ -292,7 +297,7 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
/** \brief fill the data array with data from the function plotFunction */
virtual void createPlotData( bool collectParams=true);
/** \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 refine datapoints on the function graph between two evaluations \a a and \a b */
void refine(doublePair* a, doublePair* b, unsigned int degree=0);
@ -357,14 +362,20 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPXFunctionLineGraph: public JKQTPGraph, public
QBrush getErrorBrush(JKQTPEnhancedPainter& painter) const;
QPen getErrorLinePen(JKQTPEnhancedPainter &painter) const;
QVector<double> iparams, ierrorparams;
/** \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 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 This implements line plots where the data is taken from a user supplied function \f$ x=f(y) \f$
\ingroup jkqtplotter_functiongraphs
\see \ref JKQTPlotterFunctionPlots
The following image shows some example graphs:
\image html functionplot_fy.png
\see \ref JKQTPlotterFunctionPlots , JKQTPXFunctionLineGraph, JKQTPXYFunctionLineGraph
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPYFunctionLineGraph: public JKQTPXFunctionLineGraph {
Q_OBJECT
@ -381,6 +392,10 @@ class JKQTPLOTTER_LIB_EXPORT JKQTPYFunctionLineGraph: public JKQTPXFunctionLineG
JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPYFunctionLineGraph(jkqtpSimplePlotFunctionType && f, const QString& title, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPYFunctionLineGraph(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTBasePlotter* parent);
/** \brief class constructor */
JKQTPYFunctionLineGraph(SpecialFunction type, const QVector<double>& params, const QString& title, JKQTPlotter* parent);
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;

View File

@ -0,0 +1,514 @@
/*
Copyright (c) 2020-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/jkqtpevaluatedparametriccurve.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"
#define SmallestGreaterZeroCompare_xvsgz() if ((xvsgz>10.0*DBL_MIN)&&((smallestGreaterZero<10.0*DBL_MIN) || (xvsgz<smallestGreaterZero))) smallestGreaterZero=xvsgz;
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(JKQTBasePlotter* parent):
JKQTPGraph(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);
parameterColumn=-1;
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(JKQTPlotter* parent):
JKQTPXYFunctionLineGraph(parent->getPlotter())
{
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpSimpleParametricCurveFunctionType &f, const QString &title_, double tmin_, double tmax_, JKQTBasePlotter *parent):
JKQTPXYFunctionLineGraph(parent)
{
tmin=tmin_;
tmax=tmax_;
title=title_;
plotFunction=jkqtpParametricCurveFunctionType();
simplePlotFunction=f;
data.clear();
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpSimpleParametricCurveFunctionType &f, const QString &title_, double tmin_, double tmax_, JKQTPlotter *parent):
JKQTPXYFunctionLineGraph(f, title_, tmin_, tmax_, parent->getPlotter())
{
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(jkqtpSimpleParametricCurveFunctionType &&f, const QString &title_, double tmin_, double tmax_, JKQTBasePlotter *parent):
JKQTPXYFunctionLineGraph(parent)
{
tmin=tmin_;
tmax=tmax_;
title=title_;
plotFunction=jkqtpParametricCurveFunctionType();
simplePlotFunction=std::move(f);
data.clear();
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(jkqtpSimpleParametricCurveFunctionType &&f, const QString &title_, double tmin_, double tmax_, JKQTPlotter *parent):
JKQTPXYFunctionLineGraph(std::forward<jkqtpSimpleParametricCurveFunctionType>(f), title_, tmin_, tmax_, parent->getPlotter())
{
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(jkqtpParametricCurveFunctionType &&f, const QString &title_, double tmin_, double tmax_, JKQTBasePlotter *parent):
JKQTPXYFunctionLineGraph(parent)
{
tmin=tmin_;
tmax=tmax_;
title=title_;
simplePlotFunction=jkqtpSimpleParametricCurveFunctionType();
plotFunction=std::move(f);
data.clear();
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(jkqtpParametricCurveFunctionType &&f, const QString &title_, double tmin_, double tmax_, JKQTPlotter *parent):
JKQTPXYFunctionLineGraph(std::forward<jkqtpParametricCurveFunctionType>(f), title_, tmin_, tmax_, parent->getPlotter())
{
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpParametricCurveFunctionType &f, const QString &title_, double tmin_, double tmax_, JKQTBasePlotter *parent):
JKQTPXYFunctionLineGraph(parent)
{
tmin=tmin_;
tmax=tmax_;
title=title_;
simplePlotFunction=jkqtpSimpleParametricCurveFunctionType();
plotFunction=std::move(f);
data.clear();
}
JKQTPXYFunctionLineGraph::JKQTPXYFunctionLineGraph(const jkqtpParametricCurveFunctionType &f, const QString &title_, double tmin_, double tmax_, JKQTPlotter *parent):
JKQTPXYFunctionLineGraph(f, title_, tmin_, tmax_, parent->getPlotter())
{
}
JKQTPXYFunctionLineGraph::~JKQTPXYFunctionLineGraph() {
data.clear();
}
void JKQTPXYFunctionLineGraph::setPlotFunctionFunctor(const jkqtpParametricCurveFunctionType &__value)
{
simplePlotFunction=jkqtpSimpleParametricCurveFunctionType();
plotFunction = __value;
data.clear();
}
void JKQTPXYFunctionLineGraph::setPlotFunctionFunctor(const jkqtpSimpleParametricCurveFunctionType &__value)
{
plotFunction=jkqtpParametricCurveFunctionType();
simplePlotFunction=__value;
data.clear();
}
void JKQTPXYFunctionLineGraph::setPlotFunctionFunctor(jkqtpParametricCurveFunctionType &&__value)
{
simplePlotFunction=jkqtpSimpleParametricCurveFunctionType();
plotFunction = std::move(__value);
data.clear();
}
void JKQTPXYFunctionLineGraph::setPlotFunctionFunctor(jkqtpSimpleParametricCurveFunctionType &&__value)
{
plotFunction=jkqtpParametricCurveFunctionType();
simplePlotFunction=std::move(__value);
data.clear();
}
jkqtpParametricCurveFunctionType JKQTPXYFunctionLineGraph::getPlotFunctionFunctor() const
{
return plotFunction;
}
jkqtpSimpleParametricCurveFunctionType JKQTPXYFunctionLineGraph::getSimplePlotFunction() const
{
return simplePlotFunction;
}
void JKQTPXYFunctionLineGraph::setParams(void *__value)
{
if (this->params != __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();});
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();
}
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()<minx) minx=d.x();
double xvsgz;
xvsgz=d.x(); SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
} else {
smallestGreaterZero=minx=maxx=0; return false;
}
}
bool JKQTPXYFunctionLineGraph::getYMinMax(double &miny, double &maxy, double &smallestGreaterZero)
{
if (data.size()==0) createPlotData();
if (data.size()>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()<miny) miny=d.y();
double xvsgz;
xvsgz=d.x(); SmallestGreaterZeroCompare_xvsgz();
start=false;
}
}
return !start;
} else {
smallestGreaterZero=miny=maxy=0; return false;
}
}
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, params);
else if (simplePlotFunction) func=simplePlotFunction;
jkqtpSimpleParametricCurveFunctionType fTransformedFunc= std::bind([&](const JKQTPXYFunctionLineGraph* 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);
}
void JKQTPXYFunctionLineGraph::collectParameters()
{
if (parent && parameterColumn>=0) {
iparams.clear();
JKQTPDatastore* datastore=parent->getDatastore();
int imin=0;
int imax=static_cast<int>(datastore->getRows(parameterColumn));
for (int i=imin; i<imax; i++) {
double xv=datastore->get(parameterColumn,i);
iparams<<xv;
}
//qDebug()<<"iparams_beforeclean:";
//for (int i=0; i<iparams.size(); i++) qDebug()<<iparams[i];
int i=iparams.size()-1;
while (i>=0 && !JKQTPIsOKFloat(iparams[i])) {
iparams.remove(i,1);
i--;
}
//qDebug()<<"iparams:";
//for (i=0; i<iparams.size(); i++) qDebug()<<iparams[i];
params=&iparams;
}
}
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);
}
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));
}
}
}
}
drawErrorsAfter(painter);
//std::cout<<"plot done\n";
}
void JKQTPXYFunctionLineGraph::setParams(const QVector<double> &params)
{
iparams=params;
setParams(&iparams);
}
void JKQTPXYFunctionLineGraph::setCopiedParams(const double *params, int N)
{
QVector<double> v;
for (int i=0; i<N; i++) { v<<params[i]; }
setParams(v);
}
void JKQTPXYFunctionLineGraph::setParamsV(double p1) {
QVector<double> p;
p<<p1;
setParams(p);
}
void JKQTPXYFunctionLineGraph::setParamsV(double p1, double p2) {
QVector<double> p;
p<<p1<<p2;
setParams(p);
}
void JKQTPXYFunctionLineGraph::setParamsV(double p1, double p2, double p3) {
QVector<double> p;
p<<p1<<p2<<p3;
setParams(p);
}
void JKQTPXYFunctionLineGraph::setParamsV(double p1, double p2, double p3, double p4) {
QVector<double> p;
p<<p1<<p2<<p3<<p4;
setParams(p);
}
void JKQTPXYFunctionLineGraph::setParamsV(double p1, double p2, double p3, double p4, double p5) {
QVector<double> p;
p<<p1<<p2<<p3<<p4<<p5;
setParams(p);
}
void JKQTPXYFunctionLineGraph::setParameterColumn(int __value)
{
this->parameterColumn = __value;
}
int JKQTPXYFunctionLineGraph::getParameterColumn() const
{
return this->parameterColumn;
}
void JKQTPXYFunctionLineGraph::setParameterColumn(size_t __value) {
this->parameterColumn = static_cast<int>(__value);
}
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
{
return (c==parameterColumn);
}
double JKQTPXYFunctionLineGraph::getTMin() const
{
return tmin;
}
double JKQTPXYFunctionLineGraph::getTMax() const
{
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;
}

View File

@ -0,0 +1,275 @@
/*
Copyright (c) 2020-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 jkqtpevaluatedparametriccurve_H
#define jkqtpevaluatedparametriccurve_H
/*! \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, void*)> 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.
*/
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 implements an intelligent plotting algorithm for functions. It starts by sampling
the function at minSamples positions. Then each function interval is bisected recursively if
necessary. To do so the function is evaluated at the mid point and the slopes \f$ \alpha_{\mbox{left}} \f$
and \f$ \alpha_{\mbox{right}} \f$ of the two linear segments are compared. The midpoint is added
to the graph if \f[ \left|\alpha_{\mbox{right}}-\alpha_{\mbox{left}}\right|>\mbox{slopeTolerance} \f]
In addition all sampling points except minimum and maximum are beeing shifted by a random fraction their
distance to the other points. This helps to prevent beats when sampling periodic functions.
the following image 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
*/
class JKQTPLOTTER_LIB_EXPORT JKQTPXYFunctionLineGraph: public JKQTPGraph, public JKQTPGraphLineStyleMixin {
Q_OBJECT
public:
/** \brief class constructor */
JKQTPXYFunctionLineGraph(JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(const jkqtpSimpleParametricCurveFunctionType & f, const QString& title, double tmin_=0, double tmax_=1, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(const jkqtpSimpleParametricCurveFunctionType & f, const QString& title, double tmin_, double tmax_, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(jkqtpSimpleParametricCurveFunctionType && f, const QString& title, double tmin_=0, double tmax_=1, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(jkqtpSimpleParametricCurveFunctionType && f, const QString& title, double tmin_, double tmax_, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(const jkqtpParametricCurveFunctionType & f, const QString& title, double tmin_=0, double tmax_=1, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(const jkqtpParametricCurveFunctionType & f, const QString& title, double tmin_, double tmax_, JKQTPlotter* parent);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(jkqtpParametricCurveFunctionType && f, const QString& title, double tmin_=0, double tmax_=1, JKQTBasePlotter* parent=nullptr);
/** \brief class constructor */
JKQTPXYFunctionLineGraph(jkqtpParametricCurveFunctionType && f, const QString& title, double tmin_, double tmax_, JKQTPlotter* parent);
/** \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 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
*/
virtual void setPlotFunctionFunctor (jkqtpParametricCurveFunctionType && __value);
/** \brief sets a functor to be plotted
*
* \see plotFunction
*/
virtual void setPlotFunctionFunctor (const jkqtpParametricCurveFunctionType & __value);
/** \brief sets a functor to be plotted
*
* \see simplePlotFunction
*/
virtual 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;
/*! \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<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 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<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);
/*! \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;
/*! \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 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);
/** \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 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;
};
#endif // jkqtpevaluatedparametriccurve_H

BIN
screenshots/evalcurve.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB