From 2951afa3241a9188b46ff107a7cac397a1d2076a Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 13 Oct 2017 08:28:34 +1000 Subject: [PATCH] Port boundary algorithm to c++ Also allow feature based algorithms to customise their appectable input layers types and set suitable filters for all applicable algorithms --- .../processing/qgsprocessingalgorithm.sip | 8 ++ .../processing/algs/qgis/AddTableField.py | 4 + .../plugins/processing/algs/qgis/Boundary.py | 81 ----------------- .../processing/algs/qgis/DeleteColumn.py | 6 +- .../processing/algs/qgis/DeleteHoles.py | 6 +- .../processing/algs/qgis/DensifyGeometries.py | 6 +- .../algs/qgis/DensifyGeometriesInterval.py | 6 +- .../processing/algs/qgis/ExtendLines.py | 6 +- .../processing/algs/qgis/FieldsMapper.py | 4 + .../processing/algs/qgis/LinesToPolygons.py | 3 + .../processing/algs/qgis/OffsetLine.py | 3 + .../processing/algs/qgis/Orthogonalize.py | 6 +- .../processing/algs/qgis/PolygonsToLines.py | 3 + .../algs/qgis/QGISAlgorithmProvider.py | 2 - .../algs/qgis/ReverseLineDirection.py | 3 + .../processing/algs/qgis/SingleSidedBuffer.py | 3 + .../processing/algs/qgis/TextToFloat.py | 4 + .../tests/testdata/qgis_algorithm_tests.yaml | 8 +- src/core/processing/qgsnativealgorithms.cpp | 88 +++++++++++++++++++ src/core/processing/qgsnativealgorithms.h | 28 ++++++ .../processing/qgsprocessingalgorithm.cpp | 36 +++++++- src/core/processing/qgsprocessingalgorithm.h | 19 ++-- 22 files changed, 233 insertions(+), 100 deletions(-) delete mode 100644 python/plugins/processing/algs/qgis/Boundary.py diff --git a/python/core/processing/qgsprocessingalgorithm.sip b/python/core/processing/qgsprocessingalgorithm.sip index a6e7d542bb47..c2a400c4627d 100644 --- a/python/core/processing/qgsprocessingalgorithm.sip +++ b/python/core/processing/qgsprocessingalgorithm.sip @@ -801,6 +801,14 @@ class QgsProcessingFeatureBasedAlgorithm : QgsProcessingAlgorithm :rtype: str %End + virtual QList inputLayerTypes() const; +%Docstring + Returns the valid input layer types for the source layer for this algorithm. + By default vector layers with any geometry types (excluding non-spatial, geometryless layers) + are accepted. + :rtype: list of int +%End + virtual QgsProcessing::SourceType outputLayerType() const; %Docstring Returns the layer type for layers generated by this algorithm, if diff --git a/python/plugins/processing/algs/qgis/AddTableField.py b/python/plugins/processing/algs/qgis/AddTableField.py index 76a93d687b7c..1dafae3f977b 100644 --- a/python/plugins/processing/algs/qgis/AddTableField.py +++ b/python/plugins/processing/algs/qgis/AddTableField.py @@ -27,6 +27,7 @@ from qgis.PyQt.QtCore import QVariant from qgis.core import (QgsField, + QgsProcessing, QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterEnum) @@ -72,6 +73,9 @@ def displayName(self): def outputName(self): return self.tr('Added') + def inputLayerTypes(self): + return [QgsProcessing.TypeVector] + def prepareAlgorithm(self, parameters, context, feedback): field_type = self.parameterAsEnum(parameters, self.FIELD_TYPE, context) field_name = self.parameterAsString(parameters, self.FIELD_NAME, context) diff --git a/python/plugins/processing/algs/qgis/Boundary.py b/python/plugins/processing/algs/qgis/Boundary.py deleted file mode 100644 index c6ecc309c0ff..000000000000 --- a/python/plugins/processing/algs/qgis/Boundary.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - Boundary.py - -------------- - Date : July 2016 - Copyright : (C) 2016 by Nyall Dawson - Email : nyall dot dawson 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__ = 'Nyall Dawson' -__date__ = 'July 2016' -__copyright__ = '(C) 2016, Nyall Dawson' - -# This will get replaced with a git SHA1 when you do a git archive323 - -__revision__ = '$Format:%H$' - -import os - -from qgis.core import (QgsGeometry, - QgsWkbTypes) - -from qgis.PyQt.QtGui import QIcon - -from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm - -pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] - - -class Boundary(QgisFeatureBasedAlgorithm): - - def __init__(self): - super().__init__() - - def icon(self): - return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'convex_hull.png')) - - def group(self): - return self.tr('Vector geometry') - - def name(self): - return 'boundary' - - def displayName(self): - return self.tr('Boundary') - - def outputName(self): - return self.tr('Boundary') - - def outputWkbType(self, input_wkb): - if QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.LineGeometry: - output_wkb = QgsWkbTypes.MultiPoint - elif QgsWkbTypes.geometryType(input_wkb) == QgsWkbTypes.PolygonGeometry: - output_wkb = QgsWkbTypes.MultiLineString - if QgsWkbTypes.hasZ(input_wkb): - output_wkb = QgsWkbTypes.addZ(output_wkb) - if QgsWkbTypes.hasM(input_wkb): - output_wkb = QgsWkbTypes.addM(output_wkb) - - return output_wkb - - def processFeature(self, feature, feedback): - input_geometry = feature.geometry() - if input_geometry: - output_geometry = QgsGeometry(input_geometry.geometry().boundary()) - if not output_geometry: - feedback.reportError(self.tr('No boundary for feature {} (possibly a closed linestring?)').format(feature.id())) - feature.clearGeometry() - else: - feature.setGeometry(output_geometry) - return feature diff --git a/python/plugins/processing/algs/qgis/DeleteColumn.py b/python/plugins/processing/algs/qgis/DeleteColumn.py index f723386a528d..bb81d4de56b0 100644 --- a/python/plugins/processing/algs/qgis/DeleteColumn.py +++ b/python/plugins/processing/algs/qgis/DeleteColumn.py @@ -25,7 +25,8 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsProcessingParameterField) +from qgis.core import (QgsProcessingParameterField, + QgsProcessing) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm @@ -49,6 +50,9 @@ def initParameters(self, config=None): self.tr('Fields to drop'), None, 'INPUT', QgsProcessingParameterField.Any, True)) + def inputLayerTypes(self): + return [QgsProcessing.TypeVector] + def name(self): return 'deletecolumn' diff --git a/python/plugins/processing/algs/qgis/DeleteHoles.py b/python/plugins/processing/algs/qgis/DeleteHoles.py index 795e6fdef140..503841e9c400 100644 --- a/python/plugins/processing/algs/qgis/DeleteHoles.py +++ b/python/plugins/processing/algs/qgis/DeleteHoles.py @@ -24,7 +24,8 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsProcessingParameterNumber) +from qgis.core import (QgsProcessingParameterNumber, + QgsProcessing) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm @@ -56,6 +57,9 @@ def displayName(self): def outputName(self): return self.tr('Cleaned') + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorPolygon] + def prepareAlgorithm(self, parameters, context, feedback): self.min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context) if self.min_area == 0.0: diff --git a/python/plugins/processing/algs/qgis/DensifyGeometries.py b/python/plugins/processing/algs/qgis/DensifyGeometries.py index 396508ece47f..9375dc7098b6 100644 --- a/python/plugins/processing/algs/qgis/DensifyGeometries.py +++ b/python/plugins/processing/algs/qgis/DensifyGeometries.py @@ -28,7 +28,8 @@ import os -from qgis.core import (QgsProcessingParameterNumber) +from qgis.core import (QgsProcessingParameterNumber, + QgsProcessing) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm @@ -61,6 +62,9 @@ def displayName(self): def outputName(self): return self.tr('Densified') + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon] + def prepareAlgorithm(self, parameters, context, feedback): self.vertices = self.parameterAsInt(parameters, self.VERTICES, context) return True diff --git a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py index f54d4905e558..90d9c164c77b 100644 --- a/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py +++ b/python/plugins/processing/algs/qgis/DensifyGeometriesInterval.py @@ -27,7 +27,8 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsProcessingParameterNumber) +from qgis.core import (QgsProcessingParameterNumber, + QgsProcessing) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm @@ -57,6 +58,9 @@ def displayName(self): def outputName(self): return self.tr('Densified') + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorLine, QgsProcessing.TypeVectorPolygon] + def prepareAlgorithm(self, parameters, context, feedback): interval = self.parameterAsDouble(parameters, self.INTERVAL, context) return True diff --git a/python/plugins/processing/algs/qgis/ExtendLines.py b/python/plugins/processing/algs/qgis/ExtendLines.py index c3377256fb37..02848c1a26bf 100644 --- a/python/plugins/processing/algs/qgis/ExtendLines.py +++ b/python/plugins/processing/algs/qgis/ExtendLines.py @@ -26,7 +26,8 @@ __revision__ = '$Format:%H$' from qgis.core import (QgsProcessingParameterNumber, - QgsProcessingException) + QgsProcessingException, + QgsProcessing) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm @@ -58,6 +59,9 @@ def displayName(self): def outputName(self): return self.tr('Extended') + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorLine] + def prepareAlgorithm(self, parameters, context, feedback): self.start_distance = self.parameterAsDouble(parameters, self.START_DISTANCE, context) self.end_distance = self.parameterAsDouble(parameters, self.END_DISTANCE, context) diff --git a/python/plugins/processing/algs/qgis/FieldsMapper.py b/python/plugins/processing/algs/qgis/FieldsMapper.py index a376d16d0049..3060615a9fd6 100644 --- a/python/plugins/processing/algs/qgis/FieldsMapper.py +++ b/python/plugins/processing/algs/qgis/FieldsMapper.py @@ -30,6 +30,7 @@ QgsExpression, QgsField, QgsFields, + QgsProcessing, QgsProcessingException, QgsProcessingParameterDefinition) @@ -103,6 +104,9 @@ def displayName(self): def outputName(self): return self.tr('Refactored') + def inputLayerTypes(self): + return [QgsProcessing.TypeVector] + def parameterAsFieldsMapping(self, parameters, name, context): return parameters[name] diff --git a/python/plugins/processing/algs/qgis/LinesToPolygons.py b/python/plugins/processing/algs/qgis/LinesToPolygons.py index faa1e6a341e0..8d58d59e8e70 100644 --- a/python/plugins/processing/algs/qgis/LinesToPolygons.py +++ b/python/plugins/processing/algs/qgis/LinesToPolygons.py @@ -74,6 +74,9 @@ def outputName(self): def outputType(self): return QgsProcessing.TypeVectorPolygon + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorLine] + def outputWkbType(self, input_wkb_type): return self.convertWkbToPolygons(input_wkb_type) diff --git a/python/plugins/processing/algs/qgis/OffsetLine.py b/python/plugins/processing/algs/qgis/OffsetLine.py index 912e3d1fe2f4..2bf10c97836c 100644 --- a/python/plugins/processing/algs/qgis/OffsetLine.py +++ b/python/plugins/processing/algs/qgis/OffsetLine.py @@ -87,6 +87,9 @@ def displayName(self): def outputName(self): return self.tr('Offset') + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorLine] + def outputType(self): return QgsProcessing.TypeVectorLine diff --git a/python/plugins/processing/algs/qgis/Orthogonalize.py b/python/plugins/processing/algs/qgis/Orthogonalize.py index acf5b38599c5..f01dad58502d 100644 --- a/python/plugins/processing/algs/qgis/Orthogonalize.py +++ b/python/plugins/processing/algs/qgis/Orthogonalize.py @@ -25,7 +25,8 @@ __revision__ = '$Format:%H$' -from qgis.core import (QgsProcessingException, +from qgis.core import (QgsProcessing, + QgsProcessingException, QgsProcessingParameterDefinition, QgsProcessingParameterNumber) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm @@ -70,6 +71,9 @@ def displayName(self): def outputName(self): return self.tr('Orthogonalized') + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorPolygon, QgsProcessing.TypeVectorLine] + def prepareAlgorithm(self, parameters, context, feedback): self.max_iterations = self.parameterAsInt(parameters, self.MAX_ITERATIONS, context) self.angle_tolerance = self.parameterAsDouble(parameters, self.ANGLE_TOLERANCE, context) diff --git a/python/plugins/processing/algs/qgis/PolygonsToLines.py b/python/plugins/processing/algs/qgis/PolygonsToLines.py index d07a1bed3d60..a19ffd3cbac2 100644 --- a/python/plugins/processing/algs/qgis/PolygonsToLines.py +++ b/python/plugins/processing/algs/qgis/PolygonsToLines.py @@ -67,6 +67,9 @@ def outputName(self): def outputType(self): return QgsProcessing.TypeVectorLine + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorPolygon] + def outputWkbType(self, input_wkb_type): return self.convertWkbToLines(input_wkb_type) diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index 8e165d6da9cd..43cf2d69a633 100755 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -44,7 +44,6 @@ from .Aggregate import Aggregate from .Aspect import Aspect from .BasicStatistics import BasicStatisticsForField -from .Boundary import Boundary from .CheckValidity import CheckValidity from .ConcaveHull import ConcaveHull from .CreateAttributeIndex import CreateAttributeIndex @@ -174,7 +173,6 @@ def getAlgs(self): Aggregate(), Aspect(), BasicStatisticsForField(), - Boundary(), CheckValidity(), ConcaveHull(), CreateAttributeIndex(), diff --git a/python/plugins/processing/algs/qgis/ReverseLineDirection.py b/python/plugins/processing/algs/qgis/ReverseLineDirection.py index bdde660acd41..695a870f1e55 100644 --- a/python/plugins/processing/algs/qgis/ReverseLineDirection.py +++ b/python/plugins/processing/algs/qgis/ReverseLineDirection.py @@ -51,6 +51,9 @@ def outputName(self): def outputType(self): return QgsProcessing.TypeVectorLine + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorLine] + def processFeature(self, feature, feedback): if feature.geometry(): inGeom = feature.geometry() diff --git a/python/plugins/processing/algs/qgis/SingleSidedBuffer.py b/python/plugins/processing/algs/qgis/SingleSidedBuffer.py index 806e09888e9c..abff1690ce5b 100644 --- a/python/plugins/processing/algs/qgis/SingleSidedBuffer.py +++ b/python/plugins/processing/algs/qgis/SingleSidedBuffer.py @@ -86,6 +86,9 @@ def displayName(self): def outputName(self): return self.tr('Buffers') + def inputLayerTypes(self): + return [QgsProcessing.TypeVectorLine] + def outputType(self): return QgsProcessing.TypeVectorPolygon diff --git a/python/plugins/processing/algs/qgis/TextToFloat.py b/python/plugins/processing/algs/qgis/TextToFloat.py index d62d9db2a34a..9d2d9f3cd9c0 100644 --- a/python/plugins/processing/algs/qgis/TextToFloat.py +++ b/python/plugins/processing/algs/qgis/TextToFloat.py @@ -27,6 +27,7 @@ from qgis.PyQt.QtCore import QVariant from qgis.core import (QgsField, + QgsProcessing, QgsProcessingParameterField) from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm @@ -59,6 +60,9 @@ def displayName(self): def outputName(self): return self.tr('Float from text') + def inputLayerTypes(self): + return [QgsProcessing.TypeVector] + def outputFields(self, inputFields): self.field_idx = inputFields.lookupField(self.field_name) if self.field_idx >= 0: diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 458e47963eb5..0bbaac965023 100755 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -665,7 +665,7 @@ tests: name: expected/multipoint_bounds.gml type: vector - - algorithm: qgis:boundary + - algorithm: native:boundary name: Polygon boundary params: INPUT: @@ -676,7 +676,7 @@ tests: name: expected/poly_boundary.gml type: vector - - algorithm: qgis:boundary + - algorithm: native:boundary name: Multipoly boundary params: INPUT: @@ -687,7 +687,7 @@ tests: name: expected/multipoly_boundary.gml type: vector - - algorithm: qgis:boundary + - algorithm: native:boundary name: Line boundary params: INPUT: @@ -698,7 +698,7 @@ tests: name: expected/lines_boundary.gml type: vector - - algorithm: qgis:boundary + - algorithm: native:boundary name: Multiline boundary params: INPUT: diff --git a/src/core/processing/qgsnativealgorithms.cpp b/src/core/processing/qgsnativealgorithms.cpp index b351b17041e8..205f09b9d5ef 100644 --- a/src/core/processing/qgsnativealgorithms.cpp +++ b/src/core/processing/qgsnativealgorithms.cpp @@ -94,6 +94,7 @@ void QgsNativeAlgorithms::loadAlgorithms() addAlgorithm( new QgsJoinWithLinesAlgorithm() ); addAlgorithm( new QgsAssignProjectionAlgorithm() ); addAlgorithm( new QgsAddIncrementalFieldAlgorithm() ); + addAlgorithm( new QgsBoundaryAlgorithm() ); } void QgsSaveSelectedFeatures::initAlgorithm( const QVariantMap & ) @@ -707,6 +708,11 @@ QString QgsAddIncrementalFieldAlgorithm::shortHelpString() const "The initial starting value for the incremental series can be specified." ); } +QList QgsAddIncrementalFieldAlgorithm::inputLayerTypes() const +{ + return QList() << QgsProcessing::TypeVector; +} + QgsAddIncrementalFieldAlgorithm *QgsAddIncrementalFieldAlgorithm::createInstance() const { return new QgsAddIncrementalFieldAlgorithm(); @@ -1834,6 +1840,11 @@ QString QgsMergeLinesAlgorithm::shortHelpString() const "geometry will be a MultiLineString containing any lines which could be merged and any non-connected line parts." ); } +QList QgsMergeLinesAlgorithm::inputLayerTypes() const +{ + return QList() << QgsProcessing::TypeVectorLine; +} + QgsMergeLinesAlgorithm *QgsMergeLinesAlgorithm::createInstance() const { return new QgsMergeLinesAlgorithm(); @@ -1874,6 +1885,11 @@ QgsSmoothAlgorithm *QgsSmoothAlgorithm::createInstance() const return new QgsSmoothAlgorithm(); } +QList QgsSmoothAlgorithm::inputLayerTypes() const +{ + return QList() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon; +} + void QgsSmoothAlgorithm::initParameters( const QVariantMap & ) { addParameter( new QgsProcessingParameterNumber( QStringLiteral( "ITERATIONS" ), @@ -1923,6 +1939,11 @@ QgsSimplifyAlgorithm *QgsSimplifyAlgorithm::createInstance() const return new QgsSimplifyAlgorithm(); } +QList QgsSimplifyAlgorithm::inputLayerTypes() const +{ + return QList() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon; +} + void QgsSimplifyAlgorithm::initParameters( const QVariantMap & ) { QStringList methods; @@ -3174,5 +3195,72 @@ QVariantMap QgsJoinWithLinesAlgorithm::processAlgorithm( const QVariantMap ¶ return outputs; } +QString QgsBoundaryAlgorithm::shortHelpString() const +{ + return QObject::tr( "Returns the closure of the combinatorial boundary of the input geometries (ie the " + "topological boundary of the geometry). For instance, a polygon geometry will have a " + "boundary consisting of the linestrings for each ring in the polygon. Only valid for " + "polygon or line layers." ); +} + +QList QgsBoundaryAlgorithm::inputLayerTypes() const +{ + return QList() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPolygon; +} + +QgsBoundaryAlgorithm *QgsBoundaryAlgorithm::createInstance() const +{ + return new QgsBoundaryAlgorithm(); +} + +QgsWkbTypes::Type QgsBoundaryAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const +{ + QgsWkbTypes::Type outputWkb = QgsWkbTypes::Unknown; + switch ( QgsWkbTypes::geometryType( inputWkbType ) ) + { + case QgsWkbTypes::LineGeometry: + outputWkb = QgsWkbTypes::MultiPoint; + break; + + case QgsWkbTypes::PolygonGeometry: + outputWkb = QgsWkbTypes::MultiLineString; + break; + + case QgsWkbTypes::PointGeometry: + case QgsWkbTypes::UnknownGeometry: + case QgsWkbTypes::NoGeometry: + outputWkb = QgsWkbTypes::NoGeometry; + break; + } + + if ( QgsWkbTypes::hasZ( inputWkbType ) ) + outputWkb = QgsWkbTypes::addZ( outputWkb ); + if ( QgsWkbTypes::hasM( inputWkbType ) ) + outputWkb = QgsWkbTypes::addM( outputWkb ); + + return outputWkb; +} + +QgsFeature QgsBoundaryAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) +{ + QgsFeature outFeature = feature; + + if ( feature.hasGeometry() ) + { + QgsGeometry inputGeometry = feature.geometry(); + QgsGeometry outputGeometry = QgsGeometry( inputGeometry.geometry()->boundary() ); + if ( !outputGeometry ) + { + feedback->reportError( QObject::tr( "No boundary for feature %1 (possibly a closed linestring?)'" ).arg( feature.id() ) ); + outFeature.clearGeometry(); + } + else + { + outFeature.setGeometry( outputGeometry ); + } + } + return outFeature; +} + ///@endcond diff --git a/src/core/processing/qgsnativealgorithms.h b/src/core/processing/qgsnativealgorithms.h index e4c67b0de622..e4f8d7fdcba2 100644 --- a/src/core/processing/qgsnativealgorithms.h +++ b/src/core/processing/qgsnativealgorithms.h @@ -98,6 +98,30 @@ class QgsCentroidAlgorithm : public QgsProcessingFeatureBasedAlgorithm QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override; }; +/** + * Native boundary algorithm. + */ +class QgsBoundaryAlgorithm : public QgsProcessingFeatureBasedAlgorithm +{ + + public: + + QgsBoundaryAlgorithm() = default; + QString name() const override { return QStringLiteral( "boundary" ); } + QString displayName() const override { return QObject::tr( "Boundary" ); } + QStringList tags() const override { return QObject::tr( "boundary,ring,border,exterior" ).split( ',' ); } + QString group() const override { return QObject::tr( "Vector geometry" ); } + QString shortHelpString() const override; + QList inputLayerTypes() const override; + QgsBoundaryAlgorithm *createInstance() const override SIP_FACTORY; + + protected: + + QString outputName() const override { return QObject::tr( "Boundary" ); } + QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override; + QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override; +}; + /** * Native transform algorithm. */ @@ -179,6 +203,7 @@ class QgsAddIncrementalFieldAlgorithm : public QgsProcessingFeatureBasedAlgorith virtual QStringList tags() const override { return QObject::tr( "add,create,serial,primary,key,unique,field" ).split( ',' ); } QString group() const override { return QObject::tr( "Vector table" ); } QString shortHelpString() const override; + QList inputLayerTypes() const override; QgsAddIncrementalFieldAlgorithm *createInstance() const override SIP_FACTORY; protected: @@ -686,6 +711,7 @@ class QgsMergeLinesAlgorithm : public QgsProcessingFeatureBasedAlgorithm virtual QStringList tags() const override { return QObject::tr( "line,merge,join,parts" ).split( ',' ); } QString group() const override { return QObject::tr( "Vector geometry" ); } QString shortHelpString() const override; + QList inputLayerTypes() const override; QgsMergeLinesAlgorithm *createInstance() const override SIP_FACTORY; protected: @@ -711,6 +737,7 @@ class QgsSmoothAlgorithm : public QgsProcessingFeatureBasedAlgorithm QString group() const override { return QObject::tr( "Vector geometry" ); } QString shortHelpString() const override; QgsSmoothAlgorithm *createInstance() const override SIP_FACTORY; + QList inputLayerTypes() const override; void initParameters( const QVariantMap &configuration = QVariantMap() ) override; protected: @@ -740,6 +767,7 @@ class QgsSimplifyAlgorithm : public QgsProcessingFeatureBasedAlgorithm QString group() const override { return QObject::tr( "Vector geometry" ); } QString shortHelpString() const override; QgsSimplifyAlgorithm *createInstance() const override SIP_FACTORY; + QList inputLayerTypes() const override; void initParameters( const QVariantMap &configuration = QVariantMap() ) override; protected: diff --git a/src/core/processing/qgsprocessingalgorithm.cpp b/src/core/processing/qgsprocessingalgorithm.cpp index 684cb69ca998..8e568e4e9609 100644 --- a/src/core/processing/qgsprocessingalgorithm.cpp +++ b/src/core/processing/qgsprocessingalgorithm.cpp @@ -629,11 +629,45 @@ bool QgsProcessingAlgorithm::createAutoOutputForParameter( QgsProcessingParamete void QgsProcessingFeatureBasedAlgorithm::initAlgorithm( const QVariantMap &config ) { - addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) ); + addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ), inputLayerTypes() ) ); initParameters( config ); addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), outputName(), outputLayerType() ) ); } +QList QgsProcessingFeatureBasedAlgorithm::inputLayerTypes() const +{ + return QList(); +} + +QgsProcessing::SourceType QgsProcessingFeatureBasedAlgorithm::outputLayerType() const +{ + return QgsProcessing::TypeVectorAnyGeometry; +} + +QgsProcessingFeatureSource::Flag QgsProcessingFeatureBasedAlgorithm::sourceFlags() const +{ + return static_cast( 0 ); +} + +QgsWkbTypes::Type QgsProcessingFeatureBasedAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const +{ + return inputWkbType; +} + +QgsFields QgsProcessingFeatureBasedAlgorithm::outputFields( const QgsFields &inputFields ) const +{ + return inputFields; +} + +QgsCoordinateReferenceSystem QgsProcessingFeatureBasedAlgorithm::outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const +{ + return inputCrs; +} + +void QgsProcessingFeatureBasedAlgorithm::initParameters( const QVariantMap & ) +{ +} + QgsCoordinateReferenceSystem QgsProcessingFeatureBasedAlgorithm::sourceCrs() const { if ( mSource ) diff --git a/src/core/processing/qgsprocessingalgorithm.h b/src/core/processing/qgsprocessingalgorithm.h index dcee1dcc55e1..1e1fcc89ac46 100644 --- a/src/core/processing/qgsprocessingalgorithm.h +++ b/src/core/processing/qgsprocessingalgorithm.h @@ -790,16 +790,23 @@ class CORE_EXPORT QgsProcessingFeatureBasedAlgorithm : public QgsProcessingAlgor */ virtual QString outputName() const = 0; + /** + * Returns the valid input layer types for the source layer for this algorithm. + * By default vector layers with any geometry types (excluding non-spatial, geometryless layers) + * are accepted. + */ + virtual QList inputLayerTypes() const; + /** * Returns the layer type for layers generated by this algorithm, if * this is possible to determine in advance. */ - virtual QgsProcessing::SourceType outputLayerType() const { return QgsProcessing::TypeVectorAnyGeometry; } + virtual QgsProcessing::SourceType outputLayerType() const; /** * Returns the processing feature source flags to be used in the algorithm. */ - virtual QgsProcessingFeatureSource::Flag sourceFlags() const { return static_cast( 0 ); } + virtual QgsProcessingFeatureSource::Flag sourceFlags() const; /** * Maps the input WKB geometry type (\a inputWkbType) to the corresponding @@ -808,7 +815,7 @@ class CORE_EXPORT QgsProcessingFeatureBasedAlgorithm : public QgsProcessingAlgor * This is called once by the base class when creating the output sink for the algorithm (i.e. it is * not called once per feature processed). */ - virtual QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const { return inputWkbType; } + virtual QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const; /** * Maps the input source fields (\a inputFields) to corresponding @@ -820,7 +827,7 @@ class CORE_EXPORT QgsProcessingFeatureBasedAlgorithm : public QgsProcessingAlgor * This is called once by the base class when creating the output sink for the algorithm (i.e. it is * not called once per feature processed). */ - virtual QgsFields outputFields( const QgsFields &inputFields ) const { return inputFields; } + virtual QgsFields outputFields( const QgsFields &inputFields ) const; /** * Maps the input source coordinate reference system (\a inputCrs) to a corresponding @@ -830,14 +837,14 @@ class CORE_EXPORT QgsProcessingFeatureBasedAlgorithm : public QgsProcessingAlgor * This is called once by the base class when creating the output sink for the algorithm (i.e. it is * not called once per feature processed). */ - virtual QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const { return inputCrs; } + virtual QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const; /** * Initializes any extra parameters added by the algorithm subclass. There is no need * to declare the input source or output sink, as these are automatically created by * QgsProcessingFeatureBasedAlgorithm. */ - virtual void initParameters( const QVariantMap &configuration = QVariantMap() ) { Q_UNUSED( configuration ); } + virtual void initParameters( const QVariantMap &configuration = QVariantMap() ); /** * Returns the source's coordinate reference system. This will only return a valid CRS when