diff --git a/python/plugins/processing/algs/qgis/Dissolve.py b/python/plugins/processing/algs/qgis/Dissolve.py index 740753007d3..1c912e961ea 100644 --- a/python/plugins/processing/algs/qgis/Dissolve.py +++ b/python/plugins/processing/algs/qgis/Dissolve.py @@ -26,6 +26,7 @@ __copyright__ = '(C) 2012, Victor Olaya' __revision__ = '$Format:%H$' import os +from collections import defaultdict from qgis.PyQt.QtGui import QIcon @@ -36,7 +37,7 @@ from processing.core.GeoAlgorithm import GeoAlgorithm from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException from processing.core.parameters import ParameterVector from processing.core.parameters import ParameterBoolean -from processing.core.parameters import ParameterTableField +from processing.core.parameters import ParameterTableMultipleField from processing.core.outputs import OutputVector from processing.tools import vector, dataobjects @@ -60,14 +61,14 @@ class Dissolve(GeoAlgorithm): self.tr('Input layer'), [ParameterVector.VECTOR_TYPE_POLYGON, ParameterVector.VECTOR_TYPE_LINE])) self.addParameter(ParameterBoolean(Dissolve.DISSOLVE_ALL, - self.tr('Dissolve all (do not use field)'), True)) - self.addParameter(ParameterTableField(Dissolve.FIELD, - self.tr('Unique ID field'), Dissolve.INPUT, optional=True)) + self.tr('Dissolve all (do not use fields)'), True)) + self.addParameter(ParameterTableMultipleField(Dissolve.FIELD, + self.tr('Unique ID fields'), Dissolve.INPUT, optional=True)) self.addOutput(OutputVector(Dissolve.OUTPUT, self.tr('Dissolved'))) def processAlgorithm(self, progress): useField = not self.getParameterValue(Dissolve.DISSOLVE_ALL) - fieldname = self.getParameterValue(Dissolve.FIELD) + field_names = self.getParameterValue(Dissolve.FIELD) vlayerA = dataobjects.getObjectFromUri( self.getParameterValue(Dissolve.INPUT)) vproviderA = vlayerA.dataProvider() @@ -127,20 +128,16 @@ class Dissolve(GeoAlgorithm): outFeat.setAttributes(attrs) writer.addFeature(outFeat) else: - fieldIdx = vlayerA.fieldNameIndex(fieldname) - unique = vector.getUniqueValues(vlayerA, int(fieldIdx)) - nFeat = len(unique) - myDict = {} - attrDict = {} - for item in unique: - myDict[unicode(item).strip()] = [] - attrDict[unicode(item).strip()] = None + field_indexes = [vlayerA.fieldNameIndex(f) for f in field_names.split(';')] - unique = None + attribute_dict = {} + geometry_dict = defaultdict(lambda: []) for inFeat in features: attrs = inFeat.attributes() - tempItem = attrs[fieldIdx] + + index_attrs = tuple([attrs[i] for i in field_indexes]) + tmpInGeom = QgsGeometry(inFeat.geometry()) if tmpInGeom.isGeosEmpty(): continue @@ -154,16 +151,17 @@ class Dissolve(GeoAlgorithm): 'geometry: ') + error.what()) - if attrDict[unicode(tempItem).strip()] is None: + if not index_attrs in attribute_dict: # keep attributes of first feature - attrDict[unicode(tempItem).strip()] = attrs + attribute_dict[index_attrs] = attrs - myDict[unicode(tempItem).strip()].append(tmpInGeom) + geometry_dict[index_attrs].append(tmpInGeom) - features = None + nFeat = len(attribute_dict) nElement = 0 - for key, value in myDict.items(): + for key, value in geometry_dict.items(): + outFeat = QgsFeature() nElement += 1 progress.setPercentage(int(nElement * 100 / nFeat)) try: @@ -172,7 +170,7 @@ class Dissolve(GeoAlgorithm): raise GeoAlgorithmExecutionException( self.tr('Geometry exception while dissolving')) outFeat.setGeometry(tmpOutGeom) - outFeat.setAttributes(attrDict[key]) + outFeat.setAttributes(attribute_dict[key]) writer.addFeature(outFeat) del writer diff --git a/python/plugins/processing/tests/testdata/expected/dissolve_two_fields.gml b/python/plugins/processing/tests/testdata/expected/dissolve_two_fields.gml new file mode 100644 index 00000000000..576b8e4309b --- /dev/null +++ b/python/plugins/processing/tests/testdata/expected/dissolve_two_fields.gml @@ -0,0 +1,58 @@ + + + + + -1-3 + 9.1629558541266826.088675623800385 + + + + + + 3,2 6,1 6,-3 2,-1 -1,-1 -1,3 3,3 3,2 + aa + 1 + 44.123456 + + + + + 6.241458733205375,-0.054510556621882 7.241458733205375,-1.054510556621882 5.241458733205375,-1.054510556621882 6.241458733205375,-0.054510556621882 + dd + 0 + + + + + 4.172552783109405,4.822648752399233 4.172552783109405,5.822648752399233 5.172552783109405,5.822648752399233 5.172552783109405,4.822648752399233 4.172552783109405,4.8226487523992332.443378119001919,4.423608445297505 2.443378119001919,5.0 2,5 2,6 3,6 3.0,5.423608445297505 3.443378119001919,5.423608445297505 3.443378119001919,4.423608445297505 2.443378119001919,4.423608445297505 + bb + 1 + 0.123 + + + + + 120 + -100291.43213 + + + + + 2.620729366602688,5.088675623800385 2.620729366602688,6.088675623800385 3.620729366602688,6.088675623800385 3.620729366602688,5.088675623800385 2.620729366602688,5.088675623800385 + bb + 2 + 0.123 + + + + + 8.162955854126682,2.738771593090211 8.162955854126682,3.738771593090211 9.162955854126682,3.738771593090211 9.162955854126682,2.738771593090211 8.162955854126682,2.738771593090211 + cc + 0.123 + + + diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 193292606c3..a7fc2fadcc4 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -304,6 +304,19 @@ tests: name: expected/dissolve_field.gml type: vector + - algorithm: qgis:dissolve + name: Dissolve using two fields + params: + DISSOLVE_ALL: false + FIELD: intval;name + INPUT: + name: dissolve_polys.gml + type: vector + results: + OUTPUT: + name: expected/dissolve_two_fields.gml + type: vector + - name: Dissolve with geometries reported as valid but as invalid with isGeosValid algorithm: qgis:dissolve params: