Skip to content
Permalink
Browse files
[FEATURE] Add choice of simplification method to simplify map tool
Allows different techniques to be used for simplification, including
the more cartographically pleasing "Visvalingam" simplification algorithm.

Fixes #18083
  • Loading branch information
nyalldawson authored and 3nids committed Feb 26, 2018
1 parent c0b8fbf commit dce2188
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 32 deletions.
@@ -23,7 +23,7 @@
#include "qgstolerance.h"
#include "qgisapp.h"
#include "qgssettings.h"

#include "qgsmaptopixelgeometrysimplifier.h"
#include <QMouseEvent>

#include <cmath>
@@ -35,12 +35,22 @@ QgsSimplifyDialog::QgsSimplifyDialog( QgsMapToolSimplify *tool, QWidget *parent
{
setupUi( this );

mMethodComboBox->addItem( tr( "Simplify by distance" ), ( int )QgsVectorSimplifyMethod::Distance );
mMethodComboBox->addItem( tr( "Simplify by snapping to grid" ), ( int )QgsVectorSimplifyMethod::SnapToGrid );
mMethodComboBox->addItem( tr( "Simplify by area (Visvalingam)" ), ( int )QgsVectorSimplifyMethod::Visvalingam );

spinTolerance->setValue( mTool->tolerance() );
spinTolerance->setShowClearButton( false );
cboToleranceUnits->setCurrentIndex( ( int ) mTool->toleranceUnits() );
mMethodComboBox->setCurrentIndex( mMethodComboBox->findData( mTool->method() ) );

// communication with map tool
connect( spinTolerance, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), mTool, &QgsMapToolSimplify::setTolerance );
connect( cboToleranceUnits, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), mTool, &QgsMapToolSimplify::setToleranceUnits );
connect( mMethodComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), mTool, [ = ]
{
mTool->setMethod( static_cast< QgsMapToPixelSimplifier::SimplifyAlgorithm >( mMethodComboBox->currentData().toInt() ) );
} );
connect( okButton, &QAbstractButton::clicked, mTool, &QgsMapToolSimplify::storeSimplified );
}

@@ -70,6 +80,7 @@ QgsMapToolSimplify::QgsMapToolSimplify( QgsMapCanvas *canvas )
QgsSettings settings;
mTolerance = settings.value( QStringLiteral( "digitizing/simplify_tolerance" ), 1 ).toDouble();
mToleranceUnits = settings.enumValue( QStringLiteral( "digitizing/simplify_tolerance_units" ), QgsTolerance::LayerUnits );
mMethod = static_cast< QgsMapToPixelSimplifier::SimplifyAlgorithm >( settings.value( QStringLiteral( "digitizing/simplify_method" ), 0 ).toInt() );

mSimplifyDialog = new QgsSimplifyDialog( this, canvas->topLevelWidget() );
}
@@ -111,9 +122,10 @@ void QgsMapToolSimplify::updateSimplificationPreview()
mReducedHasErrors = false;
mReducedVertexCount = 0;
int i = 0;

