Skip to content

Commit

Permalink
#8725-R: FeatureIterator use SimplifyMethod
Browse files Browse the repository at this point in the history
AbstractFeatureIterator use SimplifyMethod to simplify locally the
geometries fetched from data source (provider)
  • Loading branch information
ahuarte47 authored and m-kuhn committed Jan 15, 2014
1 parent c283402 commit 0ec7d35
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 65 deletions.
52 changes: 49 additions & 3 deletions src/core/qgsfeatureiterator.cpp
Expand Up @@ -15,33 +15,79 @@
#include "qgsfeatureiterator.h"
#include "qgslogger.h"

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

QgsAbstractFeatureIterator::QgsAbstractFeatureIterator( const QgsFeatureRequest& request )
: mRequest( request )
, mClosed( false )
, refs( 0 )
, mGeometrySimplifier( NULL )
{
const QgsSimplifyMethod& simplifyMethod = request.simplifyMethod();

if ( simplifyMethod.methodType() != QgsSimplifyMethod::NoSimplification && simplifyMethod.forceLocalOptimization() )
{
QgsSimplifyMethod::MethodType methodType = simplifyMethod.methodType();

if ( methodType == QgsSimplifyMethod::OptimizeForRendering )
{
int simplifyFlags = QgsMapToPixelSimplifier::SimplifyGeometry | QgsMapToPixelSimplifier::SimplifyEnvelope;
mGeometrySimplifier = new QgsMapToPixelSimplifier( simplifyFlags, simplifyMethod.tolerance() );
}
else
if ( methodType == QgsSimplifyMethod::PreserveTopology )
{
mGeometrySimplifier = new QgsTopologyPreservingSimplifier( simplifyMethod.tolerance() );
}
else
{
QgsDebugMsg( QString( "Simplification method type (%1) is not recognised" ).arg( methodType ) );
}
}
}

QgsAbstractFeatureIterator::~QgsAbstractFeatureIterator()
{
if ( mGeometrySimplifier )
{
delete mGeometrySimplifier;
mGeometrySimplifier = NULL;
}
}

bool QgsAbstractFeatureIterator::nextFeature( QgsFeature& f )
{
bool dataOk = false;

switch ( mRequest.filterType() )
{
case QgsFeatureRequest::FilterExpression:
return nextFeatureFilterExpression( f );
dataOk = nextFeatureFilterExpression( f );
break;

case QgsFeatureRequest::FilterFids:
return nextFeatureFilterFids( f );
dataOk = nextFeatureFilterFids( f );
break;

default:
return fetchFeature( f );
dataOk = fetchFeature( f );
break;
}

// simplify locally the geometry using the simplifier defined in constructor
if ( dataOk && mGeometrySimplifier )
{
QgsGeometry* geometry = f.geometry();

if ( geometry )
{
QGis::GeometryType geometryType = geometry->type();
if ( geometryType == QGis::Line || geometryType == QGis::Polygon ) mGeometrySimplifier->simplifyGeometry( geometry );
}
}
return dataOk;
}

bool QgsAbstractFeatureIterator::nextFeatureFilterExpression( QgsFeature& f )
Expand Down
5 changes: 5 additions & 0 deletions src/core/qgsfeatureiterator.h
Expand Up @@ -18,6 +18,7 @@
#include "qgsfeaturerequest.h"
#include "qgslogger.h"

class QgsAbstractGeometrySimplifier;

