From d96a3f4dd483c8d17d6dd873bfd7ed30b9d3df60 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Thu, 14 Sep 2017 08:47:21 +1000 Subject: [PATCH] Port simplify geometries to c++ --- python/plugins/processing/algs/help/qgis.yaml | 5 - .../algs/qgis/QGISAlgorithmProvider.py | 2 - .../algs/qgis/SimplifyGeometries.py | 96 ------------------- .../tests/testdata/qgis_algorithm_tests.yaml | 8 +- src/core/processing/qgsnativealgorithms.cpp | 62 ++++++++++++ src/core/processing/qgsnativealgorithms.h | 30 ++++++ 6 files changed, 96 insertions(+), 107 deletions(-) delete mode 100644 python/plugins/processing/algs/qgis/SimplifyGeometries.py diff --git a/python/plugins/processing/algs/help/qgis.yaml b/python/plugins/processing/algs/help/qgis.yaml index df24990eb72..ea9599f397f 100755 --- a/python/plugins/processing/algs/help/qgis.yaml +++ b/python/plugins/processing/algs/help/qgis.yaml @@ -528,11 +528,6 @@ qgis:setzvalue: > If Z values already exist in the layer, they will be overwritten with the new value. If no Z values exist, the geometry will be upgraded to include Z values and the specified value used as the initial Z value for all geometries. -qgis:simplifygeometries: > - This algorithm simplifies the geometries in a line or polygon layer. It creates a new layer with the same features as the ones in the input layer, but with geometries containing a lower number of vertices. - - The algorithm gives a choice of simplification methods, including distance based (the "Douglas-Peucker" algorithm), area based ("Visvalingam" algorithm) and snapping geometries to grid. - qgis:singlesidedbuffer: > This algorithm buffers lines by a specified distance on one side of the line only. diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index 06bc6a74e86..e056a968fbe 100644 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -141,7 +141,6 @@ from .SetZValue import SetZValue from .ShortestPathLayerToPoint import ShortestPathLayerToPoint from .ShortestPathPointToLayer import ShortestPathPointToLayer from .ShortestPathPointToPoint import ShortestPathPointToPoint -from .SimplifyGeometries import SimplifyGeometries from .SingleSidedBuffer import SingleSidedBuffer from .Slope import Slope from .SnapGeometries import SnapGeometriesToLayer @@ -279,7 +278,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider): ShortestPathLayerToPoint(), ShortestPathPointToLayer(), ShortestPathPointToPoint(), - SimplifyGeometries(), SingleSidedBuffer(), Slope(), SnapGeometriesToLayer(), diff --git a/python/plugins/processing/algs/qgis/SimplifyGeometries.py b/python/plugins/processing/algs/qgis/SimplifyGeometries.py deleted file mode 100644 index 7080579af01..00000000000 --- a/python/plugins/processing/algs/qgis/SimplifyGeometries.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - SimplifyGeometries.py - --------------------- - Date : August 2012 - Copyright : (C) 2012 by Victor Olaya - Email : volayaf at gmail dot com -*************************************************************************** -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU General Public License as published by * -* the Free Software Foundation; either version 2 of the License, or * -* (at your option) any later version. * -* * -*************************************************************************** -""" - -__author__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -# This will get replaced with a git SHA1 when you do a git archive - -__revision__ = '$Format:%H$' - -import os - -from qgis.PyQt.QtGui import QIcon - -from qgis.core import (QgsMapToPixelSimplifier, - QgsProcessingParameterEnum, - QgsProcessingParameterNumber) - -from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm - -pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] - - -class SimplifyGeometries(QgisFeatureBasedAlgorithm): - - TOLERANCE = 'TOLERANCE' - METHOD = 'METHOD' - - def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'simplify.png')) - - def group(self): - return self.tr('Vector geometry') - - def __init__(self): - super().__init__() - self.tolerance = None - self.method = None - self.simplifier = None - - def initParameters(self, config=None): - self.methods = [self.tr('Distance (Douglas-Peucker)'), - 'Snap to grid', - 'Area (Visvalingam)'] - self.addParameter(QgsProcessingParameterEnum( - self.METHOD, - self.tr('Simplification method'), - self.methods, defaultValue=0)) - self.addParameter(QgsProcessingParameterNumber(self.TOLERANCE, - self.tr('Tolerance'), minValue=0.0, maxValue=10000000.0, defaultValue=1.0)) - - def name(self): - return 'simplifygeometries' - - def displayName(self): - return self.tr('Simplify geometries') - - def outputName(self): - return self.tr('Simplified') - - def prepareAlgorithm(self, parameters, context, feedback): - self.tolerance = self.parameterAsDouble(parameters, self.TOLERANCE, context) - self.method = self.parameterAsEnum(parameters, self.METHOD, context) - if self.method != 0: - self.simplifier = QgsMapToPixelSimplifier(QgsMapToPixelSimplifier.SimplifyGeometry, self.tolerance, self.method) - - return True - - def processFeature(self, feature, feedback): - if feature.hasGeometry(): - input_geometry = feature.geometry() - - if self.method == 0: # distance - output_geometry = input_geometry.simplify(self.tolerance) - else: - output_geometry = self.simplifier.simplify(input_geometry) - - feature.setGeometry(output_geometry) - return feature diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 4a447cc5152..c61485e71c7 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -1209,7 +1209,7 @@ tests: name: expected/extract_nodes_lines.gml type: vector - - algorithm: qgis:simplifygeometries + - algorithm: native:simplifygeometries name: Simplify (lines) params: INPUT: @@ -1221,7 +1221,7 @@ tests: name: expected/simplify_lines.gml type: vector - - algorithm: qgis:simplifygeometries + - algorithm: native:simplifygeometries name: Simplify (multilines) params: INPUT: @@ -1233,7 +1233,7 @@ tests: name: expected/simplify_multilines.gml type: vector - - algorithm: qgis:simplifygeometries + - algorithm: native:simplifygeometries name: Simplify (visval) params: INPUT: @@ -1249,7 +1249,7 @@ tests: geometry: precision: 7 - - algorithm: qgis:simplifygeometries + - algorithm: native:simplifygeometries name: Simplify (grid) params: INPUT: diff --git a/src/core/processing/qgsnativealgorithms.cpp b/src/core/processing/qgsnativealgorithms.cpp index d6871be68d0..a7a1062b83b 100644 --- a/src/core/processing/qgsnativealgorithms.cpp +++ b/src/core/processing/qgsnativealgorithms.cpp @@ -81,6 +81,7 @@ void QgsNativeAlgorithms::loadAlgorithms() addAlgorithm( new QgsFixGeometriesAlgorithm() ); addAlgorithm( new QgsMergeLinesAlgorithm() ); addAlgorithm( new QgsSmoothAlgorithm() ); + addAlgorithm( new QgsSimplifyAlgorithm() ); } void QgsCentroidAlgorithm::initAlgorithm( const QVariantMap & ) @@ -1751,5 +1752,66 @@ QgsFeature QgsSmoothAlgorithm::processFeature( const QgsFeature &feature, QgsPro return f; } +QString QgsSimplifyAlgorithm::shortHelpString() const +{ + return QObject::tr( "This algorithm simplifies the geometries in a line or polygon layer. It creates a new layer " + "with the same features as the ones in the input layer, but with geometries containing a lower number of vertices.\n\n" + "The algorithm gives a choice of simplification methods, including distance based " + "(the \"Douglas-Peucker\" algorithm), area based (\"Visvalingam\" algorithm) and snapping geometries to a grid." ); +} + +QgsSimplifyAlgorithm *QgsSimplifyAlgorithm::createInstance() const +{ + return new QgsSimplifyAlgorithm(); +} + +void QgsSimplifyAlgorithm::initParameters( const QVariantMap & ) +{ + QStringList methods; + methods << QObject::tr( "Distance (Douglas-Peucker)" ) + << QObject::tr( "Snap to grid" ) + << QObject::tr( "Area (Visvalingam)" ); + + addParameter( new QgsProcessingParameterEnum( + QStringLiteral( "METHOD" ), + QObject::tr( "Simplification method" ), + methods, false, 0 ) ); + addParameter( new QgsProcessingParameterNumber( QStringLiteral( "TOLERANCE" ), + QObject::tr( "Tolerance" ), QgsProcessingParameterNumber::Double, + 1.0, false, 0, 10000000.0 ) ); +} + +bool QgsSimplifyAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) +{ + mTolerance = parameterAsDouble( parameters, QStringLiteral( "TOLERANCE" ), context ); + mMethod = static_cast< QgsMapToPixelSimplifier::SimplifyAlgorithm >( parameterAsEnum( parameters, QStringLiteral( "METHOD" ), context ) ); + if ( mMethod != QgsMapToPixelSimplifier::Distance ) + mSimplifier.reset( new QgsMapToPixelSimplifier( QgsMapToPixelSimplifier::SimplifyGeometry, mTolerance, mMethod ) ); + + return true; +} + +QgsFeature QgsSimplifyAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback * ) +{ + QgsFeature f = feature; + if ( f.hasGeometry() ) + { + QgsGeometry inputGeometry = f.geometry(); + QgsGeometry outputGeometry; + if ( mMethod == QgsMapToPixelSimplifier::Distance ) + { + outputGeometry = inputGeometry.simplify( mTolerance ); + } + else + { + outputGeometry = mSimplifier->simplify( inputGeometry ); + } + f.setGeometry( outputGeometry ); + } + return f; +} + ///@endcond + + diff --git a/src/core/processing/qgsnativealgorithms.h b/src/core/processing/qgsnativealgorithms.h index 4c51f4ca399..b5a6e1737c4 100644 --- a/src/core/processing/qgsnativealgorithms.h +++ b/src/core/processing/qgsnativealgorithms.h @@ -24,6 +24,7 @@ #include "qgis.h" #include "qgsprocessingalgorithm.h" #include "qgsprocessingprovider.h" +#include "qgsmaptopixelgeometrysimplifier.h" ///@cond PRIVATE @@ -632,6 +633,35 @@ class QgsSmoothAlgorithm : public QgsProcessingFeatureBasedAlgorithm double mMaxAngle = 0; }; +/** + * Native simplify algorithm. + */ +class QgsSimplifyAlgorithm : public QgsProcessingFeatureBasedAlgorithm +{ + + public: + + QgsSimplifyAlgorithm() = default; + QString name() const override { return QStringLiteral( "simplifygeometries" ); } + QString displayName() const override { return QObject::tr( "Simplify geometries" ); } + virtual QStringList tags() const override { return QObject::tr( "simplify,generalize,douglas,peucker,visvalingam" ).split( ',' ); } + QString group() const override { return QObject::tr( "Vector geometry" ); } + QString shortHelpString() const override; + QgsSimplifyAlgorithm *createInstance() const override SIP_FACTORY; + void initParameters( const QVariantMap &configuration = QVariantMap() ) override; + + protected: + QString outputName() const override { return QObject::tr( "Simplified" ); } + bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override; + + private: + + double mTolerance = 1.0; + QgsMapToPixelSimplifier::SimplifyAlgorithm mMethod = QgsMapToPixelSimplifier::Distance; + std::unique_ptr< QgsMapToPixelSimplifier > mSimplifier; + +}; ///@endcond PRIVATE #endif // QGSNATIVEALGORITHMS_H