qwt_bezier.cpp
Go to the documentation of this file.
1 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
2  * Qwt Widget Library
3  * Copyright (C) 1997 Josef Wilgen
4  * Copyright (C) 2002 Uwe Rathmann
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the Qwt License, Version 1.0
8  *****************************************************************************/
9 
10 #include "qwt_bezier.h"
11 #include "qwt_math.h"
12 
13 #include <qpolygon.h>
14 #include <qstack.h>
15 
16 namespace
17 {
18  class BezierData
19  {
20  public:
21  inline BezierData()
22  {
23  // default constructor with unitialized points
24  }
25 
26  inline BezierData( const QPointF &p1, const QPointF &cp1,
27  const QPointF &cp2, const QPointF &p2 ):
28  d_x1( p1.x() ),
29  d_y1( p1.y() ),
30  d_cx1( cp1.x() ),
31  d_cy1( cp1.y() ),
32  d_cx2( cp2.x() ),
33  d_cy2( cp2.y() ),
34  d_x2( p2.x() ),
35  d_y2( p2.y() )
36  {
37  }
38 
39  static inline double minFlatness( double tolerance )
40  {
41  // we can simplify the tolerance criterion check in
42  // the subdivison loop, by precalculating some
43  // flatness value.
44 
45  return 16 * ( tolerance * tolerance );
46  }
47 
48  inline double flatness() const
49  {
50  // algo by Roger Willcocks ( http://www.rops.org )
51 
52  const double ux = 3.0 * d_cx1 - 2.0 * d_x1 - d_x2;
53  const double uy = 3.0 * d_cy1 - 2.0 * d_y1 - d_y2;
54  const double vx = 3.0 * d_cx2 - 2.0 * d_x2 - d_x1;
55  const double vy = 3.0 * d_cy2 - 2.0 * d_y2 - d_y1;
56 
57  const double ux2 = ux * ux;
58  const double uy2 = uy * uy;
59 
60  const double vx2 = vx * vx;
61  const double vy2 = vy * vy;
62 
63  return qwtMaxF( ux2, vx2 ) + qwtMaxF( uy2, vy2 );
64  }
65 
66  inline BezierData subdivided()
67  {
68  BezierData bz;
69 
70  const double c1 = midValue( d_cx1, d_cx2 );
71 
72  bz.d_cx1 = midValue( d_x1, d_cx1 );
73  d_cx2 = midValue( d_cx2, d_x2 );
74  bz.d_x1 = d_x1;
75  bz.d_cx2 = midValue( bz.d_cx1, c1 );
76  d_cx1 = midValue( c1, d_cx2 );
77  bz.d_x2 = d_x1 = midValue( bz.d_cx2, d_cx1 );
78 
79  const double c2 = midValue( d_cy1, d_cy2 );
80 
81  bz.d_cy1 = midValue( d_y1, d_cy1 );
82  d_cy2 = midValue( d_cy2, d_y2 );
83  bz.d_y1 = d_y1;
84  bz.d_cy2 = midValue( bz.d_cy1, c2 );
85  d_cy1 = midValue( d_cy2, c2 );
86  bz.d_y2 = d_y1 = midValue( bz.d_cy2, d_cy1 );
87 
88  return bz;
89  }
90 
91  inline QPointF p2() const
92  {
93  return QPointF( d_x2, d_y2 );
94  }
95 
96  private:
97  inline double midValue( double v1, double v2 )
98  {
99  return 0.5 * ( v1 + v2 );
100  }
101 
102  double d_x1, d_y1;
103  double d_cx1, d_cy1;
104  double d_cx2, d_cy2;
105  double d_x2, d_y2;
106  };
107 }
108 
116 QwtBezier::QwtBezier( double tolerance ):
117  m_tolerance( qwtMaxF( tolerance, 0.0 ) ),
118  m_flatness( BezierData::minFlatness( m_tolerance ) )
119 {
120 }
121 
124 {
125 }
126 
142 {
143  m_tolerance = qwtMaxF( tolerance, 0.0 );
144  m_flatness = BezierData::minFlatness( m_tolerance );
145 }
146 
157 QPolygonF QwtBezier::toPolygon( const QPointF &p1,
158  const QPointF &cp1, const QPointF &cp2, const QPointF &p2 ) const
159 {
160  QPolygonF polygon;
161 
162  if ( m_flatness > 0.0 )
163  {
164  // a flatness of 0.0 is not achievable
165  appendToPolygon( p1, cp1, cp2, p2, polygon );
166  }
167 
168  return polygon;
169 }
170 
186 void QwtBezier::appendToPolygon( const QPointF &p1, const QPointF &cp1,
187  const QPointF &cp2, const QPointF &p2, QPolygonF &polygon ) const
188 {
189  if ( m_flatness <= 0.0 )
190  {
191  // a flatness of 0.0 is not achievable
192  return;
193  }
194 
195  if ( polygon.isEmpty() || polygon.last() != p1 )
196  polygon += p1;
197 
198  // to avoid deep stacks we convert the recursive algo
199  // to something iterative, where the parameters of the
200  // recursive class are pushed to a stack instead
201 
202  QStack<BezierData> stack;
203  stack.push( BezierData( p1, cp1, cp2, p2 ) );
204 
205  while( true )
206  {
207  BezierData &bz = stack.top();
208 
209  if ( bz.flatness() < m_flatness )
210  {
211  if ( stack.size() == 1 )
212  {
213  polygon += p2;
214  return;
215  }
216 
217  polygon += bz.p2();
218  stack.pop();
219  }
220  else
221  {
222  stack.push( bz.subdivided() );
223  }
224  }
225 
226 }
227 
239 QPointF QwtBezier::pointAt( const QPointF &p1,
240  const QPointF &cp1, const QPointF &cp2, const QPointF &p2, double t )
241 {
242  const double d1 = 3.0 * t;
243  const double d2 = 3.0 * t * t;
244  const double d3 = t * t * t;
245  const double s = 1.0 - t;
246 
247  const double x = (( s * p1.x() + d1 * cp1.x() ) * s + d2 * cp2.x() ) * s + d3 * p2.x();
248  const double y = (( s * p1.y() + d1 * cp1.y() ) * s + d2 * cp2.y() ) * s + d3 * p2.y();
249 
250  return QPointF( x, y );
251 }
252 
double m_flatness
Definition: qwt_bezier.h:49
double m_tolerance
Definition: qwt_bezier.h:48
static QPointF pointAt(const QPointF &p1, const QPointF &cp1, const QPointF &cp2, const QPointF &p2, double t)
Definition: qwt_bezier.cpp:239
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.
Definition: qwt_bezier.cpp:186
~QwtBezier()
Destructor.
Definition: qwt_bezier.cpp:123
QWT_CONSTEXPR float qwtMaxF(float a, float b)
Definition: qwt_math.h:123
void setTolerance(double tolerance)
Definition: qwt_bezier.cpp:141
QwtBezier(double tolerance=0.5)
Constructor.
Definition: qwt_bezier.cpp:116
double tolerance() const
Definition: qwt_bezier.h:56
QPolygonF toPolygon(const QPointF &p1, const QPointF &cp1, const QPointF &cp2, const QPointF &p2) const
Interpolate a Bézier curve by a polygon.
Definition: qwt_bezier.cpp:157


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:48:10