00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_bezier.h"
00011 #include <qstack.h>
00012
00013 namespace
00014 {
00015 class BezierData
00016 {
00017 public:
00018 inline BezierData()
00019 {
00020
00021 }
00022
00023 inline BezierData( const QPointF &p1, const QPointF &cp1,
00024 const QPointF &cp2, const QPointF &p2 ):
00025 d_x1( p1.x() ),
00026 d_y1( p1.y() ),
00027 d_cx1( cp1.x() ),
00028 d_cy1( cp1.y() ),
00029 d_cx2( cp2.x() ),
00030 d_cy2( cp2.y() ),
00031 d_x2( p2.x() ),
00032 d_y2( p2.y() )
00033 {
00034 }
00035
00036 static inline double minFlatness( double tolerance )
00037 {
00038
00039
00040
00041
00042 return 16 * ( tolerance * tolerance );
00043 }
00044
00045 inline double flatness() const
00046 {
00047
00048
00049 const double ux = 3.0 * d_cx1 - 2.0 * d_x1 - d_x2;
00050 const double uy = 3.0 * d_cy1 - 2.0 * d_y1 - d_y2;
00051 const double vx = 3.0 * d_cx2 - 2.0 * d_x2 - d_x1;
00052 const double vy = 3.0 * d_cy2 - 2.0 * d_y2 - d_y1;
00053
00054 const double ux2 = ux * ux;
00055 const double uy2 = uy * uy;
00056
00057 const double vx2 = vx * vx;
00058 const double vy2 = vy * vy;
00059
00060 return qMax( ux2, vx2 ) + qMax( uy2, vy2 );
00061 }
00062
00063 inline BezierData subdivided()
00064 {
00065 BezierData bz;
00066
00067 const double c1 = midValue( d_cx1, d_cx2 );
00068
00069 bz.d_cx1 = midValue( d_x1, d_cx1 );
00070 d_cx2 = midValue( d_cx2, d_x2 );
00071 bz.d_x1 = d_x1;
00072 bz.d_cx2 = midValue( bz.d_cx1, c1 );
00073 d_cx1 = midValue( c1, d_cx2 );
00074 bz.d_x2 = d_x1 = midValue( bz.d_cx2, d_cx1 );
00075
00076 const double c2 = midValue( d_cy1, d_cy2 );
00077
00078 bz.d_cy1 = midValue( d_y1, d_cy1 );
00079 d_cy2 = midValue( d_cy2, d_y2 );
00080 bz.d_y1 = d_y1;
00081 bz.d_cy2 = midValue( bz.d_cy1, c2 );
00082 d_cy1 = midValue( d_cy2, c2 );
00083 bz.d_y2 = d_y1 = midValue( bz.d_cy2, d_cy1 );
00084
00085 return bz;
00086 }
00087
00088 inline QPointF p2() const
00089 {
00090 return QPointF( d_x2, d_y2 );
00091 }
00092
00093 private:
00094 inline double midValue( double v1, double v2 )
00095 {
00096 return 0.5 * ( v1 + v2 );
00097 }
00098
00099 double d_x1, d_y1;
00100 double d_cx1, d_cy1;
00101 double d_cx2, d_cy2;
00102 double d_x2, d_y2;
00103 };
00104 }
00105
00113 QwtBezier::QwtBezier( double tolerance ):
00114 m_tolerance( qMax( tolerance, 0.0 ) ),
00115 m_flatness( BezierData::minFlatness( m_tolerance ) )
00116 {
00117 }
00118
00120 QwtBezier::~QwtBezier()
00121 {
00122 }
00123
00138 void QwtBezier::setTolerance( double tolerance )
00139 {
00140 m_tolerance = qMax( tolerance, 0.0 );
00141 m_flatness = BezierData::minFlatness( m_tolerance );
00142 }
00143
00154 QPolygonF QwtBezier::toPolygon( const QPointF &p1,
00155 const QPointF &cp1, const QPointF &cp2, const QPointF &p2 ) const
00156 {
00157 QPolygonF polygon;
00158
00159 if ( m_flatness > 0.0 )
00160 {
00161
00162 appendToPolygon( p1, cp1, cp2, p2, polygon );
00163 }
00164
00165 return polygon;
00166 }
00167
00183 void QwtBezier::appendToPolygon( const QPointF &p1, const QPointF &cp1,
00184 const QPointF &cp2, const QPointF &p2, QPolygonF &polygon ) const
00185 {
00186 if ( m_flatness <= 0.0 )
00187 {
00188
00189 return;
00190 }
00191
00192 if ( polygon.isEmpty() || polygon.last() != p1 )
00193 polygon += p1;
00194
00195
00196
00197
00198
00199 QStack<BezierData> stack;
00200 stack.push( BezierData( p1, cp1, cp2, p2 ) );
00201
00202 while( true )
00203 {
00204 BezierData &bz = stack.top();
00205
00206 if ( bz.flatness() < m_flatness )
00207 {
00208 if ( stack.size() == 1 )
00209 {
00210 polygon += p2;
00211 return;
00212 }
00213
00214 polygon += bz.p2();
00215 stack.pop();
00216 }
00217 else
00218 {
00219 stack.push( bz.subdivided() );
00220 }
00221 }
00222
00223 }