1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
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 *****************************************************************************/
10 #include "qwt_spline.h"
13 class QwtSpline::PrivateData
17 splineType( QwtSpline::Natural
)
21 QwtSpline::SplineType splineType
;
23 // coefficient vectors
32 static int lookup( double x
, const QPolygonF
&values
)
35 //qLowerBound/qHigherBound ???
38 const int size
= values
.size();
40 if ( x
<= values
[0].x() )
42 else if ( x
>= values
[size
- 2].x() )
52 i3
= i1
+ ( ( i2
- i1
) >> 1 );
54 if ( values
[i3
].x() > x
)
64 QwtSpline::QwtSpline()
66 d_data
= new PrivateData
;
71 \param other Spline used for initialization
73 QwtSpline::QwtSpline( const QwtSpline
& other
)
75 d_data
= new PrivateData( *other
.d_data
);
80 \param other Spline used for initialization
83 QwtSpline
&QwtSpline::operator=( const QwtSpline
& other
)
85 *d_data
= *other
.d_data
;
90 QwtSpline::~QwtSpline()
96 Select the algorithm used for calculating the spline
98 \param splineType Spline type
101 void QwtSpline::setSplineType( SplineType splineType
)
103 d_data
->splineType
= splineType
;
107 \return the spline type
110 QwtSpline::SplineType
QwtSpline::splineType() const
112 return d_data
->splineType
;
116 \brief Calculate the spline coefficients
118 Depending on the value of \a periodic, this function
119 will determine the coefficients for a natural or a periodic
120 spline and store them internally.
123 \return true if successful
124 \warning The sequence of x (but not y) values has to be strictly monotone
125 increasing, which means <code>points[i].x() < points[i+1].x()</code>.
126 If this is not the case, the function will return false
128 bool QwtSpline::setPoints( const QPolygonF
& points
)
130 const int size
= points
.size();
137 d_data
->points
= points
;
139 d_data
->a
.resize( size
- 1 );
140 d_data
->b
.resize( size
- 1 );
141 d_data
->c
.resize( size
- 1 );
144 if ( d_data
->splineType
== Periodic
)
145 ok
= buildPeriodicSpline( points
);
147 ok
= buildNaturalSpline( points
);
156 \return Points, that have been by setPoints()
158 QPolygonF
QwtSpline::points() const
160 return d_data
->points
;
163 //! \return A coefficients
164 const QVector
<double> &QwtSpline::coefficientsA() const
169 //! \return B coefficients
170 const QVector
<double> &QwtSpline::coefficientsB() const
175 //! \return C coefficients
176 const QVector
<double> &QwtSpline::coefficientsC() const
182 //! Free allocated memory and set size to 0
183 void QwtSpline::reset()
185 d_data
->a
.resize( 0 );
186 d_data
->b
.resize( 0 );
187 d_data
->c
.resize( 0 );
188 d_data
->points
.resize( 0 );
192 bool QwtSpline::isValid() const
194 return d_data
->a
.size() > 0;
198 Calculate the interpolated function value corresponding
199 to a given argument x.
202 \return Interpolated coordinate
204 double QwtSpline::value( double x
) const
206 if ( d_data
->a
.size() == 0 )
209 const int i
= lookup( x
, d_data
->points
);
211 const double delta
= x
- d_data
->points
[i
].x();
212 return( ( ( ( d_data
->a
[i
] * delta
) + d_data
->b
[i
] )
213 * delta
+ d_data
->c
[i
] ) * delta
+ d_data
->points
[i
].y() );
217 \brief Determines the coefficients for a natural spline
218 \return true if successful
220 bool QwtSpline::buildNaturalSpline( const QPolygonF
&points
)
224 const QPointF
*p
= points
.data();
225 const int size
= points
.size();
227 double *a
= d_data
->a
.data();
228 double *b
= d_data
->b
.data();
229 double *c
= d_data
->c
.data();
231 // set up tridiagonal equation system; use coefficient
232 // vectors as temporary buffers
233 QVector
<double> h( size
- 1 );
234 for ( i
= 0; i
< size
- 1; i
++ )
236 h
[i
] = p
[i
+1].x() - p
[i
].x();
241 QVector
<double> d( size
- 1 );
242 double dy1
= ( p
[1].y() - p
[0].y() ) / h
[0];
243 for ( i
= 1; i
< size
- 1; i
++ )
246 a
[i
] = 2.0 * ( h
[i
-1] + h
[i
] );
248 const double dy2
= ( p
[i
+1].y() - p
[i
].y() ) / h
[i
];
249 d
[i
] = 6.0 * ( dy1
- dy2
);
258 for ( i
= 1; i
< size
- 2; i
++ )
261 a
[i
+1] -= b
[i
] * c
[i
];
264 // forward elimination
265 QVector
<double> s( size
);
267 for ( i
= 2; i
< size
- 1; i
++ )
268 s
[i
] = d
[i
] - c
[i
-1] * s
[i
-1];
270 // backward elimination
271 s
[size
- 2] = - s
[size
- 2] / a
[size
- 2];
272 for ( i
= size
- 3; i
> 0; i
-- )
273 s
[i
] = - ( s
[i
] + b
[i
] * s
[i
+1] ) / a
[i
];
274 s
[size
- 1] = s
[0] = 0.0;
277 // Finally, determine the spline coefficients
279 for ( i
= 0; i
< size
- 1; i
++ )
281 a
[i
] = ( s
[i
+1] - s
[i
] ) / ( 6.0 * h
[i
] );
283 c
[i
] = ( p
[i
+1].y() - p
[i
].y() ) / h
[i
]
284 - ( s
[i
+1] + 2.0 * s
[i
] ) * h
[i
] / 6.0;
291 \brief Determines the coefficients for a periodic spline
292 \return true if successful
294 bool QwtSpline::buildPeriodicSpline( const QPolygonF
&points
)
298 const QPointF
*p
= points
.data();
299 const int size
= points
.size();
301 double *a
= d_data
->a
.data();
302 double *b
= d_data
->b
.data();
303 double *c
= d_data
->c
.data();
305 QVector
<double> d( size
- 1 );
306 QVector
<double> h( size
- 1 );
307 QVector
<double> s( size
);
310 // setup equation system; use coefficient
311 // vectors as temporary buffers
313 for ( i
= 0; i
< size
- 1; i
++ )
315 h
[i
] = p
[i
+1].x() - p
[i
].x();
320 const int imax
= size
- 2;
321 double htmp
= h
[imax
];
322 double dy1
= ( p
[0].y() - p
[imax
].y() ) / htmp
;
323 for ( i
= 0; i
<= imax
; i
++ )
326 a
[i
] = 2.0 * ( htmp
+ h
[i
] );
327 const double dy2
= ( p
[i
+1].y() - p
[i
].y() ) / h
[i
];
328 d
[i
] = 6.0 * ( dy1
- dy2
);
338 a
[0] = qSqrt( a
[0] );
339 c
[0] = h
[imax
] / a
[0];
342 for ( i
= 0; i
< imax
- 1; i
++ )
346 c
[i
] = - c
[i
-1] * b
[i
-1] / a
[i
];
347 a
[i
+1] = qSqrt( a
[i
+1] - qwtSqr( b
[i
] ) );
348 sum
+= qwtSqr( c
[i
] );
350 b
[imax
-1] = ( b
[imax
-1] - c
[imax
-2] * b
[imax
-2] ) / a
[imax
-1];
351 a
[imax
] = qSqrt( a
[imax
] - qwtSqr( b
[imax
-1] ) - sum
);
354 // forward elimination
357 for ( i
= 1; i
< imax
; i
++ )
359 s
[i
] = ( d
[i
] - b
[i
-1] * s
[i
-1] ) / a
[i
];
360 sum
+= c
[i
-1] * s
[i
-1];
362 s
[imax
] = ( d
[imax
] - b
[imax
-1] * s
[imax
-1] - sum
) / a
[imax
];
365 // backward elimination
366 s
[imax
] = - s
[imax
] / a
[imax
];
367 s
[imax
-1] = -( s
[imax
-1] + b
[imax
-1] * s
[imax
] ) / a
[imax
-1];
368 for ( i
= imax
- 2; i
>= 0; i
-- )
369 s
[i
] = - ( s
[i
] + b
[i
] * s
[i
+1] + c
[i
] * s
[imax
] ) / a
[i
];
372 // Finally, determine the spline coefficients
375 for ( i
= 0; i
< size
- 1; i
++ )
377 a
[i
] = ( s
[i
+1] - s
[i
] ) / ( 6.0 * h
[i
] );
379 c
[i
] = ( p
[i
+1].y() - p
[i
].y() )
380 / h
[i
] - ( s
[i
+1] + 2.0 * s
[i
] ) * h
[i
] / 6.0;