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;
78
QwtSpline::QwtSpline(const QwtSpline& other)
80
d_data = new PrivateData(*other.d_data);
83
QwtSpline &QwtSpline::operator=( const QwtSpline &other)
85
*d_data = *other.d_data;
90
QwtSpline::~QwtSpline()
95
void QwtSpline::setSplineType(SplineType splineType)
97
d_data->splineType = splineType;
100
QwtSpline::SplineType QwtSpline::splineType() const
102
return d_data->splineType;
105
//! Determine the function table index corresponding to a value x
108
\brief Calculate the spline coefficients
110
Depending on the value of \a periodic, this function
111
will determine the coefficients for a natural or a periodic
112
spline and store them internally.
116
\param size number of points
117
\param periodic if true, calculate periodic spline
118
\return true if successful
119
\warning The sequence of x (but not y) values has to be strictly monotone
120
increasing, which means <code>x[0] < x[1] < .... < x[n-1]</code>.
121
If this is not the case, the function will return false
123
#if QT_VERSION < 0x040000
124
bool QwtSpline::setPoints(const QwtArray<QwtDoublePoint>& points)
126
bool QwtSpline::setPoints(const QPolygonF& points)
129
const int size = points.size();
136
#if QT_VERSION < 0x040000
137
d_data->points = points.copy(); // Qt3: deep copy
139
d_data->points = points;
142
d_data->a.resize(size-1);
143
d_data->b.resize(size-1);
144
d_data->c.resize(size-1);
147
if ( d_data->splineType == Periodic )
148
ok = buildPeriodicSpline(points);
150
ok = buildNaturalSpline(points);
159
Return points passed by setPoints
161
#if QT_VERSION < 0x040000
162
QwtArray<QwtDoublePoint> QwtSpline::points() const
164
QPolygonF QwtSpline::points() const
167
return d_data->points;
171
//! Free allocated memory and set size to 0
172
void QwtSpline::reset()
177
d_data->points.resize(0);
181
bool QwtSpline::isValid() const
183
return d_data->a.size() > 0;
187
Calculate the interpolated function value corresponding
188
to a given argument x.
190
double QwtSpline::value(double x) const
192
if (d_data->a.size() == 0)
195
const int i = lookup(x, d_data->points);
197
const double delta = x - d_data->points[i].x();
198
return( ( ( ( d_data->a[i] * delta) + d_data->b[i] )
199
* delta + d_data->c[i] ) * delta + d_data->points[i].y() );
203
\brief Determines the coefficients for a natural spline
204
\return true if successful
206
#if QT_VERSION < 0x040000
207
bool QwtSpline::buildNaturalSpline(const QwtArray<QwtDoublePoint> &points)
209
bool QwtSpline::buildNaturalSpline(const QPolygonF &points)
214
#if QT_VERSION < 0x040000
215
const QwtDoublePoint *p = points.data();
217
const QPointF *p = points.data();
219
const int size = points.size();
221
double *a = d_data->a.data();
222
double *b = d_data->b.data();
223
double *c = d_data->c.data();
225
// set up tridiagonal equation system; use coefficient
226
// vectors as temporary buffers
227
QwtArray<double> h(size-1);
228
for (i = 0; i < size - 1; i++)
230
h[i] = p[i+1].x() - p[i].x();
235
QwtArray<double> d(size-1);
236
double dy1 = (p[1].y() - p[0].y()) / h[0];
237
for (i = 1; i < size - 1; i++)
240
a[i] = 2.0 * (h[i-1] + h[i]);
242
const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
243
d[i] = 6.0 * ( dy1 - dy2);
252
for(i = 1; i < size - 2;i++)
255
a[i+1] -= b[i] * c[i];
258
// forward elimination
259
QwtArray<double> s(size);
261
for ( i = 2; i < size - 1; i++)
262
s[i] = d[i] - c[i-1] * s[i-1];
264
// backward elimination
265
s[size - 2] = - s[size - 2] / a[size - 2];
266
for (i = size -3; i > 0; i--)
267
s[i] = - (s[i] + b[i] * s[i+1]) / a[i];
268
s[size - 1] = s[0] = 0.0;
271
// Finally, determine the spline coefficients
273
for (i = 0; i < size - 1; i++)
275
a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
277
c[i] = ( p[i+1].y() - p[i].y() ) / h[i]
278
- (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;
285
\brief Determines the coefficients for a periodic spline
286
\return true if successful
288
#if QT_VERSION < 0x040000
289
bool QwtSpline::buildPeriodicSpline(
290
const QwtArray<QwtDoublePoint> &points)
292
bool QwtSpline::buildPeriodicSpline(const QPolygonF &points)
297
#if QT_VERSION < 0x040000
298
const QwtDoublePoint *p = points.data();
300
const QPointF *p = points.data();
302
const int size = points.size();
304
double *a = d_data->a.data();
305
double *b = d_data->b.data();
306
double *c = d_data->c.data();
308
QwtArray<double> d(size-1);
309
QwtArray<double> h(size-1);
310
QwtArray<double> s(size);
313
// setup equation system; use coefficient
314
// vectors as temporary buffers
316
for (i = 0; i < size - 1; i++)
318
h[i] = p[i+1].x() - p[i].x();
323
const int imax = size - 2;
324
double htmp = h[imax];
325
double dy1 = (p[0].y() - p[imax].y()) / htmp;
326
for (i = 0; i <= imax; i++)
329
a[i] = 2.0 * (htmp + h[i]);
330
const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
331
d[i] = 6.0 * ( dy1 - dy2);
342
c[0] = h[imax] / a[0];
345
for( i = 0; i < imax - 1; i++)
349
c[i] = - c[i-1] * b[i-1] / a[i];
350
a[i+1] = sqrt( a[i+1] - qwtSqr(b[i]));
353
b[imax-1] = (b[imax-1] - c[imax-2] * b[imax-2]) / a[imax-1];
354
a[imax] = sqrt(a[imax] - qwtSqr(b[imax-1]) - sum);
357
// forward elimination
360
for( i = 1; i < imax; i++)
362
s[i] = (d[i] - b[i-1] * s[i-1]) / a[i];
363
sum += c[i-1] * s[i-1];
365
s[imax] = (d[imax] - b[imax-1] * s[imax-1] - sum) / a[imax];
368
// backward elimination
369
s[imax] = - s[imax] / a[imax];
370
s[imax-1] = -(s[imax-1] + b[imax-1] * s[imax]) / a[imax-1];
371
for (i= imax - 2; i >= 0; i--)
372
s[i] = - (s[i] + b[i] * s[i+1] + c[i] * s[imax]) / a[i];
375
// Finally, determine the spline coefficients
378
for ( i=0; i < size-1; i++)
380
a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
382
c[i] = ( p[i+1].y() - p[i].y() )
383
/ h[i] - (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;