Qwt User's Guide 6.2.0

qwt_weeding_curve_fitter.cpp
1 /******************************************************************************
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_weeding_curve_fitter.h"
11 #include "qwt_math.h"
12
13 #include <qpainterpath.h>
14 #include <qpolygon.h>
15 #include <qstack.h>
16 #include <qvector.h>
17
18 class QwtWeedingCurveFitter::PrivateData
19 {
20 public:
21 PrivateData()
22 : tolerance( 1.0 )
23 , chunkSize( 0 )
24 {
25 }
26
27 double tolerance;
28 uint chunkSize;
29 };
30
31 class QwtWeedingCurveFitter::Line
32 {
33 public:
34 Line( int i1 = 0, int i2 = 0 )
35 : from( i1 )
36 , to( i2 )
37 {
38 }
39
40 int from;
41 int to;
42 };
43
50 QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance )
51 : QwtCurveFitter( QwtCurveFitter::Polygon )
52 {
53 m_data = new PrivateData;
54 setTolerance( tolerance );
55 }
56
58 QwtWeedingCurveFitter::~QwtWeedingCurveFitter()
59 {
60 delete m_data;
61 }
62
76 void QwtWeedingCurveFitter::setTolerance( double tolerance )
77 {
78 m_data->tolerance = qwtMaxF( tolerance, 0.0 );
79 }
80
85 double QwtWeedingCurveFitter::tolerance() const
86 {
87 return m_data->tolerance;
88 }
89
101 void QwtWeedingCurveFitter::setChunkSize( uint numPoints )
102 {
103 if ( numPoints > 0 )
104 numPoints = qMax( numPoints, 3U );
105
106 m_data->chunkSize = numPoints;
107 }
108
114 uint QwtWeedingCurveFitter::chunkSize() const
115 {
116 return m_data->chunkSize;
117 }
118
124 QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF& points ) const
125 {
126 if ( points.isEmpty() )
127 return points;
128
129 QPolygonF fittedPoints;
130 if ( m_data->chunkSize == 0 )
131 {
132 fittedPoints = simplify( points );
133 }
134 else
135 {
136 for ( int i = 0; i < points.size(); i += m_data->chunkSize )
137 {
138 const QPolygonF p = points.mid( i, m_data->chunkSize );
139 fittedPoints += simplify( p );
140 }
141 }
142
143 return fittedPoints;
144 }
145
151 QPainterPath QwtWeedingCurveFitter::fitCurvePath( const QPolygonF& points ) const
152 {
153 QPainterPath path;
154 path.addPolygon( fitCurve( points ) );
155 return path;
156 }
157
158 QPolygonF QwtWeedingCurveFitter::simplify( const QPolygonF& points ) const
159 {
160 const double toleranceSqr = m_data->tolerance * m_data->tolerance;
161
162 QStack< Line > stack;
163 stack.reserve( 500 );
164
165 const QPointF* p = points.data();
166 const int nPoints = points.size();
167
168 QVector< bool > usePoint( nPoints, false );
169
170 stack.push( Line( 0, nPoints - 1 ) );
171
172 while ( !stack.isEmpty() )
173 {
174 const Line r = stack.pop();
175
176 // initialize line segment
177 const double vecX = p[r.to].x() - p[r.from].x();
178 const double vecY = p[r.to].y() - p[r.from].y();
179
180 const double vecLength = std::sqrt( vecX * vecX + vecY * vecY );
181
182 const double unitVecX = ( vecLength != 0.0 ) ? vecX / vecLength : 0.0;
183 const double unitVecY = ( vecLength != 0.0 ) ? vecY / vecLength : 0.0;
184
185 double maxDistSqr = 0.0;
186 int nVertexIndexMaxDistance = r.from + 1;
187 for ( int i = r.from + 1; i < r.to; i++ )
188 {
189 //compare to anchor
190 const double fromVecX = p[i].x() - p[r.from].x();
191 const double fromVecY = p[i].y() - p[r.from].y();
192
193 double distToSegmentSqr;
194 if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 )
195 {
196 distToSegmentSqr = fromVecX * fromVecX + fromVecY * fromVecY;
197 }
198 else
199 {
200 const double toVecX = p[i].x() - p[r.to].x();
201 const double toVecY = p[i].y() - p[r.to].y();
202 const double toVecLength = toVecX * toVecX + toVecY * toVecY;
203
204 const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY );
205 if ( s < 0.0 )
206 {
207 distToSegmentSqr = toVecLength;
208 }
209 else
210 {
211 distToSegmentSqr = std::fabs( toVecLength - s * s );
212 }
213 }
214
215 if ( maxDistSqr < distToSegmentSqr )
216 {
217 maxDistSqr = distToSegmentSqr;
218 nVertexIndexMaxDistance = i;
219 }
220 }
221 if ( maxDistSqr <= toleranceSqr )
222 {
223 usePoint[r.from] = true;
224 usePoint[r.to] = true;
225 }
226 else
227 {
228 stack.push( Line( r.from, nVertexIndexMaxDistance ) );
229 stack.push( Line( nVertexIndexMaxDistance, r.to ) );
230 }
231 }
232
233 QPolygonF stripped;
234 for ( int i = 0; i < nPoints; i++ )
235 {
236 if ( usePoint[i] )
237 stripped += p[i];
238 }
239
240 return stripped;
241 }
QStack
Definition: qwt_plot_zoomer.h:17
QVector
Definition: qwt_clipper.h:23
QwtCurveFitter
Abstract base class for a curve fitter.
Definition: qwt_curve_fitter.h:22
QwtWeedingCurveFitter::fitCurve
virtual QPolygonF fitCurve(const QPolygonF &) const override
Definition: qwt_weeding_curve_fitter.cpp:124
QwtWeedingCurveFitter::tolerance
double tolerance() const
Definition: qwt_weeding_curve_fitter.cpp:85
QwtWeedingCurveFitter::setTolerance
void setTolerance(double)
Definition: qwt_weeding_curve_fitter.cpp:76
QwtWeedingCurveFitter::QwtWeedingCurveFitter
QwtWeedingCurveFitter(double tolerance=1.0)
Definition: qwt_weeding_curve_fitter.cpp:50
QwtWeedingCurveFitter::setChunkSize
void setChunkSize(uint)
Definition: qwt_weeding_curve_fitter.cpp:101
QwtWeedingCurveFitter::~QwtWeedingCurveFitter
virtual ~QwtWeedingCurveFitter()
Destructor.
Definition: qwt_weeding_curve_fitter.cpp:58
QwtWeedingCurveFitter::fitCurvePath
virtual QPainterPath fitCurvePath(const QPolygonF &) const override
Definition: qwt_weeding_curve_fitter.cpp:151
QwtWeedingCurveFitter::chunkSize
uint chunkSize() const
Definition: qwt_weeding_curve_fitter.cpp:114