10#include "qwt_spline.h"
11#include "qwt_spline_parametrization.h"
12#include "qwt_spline_polynomial.h"
13#include "qwt_bezier.h"
15#include <qpainterpath.h>
26 inline double operator()(
const QPointF& p1,
const QPointF& p2 )
const
36 inline double operator()(
const QPointF& p1,
const QPointF& p2 )
const
44 inline double operator()(
const QPointF& p1,
const QPointF& p2 )
const
50 struct paramCentripetal
52 inline double operator()(
const QPointF& p1,
const QPointF& p2 )
const
60 inline double operator()(
const QPointF& p1,
const QPointF& p2 )
const
68 inline double operator()(
const QPointF& p1,
const QPointF& p2 )
const
77 inline void init(
int size )
82 inline void start(
double x1,
double y1 )
84 path.moveTo( x1, y1 );
87 inline void addCubic(
double cx1,
double cy1,
88 double cx2,
double cy2,
double x2,
double y2 )
90 path.cubicTo( cx1, cy1, cx2, cy2, x2, y2 );
101 class ControlPointsStore
104 inline ControlPointsStore():
109 inline void init(
int size )
111 controlPoints.resize( size );
112 m_cp = controlPoints.data();
115 inline void start(
double x1,
double y1 )
121 inline void addCubic(
double cx1,
double cy1,
122 double cx2,
double cy2,
double x2,
double y2 )
128 l.setLine( cx1, cy1, cx2, cy2 );
141 double slopeBoundary(
int boundaryCondition,
double boundaryValue,
142 const QPointF& p1,
const QPointF& p2,
double slope1 )
144 const double dx = p2.x() - p1.x();
145 const double dy = p2.y() - p1.y();
149 switch( boundaryCondition )
158 const double c2 = 0.5 * boundaryValue;
159 const double c1 = slope1;
161 m = 0.5 * ( 3.0 * dy / dx - c1 - c2 * dx );
166 const double c3 = boundaryValue / 6.0;
167 m = c3 * dx * dx + 2 * dy / dx - slope1;
172 const double s = dy / dx;
173 const double r = qBound( 0.0, boundaryValue, 1.0 );
175 m = s - r * ( s - slope1 );
188template<
class SplineStore >
189static inline SplineStore qwtSplineC1PathParamX(
190 const QwtSplineC1* spline,
const QPolygonF& points )
192 const int n = points.size();
196 return SplineStore();
198 const QPointF* pd = points.constData();
199 const double* md = m.constData();
202 store.init( m.size() - 1 );
203 store.start( pd[0].x(), pd[0].y() );
205 for (
int i = 0; i < n - 1; i++ )
207 const double dx3 = ( pd[i + 1].x() - pd[i].x() ) / 3.0;
209 store.addCubic( pd[i].x() + dx3, pd[i].y() + md[i] * dx3,
210 pd[i + 1].x() - dx3, pd[i + 1].y() - md[i + 1] * dx3,
211 pd[i + 1].x(), pd[i + 1].y() );
217template<
class SplineStore >
218static inline SplineStore qwtSplineC1PathParamY(
219 const QwtSplineC1* spline,
const QPolygonF& points )
221 const int n = points.size();
223 QPolygonF pointsFlipped( n );
224 for (
int i = 0; i < n; i++ )
226 pointsFlipped[i].setX( points[i].y() );
227 pointsFlipped[i].setY( points[i].x() );
232 return SplineStore();
234 const QPointF* pd = pointsFlipped.constData();
235 const double* md = m.constData();
238 store.init( m.size() - 1 );
239 store.start( pd[0].y(), pd[0].x() );
242 for (
int i = 0; i < n - 1; i++ )
244 const double dx3 = ( pd[i + 1].x() - pd[i].x() ) / 3.0;
246 store.addCubic( pd[i].y() + md[i] * dx3, pd[i].x() + dx3,
247 pd[i + 1].y() - md[i + 1] * dx3, pd[i + 1].x() - dx3,
248 pd[i + 1].y(), pd[i + 1].x() );
254template<
class SplineStore,
class Param >
255static inline SplineStore qwtSplineC1PathParametric(
256 const QwtSplineC1* spline,
const QPolygonF& points, Param param )
259 const int n = points.size();
261 QPolygonF pointsX, pointsY;
262 pointsX.resize( isClosing ? n + 1 : n );
263 pointsY.resize( isClosing ? n + 1 : n );
265 QPointF* px = pointsX.data();
266 QPointF* py = pointsY.data();
267 const QPointF* p = points.constData();
271 px[0].rx() = py[0].rx() = t;
272 px[0].ry() = p[0].x();
273 py[0].ry() = p[0].y();
275 int numParamPoints = 1;
276 for (
int i = 1; i < n; i++ )
278 const double td = param( points[i - 1], points[i] );
283 px[numParamPoints].rx() = py[numParamPoints].rx() = t;
285 px[numParamPoints].ry() = p[i].x();
286 py[numParamPoints].ry() = p[i].y();
294 const double td = param( points[n - 1], points[0] );
300 px[numParamPoints].rx() = py[numParamPoints].rx() = t;
302 px[numParamPoints].ry() = p[0].x();
303 py[numParamPoints].ry() = p[0].y();
309 if ( pointsX.size() != numParamPoints )
311 pointsX.resize( numParamPoints );
312 pointsY.resize( numParamPoints );
318 const double* mx = slopesX.constData();
319 const double* my = slopesY.constData();
326 store.init( isClosing ? n : n - 1 );
327 store.start( points[0].x(), points[0].y() );
331 for (
int i = 0; i < n - 1; i++ )
333 const QPointF& p1 = p[i];
334 const QPointF& p2 = p[i + 1];
336 const double td = param( p1, p2 );
340 const double t3 = td / 3.0;
342 const double cx1 = p1.x() + mx[j] * t3;
343 const double cy1 = p1.y() + my[j] * t3;
345 const double cx2 = p2.x() - mx[j + 1] * t3;
346 const double cy2 = p2.y() - my[j + 1] * t3;
348 store.addCubic( cx1, cy1, cx2, cy2, p2.x(), p2.y() );
355 store.addCubic( p1.x(), p1.y(), p2.x(), p2.y(), p2.x(), p2.y() );
361 const QPointF& p1 = p[n - 1];
362 const QPointF& p2 = p[0];
364 const double td = param( p1, p2 );
368 const double t3 = td / 3.0;
370 const double cx1 = p1.x() + mx[j] * t3;
371 const double cy1 = p1.y() + my[j] * t3;
373 const double cx2 = p2.x() - mx[0] * t3;
374 const double cy2 = p2.y() - my[0] * t3;
376 store.addCubic( cx1, cy1, cx2, cy2, p2.x(), p2.y() );
380 store.addCubic( p1.x(), p1.y(), p2.x(), p2.y(), p2.x(), p2.y() );
389template< QwtSplinePolynomial toPolynomial( const QPo
intF&,
double, const QPo
intF&,
double ) >
390static QPolygonF qwtPolygonParametric(
double distance,
393 QPolygonF fittedPoints;
395 const QPointF* p = points.constData();
396 const double* v = values.constData();
398 fittedPoints += p[0];
401 const int n = points.size();
403 for (
int i = 0; i < n - 1; i++ )
405 const QPointF& p1 = p[i];
406 const QPointF& p2 = p[i + 1];
410 const double l = p2.x() - p1.x();
414 fittedPoints += QPointF( p1.x() + t, p1.y() + polynomial.
valueAt( t ) );
420 if ( qFuzzyCompare( fittedPoints.last().x(), p2.x() ) )
421 fittedPoints.last() = p2;
434class QwtSpline::PrivateData
446 boundaryConditions[0].value = 0.0;
449 boundaryConditions[1].value = 0.0;
454 delete parametrization;
465 } boundaryConditions[2];
498 if ( tolerance <= 0.0 )
502 const int n = path.elementCount();
506 const QPainterPath::Element el = path.elementAt( 0 );
507 if ( el.type != QPainterPath::MoveToElement )
510 QPointF p1( el.x, el.y );
515 for (
int i = 1; i < n; i += 3 )
517 const QPainterPath::Element el1 = path.elementAt( i );
518 const QPainterPath::Element el2 = path.elementAt( i + 1 );
519 const QPainterPath::Element el3 = path.elementAt( i + 2 );
521 const QPointF cp1( el1.x, el1.y );
522 const QPointF cp2( el2.x, el2.y );
523 const QPointF p2( el3.x, el3.y );
542 m_data =
new PrivateData;
578 if ( m_data->parametrization->
type() != type )
580 delete m_data->parametrization;
596 delete m_data->parametrization;
607 return m_data->parametrization;
628 return m_data->boundaryType;
642 m_data->boundaryConditions[position].type = condition;
654 return m_data->boundaryConditions[position].type;
656 return m_data->boundaryConditions[0].type;
673 m_data->boundaryConditions[position].value = value;
685 return m_data->boundaryConditions[position].value;
687 return m_data->boundaryConditions[0].value;
701 int condition,
double valueBegin,
double valueEnd )
750 const int n = points.size();
758 path.moveTo( points[0] );
764 path.addPolygon( points );
769 if ( controlLines.size() < n - 1 )
772 const QPointF* p = points.constData();
773 const QLineF* l = controlLines.constData();
776 for (
int i = 0; i < n - 1; i++ )
777 path.cubicTo( l[i].p1(), l[i].p2(), p[i + 1] );
780 && ( controlLines.size() >= n ) )
782 path.cubicTo( l[n - 1].p1(), l[n - 1].p2(), p[0] );
806 const QPolygonF& points,
double tolerance )
const
808 if ( tolerance <= 0.0 )
812 if ( controlLines.isEmpty() )
819 const QPointF* p = points.constData();
820 const QLineF* cl = controlLines.constData();
822 const int n = controlLines.size();
826 for (
int i = 0; i < n - 1; i++ )
828 const QLineF& l = cl[i];
832 const QPointF& pn = isClosed ? p[0] : p[n];
833 const QLineF& l = cl[n - 1];
864 double distance,
bool withNodes )
const
866 if ( distance <= 0.0 )
869 const int n = points.size();
883 if ( controlLines.size() < n - 1 )
886 path += points.first();
889 const QPointF* p = points.constData();
890 const QLineF* cl = controlLines.constData();
894 for (
int i = 0; i < n - 1; i++ )
901 cl[i].p2(), p[i + 1], t / l );
908 if ( qFuzzyCompare( path.last().x(), p[i + 1].x() ) )
909 path.last() = p[i + 1];
922 && ( controlLines.size() >= n ) )
929 cl[n - 1].p2(), p[0], t / l );
934 if ( qFuzzyCompare( path.last().x(), p[0].x() ) )
981 if ( points.size() < 2 )
984 return QwtSplineC1P::slopeBoundary(
987 points[0], points[1], slopeNext );
999 const int n = points.size();
1001 const QPointF p1( points[n - 1].x(), -points[n - 1].y() );
1002 const QPointF p2( points[n - 2].x(), -points[n - 2].y() );
1014 const double slope = QwtSplineC1P::slopeBoundary( condition, value, p1, p2, -slopeBefore );
1045 const int n = points.size();
1049 using namespace QwtSplineC1P;
1056 store = qwtSplineC1PathParamX< PathStore >(
this, points );
1061 store = qwtSplineC1PathParamY< PathStore >(
this, points );
1066 store = qwtSplineC1PathParametric< PathStore >(
1067 this, points, paramUniform() );
1072 store = qwtSplineC1PathParametric< PathStore >(
1073 this, points, paramCentripetal() );
1078 store = qwtSplineC1PathParametric< PathStore >(
1079 this, points, paramChordal() );
1084 store = qwtSplineC1PathParametric< PathStore >(
1103 using namespace QwtSplineC1P;
1105 const int n = points.size();
1109 ControlPointsStore store;
1114 store = qwtSplineC1PathParamX< ControlPointsStore >(
this, points );
1119 store = qwtSplineC1PathParamY< ControlPointsStore >(
this, points );
1124 store = qwtSplineC1PathParametric< ControlPointsStore >(
1125 this, points, paramUniform() );
1130 store = qwtSplineC1PathParametric< ControlPointsStore >(
1131 this, points, paramCentripetal() );
1136 store = qwtSplineC1PathParametric< ControlPointsStore >(
1137 this, points, paramChordal() );
1142 store = qwtSplineC1PathParametric< ControlPointsStore >(
1147 return store.controlPoints;
1168 double distance,
bool withNodes )
const
1172 if ( points.size() > 2 )
1175 if ( m.size() != points.size() )
1178 return qwtPolygonParametric< QwtSplinePolynomial::fromSlopes >(
1179 distance, points, m, withNodes );
1202 const QPolygonF& points )
const
1211 for (
int i = 1; i < m.size(); i++ )
1214 points[i - 1], m[i - 1], points[i], m[i] );
1296 double distance,
bool withNodes )
const
1300 if ( points.size() > 2 )
1303 if ( cv.size() != points.size() )
1306 return qwtPolygonParametric< QwtSplinePolynomial::fromCurvatures >(
1307 distance, points, cv, withNodes );
1348 double* m =
slopes.data();
1350 const int n = points.size();
1351 const QPointF* p = points.constData();
1355 for (
int i = 0; i < n - 1; i++ )
1358 m[i] = polynomial.
c1;
1361 m[n - 1] = polynomial.
slopeAt( p[n - 1].x() - p[n - 2].x() );
1389 const QPointF* p = points.constData();
1394 for (
int i = 1; i < n; i++ )
1397 p[i - 1], cv[i - 1], p[i], cv[i] );
An implementation of the de Casteljau’s Algorithm for interpolating Bézier curves.
void appendToPolygon(const QPointF &p1, const QPointF &cp1, const QPointF &cp2, const QPointF &p2, QPolygonF &polygon) const
Interpolate a Bézier curve by a polygon.
static QPointF pointAt(const QPointF &p1, const QPointF &cp1, const QPointF &cp2, const QPointF &p2, double t)
Base class for spline interpolations providing a first order parametric continuity ( C1 ) between adj...
virtual QVector< double > slopes(const QPolygonF &) const =0
Find the first derivative at the control points.
virtual ~QwtSplineC1()
Destructor.
QwtSplineC1()
Constructor.
virtual double slopeAtBeginning(const QPolygonF &, double slopeNext) const
virtual QPainterPath painterPath(const QPolygonF &) const override
Calculate an interpolated painter path.
virtual QPolygonF equidistantPolygon(const QPolygonF &, double distance, bool withNodes) const override
Find an interpolated polygon with "equidistant" points.
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
virtual double slopeAtEnd(const QPolygonF &, double slopeBefore) const
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const
Calculate the interpolating polynomials for a non parametric spline.
virtual QPolygonF equidistantPolygon(const QPolygonF &, double distance, bool withNodes) const override
Find an interpolated polygon with "equidistant" points.
virtual QVector< double > slopes(const QPolygonF &) const override
Find the first derivative at the control points.
QwtSplineC2()
Constructor.
virtual QVector< double > curvatures(const QPolygonF &) const =0
Find the second derivative at the control points.
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const override
Calculate the interpolating polynomials for a non parametric spline.
virtual ~QwtSplineC2()
Destructor.
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
virtual ~QwtSplineG1()
Destructor.
QwtSplineG1()
Constructor.
Base class for all splines.
@ AtBeginning
the condition is at the beginning of the polynomial
@ AtEnd
the condition is at the end of the polynomial
virtual QPainterPath painterPath(const QPolygonF &) const =0
double boundaryValue(BoundaryPosition) const
void setBoundaryType(BoundaryType)
void setBoundaryCondition(BoundaryPosition, int condition)
Define the condition for an endpoint of the spline.
const QwtSplineParametrization * parametrization() const
int boundaryCondition(BoundaryPosition) const
BoundaryType boundaryType() const
virtual uint locality() const
virtual ~QwtSpline()
Destructor.
virtual QPolygonF polygon(const QPolygonF &, double tolerance) const
Interpolate a curve by a polygon.
void setBoundaryConditions(int condition, double valueBegin=0.0, double valueEnd=0.0)
Define the condition at the endpoints of a spline.
void setBoundaryValue(BoundaryPosition, double value)
Define the boundary value.
void setParametrization(int type)
virtual ~QwtSplineInterpolating()
Destructor.
virtual QPolygonF equidistantPolygon(const QPolygonF &, double distance, bool withNodes) const
Find an interpolated polygon with "equidistant" points.
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const =0
Interpolate a curve with Bezier curves.
QwtSplineInterpolating()
Constructor.
virtual QPolygonF polygon(const QPolygonF &, double tolerance) const override
Interpolate a curve by a polygon.
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
Curve parametrization used for a spline interpolation.
static double valueIncrementChordal(const QPointF &, const QPointF &)
Calculate the ParameterChordal value increment for 2 points.
static double valueIncrementCentripetal(const QPointF &, const QPointF &)
Calculate the ParameterCentripetal value increment for 2 points.
static double valueIncrementUniform(const QPointF &, const QPointF &)
Calculate the ParameterUniform value increment.
virtual double valueIncrement(const QPointF &, const QPointF &) const
Calculate the parameter value increment for 2 points.
static double valueIncrementManhattan(const QPointF &, const QPointF &)
Calculate the ParameterManhattan value increment for 2 points.
static double valueIncrementY(const QPointF &, const QPointF &)
Calculate the ParameterY value increment for 2 points.
A cubic polynomial without constant term.
double slopeAt(double x) const
static QwtSplinePolynomial fromSlopes(const QPointF &p1, double m1, const QPointF &p2, double m2)
double valueAt(double x) const
static QwtSplinePolynomial fromCurvatures(const QPointF &p1, double cv1, const QPointF &p2, double cv2)
double c1
coefficient of the linear summand