Skip to content

Commit

Permalink
ogr geometry simplifier:
Browse files Browse the repository at this point in the history
- stick to C API
- enable simplification only with GDAL >=1.9
  • Loading branch information
jef-n committed Jan 18, 2014
1 parent c3a2174 commit 3305a6c
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 128 deletions.
9 changes: 5 additions & 4 deletions src/providers/ogr/qgsogrfeatureiterator.cpp
Expand Up @@ -116,12 +116,13 @@ bool QgsOgrFeatureIterator::prepareSimplification( const QgsSimplifyMethod& simp
mGeometrySimplifier = new QgsOgrMapToPixelSimplifier( simplifyFlags, simplifyMethod.tolerance() );
return true;
}
else
if ( methodType == QgsSimplifyMethod::PreserveTopology )
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1900
else if ( methodType == QgsSimplifyMethod::PreserveTopology )
{
mGeometrySimplifier = new QgsOgrTopologyPreservingSimplifier( simplifyMethod.tolerance() );
return true;
}
#endif
else
{
QgsDebugMsg( QString( "Simplification method type (%1) is not recognised by OgrFeatureIterator class" ).arg( methodType ) );
Expand Down Expand Up @@ -272,8 +273,8 @@ bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature )

if ( geom )
{
OGRGeometry* ogrGeometry = (OGRGeometry*)geom;
if ( mGeometrySimplifier ) mGeometrySimplifier->simplifyGeometry( ogrGeometry );
if ( mGeometrySimplifier )
mGeometrySimplifier->simplifyGeometry( geom );

// get the wkb representation
int memorySize = OGR_G_WkbSize( geom );
Expand Down
201 changes: 91 additions & 110 deletions src/providers/ogr/qgsogrgeometrysimplifier.cpp
Expand Up @@ -24,7 +24,9 @@ QgsOgrAbstractGeometrySimplifier::~QgsOgrAbstractGeometrySimplifier()

/***************************************************************************/

QgsOgrTopologyPreservingSimplifier::QgsOgrTopologyPreservingSimplifier( double tolerance ) : QgsTopologyPreservingSimplifier( tolerance )
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1900
QgsOgrTopologyPreservingSimplifier::QgsOgrTopologyPreservingSimplifier( double tolerance )
: QgsTopologyPreservingSimplifier( tolerance )
{
}

Expand All @@ -33,66 +35,44 @@ QgsOgrTopologyPreservingSimplifier::~QgsOgrTopologyPreservingSimplifier()
}

//! Simplifies the specified geometry
bool QgsOgrTopologyPreservingSimplifier::simplifyGeometry( OGRGeometry* geometry )
bool QgsOgrTopologyPreservingSimplifier::simplifyGeometry( OGRGeometryH geometry )
{
OGRwkbGeometryType wkbGeometryType = QgsOgrProvider::ogrWkbSingleFlatten( geometry->getGeometryType() );
OGRwkbGeometryType wkbGeometryType = QgsOgrProvider::ogrWkbSingleFlatten( OGR_G_GetGeometryType( geometry ) );

if ( wkbGeometryType == wkbLineString || wkbGeometryType == wkbPolygon )
{
OGRGeometry* g = geometry->SimplifyPreserveTopology( mTolerance );
if ( wkbGeometryType != wkbLineString && wkbGeometryType != wkbPolygon )
return false;

if ( g )
{
size_t wkbSize = g->WkbSize();
unsigned char * wkb = (unsigned char *)OGRMalloc( wkbSize );
g->exportToWkb( ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
geometry->importFromWkb( wkb, wkbSize );
delete g;
OGRGeometryH g = OGR_G_SimplifyPreserveTopology( geometry, mTolerance );
if ( !g )
return false;

return true;
}
}
return false;
size_t wkbSize = OGR_G_WkbSize( g );
unsigned char *wkb = new unsigned char[ wkbSize ];
OGR_G_ExportToWkb( g, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );
OGR_G_ImportFromWkb( geometry, wkb, wkbSize );
delete [] wkb;
OGR_G_DestroyGeometry( g );

return true;
}
#endif

/***************************************************************************/

QgsOgrMapToPixelSimplifier::QgsOgrMapToPixelSimplifier( int simplifyFlags, double map2pixelTol ) : QgsMapToPixelSimplifier( simplifyFlags, map2pixelTol )
QgsOgrMapToPixelSimplifier::QgsOgrMapToPixelSimplifier( int simplifyFlags, double map2pixelTol )
: QgsMapToPixelSimplifier( simplifyFlags, map2pixelTol )
{
mPointBufferCount = 64;
mPointBufferPtr = ( OGRRawPoint* )OGRMalloc( mPointBufferCount * sizeof( OGRRawPoint ) );
}

QgsOgrMapToPixelSimplifier::~QgsOgrMapToPixelSimplifier()
{
if ( mPointBufferPtr )
{
OGRFree( mPointBufferPtr );
mPointBufferPtr = NULL;
}
}

//! Returns a point buffer of the specified size
OGRRawPoint* QgsOgrMapToPixelSimplifier::mallocPoints( int numPoints )
{
if ( mPointBufferPtr && mPointBufferCount < numPoints )
{
OGRFree( mPointBufferPtr );
mPointBufferPtr = NULL;
}
if ( mPointBufferPtr == NULL )
{
mPointBufferCount = numPoints;
mPointBufferPtr = ( OGRRawPoint* )OGRMalloc( mPointBufferCount * sizeof( OGRRawPoint ) );
}
return mPointBufferPtr;
}

//////////////////////////////////////////////////////////////////////////////////////////////
// Helper simplification methods

//! Simplifies the OGR-geometry (Removing duplicated points) when is applied the specified map2pixel context
bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( QGis::GeometryType geometryType, const QgsRectangle& envelope, double* xptr, int xStride, double* yptr, int yStride, int pointCount, int& pointSimplifiedCount )
bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( QGis::GeometryType geometryType, const QgsRectangle& envelope, double *xptr, double *yptr, int pointCount, int& pointSimplifiedCount )
{
Q_UNUSED( envelope )
bool canbeGeneralizable = ( mSimplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry );
Expand All @@ -104,20 +84,20 @@ bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( QGis::GeometryType geometr
double map2pixelTol = mMapToPixelTol * mMapToPixelTol; //-> Use mappixelTol for 'LengthSquare' calculations.
double x, y, lastX = 0, lastY = 0;

char* xsourcePtr = ( char* )xptr;
char* ysourcePtr = ( char* )yptr;
char* xtargetPtr = ( char* )xptr;
char* ytargetPtr = ( char* )yptr;
double *xsourcePtr = xptr;
double *ysourcePtr = yptr;
double *xtargetPtr = xptr;
double *ytargetPtr = yptr;

for ( int i = 0, numPoints = geometryType == QGis::Polygon ? pointCount - 1 : pointCount; i < numPoints; ++i )
{
memcpy( &x, xsourcePtr, sizeof( double ) ); xsourcePtr += xStride;
memcpy( &y, ysourcePtr, sizeof( double ) ); ysourcePtr += yStride;
memcpy( &x, xsourcePtr++, sizeof( double ) );
memcpy( &y, ysourcePtr++, sizeof( double ) );

if ( i == 0 || !canbeGeneralizable || QgsMapToPixelSimplifier::calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol || ( geometryType == QGis::Line && ( i == 1 || i >= numPoints - 2 ) ) )
{
memcpy( xtargetPtr, &x, sizeof( double ) ); lastX = x; xtargetPtr += xStride;
memcpy( ytargetPtr, &y, sizeof( double ) ); lastY = y; ytargetPtr += yStride;
memcpy( xtargetPtr++, &x, sizeof( double ) ); lastX = x;
memcpy( ytargetPtr++, &y, sizeof( double ) ); lastY = y;
pointSimplifiedCount++;
}
}
Expand All @@ -127,116 +107,117 @@ bool QgsOgrMapToPixelSimplifier::simplifyOgrGeometry( QGis::GeometryType geometr
memcpy( ytargetPtr, yptr, sizeof( double ) );
pointSimplifiedCount++;
}

return pointSimplifiedCount != pointCount;
}

//! 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 = lineString->getNumPoints();
if (( isaLinearRing && numPoints <= 5 ) || ( !isaLinearRing && numPoints <= 4 ) ) return false;
int numPoints = OGR_G_GetPointCount( geometry );
if (( isaLinearRing && numPoints <= 5 ) || ( !isaLinearRing && numPoints <= 4 ) )
return false;

OGREnvelope env;
geometry->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;
int numPoints = 0;

double x1 = envelope.xMinimum();
double y1 = envelope.yMinimum();
double x2 = envelope.xMaximum();
double y2 = envelope.yMaximum();

if ( isaLinearRing )
{
numPoints = 5;

This comment has been minimized.

Copy link
@ahuarte47

ahuarte47 Jan 19, 2014

Contributor

Hi @jef-n, this modification (and others below) breaks the ogr simplification, the bug #9360 has been reopened.
I have released a new pull request that fixes the code: #1087

Best Regards

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;
OGR_G_SetPoint( geometry, 0, x1, y1, 0.0 );
OGR_G_SetPoint( geometry, 1, x2, y1, 0.0 );
OGR_G_SetPoint( geometry, 2, x2, y2, 0.0 );
OGR_G_SetPoint( geometry, 3, x1, y2, 0.0 );
OGR_G_SetPoint( geometry, 4, x1, y1, 0.0 );
}
else
{
numPoints = 2;
points = mallocPoints( numPoints );
points[0].x = x1; points[0].y = y1;
points[1].x = x2; points[1].y = y2;
OGR_G_SetPoint( geometry, 0, x1, y1, 0.0 );
OGR_G_SetPoint( geometry, 1, x2, y2, 0.0 );
}
lineString->setPoints( numPoints, points );
lineString->flattenTo2D();

OGR_G_FlattenTo2D( geometry );

return true;
}
else
if ( mSimplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry )
{
QGis::GeometryType geometryType = isaLinearRing ? QGis::Polygon : QGis::Line;
int numSimplifiedPoints = 0;
else if ( mSimplifyFlags & QgsMapToPixelSimplifier::SimplifyGeometry )
{
QGis::GeometryType geometryType = isaLinearRing ? QGis::Polygon : QGis::Line;
int numSimplifiedPoints = 0;

OGRRawPoint* points = mallocPoints( numPoints );
double* xptr = ( double* )points;
double* yptr = xptr + 1;
lineString->getPoints( points );
QVector<double> x( numPoints ), y( numPoints );
for ( int i = 0; i < numPoints; i++ )
{
double z;
OGR_G_GetPoint( geometry, i, &x[i], &y[i], &z );
}

if ( simplifyOgrGeometry( geometryType, envelope, xptr, 16, yptr, 16, numPoints, numSimplifiedPoints ) )
if ( simplifyOgrGeometry( geometryType, envelope, x.data(), y.data(), numPoints, numSimplifiedPoints ) )
{
for ( int i = 0; i < numSimplifiedPoints; i++ )
{
lineString->setPoints( numSimplifiedPoints, points );
lineString->flattenTo2D();
OGR_G_SetPoint( geometry, i, x[i], y[i], 0.0 );
}
return numSimplifiedPoints != numPoints;
OGR_G_FlattenTo2D( geometry );
}

return numSimplifiedPoints != numPoints;
}
}
else
if ( wkbGeometryType == wkbPolygon )
else if ( wkbGeometryType == wkbPolygon )
{
bool result = simplifyOgrGeometry( OGR_G_GetGeometryRef( geometry, 0 ), true );

for ( int i = 1, numInteriorRings = OGR_G_GetGeometryCount( geometry ); i < numInteriorRings; ++i )
{
OGRPolygon* polygon = ( OGRPolygon* )geometry;
bool result = simplifyOgrGeometry( polygon->getExteriorRing(), true );
result |= simplifyOgrGeometry( OGR_G_GetGeometryRef( geometry, i ), true );
}

for ( int i = 0, numInteriorRings = polygon->getNumInteriorRings(); i < numInteriorRings; ++i )
{
result |= simplifyOgrGeometry( polygon->getInteriorRing( i ), true );
}
if ( result ) polygon->flattenTo2D();
return result;
if ( result )
OGR_G_FlattenTo2D( geometry );

return result;
}
else if ( wkbGeometryType == wkbMultiLineString || wkbGeometryType == wkbMultiPolygon )
{
bool result = false;

for ( int i = 1, numGeometries = OGR_G_GetGeometryCount( geometry ); i < numGeometries; ++i )
{
result |= simplifyOgrGeometry( OGR_G_GetGeometryRef( geometry, i ), wkbGeometryType == wkbMultiPolygon );
}
else
if ( wkbGeometryType == wkbMultiLineString || wkbGeometryType == wkbMultiPolygon )
{
OGRGeometryCollection* collection = ( OGRGeometryCollection* )geometry;
bool result = false;
if ( result )
OGR_G_FlattenTo2D( geometry );
return result;
}

for ( int i = 0, numGeometries = collection->getNumGeometries(); i < numGeometries; ++i )
{
result |= simplifyOgrGeometry( collection->getGeometryRef( i ), wkbGeometryType == wkbMultiPolygon );
}
if ( result ) collection->flattenTo2D();
return result;
}
return false;
}

