[processing] optimise singlepart to multipart algorithm

- keep z/m/curved geometries intact
- rewrite loop to avoid the cost of nb. feature x unique values
This commit is contained in:
nirvn 2016-11-02 16:17:10 +07:00
parent a44ea22880
commit 03e29d4f01

View File

@ -65,7 +65,7 @@ class SinglePartsToMultiparts(GeoAlgorithm):
layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT)) layer = dataobjects.getObjectFromUri(self.getParameterValue(self.INPUT))
fieldName = self.getParameterValue(self.FIELD) fieldName = self.getParameterValue(self.FIELD)
geomType = self.singleToMultiGeom(layer.wkbType()) geomType = QgsWkbTypes.multiType(layer.wkbType())
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
layer.fields().toList(), geomType, layer.crs()) layer.fields().toList(), geomType, layer.crs())
@ -73,86 +73,35 @@ class SinglePartsToMultiparts(GeoAlgorithm):
inFeat = QgsFeature() inFeat = QgsFeature()
outFeat = QgsFeature() outFeat = QgsFeature()
inGeom = QgsGeometry() inGeom = QgsGeometry()
outGeom = QgsGeometry()
index = layer.fields().lookupField(fieldName) index = layer.fields().lookupField(fieldName)
unique = vector.getUniqueValues(layer, index)
current = 0 collection_geom = {}
collection_attrs = {}
features = vector.features(layer) features = vector.features(layer)
total = 100.0 / (len(features) * len(unique)) current = 0
if not len(unique) == layer.featureCount(): total = 100.0 / (len(features))
for i in unique:
multi_feature = []
first = True
features = vector.features(layer) features = vector.features(layer)
for inFeat in features: for inFeat in features:
atMap = inFeat.attributes() atMap = inFeat.attributes()
idVar = atMap[index] idVar = atMap[index]
if str(idVar).strip() == str(i).strip(): key = str(idVar).strip()
if first: if not key in collection_geom:
attrs = atMap collection_geom[key] = []
first = False collection_attrs[key] = atMap
inGeom = inFeat.geometry() inGeom = inFeat.geometry()
vType = inGeom.type() vType = inGeom.type()
feature_list = self.extractAsMulti(inGeom) collection_geom[key].append(inGeom)
multi_feature.extend(feature_list)
current += 1 current += 1
progress.setPercentage(int(current * total)) progress.setPercentage(int(current * total))
outFeat.setAttributes(attrs) for key, geoms in collection_geom.items():
outGeom = QgsGeometry(self.convertGeometry(multi_feature, outFeat.setAttributes(collection_attrs[key])
vType)) outFeat.setGeometry(QgsGeometry.collectGeometry(geoms))
outFeat.setGeometry(outGeom)
writer.addFeature(outFeat) writer.addFeature(outFeat)
del writer del writer
else:
raise GeoAlgorithmExecutionException(
self.tr('At least two features must have same attribute '
'value! Please choose another field...'))
def singleToMultiGeom(self, wkbType):
try:
if wkbType in (QgsWkbTypes.Point, QgsWkbTypes.MultiPoint,
QgsWkbTypes.Point25D, QgsWkbTypes.MultiPoint25D):
return QgsWkbTypes.MultiPoint
elif wkbType in (QgsWkbTypes.LineString, QgsWkbTypes.MultiLineString,
QgsWkbTypes.MultiLineString25D,
QgsWkbTypes.LineString25D):
return QgsWkbTypes.MultiLineString
elif wkbType in (QgsWkbTypes.Polygon, QgsWkbTypes.MultiPolygon,
QgsWkbTypes.MultiPolygon25D, QgsWkbTypes.Polygon25D):
return QgsWkbTypes.MultiPolygon
else:
return QgsWkbTypes.Unknown
except Exception:
pass
def extractAsMulti(self, geom):
if geom.type() == QgsWkbTypes.PointGeometry:
if geom.isMultipart():
return geom.asMultiPoint()
else:
return [geom.asPoint()]
elif geom.type() == QgsWkbTypes.LineGeometry:
if geom.isMultipart():
return geom.asMultiPolyline()
else:
return [geom.asPolyline()]
else:
if geom.isMultipart():
return geom.asMultiPolygon()
else:
return [geom.asPolygon()]
def convertGeometry(self, geom_list, vType):
if vType == QgsWkbTypes.PointGeometry:
return QgsGeometry().fromMultiPoint(geom_list)
elif vType == QgsWkbTypes.LineGeometry:
return QgsGeometry().fromMultiPolyline(geom_list)
else:
return QgsGeometry().fromMultiPolygon(geom_list)