qwt_spline.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_spline.h"
00011 #include "qwt_spline_parametrization.h"
00012 #include "qwt_bezier.h"
00013 #include "qwt_math.h"
00014 
00015 namespace QwtSplineC1P
00016 {
00017     struct param
00018     {
00019         param( const QwtSplineParametrization *p ):
00020             parameter( p )
00021         {
00022         }
00023 
00024         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00025         {
00026             return parameter->valueIncrement( p1, p2 );
00027         }
00028 
00029         const QwtSplineParametrization *parameter;
00030     };
00031 
00032     struct paramY
00033     {
00034         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00035         {
00036             return QwtSplineParametrization::valueIncrementY( p1, p2 );
00037         }
00038     };
00039 
00040     struct paramUniform
00041     {
00042         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00043         {
00044             return QwtSplineParametrization::valueIncrementUniform( p1, p2 );
00045         }
00046     };
00047 
00048     struct paramCentripetal
00049     {
00050         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00051         {
00052             return QwtSplineParametrization::valueIncrementCentripetal( p1, p2 );
00053         }
00054     };
00055 
00056     struct paramChordal
00057     {
00058         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00059         {
00060             return QwtSplineParametrization::valueIncrementChordal( p1, p2 );
00061         }
00062     };
00063 
00064     struct paramManhattan
00065     {
00066         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00067         {
00068             return QwtSplineParametrization::valueIncrementManhattan( p1, p2 );
00069         }
00070     };
00071 
00072     class PathStore
00073     {
00074     public:
00075         inline void init( int size )
00076         {
00077             Q_UNUSED(size);
00078         }
00079 
00080         inline void start( double x1, double y1 )
00081         {
00082             path.moveTo( x1, y1 );
00083         }
00084 
00085         inline void addCubic( double cx1, double cy1,
00086             double cx2, double cy2, double x2, double y2 )
00087         {
00088             path.cubicTo( cx1, cy1, cx2, cy2, x2, y2 );
00089         }
00090 
00091         inline void end()
00092         {
00093             path.closeSubpath();
00094         }
00095 
00096         QPainterPath path;
00097     };
00098 
00099     class ControlPointsStore
00100     {
00101     public:
00102         inline ControlPointsStore():
00103             d_cp( NULL )
00104         {
00105         }
00106 
00107         inline void init( int size )
00108         {
00109             controlPoints.resize( size );
00110             d_cp = controlPoints.data();
00111         }   
00112 
00113         inline void start( double x1, double y1 )
00114         {   
00115             Q_UNUSED( x1 );
00116             Q_UNUSED( y1 );
00117         }
00118         
00119         inline void addCubic( double cx1, double cy1,
00120             double cx2, double cy2, double x2, double y2 )
00121         {
00122             Q_UNUSED( x2 );
00123             Q_UNUSED( y2 );
00124 
00125             QLineF &l = *d_cp++;
00126             l.setLine( cx1, cy1, cx2, cy2 );
00127         }
00128 
00129         inline void end()
00130         {
00131         } 
00132 
00133         QVector<QLineF> controlPoints;
00134 
00135     private:
00136         QLineF* d_cp;
00137     };
00138 
00139     double slopeBoundary( int boundaryCondition, double boundaryValue,
00140         const QPointF &p1, const QPointF &p2, double slope1 )
00141     {
00142         const double dx = p2.x() - p1.x();
00143         const double dy = p2.y() - p1.y();
00144 
00145         double m = 0.0;
00146 
00147         switch( boundaryCondition )
00148         {
00149             case QwtSpline::Clamped1:
00150             {
00151                 m = boundaryValue;
00152                 break;
00153             }
00154             case QwtSpline::Clamped2:
00155             {
00156                 const double c2 = 0.5 * boundaryValue;
00157                 const double c1 = slope1;
00158 
00159                 m = 0.5 * ( 3.0 * dy / dx - c1 - c2 * dx );
00160                 break;
00161             }
00162             case QwtSpline::Clamped3:
00163             {
00164                 const double c3 = boundaryValue / 6.0;
00165                 m = c3 * dx * dx + 2 * dy / dx - slope1;
00166                 break;
00167             }
00168             case QwtSpline::LinearRunout:
00169             {
00170                 const double s = dy / dx;
00171                 const double r = qBound( 0.0, boundaryValue, 1.0 );
00172 
00173                 m = s - r * ( s - slope1 );
00174                 break;
00175             }
00176             default:
00177             {
00178                 m = dy / dx; // something
00179             }
00180         }
00181 
00182         return m;
00183     }
00184 }
00185 
00186 template< class SplineStore >
00187 static inline SplineStore qwtSplineC1PathParamX(
00188     const QwtSplineC1 *spline, const QPolygonF &points )
00189 {
00190     const int n = points.size();
00191 
00192     const QVector<double> m = spline->slopes( points );
00193     if ( m.size() != n )
00194         return SplineStore();
00195 
00196     const QPointF *pd = points.constData();
00197     const double *md = m.constData();
00198 
00199     SplineStore store;
00200     store.init( m.size() - 1 );
00201     store.start( pd[0].x(), pd[0].y() );
00202 
00203     for ( int i = 0; i < n - 1; i++ )
00204     {
00205         const double dx3 = ( pd[i+1].x() - pd[i].x() ) / 3.0;
00206 
00207         store.addCubic( pd[i].x() + dx3, pd[i].y() + md[i] * dx3,
00208             pd[i+1].x() - dx3, pd[i+1].y() - md[i+1] * dx3,
00209             pd[i+1].x(), pd[i+1].y() );
00210     }
00211 
00212     return store;
00213 }
00214 
00215 template< class SplineStore >
00216 static inline SplineStore qwtSplineC1PathParamY(
00217     const QwtSplineC1 *spline, const QPolygonF &points )
00218 {
00219     const int n = points.size();
00220 
00221     QPolygonF pointsFlipped( n );
00222     for ( int i = 0; i < n; i++ )
00223     {
00224         pointsFlipped[i].setX( points[i].y() );
00225         pointsFlipped[i].setY( points[i].x() );
00226     }
00227 
00228     const QVector<double> m = spline->slopes( pointsFlipped );
00229     if ( m.size() != n )
00230         return SplineStore();
00231 
00232     const QPointF *pd = pointsFlipped.constData();
00233     const double *md = m.constData();
00234 
00235     SplineStore store;
00236     store.init( m.size() - 1 );
00237     store.start( pd[0].y(), pd[0].x() );
00238 
00239     QVector<QLineF> lines( n );
00240     for ( int i = 0; i < n - 1; i++ )
00241     {
00242         const double dx3 = ( pd[i+1].x() - pd[i].x() ) / 3.0;
00243 
00244         store.addCubic( pd[i].y() + md[i] * dx3, pd[i].x() + dx3, 
00245             pd[i+1].y() - md[i+1] * dx3, pd[i+1].x() - dx3, 
00246             pd[i+1].y(), pd[i+1].x() );
00247     }
00248 
00249     return store;
00250 }
00251 
00252 template< class SplineStore, class Param >
00253 static inline SplineStore qwtSplineC1PathParametric( 
00254     const QwtSplineC1 *spline, const QPolygonF &points, Param param )
00255 {
00256     const bool isClosing = ( spline->boundaryType() == QwtSpline::ClosedPolygon );
00257     const int n = points.size();
00258 
00259     QPolygonF pointsX, pointsY;
00260     pointsX.resize( isClosing ? n + 1 : n );
00261     pointsY.resize( isClosing ? n + 1 : n );
00262 
00263     QPointF *px = pointsX.data();
00264     QPointF *py = pointsY.data();
00265     const QPointF *p = points.constData();
00266 
00267     double t = 0.0;
00268 
00269     px[0].rx() = py[0].rx() = t;
00270     px[0].ry() = p[0].x();
00271     py[0].ry() = p[0].y();
00272 
00273     int numParamPoints = 1;
00274     for ( int i = 1; i < n; i++ )
00275     {
00276         const double td = param( points[i-1], points[i] );
00277         if ( td > 0.0 )
00278         {
00279             t += td;
00280 
00281             px[numParamPoints].rx() = py[numParamPoints].rx() = t;
00282 
00283             px[numParamPoints].ry() = p[i].x();
00284             py[numParamPoints].ry() = p[i].y();
00285 
00286             numParamPoints++;
00287         }
00288     }
00289 
00290     if ( isClosing )
00291     {
00292         const double td = param( points[n-1], points[0] );
00293 
00294         if ( td > 0.0 )
00295         {
00296             t += td;
00297 
00298             px[numParamPoints].rx() = py[numParamPoints].rx() = t;
00299 
00300             px[numParamPoints].ry() = p[0].x();
00301             py[numParamPoints].ry() = p[0].y();
00302 
00303             numParamPoints++;
00304         }
00305     }
00306 
00307     if ( pointsX.size() != numParamPoints )
00308     {
00309         pointsX.resize( numParamPoints );
00310         pointsY.resize( numParamPoints );
00311     }
00312 
00313     const QVector<double> slopesX = spline->slopes( pointsX );
00314     const QVector<double> slopesY = spline->slopes( pointsY );
00315 
00316     const double *mx = slopesX.constData();
00317     const double *my = slopesY.constData();
00318 
00319     // we don't need it anymore
00320     pointsX.clear(); 
00321     pointsY.clear(); 
00322 
00323     SplineStore store;
00324     store.init( isClosing ? n : n - 1 );
00325     store.start( points[0].x(), points[0].y() );
00326 
00327     int j = 0;
00328 
00329     for ( int i = 0; i < n - 1; i++ )
00330     {
00331         const QPointF &p1 = p[i];
00332         const QPointF &p2 = p[i+1];
00333 
00334         const double td = param( p1, p2 );
00335 
00336         if ( td != 0.0 )
00337         {
00338             const double t3 = td / 3.0;
00339 
00340             const double cx1 = p1.x() + mx[j] * t3;
00341             const double cy1 = p1.y() + my[j] * t3;
00342 
00343             const double cx2 = p2.x() - mx[j+1] * t3;
00344             const double cy2 = p2.y() - my[j+1] * t3;
00345 
00346             store.addCubic( cx1, cy1, cx2, cy2, p2.x(), p2.y() );
00347 
00348             j++;
00349         }
00350         else
00351         {
00352             // setting control points to the ends
00353             store.addCubic( p1.x(), p1.y(), p2.x(), p2.y(), p2.x(), p2.y() );
00354         }
00355     }
00356 
00357     if ( isClosing )
00358     {
00359         const QPointF &p1 = p[n-1];
00360         const QPointF &p2 = p[0];
00361 
00362         const double td = param( p1, p2 );
00363 
00364         if ( td != 0.0 )
00365         {
00366             const double t3 = td / 3.0;
00367 
00368             const double cx1 = p1.x() + mx[j] * t3;
00369             const double cy1 = p1.y() + my[j] * t3;
00370 
00371             const double cx2 = p2.x() - mx[0] * t3;
00372             const double cy2 = p2.y() - my[0] * t3;
00373 
00374             store.addCubic( cx1, cy1, cx2, cy2, p2.x(), p2.y() );
00375         }
00376         else
00377         {
00378             store.addCubic( p1.x(), p1.y(), p2.x(), p2.y(), p2.x(), p2.y() );
00379         }
00380 
00381         store.end();
00382     }
00383 
00384     return store;
00385 }
00386 
00387 template< QwtSplinePolynomial toPolynomial( const QPointF &, double, const QPointF &, double ) >
00388 static QPolygonF qwtPolygonParametric( double distance,
00389     const QPolygonF &points, const QVector<double> values, bool withNodes ) 
00390 {
00391     QPolygonF fittedPoints;
00392 
00393     const QPointF *p = points.constData();
00394     const double *v = values.constData();
00395     
00396     fittedPoints += p[0];
00397     double t = distance;
00398     
00399     const int n = points.size();
00400 
00401     for ( int i = 0; i < n - 1; i++ )
00402     {
00403         const QPointF &p1 = p[i];
00404         const QPointF &p2 = p[i+1];
00405 
00406         const QwtSplinePolynomial polynomial = toPolynomial( p1, v[i], p2, v[i+1] );
00407             
00408         const double l = p2.x() - p1.x();
00409         
00410         while ( t < l )
00411         {
00412             fittedPoints += QPointF( p1.x() + t, p1.y() + polynomial.valueAt( t ) );
00413             t += distance;
00414         }   
00415         
00416         if ( withNodes )
00417         {
00418             if ( qFuzzyCompare( fittedPoints.last().x(), p2.x() ) )
00419                 fittedPoints.last() = p2;
00420             else
00421                 fittedPoints += p2;
00422         }       
00423         else
00424         {
00425             t -= l;
00426         }   
00427     }   
00428     
00429     return fittedPoints;
00430 }
00431 
00432 class QwtSpline::PrivateData
00433 {
00434 public:
00435     PrivateData():
00436         boundaryType( QwtSpline::ConditionalBoundaries )
00437     {
00438         parametrization = new QwtSplineParametrization( 
00439             QwtSplineParametrization::ParameterChordal );
00440 
00441         // parabolic runout at both ends
00442         
00443         boundaryConditions[0].type = QwtSpline::Clamped3;
00444         boundaryConditions[0].value = 0.0;
00445         
00446         boundaryConditions[1].type = QwtSpline::Clamped3;
00447         boundaryConditions[1].value = 0.0;
00448     }
00449 
00450     ~PrivateData()
00451     {
00452         delete parametrization;
00453     }
00454 
00455     QwtSplineParametrization *parametrization;
00456     QwtSpline::BoundaryType boundaryType;
00457 
00458     struct
00459     {   
00460         int type;
00461         double value;
00462     
00463     } boundaryConditions[2];
00464 };
00465 
00494 QPolygonF QwtSpline::polygon( const QPolygonF &points, double tolerance ) const
00495 {
00496     if ( tolerance <= 0.0 )
00497         return QPolygonF();
00498 
00499     const QPainterPath path = painterPath( points );
00500     const int n = path.elementCount();
00501     if ( n == 0 )
00502         return QPolygonF();
00503 
00504     const QPainterPath::Element el = path.elementAt( 0 );
00505     if ( el.type != QPainterPath::MoveToElement )
00506         return QPolygonF();
00507 
00508     QPointF p1( el.x, el.y );
00509 
00510     QPolygonF polygon;
00511     QwtBezier bezier( tolerance );
00512 
00513     for ( int i = 1; i < n; i += 3 )
00514     {
00515         const QPainterPath::Element el1 = path.elementAt( i );
00516         const QPainterPath::Element el2 = path.elementAt( i + 1 );
00517         const QPainterPath::Element el3 = path.elementAt( i + 2 );
00518 
00519         const QPointF cp1( el1.x, el1.y );
00520         const QPointF cp2( el2.x, el2.y );
00521         const QPointF p2( el3.x, el3.y );
00522 
00523         bezier.appendToPolygon( p1, cp1, cp2, p2, polygon );
00524 
00525         p1 = p2;
00526     }
00527 
00528     return polygon;
00529 }
00530 
00538 QwtSpline::QwtSpline()
00539 {
00540     d_data = new PrivateData;
00541 }
00542 
00544 QwtSpline::~QwtSpline()
00545 {
00546     delete d_data;
00547 }
00548 
00562 uint QwtSpline::locality() const
00563 {
00564     return 0;
00565 }
00566 
00574 void QwtSpline::setParametrization( int type )
00575 {
00576     if ( d_data->parametrization->type() != type )
00577     {
00578         delete d_data->parametrization;
00579         d_data->parametrization = new QwtSplineParametrization( type );
00580     }
00581 }
00582 
00590 void QwtSpline::setParametrization( QwtSplineParametrization *parametrization )
00591 {
00592     if ( ( parametrization != NULL ) && ( d_data->parametrization != parametrization ) )
00593     {
00594         delete d_data->parametrization;
00595         d_data->parametrization = parametrization;
00596     }
00597 }   
00598 
00603 const QwtSplineParametrization *QwtSpline::parametrization() const
00604 {
00605     return d_data->parametrization;
00606 }
00607 
00615 void QwtSpline::setBoundaryType( BoundaryType boundaryType )
00616 {
00617     d_data->boundaryType = boundaryType;
00618 }
00619 
00624 QwtSpline::BoundaryType QwtSpline::boundaryType() const
00625 {
00626     return d_data->boundaryType;
00627 }
00628 
00637 void QwtSpline::setBoundaryCondition( BoundaryPosition position, int condition )
00638 {
00639     if ( ( position == QwtSpline::AtBeginning ) || ( position == QwtSpline::AtEnd ) )
00640         d_data->boundaryConditions[position].type = condition;
00641 }
00642 
00649 int QwtSpline::boundaryCondition( BoundaryPosition position ) const
00650 {
00651     if ( ( position == QwtSpline::AtBeginning ) || ( position == QwtSpline::AtEnd ) )
00652         return d_data->boundaryConditions[position].type;
00653         
00654     return d_data->boundaryConditions[0].type; // should never happen
00655 }   
00656 
00668 void QwtSpline::setBoundaryValue( BoundaryPosition position, double value )
00669 {
00670     if ( ( position == QwtSpline::AtBeginning ) || ( position == QwtSpline::AtEnd ) )
00671         d_data->boundaryConditions[position].value = value;
00672 }       
00673 
00680 double QwtSpline::boundaryValue( BoundaryPosition position ) const
00681 {
00682     if ( ( position == QwtSpline::AtBeginning ) || ( position == QwtSpline::AtEnd ) )
00683         return d_data->boundaryConditions[position].value;
00684         
00685     return d_data->boundaryConditions[0].value; // should never happen
00686 }   
00687 
00698 void QwtSpline::setBoundaryConditions(
00699     int condition, double valueBegin, double valueEnd )
00700 {   
00701     setBoundaryCondition( QwtSpline::AtBeginning, condition );
00702     setBoundaryValue( QwtSpline::AtBeginning, valueBegin ); 
00703     
00704     setBoundaryCondition( QwtSpline::AtEnd, condition );
00705     setBoundaryValue( QwtSpline::AtEnd, valueEnd );
00706 }   
00707 
00709 QwtSplineInterpolating::QwtSplineInterpolating()
00710 {
00711 }
00712 
00714 QwtSplineInterpolating::~QwtSplineInterpolating()
00715 {
00716 }
00717 
00746 QPainterPath QwtSplineInterpolating::painterPath( const QPolygonF &points ) const
00747 {
00748     const int n = points.size();
00749 
00750     QPainterPath path;
00751     if ( n == 0 )
00752         return path;
00753 
00754     if ( n == 1 )
00755     {
00756         path.moveTo( points[0] );
00757         return path;
00758     }
00759 
00760     if ( n == 2 )
00761     {
00762         path.addPolygon( points );
00763         return path;
00764     }
00765 
00766     const QVector<QLineF> controlLines = bezierControlLines( points );
00767     if ( controlLines.size() < n - 1 )
00768         return path;
00769 
00770     const QPointF *p = points.constData();
00771     const QLineF *l = controlLines.constData();
00772 
00773     path.moveTo( p[0] );
00774     for ( int i = 0; i < n - 1; i++ )
00775         path.cubicTo( l[i].p1(), l[i].p2(), p[i+1] );
00776 
00777     if ( ( boundaryType() == QwtSpline::ClosedPolygon )
00778         && ( controlLines.size() >= n ) )
00779     {
00780         path.cubicTo( l[n-1].p1(), l[n-1].p2(), p[0] );
00781         path.closeSubpath();
00782     }
00783 
00784     return path;
00785 }
00786 
00803 QPolygonF QwtSplineInterpolating::polygon(
00804     const QPolygonF &points, double tolerance ) const
00805 {
00806     if ( tolerance <= 0.0 )
00807         return QPolygonF();
00808 
00809     const QVector<QLineF> controlLines = bezierControlLines( points );
00810     if ( controlLines.isEmpty() )
00811         return QPolygonF();
00812 
00813     const bool isClosed = boundaryType() == QwtSpline::ClosedPolygon;
00814 
00815     QwtBezier bezier( tolerance );
00816 
00817     const QPointF *p = points.constData();
00818     const QLineF *cl = controlLines.constData();
00819 
00820     const int n = controlLines.size();
00821 
00822     QPolygonF polygon;
00823 
00824     for ( int i = 0; i < n - 1; i++ )
00825     {
00826         const QLineF &l = cl[i];
00827         bezier.appendToPolygon( p[i], l.p1(), l.p2(), p[i+1], polygon );
00828     }
00829 
00830     const QPointF &pn = isClosed ? p[0] : p[n];
00831     const QLineF &l = cl[n-1];
00832 
00833     bezier.appendToPolygon( p[n-1], l.p1(), l.p2(), pn, polygon );
00834 
00835     return polygon;
00836 }
00837 
00861 QPolygonF QwtSplineInterpolating::equidistantPolygon( const QPolygonF &points, 
00862     double distance, bool withNodes ) const
00863 {
00864     if ( distance <= 0.0 )
00865         return QPolygonF();
00866 
00867     const int n = points.size();
00868     if ( n <= 1 )
00869         return points;
00870 
00871     if ( n == 2 )
00872     {
00873         // TODO
00874         return points;
00875     }
00876 
00877     QPolygonF path;
00878 
00879     const QVector<QLineF> controlLines = bezierControlLines( points );
00880 
00881     if ( controlLines.size() < n - 1 )
00882         return path;
00883 
00884     path += points.first();
00885     double t = distance;
00886 
00887     const QPointF *p = points.constData();
00888     const QLineF *cl = controlLines.constData();
00889 
00890     const QwtSplineParametrization *param = parametrization();
00891 
00892     for ( int i = 0; i < n - 1; i++ )
00893     {
00894         const double l = param->valueIncrement( p[i], p[i+1] );
00895 
00896         while ( t < l )
00897         {
00898             path += QwtBezier::pointAt( p[i], cl[i].p1(),
00899                 cl[i].p2(), p[i+1], t / l );
00900 
00901             t += distance;
00902         }
00903 
00904         if ( withNodes )
00905         {
00906             if ( qFuzzyCompare( path.last().x(), p[i+1].x() ) )
00907                 path.last() = p[i+1];
00908             else
00909                 path += p[i+1];
00910 
00911             t = distance;
00912         }
00913         else
00914         {
00915             t -= l;
00916         }
00917     }
00918 
00919     if ( ( boundaryType() == QwtSpline::ClosedPolygon )
00920         && ( controlLines.size() >= n ) )
00921     {
00922         const double l = param->valueIncrement( p[n-1], p[0] );
00923 
00924         while ( t < l )
00925         {
00926             path += QwtBezier::pointAt( p[n-1], cl[n-1].p1(),
00927                 cl[n-1].p2(), p[0], t / l );
00928 
00929             t += distance;
00930         }
00931 
00932         if ( qFuzzyCompare( path.last().x(), p[0].x() ) )
00933             path.last() = p[0];
00934         else 
00935             path += p[0];
00936     }
00937 
00938     return path;
00939 }
00940 
00942 QwtSplineG1::QwtSplineG1()
00943 {
00944 }
00945 
00947 QwtSplineG1::~QwtSplineG1()
00948 {
00949 }
00950 
00960 QwtSplineC1::QwtSplineC1()
00961 {
00962     setParametrization( QwtSplineParametrization::ParameterX );
00963 }
00964 
00966 QwtSplineC1::~QwtSplineC1()
00967 {
00968 }
00969 
00977 double QwtSplineC1::slopeAtBeginning( const QPolygonF &points, double slopeNext ) const
00978 {
00979     if ( points.size() < 2 )
00980         return 0.0;
00981 
00982     return QwtSplineC1P::slopeBoundary(
00983         boundaryCondition( QwtSpline::AtBeginning ),
00984         boundaryValue( QwtSpline::AtBeginning ),
00985         points[0], points[1], slopeNext );
00986 }
00987 
00995 double QwtSplineC1::slopeAtEnd( const QPolygonF &points, double slopeBefore ) const
00996 {
00997     const int n = points.size();
00998     
00999     const QPointF p1( points[n-1].x(), -points[n-1].y() );
01000     const QPointF p2( points[n-2].x(), -points[n-2].y() );
01001     
01002     const int condition = boundaryCondition( QwtSpline::AtEnd );
01003         
01004     double value = boundaryValue( QwtSpline::AtEnd );
01005     if ( condition != QwtSpline::LinearRunout )
01006     {
01007         // beside LinearRunout the boundaryValue is a slope or curvature
01008         // and needs to be inverted too
01009         value = -value;
01010     }   
01011     
01012     const double slope = QwtSplineC1P::slopeBoundary( condition, value, p1, p2, -slopeBefore );
01013     return -slope;
01014 }
01015 
01041 QPainterPath QwtSplineC1::painterPath( const QPolygonF &points ) const
01042 {
01043     const int n = points.size();
01044     if ( n <= 2 )
01045         return QwtSplineInterpolating::painterPath( points );
01046 
01047     using namespace QwtSplineC1P;
01048 
01049     PathStore store;
01050     switch( parametrization()->type() )
01051     {
01052         case QwtSplineParametrization::ParameterX:
01053         {
01054             store = qwtSplineC1PathParamX<PathStore>( this, points );
01055             break;
01056         }
01057         case QwtSplineParametrization::ParameterY:
01058         {
01059             store = qwtSplineC1PathParamY<PathStore>( this, points );
01060             break;
01061         }
01062         case QwtSplineParametrization::ParameterUniform:
01063         {
01064             store = qwtSplineC1PathParametric<PathStore>(
01065                 this, points, paramUniform() );
01066             break;
01067         }
01068         case QwtSplineParametrization::ParameterCentripetal:
01069         {
01070             store = qwtSplineC1PathParametric<PathStore>(
01071                 this, points, paramCentripetal() );
01072             break;
01073         }
01074         case QwtSplineParametrization::ParameterChordal:
01075         {
01076             store = qwtSplineC1PathParametric<PathStore>(
01077                 this, points, paramChordal() );
01078             break;
01079         }
01080         default:
01081         {
01082             store = qwtSplineC1PathParametric<PathStore>(
01083                 this, points, param( parametrization() ) );
01084         }
01085     }
01086 
01087     return store.path;
01088 }
01089 
01099 QVector<QLineF> QwtSplineC1::bezierControlLines( const QPolygonF &points ) const
01100 {
01101     using namespace QwtSplineC1P;
01102 
01103     const int n = points.size();
01104     if ( n <= 2 )
01105         return QVector<QLineF>();
01106 
01107     ControlPointsStore store;
01108     switch( parametrization()->type() )
01109     {
01110         case QwtSplineParametrization::ParameterX:
01111         {
01112             store = qwtSplineC1PathParamX<ControlPointsStore>( this, points );
01113             break;
01114         }
01115         case QwtSplineParametrization::ParameterY:
01116         {
01117             store = qwtSplineC1PathParamY<ControlPointsStore>( this, points );
01118             break;
01119         }
01120         case QwtSplineParametrization::ParameterUniform:
01121         {
01122             store = qwtSplineC1PathParametric<ControlPointsStore>(
01123                 this, points, paramUniform() );
01124             break;
01125         }
01126         case QwtSplineParametrization::ParameterCentripetal:
01127         {
01128             store = qwtSplineC1PathParametric<ControlPointsStore>(
01129                 this, points, paramCentripetal() );
01130             break;
01131         }
01132         case QwtSplineParametrization::ParameterChordal:
01133         {
01134             store = qwtSplineC1PathParametric<ControlPointsStore>(
01135                 this, points, paramChordal() );
01136             break;
01137         }
01138         default:
01139         {
01140             store = qwtSplineC1PathParametric<ControlPointsStore>(
01141                 this, points, param( parametrization() ) );
01142         }
01143     }
01144 
01145     return store.controlPoints;
01146 }
01147 
01165 QPolygonF QwtSplineC1::equidistantPolygon( const QPolygonF &points,
01166     double distance, bool withNodes ) const
01167 {
01168     if ( parametrization()->type() == QwtSplineParametrization::ParameterX )
01169     {
01170         if ( points.size() > 2 )
01171         {
01172             const QVector<double> m = slopes( points );
01173             if ( m.size() != points.size() )
01174                 return QPolygonF();
01175 
01176             return qwtPolygonParametric<QwtSplinePolynomial::fromSlopes>(
01177                 distance, points, m, withNodes );
01178         }
01179     }
01180 
01181     return QwtSplineInterpolating::equidistantPolygon( points, distance, withNodes );
01182 }
01183 
01199 QVector<QwtSplinePolynomial> QwtSplineC1::polynomials(
01200     const QPolygonF &points ) const
01201 {
01202     QVector<QwtSplinePolynomial> polynomials;
01203 
01204     const QVector<double> m = slopes( points );
01205     if ( m.size() < 2 )
01206         return polynomials;
01207 
01208     for ( int i = 1; i < m.size(); i++ )
01209     {
01210         polynomials += QwtSplinePolynomial::fromSlopes( 
01211             points[i-1], m[i-1], points[i], m[i] );
01212     }
01213 
01214     return polynomials;
01215 }
01216 
01225 QwtSplineC2::QwtSplineC2()
01226 {
01227 }
01228 
01230 QwtSplineC2::~QwtSplineC2()
01231 {
01232 }
01233 
01246 QPainterPath QwtSplineC2::painterPath( const QPolygonF &points ) const
01247 {
01248     // could be implemented from curvatures without the extra
01249     // loop for calculating the slopes vector. TODO ...
01250 
01251     return QwtSplineC1::painterPath( points );
01252 }
01253 
01267 QVector<QLineF> QwtSplineC2::bezierControlLines( const QPolygonF &points ) const
01268 {
01269     // could be implemented from curvatures without the extra
01270     // loop for calculating the slopes vector. TODO ...
01271 
01272     return QwtSplineC1::bezierControlLines( points );
01273 }
01274 
01292 QPolygonF QwtSplineC2::equidistantPolygon( const QPolygonF &points,
01293     double distance, bool withNodes ) const
01294 {
01295     if ( parametrization()->type() == QwtSplineParametrization::ParameterX )
01296     {
01297         if ( points.size() > 2 )
01298         {
01299             const QVector<double> cv = curvatures( points );
01300             if ( cv.size() != points.size() )
01301                 return QPolygonF();
01302 
01303             return qwtPolygonParametric<QwtSplinePolynomial::fromCurvatures>( 
01304                 distance, points, cv, withNodes );
01305         }
01306     }
01307 
01308     return QwtSplineInterpolating::equidistantPolygon( points, distance, withNodes );
01309 }
01310 
01336 QVector<double> QwtSplineC2::slopes( const QPolygonF &points ) const
01337 {
01338     const QVector<double> curvatures = this->curvatures( points );
01339     if ( curvatures.size() < 2 )
01340         return QVector<double>();
01341     
01342     QVector<double> slopes( curvatures.size() );
01343 
01344     const double *cv = curvatures.constData();
01345     double *m = slopes.data();
01346 
01347     const int n = points.size();
01348     const QPointF *p = points.constData();
01349 
01350     QwtSplinePolynomial polynomial;
01351 
01352     for ( int i = 0; i < n - 1; i++ )
01353     {
01354         polynomial = QwtSplinePolynomial::fromCurvatures( p[i], cv[i], p[i+1], cv[i+1] );
01355         m[i] = polynomial.c1;
01356     }
01357 
01358     m[n-1] = polynomial.slopeAt( p[n-1].x() - p[n-2].x() );
01359 
01360     return slopes;
01361 }
01362 
01378 QVector<QwtSplinePolynomial> QwtSplineC2::polynomials( const QPolygonF &points ) const
01379 {
01380     QVector<QwtSplinePolynomial> polynomials;
01381     
01382     const QVector<double> curvatures = this->curvatures( points );
01383     if ( curvatures.size() < 2 )
01384         return polynomials;
01385 
01386     const QPointF *p = points.constData();
01387     const double *cv = curvatures.constData();
01388     const int n = curvatures.size();
01389     
01390     for ( int i = 1; i < n; i++ )
01391     {   
01392         polynomials += QwtSplinePolynomial::fromCurvatures(
01393             p[i-1], cv[i-1], p[i], cv[i] );
01394     }
01395     
01396     return polynomials;
01397 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56