Qwt User's Guide 6.2.0

qwt_spline_pleasing.cpp
1 /******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10 #include "qwt_spline_pleasing.h"
11 #include "qwt_spline_parametrization.h"
12
13 #include <qpainterpath.h>
14
15 static inline double qwtChordalLength( const QPointF& point1, const QPointF& point2 )
16 {
17 const double dx = point2.x() - point1.x();
18 const double dy = point2.y() - point1.y();
19
20 return std::sqrt( dx * dx + dy * dy );
21 }
22
23 template< class Param >
24 static QPointF qwtVector( Param param,
25 const QPointF& p1, const QPointF& p2 )
26 {
27 return ( p2 - p1 ) / param( p1, p2 );
28 }
29
30 template< class Param >
31 static QPointF qwtVectorCardinal( Param param,
32 const QPointF& p1, const QPointF& p2, const QPointF& p3 )
33 {
34 const double t1 = param( p1, p2 );
35 const double t2 = param( p2, p3 );
36
37 return t2 * ( p3 - p1 ) / ( t1 + t2 );
38 }
39
40 namespace QwtSplinePleasingP
41 {
42 struct Tension
43 {
44 double t1;
45 double t2;
46 };
47
48 struct param
49 {
50 param( const QwtSplineParametrization* p ):
51 parameter( p )
52 {
53 }
54
55 inline double operator()( const QPointF& p1, const QPointF& p2 ) const
56 {
57 return parameter->valueIncrement( p1, p2 );
58 }
59
60 const QwtSplineParametrization* parameter;
61 };
62
63 struct paramUniform
64 {
65 inline double operator()( const QPointF& p1, const QPointF& p2 ) const
66 {
67 return QwtSplineParametrization::valueIncrementUniform( p1, p2 );
68 }
69 };
70
71 class PathStore
72 {
73 public:
74 inline void init( int )
75 {
76 }
77
78 inline void start( const QPointF& p0 )
79 {
80 path.moveTo( p0 );
81 }
82
83 inline void addCubic( const QPointF& cp1,
84 const QPointF& cp2, const QPointF& p2 )
85 {
86 path.cubicTo( cp1, cp2, p2 );
87 }
88
89 QPainterPath path;
90 };
91
92 class ControlPointsStore
93 {
94 public:
95 inline ControlPointsStore():
96 m_cp( NULL )
97 {
98 }
99
100 inline void init( int size )
101 {
102 controlPoints.resize( size );
103 m_cp = controlPoints.data();
104 }
105
106 inline void start( const QPointF& )
107 {
108 }
109
110 inline void addCubic( const QPointF& cp1,
111 const QPointF& cp2, const QPointF& )
112 {
113 QLineF& l = *m_cp++;
114 l.setPoints( cp1, cp2 );
115 }
116
117 QVector< QLineF > controlPoints;
118
119 private:
120 QLineF* m_cp;
121 };
122 }
123
124 static inline QwtSplinePleasingP::Tension qwtTensionPleasing(
125 double d13, double d23, double d24,
126 const QPointF& p1, const QPointF& p2,
127 const QPointF& p3, const QPointF& p4 )
128 {
129 QwtSplinePleasingP::Tension tension;
130
131 const bool b1 = ( d13 / 3.0 ) < d23;
132 const bool b2 = ( d24 / 3.0 ) < d23;
133
134 if ( b1 )
135 {
136 if ( b2 )
137 {
138 tension.t1 = ( p1 != p2 ) ? ( 1.0 / 3.0 ) : ( 2.0 / 3.0 );
139 tension.t2 = ( p3 != p4 ) ? ( 1.0 / 3.0 ) : ( 2.0 / 3.0 );
140 }
141 else
142 {
143 tension.t1 = tension.t2 = d23 / d24;
144 }
145 }
146 else
147 {
148 if ( b2 )
149 {
150 tension.t1 = tension.t2 = d23 / d13;
151 }
152 else
153 {
154 tension.t1 = d23 / d13;
155 tension.t2 = d23 / d24;
156 }
157 }
158
159 return tension;
160 }
161
162 template< class SplineStore, class Param >
163 static SplineStore qwtSplinePathPleasing( const QPolygonF& points,
164 bool isClosed, Param param )
165 {
166 using namespace QwtSplinePleasingP;
167
168 const int size = points.size();
169
170 const QPointF* p = points.constData();
171
172 SplineStore store;
173 store.init( isClosed ? size : size - 1 );
174 store.start( p[0] );
175
176 double d13;
177 QPointF vec1;
178
179 if ( isClosed )
180 {
181 d13 = qwtChordalLength(p[0], p[2]);
182
183 const Tension t0 = qwtTensionPleasing(
184 qwtChordalLength( p[size - 1], p[1]), qwtChordalLength(p[0], p[1]),
185 d13, p[size - 1], p[0], p[1], p[2] );
186
187 const QPointF vec0 = qwtVectorCardinal< Param >( param, p[size - 1], p[0], p[1] );
188 vec1 = qwtVectorCardinal< Param >( param, p[0], p[1], p[2] );
189
190 store.addCubic( p[0] + vec0 * t0.t1, p[1] - vec1 * t0.t2, p[1] );
191 }
192 else
193 {
194 d13 = qwtChordalLength(p[0], p[2]);
195
196 const Tension t0 = qwtTensionPleasing(
197 qwtChordalLength( p[0], p[1]), qwtChordalLength(p[0], p[1]),
198 d13, p[0], p[0], p[1], p[2] );
199
200 const QPointF vec0 = 0.5 * qwtVector< Param >( param, p[0], p[1] );
201 vec1 = qwtVectorCardinal< Param >( param, p[0], p[1], p[2] );
202
203 store.addCubic( p[0] + vec0 * t0.t1, p[1] - vec1 * t0.t2, p[1] );
204 }
205
206 for ( int i = 1; i < size - 2; i++ )
207 {
208 const double d23 = qwtChordalLength( p[i], p[i + 1] );
209 const double d24 = qwtChordalLength( p[i], p[i + 2] );
210
211 const QPointF vec2 = qwtVectorCardinal< Param >( param, p[i], p[i + 1], p[i + 2] );
212
213 const Tension t = qwtTensionPleasing(
214 d13, d23, d24, p[i - 1], p[i], p[i + 1], p[i + 2] );
215
216 store.addCubic( p[i] + vec1 * t.t1, p[i + 1] - vec2 * t.t2, p[i + 1] );
217
218 d13 = d24;
219 vec1 = vec2;
220 }
221
222 if ( isClosed )
223 {
224 const double d24 = qwtChordalLength( p[size - 2], p[0] );
225
226 const Tension tn = qwtTensionPleasing(
227 d13, qwtChordalLength( p[size - 2], p[size - 1] ), d24,
228 p[size - 3], p[size - 2], p[size - 1], p[0] );
229
230 const QPointF vec2 = qwtVectorCardinal< Param >( param, p[size - 2], p[size - 1], p[0] );
231 store.addCubic( p[size - 2] + vec1 * tn.t1, p[size - 1] - vec2 * tn.t2, p[size - 1] );
232
233 const double d34 = qwtChordalLength( p[size - 1], p[0] );
234 const double d35 = qwtChordalLength( p[size - 1], p[1] );
235
236 const Tension tc = qwtTensionPleasing( d24, d34, d35, p[size - 2], p[size - 1], p[0], p[1] );
237
238 const QPointF vec3 = qwtVectorCardinal< Param >( param, p[size - 1], p[0], p[1] );
239
240 store.addCubic( p[size - 1] + vec2 * tc.t1, p[0] - vec3 * tc.t2, p[0] );
241 }
242 else
243 {
244 const double d24 = qwtChordalLength( p[size - 2], p[size - 1] );
245
246 const Tension tn = qwtTensionPleasing(
247 d13, qwtChordalLength( p[size - 2], p[size - 1] ), d24,
248 p[size - 3], p[size - 2], p[size - 1], p[size - 1] );
249
250 const QPointF vec2 = 0.5 * qwtVector< Param >( param, p[size - 2], p[size - 1] );
251 store.addCubic( p[size - 2] + vec1 * tn.t1, p[size - 1] - vec2 * tn.t2, p[size - 1] );
252 }
253
254 return store;
255 }
256
265 QwtSplinePleasing::QwtSplinePleasing()
266 {
267 setParametrization( QwtSplineParametrization::ParameterUniform );
268 }
269
271 QwtSplinePleasing::~QwtSplinePleasing()
272 {
273 }
274
276 uint QwtSplinePleasing::locality() const
277 {
278 return 2;
279 }
280
290 QPainterPath QwtSplinePleasing::painterPath( const QPolygonF& points ) const
291 {
292 const int size = points.size();
293 if ( size <= 2 )
294 return QwtSplineG1::painterPath( points );
295
296 const bool isClosing = ( boundaryType() == QwtSpline::ClosedPolygon );
297
298 using namespace QwtSplinePleasingP;
299
300 PathStore store;
301 if ( parametrization()->type() == QwtSplineParametrization::ParameterUniform )
302 {
303 store = qwtSplinePathPleasing< PathStore >( points,
304 isClosing, paramUniform() );
305 }
306 else
307 {
308 store = qwtSplinePathPleasing< PathStore >( points,
309 isClosing, param( parametrization() ) );
310 }
311
312 if ( isClosing )
313 store.path.closeSubpath();
314
315 return store.path;
316 }
317
327 QVector< QLineF > QwtSplinePleasing::bezierControlLines(
328 const QPolygonF& points ) const
329 {
330 const int size = points.size();
331 if ( size <= 2 )
332 return QVector< QLineF >();
333
334 const bool isClosing = ( boundaryType() == QwtSpline::ClosedPolygon );
335
336 using namespace QwtSplinePleasingP;
337
338 ControlPointsStore store;
339 if ( parametrization()->type() == QwtSplineParametrization::ParameterUniform )
340 {
341 store = qwtSplinePathPleasing< ControlPointsStore >( points,
342 isClosing, paramUniform() );
343 }
344 else
345 {
346 store = qwtSplinePathPleasing< ControlPointsStore >( points,
347 isClosing, param( parametrization() ) );
348 }
349
350 return store.controlPoints;
351 }
QVector< QLineF >
QwtSpline::parametrization
const QwtSplineParametrization * parametrization() const
Definition: qwt_spline.cpp:605
QwtSpline::boundaryType
BoundaryType boundaryType() const
Definition: qwt_spline.cpp:626
QwtSpline::ClosedPolygon
@ ClosedPolygon
Definition: qwt_spline.h:92
QwtSpline::setParametrization
void setParametrization(int type)
Definition: qwt_spline.cpp:576
QwtSplineInterpolating::painterPath
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
Definition: qwt_spline.cpp:748
QwtSplineParametrization
Curve parametrization used for a spline interpolation.
Definition: qwt_spline_parametrization.h:45
QwtSplineParametrization::type
int type() const
Definition: qwt_spline_parametrization.cpp:72
QwtSplineParametrization::valueIncrementUniform
static double valueIncrementUniform(const QPointF &, const QPointF &)
Calculate the ParameterUniform value increment.
Definition: qwt_spline_parametrization.h:162
QwtSplineParametrization::ParameterUniform
@ ParameterUniform
Definition: qwt_spline_parametrization.h:72
QwtSplinePleasing::locality
virtual uint locality() const override
Definition: qwt_spline_pleasing.cpp:276
QwtSplinePleasing::bezierControlLines
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
Definition: qwt_spline_pleasing.cpp:327
QwtSplinePleasing::~QwtSplinePleasing
virtual ~QwtSplinePleasing()
Destructor.
Definition: qwt_spline_pleasing.cpp:271
QwtSplinePleasing::painterPath
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
Definition: qwt_spline_pleasing.cpp:290
QwtSplinePleasing::QwtSplinePleasing
QwtSplinePleasing()
Constructor.
Definition: qwt_spline_pleasing.cpp:265