10 #include "qwt_spline.h" 
   11 #include "qwt_spline_parametrization.h" 
   12 #include "qwt_spline_polynomial.h" 
   13 #include "qwt_bezier.h" 
   15 #include <qpainterpath.h> 
   17 namespace QwtSplineC1P
 
   26         inline double operator()( 
const QPointF& p1, 
const QPointF& p2 )
 const 
   28             return parameter->valueIncrement( p1, p2 );
 
   36         inline double operator()( 
const QPointF& p1, 
const QPointF& p2 )
 const 
   44         inline double operator()( 
const QPointF& p1, 
const QPointF& p2 )
 const 
   50     struct paramCentripetal
 
   52         inline double operator()( 
const QPointF& p1, 
const QPointF& p2 )
 const 
   60         inline double operator()( 
const QPointF& p1, 
const QPointF& p2 )
 const 
   68         inline double operator()( 
const QPointF& p1, 
const QPointF& p2 )
 const 
   77         inline void init( 
int size )
 
   82         inline void start( 
double x1, 
double y1 )
 
   84             path.moveTo( x1, y1 );
 
   87         inline void addCubic( 
double cx1, 
double cy1,
 
   88             double cx2, 
double cy2, 
double x2, 
double y2 )
 
   90             path.cubicTo( cx1, cy1, cx2, cy2, x2, y2 );
 
  101     class ControlPointsStore
 
  104         inline ControlPointsStore():
 
  109         inline void init( 
int size )
 
  111             controlPoints.resize( size );
 
  112             m_cp = controlPoints.data();
 
  115         inline void start( 
double x1, 
double y1 )
 
  121         inline void addCubic( 
double cx1, 
double cy1,
 
  122             double cx2, 
double cy2, 
double x2, 
double y2 )
 
  128             l.setLine( cx1, cy1, cx2, cy2 );
 
  141     double slopeBoundary( 
int boundaryCondition, 
double boundaryValue,
 
  142         const QPointF& p1, 
const QPointF& p2, 
double slope1 )
 
  144         const double dx = p2.x() - p1.x();
 
  145         const double dy = p2.y() - p1.y();
 
  149         switch( boundaryCondition )
 
  158                 const double c2 = 0.5 * boundaryValue;
 
  159                 const double c1 = slope1;
 
  161                 m = 0.5 * ( 3.0 * dy / dx - c1 - c2 * dx );
 
  166                 const double c3 = boundaryValue / 6.0;
 
  167                 m = c3 * dx * dx + 2 * dy / dx - slope1;
 
  172                 const double s = dy / dx;
 
  173                 const double r = qBound( 0.0, boundaryValue, 1.0 );
 
  175                 m = s - r * ( s - slope1 );
 
  188 template< 
class SplineStore >
 
  189 static inline SplineStore qwtSplineC1PathParamX(
 
  190     const QwtSplineC1* spline, 
const QPolygonF& points )
 
  192     const int n = points.size();
 
  196         return SplineStore();
 
  198     const QPointF* pd = points.constData();
 
  199     const double* md = m.constData();
 
  202     store.init( m.size() - 1 );
 
  203     store.start( pd[0].x(), pd[0].y() );
 
  205     for ( 
int i = 0; i < n - 1; i++ )
 
  207         const double dx3 = ( pd[i + 1].x() - pd[i].x() ) / 3.0;
 
  209         store.addCubic( pd[i].x() + dx3, pd[i].y() + md[i] * dx3,
 
  210             pd[i + 1].x() - dx3, pd[i + 1].y() - md[i + 1] * dx3,
 
  211             pd[i + 1].x(), pd[i + 1].y() );
 
  217 template< 
class SplineStore >
 
  218 static inline SplineStore qwtSplineC1PathParamY(
 
  219     const QwtSplineC1* spline, 
const QPolygonF& points )
 
  221     const int n = points.size();
 
  223     QPolygonF pointsFlipped( n );
 
  224     for ( 
int i = 0; i < n; i++ )
 
  226         pointsFlipped[i].setX( points[i].y() );
 
  227         pointsFlipped[i].setY( points[i].x() );
 
  232         return SplineStore();
 
  234     const QPointF* pd = pointsFlipped.constData();
 
  235     const double* md = m.constData();
 
  238     store.init( m.size() - 1 );
 
  239     store.start( pd[0].y(), pd[0].x() );
 
  242     for ( 
int i = 0; i < n - 1; i++ )
 
  244         const double dx3 = ( pd[i + 1].x() - pd[i].x() ) / 3.0;
 
  246         store.addCubic( pd[i].y() + md[i] * dx3, pd[i].x() + dx3,
 
  247             pd[i + 1].y() - md[i + 1] * dx3, pd[i + 1].x() - dx3,
 
  248             pd[i + 1].y(), pd[i + 1].x() );
 
  254 template< 
class SplineStore, 
class Param >
 
  255 static inline SplineStore qwtSplineC1PathParametric(
 
  256     const QwtSplineC1* spline, 
const QPolygonF& points, Param param )
 
  259     const int n = points.size();
 
  261     QPolygonF pointsX, pointsY;
 
  262     pointsX.resize( isClosing ? n + 1 : n );
 
  263     pointsY.resize( isClosing ? n + 1 : n );
 
  265     QPointF* px = pointsX.data();
 
  266     QPointF* py = pointsY.data();
 
  267     const QPointF* p = points.constData();
 
  271     px[0].rx() = py[0].rx() = t;
 
  272     px[0].ry() = p[0].x();
 
  273     py[0].ry() = p[0].y();
 
  275     int numParamPoints = 1;
 
  276     for ( 
int i = 1; i < n; i++ )
 
  278         const double td = param( points[i - 1], points[i] );
 
  283             px[numParamPoints].rx() = py[numParamPoints].rx() = t;
 
  285             px[numParamPoints].ry() = p[i].x();
 
  286             py[numParamPoints].ry() = p[i].y();
 
  294         const double td = param( points[n - 1], points[0] );
 
  300             px[numParamPoints].rx() = py[numParamPoints].rx() = t;
 
  302             px[numParamPoints].ry() = p[0].x();
 
  303             py[numParamPoints].ry() = p[0].y();
 
  309     if ( pointsX.size() != numParamPoints )
 
  311         pointsX.resize( numParamPoints );
 
  312         pointsY.resize( numParamPoints );
 
  318     const double* mx = slopesX.constData();
 
  319     const double* my = slopesY.constData();
 
  326     store.init( isClosing ? n : n - 1 );
 
  327     store.start( points[0].x(), points[0].y() );
 
  331     for ( 
int i = 0; i < n - 1; i++ )
 
  333         const QPointF& p1 = p[i];
 
  334         const QPointF& p2 = p[i + 1];
 
  336         const double td = param( p1, p2 );
 
  340             const double t3 = td / 3.0;
 
  342             const double cx1 = p1.x() + mx[j] * t3;
 
  343             const double cy1 = p1.y() + my[j] * t3;
 
  345             const double cx2 = p2.x() - mx[j + 1] * t3;
 
  346             const double cy2 = p2.y() - my[j + 1] * t3;
 
  348             store.addCubic( cx1, cy1, cx2, cy2, p2.x(), p2.y() );
 
  355             store.addCubic( p1.x(), p1.y(), p2.x(), p2.y(), p2.x(), p2.y() );
 
  361         const QPointF& p1 = p[n - 1];
 
  362         const QPointF& p2 = p[0];
 
  364         const double td = param( p1, p2 );
 
  368             const double t3 = td / 3.0;
 
  370             const double cx1 = p1.x() + mx[j] * t3;
 
  371             const double cy1 = p1.y() + my[j] * t3;
 
  373             const double cx2 = p2.x() - mx[0] * t3;
 
  374             const double cy2 = p2.y() - my[0] * t3;
 
  376             store.addCubic( cx1, cy1, cx2, cy2, p2.x(), p2.y() );
 
  380             store.addCubic( p1.x(), p1.y(), p2.x(), p2.y(), p2.x(), p2.y() );
 
  389 template< QwtSplinePolynomial toPolynomial( const QPo
intF&, 
double, const QPo
intF&, 
double ) >
 
  390 static QPolygonF qwtPolygonParametric( 
double distance,
 
  393     QPolygonF fittedPoints;
 
  395     const QPointF* p = points.constData();
 
  396     const double* v = values.constData();
 
  398     fittedPoints += p[0];
 
  401     const int n = points.size();
 
  403     for ( 
int i = 0; i < n - 1; i++ )
 
  405         const QPointF& p1 = p[i];
 
  406         const QPointF& p2 = p[i + 1];
 
  410         const double l = p2.x() - p1.x();
 
  414             fittedPoints += QPointF( p1.x() + t, p1.y() + polynomial.
valueAt( t ) );
 
  420             if ( qFuzzyCompare( fittedPoints.last().x(), p2.x() ) )
 
  421                 fittedPoints.last() = p2;
 
  434 class QwtSpline::PrivateData
 
  446         boundaryConditions[0].value = 0.0;
 
  449         boundaryConditions[1].value = 0.0;
 
  465     } boundaryConditions[2];
 
  498     if ( tolerance <= 0.0 )
 
  502     const int n = path.elementCount();
 
  506     const QPainterPath::Element el = path.elementAt( 0 );
 
  507     if ( el.type != QPainterPath::MoveToElement )
 
  510     QPointF p1( el.x, el.y );
 
  515     for ( 
int i = 1; i < n; i += 3 )
 
  517         const QPainterPath::Element el1 = path.elementAt( i );
 
  518         const QPainterPath::Element el2 = path.elementAt( i + 1 );
 
  519         const QPainterPath::Element el3 = path.elementAt( i + 2 );
 
  521         const QPointF cp1( el1.x, el1.y );
 
  522         const QPointF cp2( el2.x, el2.y );
 
  523         const QPointF p2( el3.x, el3.y );
 
  542     m_data = 
