diff --git a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py index e029ff62f33..7ab3688e630 100644 --- a/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py @@ -111,6 +111,7 @@ from .ShortestPathLayerToPoint import ShortestPathLayerToPoint from .ShortestPathPointToLayer import ShortestPathPointToLayer from .ShortestPathPointToPoint import ShortestPathPointToPoint from .SimplifyGeometries import SimplifyGeometries +from .SinglePartsToMultiparts import SinglePartsToMultiparts from .SingleSidedBuffer import SingleSidedBuffer from .Slope import Slope from .Smooth import Smooth @@ -130,7 +131,6 @@ from .VoronoiPolygons import VoronoiPolygons from .ZonalStatistics import ZonalStatistics # from .ExtractByLocation import ExtractByLocation -# from .SinglePartsToMultiparts import SinglePartsToMultiparts # from .ConvexHull import ConvexHull # from .FixedDistanceBuffer import FixedDistanceBuffer # from .VariableDistanceBuffer import VariableDistanceBuffer @@ -185,7 +185,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider): def getAlgs(self): # algs = [ - # SinglePartsToMultiparts(), # ConvexHull(), FixedDistanceBuffer(), # VariableDistanceBuffer(), # RandomSelection(), RandomSelectionWithinSubsets(), @@ -285,6 +284,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider): ShortestPathPointToLayer(), ShortestPathPointToPoint(), SimplifyGeometries(), + SinglePartsToMultiparts(), SingleSidedBuffer(), Slope(), Smooth(), diff --git a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py index 544b5e8a747..1d4f86a740b 100644 --- a/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py +++ b/python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py @@ -30,12 +30,17 @@ import os from qgis.PyQt.QtGui import QIcon -from qgis.core import QgsFeature, QgsFeatureSink, QgsGeometry, QgsWkbTypes, QgsProcessingUtils, NULL +from qgis.core import (QgsFeature, + QgsFeatureSink, + QgsGeometry, + QgsWkbTypes, + QgsProcessingUtils, + NULL, + QgsProcessingParameterFeatureSource, + QgsProcessingParameterField, + QgsProcessingParameterFeatureSink) from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm -from processing.core.parameters import ParameterVector -from processing.core.parameters import ParameterTableField -from processing.core.outputs import OutputVector pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] @@ -56,11 +61,12 @@ class SinglePartsToMultiparts(QgisAlgorithm): super().__init__() def initAlgorithm(self, config=None): - self.addParameter(ParameterVector(self.INPUT, self.tr('Input layer'))) - self.addParameter(ParameterTableField(self.FIELD, - self.tr('Unique ID field'), self.INPUT)) + self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, + self.tr('Input layer'))) + self.addParameter(QgsProcessingParameterField(self.FIELD, + self.tr('Unique ID field'), parentLayerParameterName=self.INPUT)) - self.addOutput(OutputVector(self.OUTPUT, self.tr('Multipart'))) + self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Multipart'))) def name(self): return 'singlepartstomultipart' @@ -69,31 +75,29 @@ class SinglePartsToMultiparts(QgisAlgorithm): return self.tr('Singleparts to multipart') def processAlgorithm(self, parameters, context, feedback): - layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context) - fieldName = self.getParameterValue(self.FIELD) + source = self.parameterAsSource(parameters, self.INPUT, context) + field_name = self.parameterAsString(parameters, self.FIELD, context) - geomType = QgsWkbTypes.multiType(layer.wkbType()) + geom_type = QgsWkbTypes.multiType(source.wkbType()) - writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(layer.fields(), geomType, layer.crs(), - context) + (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, + source.fields(), geom_type, source.sourceCrs()) - outFeat = QgsFeature() - inGeom = QgsGeometry() - - index = layer.fields().lookupField(fieldName) + index = source.fields().lookupField(field_name) collection_geom = {} collection_attrs = {} - features = QgsProcessingUtils.getFeatures(layer, context) - total = 100.0 / layer.featureCount() if layer.featureCount() else 0 + features = source.getFeatures() + total = 100.0 / source.featureCount() if source.featureCount() else 0 for current, feature in enumerate(features): + if feedback.isCanceled(): + break + atMap = feature.attributes() idVar = atMap[index] - if idVar in [None, NULL]: - outFeat.setAttributes(atMap) - outFeat.setGeometry(feature.geometry()) - writer.addFeature(outFeat, QgsFeatureSink.FastInsert) + if idVar in [None, NULL] or not feature.hasGeometry(): + sink.addFeature(feature, QgsFeatureSink.FastInsert) feedback.setProgress(int(current * total)) continue @@ -108,8 +112,12 @@ class SinglePartsToMultiparts(QgisAlgorithm): feedback.setProgress(int(current * total)) for key, geoms in collection_geom.items(): - outFeat.setAttributes(collection_attrs[key]) - outFeat.setGeometry(QgsGeometry.collectGeometry(geoms)) - writer.addFeature(outFeat, QgsFeatureSink.FastInsert) + if feedback.isCanceled(): + break - del writer + feature = QgsFeature() + feature.setAttributes(collection_attrs[key]) + feature.setGeometry(QgsGeometry.collectGeometry(geoms)) + sink.addFeature(feature, QgsFeatureSink.FastInsert) + + return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/tests/testdata/expected/single_to_multi.gfs b/python/plugins/processing/tests/testdata/expected/single_to_multi.gfs index 70b2931c296..099f6342305 100644 --- a/python/plugins/processing/tests/testdata/expected/single_to_multi.gfs +++ b/python/plugins/processing/tests/testdata/expected/single_to_multi.gfs @@ -6,7 +6,7 @@ 6 EPSG:4326 - 4 + 5 0.21020 8.96288 -5.48232 diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 713280e7d26..a8109607c2e 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -2363,20 +2363,18 @@ tests: name: expected/mean_coordinates.gml type: vector -# # Temporarily disable until we figure out why it failed after merging -# # into master -# #- algorithm: qgis:singlepartstomultipart -# # name: single part to multipart -# # params: -# # FIELD: id -# # INPUT: -# # name: custom/single_part_poly.gml -# # type: vector -# # results: -# # OUTPUT: -# # name: expected/single_to_multi.gml -# # type: vector -# + - algorithm: qgis:singlepartstomultipart + name: single part to multipart + params: + FIELD: id + INPUT: + name: custom/single_part_poly.gml + type: vector + results: + OUTPUT: + name: expected/single_to_multi.gml + type: vector + # - algorithm: qgis:zonalstatistics # name: simple zonal statistics # params: