Skip to content
Permalink
Browse files

Add SimplifyAlgorithm enum for local simplification

It implements the SimplifyAlgorithm enum for local simplification of
geometries.
Also the SnapToGrid algorithm is added.
  • Loading branch information
ahuarte47 committed Mar 23, 2016
1 parent 01ece90 commit 734b8b4c628696689038b6d7e7d84a40a5d62749
@@ -4,6 +4,13 @@ class QgsMapToPixelSimplifier : QgsAbstractGeometrySimplifier
#include "qgsmaptopixelgeometrysimplifier.h"
%End
public:
//! Types of simplification algorithms that can be used
enum SimplifyAlgorithm
{
Distance = 0, //!< The simplification uses the distance between points to remove duplicate points
SnapToGrid = 1, //!< The simplification uses a grid (similar to ST_SnapToGrid) to remove duplicate points
};

QgsMapToPixelSimplifier( int simplifyFlags, double tolerance );
virtual ~QgsMapToPixelSimplifier();

@@ -20,10 +27,16 @@ class QgsMapToPixelSimplifier : QgsAbstractGeometrySimplifier
//! 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 whether the points belong to the same grid
static bool equalSnapToGrid( double x1, double y1, double x2, double y2, double gridOriginX, double gridOriginY, float gridInverseSizeXY );

public:
int simplifyFlags() const;
void setSimplifyFlags( int simplifyFlags );

SimplifyAlgorithm simplifyAlgorithm() const;
void setSimplifyAlgorithm( SimplifyAlgorithm simplifyAlgorithm );

//! Returns a simplified version the specified geometry
virtual QgsGeometry* simplify( QgsGeometry* geometry ) const;
//! Simplifies the specified geometry
@@ -42,9 +55,9 @@ class QgsMapToPixelSimplifier : QgsAbstractGeometrySimplifier
bool isGeneralizableByMapBoundingBox( const QgsRectangle& envelope ) const;

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

//! Simplifies the WKB-point array when is applied the specified map2pixel context
static bool simplifyPoints( QgsWKBTypes::Type wkbType, QgsConstWkbPtr& sourceWkbPtr, QPolygonF& targetPoints, int simplifyFlags, double tolerance );
static bool simplifyPoints( QgsWKBTypes::Type wkbType, QgsConstWkbPtr& sourceWkbPtr, QPolygonF& targetPoints, int simplifyFlags, double tolerance, SimplifyAlgorithm simplifyAlgorithm = Distance );

};
@@ -29,6 +29,18 @@ class QgsVectorSimplifyMethod
/** Gets the simplification hints of the vector layer managed */
QFlags<QgsVectorSimplifyMethod::SimplifyHint> simplifyHints() const;

/** Types of local simplification algorithms that can be used */
enum SimplifyAlgorithm
{
Distance = 0, //!< The simplification uses the distance between points to remove duplicate points
SnapToGrid = 1, //!< The simplification uses a grid (similar to ST_SnapToGrid) to remove duplicate points
};

/** Sets the local simplification algorithm of the vector layer managed */
void setSimplifyAlgorithm( const SimplifyAlgorithm& simplifyAlgorithm );
/** Gets the local simplification algorithm of the vector layer managed */
SimplifyAlgorithm simplifyAlgorithm() const;

/** 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 in map units. Represents the maximum distance in map units between two coordinates which can be considered equal */
@@ -613,6 +613,11 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl )
doubleSpinBoxMagnifierDefault->setSuffix( "%" );
doubleSpinBoxMagnifierDefault->setValue( mSettings->value( "/qgis/magnifier_level", 100 ).toInt() );

// Default local simplification algorithm
mSimplifyAlgorithmComboBox->addItem( tr( "Distance" ), ( int )QgsVectorSimplifyMethod::Distance );
mSimplifyAlgorithmComboBox->addItem( tr( "SnapToGrid" ), ( int )QgsVectorSimplifyMethod::SnapToGrid );
mSimplifyAlgorithmComboBox->setCurrentIndex( mSimplifyAlgorithmComboBox->findData( mSettings->value( "/qgis/simplifyAlgorithm", 0 ).toInt() ) );

// Slightly awkard here at the settings value is true to use QImage,
// but the checkbox is true to use QPixmap
chkAddedVisibility->setChecked( mSettings->value( "/qgis/new_layers_visible", true ).toBool() );
@@ -1212,6 +1217,7 @@ void QgsOptions::saveOptions()
if ( mSimplifyDrawingSpinBox->value() > 1 ) simplifyHints |= QgsVectorSimplifyMethod::AntialiasingSimplification;
}
mSettings->setValue( "/qgis/simplifyDrawingHints", ( int ) simplifyHints );
mSettings->setValue( "/qgis/simplifyAlgorithm", mSimplifyAlgorithmComboBox->itemData( mSimplifyAlgorithmComboBox->currentIndex() ).toInt() );
mSettings->setValue( "/qgis/simplifyDrawingTol", mSimplifyDrawingSpinBox->value() );
mSettings->setValue( "/qgis/simplifyLocal", !mSimplifyDrawingAtProvider->isChecked() );
mSettings->setValue( "/qgis/simplifyMaxScale", 1.0 / mSimplifyMaximumScaleComboBox->scale() );
@@ -439,6 +439,11 @@ void QgsVectorLayerProperties::syncToLayer()
mSimplifyDrawingGroupBox->setEnabled( false );
}

// Default local simplification algorithm
mSimplifyAlgorithmComboBox->addItem( tr( "Distance" ), ( int )QgsVectorSimplifyMethod::Distance );
mSimplifyAlgorithmComboBox->addItem( tr( "SnapToGrid" ), ( int )QgsVectorSimplifyMethod::SnapToGrid );
mSimplifyAlgorithmComboBox->setCurrentIndex( mSimplifyAlgorithmComboBox->findData(( int )simplifyMethod.simplifyAlgorithm() ) );

