Skip to content

Commit

Permalink
#8725-R: simplify edited geometries in QgsVectorLayerFeatureIterator
Browse files Browse the repository at this point in the history
  • Loading branch information
ahuarte47 authored and m-kuhn committed Jan 15, 2014
1 parent 4cc82e6 commit 61041da
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 25 deletions.
2 changes: 2 additions & 0 deletions python/core/core.sip
Expand Up @@ -37,6 +37,7 @@
%Include qgsfield.sip
%Include qgsgeometry.sip
%Include qgsgeometryvalidator.sip
%Include qgsgeometrysimplifier.sip
%Include qgsgml.sip
%Include qgsgmlschema.sip
%Include qgshttptransaction.sip
Expand Down Expand Up @@ -75,6 +76,7 @@
%Include qgsrunprocess.sip
%Include qgsscalecalculator.sip
%Include qgsscaleutils.sip
%Include qgssimplifymethod.sip
%Include qgssnapper.sip
%Include qgsspatialindex.sip
%Include qgstolerance.sip
Expand Down
23 changes: 23 additions & 0 deletions python/core/qgsgeometrysimplifier.sip
@@ -0,0 +1,23 @@

/** Abstract base class for simplify geometries using a specific algorithm */
class QgsAbstractGeometrySimplifier
{
%TypeHeaderCode
#include "qgsgeometrysimplifier.h"
%End

public:
virtual ~QgsAbstractGeometrySimplifier();

/** Returns a simplified version the specified geometry */
virtual QgsGeometry* simplify( QgsGeometry* geometry ) const = 0;
/** Simplifies the specified geometry */
virtual bool simplifyGeometry( QgsGeometry* geometry ) const = 0;

// MapToPixel simplification helper methods
public:
/** Returns whether the device-envelope can be replaced by its BBOX when is applied the specified tolerance */
static bool canbeGeneralizedByDeviceBoundingBox( const QgsRectangle& envelope, float mapToPixelTol = 1.0f );
/** Returns whether the device-geometry can be replaced by its BBOX when is applied the specified tolerance */
static bool canbeGeneralizedByDeviceBoundingBox( const QVector<QPointF>& points, float mapToPixelTol = 1.0f );
};
39 changes: 39 additions & 0 deletions python/core/qgssimplifymethod.sip
@@ -0,0 +1,39 @@

/** This class contains information about how to simplify geometries fetched from a QgsFeatureIterator */
class QgsSimplifyMethod
{
%TypeHeaderCode
#include "qgssimplifymethod.h"
%End

public:
enum MethodType
{
NoSimplification, //!< No simplification is applied
OptimizeForRendering, //!< Simplify using the map2pixel data to optimize the rendering of geometries
PreserveTopology //!< Simplify using the Douglas-Peucker algorithm ensuring that the result is a valid geometry
};

//! construct a default method
QgsSimplifyMethod();
//! copy constructor
QgsSimplifyMethod( const QgsSimplifyMethod& rh );

/** Sets the simplification type */
void setMethodType( MethodType methodType );
/** Gets the simplification type */
MethodType methodType() const;

/** Sets the tolerance of simplification. Represents the maximum distance between two coordinates which can be considered equal */
void setTolerance( double tolerance );
/** Gets the tolerance of simplification */
double tolerance() const;

/** Sets whether the simplification executes after fetch the geometries from provider, otherwise it executes, when supported, in provider before fetch the geometries */
void setForceLocalOptimization( bool localOptimization );
/** Gets whether the simplification executes after fetch the geometries from provider, otherwise it executes, when supported, in provider before fetch the geometries */
bool forceLocalOptimization() const;

/** Creates a geometry simplifier according to specified method */
static QgsAbstractGeometrySimplifier* createGeometrySimplifier( const QgsSimplifyMethod& simplifyMethod );
};
23 changes: 3 additions & 20 deletions src/core/qgsfeatureiterator.cpp
Expand Up @@ -16,7 +16,6 @@
#include "qgslogger.h"

#include "qgsgeometrysimplifier.h"
#include "qgsmaptopixelgeometrysimplifier.h"
#include "qgssimplifymethod.h"

QgsAbstractFeatureIterator::QgsAbstractFeatureIterator( const QgsFeatureRequest& request )
Expand Down Expand Up @@ -104,27 +103,11 @@ bool QgsAbstractFeatureIterator::prepareSimplification( const QgsSimplifyMethod&
mGeometrySimplifier = NULL;
}

