JKQTPlotter trunk/v5.0.0
an extensive Qt5+Qt6 Plotter framework (including a feature-richt plotter widget, a speed-optimized, but limited variant and a LaTeX equation renderer!), written fully in C/C++ and without external dependencies
Loading...
Searching...
No Matches
jkqtpgeometrytools.h
1/*
2 Copyright (c) 2020-2022 Jan W. Krieger (<jan@jkrieger.de>)
3
4
5
6 This software is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation, either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20
21#ifndef JKQTPGEOMETRYTOOLS_H_INCLUDED
22#define JKQTPGEOMETRYTOOLS_H_INCLUDED
23#include "jkqtcommon/jkqtcommon_imexport.h"
24#include <QPolygonF>
25#include <QPolygon>
26#include <QRectF>
27#include <QRect>
28#include <QLineF>
29#include <QLine>
30#include <QPainterPath>
31#include <QVector>
32#include <vector>
33#include <forward_list>
34#include <cmath>
35#include <utility>
36#include <random>
37#include <QDebug>
38#include "jkqtcommon/jkqtpmathtools.h"
39#include "jkqtcommon/jkqtpcodestructuring.h"
40
41
42/** \brief rotate a rectangle by given angle (rotates all points around the center of the rectangle and returns it as a QPolygonF)
43 * \ingroup jkqtptools_drawing
44 */
45JKQTCOMMON_LIB_EXPORT QPolygonF jkqtpRotateRect(QRectF r, double angle);
46
47
48/** \brief adaptive drawing of a function graph, specified by two function \f$ f_x(t) \f$ and \f$ f_y(t) \f$ evaluated over a parameter range \f$ t\in\left[t_\text{min}..t_\text{max}\right] \f$ */
50public:
51
52 /** \brief class constructor
53 *
54 * \param fx_ function \f$ f_x(t) \f$
55 * \param fy_ function \f$ f_y(t) \f$
56 * \param minSamples_ the minimum number of points to evaluate the function at
57 * \param maxRefinementDegree_ the maximum number of recursive refinement steps
58 * each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
59 * of points plotted at all are thus:
60 * \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
61 * \param slopeTolerance_ the tolerance for the difference of two subsequent slopes
62 * \param minPixelPerSample_ create one sample at least every \a minPixelPerSample pixels
63 */
64 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);
65
66 /** \brief class constructor
67 *
68 * \param fxy_ function \f$ [x,y]=f_{xy}(t) \f$
69 * \param minSamples_ the minimum number of points to evaluate the function at
70 * \param maxRefinementDegree_ the maximum number of recursive refinement steps
71 * each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
72 * of points plotted at all are thus:
73 * \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
74 * \param slopeTolerance_ the tolerance for the difference of two subsequent slopes
75 * \param minPixelPerSample_ create one sample at least every \a minPixelPerSample pixels
76 */
77 JKQTPAdaptiveFunctionGraphEvaluator(const std::function<QPointF(double)>& fxy_, unsigned int minSamples_=10, unsigned int maxRefinementDegree_=5, double slopeTolerance_=0.005, double minPixelPerSample_=32);
78
79 /** \brief evaluate the function specified in the constructor over the given parameter range \a tmin ... \a tmax
80 *
81 * \param tmin lower parameter range limit \f$ t_\text{min} \f$
82 * \param tmax upper parameter range limit \f$ t_\text{max} \f$
83 */
84 QVector<QPointF> evaluate(double tmin=0.0, double tmax=1.0) const;
85protected:
86 typedef std::forward_list<std::pair<double, QPointF>> InternalList;
87 /** \brief refine (if necessary) the function graph between the two points \a a and \a b, working on the given list of data \a data */
88 void refine(InternalList& data, InternalList::iterator a, InternalList::iterator b, unsigned int degree) const;
89
90 /** \brief function \f$ f_x(t) \f$ */
91 std::function<double(double)> fx;
92 /** \brief function \f$ f_y(t) \f$ */
93 std::function<double(double)> fy;
94 /** \brief function \f$ [x,y]=f_{xy}(t) \f$ */
95 std::function<QPointF(double)> fxy;
96 /** \brief the minimum number of points to evaluate the function at */
97 unsigned int minSamples;
98 /** \brief the maximum number of recursive refinement steps
99 *
100 * each step bisects the interval \f$ [a, b] \f$ into two halfes. So the maximum number
101 * of points plotted at all are thus:
102 * \f[ \mbox{minSamples} \cdot 2^{\mbox{maxRefinementDegree}} \f]
103 */
105 /** \brief the tolerance for the difference of two subsequent slopes */
107 /** \brief create one sample at least every \a minPixelPerSample pixels */
109 /** \brief random number generation: device */
110 mutable std::random_device rd; // random number generators:
111 /** \brief random number generation: egenrator */
112 mutable std::mt19937 gen;
113 /** \brief random number generation: distribution */
114 mutable std::uniform_real_distribution<double> dist;
115
116};
117
118
119/*! \brief represent an ellipse as a series of points on the ellipse
120 \ingroup jkqtptools_drawing
121
122 \return a QVector<QPointF> with points that may be used for drawing
123 \param x center of ellipse (x-coordinate)
124 \param y center of ellipse (y-coordinate)
125 \param a half axis in x-direction
126 \param b half axis in y-direction
127 \param angle_start starting angle of ellipse section
128 \param angle_end ending angle of ellipse section
129 \param alpha rotation angle of ellipse
130 \param controlPoints the number of points to use for drawing
131 \param[out] x_start first point of ellipse
132 \param[out] x_end last point of ellipse
133
134 \note all angles are given in degrees [0..360]
135*/
136JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSplitEllipseIntoPoints(double x, double y, double a, double b, double angle_start=0, double angle_end=360, double alpha=0, int controlPoints=180, QPointF* x_start=nullptr, QPointF* x_end=nullptr);
137
138
139/*! \brief represent an ellipse as a series of points on the ellipse
140 \ingroup jkqtptools_drawing
141
142 \return a QVector<QPointF> with points that may be used for drawing
143 \param fTransform a function that transforms a point in graph coordinate space into pixel coordinate space
144 \param x center of ellipse (x-coordinate)
145 \param y center of ellipse (y-coordinate)
146 \param a half axis in x-direction
147 \param b half axis in y-direction
148 \param angle_start starting angle of ellipse section
149 \param angle_end ending angle of ellipse section
150 \param alpha rotation angle of ellipse
151 \param[out] x_start first point of ellipse, with fTransform applied
152 \param[out] x_end last point of ellipse, with fTransform applied
153 \param[out] x_start_notrafo first point of ellipse, without fTransform applied
154 \param[out] x_end_notrafo last point of ellipse, without fTransform applied
155
156 \note all angles are given in degrees [0..360]
157*/
158JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSplitEllipseIntoPoints(std::function<QPointF(QPointF)> fTransform, double x, double y, double a, double b, double angle_start=0, double angle_end=360, double alpha=0, QPointF* x_start=nullptr, QPointF* x_end=nullptr, QPointF* x_start_notrafo=nullptr, QPointF* x_end_notrafo=nullptr);
159
160
161
162/*! \brief represent a line as a series of points on the ellipse
163 \ingroup jkqtptools_drawing
164
165 \return a QVector<QPointF> with points that may be used for drawing
166 \param line the line to draw
167 \param controlPoints the number of points to use for drawing
168
169*/
170JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSplitLineIntoPoints(const QLineF& line, int controlPoints=180);
171
172/*! \brief represent a line as a series of points on the ellipse
173 \ingroup jkqtptools_drawing
174
175 \return a QVector<QPointF> with points that may be used for drawing
176 \param line the line to draw in graph coordinate space
177 \param fTransform a function that transforms a point in graph coordinate space into pixel coordinate space
178
179*/
180JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSplitLineIntoPoints(const QLineF& line, std::function<QPointF(QPointF)> fTransform);
181
182
183/*! \brief represent a poly-line as a series of points on the ellipse
184 \ingroup jkqtptools_drawing
185
186 \return a QVector<QPointF> with points that may be used for drawing
187 \param line the poly-line to draw in graph coordinate space
188 \param fTransform a function that transforms a point in graph coordinate space into pixel coordinate space
189
190*/
191JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSplitPolylineIntoPoints(const QVector<QPointF>& line, std::function<QPointF(QPointF)> fTransform);
192
193
194/*! \brief takes a list of points and tries to reduce them. Three points are merged to two, if they form a straight line
195 \ingroup jkqtptools_drawing
196
197 \return a cleaned QVector<QPointF>
198 \param points input poly-line
199 \param maxConsecutiveAngleDegree is two consecutive line-segments differ by an angle smaller than this, they can be merged
200
201 \note this implements an incomplete algorithm
202
203*/
204JKQTCOMMON_LIB_EXPORT QVector<QPointF> JKQTPSimplyfyLineSegemnts(const QVector<QPointF>& points, double maxConsecutiveAngleDegree=0.2);
205
206
207/** \brief cleans a polygon by uniting all consecutive points that were closer than distanceThreshold are united
208 * \ingroup jkqtptools_drawing
209 *
210 * \param poly polygon to clean
211 * \param distanceThreshold if two end-points are closer together as this value, they are united to a single point
212 * \return a cleaned polygon, where all consecutive points that were closer than distanceThreshold are united
213 */
214JKQTCOMMON_LIB_EXPORT QPolygonF JKQTPCleanPolygon(const QPolygonF& poly, double distanceThreshold=0.3);
215
216/** \brief takes a list of QLineF objesct \a lines and tries to combine as many of them as possible to QPolygonF objects.
217 * <b>Note: This method implements an incomplete algorithm with \a searchMaxSurroundingElements>0, as solving
218 * the complete problem is very time-consuming (cubic runtime)</b>
219 * \ingroup jkqtptools_drawing
220 *
221 * \param lines line segments to unify
222 * \param distanceThreshold if two end-points are closer together as this value, they are united to a single point
223 * \param searchMaxSurroundingElements limits the search for a connected polygon to at most this number of neighbors
224 * \return a vector of QPolygonF objects, which contain longer line-segments formed from \a lines
225 */
226JKQTCOMMON_LIB_EXPORT QVector<QPolygonF> JKQTPUnifyLinesToPolygons(const QVector<QLineF>& lines, double distanceThreshold=0.3, int searchMaxSurroundingElements=10);
227
228/** \brief clip a QLineF \a line to the rectangle defines by \a clippingRect
229 * \ingroup jkqtptools_drawing
230 *
231 * \param[in,out] line The line to clip, if clipping is possible this is modified to the clipped line.
232 * If the line is outside \a clippingRect this is modified to \c line=QLineF() i.e. a null-line!
233 * \param clippingRect the rectangle to clip to
234 * \return \c true, if the line had at least some points within \a clippingRect, \c false otherwise.
235 * The clipped line (or a null-line) is returned in the by-refrence parameter \a line
236 *
237 * \see This function uses the Linag-Barsky-Algorithm: https://en.wikipedia.org/wiki/Liang%E2%80%93Barsky_algorithm https://www.skytopia.com/project/articles/compsci/clipping.html
238 */
239JKQTCOMMON_LIB_EXPORT bool JKQTPClipLine(QLineF& line, const QRectF& clippingRect);
240
241
242
243
244
245#endif // JKQTPGEOMETRYTOOLS_H_INCLUDED
adaptive drawing of a function graph, specified by two function and evaluated over a parameter rang...
Definition jkqtpgeometrytools.h:49
std::function< double(double)> fy
function
Definition jkqtpgeometrytools.h:93
std::uniform_real_distribution< double > dist
random number generation: distribution
Definition jkqtpgeometrytools.h:114
std::random_device rd
random number generation: device
Definition jkqtpgeometrytools.h:110
JKQTPAdaptiveFunctionGraphEvaluator(const std::function< QPointF(double)> &fxy_, unsigned int minSamples_=10, unsigned int maxRefinementDegree_=5, double slopeTolerance_=0.005, double minPixelPerSample_=32)
class constructor
std::forward_list< std::pair< double, QPointF > > InternalList
Definition jkqtpgeometrytools.h:86
std::function< double(double)> fx
function
Definition jkqtpgeometrytools.h:91
double minPixelPerSample
create one sample at least every minPixelPerSample pixels
Definition jkqtpgeometrytools.h:108
unsigned int minSamples
the minimum number of points to evaluate the function at
Definition jkqtpgeometrytools.h:97
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)
class constructor
double slopeTolerance
the tolerance for the difference of two subsequent slopes
Definition jkqtpgeometrytools.h:106
void refine(InternalList &data, InternalList::iterator a, InternalList::iterator b, unsigned int degree) const
refine (if necessary) the function graph between the two points a and b, working on the given list of...
QVector< QPointF > evaluate(double tmin=0.0, double tmax=1.0) const
evaluate the function specified in the constructor over the given parameter range tmin ....
unsigned int maxRefinementDegree
the maximum number of recursive refinement steps
Definition jkqtpgeometrytools.h:104
std::function< QPointF(double)> fxy
function
Definition jkqtpgeometrytools.h:95
std::mt19937 gen
random number generation: egenrator
Definition jkqtpgeometrytools.h:112
JKQTCOMMON_LIB_EXPORT QVector< QPolygonF > JKQTPUnifyLinesToPolygons(const QVector< QLineF > &lines, double distanceThreshold=0.3, int searchMaxSurroundingElements=10)
takes a list of QLineF objesct lines and tries to combine as many of them as possible to QPolygonF ob...
JKQTCOMMON_LIB_EXPORT bool JKQTPClipLine(QLineF &line, const QRectF &clippingRect)
clip a QLineF line to the rectangle defines by clippingRect
JKQTCOMMON_LIB_EXPORT QVector< QPointF > JKQTPSimplyfyLineSegemnts(const QVector< QPointF > &points, double maxConsecutiveAngleDegree=0.2)
takes a list of points and tries to reduce them. Three points are merged to two, if they form a strai...
JKQTCOMMON_LIB_EXPORT QVector< QPointF > JKQTPSplitEllipseIntoPoints(double x, double y, double a, double b, double angle_start=0, double angle_end=360, double alpha=0, int controlPoints=180, QPointF *x_start=nullptr, QPointF *x_end=nullptr)
represent an ellipse as a series of points on the ellipse
JKQTCOMMON_LIB_EXPORT QVector< QPointF > JKQTPSplitPolylineIntoPoints(const QVector< QPointF > &line, std::function< QPointF(QPointF)> fTransform)
represent a poly-line as a series of points on the ellipse
JKQTCOMMON_LIB_EXPORT QPolygonF JKQTPCleanPolygon(const QPolygonF &poly, double distanceThreshold=0.3)
cleans a polygon by uniting all consecutive points that were closer than distanceThreshold are united
JKQTCOMMON_LIB_EXPORT QVector< QPointF > JKQTPSplitLineIntoPoints(const QLineF &line, int controlPoints=180)
represent a line as a series of points on the ellipse
JKQTCOMMON_LIB_EXPORT QPolygonF jkqtpRotateRect(QRectF r, double angle)
rotate a rectangle by given angle (rotates all points around the center of the rectangle and returns ...
#define JKQTCOMMON_LIB_EXPORT
Definition jkqtcommon_imexport.h:87