qwt_spline_pleasing.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_pleasing.h"
00011 #include "qwt_spline_parametrization.h"
00012 
00013 static inline double qwtChordalLength( const QPointF &point1, const QPointF &point2 )
00014 {
00015     const double dx = point2.x() - point1.x();
00016     const double dy = point2.y() - point1.y();
00017 
00018     return qSqrt( dx * dx + dy * dy );
00019 }
00020 
00021 template< class Param >
00022 static QPointF qwtVector( Param param,
00023     const QPointF &p1, const QPointF &p2 )
00024 {
00025     return ( p2 - p1 ) / param( p1, p2 );
00026 }
00027 
00028 template< class Param >
00029 static QPointF qwtVectorCardinal( Param param,
00030     const QPointF &p1, const QPointF &p2, const QPointF &p3 )
00031 {
00032     const double t1 = param( p1, p2 );
00033     const double t2 = param( p2, p3 );
00034 
00035     return t2 * ( p3 - p1 ) / ( t1 + t2 );
00036 }
00037 
00038 namespace QwtSplinePleasingP
00039 {
00040     struct Tension
00041     {
00042         double t1;
00043         double t2;
00044     };
00045 
00046     struct param
00047     {
00048         param( const QwtSplineParametrization *p ):
00049             parameter( p )
00050         {
00051         }
00052 
00053         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00054         {
00055             return parameter->valueIncrement( p1, p2 );
00056         }
00057 
00058         const QwtSplineParametrization *parameter;
00059     };
00060 
00061     struct paramUniform
00062     {
00063         inline double operator()( const QPointF &p1, const QPointF &p2 ) const
00064         {
00065             return QwtSplineParametrization::valueIncrementUniform( p1, p2 );
00066         }
00067     };
00068 
00069     class PathStore
00070     {
00071     public:
00072         inline void init( int )
00073         {
00074         }
00075 
00076         inline void start( const QPointF &p0 )
00077         {
00078             path.moveTo( p0 );
00079         }
00080 
00081         inline void addCubic( const QPointF &cp1,
00082             const QPointF &cp2, const QPointF &p2 )
00083         {
00084             path.cubicTo( cp1, cp2, p2 );
00085         }
00086 
00087         QPainterPath path;
00088     };
00089 
00090     class ControlPointsStore
00091     {
00092     public:
00093         inline ControlPointsStore():
00094             d_cp( NULL )
00095         {
00096         }
00097 
00098         inline void init( int size )
00099         {
00100             controlPoints.resize( size );
00101             d_cp = controlPoints.data();
00102         }
00103 
00104         inline void start( const QPointF & )
00105         {
00106         }
00107 
00108         inline void addCubic( const QPointF &cp1,
00109             const QPointF &cp2, const QPointF & )
00110         {
00111             QLineF &l = *d_cp++;
00112             l.setPoints( cp1, cp2 );
00113         }
00114 
00115         QVector<QLineF> controlPoints;
00116 
00117     private:
00118         QLineF* d_cp;
00119     };
00120 }
00121 
00122 static inline QwtSplinePleasingP::Tension qwtTensionPleasing(
00123     double d13, double d23, double d24,
00124     const QPointF &p1, const QPointF &p2,
00125     const QPointF &p3, const QPointF &p4 )
00126 {
00127     QwtSplinePleasingP::Tension tension;
00128 
00129     const bool b1 = ( d13 / 3.0 ) < d23;
00130     const bool b2 = ( d24 / 3.0 ) < d23;
00131 
00132     if ( b1 )
00133     {
00134         if ( b2 )
00135         {
00136             tension.t1 = ( p1 != p2 ) ? ( 1.0 / 3.0 ) : ( 2.0 / 3.0 );
00137             tension.t2 = ( p3 != p4 ) ? ( 1.0 / 3.0 ) : ( 2.0 / 3.0 );
00138         }
00139         else
00140         {
00141             tension.t1 = tension.t2 = d23 / d24;
00142         }
00143     }
00144     else
00145     {
00146         if ( b2 )
00147         {
00148             tension.t1 = tension.t2 = d23 / d13;
00149         }
00150         else
00151         {
00152             tension.t1 = d23 / d13;
00153             tension.t2 = d23 / d24;
00154         }
00155     }
00156 
00157     return tension;
00158 }
00159 
00160 template< class SplineStore, class Param >
00161 static SplineStore qwtSplinePathPleasing( const QPolygonF &points, 
00162     bool isClosed, Param param )
00163 {
00164     using namespace QwtSplinePleasingP;
00165 
00166     const int size = points.size();
00167 
00168     const QPointF *p = points.constData();
00169 
00170     SplineStore store;
00171     store.init( isClosed ? size : size - 1 );
00172     store.start( p[0] );
00173 
00174     double d13;
00175     QPointF vec1;
00176 
00177     if ( isClosed )
00178     {
00179         d13 = qwtChordalLength(p[0], p[2]);
00180 
00181         const Tension t0 = qwtTensionPleasing( 
00182             qwtChordalLength( p[size-1], p[1]), qwtChordalLength(p[0], p[1]),
00183             d13, p[size-1], p[0], p[1], p[2] );
00184 
00185         const QPointF vec0 = qwtVectorCardinal<Param>( param, p[size-1], p[0], p[1] );
00186         vec1 = qwtVectorCardinal<Param>( param, p[0], p[1], p[2] );
00187 
00188         store.addCubic( p[0] + vec0 * t0.t1, p[1] - vec1 * t0.t2, p[1] );
00189     }
00190     else
00191     {
00192         d13 = qwtChordalLength(p[0], p[2]);
00193 
00194         const Tension t0 = qwtTensionPleasing( 
00195             qwtChordalLength( p[0], p[1]), qwtChordalLength(p[0], p[1]),
00196             d13,  p[0], p[0], p[1], p[2] );
00197 
00198         const QPointF vec0 = 0.5 * qwtVector<Param>( param, p[0], p[1] );
00199         vec1 = qwtVectorCardinal<Param>( param, p[0], p[1], p[2] );
00200 
00201         store.addCubic( p[0] + vec0 * t0.t1, p[1] - vec1 * t0.t2, p[1] );
00202     }
00203 
00204     for ( int i = 1; i < size - 2; i++ )
00205     {
00206         const double d23 = qwtChordalLength( p[i], p[i+1] );
00207         const double d24 = qwtChordalLength( p[i], p[i+2] );
00208 
00209         const QPointF vec2 = qwtVectorCardinal<Param>( param, p[i], p[i+1], p[i+2] );
00210 
00211         const Tension t = qwtTensionPleasing( 
00212             d13, d23, d24, p[i-1], p[i], p[i+1], p[i+2] );
00213 
00214         store.addCubic( p[i] + vec1 * t.t1, p[i+1] - vec2 * t.t2, p[i+1] );
00215 
00216         d13 = d24;
00217         vec1 = vec2;
00218     }
00219 
00220     if ( isClosed )
00221     {
00222         const double d24 = qwtChordalLength( p[size-2], p[0] );
00223 
00224         const Tension tn = qwtTensionPleasing( 
00225             d13, qwtChordalLength( p[size-2], p[size-1] ), d24, 
00226             p[size-3], p[size-2], p[size-1], p[0] );
00227 
00228         const QPointF vec2 = qwtVectorCardinal<Param>( param, p[size-2], p[size-1], p[0] );
00229         store.addCubic( p[size-2] + vec1 * tn.t1, p[size-1] - vec2 * tn.t2, p[size-1] );
00230 
00231         const double d34 = qwtChordalLength( p[size-1], p[0] );
00232         const double d35 = qwtChordalLength( p[size-1], p[1] );
00233 
00234         const Tension tc = qwtTensionPleasing( d24, d34, d35, p[size-2], p[size-1], p[0], p[1] );
00235 
00236         const QPointF vec3 = qwtVectorCardinal<Param>( param, p[size-1], p[0], p[1] );
00237 
00238         store.addCubic( p[size-1] + vec2 * tc.t1, p[0] - vec3 * tc.t2, p[0] );
00239     }
00240     else
00241     {
00242         const double d24 = qwtChordalLength( p[size-2], p[size-1] );
00243 
00244         const Tension tn = qwtTensionPleasing( 
00245             d13, qwtChordalLength( p[size-2], p[size-1] ), d24, 
00246             p[size-3], p[size-2], p[size-1], p[size-1] );
00247 
00248         const QPointF vec2 = 0.5 * qwtVector<Param>( param, p[size-2], p[size-1] );
00249         store.addCubic( p[size-2] + vec1 * tn.t1, p[size-1] - vec2 * tn.t2, p[size-1] );
00250     }
00251 
00252     return store;
00253 }
00254 
00263 QwtSplinePleasing::QwtSplinePleasing()
00264 {
00265     setParametrization( QwtSplineParametrization::ParameterUniform );
00266 }
00267 
00269 QwtSplinePleasing::~QwtSplinePleasing()
00270 {
00271 }
00272 
00274 uint QwtSplinePleasing::locality() const
00275 {
00276     return 2;
00277 }
00278 
00288 QPainterPath QwtSplinePleasing::painterPath( const QPolygonF &points ) const
00289 {
00290     const int size = points.size();
00291     if ( size <= 2 )
00292         return QwtSplineG1::painterPath( points );
00293 
00294     const bool isClosing = ( boundaryType() == QwtSpline::ClosedPolygon );
00295 
00296     using namespace QwtSplinePleasingP;
00297 
00298     PathStore store;
00299     if ( parametrization()->type() == QwtSplineParametrization::ParameterUniform )
00300     {
00301         store = qwtSplinePathPleasing<PathStore>( points, 
00302             isClosing, paramUniform() );
00303     }
00304     else
00305     {
00306         store = qwtSplinePathPleasing<PathStore>( points, 
00307             isClosing, param( parametrization() ) );
00308     }
00309 
00310     if ( isClosing )
00311         store.path.closeSubpath();
00312 
00313     return store.path;
00314 }
00315 
00325 QVector<QLineF> QwtSplinePleasing::bezierControlLines( 
00326     const QPolygonF &points ) const
00327 {
00328     const int size = points.size();
00329     if ( size <= 2 )
00330         return QVector<QLineF>();
00331 
00332     const bool isClosing = ( boundaryType() == QwtSpline::ClosedPolygon );
00333 
00334     using namespace QwtSplinePleasingP;
00335 
00336     ControlPointsStore store;
00337     if ( parametrization()->type() == QwtSplineParametrization::ParameterUniform )
00338     {
00339         store = qwtSplinePathPleasing<ControlPointsStore>( points, 
00340             isClosing, paramUniform() );
00341     }
00342     else
00343     {
00344         store = qwtSplinePathPleasing<ControlPointsStore>( points, 
00345             isClosing, param( parametrization() ) );
00346     }
00347 
00348     return store.controlPoints;
00349 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Wed Jul 3 2019 19:28:05