//////////////////////////////////////////////////////////////////////////////////////////////

//! Simplifies the specified geometry
bool QgsOgrMapToPixelSimplifier::simplifyGeometry( OGRGeometry* geometry )
bool QgsOgrMapToPixelSimplifier::simplifyGeometry( OGRGeometryH geometry )
{
OGRwkbGeometryType wkbGeometryType = QgsOgrProvider::ogrWkbSingleFlatten( geometry->getGeometryType() );
OGRwkbGeometryType wkbGeometryType = QgsOgrProvider::ogrWkbSingleFlatten( OGR_G_GetGeometryType( geometry ) );

if ( wkbGeometryType == wkbLineString || wkbGeometryType == wkbPolygon )
{
return simplifyOgrGeometry( geometry, wkbGeometryType == wkbPolygon );
}

return false;
}
22 changes: 8 additions & 14 deletions src/providers/ogr/qgsogrgeometrysimplifier.h
Expand Up @@ -18,7 +18,7 @@
#define QGSOGRGEOMETRYSIMPLIFIER_H

#include "qgsmaptopixelgeometrysimplifier.h"
#include <ogr_geometry.h>
#include <ogr_api.h>

/**
* Abstract base class for simplify OGR-geometries using a specific algorithm
Expand All @@ -29,9 +29,10 @@ class QgsOgrAbstractGeometrySimplifier
virtual ~QgsOgrAbstractGeometrySimplifier();

//! Simplifies the specified geometry
virtual bool simplifyGeometry( OGRGeometry* geometry ) = 0;
virtual bool simplifyGeometry( OGRGeometryH geometry ) = 0;
};

#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 1900
/**
* OGR Implementation of GeometrySimplifier using the Douglas-Peucker algorithm
*
Expand All @@ -45,8 +46,9 @@ class QgsOgrTopologyPreservingSimplifier : public QgsOgrAbstractGeometrySimplifi
virtual ~QgsOgrTopologyPreservingSimplifier();

//! Simplifies the specified geometry
virtual bool simplifyGeometry( OGRGeometry* geometry );
virtual bool simplifyGeometry( OGRGeometryH geometry );
};
#endif

/**
* OGR implementation of GeometrySimplifier using the "MapToPixel" algorithm
Expand All @@ -61,22 +63,14 @@ class QgsOgrMapToPixelSimplifier : public QgsOgrAbstractGeometrySimplifier, QgsM
virtual ~QgsOgrMapToPixelSimplifier();

private:
//! Point memory buffer for optimize the simplification process
OGRRawPoint* 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, const QgsRectangle& envelope, double* xptr, int xStride, double* yptr, int yStride, int pointCount, int& pointSimplifiedCount );
bool simplifyOgrGeometry( QGis::GeometryType geometryType, const QgsRectangle& envelope, double *xptr, double *yptr, int pointCount, int &pointSimplifiedCount );
//! Simplifies the OGR-geometry (Removing duplicated points) when is applied the specified map2pixel context
bool simplifyOgrGeometry( OGRGeometry* geometry, bool isaLinearRing );

//! Returns a point buffer of the specified size
OGRRawPoint* mallocPoints( int numPoints );
bool simplifyOgrGeometry( OGRGeometryH geometry, bool isaLinearRing );

public:
//! Simplifies the specified geometry
virtual bool simplifyGeometry( OGRGeometry* geometry );
virtual bool simplifyGeometry( OGRGeometryH geometry );
};

#endif // QGSOGRGEOMETRYSIMPLIFIER_H

0 comments on commit 3305a6c

Please sign in to comment.