Skip to content
Permalink
Browse files

[FEATURE] Make processing dissolve algorithm accept multiple fields

This allows you to dissolve based on more than one field value
  • Loading branch information
nyalldawson committed Jul 29, 2016
1 parent f449bf2 commit bb54b4f41a726737d5d28a71632ed29a9a8045df
@@ -26,6 +26,7 @@
__revision__ = '$Format:%H$'

import os
from collections import defaultdict

from qgis.PyQt.QtGui import QIcon

@@ -36,7 +37,7 @@
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 @@ def defineCharacteristics(self):
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 @@ def processAlgorithm(self, progress):
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 @@ def processAlgorithm(self, progress):
'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 @@ def processAlgorithm(self, progress):
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
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ dissolve_two_fields.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>9.162955854126682</gml:X><gml:Y>6.088675623800385</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:dissolve_two_fields fid="polys.0">
<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>
<ogr:name>aa</ogr:name>
<ogr:intval>1</ogr:intval>
<ogr:floatval>44.123456</ogr:floatval>
</ogr:dissolve_two_fields>
</gml:featureMember>
<gml:featureMember>
<ogr:dissolve_two_fields fid="polys.1">
<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>
<ogr:name>dd</ogr:name>
<ogr:floatval>0</ogr:floatval>
</ogr:dissolve_two_fields>
</gml:featureMember>
<gml:featureMember>
<ogr:dissolve_two_fields fid="polys.2">
<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>
<ogr:name>bb</ogr:name>
<ogr:intval>1</ogr:intval>
<ogr:floatval>0.123</ogr:floatval>
</ogr:dissolve_two_fields>
</gml:featureMember>
<gml:featureMember>
<ogr:dissolve_two_fields fid="polys.3">
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
</ogr:dissolve_two_fields>
</gml:featureMember>
<gml:featureMember>
<ogr:dissolve_two_fields fid="polys.8">
<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>
<ogr:name>bb</ogr:name>
<ogr:intval>2</ogr:intval>
<ogr:floatval>0.123</ogr:floatval>
</ogr:dissolve_two_fields>
</gml:featureMember>
<gml:featureMember>
<ogr:dissolve_two_fields fid="polys.7">
<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>
<ogr:name>cc</ogr:name>
<ogr:floatval>0.123</ogr:floatval>
</ogr:dissolve_two_fields>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -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:

0 comments on commit bb54b4f

Please sign in to comment.
You can’t perform that action at this time.