10#include "qwt_spline_cubic.h" 
   11#include "qwt_spline_polynomial.h" 
   14#include <qpainterpath.h> 
   16#define SLOPES_INCREMENTAL 0 
   19namespace QwtSplineCubicP
 
   24        inline KahanSum( 
double value = 0.0 ):
 
   32            m_sum = m_carry = 0.0;
 
   35        inline double value()
 const 
   40        inline void add( 
double value )
 
   42            const double y = value - m_carry;
 
   43            const double t = m_sum + y;
 
   45            m_carry = ( t - m_sum ) - y;
 
   49        static inline double sum3( 
double d1, 
double d2, 
double d3 )
 
   58        static inline double sum4( 
double d1, 
double d2, 
double d3, 
double d4 )
 
   77        inline void setup( 
int size )
 
   79            m_curvatures.resize( size );
 
   80            m_cv = m_curvatures.data();
 
   83        inline void storeFirst( 
double,
 
   84            const QPointF&, 
const QPointF&, 
double b1, 
double )
 
   89        inline void storeNext( 
int index, 
double,
 
   90            const QPointF&, 
const QPointF&, 
double, 
double b2 )
 
   92            m_cv[index] = 2.0 * b2;
 
   95        inline void storeLast( 
double,
 
   96            const QPointF&, 
const QPointF&, 
double, 
double b2 )
 
   98            m_cv[m_curvatures.size() - 1] = 2.0 * b2;
 
  101        inline void storePrevious( 
int index, 
double,
 
  102            const QPointF&, 
const QPointF&, 
double b1, 
double )
 
  104            m_cv[index] = 2.0 * b1;
 
  109            m_cv[0] = m_cv[m_curvatures.size() - 1];
 
  122        inline void setup( 
int size )
 
  124            m_slopes.resize( size );
 
  125            m_m = m_slopes.data();
 
  128        inline void storeFirst( 
double h,
 
  129            const QPointF& p1, 
const QPointF& p2, 
double b1, 
double b2 )
 
  131            const double s = ( p2.y() - p1.y() ) / h;
 
  132            m_m[0] = s - h * ( 2.0 * b1 + b2 ) / 3.0;
 
  138        inline void storeNext( 
int index, 
double h,
 
  139            const QPointF& p1, 
const QPointF& p2, 
double b1, 
double b2 )
 
  141#if SLOPES_INCREMENTAL 
  145            m_sum.add( ( b1 + b2 ) * h );
 
  146            m_m[index] = m_sum.value();
 
  148            m_m[index] = m_m[index - 1] + ( b1 + b2 ) * h;
 
  151            const double s = ( p2.y() - p1.y() ) / h;
 
  152            m_m[index] = s + h * ( b1 + 2.0 * b2 ) / 3.0;
 
  156        inline void storeLast( 
double h,
 
  157            const QPointF& p1, 
const QPointF& p2, 
double b1, 
double b2 )
 
  159            const double s = ( p2.y() - p1.y() ) / h;
 
  160            m_m[m_slopes.size() - 1] = s + h * ( b1 + 2.0 * b2 ) / 3.0;
 
  162            m_sum.add( m_m[m_slopes.size() - 1] );
 
  166        inline void storePrevious( 
int index, 
double h,
 
  167            const QPointF& p1, 
const QPointF& p2, 
double b1, 
double b2 )
 
  169#if SLOPES_INCREMENTAL 
  173            m_sum.add( -( b1 + b2 ) * h );
 
  174            m_m[index] = m_sum.value();
 
  176            m_m[index] = m_m[index + 1] - ( b1 + b2 ) * h;
 
  180            const double s = ( p2.y() - p1.y() ) / h;
 
  181            m_m[index] = s - h * ( 2.0 * b1 + b2 ) / 3.0;
 
  187            m_m[0] = m_m[m_slopes.size() - 1];
 
  195#if SLOPES_INCREMENTAL 
  201namespace QwtSplineCubicP
 
  210        inline Equation2( 
double p0, 
double q0, 
double r0 ):
 
  217        inline void setup( 
double p0, 
double q0, 
double r0 )
 
  224        inline Equation2 normalized()
 const 
  234        inline double resolved1( 
double x2 )
 const 
  236            return ( r - q * x2 ) / p;
 
  239        inline double resolved2( 
double x1 )
 const 
  241            return ( r - p * x1 ) / q;
 
  244        inline double resolved1( 
const Equation2& eq )
 const 
  248            return ( r - k * eq.r ) / ( p - k * eq.p );
 
  251        inline double resolved2( 
const Equation2& eq )
 const 
  254            const double k = p / eq.p;
 
  255            return ( r - k * eq.r ) / ( q - k * eq.q );
 
  269        inline Equation3( 
const QPointF& p1, 
const QPointF& p2, 
const QPointF& p3 )
 
  271            const double h1 = p2.x() - p1.x();
 
  272            const double s1 = ( p2.y() - p1.y() ) / h1;
 
  274            const double h2 = p3.x() - p2.x();
 
  275            const double s2 = ( p3.y() - p2.y() ) / h2;
 
  283        inline Equation3( 
double cp, 
double cq, 
double du, 
double dr ):
 
  291        inline bool operator==( 
const Equation3& c )
 const 
  293            return ( p == c.p ) && ( q == c.q ) &&
 
  294                   ( u == c.u ) && ( r == c.r );
 
  297        inline void setup( 
double cp, 
double cq, 
double du, 
double dr )
 
  305        inline Equation3 normalized()
 const 
  316        inline Equation2 substituted1( 
const Equation3& eq )
 const 
  319            const double k = p / eq.p;
 
  320            return Equation2( q - k * eq.q, u - k * eq.u, r - k * eq.r );
 
  323        inline Equation2 substituted2( 
const Equation3& eq )
 const 
  327            const double k = q / eq.q;
 
  328            return Equation2( p - k * eq.p, u - k * eq.u, r - k * eq.r );
 
  331        inline Equation2 substituted3( 
const Equation3& eq )
 const 
  335            const double k = u / eq.u;
 
  336            return Equation2( p - k * eq.p, q - k * eq.q, r - k * eq.r );
 
  339        inline Equation2 substituted1( 
const Equation2& eq )
 const 
  342            const double k = p / eq.p;
 
  343            return Equation2( q - k * eq.q, u, r - k * eq.r );
 
  346        inline Equation2 substituted3( 
const Equation2& eq )
 const 
  350            const double k = u / eq.q;
 
  351            return Equation2( p, q - k * eq.p, r - k * eq.r );
 
  355        inline double resolved1( 
double x2, 
double x3 )
 const 
  357            return ( r - q * x2 - u * x3 ) / p;
 
  360        inline double resolved2( 
double x1, 
double x3 )
 const 
  362            return ( r - u * x3 - p * x1 ) / q;
 
  365        inline double resolved3( 
double x1, 
double x2 )
 const 
  367            return ( r - p * x1 - q * x2 ) / u;
 
  376static QDebug operator<<( QDebug debug, 
const QwtSplineCubicP::Equation2& eq )
 
  378    debug.nospace() << 
"EQ2(" << eq.p << 
", " << eq.q << 
", " << eq.r << 
")";
 
  379    return debug.space();
 
  382static QDebug operator<<( QDebug debug, 
const QwtSplineCubicP::Equation3& eq )
 
  384    debug.nospace() << 
"EQ3(" << eq.p << 
", " 
  385                    << eq.q << 
", " << eq.u << 
", " << eq.r << 
")";
 
  386    return debug.space();
 
  390namespace QwtSplineCubicP
 
  396        void setStartCondition( 
double p, 
double q, 
double u, 
double r )
 
  398            m_conditionsEQ[0].setup( p, q, u, r );
 
  401        void setEndCondition( 
double p, 
double q, 
double u, 
double r )
 
  403            m_conditionsEQ[1].setup( p, q, u, r );
 
  406        const T& store()
 const 
  411        void resolve( 
const QPolygonF& p )
 
  413            const int n = p.size();
 
  417            if ( m_conditionsEQ[0].p == 0.0 ||
 
  418                ( m_conditionsEQ[0].q == 0.0 && m_conditionsEQ[0].u != 0.0 ) )
 
  423            if ( m_conditionsEQ[1].u == 0.0 ||
 
  424                ( m_conditionsEQ[1].q == 0.0 && m_conditionsEQ[1].p != 0.0 ) )
 
  429            const double h0 = p[1].x() - p[0].x();
 
  430            const double h1 = p[2].x() - p[1].x();
 
  431            const double hn = p[n - 1].x() - p[n - 2].x();
 
  443                const Equation3 eqSpline0( p[0], p[1], p[2] ); 
 
  444                const Equation2 eq0 = m_conditionsEQ[0].substituted1( eqSpline0 );
 
  451                if ( m_conditionsEQ[0].normalized() == m_conditionsEQ[1].normalized() )
 
  462                    const Equation2 eq = m_conditionsEQ[1].substituted1( eqSpline0 );
 
  463                    b1 = eq0.resolved1( eq );
 
  466                const double b2 = eq0.resolved2( b1 );
 
  467                const double b0 = eqSpline0.resolved1( b1, b2 );
 
  469                m_store.storeFirst( h0, p[0], p[1], b0, b1 );
 
  470                m_store.storeNext( 1, h0, p[0], p[1], b0, b1 );
 
  471                m_store.storeNext( 2, h1, p[1], p[2], b1, b2 );
 
  476            const Equation3 eqSplineN( p[n - 3], p[n - 2], p[n - 1] );
 
  477            const Equation2 eqN = m_conditionsEQ[1].substituted3( eqSplineN );
 
  482                const Equation3 eqSplineR( p[n - 4], p[n - 3], p[n - 2] );
 
  483                eq = eqSplineR.substituted3( eq );
 
  484                eq = substituteSpline( p, eq );
 
  487            const Equation3 eqSpline0( p[0], p[1], p[2] );
 
  490            if ( m_conditionsEQ[0].u == 0.0 )
 
  492                eq = eqSpline0.substituted3( eq );
 
  494                const Equation3& eq0 = m_conditionsEQ[0];
 
  495                b0 = Equation2( eq0.p, eq0.q, eq0.r ).resolved1( eq );
 
  496                b1 = eq.resolved2( b0 );
 
  500                const Equation2 eqX = m_conditionsEQ[0].substituted3( eq );
 
  501                const Equation2 eqY = eqSpline0.substituted3( eq );
 
  503                b0 = eqY.resolved1( eqX );
 
  504                b1 = eqY.resolved2( b0 );
 
  507            m_store.storeFirst( h0, p[0], p[1], b0, b1 );
 
  508            m_store.storeNext( 1, h0, p[0], p[1], b0, b1 );
 
  510            const double bn2 = resolveSpline( p, b1 );
 
  512            const double bn1 = eqN.resolved2( bn2 );
 
  513            const double bn0 = m_conditionsEQ[1].resolved3( bn2, bn1 );
 
  515            const double hx = p[n - 2].x() - p[n - 3].x();
 
  516            m_store.storeNext( n - 2, hx, p[n - 3], p[n - 2], bn2, bn1 );
 
  517            m_store.storeNext( n - 1, hn, p[n - 2], p[n - 1], bn1, bn0 );
 
  521        Equation2 substituteSpline( 
const QPolygonF& points, 
const Equation2& eq )
 
  523            const int n = points.size();
 
  525            m_eq.resize( n - 2 );
 
  530            double slope2 = ( points[n - 3].y() - points[n - 4].y() ) / eq.p;
 
  532            for ( 
int i = n - 4; i > 1; i-- )
 
  534                const Equation2& eq2 = m_eq[i + 1];
 
  535                Equation2& eq1 = m_eq[i];
 
  537                eq1.p = points[i].x() - points[i - 1].x();
 
  538                const double slope1 = ( points[i].y() - points[i - 1].y() ) / eq1.p;
 
  540                const double v = eq2.p / eq2.q;
 
  542                eq1.q = 2.0 * ( eq1.p + eq2.p ) - v * eq2.p;
 
  543                eq1.r = 3.0 * ( slope2 - slope1 ) - v * eq2.r;
 
  551        double resolveSpline( 
const QPolygonF& points, 
double b1 )
 
  553            const int n = points.size();
 
  554            const QPointF* p = points.constData();
 
  556            for ( 
int i = 2; i < n - 2; i++ )
 
  559                const double b2 = m_eq[i].resolved2( b1 );
 
  560                m_store.storeNext( i, m_eq[i].p, p[i - 1], p[i], b1, b2 );
 
  569        Equation3 m_conditionsEQ[2];
 
  575    class EquationSystem2
 
  578        const T& store()
 const 
  583        void resolve( 
const QPolygonF& p )
 
  585            const int n = p.size();
 
  587            if ( p[n - 1].y() != p[0].y() )
 
  592            const double h0 = p[1].x() - p[0].x();
 
  593            const double s0 = ( p[1].y() - p[0].y() ) / h0;
 
  597                const double h1 = p[2].x() - p[1].x();
 
  598                const double s1 = ( p[2].y() - p[1].y() ) / h1;
 
  600                const double b = 3.0 * ( s0 - s1 ) / ( h0 + h1 );
 
  603                m_store.storeLast( h1, p[1], p[2], -b, b );
 
  604                m_store.storePrevious( 1, h1, p[1], p[2], -b, b );
 
  610            const double hn = p[n - 1].x() - p[n - 2].x();
 
  613            substitute( p, eqn, eqX );
 
  615            const double b0 = eqn.resolved2( eqX );
 
  616            const double bn = eqn.resolved1( b0 );
 
  619            m_store.storeLast( hn, p[n - 2], p[n - 1], bn, b0 );
 
  620            m_store.storePrevious( n - 2, hn, p[n - 2], p[n - 1], bn, b0 );
 
  622            resolveSpline( p, b0, bn );
 
  629        void substitute( 
const QPolygonF& points, Equation2& eqn, Equation2& eqX )
 
  631            const int n = points.size();
 
  633            const double hn = points[n - 1].x() - points[n - 2].x();
 
  635            const Equation3 eqSpline0( points[0], points[1], points[2] );
 
  636            const Equation3 eqSplineN(
 
  637                QPointF( points[0].x() - hn, points[n - 2].y() ), points[0], points[1] );
 
  639            m_eq.resize( n - 1 );
 
  646            double slope1 = ( points[2].y() - points[1].y() ) / m_eq[1].u;
 
  660            for ( 
int i = 2; i < n - 1; i++ )
 
  662                const Equation3& eq1 = m_eq[i - 1];
 
  663                Equation3& eq2 = m_eq[i];
 
  665                dq += eq1.p * eq1.p / eq1.q;
 
  666                dr += eq1.p * eq1.r / eq1.q;
 
  668                eq2.u = points[i + 1].x() - points[i].x();
 
  669                const double slope2 = ( points[i + 1].y() - points[i].y() ) / eq2.u;
 
  671                const double k = eq1.u / eq1.q;
 
  674                eq2.q = 2.0 * ( eq1.u + eq2.u ) - eq1.u * k;
 
  675                eq2.r = 3.0 * ( slope2 - slope1 ) - eq1.r * k;
 
  682            eqn.setup( m_eq[n - 2].q, m_eq[n - 2].p + eqSplineN.p, m_eq[n - 2].r );
 
  685            eqX.setup( m_eq[n - 2].p + eqSplineN.p, eqSplineN.q - dq, eqSplineN.r - dr );
 
  688        void resolveSpline( 
const QPolygonF& points, 
double b0, 
double bi )
 
  690            const int n = points.size();
 
  692            for ( 
int i = n - 3; i >= 1; i-- )
 
  694                const Equation3& eq = m_eq[i];
 
  696                const double b = eq.resolved2( b0, bi );
 
  697                m_store.storePrevious( i, eq.u, points[i], points[i + 1], b, bi );
 
  703        void resolveSpline2( 
const QPolygonF& points,
 
  706            const int n = points.size();
 
  708            bi = m_eq[0].resolved3( b0, bi );
 
  710            for ( 
int i = 1; i < n - 2; i++ )
 
  712                const Equation3& eq = m_eq[i];
 
  714                const double b = eq.resolved3( b0, bi );
 
  715                m[i + 1] = m[i] + ( b + bi ) * m_eq[i].u;
 
  721        void resolveSpline3( 
const QPolygonF& points,
 
  724            const int n = points.size();
 
  726            double h0 = ( points[1].x() - points[0].x() );
 
  727            double s0 = ( points[1].y() - points[0].y() ) / h0;
 
  729            m[1] = m[0] + ( b0 + b1 ) * h0;
 
  731            for ( 
int i = 1; i < n - 1; i++ )
 
  733                const double h1 = ( points[i + 1].x() - points[i].x() );
 
  734                const double s1 = ( points[i + 1].y() - points[i].y() ) / h1;
 
  736                const double r = 3.0 * ( s1 - s0 );
 
  738                const double b2 = ( r - h0 * b0 - 2.0 * ( h0 + h1 ) * b1 ) / h1;
 
  739                m[i + 1] = m[i] + ( b1 + b2 ) * h1;
 
  748        void resolveSpline4( 
const QPolygonF& points,
 
  751            const int n = points.size();
 
  753            double h2 = ( points[n - 1].x() - points[n - 2].x() );
 
  754            double s2 = ( points[n - 1].y() - points[n - 2].y() ) / h2;
 
  756            for ( 
int i = n - 2; i > 1; i-- )
 
  758                const double h1 = ( points[i].x() - points[i - 1].x() );
 
  759                const double s1 = ( points[i].y() - points[i - 1].y() ) / h1;
 
  761                const double r = 3.0 * ( s2 - s1 );
 
  762                const double k = 2.0 * ( h1 + h2 );
 
  764                const double b0 = ( r - h2 * b2 - k * b1 ) / h1;
 
  766                m[i - 1] = m[i] - ( b0 + b1 ) * h1;
 
  781static void qwtSetupEndEquations(
 
  782    int conditionBegin, 
double valueBegin, 
int conditionEnd, 
double valueEnd,
 
  783    const QPolygonF& points, QwtSplineCubicP::Equation3 eq[2] )
 
  785    const int n = points.size();
 
  787    const double h0 = points[1].x() - points[0].x();
 
  788    const double s0 = ( points[1].y() - points[0].y() ) / h0;
 
  790    const double hn = ( points[n - 1].x() - points[n - 2].x() );
 
  791    const double sn = ( points[n - 1].y() - points[n - 2].y() ) / hn;
 
  793    switch( conditionBegin )
 
  808            eq[0].setup( 2 * h0 / 3.0, h0 / 3.0, 0.0, s0 - valueBegin );
 
  821            eq[0].setup( 1.0, 0.0, 0.0, 0.5 * valueBegin );
 
  836            eq[0].setup( 1.0, -1.0, 0.0, -0.5 * valueBegin * h0 );
 
  842            const double r0 = qBound( 0.0, valueBegin, 1.0 );
 
  846                eq[0].setup( 2 * h0 / 3.0, h0 / 3.0, 0.0, 0.0 );
 
  850                eq[0].setup( 1.0 + 2.0 / r0, 2.0 + 1.0 / r0, 0.0, 0.0 );
 
  875                v0 = h0 / ( points[2].x() - points[1].x() );
 
  878            eq[0].setup( 1.0, -( 1.0 + v0 ), v0, 0.0 );
 
  885            eq[0].setup( 1.0, 0.0, 0.0, 0.0 );
 
  890    switch( conditionEnd )
 
  895            eq[1].setup( 0.0, 1.0 / 3.0 * hn, 2.0 / 3.0 * hn, valueEnd - sn );
 
  901            eq[1].setup( 0.0, 0.0, 1.0, 0.5 * valueEnd );
 
  907            eq[1].setup( 0.0, 1.0, -1.0, -0.5 * valueEnd * hn );
 
  912            const double rn = qBound( 0.0, valueEnd, 1.0 );
 
  916                eq[1].setup( 0.0, 1.0 / 3.0 * hn, 2.0 / 3.0 * hn, 0.0 );
 
  920                eq[1].setup( 0.0, 2.0 + 1.0 / rn, 1.0 + 2.0 / rn, 0.0 );
 
  942                vn = hn / ( points[n - 2].x() - points[n - 3].x() );
 
  945            eq[1].setup( vn, -( 1.0 + vn ), 1.0, 0.0 );
 
  952            eq[1].setup( 0.0, 0.0, 1.0, 0.0 );
 
  958class QwtSplineCubic::PrivateData
 
 1008    using namespace QwtSplineCubicP;
 
 1010    if ( points.size() <= 2 )
 
 1016        EquationSystem2< SlopeStore > eqs;
 
 1017        eqs.resolve( points );
 
 1019        return eqs.store().slopes();
 
 1022    if ( points.size() == 3 )
 
 1028            const double h0 = points[1].x() - points[0].x();
 
 1029            const double h1 = points[2].x() - points[1].x();
 
 1031            const double s0 = ( points[1].y() - points[0].y() ) / h0;
 
 1032            const double s1 = ( points[2].y() - points[1].y() ) / h1;
 
 1039            const double b = ( s1 - s0 ) / ( h0 + h1 );
 
 1054    qwtSetupEndEquations(
 
 1061    EquationSystem< SlopeStore > eqs;
 
 1062    eqs.setStartCondition( eq[0].p, eq[0].q, eq[0].u, eq[0].r );
 
 1063    eqs.setEndCondition( eq[1].p, eq[1].q, eq[1].u, eq[1].r );
 
 1064    eqs.resolve( points );
 
 1066    return eqs.store().slopes();
 
 
 1080    using namespace QwtSplineCubicP;
 
 1082    if ( points.size() <= 2 )
 
 1088        EquationSystem2< CurvatureStore > eqs;
 
 1089        eqs.resolve( points );
 
 1091        return eqs.store().curvatures();
 
 1094    if ( points.size() == 3 )
 
 1104    qwtSetupEndEquations(
 
 1111    EquationSystem< CurvatureStore > eqs;
 
 1112    eqs.setStartCondition( eq[0].p, eq[0].q, eq[0].u, eq[0].r );
 
 1113    eqs.setEndCondition( eq[1].p, eq[1].q, eq[1].u, eq[1].r );
 
 1114    eqs.resolve( points );
 
 1116    return eqs.store().curvatures();
 
 
virtual QPainterPath painterPath(const QPolygonF &) const override
Calculate an interpolated painter path.
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const override
Calculate the interpolating polynomials for a non parametric spline.
QwtSplineCubic()
Constructor The default setting is a non closing natural spline with no parametrization.
virtual ~QwtSplineCubic()
Destructor.
virtual uint locality() const override
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
virtual QVector< QLineF > bezierControlLines(const QPolygonF &points) const override
Interpolate a curve with Bezier curves.
virtual QVector< double > curvatures(const QPolygonF &) const override
Find the second derivative at the control points.
virtual QVector< double > slopes(const QPolygonF &) const override
Find the first derivative at the control points.
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const override
Calculate the interpolating polynomials for a non parametric spline.
@ AtBeginning
the condition is at the beginning of the polynomial
@ AtEnd
the condition is at the end of the polynomial
double boundaryValue(BoundaryPosition) const
void setBoundaryCondition(BoundaryPosition, int condition)
Define the condition for an endpoint of the spline.
int boundaryCondition(BoundaryPosition) const
BoundaryType boundaryType() const
void setBoundaryValue(BoundaryPosition, double value)
Define the boundary value.