new PrivateData;
 
  578     if ( m_data->parametrization->type() != type )
 
  580         delete m_data->parametrization;
 
  596         delete m_data->parametrization;
 
  607     return m_data->parametrization;
 
  628     return m_data->boundaryType;
 
  642         m_data->boundaryConditions[position].type = condition;
 
  654         return m_data->boundaryConditions[position].type;
 
  656     return m_data->boundaryConditions[0].type; 
 
  673         m_data->boundaryConditions[position].value = value;
 
  685         return m_data->boundaryConditions[position].value;
 
  687     return m_data->boundaryConditions[0].value; 
 
  701     int condition, 
double valueBegin, 
double valueEnd )
 
  750     const int n = points.size();
 
  758         path.moveTo( points[0] );
 
  764         path.addPolygon( points );
 
  769     if ( controlLines.size() < n - 1 )
 
  772     const QPointF* p = points.constData();
 
  773     const QLineF* l = controlLines.constData();
 
  776     for ( 
int i = 0; i < n - 1; i++ )
 
  777         path.cubicTo( l[i].p1(), l[i].p2(), p[i + 1] );
 
  780         && ( controlLines.size() >= n ) )
 
  782         path.cubicTo( l[n - 1].p1(), l[n - 1].p2(), p[0] );
 
  806     const QPolygonF& points, 
double tolerance )
 const 
  808     if ( tolerance <= 0.0 )
 
  812     if ( controlLines.isEmpty() )
 
  819     const QPointF* p = points.constData();
 
  820     const QLineF* cl = controlLines.constData();
 
  822     const int n = controlLines.size();
 
  826     for ( 
int i = 0; i < n - 1; i++ )
 
  828         const QLineF& l = cl[i];
 
  832     const QPointF& pn = isClosed ? p[0] : p[n];
 
  833     const QLineF& l = cl[n - 1];
 
  864     double distance, 
