From f79dfa1551035eaec9c109531cbc2e7607beafc1 Mon Sep 17 00:00:00 2001 From: Alvaro Huarte Date: Tue, 21 Jan 2014 11:18:36 +0100 Subject: [PATCH] #9360R: enable ogr simplification for GDAL-OGR >= 1.11 --- src/providers/ogr/qgsogrfeatureiterator.cpp | 4 +- .../ogr/qgsogrgeometrysimplifier.cpp | 111 ++++++++++-------- src/providers/ogr/qgsogrgeometrysimplifier.h | 37 ++---- src/providers/ogr/qgsogrprovider.cpp | 3 +- 4 files changed, 77 insertions(+), 78 deletions(-) diff --git a/src/providers/ogr/qgsogrfeatureiterator.cpp b/src/providers/ogr/qgsogrfeatureiterator.cpp index 76782eeae3c..755a624df28 100644 --- a/src/providers/ogr/qgsogrfeatureiterator.cpp +++ b/src/providers/ogr/qgsogrfeatureiterator.cpp @@ -111,7 +111,7 @@ bool QgsOgrFeatureIterator::prepareSimplification( const QgsSimplifyMethod& simp QgsSimplifyMethod::MethodType methodType = simplifyMethod.methodType(); Q_UNUSED( methodType); -#if defined(HAVE_OGR_GEOMETRY_CLASS) +#if defined(GDAL_VERSION_NUM) && defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0) if ( methodType == QgsSimplifyMethod::OptimizeForRendering ) { int simplifyFlags = QgsMapToPixelSimplifier::SimplifyGeometry | QgsMapToPixelSimplifier::SimplifyEnvelope; @@ -134,7 +134,7 @@ bool QgsOgrFeatureIterator::prepareSimplification( const QgsSimplifyMethod& simp bool QgsOgrFeatureIterator::providerCanSimplify( QgsSimplifyMethod::MethodType methodType ) const { -#if defined(HAVE_OGR_GEOMETRY_CLASS) +#if defined(GDAL_VERSION_NUM) && defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0) if ( methodType == QgsSimplifyMethod::OptimizeForRendering ) { return true; diff --git a/src/providers/ogr/qgsogrgeometrysimplifier.cpp b/src/providers/ogr/qgsogrgeometrysimplifier.cpp index a532a0eb943..433f571b859 100644 --- a/src/providers/ogr/qgsogrgeometrysimplifier.cpp +++ b/src/providers/ogr/qgsogrgeometrysimplifier.cpp @@ -25,6 +25,7 @@ QgsOgrAbstractGeometrySimplifier::~QgsOgrAbstractGeometrySimplifier() /***************************************************************************/ #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1900 + QgsOgrTopologyPreservingSimplifier::QgsOgrTopologyPreservingSimplifier( double tolerance ) : QgsTopologyPreservingSimplifier( tolerance ) { @@ -59,10 +60,7 @@ bool QgsOgrTopologyPreservingSimplifier::simplifyGeometry( OGRGeometryH geometry /***************************************************************************/ -#if defined(HAVE_OGR_GEOMETRY_CLASS) - -// Use OgrGeometry class to speed up simplification on provider side -#include +#if defined(GDAL_VERSION_NUM) && defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0) QgsOgrMapToPixelSimplifier::QgsOgrMapToPixelSimplifier( int simplifyFlags, double map2pixelTol ) : QgsMapToPixelSimplifier( simplifyFlags, map2pixelTol ) @@ -81,7 +79,7 @@ QgsOgrMapToPixelSimplifier::~QgsOgrMapToPixelSimplifier() } //! Returns a point buffer of the specified size -OGRRawPoint* QgsOgrMapToPixelSimplifier::mallocPoints( int numPoints ) +QgsPoint* QgsOgrMapToPixelSimplifier::mallocPoints( int numPoints ) { if ( mPointBufferPtr && mPointBufferCount < numPoints ) { @@ -91,11 +89,41 @@ OGRRawPoint* QgsOgrMapToPixelSimplifier::mallocPoints( int numPoints ) if ( !mPointBufferPtr ) { mPointBufferCount = numPoints; - mPointBufferPtr = ( OGRRawPoint* )OGRMalloc( mPointBufferCount * sizeof( OGRRawPoint ) ); + mPointBufferPtr = ( QgsPoint* )OGRMalloc( mPointBufferCount * sizeof( QgsPoint ) ); } return mPointBufferPtr; } +//! Returns a point buffer of the specified envelope +QgsPoint* QgsOgrMapToPixelSimplifier::getEnvelopePoints( const QgsRectangle& envelope, int& numPoints, bool isaLinearRing ) +{ + QgsPoint* points = NULL; + + double x1 = envelope.xMinimum(); + double y1 = envelope.yMinimum(); + double x2 = envelope.xMaximum(); + double y2 = envelope.yMaximum(); + + if ( isaLinearRing ) + { + numPoints = 5; + points = mallocPoints( numPoints ); + points[0].set( x1, y1 ); + points[1].set( x2, y1 ); + points[2].set( x2, y2 ); + points[3].set( x1, y2 ); + points[4].set( x1, y1 ); + } + else + { + numPoints = 2; + points = mallocPoints( numPoints ); + points[0].set( x1, y1 ); + points[1].set( x2, y2 ); + } + return points; +} + ////////////////////////////////////////////////////////////////////////////////////////////// // Helper simplification methods @@ -138,52 +166,29 @@ bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( QGis::GeometryType geometr } //! Simplifies the OGR-geometry (Removing duplicated points) when is applied the specified map2pixel context -bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( OGRGeometry* geometry, bool isaLinearRing ) +bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( OGRGeometryH geometry, bool isaLinearRing ) { - OGRwkbGeometryType wkbGeometryType = wkbFlatten( geometry->getGeometryType() ); + OGRwkbGeometryType wkbGeometryType = wkbFlatten( OGR_G_GetGeometryType( geometry ) ); // Simplify the geometry rewriting temporally its WKB-stream for saving calloc's. if ( wkbGeometryType == wkbLineString ) { - OGRLineString* lineString = ( OGRLineString* )geometry; + int numPoints = OGR_G_GetPointCount( geometry ); - int numPoints = lineString->getNumPoints(); if (( isaLinearRing && numPoints <= 5 ) || ( !isaLinearRing && numPoints <= 4 ) ) return false; OGREnvelope env; - lineString->getEnvelope( &env ); + OGR_G_GetEnvelope( geometry, &env ); QgsRectangle envelope( env.MinX, env.MinY, env.MaxX, env.MaxY ); // Can replace the geometry by its BBOX ? if (( mSimplifyFlags & QgsMapToPixelSimplifier::SimplifyEnvelope ) && canbeGeneralizedByMapBoundingBox( envelope ) ) { - OGRRawPoint* points = NULL; + QgsPoint* points = getEnvelopePoints( envelope, numPoints, isaLinearRing ); - double x1 = envelope.xMinimum(); - double y1 = envelope.yMinimum(); - double x2 = envelope.xMaximum(); - double y2 = envelope.yMaximum(); - - if ( isaLinearRing ) - { - numPoints = 5; - points = mallocPoints( numPoints ); - points[0].x = x1; points[0].y = y1; - points[1].x = x2; points[1].y = y1; - points[2].x = x2; points[2].y = y2; - points[3].x = x1; points[3].y = y2; - points[4].x = x1; points[4].y = y1; - } - else - { - numPoints = 2; - points = mallocPoints( numPoints ); - points[0].x = x1; points[0].y = y1; - points[1].x = x2; points[1].y = y2; - } - lineString->setPoints( numPoints, points ); - lineString->flattenTo2D(); + setGeometryPoints( geometry, points, numPoints ); + OGR_G_FlattenTo2D( geometry ); return true; } @@ -192,27 +197,29 @@ bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( OGRGeometry* geometry, boo QGis::GeometryType geometryType = isaLinearRing ? QGis::Polygon : QGis::Line; int numSimplifiedPoints = 0; - OGRRawPoint* points = mallocPoints( numPoints ); + QgsPoint* points = mallocPoints( numPoints ); double* xptr = ( double* )points; double* yptr = xptr + 1; - lineString->getPoints( points ); + OGR_G_GetPoints( geometry, xptr, 16, yptr, 16, NULL, 0 ); if ( simplifyOgrGeometry( geometryType, xptr, 16, yptr, 16, numPoints, numSimplifiedPoints ) ) { - lineString->setPoints( numSimplifiedPoints, points ); - lineString->flattenTo2D(); + if (( isaLinearRing && numSimplifiedPoints <= 4 ) || ( !isaLinearRing && numSimplifiedPoints <= 1 ) ) + points = getEnvelopePoints( envelope, numSimplifiedPoints, isaLinearRing ); + + setGeometryPoints( geometry, points, numSimplifiedPoints ); + OGR_G_FlattenTo2D( geometry ); } return numSimplifiedPoints != numPoints; } } else if ( wkbGeometryType == wkbPolygon ) { - OGRPolygon* polygon = ( OGRPolygon* )geometry; - bool result = simplifyOgrGeometry( polygon->getExteriorRing(), true ); + bool result = simplifyOgrGeometry( OGR_G_GetGeometryRef( geometry, 0 ), true ); - for ( int i = 0, numInteriorRings = polygon->getNumInteriorRings(); i < numInteriorRings; ++i ) + for ( int i = 1, numInteriorRings = OGR_G_GetGeometryCount( geometry ); i < numInteriorRings; ++i ) { - result |= simplifyOgrGeometry( polygon->getInteriorRing( i ), true ); + result |= simplifyOgrGeometry( OGR_G_GetGeometryRef( geometry, i ), true ); } if ( result ) @@ -222,12 +229,11 @@ bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( OGRGeometry* geometry, boo } else if ( wkbGeometryType == wkbMultiLineString || wkbGeometryType == wkbMultiPolygon ) { - OGRGeometryCollection* collection = ( OGRGeometryCollection* )geometry; bool result = false; - for ( int i = 0, numGeometries = collection->getNumGeometries(); i < numGeometries; ++i ) + for ( int i = 0, numGeometries = OGR_G_GetGeometryCount( geometry ); i < numGeometries; ++i ) { - result |= simplifyOgrGeometry( collection->getGeometryRef( i ), wkbGeometryType == wkbMultiPolygon ); + result |= simplifyOgrGeometry( OGR_G_GetGeometryRef( geometry, i ), wkbGeometryType == wkbMultiPolygon ); } if ( result ) @@ -239,6 +245,15 @@ bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( OGRGeometry* geometry, boo return false; } +//! Load a point array to the specified LineString geometry +void QgsOgrMapToPixelSimplifier::setGeometryPoints( OGRGeometryH geometry, QgsPoint* points, int numPoints ) +{ + double* xptr = ( double* )points; + double* yptr = xptr + 1; + + OGR_G_SetPoints( geometry, numPoints, xptr, 16, yptr, 16, NULL, 0 ); +} + ////////////////////////////////////////////////////////////////////////////////////////////// //! Simplifies the specified geometry @@ -248,7 +263,7 @@ bool QgsOgrMapToPixelSimplifier::simplifyGeometry( OGRGeometryH geometry ) if ( wkbGeometryType == wkbLineString || wkbGeometryType == wkbPolygon ) { - return simplifyOgrGeometry( (OGRGeometry*) geometry, wkbGeometryType == wkbPolygon ); + return simplifyOgrGeometry( geometry, wkbGeometryType == wkbPolygon ); } return false; diff --git a/src/providers/ogr/qgsogrgeometrysimplifier.h b/src/providers/ogr/qgsogrgeometrysimplifier.h index e7faf27c890..54ce3505624 100644 --- a/src/providers/ogr/qgsogrgeometrysimplifier.h +++ b/src/providers/ogr/qgsogrgeometrysimplifier.h @@ -18,29 +18,9 @@ #define QGSOGRGEOMETRYSIMPLIFIER_H #include "qgsmaptopixelgeometrysimplifier.h" -#include +#include "qgspoint.h" -/* TODO: - * Disable OGR-simplification on provider side because of OGRGeometry class - * (GDAL C++ API) is not available in current QGIS builds. - * This simplification is ~5-10% faster than simplification on QGIS side - * (for very complex polygons up to ~20%). - * - * While GDAL C API has not published the needed method 'OGR_G_SetPoints()' - * to rewrite the geometry of a LineString/LinearRing in one single call, - * we can not enable the OGR-simplification to change the current disabled - * references of OGRGeometry* (GDAL C++ API) to OGRGeometryH (GDAL C API). - * - * Search in 'qgsogrgeometrysimplifier.cpp' : lineString->setPoints(...); - * We can not use 'OGR_G_SetPoint(...)' because of each call reallocs the - * point array of the geometry and it is very-very slow. - * -#if defined(__cplusplus) - #define HAVE_OGR_GEOMETRY_CLASS 1 - class OGRGeometry; - class OGRRawPoint; -#endif - */ +#include /** * Abstract base class for simplify OGR-geometries using a specific algorithm @@ -72,7 +52,7 @@ class QgsOgrTopologyPreservingSimplifier : public QgsOgrAbstractGeometrySimplifi }; #endif -#if defined(HAVE_OGR_GEOMETRY_CLASS) +#if defined(GDAL_VERSION_NUM) && defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0) /** * OGR implementation of GeometrySimplifier using the "MapToPixel" algorithm * @@ -87,17 +67,22 @@ class QgsOgrMapToPixelSimplifier : public QgsOgrAbstractGeometrySimplifier, QgsM private: //! Point memory buffer for optimize the simplification process - OGRRawPoint* mPointBufferPtr; + QgsPoint* mPointBufferPtr; //! Current Point memory buffer size int mPointBufferCount; //! Simplifies the OGR-geometry (Removing duplicated points) when is applied the specified map2pixel context bool simplifyOgrGeometry( QGis::GeometryType geometryType, double* xptr, int xStride, double* yptr, int yStride, int pointCount, int& pointSimplifiedCount ); //! Simplifies the OGR-geometry (Removing duplicated points) when is applied the specified map2pixel context - bool simplifyOgrGeometry( OGRGeometry* geometry, bool isaLinearRing ); + bool simplifyOgrGeometry( OGRGeometryH geometry, bool isaLinearRing ); //! Returns a point buffer of the specified size - OGRRawPoint* mallocPoints( int numPoints ); + QgsPoint* mallocPoints( int numPoints ); + //! Returns a point buffer of the specified envelope + QgsPoint* getEnvelopePoints( const QgsRectangle& envelope, int& numPoints, bool isaLinearRing ); + + //! Load a point array to the specified LineString geometry + static void setGeometryPoints( OGRGeometryH geometry, QgsPoint* points, int numPoints ); public: //! Simplifies the specified geometry diff --git a/src/providers/ogr/qgsogrprovider.cpp b/src/providers/ogr/qgsogrprovider.cpp index c7a3d19c85f..563a8a72a0e 100644 --- a/src/providers/ogr/qgsogrprovider.cpp +++ b/src/providers/ogr/qgsogrprovider.cpp @@ -45,7 +45,6 @@ email : sherman at mrcc.com #include "qgsgeometry.h" #include "qgscoordinatereferencesystem.h" #include "qgsvectorlayerimport.h" -#include "qgsogrgeometrysimplifier.h" static const QString TEXT_PROVIDER_KEY = "ogr"; static const QString TEXT_PROVIDER_DESCRIPTION = @@ -1496,7 +1495,7 @@ int QgsOgrProvider::capabilities() const } // supports geometry simplification on provider side -#if defined(HAVE_OGR_GEOMETRY_CLASS) +#if defined(GDAL_VERSION_NUM) && defined(GDAL_COMPUTE_VERSION) && GDAL_VERSION_NUM >= GDAL_COMPUTE_VERSION(1,11,0) ability |= QgsVectorDataProvider::SimplifyGeometries; #endif #if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1900