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 <qstack.h>
12 
13 namespace
14 {
15  class BezierData
16  {
17  public:
18  inline BezierData()
19  {
20  // default constructor with unitialized points
21  }
22 
23  inline BezierData( const QPointF &p1, const QPointF &cp1,
24  const QPointF &cp2, const QPointF &p2 ):
25  d_x1( p1.x() ),
26  d_y1( p1.y() ),
27  d_cx1( cp1.x() ),
28  d_cy1( cp1.y() ),
29  d_cx2( cp2.x() ),
30  d_cy2( cp2.y() ),
31  d_x2( p2.x() ),
32  d_y2( p2.y() )
33  {
34  }
35 
36  static inline double minFlatness( double tolerance )
37  {
38  // we can make simplify the tolerance criterion check in
39  // the subdivison loop cheaper, by precalculating some
40  // flatness value.
41 
42  return 16 * ( tolerance * tolerance );
43  }
44 
45  inline double flatness() const
46  {
47  // algo by Roger Willcocks ( http://www.rops.org )
48 
49  const double ux = 3.0 * d_cx1 - 2.0 * d_x1 - d_x2;
50  const double uy = 3.0 * d_cy1 - 2.0 * d_y1 - d_y2;
51  const double vx = 3.0 * d_cx2 - 2.0 * d_x2 - d_x1;
52  const double vy = 3.0 * d_cy2 - 2.0 * d_y2 - d_y1;
53 
54  const double ux2 = ux * ux;
55  const double uy2 = uy * uy;
56 
57  const double vx2 = vx * vx;
58  const double vy2 = vy * vy;
59 
60  return qMax( ux2, vx2 ) + qMax( uy2, vy2 );
61  }
62 
63  inline BezierData subdivided()
64  {
65  BezierData bz;
66 
67  const double c1 = midValue( d_cx1, d_cx2 );
68 
69  bz.d_cx1 = midValue( d_x1, d_cx1 );
70  d_cx2 = midValue( d_cx2, d_x2 );
71  bz.d_x1 = d_x1;
72  bz.d_cx2 = midValue( bz.d_cx1, c1 );
73  d_cx1 = midValue( c1, d_cx2 );
74  bz.d_x2 = d_x1 = midValue( bz.d_cx2, d_cx1 );
75 
76  const double c2 = midValue( d_cy1, d_cy2 );
77 
78  bz.d_cy1 = midValue( d_y1, d_cy1 );
79  d_cy2 = midValue( d_cy2, d_y2 );
80  bz.d_y1 = d_y1;
81  bz.d_cy2 = midValue( bz.d_cy1, c2 );
82  d_cy1 = midValue( d_cy2, c2 );
83  bz.d_y2 = d_y1 = midValue( bz.d_cy2, d_cy1 );
84 
85  return bz;
86  }
87 
88  inline QPointF p2() const
89  {
90  return QPointF( d_x2, d_y2 );
91  }
92 
93  private:
94  inline double midValue( double v1, double v2 )
95  {
96  return 0.5 * ( v1 + v2 );
97  }
98 
99  double d_x1, d_y1;
100  double d_cx1, d_cy1;
101  double d_cx2, d_cy2;
102  double d_x2, d_y2;
103  };
104 }
105 
113 QwtBezier::QwtBezier( double tolerance ):
114  m_tolerance( qMax( tolerance, 0.0 ) ),
115  m_flatness( BezierData::minFlatness( m_tolerance ) )
116 {
117 }
118 
121 {
122 }
123 
139 {
140  m_tolerance = qMax( tolerance, 0.0 );
141  m_flatness = BezierData::minFlatness( m_tolerance );
142 }
143 
154 QPolygonF QwtBezier::toPolygon( const QPointF &p1,
155  const QPointF &cp1, const QPointF &cp2, const QPointF &p2 ) const
156 {
157  QPolygonF polygon;
158 
159  if ( m_flatness > 0.0 )
160  {
161  // a flatness of 0.0 is not achievable
162  appendToPolygon( p1, cp1, cp2, p2, polygon );
163  }
164 
165  return polygon;
166 }
167 
183 void QwtBezier::appendToPolygon( const QPointF &p1, const QPointF &cp1,
184  const QPointF &cp2, const QPointF &p2, QPolygonF &polygon ) const
185 {
186  if ( m_flatness <= 0.0 )
187  {
188  // a flatness of 0.0 is not achievable
189  return;
190  }
191 
192  if ( polygon.isEmpty() || polygon.last() != p1 )
193  polygon += p1;
194 
195  // to avoid deep stacks we convert the recursive algo
196  // to something iterative, where the parameters of the
197  // recursive class are pushed to a stack instead
198 
200  stack.push( BezierData( p1, cp1, cp2, p2 ) );
201 
202  while( true )
203  {
204  BezierData &bz = stack.top();
205 
206  if ( bz.flatness() < m_flatness )
207  {
208  if ( stack.size() == 1 )
209  {
210  polygon += p2;
211  return;
212  }
213 
214  polygon += bz.p2();
215  stack.pop();
216  }
217  else
218  {
219  stack.push( bz.subdivided() );
220  }
221  }
222 
223 }
double m_flatness
Definition: qwt_bezier.h:47
double m_tolerance
Definition: qwt_bezier.h:46
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:183
~QwtBezier()
Destructor.
Definition: qwt_bezier.cpp:120
void setTolerance(double tolerance)
Definition: qwt_bezier.cpp:138
TFSIMD_FORCE_INLINE const tfScalar & y() const
QwtBezier(double tolerance=0.5)
Constructor.
Definition: qwt_bezier.cpp:113
TFSIMD_FORCE_INLINE const tfScalar & x() const
double tolerance() const
Definition: qwt_bezier.h:54
void * stack[40]
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:154


plotjuggler
Author(s): Davide Faconti
autogenerated on Sat Jul 6 2019 03:44:17