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"
12
#include "qwt_array.h"
14
class QwtSpline::PrivateData
18
splineType(QwtSpline::Natural)
22
QwtSpline::SplineType splineType;
24
// coefficient vectors
30
#if QT_VERSION < 0x040000
31
QwtArray<QwtDoublePoint> points;
37
#if QT_VERSION < 0x040000
38
static int lookup(double x, const QwtArray<QwtDoublePoint> &values)
40
static int lookup(double x, const QPolygonF &values)
44
//qLowerBiund/qHigherBound ???
47
const int size = (int)values.size();
49
if (x <= values[0].x())
51
else if (x >= values[size - 2].x())
61
i3 = i1 + ((i2 - i1) >> 1);
63
if (values[i3].x() > x)
73
QwtSpline::QwtSpline()
75
d_data = new PrivateData;
80
\param other Spline used for initilization
82
QwtSpline::QwtSpline(const QwtSpline& other)
84
d_data = new PrivateData(*other.d_data);
89
\param other Spline used for initilization
91
QwtSpline &QwtSpline::operator=( const QwtSpline &other)
93
*d_data = *other.d_data;
98
QwtSpline::~QwtSpline()
104
Select the algorithm used for calculating the spline
106
\param splineType Spline type
109
void QwtSpline::setSplineType(SplineType splineType)
111
d_data->splineType = splineType;
115
\return the spline type
118
QwtSpline::SplineType QwtSpline::splineType() const
120
return d_data->splineType;
124
\brief Calculate the spline coefficients
126
Depending on the value of \a periodic, this function
127
will determine the coefficients for a natural or a periodic
128
spline and store them internally.
132
\param size number of points
133
\param periodic if true, calculate periodic spline
134
\return true if successful
135
\warning The sequence of x (but not y) values has to be strictly monotone
136
increasing, which means <code>x[0] < x[1] < .... < x[n-1]</code>.
137
If this is not the case, the function will return false
139
#if QT_VERSION < 0x040000
140
bool QwtSpline::setPoints(const QwtArray<QwtDoublePoint>& points)
142
bool QwtSpline::setPoints(const QPolygonF& points)
145
const int size = points.size();
152
#if QT_VERSION < 0x040000
153
d_data->points = points.copy(); // Qt3: deep copy
155
d_data->points = points;
158
d_data->a.resize(size-1);
159
d_data->b.resize(size-1);
160
d_data->c.resize(size-1);
163
if ( d_data->splineType == Periodic )
164
ok = buildPeriodicSpline(points);
166
ok = buildNaturalSpline(points);
175
Return points passed by setPoints
177
#if QT_VERSION < 0x040000
178
QwtArray<QwtDoublePoint> QwtSpline::points() const
180
QPolygonF QwtSpline::points() const
183
return d_data->points;
186
//! \return A coefficients
187
const QwtArray<double> &QwtSpline::coefficientsA() const
192
//! \return B coefficients
193
const QwtArray<double> &QwtSpline::coefficientsB() const
198
//! \return C coefficients
199
const QwtArray<double> &QwtSpline::coefficientsC() const
205
//! Free allocated memory and set size to 0
206
void QwtSpline::reset()
211
d_data->points.resize(0);
215
bool QwtSpline::isValid() const
217
return d_data->a.size() > 0;
221
Calculate the interpolated function value corresponding
222
to a given argument x.
224
double QwtSpline::value(double x) const
226
if (d_data->a.size() == 0)
229
const int i = lookup(x, d_data->points);
231
const double delta = x - d_data->points[i].x();
232
return( ( ( ( d_data->a[i] * delta) + d_data->b[i] )
233
* delta + d_data->c[i] ) * delta + d_data->points[i].y() );
237
\brief Determines the coefficients for a natural spline
238
\return true if successful
240
#if QT_VERSION < 0x040000
241
bool QwtSpline::buildNaturalSpline(const QwtArray<QwtDoublePoint> &points)
243
bool QwtSpline::buildNaturalSpline(const QPolygonF &points)
248
#if QT_VERSION < 0x040000
249
const QwtDoublePoint *p = points.data();
251
const QPointF *p = points.data();
253
const int size = points.size();
255
double *a = d_data->a.data();
256
double *b = d_data->b.data();
257
double *c = d_data->c.data();
259
// set up tridiagonal equation system; use coefficient
260
// vectors as temporary buffers
261
QwtArray<double> h(size-1);
262
for (i = 0; i < size - 1; i++)
264
h[i] = p[i+1].x() - p[i].x();
269
QwtArray<double> d(size-1);
270
double dy1 = (p[1].y() - p[0].y()) / h[0];
271
for (i = 1; i < size - 1; i++)
274
a[i] = 2.0 * (h[i-1] + h[i]);
276
const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
277
d[i] = 6.0 * ( dy1 - dy2);
286
for(i = 1; i < size - 2;i++)
289
a[i+1] -= b[i] * c[i];
292
// forward elimination
293
QwtArray<double> s(size);
295
for ( i = 2; i < size - 1; i++)
296
s[i] = d[i] - c[i-1] * s[i-1];
298
// backward elimination
299
s[size - 2] = - s[size - 2] / a[size - 2];
300
for (i = size -3; i > 0; i--)
301
s[i] = - (s[i] + b[i] * s[i+1]) / a[i];
302
s[size - 1] = s[0] = 0.0;
305
// Finally, determine the spline coefficients
307
for (i = 0; i < size - 1; i++)
309
a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
311
c[i] = ( p[i+1].y() - p[i].y() ) / h[i]
312
- (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;
319
\brief Determines the coefficients for a periodic spline
320
\return true if successful
322
#if QT_VERSION < 0x040000
323
bool QwtSpline::buildPeriodicSpline(
324
const QwtArray<QwtDoublePoint> &points)
326
bool QwtSpline::buildPeriodicSpline(const QPolygonF &points)
331
#if QT_VERSION < 0x040000
332
const QwtDoublePoint *p = points.data();
334
const QPointF *p = points.data();
336
const int size = points.size();
338
double *a = d_data->a.data();
339
double *b = d_data->b.data();
340
double *c = d_data->c.data();
342
QwtArray<double> d(size-1);
343
QwtArray<double> h(size-1);
344
QwtArray<double> s(size);
347
// setup equation system; use coefficient
348
// vectors as temporary buffers
350
for (i = 0; i < size - 1; i++)
352
h[i] = p[i+1].x() - p[i].x();
357
const int imax = size - 2;
358
double htmp = h[imax];
359
double dy1 = (p[0].y() - p[imax].y()) / htmp;
360
for (i = 0; i <= imax; i++)
363
a[i] = 2.0 * (htmp + h[i]);
364
const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
365
d[i] = 6.0 * ( dy1 - dy2);
376
c[0] = h[imax] / a[0];
379
for( i = 0; i < imax - 1; i++)
383
c[i] = - c[i-1] * b[i-1] / a[i];
384
a[i+1] = sqrt( a[i+1] - qwtSqr(b[i]));
387
b[imax-1] = (b[imax-1] - c[imax-2] * b[imax-2]) / a[imax-1];
388
a[imax] = sqrt(a[imax] - qwtSqr(b[imax-1]) - sum);
391
// forward elimination
394
for( i = 1; i < imax; i++)
396
s[i] = (d[i] - b[i-1] * s[i-1]) / a[i];
397
sum += c[i-1] * s[i-1];
399
s[imax] = (d[imax] - b[imax-1] * s[imax-1] - sum) / a[imax];
402
// backward elimination
403
s[imax] = - s[imax] / a[imax];
404
s[imax-1] = -(s[imax-1] + b[imax-1] * s[imax]) / a[imax-1];
405
for (i= imax - 2; i >= 0; i--)
406
s[i] = - (s[i] + b[i] * s[i+1] + c[i] * s[imax]) / a[i];
409
// Finally, determine the spline coefficients
412
for ( i=0; i < size-1; i++)
414
a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
416
c[i] = ( p[i+1].y() - p[i].y() )
417
/ h[i] - (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;