/** \ingroup core
* Internal feature iterator to be implemented within data providers
Expand Down Expand Up @@ -85,6 +86,10 @@ class CORE_EXPORT QgsAbstractFeatureIterator
void ref(); //!< add reference
void deref(); //!< remove reference, delete if refs == 0
friend class QgsFeatureIterator;

private:
//! optional object to locally simplify geometries fetched by this feature iterator
QgsAbstractGeometrySimplifier* mGeometrySimplifier;
};


Expand Down
45 changes: 7 additions & 38 deletions src/core/qgsmaptopixelgeometrysimplifier.cpp
Expand Up @@ -18,11 +18,9 @@
#include "qgsmaptopixelgeometrysimplifier.h"
#include "qgsapplication.h"

QgsMapToPixelSimplifier::QgsMapToPixelSimplifier( int simplifyFlags, const QgsCoordinateTransform* coordinateTransform, const QgsMapToPixel* mapTolPixel, float mapToPixelTol )
QgsMapToPixelSimplifier::QgsMapToPixelSimplifier( int simplifyFlags, double map2pixelTol )
: mSimplifyFlags( simplifyFlags )
, mMapCoordTransform( coordinateTransform )
, mMapToPixel( mapTolPixel )
, mMapToPixelTol( mapToPixelTol )
, mMapToPixelTol( map2pixelTol )
{
}
QgsMapToPixelSimplifier::~QgsMapToPixelSimplifier()
Expand All @@ -41,32 +39,6 @@ float QgsMapToPixelSimplifier::calculateLengthSquared2D( double x1, double y1, d
return vx*vx + vy*vy;
}

//! Returns the MapTolerance for transform between map coordinates and device coordinates
float QgsMapToPixelSimplifier::calculateViewPixelTolerance( const QgsRectangle& boundingRect, const QgsCoordinateTransform* ct, const QgsMapToPixel* mapToPixel )
{
double mapUnitsPerPixel = mapToPixel ? mapToPixel->mapUnitsPerPixel() : 1.0;
double mapUnitsFactor = 1;

// Calculate one aprox factor of the size of the BBOX from the source CoordinateSystem to the target CoordinateSystem
if ( ct && !(( QgsCoordinateTransform* )ct )->isShortCircuited() )
{
QgsRectangle sourceRect = boundingRect;
QgsRectangle targetRect = ct->transform( sourceRect );

QgsPoint minimumSrcPoint( sourceRect.xMinimum(), sourceRect.yMinimum() );
QgsPoint maximumSrcPoint( sourceRect.xMaximum(), sourceRect.yMaximum() );
QgsPoint minimumDstPoint( targetRect.xMinimum(), targetRect.yMinimum() );
QgsPoint maximumDstPoint( targetRect.xMaximum(), targetRect.yMaximum() );

double sourceHypothenuse = sqrt( calculateLengthSquared2D( minimumSrcPoint.x(), minimumSrcPoint.y(), maximumSrcPoint.x(), maximumSrcPoint.y() ) );
double targetHypothenuse = sqrt( calculateLengthSquared2D( minimumDstPoint.x(), minimumDstPoint.y(), maximumDstPoint.x(), maximumDstPoint.y() ) );

if ( targetHypothenuse != 0 )
mapUnitsFactor = sourceHypothenuse / targetHypothenuse;
}
return ( float )( mapUnitsPerPixel * mapUnitsFactor );
}

//! Returns the BBOX of the specified WKB-point stream
inline static QgsRectangle calculateBoundingBox( QGis::WkbType wkbType, unsigned char* wkb, size_t numPoints )
{
Expand Down Expand Up @@ -169,7 +141,7 @@ inline static bool generalizeWkbGeometry( QGis::WkbType wkbType, unsigned char*
}

//! Simplify the WKB-geometry using the specified tolerance
bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, unsigned char* sourceWkb, size_t sourceWkbSize, unsigned char* targetWkb, size_t& targetWkbSize, const QgsRectangle& envelope, float map2pixelTol, bool writeHeader, bool isaLinearRing )
bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, unsigned char* sourceWkb, size_t sourceWkbSize, unsigned char* targetWkb, size_t& targetWkbSize, const QgsRectangle& envelope, double map2pixelTol, bool writeHeader, bool isaLinearRing )
{
bool canbeGeneralizable = true;
bool hasZValue = QGis::wkbDimensions( wkbType ) == 3;
Expand Down Expand Up @@ -339,10 +311,8 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry( int simplifyFlags, QGis::WkbT
//////////////////////////////////////////////////////////////////////////////////////////////

//! Returns whether the envelope can be replaced by its BBOX when is applied the specified map2pixel context
bool QgsMapToPixelSimplifier::canbeGeneralizedByMapBoundingBox( const QgsRectangle& envelope, const QgsCoordinateTransform* coordinateTransform, const QgsMapToPixel* mapToPixel, float mapToPixelTol )
bool QgsMapToPixelSimplifier::canbeGeneralizedByMapBoundingBox( const QgsRectangle& envelope, double map2pixelTol )
{
double map2pixelTol = mapToPixelTol * calculateViewPixelTolerance( envelope, coordinateTransform, mapToPixel );

// Can replace the geometry by its BBOX ?
if (( envelope.xMaximum() - envelope.xMinimum() ) < map2pixelTol && ( envelope.yMaximum() - envelope.yMinimum() ) < map2pixelTol )
{
Expand All @@ -360,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, mMapCoordTransform, mMapToPixel, mMapToPixelTol );
simplifyGeometry( g, mSimplifyFlags, mMapToPixelTol );

return g;
}

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

Expand All @@ -376,7 +346,6 @@ bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry* geometry, int simpl

QgsRectangle envelope = geometry->boundingBox();
QGis::WkbType wkbType = geometry->wkbType();
double map2pixelTol = mapToPixelTol * calculateViewPixelTolerance( envelope, coordinateTransform, mapToPixel );

unsigned char* wkb = ( unsigned char* )geometry->asWkb( );
size_t wkbSize = geometry->wkbSize( );
Expand All @@ -395,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, mMapCoordTransform, mMapToPixel, mMapToPixelTol );
return simplifyGeometry( geometry, mSimplifyFlags, mMapToPixelTol );
}
31 changes: 7 additions & 24 deletions src/core/qgsmaptopixelgeometrysimplifier.h
Expand Up @@ -32,7 +32,7 @@
class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier
{
public:
QgsMapToPixelSimplifier( int simplifyFlags, const QgsCoordinateTransform* coordinateTransform, const QgsMapToPixel* mapToPixel, float mapToPixelTol );
QgsMapToPixelSimplifier( int simplifyFlags, double map2pixelTol );
virtual ~QgsMapToPixelSimplifier();

//! Applicable simplification flags
Expand All @@ -45,37 +45,22 @@ class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier

private:
//! Simplify the WKB-geometry using the specified tolerance
static bool simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, unsigned char* sourceWkb, size_t sourceWkbSize, unsigned char* targetWkb, size_t& targetWkbSize, const QgsRectangle& envelope, float map2pixelTol, bool writeHeader = true, bool isaLinearRing = false );
static bool simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, unsigned char* sourceWkb, size_t sourceWkbSize, unsigned char* targetWkb, size_t& targetWkbSize, const QgsRectangle& envelope, double map2pixelTol, bool writeHeader = true, bool isaLinearRing = false );

protected:
//! Current simplification flags
int mSimplifyFlags;

//! For transformation between coordinate systems from current layer to map target. Can be 0 if on-the-fly reprojection is not used
const QgsCoordinateTransform* mMapCoordTransform;
//! For transformation between map coordinates and device coordinates
const QgsMapToPixel* mMapToPixel;
//! Factor tolterance to apply in transformation between map coordinates and device coordinates
float mMapToPixelTol;
//! Map2Pixel tolerance for the simplification
double mMapToPixelTol;

//! 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 );
//! Returns the MapTolerance for transform between map coordinates and device coordinates
static float calculateViewPixelTolerance( const QgsRectangle& boundingRect, const QgsCoordinateTransform* ct, const QgsMapToPixel* mapToPixel );

public:
int simplifyFlags() const { return mSimplifyFlags; }
void setSimplifyFlags( int simplifyFlags ) { mSimplifyFlags = simplifyFlags; }

const QgsCoordinateTransform* coordinateTransform() const { return mMapCoordTransform; }
void setCoordinateTransform( const QgsCoordinateTransform* ct ) { mMapCoordTransform = ct; }

const QgsMapToPixel* mapToPixel() const { return mMapToPixel; }
void setMapToPixel( const QgsMapToPixel* mtp ) { mMapToPixel = mtp; }

float mapToPixelTol() const { return mMapToPixelTol; }
void setMapToPixelTol( float map2pixelTol ) { mMapToPixelTol = map2pixelTol; }

//! Returns a simplified version the specified geometry
virtual QgsGeometry* simplify( QgsGeometry* geometry ) const;
//! Simplifies the specified geometry
Expand All @@ -85,15 +70,13 @@ class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier
public:

//! Returns whether the envelope can be replaced by its BBOX when is applied the specified map2pixel context
static bool canbeGeneralizedByMapBoundingBox( const QgsRectangle& envelope,
const QgsCoordinateTransform* coordinateTransform, const QgsMapToPixel* mapToPixel, float mapToPixelTol = 1.0f );
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, mMapCoordTransform, mMapToPixel, mMapToPixelTol ); }
inline bool canbeGeneralizedByMapBoundingBox( const QgsRectangle& envelope ) const { return canbeGeneralizedByMapBoundingBox( envelope, mMapToPixelTol ); }

//! Simplifies the geometry when is applied the specified map2pixel context
static bool simplifyGeometry( QgsGeometry* geometry,
int simplifyFlags, const QgsCoordinateTransform* coordinateTransform, const QgsMapToPixel* mapToPixel, float mapToPixelTol = 1.0f );
static bool simplifyGeometry( QgsGeometry* geometry, int simplifyFlags, double map2pixelTol );

};

Expand Down

0 comments on commit 0ec7d35

Please sign in to comment.