bool withNodes )
 const 
  866     if ( distance <= 0.0 )
 
  869     const int n = points.size();
 
  883     if ( controlLines.size() < n - 1 )
 
  886     path += points.first();
 
  889     const QPointF* p = points.constData();
 
  890     const QLineF* cl = controlLines.constData();
 
  894     for ( 
int i = 0; i < n - 1; i++ )
 
  901                 cl[i].p2(), p[i + 1], t / l );
 
  908             if ( qFuzzyCompare( path.last().x(), p[i + 1].x() ) )
 
  909                 path.last() = p[i + 1];
 
  922         && ( controlLines.size() >= n ) )
 
  929                 cl[n - 1].p2(), p[0], t / l );
 
  934         if ( qFuzzyCompare( path.last().x(), p[0].x() ) )
 
  981     if ( points.size() < 2 )
 
  984     return QwtSplineC1P::slopeBoundary(
 
  987         points[0], points[1], slopeNext );
 
  999     const int n = points.size();
 
 1001     const QPointF p1( points[n - 1].x(), -points[n - 1].y() );
 
 1002     const QPointF p2( points[n - 2].x(), -points[n - 2].y() );
 
 1014     const double slope = QwtSplineC1P::slopeBoundary( condition, value, p1, p2, -slopeBefore );
 
 1045     const int n = points.size();
 
 1049     using namespace QwtSplineC1P;
 
 1056             store = qwtSplineC1PathParamX< PathStore >( 
this, points );
 
 1061             store = qwtSplineC1PathParamY< PathStore >( 
this, points );
 
 1066             store = qwtSplineC1PathParametric< PathStore >(
 
 1067                 this, points, paramUniform() );
 
 1072             store = qwtSplineC1PathParametric< PathStore >(
 
 1073                 this, points, paramCentripetal() );
 
 1078             store = qwtSplineC1PathParametric< PathStore >(
 
 1079                 this, points, paramChordal() );
 
 1084             store = qwtSplineC1PathParametric< PathStore >(
 
 1103     using namespace QwtSplineC1P;
 
 1105     const int n = points.size();
 
 1109     ControlPointsStore store;
 
 1114             store = qwtSplineC1PathParamX< ControlPointsStore >( 
this, points );
 
 1119             store = qwtSplineC1PathParamY< ControlPointsStore >( 
this, points );
 
 1124             store = qwtSplineC1PathParametric< ControlPointsStore >(
 
 1125                 this, points, paramUniform() );
 
 1130             store = qwtSplineC1PathParametric< ControlPointsStore >(
 
 1131                 this, points, paramCentripetal() );
 
 1136             store = qwtSplineC1PathParametric< ControlPointsStore >(
 
 1137                 this, points, paramChordal() );
 
 1142             store = qwtSplineC1PathParametric< ControlPointsStore >(
 
 1147     return store.controlPoints;
 
 1168     double distance, 
bool withNodes )
 const 
 1172         if ( points.size() > 2 )
 
 1175             if ( m.size() != points.size() )
 
 1178             return qwtPolygonParametric< QwtSplinePolynomial::fromSlopes >(
 
 1179                 distance, points, m, withNodes );
 
 1202     const QPolygonF& points )
 const 
 1211     for ( 
int i = 1; i < m.size(); i++ )
 
 1214             points[i - 1], m[i - 1], points[i], m[i] );
 
 1296     double distance, 
bool withNodes )
 const 
 1300         if ( points.size() > 2 )
 
 1303             if ( cv.size() != points.size() )
 
 1306             return qwtPolygonParametric< QwtSplinePolynomial::fromCurvatures >(
 
 1307                 distance, points, cv, withNodes );
 
 1342     if ( curvatures.size() < 2 )
 
 1347     const double* cv = curvatures.constData();
 
 1348     double* m = 
slopes.data();
 
 1350     const int n = points.size();
 
 1351     const QPointF* p = points.constData();
 
 1355     for ( 
int i = 0; i < n - 1; i++ )
 
 1358         m[i] = polynomial.
c1;
 
 1361     m[n - 1] = polynomial.
slopeAt( p[n - 1].x() - p[n - 2].x() );
 
 1386     if ( curvatures.size() < 2 )
 
 1389     const QPointF* p = points.constData();
 
 1390     const double* cv = curvatures.constData();
 
 1391     const int n = curvatures.size();
 
 1394     for ( 
int i = 1; i < n; i++ )
 
 1397             p[i - 1], cv[i - 1], p[i], cv[i] );
 
