Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_spline.h"
00011 #include "qwt_math.h"
00012 #include "qwt_array.h"
00013
00014 class QwtSpline::PrivateData
00015 {
00016 public:
00017 PrivateData():
00018 splineType(QwtSpline::Natural)
00019 {
00020 }
00021
00022 QwtSpline::SplineType splineType;
00023
00024
00025 QwtArray<double> a;
00026 QwtArray<double> b;
00027 QwtArray<double> c;
00028
00029
00030 #if QT_VERSION < 0x040000
00031 QwtArray<QwtDoublePoint> points;
00032 #else
00033 QPolygonF points;
00034 #endif
00035 };
00036
00037 #if QT_VERSION < 0x040000
00038 static int lookup(double x, const QwtArray<QwtDoublePoint> &values)
00039 #else
00040 static int lookup(double x, const QPolygonF &values)
00041 #endif
00042 {
00043 #if 0
00044
00045 #endif
00046 int i1;
00047 const int size = (int)values.size();
00048
00049 if (x <= values[0].x())
00050 i1 = 0;
00051 else if (x >= values[size - 2].x())
00052 i1 = size - 2;
00053 else
00054 {
00055 i1 = 0;
00056 int i2 = size - 2;
00057 int i3 = 0;
00058
00059 while ( i2 - i1 > 1 )
00060 {
00061 i3 = i1 + ((i2 - i1) >> 1);
00062
00063 if (values[i3].x() > x)
00064 i2 = i3;
00065 else
00066 i1 = i3;
00067 }
00068 }
00069 return i1;
00070 }
00071
00073 QwtSpline::QwtSpline()
00074 {
00075 d_data = new PrivateData;
00076 }
00077
00082 QwtSpline::QwtSpline(const QwtSpline& other)
00083 {
00084 d_data = new PrivateData(*other.d_data);
00085 }
00086
00091 QwtSpline &QwtSpline::operator=( const QwtSpline &other)
00092 {
00093 *d_data = *other.d_data;
00094 return *this;
00095 }
00096
00098 QwtSpline::~QwtSpline()
00099 {
00100 delete d_data;
00101 }
00102
00109 void QwtSpline::setSplineType(SplineType splineType)
00110 {
00111 d_data->splineType = splineType;
00112 }
00113
00118 QwtSpline::SplineType QwtSpline::splineType() const
00119 {
00120 return d_data->splineType;
00121 }
00122
00139 #if QT_VERSION < 0x040000
00140 bool QwtSpline::setPoints(const QwtArray<QwtDoublePoint>& points)
00141 #else
00142 bool QwtSpline::setPoints(const QPolygonF& points)
00143 #endif
00144 {
00145 const int size = points.size();
00146 if (size <= 2)
00147 {
00148 reset();
00149 return false;
00150 }
00151
00152 #if QT_VERSION < 0x040000
00153 d_data->points = points.copy();
00154 #else
00155 d_data->points = points;
00156 #endif
00157
00158 d_data->a.resize(size-1);
00159 d_data->b.resize(size-1);
00160 d_data->c.resize(size-1);
00161
00162 bool ok;
00163 if ( d_data->splineType == Periodic )
00164 ok = buildPeriodicSpline(points);
00165 else
00166 ok = buildNaturalSpline(points);
00167
00168 if (!ok)
00169 reset();
00170
00171 return ok;
00172 }
00173
00177 #if QT_VERSION < 0x040000
00178 QwtArray<QwtDoublePoint> QwtSpline::points() const
00179 #else
00180 QPolygonF QwtSpline::points() const
00181 #endif
00182 {
00183 return d_data->points;
00184 }
00185
00187 const QwtArray<double> &QwtSpline::coefficientsA() const
00188 {
00189 return d_data->a;
00190 }
00191
00193 const QwtArray<double> &QwtSpline::coefficientsB() const
00194 {
00195 return d_data->b;
00196 }
00197
00199 const QwtArray<double> &QwtSpline::coefficientsC() const
00200 {
00201 return d_data->c;
00202 }
00203
00204
00206 void QwtSpline::reset()
00207 {
00208 d_data->a.resize(0);
00209 d_data->b.resize(0);
00210 d_data->c.resize(0);
00211 d_data->points.resize(0);
00212 }
00213
00215 bool QwtSpline::isValid() const
00216 {
00217 return d_data->a.size() > 0;
00218 }
00219
00224 double QwtSpline::value(double x) const
00225 {
00226 if (d_data->a.size() == 0)
00227 return 0.0;
00228
00229 const int i = lookup(x, d_data->points);
00230
00231 const double delta = x - d_data->points[i].x();
00232 return( ( ( ( d_data->a[i] * delta) + d_data->b[i] )
00233 * delta + d_data->c[i] ) * delta + d_data->points[i].y() );
00234 }
00235
00240 #if QT_VERSION < 0x040000
00241 bool QwtSpline::buildNaturalSpline(const QwtArray<QwtDoublePoint> &points)
00242 #else
00243 bool QwtSpline::buildNaturalSpline(const QPolygonF &points)
00244 #endif
00245 {
00246 int i;
00247
00248 #if QT_VERSION < 0x040000
00249 const QwtDoublePoint *p = points.data();
00250 #else
00251 const QPointF *p = points.data();
00252 #endif
00253 const int size = points.size();
00254
00255 double *a = d_data->a.data();
00256 double *b = d_data->b.data();
00257 double *c = d_data->c.data();
00258
00259
00260
00261 QwtArray<double> h(size-1);
00262 for (i = 0; i < size - 1; i++)
00263 {
00264 h[i] = p[i+1].x() - p[i].x();
00265 if (h[i] <= 0)
00266 return false;
00267 }
00268
00269 QwtArray<double> d(size-1);
00270 double dy1 = (p[1].y() - p[0].y()) / h[0];
00271 for (i = 1; i < size - 1; i++)
00272 {
00273 b[i] = c[i] = h[i];
00274 a[i] = 2.0 * (h[i-1] + h[i]);
00275
00276 const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
00277 d[i] = 6.0 * ( dy1 - dy2);
00278 dy1 = dy2;
00279 }
00280
00281
00282
00283
00284
00285
00286 for(i = 1; i < size - 2;i++)
00287 {
00288 c[i] /= a[i];
00289 a[i+1] -= b[i] * c[i];
00290 }
00291
00292
00293 QwtArray<double> s(size);
00294 s[1] = d[1];
00295 for ( i = 2; i < size - 1; i++)
00296 s[i] = d[i] - c[i-1] * s[i-1];
00297
00298
00299 s[size - 2] = - s[size - 2] / a[size - 2];
00300 for (i = size -3; i > 0; i--)
00301 s[i] = - (s[i] + b[i] * s[i+1]) / a[i];
00302 s[size - 1] = s[0] = 0.0;
00303
00304
00305
00306
00307 for (i = 0; i < size - 1; i++)
00308 {
00309 a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
00310 b[i] = 0.5 * s[i];
00311 c[i] = ( p[i+1].y() - p[i].y() ) / h[i]
00312 - (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;
00313 }
00314
00315 return true;
00316 }
00317
00322 #if QT_VERSION < 0x040000
00323 bool QwtSpline::buildPeriodicSpline(
00324 const QwtArray<QwtDoublePoint> &points)
00325 #else
00326 bool QwtSpline::buildPeriodicSpline(const QPolygonF &points)
00327 #endif
00328 {
00329 int i;
00330
00331 #if QT_VERSION < 0x040000
00332 const QwtDoublePoint *p = points.data();
00333 #else
00334 const QPointF *p = points.data();
00335 #endif
00336 const int size = points.size();
00337
00338 double *a = d_data->a.data();
00339 double *b = d_data->b.data();
00340 double *c = d_data->c.data();
00341
00342 QwtArray<double> d(size-1);
00343 QwtArray<double> h(size-1);
00344 QwtArray<double> s(size);
00345
00346
00347
00348
00349
00350 for (i = 0; i < size - 1; i++)
00351 {
00352 h[i] = p[i+1].x() - p[i].x();
00353 if (h[i] <= 0.0)
00354 return false;
00355 }
00356
00357 const int imax = size - 2;
00358 double htmp = h[imax];
00359 double dy1 = (p[0].y() - p[imax].y()) / htmp;
00360 for (i = 0; i <= imax; i++)
00361 {
00362 b[i] = c[i] = h[i];
00363 a[i] = 2.0 * (htmp + h[i]);
00364 const double dy2 = (p[i+1].y() - p[i].y()) / h[i];
00365 d[i] = 6.0 * ( dy1 - dy2);
00366 dy1 = dy2;
00367 htmp = h[i];
00368 }
00369
00370
00371
00372
00373
00374
00375 a[0] = sqrt(a[0]);
00376 c[0] = h[imax] / a[0];
00377 double sum = 0;
00378
00379 for( i = 0; i < imax - 1; i++)
00380 {
00381 b[i] /= a[i];
00382 if (i > 0)
00383 c[i] = - c[i-1] * b[i-1] / a[i];
00384 a[i+1] = sqrt( a[i+1] - qwtSqr(b[i]));
00385 sum += qwtSqr(c[i]);
00386 }
00387 b[imax-1] = (b[imax-1] - c[imax-2] * b[imax-2]) / a[imax-1];
00388 a[imax] = sqrt(a[imax] - qwtSqr(b[imax-1]) - sum);
00389
00390
00391
00392 s[0] = d[0] / a[0];
00393 sum = 0;
00394 for( i = 1; i < imax; i++)
00395 {
00396 s[i] = (d[i] - b[i-1] * s[i-1]) / a[i];
00397 sum += c[i-1] * s[i-1];
00398 }
00399 s[imax] = (d[imax] - b[imax-1] * s[imax-1] - sum) / a[imax];
00400
00401
00402
00403 s[imax] = - s[imax] / a[imax];
00404 s[imax-1] = -(s[imax-1] + b[imax-1] * s[imax]) / a[imax-1];
00405 for (i= imax - 2; i >= 0; i--)
00406 s[i] = - (s[i] + b[i] * s[i+1] + c[i] * s[imax]) / a[i];
00407
00408
00409
00410
00411 s[size-1] = s[0];
00412 for ( i=0; i < size-1; i++)
00413 {
00414 a[i] = ( s[i+1] - s[i] ) / ( 6.0 * h[i]);
00415 b[i] = 0.5 * s[i];
00416 c[i] = ( p[i+1].y() - p[i].y() )
00417 / h[i] - (s[i+1] + 2.0 * s[i] ) * h[i] / 6.0;
00418 }
00419
00420 return true;
00421 }