diff --git a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py deleted file mode 100644 index 5420d375c1c8..000000000000 --- a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - DensifyGeometriesInterval.py by Anita Graser, Dec 2012 - based on DensifyGeometries.py - --------------------- - Date : October 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__ = 'Anita Graser' -__date__ = 'Dec 2012' -__copyright__ = '(C) 2012, Anita Graser' - -# This will get replaced with a git SHA1 when you do a git archive - -__revision__ = '$Format:%H$' - -from qgis.core import (QgsProcessingParameterDistance, - QgsProcessing) - -from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm - - -class DensifyGeometriesInterval(QgisFeatureBasedAlgorithm): - - INTERVAL = 'INTERVAL' - - def tags(self): - return self.tr('add,vertex,vertices,points,nodes').split(',') - - def group(self): - return self.tr('Vector geometry') - - def groupId(self): - return 'vectorgeometry' - - def __init__(self): - super().__init__() - self.interval = None - - def initParameters(self, config=None): - self.addParameter(QgsProcessingParameterDistance(self.INTERVAL, - self.tr('Interval between vertices to add'), - 1, 'INPUT', False, 0, 10000000)) - - def name(self): - return 'densifygeometriesgivenaninterval' - - def displayName(self): - return self.tr('Densify by interval') - - def outputName(self): - return self.tr('Densified') - - def inputLayerTypes(self): - return [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon] - - def prepareAlgorithm(self, parameters, context, feedback): - self.interval = self.parameterAsDouble(parameters, self.INTERVAL, context) - return True - - def processFeature(self, feature, context, feedback): - if feature.hasGeometry(): - new_geometry = feature.geometry().densifyByDistance(float(self.interval)) - feature.setGeometry(new_geometry) - return [feature] diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py index c302b46b7525..32ddde1ebaaa 100644 --- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py @@ -61,7 +61,6 @@ from .DeleteColumn import DeleteColumn from .DeleteDuplicateGeometries import DeleteDuplicateGeometries from .DensifyGeometries import DensifyGeometries -from .DensifyGeometriesInterval import DensifyGeometriesInterval from .EliminateSelection import EliminateSelection from .ExecuteSQL import ExecuteSQL from .ExportGeometryInfo import ExportGeometryInfo @@ -172,7 +171,6 @@ def getAlgs(self): DeleteColumn(), DeleteDuplicateGeometries(), DensifyGeometries(), - DensifyGeometriesInterval(), EliminateSelection(), ExecuteSQL(), ExportGeometryInfo(), diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index 645f8f6feeb8..358c7eb39de2 100644 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -32,6 +32,7 @@ SET(QGIS_ANALYSIS_SRCS processing/qgsalgorithmclip.cpp processing/qgsalgorithmconvexhull.cpp processing/qgsalgorithmdbscanclustering.cpp + processing/qgsalgorithmdensifygeometries.cpp processing/qgsalgorithmdifference.cpp processing/qgsalgorithmdissolve.cpp processing/qgsalgorithmdrape.cpp diff --git a/src/analysis/processing/qgsalgorithmdensifygeometries.cpp b/src/analysis/processing/qgsalgorithmdensifygeometries.cpp new file mode 100644 index 000000000000..96c78f94eb4d --- /dev/null +++ b/src/analysis/processing/qgsalgorithmdensifygeometries.cpp @@ -0,0 +1,98 @@ +/*************************************************************************** + qgsalgorithmdensifygeometries.cpp + --------------------- + begin : January 2019 + copyright : (C) 2019 by Matthias Kuhn + email : matthias@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + + +#include "qgsalgorithmdensifygeometries.h" + +QString QgsDensifyGeometriesAlgorithm::name() const +{ + return QStringLiteral( "densifygeometriesgivenaninterval" ); +} + +QString QgsDensifyGeometriesAlgorithm::displayName() const +{ + return QObject::tr( "Densify by interval" ); +} + +QStringList QgsDensifyGeometriesAlgorithm::tags() const +{ + return QObject::tr( "add,vertex,vertices,points,nodes" ).split( ',' ); +} + +QString QgsDensifyGeometriesAlgorithm::group() const +{ + return QObject::tr( "Vector geometry" ); +} + +QString QgsDensifyGeometriesAlgorithm::groupId() const +{ + return QStringLiteral( "vectorgeometry" ); +} + +QString QgsDensifyGeometriesAlgorithm::shortHelpString() const +{ + return QObject::tr( "Geometries are densified by adding additional vertices on " + "edges that have a maximum distance of the interval parameter " + "in map units." ); +} + +QString QgsDensifyGeometriesAlgorithm::shortDescription() const +{ + return QObject::tr( "Creates a densified version of geometries." ); +} + +QgsDensifyGeometriesAlgorithm *QgsDensifyGeometriesAlgorithm::createInstance() const +{ + return new QgsDensifyGeometriesAlgorithm; + +} + +QList QgsDensifyGeometriesAlgorithm::inputLayerTypes() const +{ + return QList() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon; +} + +void QgsDensifyGeometriesAlgorithm::initParameters( const QVariantMap &configuration ) +{ + Q_UNUSED( configuration ) + addParameter( new QgsProcessingParameterDistance( QStringLiteral( "INTERVAL" ), + QObject::tr( "Interval between vertices to add" ), + 1, QStringLiteral( "INPUT" ), false, 0, 10000000 ) ); +} + +QString QgsDensifyGeometriesAlgorithm::outputName() const +{ + return QObject::tr( "Densified" ); +} + +QgsFeatureList QgsDensifyGeometriesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + Q_UNUSED( context ); + Q_UNUSED( feedback ); + QgsFeature modifiedFeature = feature; + if ( feature.hasGeometry() ) + modifiedFeature.setGeometry( feature.geometry().densifyByDistance( mInterval ) ); + + return QgsFeatureList() << modifiedFeature; +} + +bool QgsDensifyGeometriesAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + Q_UNUSED( feedback ); + mInterval = parameterAsDouble( parameters, QStringLiteral( "INTERVAL" ), context ); + return true; +} diff --git a/src/analysis/processing/qgsalgorithmdensifygeometries.h b/src/analysis/processing/qgsalgorithmdensifygeometries.h new file mode 100644 index 000000000000..fd88654ffe08 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmdensifygeometries.h @@ -0,0 +1,55 @@ +/*************************************************************************** + qgsalgorithmdensifygeometries.h + --------------------- + begin : January 2019 + copyright : (C) 2019 by Matthias Kuhn + email : matthias@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +#ifndef QGSALGORITHMDENSIFYGEOMETRIES_H +#define QGSALGORITHMDENSIFYGEOMETRIES_H + +#define SIP_NO_FILE + +#include "qgis.h" +#include "qgsprocessingalgorithm.h" + +///@cond PRIVATE + + +class QgsDensifyGeometriesAlgorithm : public QgsProcessingFeatureBasedAlgorithm +{ + public: + + QgsDensifyGeometriesAlgorithm() = default; + QString name() const override; + QString displayName() const override; + QStringList tags() const override; + QString group() const override; + QString groupId() const override; + QString shortHelpString() const override; + QString shortDescription() const override; + QgsDensifyGeometriesAlgorithm *createInstance() const override SIP_FACTORY; + QList inputLayerTypes() const override; + + protected: + void initParameters( const QVariantMap &configuration = QVariantMap() ) override; + QString outputName() const override; + QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + + private: + double mInterval = 0.0; +}; + +///@endcond PRIVATE +#endif // QGSALGORITHMDENSIFYGEOMETRIES_H diff --git a/src/analysis/processing/qgsnativealgorithms.cpp b/src/analysis/processing/qgsnativealgorithms.cpp index f4687b9c540f..5ca56083b835 100644 --- a/src/analysis/processing/qgsnativealgorithms.cpp +++ b/src/analysis/processing/qgsnativealgorithms.cpp @@ -27,6 +27,7 @@ #include "qgsalgorithmclip.h" #include "qgsalgorithmconvexhull.h" #include "qgsalgorithmdbscanclustering.h" +#include "qgsalgorithmdensifygeometries.h" #include "qgsalgorithmdifference.h" #include "qgsalgorithmdissolve.h" #include "qgsalgorithmdrape.h" @@ -246,6 +247,7 @@ void QgsNativeAlgorithms::loadAlgorithms() addAlgorithm( new QgsWedgeBuffersAlgorithm() ); addAlgorithm( new QgsZonalHistogramAlgorithm() ); addAlgorithm( new QgsPolygonsToLinesAlgorithm() ); + addAlgorithm( new QgsDensifyGeometriesAlgorithm() ); } diff --git a/tests/src/analysis/testqgsprocessingalgs.cpp b/tests/src/analysis/testqgsprocessingalgs.cpp index bcccb4d4cb0f..38b596f3420e 100644 --- a/tests/src/analysis/testqgsprocessingalgs.cpp +++ b/tests/src/analysis/testqgsprocessingalgs.cpp @@ -42,7 +42,7 @@ class TestQgsProcessingAlgs: public QObject */ std::unique_ptr featureBasedAlg( const QString &id ); - QgsFeature runForFeature( const std::unique_ptr &alg, QgsFeature feature, const QString &layerType ); + QgsFeature runForFeature( const std::unique_ptr &alg, QgsFeature feature, const QString &layerType, QVariantMap parameters = QVariantMap() ); private slots: void initTestCase();// will be called before the first testfunction is executed. @@ -58,9 +58,13 @@ class TestQgsProcessingAlgs: public QObject void kmeansCluster(); void categorizeByStyle(); void extractBinary(); + void polygonsToLines_data(); void polygonsToLines(); + void densifyGeometries_data(); + void densifyGeometries(); + private: QString mPointLayerPath; @@ -74,8 +78,9 @@ std::unique_ptr TestQgsProcessingAlgs::featu return std::unique_ptr( static_cast( QgsApplication::processingRegistry()->createAlgorithmById( id ) ) ); } -QgsFeature TestQgsProcessingAlgs::runForFeature( const std::unique_ptr< QgsProcessingFeatureBasedAlgorithm > &alg, QgsFeature feature, const QString &layerType ) +QgsFeature TestQgsProcessingAlgs::runForFeature( const std::unique_ptr< QgsProcessingFeatureBasedAlgorithm > &alg, QgsFeature feature, const QString &layerType, QVariantMap parameters ) { + Q_ASSERT( alg.get() ); std::unique_ptr< QgsProcessingContext > context = qgis::make_unique< QgsProcessingContext >(); QgsProject p; context->setProject( &p ); @@ -83,8 +88,6 @@ QgsFeature TestQgsProcessingAlgs::runForFeature( const std::unique_ptr< QgsProce QgsProcessingFeedback feedback; context->setFeedback( &feedback ); - QVariantMap parameters; - std::unique_ptr inputLayer( qgis::make_unique( layerType, QStringLiteral( "layer" ), QStringLiteral( "memory" ) ) ); inputLayer->dataProvider()->addFeature( feature ); @@ -753,5 +756,90 @@ void TestQgsProcessingAlgs::polygonsToLines() QVERIFY2( result.geometry().equals( expectedGeometry ), QStringLiteral( "Result: %1, Expected: %2" ).arg( result.geometry().asWkt(), expectedGeometry.asWkt() ).toUtf8().constData() ); } +void TestQgsProcessingAlgs::densifyGeometries_data() +{ + QTest::addColumn( "sourceGeometry" ); + QTest::addColumn( "expectedGeometry" ); + QTest::addColumn( "interval" ); + QTest::addColumn( "geometryType" ); + + QTest::newRow( "Null geometry" ) + << QgsGeometry() + << QgsGeometry() + << 0.1 + << "Point"; + + QTest::newRow( "PointZ" ) + << QgsGeometry::fromWkt( "PointZ( 1 2 3 )" ) + << QgsGeometry::fromWkt( "PointZ( 1 2 3 )" ) + << 0.1 + << "Point"; + + QTest::newRow( "MultiPoint" ) + << QgsGeometry::fromWkt( "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))" ) + << QgsGeometry::fromWkt( "MULTIPOINT ((155 271), (150 360), (260 360), (271 265), (280 260), (270 370), (154 354), (150 260))" ) + << 0.1 + << "Point"; + + QTest::newRow( "LineString big distance" ) + << QgsGeometry::fromWkt( "LineString( 0 0, 10 0, 10 10 )" ) + << QgsGeometry::fromWkt( "LineString( 0 0, 10 0, 10 10 )" ) + << 100. + << "LineString"; + + QTest::newRow( "LineString small distance" ) + << QgsGeometry::fromWkt( "LineString( 0 0, 10 0, 10 10 )" ) + << QgsGeometry::fromWkt( "LineString (0 0, 2.5 0, 5 0, 7.5 0, 10 0, 10 2.5, 10 5, 10 7.5, 10 10)" ) + << 3. + << "LineString"; + + QTest::newRow( "LineStringZ" ) + << QgsGeometry::fromWkt( "LineStringZ( 0 0 1, 10 0 2, 10 10 0)" ) + << QgsGeometry::fromWkt( "LineStringZ (0 0 1, 5 0 1.5, 10 0 2, 10 5 1, 10 10 0)" ) + << 6. + << "LineString"; + + QTest::newRow( "LineStringM" ) + << QgsGeometry::fromWkt( "LineStringM( 0 0 0, 10 0 2, 10 10 0)" ) + << QgsGeometry::fromWkt( "LineStringM (0 0 0, 2.5 0 0.5, 5 0 1, 7.5 0 1.5, 10 0 2, 10 2.5 1.5, 10 5 1, 10 7.5 0.5, 10 10 0)" ) + << 3. + << "LineString"; + + QTest::newRow( "LineStringZM" ) + << QgsGeometry::fromWkt( "LineStringZM( 0 0 1 10, 10 0 2 8, 10 10 0 4)" ) + << QgsGeometry::fromWkt( "LineStringZM (0 0 1 10, 5 0 1.5 9, 10 0 2 8, 10 5 1 6, 10 10 0 4)" ) + << 6. + << "LineString"; + + QTest::newRow( "Polygon" ) + << QgsGeometry::fromWkt( "Polygon(( 0 0, 20 0, 20 20, 0 0 ))" ) + << QgsGeometry::fromWkt( "Polygon ((0 0, 5 0, 10 0, 15 0, 20 0, 20 5, 20 10, 20 15, 20 20, 16 16, 12 12, 7.99999999999999822 7.99999999999999822, 4 4, 0 0))" ) + << 6. + << "Polygon"; +} + +void TestQgsProcessingAlgs::densifyGeometries() +{ + QFETCH( QgsGeometry, sourceGeometry ); + QFETCH( QgsGeometry, expectedGeometry ); + QFETCH( double, interval ); + QFETCH( QString, geometryType ); + + std::unique_ptr< QgsProcessingFeatureBasedAlgorithm > alg( featureBasedAlg( "native:densifygeometriesgivenaninterval" ) ); + + QVariantMap parameters; + parameters.insert( QStringLiteral( "INTERVAL" ), interval ); + + QgsFeature feature; + feature.setGeometry( sourceGeometry ); + + QgsFeature result = runForFeature( alg, feature, geometryType, parameters ); + + if ( expectedGeometry.isNull() ) + QVERIFY( result.geometry().isNull() ); + else + QVERIFY2( result.geometry().equals( expectedGeometry ), QStringLiteral( "Result: %1, Expected: %2" ).arg( result.geometry().asWkt(), expectedGeometry.asWkt() ).toUtf8().constData() ); +} + QGSTEST_MAIN( TestQgsProcessingAlgs ) #include "testqgsprocessingalgs.moc"