QStringList myScalesList = PROJECT_SCALES.split( ',' );
myScalesList.append( "1:1" );
mSimplifyMaximumScaleComboBox->updateScales( myScalesList );
@@ -625,6 +630,7 @@ void QgsVectorLayerProperties::apply()
}
QgsVectorSimplifyMethod simplifyMethod = mLayer->simplifyMethod();
simplifyMethod.setSimplifyHints( simplifyHints );
simplifyMethod.setSimplifyAlgorithm( static_cast< QgsVectorSimplifyMethod::SimplifyAlgorithm >( mSimplifyAlgorithmComboBox->itemData( mSimplifyAlgorithmComboBox->currentIndex() ).toInt() ) );
simplifyMethod.setThreshold( mSimplifyDrawingSpinBox->value() );
simplifyMethod.setForceLocalOptimization( !mSimplifyDrawingAtProvider->isChecked() );
simplifyMethod.setMaximumScale( 1.0 / mSimplifyMaximumScaleComboBox->scale() );
@@ -33,10 +33,11 @@ const QgsConstWkbPtr &QgsConstWkbSimplifierPtr::operator>>( QPolygonF &points )
if ( mSimplifyMethod.simplifyHints() != QgsVectorSimplifyMethod::NoSimplification && mSimplifyMethod.forceLocalOptimization() )
{
int simplifyHints = mSimplifyMethod.simplifyHints() | QgsMapToPixelSimplifier::SimplifyEnvelope;
QgsMapToPixelSimplifier::SimplifyAlgorithm simplifyAlgorithm = static_cast< QgsMapToPixelSimplifier::SimplifyAlgorithm >( mSimplifyMethod.simplifyAlgorithm() );

QgsConstWkbPtr wkbPtr = *this;

if ( QgsMapToPixelSimplifier::simplifyPoints( mWkbType, wkbPtr, points, simplifyHints, mSimplifyMethod.tolerance() ) )
if ( QgsMapToPixelSimplifier::simplifyPoints( mWkbType, wkbPtr, points, simplifyHints, mSimplifyMethod.tolerance(), simplifyAlgorithm ) )
{
mP = const_cast< unsigned char * >(( const unsigned char * ) wkbPtr );
return *this;
@@ -21,9 +21,10 @@
#include "qgslogger.h"


QgsMapToPixelSimplifier::QgsMapToPixelSimplifier( int simplifyFlags, double tolerance )
QgsMapToPixelSimplifier::QgsMapToPixelSimplifier( int simplifyFlags, double tolerance, SimplifyAlgorithm simplifyAlgorithm )
: mSimplifyFlags( simplifyFlags )
, mTolerance( tolerance )
, mSimplifyAlgorithm( simplifyAlgorithm )
{
}

@@ -40,7 +41,22 @@ float QgsMapToPixelSimplifier::calculateLengthSquared2D( double x1, double y1, d
float vx = static_cast< float >( x2 - x1 );
float vy = static_cast< float >( y2 - y1 );

return vx*vx + vy*vy;
return ( vx * vx ) + ( vy * vy );
}


//! Returns whether the points belong to the same grid
bool QgsMapToPixelSimplifier::equalSnapToGrid( double x1, double y1, double x2, double y2, double gridOriginX, double gridOriginY, float gridInverseSizeXY )
{
int grid_x1 = qRound(( x1 - gridOriginX ) * gridInverseSizeXY );
int grid_x2 = qRound(( x2 - gridOriginX ) * gridInverseSizeXY );
if ( grid_x1 != grid_x2 ) return false;

int grid_y1 = qRound(( y1 - gridOriginY ) * gridInverseSizeXY );
int grid_y2 = qRound(( y2 - gridOriginY ) * gridInverseSizeXY );
if ( grid_y1 != grid_y2 ) return false;

return true;
}

//! Returns the BBOX of the specified WKB-point stream
@@ -122,7 +138,9 @@ static bool generalizeWkbGeometryByBoundingBox(

//! Simplify the WKB-geometry using the specified tolerance
bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
int simplifyFlags, QGis::WkbType wkbType,
int simplifyFlags,
SimplifyAlgorithm simplifyAlgorithm,
QGis::WkbType wkbType,
QgsConstWkbPtr sourceWkbPtr,
QgsWkbPtr targetWkbPtr,
int &targetWkbSize,
@@ -184,8 +202,6 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
targetWkbPtr << numTargetPoints;
targetWkbSize += 4;

map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations.

bool isLongSegment;
bool hasLongSegments = false; //-> To avoid replace the simplified geometry by its BBOX when there are 'long' segments.
bool badLuck = false;
@@ -205,27 +221,59 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
}

// Process each vertex...
for ( int i = 0; i < numPoints; ++i )
if ( simplifyAlgorithm == SnapToGrid )
{
sourceWkbPtr >> x >> y;
sourceWkbPtr += skipZM;
double gridOriginX = envelope.xMinimum();
double gridOriginY = envelope.yMinimum();

isLongSegment = false;
// Use a factor for the maximum displacement distance for simplification, similar as GeoServer does
float gridInverseSizeXY = map2pixelTol != 0 ? ( float )( 1.0f / ( 0.8 * map2pixelTol ) ) : 0.0f;

if ( i == 0 ||
!isGeneralizable ||
( isLongSegment = ( calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol ) ) ||
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
for ( int i = 0; i < numPoints; ++i )
{
targetWkbPtr << x << y;
lastX = x;
lastY = y;
numTargetPoints++;
sourceWkbPtr >> x >> y;
sourceWkbPtr += skipZM;

if ( i == 0 ||
!isGeneralizable ||
!equalSnapToGrid( x, y, lastX, lastY, gridOriginX, gridOriginY, gridInverseSizeXY ) ||
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
{
targetWkbPtr << x << y;
lastX = x;
lastY = y;
numTargetPoints++;
}

hasLongSegments |= isLongSegment;
r.combineExtentWith( x, y );
}
}
else
{
map2pixelTol *= map2pixelTol; //-> Use mappixelTol for 'LengthSquare' calculations.

for ( int i = 0; i < numPoints; ++i )
{
sourceWkbPtr >> x >> y;
sourceWkbPtr += skipZM;

isLongSegment = false;

r.combineExtentWith( x, y );
if ( i == 0 ||
!isGeneralizable ||
( isLongSegment = ( calculateLengthSquared2D( x, y, lastX, lastY ) > map2pixelTol ) ) ||
( !isaLinearRing && ( i == 1 || i >= numPoints - 2 ) ) )
{
targetWkbPtr << x << y;
lastX = x;
lastY = y;
numTargetPoints++;

hasLongSegments |= isLongSegment;
}

r.combineExtentWith( x, y );
}
}

QgsWkbPtr nextPointPtr( targetWkbPtr );
@@ -296,7 +344,7 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
int sourceWkbSize_i = sizeof( int ) + numPoints_i * QGis::wkbDimensions( wkbType ) * sizeof( double );
int targetWkbSize_i = 0;

result |= simplifyWkbGeometry( simplifyFlags, wkbType, sourceWkbPtr, targetWkbPtr, targetWkbSize_i, envelope_i, map2pixelTol, false, true );
result |= simplifyWkbGeometry( simplifyFlags, simplifyAlgorithm, wkbType, sourceWkbPtr, targetWkbPtr, targetWkbSize_i, envelope_i, map2pixelTol, false, true );
sourceWkbPtr += sourceWkbSize_i;
targetWkbPtr += targetWkbSize_i;

@@ -347,7 +395,7 @@ bool QgsMapToPixelSimplifier::simplifyWkbGeometry(
sourceWkbPtr2 += wkbSize_i;
}
}
result |= simplifyWkbGeometry( simplifyFlags, QGis::singleType( wkbType ), sourceWkbPtr, targetWkbPtr, targetWkbSize_i, envelope, map2pixelTol, true, false );
result |= simplifyWkbGeometry( simplifyFlags, simplifyAlgorithm, QGis::singleType( wkbType ), sourceWkbPtr, targetWkbPtr, targetWkbSize_i, envelope, map2pixelTol, true, false );
sourceWkbPtr += sourceWkbSize_i;
targetWkbPtr += targetWkbSize_i;

@@ -376,13 +424,13 @@ QgsGeometry* QgsMapToPixelSimplifier::simplify( QgsGeometry* geometry ) const
unsigned char* wkb = new unsigned char[ wkbSize ];
memcpy( wkb, geometry->asWkb(), wkbSize );
g->fromWkb( wkb, wkbSize );
simplifyGeometry( g, mSimplifyFlags, mTolerance );
simplifyGeometry( g, mSimplifyFlags, mTolerance, mSimplifyAlgorithm );

return g;
}

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

@@ -402,7 +450,7 @@ bool QgsMapToPixelSimplifier::simplifyGeometry( QgsGeometry *geometry, int simpl

try
{
if ( simplifyWkbGeometry( simplifyFlags, wkbType, wkbPtr, targetWkbPtr, finalWkbSize, envelope, tolerance ) )
if ( simplifyWkbGeometry( simplifyFlags, simplifyAlgorithm, wkbType, wkbPtr, targetWkbPtr, finalWkbSize, envelope, tolerance ) )
{
unsigned char *finalWkb = new unsigned char[finalWkbSize];
memcpy( finalWkb, targetWkb, finalWkbSize );
@@ -423,11 +471,11 @@ 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, mTolerance );
return simplifyGeometry( geometry, mSimplifyFlags, mTolerance, mSimplifyAlgorithm );
}

//! Simplifies the WKB-point array (Removing duplicated points) when is applied the specified map2pixel context
bool QgsMapToPixelSimplifier::simplifyPoints( QgsWKBTypes::Type wkbType, QgsConstWkbPtr& sourceWkbPtr, QPolygonF& targetPoints, int simplifyFlags, double tolerance )
bool QgsMapToPixelSimplifier::simplifyPoints( QgsWKBTypes::Type wkbType, QgsConstWkbPtr& sourceWkbPtr, QPolygonF& targetPoints, int simplifyFlags, double tolerance, SimplifyAlgorithm simplifyAlgorithm )
{
QgsWKBTypes::Type singleType = QgsWKBTypes::singleType( wkbType );
QgsWKBTypes::Type flatType = QgsWKBTypes::flatType( singleType );
@@ -457,7 +505,7 @@ bool QgsMapToPixelSimplifier::simplifyPoints( QgsWKBTypes::Type wkbType, QgsCons
targetWkbPtr << ( char ) QgsApplication::endian() << flatType;
targetWkbSize = 5;

if ( simplifyWkbGeometry( simplifyFlags, QGis::fromNewWkbType( singleType ), sourceWkbPtr, targetWkbPtr, targetWkbSize, envelope, tolerance, false, isaLinearRing ) )
if ( simplifyWkbGeometry( simplifyFlags, simplifyAlgorithm, QGis::fromNewWkbType( singleType ), sourceWkbPtr, targetWkbPtr, targetWkbSize, envelope, tolerance, false, isaLinearRing ) )
{
QgsConstWkbPtr finalWkbPtr( targetWkb, targetWkbSize );
finalWkbPtr.readHeader();
@@ -481,5 +529,5 @@ bool QgsMapToPixelSimplifier::simplifyPoints( QgsWKBTypes::Type wkbType, QgsCons
//! Simplifies the specified WKB-point array
bool QgsMapToPixelSimplifier::simplifyPoints( QgsWKBTypes::Type wkbType, QgsConstWkbPtr& sourceWkbPtr, QPolygonF& targetPoints ) const
{
return simplifyPoints( wkbType, sourceWkbPtr, targetPoints, mSimplifyFlags, mTolerance );
return simplifyPoints( wkbType, sourceWkbPtr, targetPoints, mSimplifyFlags, mTolerance, mSimplifyAlgorithm );
}
@@ -32,7 +32,14 @@
class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier
{
public:
QgsMapToPixelSimplifier( int simplifyFlags, double tolerance );
//! Types of simplification algorithms that can be used
enum SimplifyAlgorithm
{
Distance = 0, //!< The simplification uses the distance between points to remove duplicate points
SnapToGrid = 1, //!< The simplification uses a grid (similar to ST_SnapToGrid) to remove duplicate points
};

QgsMapToPixelSimplifier( int simplifyFlags, double tolerance, SimplifyAlgorithm simplifyAlgorithm = Distance );
virtual ~QgsMapToPixelSimplifier();

//! Applicable simplification flags
@@ -45,22 +52,31 @@ class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier

private:
//! Simplify the WKB-geometry using the specified tolerance
static bool simplifyWkbGeometry( int simplifyFlags, QGis::WkbType wkbType, QgsConstWkbPtr sourceWkbPtr, QgsWkbPtr targetWkbPtr, int &targetWkbSize, const QgsRectangle& envelope, double map2pixelTol, bool writeHeader = true, bool isaLinearRing = false );
static bool simplifyWkbGeometry( int simplifyFlags, SimplifyAlgorithm simplifyAlgorithm, QGis::WkbType wkbType, QgsConstWkbPtr sourceWkbPtr, QgsWkbPtr targetWkbPtr, int &targetWkbSize, const QgsRectangle& envelope, double map2pixelTol, bool writeHeader = true, bool isaLinearRing = false );

protected:
//! Current simplification flags
int mSimplifyFlags;

//! Current algorithm
SimplifyAlgorithm mSimplifyAlgorithm;

//! 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 );

//! Returns whether the points belong to the same grid
static bool equalSnapToGrid( double x1, double y1, double x2, double y2, double gridOriginX, double gridOriginY, float gridInverseSizeXY );

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

SimplifyAlgorithm simplifyAlgorithm() const { return mSimplifyAlgorithm; }
void setSimplifyAlgorithm( SimplifyAlgorithm simplifyAlgorithm ) { mSimplifyAlgorithm = simplifyAlgorithm; }

//! Returns a simplified version the specified geometry
virtual QgsGeometry* simplify( QgsGeometry* geometry ) const override;
//! Simplifies the specified geometry
@@ -82,10 +98,10 @@ class CORE_EXPORT QgsMapToPixelSimplifier : public QgsAbstractGeometrySimplifier
}

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

//! Simplifies the WKB-point array when is applied the specified map2pixel context
static bool simplifyPoints( QgsWKBTypes::Type wkbType, QgsConstWkbPtr& sourceWkbPtr, QPolygonF& targetPoints, int simplifyFlags, double tolerance );
static bool simplifyPoints( QgsWKBTypes::Type wkbType, QgsConstWkbPtr& sourceWkbPtr, QPolygonF& targetPoints, int simplifyFlags, double tolerance, SimplifyAlgorithm simplifyAlgorithm = Distance );
};

#endif // QGSMAPTOPIXELGEOMETRYSIMPLIFIER_H

0 comments on commit 734b8b4

Please sign in to comment.
You can’t perform that action at this time.