10 #include "qwt_spline_cubic.h" 
   11 #include "qwt_spline_polynomial.h" 
   14 #include <qpainterpath.h> 
   16 #define SLOPES_INCREMENTAL 0 
   19 namespace 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 
  201 namespace 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;
 
  376 static QDebug operator<<( QDebug debug, 
const QwtSplineCubicP::Equation2& eq )
 
  378     debug.nospace() << 
"EQ2(" << eq.p << 
", " << eq.q << 
", " << eq.r << 
")";
 
  379     return debug.space();
 
  382 static 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();
 
  390 namespace 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;
 
  781 static 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 );
 
  958 class 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.