Loading...
Searching...
No Matches
qwt_spline_pleasing.cpp
/******************************************************************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
#include "qwt_spline_pleasing.h"
#include "qwt_spline_parametrization.h"
#include <qpainterpath.h>
static inline double qwtChordalLength( const QPointF& point1, const QPointF& point2 )
{
const double dx = point2.x() - point1.x();
const double dy = point2.y() - point1.y();
return std::sqrt( dx * dx + dy * dy );
}
template< class Param >
static QPointF qwtVector( Param param,
const QPointF& p1, const QPointF& p2 )
{
return ( p2 - p1 ) / param( p1, p2 );
}
template< class Param >
static QPointF qwtVectorCardinal( Param param,
const QPointF& p1, const QPointF& p2, const QPointF& p3 )
{
const double t1 = param( p1, p2 );
const double t2 = param( p2, p3 );
return t2 * ( p3 - p1 ) / ( t1 + t2 );
}
namespace QwtSplinePleasingP
{
struct Tension
{
double t1;
double t2;
};
struct param
{
param( const QwtSplineParametrization* p ):
parameter( p )
{
}
inline double operator()( const QPointF& p1, const QPointF& p2 ) const
{
return parameter->valueIncrement( p1, p2 );
}
const QwtSplineParametrization* parameter;
};
struct paramUniform
{
inline double operator()( const QPointF& p1, const QPointF& p2 ) const
{
return QwtSplineParametrization::valueIncrementUniform( p1, p2 );
}
};
class PathStore
{
public:
inline void init( int )
{
}
inline void start( const QPointF& p0 )
{
path.moveTo( p0 );
}
inline void addCubic( const QPointF& cp1,
const QPointF& cp2, const QPointF& p2 )
{
path.cubicTo( cp1, cp2, p2 );
}
QPainterPath path;
};
class ControlPointsStore
{
public:
inline ControlPointsStore():
m_cp( NULL )
{
}
inline void init( int size )
{
controlPoints.resize( size );
m_cp = controlPoints.data();
}
inline void start( const QPointF& )
{
}
inline void addCubic( const QPointF& cp1,
const QPointF& cp2, const QPointF& )
{
QLineF& l = *m_cp++;
l.setPoints( cp1, cp2 );
}
QVector< QLineF > controlPoints;
private:
QLineF* m_cp;
};
}
static inline QwtSplinePleasingP::Tension qwtTensionPleasing(
double d13, double d23, double d24,
const QPointF& p1, const QPointF& p2,
const QPointF& p3, const QPointF& p4 )
{
QwtSplinePleasingP::Tension tension;
const bool b1 = ( d13 / 3.0 ) < d23;
const bool b2 = ( d24 / 3.0 ) < d23;
if ( b1 )
{
if ( b2 )
{
tension.t1 = ( p1 != p2 ) ? ( 1.0 / 3.0 ) : ( 2.0 / 3.0 );
tension.t2 = ( p3 != p4 ) ? ( 1.0 / 3.0 ) : ( 2.0 / 3.0 );
}
else
{
tension.t1 = tension.t2 = d23 / d24;
}
}
else
{
if ( b2 )
{
tension.t1 = tension.t2 = d23 / d13;
}
else
{
tension.t1 = d23 / d13;
tension.t2 = d23 / d24;
}
}
return tension;
}
template< class SplineStore, class Param >
static SplineStore qwtSplinePathPleasing( const QPolygonF& points,
bool isClosed, Param param )
{
using namespace QwtSplinePleasingP;
const int size = points.size();
const QPointF* p = points.constData();
SplineStore store;
store.init( isClosed ? size : size - 1 );
store.start( p[0] );
double d13;
QPointF vec1;
if ( isClosed )
{
d13 = qwtChordalLength(p[0], p[2]);
const Tension t0 = qwtTensionPleasing(
qwtChordalLength( p[size - 1], p[1]), qwtChordalLength(p[0], p[1]),
d13, p[size - 1], p[0], p[1], p[2] );
const QPointF vec0 = qwtVectorCardinal< Param >( param, p[size - 1], p[0], p[1] );
vec1 = qwtVectorCardinal< Param >( param, p[0], p[1], p[2] );
store.addCubic( p[0] + vec0 * t0.t1, p[1] - vec1 * t0.t2, p[1] );
}
else
{
d13 = qwtChordalLength(p[0], p[2]);
const Tension t0 = qwtTensionPleasing(
qwtChordalLength( p[0], p[1]), qwtChordalLength(p[0], p[1]),
d13, p[0], p[0], p[1], p[2] );
const QPointF vec0 = 0.5 * qwtVector< Param >( param, p[0], p[1] );
vec1 = qwtVectorCardinal< Param >( param, p[0], p[1], p[2] );
store.addCubic( p[0] + vec0 * t0.t1, p[1] - vec1 * t0.t2, p[1] );
}
for ( int i = 1; i < size - 2; i++ )
{
const double d23 = qwtChordalLength( p[i], p[i + 1] );
const double d24 = qwtChordalLength( p[i], p[i + 2] );
const QPointF vec2 = qwtVectorCardinal< Param >( param, p[i], p[i + 1], p[i + 2] );
const Tension t = qwtTensionPleasing(
d13, d23, d24, p[i - 1], p[i], p[i + 1], p[i + 2] );
store.addCubic( p[i] + vec1 * t.t1, p[i + 1] - vec2 * t.t2, p[i + 1] );
d13 = d24;
vec1 = vec2;
}
if ( isClosed )
{
const double d24 = qwtChordalLength( p[size - 2], p[0] );
const Tension tn = qwtTensionPleasing(
d13, qwtChordalLength( p[size - 2], p[size - 1] ), d24,
p[size - 3], p[size - 2], p[size - 1], p[0] );
const QPointF vec2 = qwtVectorCardinal< Param >( param, p[size - 2], p[size - 1], p[0] );
store.addCubic( p[size - 2] + vec1 * tn.t1, p[size - 1] - vec2 * tn.t2, p[size - 1] );
const double d34 = qwtChordalLength( p[size - 1], p[0] );
const double d35 = qwtChordalLength( p[size - 1], p[1] );
const Tension tc = qwtTensionPleasing( d24, d34, d35, p[size - 2], p[size - 1], p[0], p[1] );
const QPointF vec3 = qwtVectorCardinal< Param >( param, p[size - 1], p[0], p[1] );
store.addCubic( p[size - 1] + vec2 * tc.t1, p[0] - vec3 * tc.t2, p[0] );
}
else
{
const double d24 = qwtChordalLength( p[size - 2], p[size - 1] );
const Tension tn = qwtTensionPleasing(
d13, qwtChordalLength( p[size - 2], p[size - 1] ), d24,
p[size - 3], p[size - 2], p[size - 1], p[size - 1] );
const QPointF vec2 = 0.5 * qwtVector< Param >( param, p[size - 2], p[size - 1] );
store.addCubic( p[size - 2] + vec1 * tn.t1, p[size - 1] - vec2 * tn.t2, p[size - 1] );
}
return store;
}
QwtSplinePleasing::QwtSplinePleasing()
{
setParametrization( QwtSplineParametrization::ParameterUniform );
}
QwtSplinePleasing::~QwtSplinePleasing()
{
}
uint QwtSplinePleasing::locality() const
{
return 2;
}
QPainterPath QwtSplinePleasing::painterPath( const QPolygonF& points ) const
{
const int size = points.size();
if ( size <= 2 )
return QwtSplineG1::painterPath( points );
const bool isClosing = ( boundaryType() == QwtSpline::ClosedPolygon );
using namespace QwtSplinePleasingP;
PathStore store;
if ( parametrization()->type() == QwtSplineParametrization::ParameterUniform )
{
store = qwtSplinePathPleasing< PathStore >( points,
isClosing, paramUniform() );
}
else
{
store = qwtSplinePathPleasing< PathStore >( points,
isClosing, param( parametrization() ) );
}
if ( isClosing )
store.path.closeSubpath();
return store.path;
}
QVector< QLineF > QwtSplinePleasing::bezierControlLines(
const QPolygonF& points ) const
{
const int size = points.size();
if ( size <= 2 )
return QVector< QLineF >();
const bool isClosing = ( boundaryType() == QwtSpline::ClosedPolygon );
using namespace QwtSplinePleasingP;
ControlPointsStore store;
if ( parametrization()->type() == QwtSplineParametrization::ParameterUniform )
{
store = qwtSplinePathPleasing< ControlPointsStore >( points,
isClosing, paramUniform() );
}
else
{
store = qwtSplinePathPleasing< ControlPointsStore >( points,
isClosing, param( parametrization() ) );
}
return store.controlPoints;
}
QVector< QLineF >
QwtSpline::painterPath
virtual QPainterPath painterPath(const QPolygonF &) const =0
QwtSpline::parametrization
const QwtSplineParametrization * parametrization() const
Definition qwt_spline.cpp:605
QwtSpline::boundaryType
BoundaryType boundaryType() const
Definition qwt_spline.cpp:626
QwtSpline::ClosedPolygon
@ ClosedPolygon
Definition qwt_spline.h:92
QwtSpline::setParametrization
void setParametrization(int type)
Definition qwt_spline.cpp:576
QwtSplineParametrization
Curve parametrization used for a spline interpolation.
Definition qwt_spline_parametrization.h:45
QwtSplineParametrization::type
int type() const
Definition qwt_spline_parametrization.cpp:72
QwtSplineParametrization::valueIncrementUniform
static double valueIncrementUniform(const QPointF &, const QPointF &)
Calculate the ParameterUniform value increment.
Definition qwt_spline_parametrization.h:162
QwtSplineParametrization::valueIncrement
virtual double valueIncrement(const QPointF &, const QPointF &) const
Calculate the parameter value increment for 2 points.
Definition qwt_spline_parametrization.cpp:35
QwtSplineParametrization::ParameterUniform
@ ParameterUniform
Definition qwt_spline_parametrization.h:72
QwtSplinePleasing::locality
virtual uint locality() const override
Definition qwt_spline_pleasing.cpp:276
QwtSplinePleasing::bezierControlLines
virtual QVector< QLineF > bezierControlLines(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
Definition qwt_spline_pleasing.cpp:327
QwtSplinePleasing::~QwtSplinePleasing
virtual ~QwtSplinePleasing()
Destructor.
Definition qwt_spline_pleasing.cpp:271
QwtSplinePleasing::painterPath
virtual QPainterPath painterPath(const QPolygonF &) const override
Interpolate a curve with Bezier curves.
Definition qwt_spline_pleasing.cpp:290
QwtSplinePleasing::QwtSplinePleasing
QwtSplinePleasing()
Constructor.
Definition qwt_spline_pleasing.cpp:265