Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
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
18class 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
31class 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
51 : QwtCurveFitter( QwtCurveFitter::Polygon )
52{
53 m_data = new PrivateData;
55}
56
62
77{
78 m_data->tolerance = qwtMaxF( tolerance, 0.0 );
79}
80
86{
87 return m_data->tolerance;
88}
89
102{
103 if ( numPoints > 0 )
104 numPoints = qMax( numPoints, 3U );
105
106 m_data->chunkSize = numPoints;
107}
108
115{
116 return m_data->chunkSize;
117}
118
124QPolygonF 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
151QPainterPath QwtWeedingCurveFitter::fitCurvePath( const QPolygonF& points ) const
152{
153 QPainterPath path;
154 path.addPolygon( fitCurve( points ) );
155 return path;
156}
157
158QPolygonF 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}
Abstract base class for a curve fitter.
virtual QPolygonF fitCurve(const QPolygonF &) const override
QwtWeedingCurveFitter(double tolerance=1.0)
virtual ~QwtWeedingCurveFitter()
Destructor.
virtual QPainterPath fitCurvePath(const QPolygonF &) const override