diff --git a/python/core/qgssimplifymethod.sip b/python/core/qgssimplifymethod.sip index 8fa8ba97d33..35520e5c358 100644 --- a/python/core/qgssimplifymethod.sip +++ b/python/core/qgssimplifymethod.sip @@ -26,11 +26,16 @@ class QgsSimplifyMethod //! Gets the simplification type MethodType methodType() const; - //! Sets the tolerance of simplification. Represents the maximum distance between two coordinates which can be considered equal + //! Sets the tolerance of simplification in map units. Represents the maximum distance between two coordinates which can be considered equal void setTolerance( double tolerance ); - //! Gets the tolerance of simplification + //! Gets the tolerance of simplification in map units double tolerance() const; + //! Sets the simplification threshold in pixels. Represents the maximum distance in pixels between two coordinates which can be considered equal. + void setThreshold( float threshold ); + //! Gets the simplification threshold in pixels. Represents the maximum distance in pixels between two coordinates which can be considered equal. + float threshold() 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 diff --git a/src/core/qgssimplifymethod.cpp b/src/core/qgssimplifymethod.cpp index 154ee4919b0..17fe43ec3bc 100644 --- a/src/core/qgssimplifymethod.cpp +++ b/src/core/qgssimplifymethod.cpp @@ -21,6 +21,7 @@ QgsSimplifyMethod::QgsSimplifyMethod() : mMethodType( QgsSimplifyMethod::NoSimplification ) , mTolerance( 1 ) + , mThreshold( 1 ) , mForceLocalOptimization( true ) { } @@ -34,6 +35,7 @@ QgsSimplifyMethod& QgsSimplifyMethod::operator=( const QgsSimplifyMethod & rh ) { mMethodType = rh.mMethodType; mTolerance = rh.mTolerance; + mThreshold = rh.mThreshold; mForceLocalOptimization = rh.mForceLocalOptimization; return *this; diff --git a/src/core/qgssimplifymethod.h b/src/core/qgssimplifymethod.h index 009c471e892..2d7b99ab989 100644 --- a/src/core/qgssimplifymethod.h +++ b/src/core/qgssimplifymethod.h @@ -44,11 +44,16 @@ class CORE_EXPORT QgsSimplifyMethod //! Gets the simplification type inline MethodType methodType() const { return mMethodType; } - //! Sets the tolerance of simplification. Represents the maximum distance between two coordinates which can be considered equal + //! Sets the tolerance of simplification in map units. Represents the maximum distance in map units between two coordinates which can be considered equal. void setTolerance( double tolerance ); - //! Gets the tolerance of simplification + //! Gets the tolerance of simplification in map units . Represents the maximum distance in map units between two coordinates which can be considered equal. inline double tolerance() const { return mTolerance; } + //! Sets the simplification threshold in pixels. Represents the maximum distance in pixels between two coordinates which can be considered equal. + void setThreshold( float threshold ) { mThreshold = threshold; } + //! Gets the simplification threshold in pixels. Represents the maximum distance in pixels between two coordinates which can be considered equal. + inline float threshold() const { return mThreshold; } + //! 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 @@ -62,6 +67,8 @@ class CORE_EXPORT QgsSimplifyMethod MethodType mMethodType; //! Tolerance of simplification, it represents the maximum distance between two coordinates which can be considered equal double mTolerance; + /** Simplification threshold */ + float mThreshold; //! Simplification executes after fetch the geometries from provider, otherwise it executes, when supported, in provider before fetch the geometries bool mForceLocalOptimization; }; diff --git a/src/core/qgsvectorlayerrenderer.cpp b/src/core/qgsvectorlayerrenderer.cpp index c6d81d15a6e..98a18c8f53b 100644 --- a/src/core/qgsvectorlayerrenderer.cpp +++ b/src/core/qgsvectorlayerrenderer.cpp @@ -218,6 +218,8 @@ bool QgsVectorLayerRenderer::render() QgsSimplifyMethod simplifyMethod; simplifyMethod.setMethodType( QgsSimplifyMethod::OptimizeForRendering ); simplifyMethod.setTolerance( map2pixelTol ); + simplifyMethod.setThreshold( mSimplifyMethod.threshold() ); + simplifyMethod.setForceLocalOptimization( mSimplifyMethod.forceLocalOptimization() ); featureRequest.setSimplifyMethod( simplifyMethod ); diff --git a/src/providers/postgres/qgspostgresfeatureiterator.cpp b/src/providers/postgres/qgspostgresfeatureiterator.cpp index 5d24c131ab2..208f9fa64ac 100644 --- a/src/providers/postgres/qgspostgresfeatureiterator.cpp +++ b/src/providers/postgres/qgspostgresfeatureiterator.cpp @@ -364,12 +364,69 @@ bool QgsPostgresFeatureIterator::declareCursor( const QString& whereClause ) ? mSource->mRequestedGeomType : mSource->mDetectedGeomType ) ) != QGis::WKBPoint ) { + // PostGIS simplification method to use + QString simplifyPostgisMethod; + + // Simplify again with st_simplify after first simplification ? + bool postSimplification; + postSimplification = false; // default to false. Set to true only for postgis >= 2.2 when using st_removerepeatedpoints + + if ( mRequest.simplifyMethod().methodType() == QgsSimplifyMethod::OptimizeForRendering ) + { + // Optimize simplification for rendering + if ( mConn->majorVersion() < 2 ) + { + simplifyPostgisMethod = "snaptogrid"; + } + else + { + + // Default to st_snaptogrid + simplifyPostgisMethod = "st_snaptogrid"; + + if (( mConn->majorVersion() == 2 && mConn->minorVersion() >= 2 ) || + mConn->majorVersion() > 2 ) + { + // For postgis >= 2.2 Use ST_RemoveRepeatedPoints instead + // Do it only if threshold is <= 1 pixel to avoid holes in adjacent polygons + // We should perhaps use it always for Linestrings, even if threshold > 1 ? + if ( mRequest.simplifyMethod().threshold() <= 1.0 ) + { + simplifyPostgisMethod = "st_removerepeatedpoints"; + postSimplification = true; // Ask to apply a post-filtering simplification + } + } + } + } + else + { + // preserve topology + if ( mConn->majorVersion() < 2 ) + { + simplifyPostgisMethod = "simplifypreservetopology"; + } + else + { + simplifyPostgisMethod = "st_simplifypreservetopology"; + } + } + QgsDebugMsg( + QString( "PostGIS Server side simplification : threshold %1 pixels - method %2" ) + .arg( mRequest.simplifyMethod().threshold() ) + .arg( simplifyPostgisMethod ) + ); + geom = QString( "%1(%2,%3)" ) - .arg( mRequest.simplifyMethod().methodType() == QgsSimplifyMethod::OptimizeForRendering - ? ( mConn->majorVersion() < 2 ? "snaptogrid" : "st_snaptogrid" ) - : ( mConn->majorVersion() < 2 ? "simplifypreservetopology" : "st_simplifypreservetopology" ), - geom ) - .arg( mRequest.simplifyMethod().tolerance() * 0.8 ); //-> Default factor for the maximum displacement distance for simplification, similar as GeoServer does + .arg( simplifyPostgisMethod, geom ) + .arg( mRequest.simplifyMethod().tolerance() * 0.8 ); //-> Default factor for the maximum displacement distance for simplification, similar as GeoServer does + + // Post-simplification + if ( postSimplification ) + { + geom = QString( "st_simplify( %1, %2, true )" ) + .arg( geom ) + .arg( mRequest.simplifyMethod().tolerance() * 0.7 ); //-> We use a smaller tolerance than pre-filtering to be on the safe side + } } geom = QString( "%1(%2,'%3')" ) @@ -382,7 +439,7 @@ bool QgsPostgresFeatureIterator::declareCursor( const QString& whereClause ) } switch ( mSource->mPrimaryKeyType ) -{ + { case pktOid: query += delim + "oid"; delim = ',';