diff --git a/JKQtPlotterBuildAllExamples.pro b/JKQtPlotterBuildAllExamples.pro
index 0c0ed5e3c5..deaa934880 100644
--- a/JKQtPlotterBuildAllExamples.pro
+++ b/JKQtPlotterBuildAllExamples.pro
@@ -86,6 +86,7 @@ addSimpleTest(datastore_regression)
addSimpleTest(datastore_groupedstat)
addSimpleTest(contourplot)
addSimpleTest(violinplot)
+addSimpleTest(evalcurve)
#addSimpleTest(rgbimageplot_opencv)
#addSimpleTest(imageplot_opencv)
diff --git a/doc/dox/examples_and_tutorials.dox b/doc/dox/examples_and_tutorials.dox
index eb9705e9d3..27693b23ea 100644
--- a/doc/dox/examples_and_tutorials.dox
+++ b/doc/dox/examples_and_tutorials.dox
@@ -56,6 +56,9 @@ All test-projects are Qt-projects that use qmake to build. You can load them int
\image html functionplot_small.png
- | JKQTPXFunctionLineGraph, JKQTPYFunctionLineGraph
+ | JKQTPXParsedFunctionLineGraph, JKQTPYParsedFunctionLineGraph
\defgroup jkqtplotter_barssticks Barcharts, Impulse-Charts, ...
diff --git a/doc/dox/whatsnew.dox b/doc/dox/whatsnew.dox
index ab85bc34a2..5b55d92c04 100644
--- a/doc/dox/whatsnew.dox
+++ b/doc/dox/whatsnew.dox
@@ -25,6 +25,7 @@ Changes, compared to \ref page_whatsnew_V2019_11 "v2019.11" include:
improved: constructors and access functions for several geometric objects (e.g. more constructors, additional functions to retrieve parameters in diferent forms, iterators for polygons, ...)
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)
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
+ new: a new graph class JKQTPXYFunctionLineGraph draws parametric 2D curves ( \f$ [x,y] = f(t) \f$ ), see \ref JKQTPlotterEvalCurves for an example
\subsection page_whatsnew_TRUNK_DOWNLOAD trunk: Download
diff --git a/doc/images/plot_evalcurve.png b/doc/images/plot_evalcurve.png
new file mode 100644
index 0000000000..38643cd913
Binary files /dev/null and b/doc/images/plot_evalcurve.png differ
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 36d6c4fbc6..e2e4670dbb 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -58,5 +58,6 @@ add_subdirectory(symbols_and_styles)
add_subdirectory(ui)
add_subdirectory(user_interaction)
add_subdirectory(violinplot)
+add_subdirectory(evalcurve)
diff --git a/examples/README.md b/examples/README.md
index 4473084bf8..94a38933a3 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -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` C++-style QVector as plot data 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` 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` 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` |
diff --git a/examples/evalcurve/CMakeLists.txt b/examples/evalcurve/CMakeLists.txt
new file mode 100644
index 0000000000..19dada8fe3
--- /dev/null
+++ b/examples/evalcurve/CMakeLists.txt
@@ -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})
diff --git a/examples/evalcurve/README.md b/examples/evalcurve/README.md
new file mode 100644
index 0000000000..a0ac644885
--- /dev/null
+++ b/examples/evalcurve/README.md
@@ -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) .
+
+
+
diff --git a/examples/evalcurve/evalcurve.cpp b/examples/evalcurve/evalcurve.cpp
new file mode 100644
index 0000000000..11c82eed45
--- /dev/null
+++ b/examples/evalcurve/evalcurve.cpp
@@ -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
+#include
+#include
+#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();
+}
diff --git a/examples/evalcurve/evalcurve.pro b/examples/evalcurve/evalcurve.pro
new file mode 100644
index 0000000000..6aa71828aa
--- /dev/null
+++ b/examples/evalcurve/evalcurve.pro
@@ -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
+
+
+
+
diff --git a/examples/evalcurve/evalcurve_and_lib.pro b/examples/evalcurve/evalcurve_and_lib.pro
new file mode 100644
index 0000000000..87a4b001f1
--- /dev/null
+++ b/examples/evalcurve/evalcurve_and_lib.pro
@@ -0,0 +1,8 @@
+TEMPLATE = subdirs
+
+SUBDIRS += jkqtplotterlib evalcurve
+
+jkqtplotterlib.file = ../../qmake/staticlib/jkqtplotterlib/jkqtplotterlib.pro
+
+evalcurve.file=$$PWD/evalcurve.pro
+evalcurve.depends = jkqtplotterlib
diff --git a/lib/jkqtcommon/jkqtpgeometrytools.cpp b/lib/jkqtcommon/jkqtpgeometrytools.cpp
index c1fd561681..4afd2f1332 100644
--- a/lib/jkqtcommon/jkqtpgeometrytools.cpp
+++ b/lib/jkqtcommon/jkqtpgeometrytools.cpp
@@ -69,13 +69,10 @@ QVector JKQTPSplitEllipseIntoPoints(std::function fT
std::function 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 fx = [&](double t) ->double {
- return fTransform(fell(t)).x();
+ std::function fxy = [&](double t) ->QPointF {
+ return fTransform(fell(t));
};
- std::function fy = [&](double t) ->double {
- return fTransform(fell(t)).y();
- };
- JKQTPAdaptiveFunctionGraphEvaluator eval(fx, fy);
+ JKQTPAdaptiveFunctionGraphEvaluator eval(fxy);
const QVector points=eval.evaluate(angle_start*JKQTPSTATISTICS_PI/180.0, angle_end*JKQTPSTATISTICS_PI/180.0);
if (points.size()>0) {
@@ -238,6 +235,17 @@ QVector JKQTPSimplyfyLineSegemnts(const QVector &points, doubl
JKQTPAdaptiveFunctionGraphEvaluator::JKQTPAdaptiveFunctionGraphEvaluator(const std::function &fx_, const std::function &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 &fxy_, unsigned int minSamples_, unsigned int maxRefinementDegree_, double slopeTolerance_, double minPixelPerSample_):
+ fxy(fxy_),
minSamples(minSamples_),
maxRefinementDegree(maxRefinementDegree_),
slopeTolerance(slopeTolerance_),
@@ -252,19 +260,19 @@ QVector JKQTPAdaptiveFunctionGraphEvaluator::evaluate(double tmin, doub
double delta_t0=(tmax-tmin)/static_cast(minSamples);
- intData.push_front(std::pair(tmin, QPointF(fx(tmin), fy(tmin))));
+ intData.push_front(std::pair(tmin, fxy(tmin)));
InternalList::iterator a=intData.begin();
//qDebug()<<"**************************************************";
for (double t=tmin+delta_t0; t(treal, QPointF(fx(treal), fy(treal))));
+ intData.insert_after(a, std::pair(treal, fxy(treal)));
InternalList::iterator b=a; b++;
//qDebug()<<"t="<(tmax, QPointF(fx(tmax), fy(tmax))));
+ intData.insert_after(a, std::pair(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 JKQTPSplitLineIntoPoints(const QLineF &line, std::function fTransform)
{
- std::function fx = [&line, &fTransform](double t) ->double {
- return fTransform(line.p1()+t*(line.p2()-line.p1())).x();
+ std::function fxy = [&line, &fTransform] (double t) ->QPointF {
+ return fTransform(line.p1()+t*(line.p2()-line.p1()));
};
- std::function 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);
}
diff --git a/lib/jkqtcommon/jkqtpgeometrytools.h b/lib/jkqtcommon/jkqtpgeometrytools.h
index bb9eed8d2e..9ed8d43bfd 100644
--- a/lib/jkqtcommon/jkqtpgeometrytools.h
+++ b/lib/jkqtcommon/jkqtpgeometrytools.h
@@ -62,6 +62,19 @@ public:
*/
JKQTPAdaptiveFunctionGraphEvaluator(const std::function& fx_, const std::function& 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& 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 fx;
/** \brief function \f$ f_y(t) \f$ */
std::function fy;
+ /** \brief function \f$ [x,y]=f_{xy}(t) \f$ */
+ std::function fxy;
/** \brief the minimum number of points to evaluate the function at */
unsigned int minSamples;
/** \brief the maximum number of recursive refinement steps
diff --git a/lib/jkqtplotter.pri b/lib/jkqtplotter.pri
index 1934ab8cab..2e9fcea2c0 100644
--- a/lib/jkqtplotter.pri
+++ b/lib/jkqtplotter.pri
@@ -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 \
diff --git a/lib/jkqtplotter/CMakeLists.txt b/lib/jkqtplotter/CMakeLists.txt
index 654f63385b..c83991e89a 100644
--- a/lib/jkqtplotter/CMakeLists.txt
+++ b/lib/jkqtplotter/CMakeLists.txt
@@ -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
diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp
index c48cbc6a35..3eebb330f0 100644
--- a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp
+++ b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.cpp
@@ -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 ¶ms, 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 ¶ms, 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 ¶ms, const QString &title_, JKQTBasePlotter *parent):
+ JKQTPXFunctionLineGraph(type, params, title_, parent)
+{
+}
+
+JKQTPYFunctionLineGraph::JKQTPYFunctionLineGraph(JKQTPYFunctionLineGraph::SpecialFunction type, const QVector ¶ms, const QString &title_, JKQTPlotter *parent):
+ JKQTPXFunctionLineGraph(type, params, title_, parent->getPlotter())
+{
+
+}
+
void JKQTPYFunctionLineGraph::draw(JKQTPEnhancedPainter& painter) {
#ifdef JKQTBP_AUTOTIMER
JKQTPAutoOutputTimer jkaaot("JKQTPYFunctionLineGraph::draw");
diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h
index b95b00b6eb..d120cf212c 100644
--- a/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h
+++ b/lib/jkqtplotter/graphs/jkqtpevaluatedfunction.h
@@ -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 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 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& params, const QString& title, JKQTBasePlotter* parent);
+ /** \brief class constructor */
+ JKQTPXFunctionLineGraph(SpecialFunction type, const QVector& 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 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 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;
};
/*! \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& params, const QString& title, JKQTBasePlotter* parent);
+ /** \brief class constructor */
+ JKQTPYFunctionLineGraph(SpecialFunction type, const QVector& params, const QString& title, JKQTPlotter* parent);
/** \brief plots the graph to the plotter object specified as parent */
virtual void draw(JKQTPEnhancedPainter& painter) override;
diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp
new file mode 100644
index 0000000000..9f7e50fd24
--- /dev/null
+++ b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.cpp
@@ -0,0 +1,514 @@
+/*
+ Copyright (c) 2020-2020 Jan W. Krieger ()
+
+
+
+ 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 .
+*/
+
+
+
+#include "jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h"
+#include "jkqtplotter/jkqtpbaseplotter.h"
+#include
+#include
+#include
+#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) || (xvsgzgetPlotter())
+{
+
+}
+
+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(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(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()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);
+
+ 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(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; igetDatastore();
+ 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 ¶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;
+}
+
+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 JKQTPXYFunctionLineGraph::getTRange() const
+{
+ return QPair(tmin,tmax);
+}
+
+void JKQTPXYFunctionLineGraph::setTRange(double tmin_, double tmax_)
+{
+ tmin=tmin_;
+ tmax=tmax_;
+}
+
+void JKQTPXYFunctionLineGraph::setTRange(const QPair &range)
+{
+ tmin=range.first;
+ tmax=range.second;
+}
+
diff --git a/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h
new file mode 100644
index 0000000000..7d3edad10c
--- /dev/null
+++ b/lib/jkqtplotter/graphs/jkqtpevaluatedparametriccurve.h
@@ -0,0 +1,275 @@
+/*
+ Copyright (c) 2020-2020 Jan W. Krieger ()
+
+
+
+ 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 .
+*/
+
+
+
+#include
+#include
+#include
+#include "jkqtplotter/graphs/jkqtpscatter.h"
+#include "jkqtplotter/jkqtpgraphsbasestylingmixins.h"
+#include "jkqtplotter/jkqtplotter_imexport.h"
+#include "jkqtcommon/jkqtpgeometrytools.h"
+#include
+
+#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 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 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& 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 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 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& 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 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 iparams;
+};
+
+#endif // jkqtpevaluatedparametriccurve_H
diff --git a/screenshots/evalcurve.png b/screenshots/evalcurve.png
new file mode 100644
index 0000000000..f44cd00696
Binary files /dev/null and b/screenshots/evalcurve.png differ
diff --git a/screenshots/evalcurve_small.png b/screenshots/evalcurve_small.png
new file mode 100644
index 0000000000..3638362acf
Binary files /dev/null and b/screenshots/evalcurve_small.png differ
|