// setup the local simplification of geometries to fetch, it uses the settings of current FeatureRequest
// setup the local simplification of geometries to fetch
if ( simplifyMethod.methodType() != QgsSimplifyMethod::NoSimplification && simplifyMethod.forceLocalOptimization() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
{
QgsSimplifyMethod::MethodType methodType = simplifyMethod.methodType();

if ( methodType == QgsSimplifyMethod::OptimizeForRendering )
{
int simplifyFlags = QgsMapToPixelSimplifier::SimplifyGeometry | QgsMapToPixelSimplifier::SimplifyEnvelope;
mGeometrySimplifier = new QgsMapToPixelSimplifier( simplifyFlags, simplifyMethod.tolerance() );
return true;
}
else
if ( methodType == QgsSimplifyMethod::PreserveTopology )
{
mGeometrySimplifier = new QgsTopologyPreservingSimplifier( simplifyMethod.tolerance() );
return true;
}
else
{
QgsDebugMsg( QString( "Simplification method type (%1) is not recognised" ).arg( methodType ) );
}
mGeometrySimplifier = QgsSimplifyMethod::createGeometrySimplifier( simplifyMethod );
return mGeometrySimplifier != NULL;
}
return false;
}
Expand Down
25 changes: 25 additions & 0 deletions src/core/qgssimplifymethod.cpp
Expand Up @@ -14,6 +14,9 @@
***************************************************************************/

#include "qgssimplifymethod.h"
#include "qgslogger.h"
#include "qgsgeometrysimplifier.h"
#include "qgsmaptopixelgeometrysimplifier.h"

QgsSimplifyMethod::QgsSimplifyMethod()
: mMethodType( QgsSimplifyMethod::NoSimplification )
Expand Down Expand Up @@ -50,3 +53,25 @@ void QgsSimplifyMethod::setForceLocalOptimization( bool localOptimization )
{
mForceLocalOptimization = localOptimization;
}

QgsAbstractGeometrySimplifier* QgsSimplifyMethod::createGeometrySimplifier( const QgsSimplifyMethod& simplifyMethod )
{
QgsSimplifyMethod::MethodType methodType = simplifyMethod.methodType();

// returns a geometry simplifier according to specified method
if ( methodType == QgsSimplifyMethod::OptimizeForRendering )
{
int simplifyFlags = QgsMapToPixelSimplifier::SimplifyGeometry | QgsMapToPixelSimplifier::SimplifyEnvelope;
return new QgsMapToPixelSimplifier( simplifyFlags, simplifyMethod.tolerance() );
}
else
if ( methodType == QgsSimplifyMethod::PreserveTopology )
{
return new QgsTopologyPreservingSimplifier( simplifyMethod.tolerance() );
}
else
{
QgsDebugMsg( QString( "Simplification method type (%1) is not recognised" ).arg( methodType ) );
return NULL;
}
}
5 changes: 5 additions & 0 deletions src/core/qgssimplifymethod.h
Expand Up @@ -16,6 +16,8 @@
#ifndef QGSSIMPLIFYMETHOD_H
#define QGSSIMPLIFYMETHOD_H

class QgsAbstractGeometrySimplifier;

/**
* This class contains information about how to simplify geometries fetched from a QgsFeatureIterator
*/
Expand Down Expand Up @@ -51,6 +53,9 @@ class CORE_EXPORT QgsSimplifyMethod
//! Gets whether the simplification executes after fetch the geometries from provider, otherwise it executes, when supported, in provider before fetch the geometries
inline bool forceLocalOptimization() const { return mForceLocalOptimization; }

//! Creates a geometry simplifier according to specified method
static QgsAbstractGeometrySimplifier* createGeometrySimplifier( const QgsSimplifyMethod& simplifyMethod );

protected:
//! Simplification method
MethodType mMethodType;
Expand Down
52 changes: 48 additions & 4 deletions src/core/qgsvectorlayerfeatureiterator.cpp
Expand Up @@ -19,9 +19,11 @@
#include "qgsvectorlayer.h"
#include "qgsvectorlayereditbuffer.h"
#include "qgsvectorlayerjoinbuffer.h"
#include "qgsgeometrysimplifier.h"
#include "qgssimplifymethod.h"

QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayer* layer, const QgsFeatureRequest& request )
: QgsAbstractFeatureIterator( request ), L( layer )
: QgsAbstractFeatureIterator( request ), L( layer ), mEditGeometrySimplifier( NULL )
{
QgsVectorLayerJoinBuffer* joinBuffer = L->mJoinBuffer;

Expand Down Expand Up @@ -86,21 +88,27 @@ QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator( QgsVectorLayer* la
mProviderIterator = L->dataProvider()->getFeatures( mProviderRequest );
}

// prepare if required the local simplification of geometries to fetch
prepareSimplification( request.simplifyMethod() );

rewindEditBuffer();
}

