3 changes: 0 additions & 3 deletions python/core/qgssimplifymethod.sip
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ class QgsSimplifyMethod
/** Gets the tolerance of simplification */
double tolerance() const;

/** Returns the optimal tolerance for Douglas-Peucker simplification algorithms */
double toleranceForDouglasPeuckerAlgorithms() 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 */
Expand Down
5 changes: 4 additions & 1 deletion src/core/qgsgeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4697,7 +4697,10 @@ bool QgsGeometry::exportWkbToGeos() const
}
sequence << QgsPoint( *x, *y );
}
lines << createGeosLineString( sequence );

// ignore invalid parts, it can come from ST_Simplify operations
if ( sequence.count() > 1 )
lines << createGeosLineString( sequence );
}
mGeos = createGeosCollection( GEOS_MULTILINESTRING, lines );
mDirtyGeos = false;
Expand Down
12 changes: 6 additions & 6 deletions src/core/qgsmaptopixelgeometrysimplifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
#include "qgsmaptopixelgeometrysimplifier.h"
#include "qgsapplication.h"

QgsMapToPixelSimplifier::QgsMapToPixelSimplifier( int simplifyFlags, double map2pixelTol )
QgsMapToPixelSimplifier::QgsMapToPixelSimplifier( int simplifyFlags, double tolerance )
: mSimplifyFlags( simplifyFlags )
, mMapToPixelTol( map2pixelTol )
, mTolerance( tolerance )
{
}
QgsMapToPixelSimplifier::~QgsMapToPixelSimplifier()
Expand Down Expand Up @@ -330,13 +330,13 @@ QgsGeometry* QgsMapToPixelSimplifier::simplify( QgsGeometry* geometry ) const
unsigned char* wkb = ( unsigned char* )malloc( wkbSize );
memcpy( wkb, geometry->asWkb(), wkbSize );
g->fromWkb( wkb, wkbSize );
simplifyGeometry( g, mSimplifyFlags, mMapToPixelTol );
simplifyGeometry( g, mSimplifyFlags, mTolerance );

return g;
}

//! Simplifies the geometry (Removing duplicated points) when is applied the specified map2pixel context
bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry, int simplifyFlags, double map2pixelTol )
bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry, int simplifyFlags, double tolerance )
{
size_t targetWkbSize = 0;

Expand All @@ -351,7 +351,7 @@ bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry, int simpl
size_t wkbSize = geometry->wkbSize( );

// Simplify the geometry rewriting temporally its WKB-stream for saving calloc's.
if ( simplifyWkbGeometry( simplifyFlags, wkbType, wkb, wkbSize, wkb, targetWkbSize, envelope, map2pixelTol ) )
if ( simplifyWkbGeometry( simplifyFlags, wkbType, wkb, wkbSize, wkb, targetWkbSize, envelope, tolerance ) )
{
unsigned char* targetWkb = ( unsigned char* )malloc( targetWkbSize );
memcpy( targetWkb, wkb, targetWkbSize );
Expand All @@ -364,5 +364,5 @@ bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry, int simpl
//! Simplifies the geometry (Removing duplicated points) when is applied the specified map2pixel context
bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry ) const
{
return simplifyGeometry( geometry, mSimplifyFlags, mMapToPixelTol );
return simplifyGeometry( geometry, mSimplifyFlags, mTolerance );
}
10 changes: 5 additions & 5 deletions src/core/qgsmaptopixelgeometrysimplifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier
{
public:
QgsMapToPixelSimplifier( int simplifyFlags, double map2pixelTol );
QgsMapToPixelSimplifier( int simplifyFlags, double tolerance );
virtual ~QgsMapToPixelSimplifier();

//! Applicable simplification flags
Expand All @@ -51,8 +51,8 @@ class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier
//! Current simplification flags
int mSimplifyFlags;

//! Map2Pixel tolerance for the simplification
double mMapToPixelTol;
//! Distance tolerance for the simplification
double mTolerance;

//! Returns the squared 2D-distance of the vector defined by the two points specified
static float calculateLengthSquared2D( double x1, double y1, double x2, double y2 );
Expand All @@ -73,10 +73,10 @@ class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier
static bool canbeGeneralizedByMapBoundingBox( const QgsRectangle& envelope, double map2pixelTol );

//! Returns whether the envelope can be replaced by its BBOX when is applied the specified map2pixel context
inline bool canbeGeneralizedByMapBoundingBox( const QgsRectangle& envelope ) const { return canbeGeneralizedByMapBoundingBox( envelope, mMapToPixelTol ); }
inline bool canbeGeneralizedByMapBoundingBox( const QgsRectangle& envelope ) const { return canbeGeneralizedByMapBoundingBox( envelope, mTolerance ); }

//! Simplifies the geometry when is applied the specified map2pixel context
static bool simplifyGeometry( QgsGeometry* geometry, int simplifyFlags, double map2pixelTol );
static bool simplifyGeometry( QgsGeometry* geometry, int simplifyFlags, double tolerance );

};

Expand Down
6 changes: 0 additions & 6 deletions src/core/qgssimplifymethod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,6 @@ void QgsSimplifyMethod::setForceLocalOptimization( bool localOptimization )
mForceLocalOptimization = localOptimization;
}

