| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381 | /* -*- 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"class QwtSpline::PrivateData{public:    PrivateData():        splineType( QwtSpline::Natural )    {    }    QwtSpline::SplineType splineType;    // coefficient vectors    QVector<double> a;    QVector<double> b;    QVector<double> c;    // control points    QPolygonF points;};static int lookup( double x, const QPolygonF &values ){#if 0//qLowerBound/qHigherBound ???#endif    int i1;    const int size = ( int )values.size();    if ( x <= values[0].x() )        i1 = 0;    else if ( x >= values[size - 2].x() )        i1 = size - 2;    else    {        i1 = 0;        int i2 = size - 2;        int i3 = 0;        while ( i2 - i1 > 1 )        {            i3 = i1 + ( ( i2 - i1 ) >> 1 );            if ( values[i3].x() > x )                i2 = i3;            else                i1 = i3;        }    }    return i1;}//! ConstructorQwtSpline::QwtSpline(){    d_data = new PrivateData;}/*!   Copy constructor   \param other Spline used for initilization*/QwtSpline::QwtSpline( const QwtSpline& other ){    d_data = new PrivateData( *other.d_data );}/*!   Assignment operator   \param other Spline used for initilization*/QwtSpline &QwtSpline::operator=( const QwtSpline & other ){    *d_data = *other.d_data;    return *this;}//! DestructorQwtSpline::~QwtSpline(){    delete d_data;}/*!   Select the algorithm used for calculating the spline   \param splineType Spline type   \sa splineType()*/void QwtSpline::setSplineType( SplineType splineType ){    d_data->splineType = splineType;}/*!   \return the spline type   \sa setSplineType()*/QwtSpline::SplineType QwtSpline::splineType() const{    return d_data->splineType;}/*!  \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 points Points  \return true if successful  \warning The sequence of x (but not y) values has to be strictly monotone           increasing, which means <code>points[i].x() < points[i+1].x()</code>.       If this is not the case, the function will return false*/bool QwtSpline::setPoints( const QPolygonF& points ){    const int size = points.size();    if ( size <= 2 )    {        reset();        return false;    }    d_data->points = points;    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 );    if ( !ok )        reset();    return ok;}/*!   Return points passed by setPoints*/QPolygonF QwtSpline::points() const{    return d_data->points;}//! \return A coefficientsconst QVector<double> &QwtSpline::coefficientsA() const{    return d_data->a;}//! \return B coefficientsconst QVector<double> &QwtSpline::coefficientsB() const{    return d_data->b;}//! \return C coefficientsconst QVector<double> &QwtSpline::coefficientsC() const{    return d_data->c;}//! Free allocated memory and set size to 0void QwtSpline::reset(){    d_data->a.resize( 0 );    d_data->b.resize( 0 );    d_data->c.resize( 0 );    d_data->points.resize( 0 );}//! True if validbool 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*/bool QwtSpline::buildNaturalSpline( const QPolygonF &points ){    int i;    const QPointF *p = points.data();    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    QVector<double> h( size - 1 );    for ( i = 0; i < size - 1; i++ )    {        h[i] = p[i+1].x() - p[i].x();        if ( h[i] <= 0 )            return false;    }    QVector<double> d( size - 1 );    double dy1 = ( p[1].y() - p[0].y() ) / h[0];    for ( i = 1; i < size - 1; i++ )    {        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    //    // L-U Factorization    for ( i = 1; i < size - 2; i++ )    {        c[i] /= a[i];        a[i+1] -= b[i] * c[i];    }    // forward elimination    QVector<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    //    for ( i = 0; i < size - 1; i++ )    {        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*/bool QwtSpline::buildPeriodicSpline( const QPolygonF &points ){    int i;    const QPointF *p = points.data();    const int size = points.size();    double *a = d_data->a.data();    double *b = d_data->b.data();    double *c = d_data->c.data();    QVector<double> d( size - 1 );    QVector<double> h( size - 1 );    QVector<double> s( size );    //    //  setup equation system; use coefficient    //  vectors as temporary buffers    //    for ( i = 0; i < size - 1; i++ )    {        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;    for ( i = 0; i <= imax; i++ )    {        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] = qSqrt( a[0] );    c[0] = h[imax] / a[0];    double sum = 0;    for ( i = 0; i < imax - 1; i++ )    {        b[i] /= a[i];        if ( i > 0 )            c[i] = - c[i-1] * b[i-1] / a[i];        a[i+1] = qSqrt( 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] = qSqrt( a[imax] - qwtSqr( b[imax-1] ) - sum );    // forward elimination    s[0] = d[0] / a[0];    sum = 0;    for ( i = 1; i < imax; i++ )    {        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];    for ( i = 0; i < size - 1; i++ )    {        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;}
 |