if ( mRequest.filterType() == QgsFeatureRequest::FilterExpression )
{
mRequest.filterExpression()->prepare( L->pendingFields() );
}

// prepare if required the local simplification of geometries to fetch
prepareSimplification( request.simplifyMethod() );
}


QgsVectorLayerFeatureIterator::~QgsVectorLayerFeatureIterator()
{
if ( mEditGeometrySimplifier )
{
delete mEditGeometrySimplifier;
mEditGeometrySimplifier = NULL;
}

close();
}

Expand Down Expand Up @@ -242,8 +250,18 @@ void QgsVectorLayerFeatureIterator::useAddedFeature( const QgsFeature& src, QgsF
f.setFields( &L->mUpdatedFields );

if ( src.geometry() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
{
f.setGeometry( *src.geometry() );

// simplify the edited geometry using its simplifier configured
if ( mEditGeometrySimplifier )
{
QgsGeometry* geometry = f.geometry();
QGis::GeometryType geometryType = geometry->type();
if ( geometryType == QGis::Line || geometryType == QGis::Polygon ) mEditGeometrySimplifier->simplifyGeometry( geometry );
}
}

// TODO[MD]: if subset set just some attributes

f.setAttributes( src.attributes() );
Expand Down Expand Up @@ -313,8 +331,18 @@ void QgsVectorLayerFeatureIterator::useChangedAttributeFeature( QgsFeatureId fid
f.setFields( &L->mUpdatedFields );

if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
{
f.setGeometry( geom );

// simplify the edited geometry using its simplifier configured
if ( mEditGeometrySimplifier )
{
QgsGeometry* geometry = f.geometry();
QGis::GeometryType geometryType = geometry->type();
if ( geometryType == QGis::Line || geometryType == QGis::Polygon ) mEditGeometrySimplifier->simplifyGeometry( geometry );
}
}

bool subsetAttrs = ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes );
if ( !subsetAttrs || ( subsetAttrs && mRequest.subsetOfAttributes().count() > 0 ) )
{
Expand Down Expand Up @@ -436,6 +464,22 @@ void QgsVectorLayerFeatureIterator::addJoinedAttributes( QgsFeature &f )
}
}

bool QgsVectorLayerFeatureIterator::prepareSimplification( const QgsSimplifyMethod& simplifyMethod )
{
if ( mEditGeometrySimplifier )
{
delete mEditGeometrySimplifier;
mEditGeometrySimplifier = NULL;
}

// setup the simplification of edited geometries to fetch
if ( simplifyMethod.methodType() != QgsSimplifyMethod::NoSimplification && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
{
mEditGeometrySimplifier = QgsSimplifyMethod::createGeometrySimplifier( simplifyMethod );
}

return QgsAbstractFeatureIterator::prepareSimplification( simplifyMethod );
}


void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesCached( QgsFeature& f, const QVariant& joinValue ) const
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgsvectorlayerfeatureiterator.h
Expand Up @@ -46,6 +46,9 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
//! while for others filtering is left to the provider implementation.
inline virtual bool nextFeatureFilterExpression( QgsFeature &f ) { return fetchFeature( f ); }

//! Setup the simplification of geometries to fetch using the specified simplify method
virtual bool prepareSimplification( const QgsSimplifyMethod& simplifyMethod );

QgsVectorLayer* L;

QgsFeatureRequest mProviderRequest;
Expand Down Expand Up @@ -114,6 +117,10 @@ class CORE_EXPORT QgsVectorLayerFeatureIterator : public QgsAbstractFeatureItera
/** Informations about joins used in the current select() statement.
Allows faster mapping of attribute ids compared to mVectorJoins */
QMap<QgsVectorLayer*, FetchJoinInfo> mFetchJoinInfo;

private:
//! optional object to locally simplify edited (changed or added) geometries fetched by this feature iterator
QgsAbstractGeometrySimplifier* mEditGeometrySimplifier;
};

#endif // QGSVECTORLAYERFEATUREITERATOR_H
2 changes: 1 addition & 1 deletion src/providers/ogr/qgsogrfeatureiterator.cpp
Expand Up @@ -115,7 +115,7 @@ bool QgsOgrFeatureIterator::prepareSimplification( const QgsSimplifyMethod& simp
mGeometrySimplifier = NULL;
}

// setup if required the simplification of OGR-geometries fetched, it uses the settings of current FeatureRequest
// setup if required the simplification of OGR-geometries fetched
if ( simplifyMethod.methodType() != QgsSimplifyMethod::NoSimplification && !simplifyMethod.forceLocalOptimization() && !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
{
QgsSimplifyMethod::MethodType methodType = simplifyMethod.methodType();
Expand Down

0 comments on commit 61041da

Please sign in to comment.