double QgsSimplifyMethod::toleranceForDouglasPeuckerAlgorithms() const
{
//TODO: define more precise value, now, it is experimental but conservative
return mTolerance / 5.0;
}

QgsAbstractGeometrySimplifier* QgsSimplifyMethod::createGeometrySimplifier( const QgsSimplifyMethod& simplifyMethod )
{
QgsSimplifyMethod::MethodType methodType = simplifyMethod.methodType();
Expand Down
3 changes: 0 additions & 3 deletions src/core/qgssimplifymethod.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ class CORE_EXPORT QgsSimplifyMethod
//! Gets the tolerance of simplification
inline double tolerance() const { return mTolerance; }

//! Returns the optimal tolerance for Douglas-Peucker simplification algorithms
double toleranceForDouglasPeuckerAlgorithms() 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
Expand Down
6 changes: 3 additions & 3 deletions src/providers/ogr/qgsogrgeometrysimplifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ bool QgsOgrTopologyPreservingSimplifier::simplifyGeometry( OGRGeometryH geometry
#if defined(GDAL_VERSION_NUM) && defined(GDAL_COMPUTE_VERSION)
#if GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0)

QgsOgrMapToPixelSimplifier::QgsOgrMapToPixelSimplifier( int simplifyFlags, double map2pixelTol )
: QgsMapToPixelSimplifier( simplifyFlags, map2pixelTol )
QgsOgrMapToPixelSimplifier::QgsOgrMapToPixelSimplifier( int simplifyFlags, double tolerance )
: QgsMapToPixelSimplifier( simplifyFlags, tolerance )
, mPointBufferPtr( NULL )
, mPointBufferCount( 0 )
{
Expand Down Expand Up @@ -137,7 +137,7 @@ bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( QGis::GeometryType geometr
if ( geometryType == QGis::Point || geometryType == QGis::UnknownGeometry ) return false;
pointSimplifiedCount = 0;

double map2pixelTol = mMapToPixelTol * mMapToPixelTol; //-> Use mappixelTol for 'LengthSquare' calculations.
double map2pixelTol = mTolerance * mTolerance; //-> Use mappixelTol for 'LengthSquare' calculations.
double x, y, lastX = 0, lastY = 0;

char* xsourcePtr = ( char* )xptr;
Expand Down
2 changes: 1 addition & 1 deletion src/providers/ogr/qgsogrgeometrysimplifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class QgsOgrTopologyPreservingSimplifier : public QgsOgrAbstractGeometrySimplifi
class QgsOgrMapToPixelSimplifier : public QgsOgrAbstractGeometrySimplifier, QgsMapToPixelSimplifier
{
public:
QgsOgrMapToPixelSimplifier( int simplifyFlags, double map2pixelTol );
QgsOgrMapToPixelSimplifier( int simplifyFlags, double tolerance );
virtual ~QgsOgrMapToPixelSimplifier();

private:
Expand Down
57 changes: 53 additions & 4 deletions src/providers/postgres/qgspostgresfeatureiterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
***************************************************************************/
#include "qgspostgresfeatureiterator.h"
#include "qgspostgresprovider.h"
#include "qgsgeometry.h"

#include "qgslogger.h"
#include "qgsmessagelog.h"
Expand Down Expand Up @@ -292,6 +293,7 @@ QString QgsPostgresFeatureIterator::whereClauseRect()
bool QgsPostgresFeatureIterator::declareCursor( const QString& whereClause )
{
mFetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) && !P->mGeometryColumn.isNull();
bool simplifyGeometry = false;

try
{
Expand All @@ -303,11 +305,10 @@ bool QgsPostgresFeatureIterator::declareCursor( const QString& whereClause )
{
QString simplifyFunctionName = simplifyMethod.methodType() == QgsSimplifyMethod::OptimizeForRendering
? ( P->mConnectionRO->majorVersion() < 2 ? "simplify" : "st_simplify" )
: ( P->mConnectionRO->majorVersion() < 2 ? "simplifypreservetopology" : "st_simplifypreservetopology" );
: ( P->mConnectionRO->majorVersion() < 2 ? "simplifypreservetopology" : "st_simplifypreservetopology" );

double tolerance = simplifyMethod.methodType() == QgsSimplifyMethod::OptimizeForRendering
? simplifyMethod.toleranceForDouglasPeuckerAlgorithms()
: simplifyMethod.tolerance();
double tolerance = simplifyMethod.tolerance() * 0.8; //-> Default factor for the maximum displacement distance for simplification, similar as GeoServer does
simplifyGeometry = simplifyMethod.methodType() == QgsSimplifyMethod::OptimizeForRendering;

query += QString( "%1(%5(%2%3,%6),'%4')" )
.arg( P->mConnectionRO->majorVersion() < 2 ? "asbinary" : "st_asbinary" )
Expand Down Expand Up @@ -368,6 +369,17 @@ bool QgsPostgresFeatureIterator::declareCursor( const QString& whereClause )
query += delim + P->mConnectionRO->fieldExpression( P->field( idx ) );
}

// query BBOX of geometries to redefine the geometries collapsed by ST_Simplify()
if ( simplifyGeometry && !( P->mConnectionRO->majorVersion() >= 2 && P->mConnectionRO->minorVersion() >= 1 ) )
{
query += QString( ",%1(%5(%2)%3,'%4')" )
.arg( P->mConnectionRO->majorVersion() < 2 ? "asbinary" : "st_asbinary" )
.arg( P->quotedIdentifier( P->mGeometryColumn ) )
.arg( P->mSpatialColType == sctGeography ? "::geometry" : "" )
.arg( P->endianString() )
.arg( P->mConnectionRO->majorVersion() < 2 ? "envelope" : "st_envelope" );
}

query += " FROM " + P->mQuery;

if ( !whereClause.isEmpty() )
Expand Down Expand Up @@ -591,6 +603,43 @@ bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int
getFeatureAttribute( idx, queryResult, row, col, feature );
}

// fix collapsed geometries by ST_Simplify() using the BBOX fetched from the current query
const QgsSimplifyMethod& simplifyMethod = mRequest.simplifyMethod();
if ( mFetchGeometry && !simplifyMethod.forceLocalOptimization() && simplifyMethod.methodType() == QgsSimplifyMethod::OptimizeForRendering )
{
QgsGeometry* geometry = feature.geometry();

if ( !( P->mConnectionRO->majorVersion() >= 2 && P->mConnectionRO->minorVersion() >= 1 ) && ( !geometry || geometry->length() == 0 ) )
{
int returnedLength = ::PQgetlength( queryResult.result(), row, col );

if ( returnedLength > 0 )
{
unsigned char *featureGeom = new unsigned char[returnedLength + 1];
memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength );
memset( featureGeom + returnedLength, 0, 1 );

QgsGeometry *envelope = new QgsGeometry();
envelope->fromWkb( featureGeom, returnedLength + 1 );

if ( QGis::flatType( QGis::singleType( P->geometryType() ) ) == QGis::WKBPolygon )
{
feature.setGeometry( envelope );
}
else
{
QgsPolyline polyline;
polyline.append( envelope->vertexAt( 0 ) );
polyline.append( envelope->vertexAt( 2 ) );
delete envelope;

geometry = QgsGeometry::fromPolyline( polyline );
feature.setGeometry( geometry );
}
}
}
}

return true;
}
catch ( QgsPostgresProvider::PGFieldNotFound )
Expand Down