Newer
Older
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
#include "qwt_spline.h"
#include "qwt_math.h"
#include "qwt_array.h"
class QwtSpline::PrivateData
{
public:
PrivateData():
}
QwtSpline::SplineType splineType;
// coefficient vectors
QwtArray<double> a;
QwtArray<double> b;
QwtArray<double> c;
// control points
#if QT_VERSION < 0x040000
QwtArray<QwtDoublePoint> points;
#else
QPolygonF points;
#endif
};
#if QT_VERSION < 0x040000
static int lookup(double x, const QwtArray<QwtDoublePoint> &values)
#else
static int lookup(double x, const QPolygonF &values)
#endif
{
#if 0
//qLowerBiund/qHigherBound ???
#endif
int i1;
const int size = (int)values.size();
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
}
}
return i1;
}
//! Constructor
QwtSpline::QwtSpline()
{
d_data = new PrivateData;
}
QwtSpline::QwtSpline(const QwtSpline& other)
{
d_data = new PrivateData(*other.d_data);
}
QwtSpline &QwtSpline::operator=( const QwtSpline &other)
{
*d_data = *other.d_data;
return *this;
}
//! Destructor
QwtSpline::~QwtSpline()
{
delete d_data;
}
void QwtSpline::setSplineType(SplineType splineType)
{
d_data->splineType = splineType;
}
QwtSpline::SplineType QwtSpline::splineType() const
{
return d_data->splineType;
}
//! Determine the function table index corresponding to a value x
/*!
\brief Calculate the spline coefficients
Depending on the value of \a periodic, this function
will determine the coefficients for a natural or a periodic
spline and store them internally.
\param x
\param y points
\param size number of points
\param periodic if true, calculate periodic spline
\return true if successful
\warning The sequence of x (but not y) values has to be strictly monotone
increasing, which means <code>x[0] < x[1] < .... < x[n-1]</code>.
If this is not the case, the function will return false
*/
#if QT_VERSION < 0x040000
bool QwtSpline::setPoints(const QwtArray<QwtDoublePoint>& points)
#else
bool QwtSpline::setPoints(const QPolygonF& points)
#endif
{
const int size = points.size();
reset();
return false;
}
#if QT_VERSION < 0x040000
d_data->points = points.copy(); // Qt3: deep copy
#else
d_data->points = points;
#endif
d_data->a.resize(size-1);
d_data->b.resize(size-1);
d_data->c.resize(size-1);
bool ok;
if ( d_data->splineType == Periodic )
ok = buildPeriodicSpline(points);
else
ok = buildNaturalSpline(points);
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
reset();
return ok;
}
/*!
Return points passed by setPoints
*/
#if QT_VERSION < 0x040000
QwtArray<QwtDoublePoint> QwtSpline::points() const
#else
QPolygonF QwtSpline::points() const
#endif
{
return d_data->points;
}
//! Free allocated memory and set size to 0
void QwtSpline::reset()
{
d_data->a.resize(0);
d_data->b.resize(0);
d_data->c.resize(0);
d_data->points.resize(0);
}
//! True if valid
bool QwtSpline::isValid() const
{
return d_data->a.size() > 0;
}
/*!
Calculate the interpolated function value corresponding
to a given argument x.
*/
double QwtSpline::value(double x) const
{
if (d_data->a.size() == 0)
return 0.0;
const int i = lookup(x, d_data->points);
const double delta = x - d_data->points[i].x();
return( ( ( ( d_data->a[i] * delta) + d_data->b[i] )
* delta + d_data->c[i] ) * delta + d_data->points[i].y() );
}
/*!
\brief Determines the coefficients for a natural spline
\return true if successful
*/
#if QT_VERSION < 0x040000
bool QwtSpline::buildNaturalSpline(const QwtArray<QwtDoublePoint> &points)
#else
bool QwtSpline::buildNaturalSpline(const QPolygonF &points)
#endif
{
int i;
#if QT_VERSION < 0x040000
const QwtDoublePoint *p = points.data();
#else
const QPointF *p = points.data();
#endif
const int size = points.size();
double *a = d_data->a.data();
double *b = d_data->b.data();
double *c = d_data->c.data();
// set up tridiagonal equation system; use coefficient
// vectors as temporary buffers
QwtArray<double> h(size-1);
h[i] = p[i+1].x() - p[i].x();
if (h[i] <= 0)
return false;
}
QwtArray<double> d(size-1);
double dy1 = (p[1].y() - p[0].y()) / h[0];
b[i] = c[i] = h[i];
a[i] = 2.0 * (h[i-1] + h[i]);
const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
d[i] = 6.0 * ( dy1 - dy2);
dy1 = dy2;
}
//
// solve it
//
}
// forward elimination
QwtArray<double> s(size);
s[1] = d[1];
for ( i = 2; i < size - 1; i++)
s[i] = d[i] - c[i-1] * s[i-1];
// backward elimination
s[size - 2] = - s[size - 2] / a[size - 2];
for (i = size -3; i > 0; i--)
s[i] = - (s[i] + b[i] * s[i+1]) / a[i];
s[size - 1] = s[0] = 0.0;
//
// Finally, determine the spline coefficients
//
a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
b[i] = 0.5 * s[i];
c[i] = ( p[i+1].y() - p[i].y() ) / h[i]
- (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;
}
return true;
}
/*!
\brief Determines the coefficients for a periodic spline
\return true if successful
*/
#if QT_VERSION < 0x040000
bool QwtSpline::buildPeriodicSpline(
const QwtArray<QwtDoublePoint> &points)
#else
bool QwtSpline::buildPeriodicSpline(const QPolygonF &points)
#endif
{
int i;
#if QT_VERSION < 0x040000
const QwtDoublePoint *p = points.data();
#else
const QPointF *p = points.data();
#endif
const int size = points.size();
double *a = d_data->a.data();
double *b = d_data->b.data();
double *c = d_data->c.data();
QwtArray<double> d(size-1);
QwtArray<double> h(size-1);
QwtArray<double> s(size);
//
// setup equation system; use coefficient
// vectors as temporary buffers
//
h[i] = p[i+1].x() - p[i].x();
if (h[i] <= 0.0)
return false;
}
const int imax = size - 2;
double htmp = h[imax];
double dy1 = (p[0].y() - p[imax].y()) / htmp;
b[i] = c[i] = h[i];
a[i] = 2.0 * (htmp + h[i]);
const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
d[i] = 6.0 * ( dy1 - dy2);
dy1 = dy2;
htmp = h[i];
}
//
// solve it
//
// L-U Factorization
a[0] = sqrt(a[0]);
c[0] = h[imax] / a[0];
double sum = 0;
a[i+1] = sqrt( a[i+1] - qwtSqr(b[i]));
sum += qwtSqr(c[i]);
}
b[imax-1] = (b[imax-1] - c[imax-2] * b[imax-2]) / a[imax-1];
a[imax] = sqrt(a[imax] - qwtSqr(b[imax-1]) - sum);
// forward elimination
s[0] = d[0] / a[0];
sum = 0;
s[i] = (d[i] - b[i-1] * s[i-1]) / a[i];
sum += c[i-1] * s[i-1];
}
s[imax] = (d[imax] - b[imax-1] * s[imax-1] - sum) / a[imax];
// backward elimination
s[imax] = - s[imax] / a[imax];
s[imax-1] = -(s[imax-1] + b[imax-1] * s[imax]) / a[imax-1];
for (i= imax - 2; i >= 0; i--)
s[i] = - (s[i] + b[i] * s[i+1] + c[i] * s[imax]) / a[i];
//
// Finally, determine the spline coefficients
//
s[size-1] = s[0];
a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
b[i] = 0.5 * s[i];
c[i] = ( p[i+1].y() - p[i].y() )
/ h[i] - (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;