Q_FOREACH ( const QgsFeature &fSel, mSelectedFeatures )
{
QgsGeometry g = fSel.geometry().simplify( layerTolerance );
QgsGeometry g = processGeometry( fSel.geometry(), layerTolerance );
if ( !g.isNull() )
{
mReducedVertexCount += g.constGet()->nCoordinates();
@@ -128,6 +140,39 @@ void QgsMapToolSimplify::updateSimplificationPreview()
mSimplifyDialog->enableOkButton( !mReducedHasErrors );
}

QgsGeometry QgsMapToolSimplify::processGeometry( const QgsGeometry &geometry, double tolerance ) const
{
switch ( mMethod )
{
case QgsMapToPixelSimplifier::Distance:
return geometry.simplify( tolerance );

case QgsMapToPixelSimplifier::SnapToGrid:
case QgsMapToPixelSimplifier::Visvalingam:
{
QgsMapToPixelSimplifier simplifier( QgsMapToPixelSimplifier::SimplifyGeometry, tolerance, mMethod );
return simplifier.simplify( geometry );
}
}
return QgsGeometry(); //no warnings
}

QgsMapToPixelSimplifier::SimplifyAlgorithm QgsMapToolSimplify::method() const
{
return mMethod;
}

void QgsMapToolSimplify::setMethod( QgsMapToPixelSimplifier::SimplifyAlgorithm method )
{
mMethod = method;

QgsSettings settings;
settings.setValue( QStringLiteral( "digitizing/simplify_method" ), method );

if ( !mSelectedFeatures.isEmpty() )
updateSimplificationPreview();
}

void QgsMapToolSimplify::storeSimplified()
{
QgsVectorLayer *vlayer = currentVectorLayer();
@@ -136,7 +181,7 @@ void QgsMapToolSimplify::storeSimplified()
vlayer->beginEditCommand( tr( "Geometry simplified" ) );
Q_FOREACH ( const QgsFeature &feat, mSelectedFeatures )
{
QgsGeometry g = feat.geometry().simplify( layerTolerance );
QgsGeometry g = processGeometry( feat.geometry(), layerTolerance );
if ( !g.isNull() )
{
vlayer->changeGeometry( feat.id(), g );
@@ -23,6 +23,7 @@
#include "qgsfeature.h"
#include "qgstolerance.h"
#include "qgis_app.h"
#include "qgsmaptopixelgeometrysimplifier.h"

class QgsRubberBand;
class QgsMapToolSimplify;
@@ -71,6 +72,10 @@ class APP_EXPORT QgsMapToolSimplify: public QgsMapToolEdit

QString statusText() const;

QgsMapToPixelSimplifier::SimplifyAlgorithm method() const;

void setMethod( QgsMapToPixelSimplifier::SimplifyAlgorithm method );

public slots:
//! Slot to change display when slidebar is moved
void setTolerance( double tolerance );
@@ -89,6 +94,12 @@ class APP_EXPORT QgsMapToolSimplify: public QgsMapToolEdit

void updateSimplificationPreview();

/**
* Simplifies a \a geometry to the specified \a tolerance, respecting the preset
* simplification method.
*/
QgsGeometry processGeometry( const QgsGeometry &geometry, double tolerance ) const;

// data
//! Dialog with slider to set correct tolerance value
QgsSimplifyDialog *mSimplifyDialog = nullptr;
@@ -113,6 +124,9 @@ class APP_EXPORT QgsMapToolSimplify: public QgsMapToolEdit
int mOriginalVertexCount = 0;
int mReducedVertexCount = 0;
bool mReducedHasErrors = false;

QgsMapToPixelSimplifier::SimplifyAlgorithm mMethod = QgsMapToPixelSimplifier::Distance;

};

#endif
@@ -7,21 +7,24 @@
<x>0</x>
<y>0</y>
<width>527</width>
<height>63</height>
<height>98</height>
</rect>
</property>
<property name="windowTitle">
<string>Simplification Tool</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="3">
<widget class="QPushButton" name="okButton">
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>OK</string>
<string>Tolerance</string>
</property>
</widget>
</item>
<item row="0" column="2">
<item row="3" column="0" colspan="4">
<widget class="QLabel" name="labelStatus"/>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="cboToleranceUnits">
<item>
<property name="text">
@@ -40,15 +43,8 @@
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Tolerance</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="spinTolerance">
<item row="1" column="1">
<widget class="QgsDoubleSpinBox" name="spinTolerance">
<property name="decimals">
<number>6</number>
</property>
@@ -60,12 +56,34 @@
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<widget class="QLabel" name="labelStatus"/>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Method</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="okButton">
<property name="text">
<string>OK</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="mMethodComboBox"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>qgsdoublespinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mMethodComboBox</tabstop>
<tabstop>spinTolerance</tabstop>
<tabstop>cboToleranceUnits</tabstop>
<tabstop>okButton</tabstop>
@@ -345,7 +345,7 @@
</sizepolicy>
</property>
<property name="currentIndex">
<number>0</number>
<number>12</number>
</property>
<widget class="QWidget" name="mOptsPage_Information">
<layout class="QVBoxLayout" name="verticalLayout_5">
@@ -421,8 +421,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>651</width>
<height>537</height>
<width>285</width>
<height>399</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
@@ -696,8 +696,8 @@ border-radius: 2px;</string>
<rect>
<x>0</x>
<y>0</y>
<width>651</width>
<height>537</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_18">
@@ -882,8 +882,8 @@ border-radius: 2px;</string>
<rect>
<x>0</x>
<y>0</y>
<width>651</width>
<height>537</height>
<width>104</width>
<height>102</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_23">
@@ -1277,8 +1277,8 @@ border-radius: 2px;</string>
<rect>
<x>0</x>
<y>0</y>
<width>651</width>
<height>537</height>
<width>100</width>
<height>30</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_21">
@@ -1451,8 +1451,8 @@ border-radius: 2px;</string>
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>521</height>
<width>671</width>
<height>522</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_32">
@@ -1905,8 +1905,8 @@ border-radius: 2px;</string>
<rect>
<x>0</x>
<y>0</y>
<width>651</width>
<height>537</height>
<width>639</width>
<height>656</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
@@ -2467,6 +2467,34 @@ border-radius: 2px;</string>
</tabstops>
<resources>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
<include location="../../images/images.qrc"/>
</resources>
<connections>
<connection>

0 comments on commit dce2188

Please sign in to comment.