[FEATURE] Make processing dissolve algorithm accept multiple fields

This allows you to dissolve based on more than one field value
This commit is contained in:
Nyall Dawson 2016-07-29 18:46:23 +10:00
parent f449bf2361
commit bb54b4f41a
3 changed files with 90 additions and 21 deletions

View File

@ -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

View File

@ -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>

View File

@ -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: