Skip to content

Commit bb54b4f

Browse files
committedAug 2, 2016
[FEATURE] Make processing dissolve algorithm accept multiple fields
This allows you to dissolve based on more than one field value
1 parent f449bf2 commit bb54b4f

File tree

3 files changed

+90
-21
lines changed

3 files changed

+90
-21
lines changed
 

‎python/plugins/processing/algs/qgis/Dissolve.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
__revision__ = '$Format:%H$'
2727

2828
import os
29+
from collections import defaultdict
2930

3031
from qgis.PyQt.QtGui import QIcon
3132

@@ -36,7 +37,7 @@
3637
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
3738
from processing.core.parameters import ParameterVector
3839
from processing.core.parameters import ParameterBoolean
39-
from processing.core.parameters import ParameterTableField
40+
from processing.core.parameters import ParameterTableMultipleField
4041
from processing.core.outputs import OutputVector
4142
from processing.tools import vector, dataobjects
4243

@@ -60,14 +61,14 @@ def defineCharacteristics(self):
6061
self.tr('Input layer'),
6162
[ParameterVector.VECTOR_TYPE_POLYGON, ParameterVector.VECTOR_TYPE_LINE]))
6263
self.addParameter(ParameterBoolean(Dissolve.DISSOLVE_ALL,
63-
self.tr('Dissolve all (do not use field)'), True))
64-
self.addParameter(ParameterTableField(Dissolve.FIELD,
65-
self.tr('Unique ID field'), Dissolve.INPUT, optional=True))
64+
self.tr('Dissolve all (do not use fields)'), True))
65+
self.addParameter(ParameterTableMultipleField(Dissolve.FIELD,
66+
self.tr('Unique ID fields'), Dissolve.INPUT, optional=True))
6667
self.addOutput(OutputVector(Dissolve.OUTPUT, self.tr('Dissolved')))
6768

6869
def processAlgorithm(self, progress):
6970
useField = not self.getParameterValue(Dissolve.DISSOLVE_ALL)
70-
fieldname = self.getParameterValue(Dissolve.FIELD)
71+
field_names = self.getParameterValue(Dissolve.FIELD)
7172
vlayerA = dataobjects.getObjectFromUri(
7273
self.getParameterValue(Dissolve.INPUT))
7374
vproviderA = vlayerA.dataProvider()
@@ -127,20 +128,16 @@ def processAlgorithm(self, progress):
127128
outFeat.setAttributes(attrs)
128129
writer.addFeature(outFeat)
129130
else:
130-
fieldIdx = vlayerA.fieldNameIndex(fieldname)
131-
unique = vector.getUniqueValues(vlayerA, int(fieldIdx))
132-
nFeat = len(unique)
133-
myDict = {}
134-
attrDict = {}
135-
for item in unique:
136-
myDict[unicode(item).strip()] = []
137-
attrDict[unicode(item).strip()] = None
131+
field_indexes = [vlayerA.fieldNameIndex(f) for f in field_names.split(';')]
138132

139-
unique = None
133+
attribute_dict = {}
134+
geometry_dict = defaultdict(lambda: [])
140135

141136
for inFeat in features:
142137
attrs = inFeat.attributes()
143-
tempItem = attrs[fieldIdx]
138+
139+
index_attrs = tuple([attrs[i] for i in field_indexes])
140+
144141
tmpInGeom = QgsGeometry(inFeat.geometry())
145142
if tmpInGeom.isGeosEmpty():
146143
continue
@@ -154,16 +151,17 @@ def processAlgorithm(self, progress):
154151
'geometry: ')
155152
+ error.what())
156153

157-
if attrDict[unicode(tempItem).strip()] is None:
154+
if not index_attrs in attribute_dict:
158155
# keep attributes of first feature
159-
attrDict[unicode(tempItem).strip()] = attrs
156+
attribute_dict[index_attrs] = attrs
160157

161-
myDict[unicode(tempItem).strip()].append(tmpInGeom)
158+
geometry_dict[index_attrs].append(tmpInGeom)
162159

163-
features = None
160+
nFeat = len(attribute_dict)
164161

165162
nElement = 0
166-
for key, value in myDict.items():
163+
for key, value in geometry_dict.items():
164+
outFeat = QgsFeature()
167165
nElement += 1
168166
progress.setPercentage(int(nElement * 100 / nFeat))
169167
try:
@@ -172,7 +170,7 @@ def processAlgorithm(self, progress):
172170
raise GeoAlgorithmExecutionException(
173171
self.tr('Geometry exception while dissolving'))
174172
outFeat.setGeometry(tmpOutGeom)
175-
outFeat.setAttributes(attrDict[key])
173+
outFeat.setAttributes(attribute_dict[key])
176174
writer.addFeature(outFeat)
177175

178176
del writer
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://ogr.maptools.org/ dissolve_two_fields.xsd"
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
10+
<gml:coord><gml:X>9.162955854126682</gml:X><gml:Y>6.088675623800385</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:dissolve_two_fields fid="polys.0">
16+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 -1,-1 -1,3 3,3 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
17+
<ogr:name>aa</ogr:name>
18+
<ogr:intval>1</ogr:intval>
19+
<ogr:floatval>44.123456</ogr:floatval>
20+
</ogr:dissolve_two_fields>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:dissolve_two_fields fid="polys.1">
24+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6.241458733205375,-0.054510556621882 7.241458733205375,-1.054510556621882 5.241458733205375,-1.054510556621882 6.241458733205375,-0.054510556621882</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
25+
<ogr:name>dd</ogr:name>
26+
<ogr:floatval>0</ogr:floatval>
27+
</ogr:dissolve_two_fields>
28+
</gml:featureMember>
29+
<gml:featureMember>
30+
<ogr:dissolve_two_fields fid="polys.2">
31+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>4.172552783109405,4.822648752399233 4.172552783109405,5.822648752399233 5.172552783109405,5.822648752399233 5.172552783109405,4.822648752399233 4.172552783109405,4.822648752399233</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2.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</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
32+
<ogr:name>bb</ogr:name>
33+
<ogr:intval>1</ogr:intval>
34+
<ogr:floatval>0.123</ogr:floatval>
35+
</ogr:dissolve_two_fields>
36+
</gml:featureMember>
37+
<gml:featureMember>
38+
<ogr:dissolve_two_fields fid="polys.3">
39+
<ogr:intval>120</ogr:intval>
40+
<ogr:floatval>-100291.43213</ogr:floatval>
41+
</ogr:dissolve_two_fields>
42+
</gml:featureMember>
43+
<gml:featureMember>
44+
<ogr:dissolve_two_fields fid="polys.8">
45+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2.620729366602688,5.088675623800385 2.620729366602688,6.088675623800385 3.620729366602688,6.088675623800385 3.620729366602688,5.088675623800385 2.620729366602688,5.088675623800385</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
46+
<ogr:name>bb</ogr:name>
47+
<ogr:intval>2</ogr:intval>
48+
<ogr:floatval>0.123</ogr:floatval>
49+
</ogr:dissolve_two_fields>
50+
</gml:featureMember>
51+
<gml:featureMember>
52+
<ogr:dissolve_two_fields fid="polys.7">
53+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>8.162955854126682,2.738771593090211 8.162955854126682,3.738771593090211 9.162955854126682,3.738771593090211 9.162955854126682,2.738771593090211 8.162955854126682,2.738771593090211</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
54+
<ogr:name>cc</ogr:name>
55+
<ogr:floatval>0.123</ogr:floatval>
56+
</ogr:dissolve_two_fields>
57+
</gml:featureMember>
58+
</ogr:FeatureCollection>

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,19 @@ tests:
304304
name: expected/dissolve_field.gml
305305
type: vector
306306

307+
- algorithm: qgis:dissolve
308+
name: Dissolve using two fields
309+
params:
310+
DISSOLVE_ALL: false
311+
FIELD: intval;name
312+
INPUT:
313+
name: dissolve_polys.gml
314+
type: vector
315+
results:
316+
OUTPUT:
317+
name: expected/dissolve_two_fields.gml
318+
type: vector
319+
307320
- name: Dissolve with geometries reported as valid but as invalid with isGeosValid
308321
algorithm: qgis:dissolve
309322
params:

0 commit comments

Comments
 (0)