An implementation of the de Casteljau’s Algorithm for interpolating Bézier curves.
void appendToPolygon(const QPointF &p1, const QPointF &cp1, const QPointF &cp2, const QPointF &p2, QPolygonF &polygon) const
Interpolate a Bézier curve by a polygon.
static QPointF pointAt(const QPointF &p1, const QPointF &cp1, const QPointF &cp2, const QPointF &p2, double t)
Base class for spline interpolations providing a first order parametric continuity ( C1 ) between adj...
virtual QVector< double > slopes(const QPolygonF &) const =0
Find the first derivative at the control points.
virtual ~QwtSplineC1()
Destructor.
QwtSplineC1()
Constructor.
virtual double slopeAtBeginning(const QPolygonF &, double slopeNext) const
virtual QPainterPath painterPath(const QPolygonF &) const override
Calculate an interpolated painter path.
virtual QPolygonF equidistantPolygon(const QPolygonF &, double distance, bool withNodes) const override
Find an interpolated polygon with "equidistant" points.
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
virtual double slopeAtEnd(const QPolygonF &, double slopeBefore) const
virtual QVector< QwtSplinePolynomial > polynomials(const QPolygonF &) const
Calculate the interpolating polynomials for a non parametric spline.
virtual QPolygonF equidistantPolygon(const QPolygonF &, double distance, bool withNodes) const override
Find an interpolated polygon with "equidistant" points.
virtual QVector< double > slopes(const QPolygonF &) const override
Find the first derivative at the control points.
QwtSplineC2()
Constructor.
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.
virtual ~QwtSplineC2()
Destructor.
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
virtual ~QwtSplineG1()
Destructor.
QwtSplineG1()
Constructor.
Base class for all splines.
@ AtBeginning
the condition is at the beginning of the polynomial
@ AtEnd
the condition is at the end of the polynomial
virtual QPainterPath painterPath(const QPolygonF &) const =0
double boundaryValue(BoundaryPosition) const
void setBoundaryType(BoundaryType)
void setBoundaryCondition(BoundaryPosition, int condition)
Define the condition for an endpoint of the spline.
const QwtSplineParametrization * parametrization() const
int boundaryCondition(BoundaryPosition) const
BoundaryType boundaryType() const
virtual uint locality() const
virtual ~QwtSpline()
Destructor.
virtual QPolygonF polygon(const QPolygonF &, double tolerance) const
Interpolate a curve by a polygon.
void setBoundaryConditions(int condition, double valueBegin=0.0, double valueEnd=0.0)
Define the condition at the endpoints of a spline.
void setBoundaryValue(BoundaryPosition, double value)
Define the boundary value.
void setParametrization(int type)
virtual ~QwtSplineInterpolating()
Destructor.
virtual QPolygonF equidistantPolygon(const QPolygonF &, double distance, bool withNodes) const
Find an interpolated polygon with "equidistant" points.
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const =0
Interpolate a curve with Bezier curves.
QwtSplineInterpolating()
Constructor.
virtual QPolygonF polygon(const QPolygonF &, double tolerance) const override
Interpolate a curve by a polygon.
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
Curve parametrization used for a spline interpolation.
static double valueIncrementChordal(const QPointF &, const QPointF &)
Calculate the ParameterChordal value increment for 2 points.
static double valueIncrementCentripetal(const QPointF &, const QPointF &)
Calculate the ParameterCentripetal value increment for 2 points.
static double valueIncrementUniform(const QPointF &, const QPointF &)
Calculate the ParameterUniform value increment.
virtual double valueIncrement(const QPointF &, const QPointF &) const
Calculate the parameter value increment for 2 points.
static double valueIncrementManhattan(const QPointF &, const QPointF &)
Calculate the ParameterManhattan value increment for 2 points.
static double valueIncrementY(const QPointF &, const QPointF &)
Calculate the ParameterY value increment for 2 points.
A cubic polynomial without constant term.
double slopeAt(double x) const
static QwtSplinePolynomial fromSlopes(const QPointF &p1, double m1, const QPointF &p2, double m2)
double valueAt(double x) const
static QwtSplinePolynomial fromCurvatures(const QPointF &p1, double cv1, const QPointF &p2, double cv2)
double c1
coefficient of the linear summand