qwt_weeding_curve_fitter.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_weeding_curve_fitter.h"
00011 #include "qwt_math.h"
00012 #include <qstack.h>
00013 #include <qvector.h>
00014 
00015 #if QT_VERSION < 0x040601
00016 #define qFabs(x) ::fabs(x)
00017 #endif
00018 
00019 class QwtWeedingCurveFitter::PrivateData
00020 {
00021 public:
00022     PrivateData():
00023         tolerance( 1.0 ),
00024         chunkSize( 0 )
00025     {
00026     }
00027 
00028     double tolerance;
00029     uint chunkSize;
00030 };
00031 
00032 class QwtWeedingCurveFitter::Line
00033 {
00034 public:
00035     Line( int i1 = 0, int i2 = 0 ):
00036         from( i1 ),
00037         to( i2 )
00038     {
00039     }
00040 
00041     int from;
00042     int to;
00043 };
00044 
00051 QwtWeedingCurveFitter::QwtWeedingCurveFitter( double tolerance ):
00052     QwtCurveFitter( QwtCurveFitter::Polygon )
00053 {
00054     d_data = new PrivateData;
00055     setTolerance( tolerance );
00056 }
00057 
00059 QwtWeedingCurveFitter::~QwtWeedingCurveFitter()
00060 {
00061     delete d_data;
00062 }
00063 
00077 void QwtWeedingCurveFitter::setTolerance( double tolerance )
00078 {
00079     d_data->tolerance = qMax( tolerance, 0.0 );
00080 }
00081 
00086 double QwtWeedingCurveFitter::tolerance() const
00087 {
00088     return d_data->tolerance;
00089 }
00090 
00102 void QwtWeedingCurveFitter::setChunkSize( uint numPoints )
00103 {
00104     if ( numPoints > 0 )
00105         numPoints = qMax( numPoints, 3U );
00106 
00107     d_data->chunkSize = numPoints;
00108 }
00109 
00116 uint QwtWeedingCurveFitter::chunkSize() const
00117 {
00118     return d_data->chunkSize;
00119 }
00120 
00126 QPolygonF QwtWeedingCurveFitter::fitCurve( const QPolygonF &points ) const
00127 {
00128     QPolygonF fittedPoints;
00129 
00130     if ( d_data->chunkSize == 0 )
00131     {
00132         fittedPoints = simplify( points );
00133     }
00134     else
00135     {
00136         for ( int i = 0; i < points.size(); i += d_data->chunkSize )
00137         {
00138             const QPolygonF p = points.mid( i, d_data->chunkSize );
00139             fittedPoints += simplify( p );
00140         }
00141     }
00142 
00143     return fittedPoints;
00144 }
00145 
00151 QPainterPath QwtWeedingCurveFitter::fitCurvePath( const QPolygonF &points ) const
00152 {
00153     QPainterPath path;
00154     path.addPolygon( fitCurve( points ) );
00155     return path;
00156 }
00157 
00158 QPolygonF QwtWeedingCurveFitter::simplify( const QPolygonF &points ) const
00159 {
00160     const double toleranceSqr = d_data->tolerance * d_data->tolerance;
00161 
00162     QStack<Line> stack;
00163     stack.reserve( 500 );
00164 
00165     const QPointF *p = points.data();
00166     const int nPoints = points.size();
00167 
00168     QVector<bool> usePoint( nPoints, false );
00169 
00170     stack.push( Line( 0, nPoints - 1 ) );
00171 
00172     while ( !stack.isEmpty() )
00173     {
00174         const Line r = stack.pop();
00175 
00176         // initialize line segment
00177         const double vecX = p[r.to].x() - p[r.from].x();
00178         const double vecY = p[r.to].y() - p[r.from].y();
00179 
00180         const double vecLength = qSqrt( vecX * vecX + vecY * vecY );
00181 
00182         const double unitVecX = ( vecLength != 0.0 ) ? vecX / vecLength : 0.0;
00183         const double unitVecY = ( vecLength != 0.0 ) ? vecY / vecLength : 0.0;
00184 
00185         double maxDistSqr = 0.0;
00186         int nVertexIndexMaxDistance = r.from + 1;
00187         for ( int i = r.from + 1; i < r.to; i++ )
00188         {
00189             //compare to anchor
00190             const double fromVecX = p[i].x() - p[r.from].x();
00191             const double fromVecY = p[i].y() - p[r.from].y();
00192 
00193             double distToSegmentSqr;
00194             if ( fromVecX * unitVecX + fromVecY * unitVecY < 0.0 )
00195             {
00196                 distToSegmentSqr = fromVecX * fromVecX + fromVecY * fromVecY;
00197             }
00198             else
00199             {
00200                 const double toVecX = p[i].x() - p[r.to].x();
00201                 const double toVecY = p[i].y() - p[r.to].y();
00202                 const double toVecLength = toVecX * toVecX + toVecY * toVecY;
00203 
00204                 const double s = toVecX * ( -unitVecX ) + toVecY * ( -unitVecY );
00205                 if ( s < 0.0 )
00206                 {
00207                     distToSegmentSqr = toVecLength;
00208                 }
00209                 else
00210                 {
00211                     distToSegmentSqr = qFabs( toVecLength - s * s );
00212                 }
00213             }
00214 
00215             if ( maxDistSqr < distToSegmentSqr )
00216             {
00217                 maxDistSqr = distToSegmentSqr;
00218                 nVertexIndexMaxDistance = i;
00219             }
00220         }
00221         if ( maxDistSqr <= toleranceSqr )
00222         {
00223             usePoint[r.from] = true;
00224             usePoint[r.to] = true;
00225         }
00226         else
00227         {
00228             stack.push( Line( r.from, nVertexIndexMaxDistance ) );
00229             stack.push( Line( nVertexIndexMaxDistance, r.to ) );
00230         }
00231     }
00232 
00233     QPolygonF stripped;
00234     for ( int i = 0; i < nPoints; i++ )
00235     {
00236         if ( usePoint[i] )
00237             stripped += p[i];
00238     }
00239 
00240     return stripped;
00241 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:57