[processing] fixes for vector geoprocessing algorithms

This commit is contained in:
Alexander Bruy 2016-01-29 11:03:38 +02:00
parent 4c2c905c32
commit d4e400a425
5 changed files with 224 additions and 169 deletions

View File

@ -26,12 +26,18 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from qgis.core import QGis, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsWKBTypes from qgis.core import QGis, QgsFeature, QgsGeometry, QgsFeatureRequest, QgsWKBTypes
from processing.core.GeoAlgorithm import GeoAlgorithm from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.ProcessingLog import ProcessingLog from processing.core.ProcessingLog import ProcessingLog
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector from processing.tools import dataobjects, vector
GEOM_25D = [QGis.WKBPoint25D, QGis.WKBLineString25D, QGis.WKBPolygon25D,
QGis.WKBMultiPoint25D, QGis.WKBMultiLineString25D,
QGis.WKBMultiPolygon25D]
class Clip(GeoAlgorithm): class Clip(GeoAlgorithm):
@ -54,6 +60,11 @@ class Clip(GeoAlgorithm):
layerB = dataobjects.getObjectFromUri( layerB = dataobjects.getObjectFromUri(
self.getParameterValue(Clip.OVERLAY)) self.getParameterValue(Clip.OVERLAY))
geomType = layerA.dataProvider().geometryType()
if geomType in GEOM_25D:
raise GeoAlgorithmExecutionException(
self.tr('Input layer has unsupported geometry type {}').format(geomType))
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
layerA.pendingFields(), layerA.pendingFields(),
layerA.dataProvider().geometryType(), layerA.dataProvider().geometryType(),
@ -88,39 +99,37 @@ class Clip(GeoAlgorithm):
outFeat.setGeometry(QgsGeometry(tmpGeom)) outFeat.setGeometry(QgsGeometry(tmpGeom))
first = False first = False
else: else:
try: cur_geom = QgsGeometry(outFeat.geometry())
cur_geom = QgsGeometry(outFeat.geometry()) new_geom = QgsGeometry(cur_geom.combine(tmpGeom))
new_geom = QgsGeometry( if new_geom.isGeosEmpty() or not new_geom.isGeosValid():
cur_geom.combine(tmpGeom))
outFeat.setGeometry(QgsGeometry(new_geom))
except:
ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
self.tr('GEOS geoprocessing error: One or ' self.tr('GEOS geoprocessing error: One or '
'more input features have invalid ' 'more input features have invalid '
'geometry.')) 'geometry.'))
break break
outFeat.setGeometry(QgsGeometry(new_geom))
if found: if found:
try: cur_geom = QgsGeometry(outFeat.geometry())
cur_geom = QgsGeometry(outFeat.geometry()) new_geom = QgsGeometry(geom.intersection(cur_geom))
new_geom = QgsGeometry(geom.intersection(cur_geom)) if new_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(new_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
if new_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(new_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection: int_com = QgsGeometry(geom.combine(cur_geom))
int_com = QgsGeometry(geom.combine(cur_geom)) int_sym = QgsGeometry(geom.symDifference(cur_geom))
int_sym = QgsGeometry(geom.symDifference(cur_geom)) new_geom = QgsGeometry(int_com.difference(int_sym))
new_geom = QgsGeometry(int_com.difference(int_sym)) if new_geom.isGeosEmpty() or not new_geom.isGeosValid():
try:
outFeat.setGeometry(new_geom)
outFeat.setAttributes(attrs)
writer.addFeature(outFeat)
except:
ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
self.tr('Feature geometry error: One or more ' self.tr('GEOS geoprocessing error: One or more '
'output features ignored due to ' 'input features have invalid geometry.'))
'invalid geometry.'))
continue continue
try:
outFeat.setGeometry(new_geom)
outFeat.setAttributes(attrs)
writer.addFeature(outFeat)
except: except:
ProcessingLog.addToLog(ProcessingLog.LOG_ERROR, ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
self.tr('GEOS geoprocessing error: One or more ' self.tr('Feature geometry error: One or more '
'input features have invalid geometry.')) 'output features ignored due to '
'invalid geometry.'))
continue continue
current += 1 current += 1

View File

@ -25,13 +25,18 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from qgis.core import QgsFeatureRequest, QgsFeature, QgsGeometry from qgis.core import QGis, QgsFeatureRequest, QgsFeature, QgsGeometry
from processing.core.ProcessingLog import ProcessingLog from processing.core.ProcessingLog import ProcessingLog
from processing.core.GeoAlgorithm import GeoAlgorithm from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector from processing.tools import dataobjects, vector
GEOM_25D = [QGis.WKBPoint25D, QGis.WKBLineString25D, QGis.WKBPolygon25D,
QGis.WKBMultiPoint25D, QGis.WKBMultiLineString25D,
QGis.WKBMultiPolygon25D]
class Difference(GeoAlgorithm): class Difference(GeoAlgorithm):
@ -59,13 +64,14 @@ class Difference(GeoAlgorithm):
layerB = dataobjects.getObjectFromUri( layerB = dataobjects.getObjectFromUri(
self.getParameterValue(Difference.OVERLAY)) self.getParameterValue(Difference.OVERLAY))
GEOS_EXCEPT = True geomType = layerA.dataProvider().geometryType()
if geomType in GEOM_25D:
FEATURE_EXCEPT = True raise GeoAlgorithmExecutionException(
self.tr('Input layer has unsupported geometry type {}').format(geomType))
writer = self.getOutputFromName( writer = self.getOutputFromName(
Difference.OUTPUT).getVectorWriter(layerA.pendingFields(), Difference.OUTPUT).getVectorWriter(layerA.pendingFields(),
layerA.dataProvider().geometryType(), geomType,
layerA.dataProvider().crs()) layerA.dataProvider().crs())
inFeatA = QgsFeature() inFeatA = QgsFeature()
@ -89,17 +95,15 @@ class Difference(GeoAlgorithm):
request = QgsFeatureRequest().setFilterFid(i) request = QgsFeatureRequest().setFilterFid(i)
inFeatB = layerB.getFeatures(request).next() inFeatB = layerB.getFeatures(request).next()
tmpGeom = QgsGeometry(inFeatB.geometry()) tmpGeom = QgsGeometry(inFeatB.geometry())
try: if diff_geom.intersects(tmpGeom):
if diff_geom.intersects(tmpGeom): diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
diff_geom = QgsGeometry(diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
if diff_geom.isGeosEmpty(): ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
GEOS_EXCEPT = False self.tr('GEOS geoprocessing error: One or '
'more input features have invalid '
'geometry.'))
add = False add = False
break break
except:
GEOS_EXCEPT = False
add = False
break
if add: if add:
try: try:
@ -107,17 +111,11 @@ class Difference(GeoAlgorithm):
outFeat.setAttributes(attrs) outFeat.setAttributes(attrs)
writer.addFeature(outFeat) writer.addFeature(outFeat)
except: except:
FEATURE_EXCEPT = False ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
continue continue
current += 1 current += 1
progress.setPercentage(int(current * total)) progress.setPercentage(int(current * total))
del writer del writer
if not GEOS_EXCEPT:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Geometry exception while computing difference'))
if not FEATURE_EXCEPT:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Feature exception while computing difference'))

View File

@ -26,8 +26,10 @@ __copyright__ = '(C) 2012, Victor Olaya'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from qgis.core import QGis, QgsFeatureRequest, QgsFeature, QgsGeometry, QgsWKBTypes from qgis.core import QGis, QgsFeatureRequest, QgsFeature, QgsGeometry, QgsWKBTypes
from processing.core.GeoAlgorithm import GeoAlgorithm from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.ProcessingLog import ProcessingLog from processing.core.ProcessingLog import ProcessingLog
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector from processing.tools import dataobjects, vector
@ -41,6 +43,10 @@ for key, value in wkbTypeGroups.items():
for const in value: for const in value:
wkbTypeGroups[const] = key wkbTypeGroups[const] = key
GEOM_25D = [QGis.WKBPoint25D, QGis.WKBLineString25D, QGis.WKBPolygon25D,
QGis.WKBMultiPoint25D, QGis.WKBMultiLineString25D,
QGis.WKBMultiPolygon25D]
class Intersection(GeoAlgorithm): class Intersection(GeoAlgorithm):
@ -48,6 +54,15 @@ class Intersection(GeoAlgorithm):
INPUT2 = 'INPUT2' INPUT2 = 'INPUT2'
OUTPUT = 'OUTPUT' OUTPUT = 'OUTPUT'
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Intersection')
self.group, self.i18n_group = self.trAlgorithm('Vector overlay tools')
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addParameter(ParameterVector(self.INPUT2,
self.tr('Intersect layer'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Intersection')))
def processAlgorithm(self, progress): def processAlgorithm(self, progress):
vlayerA = dataobjects.getObjectFromUri( vlayerA = dataobjects.getObjectFromUri(
self.getParameterValue(self.INPUT)) self.getParameterValue(self.INPUT))
@ -55,9 +70,14 @@ class Intersection(GeoAlgorithm):
self.getParameterValue(self.INPUT2)) self.getParameterValue(self.INPUT2))
vproviderA = vlayerA.dataProvider() vproviderA = vlayerA.dataProvider()
geomType = vproviderA.geometryType()
if geomType in GEOM_25D:
raise GeoAlgorithmExecutionException(
self.tr('Input layer has unsupported geometry type {}').format(geomType))
fields = vector.combineVectorFields(vlayerA, vlayerB) fields = vector.combineVectorFields(vlayerA, vlayerB)
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields,
vproviderA.geometryType(), vproviderA.crs()) geomType, vproviderA.crs())
inFeatA = QgsFeature() inFeatA = QgsFeature()
inFeatB = QgsFeature() inFeatB = QgsFeature()
outFeat = QgsFeature() outFeat = QgsFeature()
@ -75,36 +95,30 @@ class Intersection(GeoAlgorithm):
request = QgsFeatureRequest().setFilterFid(i) request = QgsFeatureRequest().setFilterFid(i)
inFeatB = vlayerB.getFeatures(request).next() inFeatB = vlayerB.getFeatures(request).next()
tmpGeom = QgsGeometry(inFeatB.geometry()) tmpGeom = QgsGeometry(inFeatB.geometry())
try: if geom.intersects(tmpGeom):
if geom.intersects(tmpGeom): atMapB = inFeatB.attributes()
atMapB = inFeatB.attributes() int_geom = QgsGeometry(geom.intersection(tmpGeom))
int_geom = QgsGeometry(geom.intersection(tmpGeom)) if int_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
if int_geom.wkbType() == QGis.WKBUnknown or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection: int_com = geom.combine(tmpGeom)
int_com = geom.combine(tmpGeom) int_sym = geom.symDifference(tmpGeom)
int_sym = geom.symDifference(tmpGeom) int_geom = QgsGeometry(int_com.difference(int_sym))
int_geom = QgsGeometry(int_com.difference(int_sym)) if int_geom.isGeosEmpty() or not int_geom.isGeosValid():
try: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]: self.tr('GEOS geoprocessing error: One or '
outFeat.setGeometry(int_geom) 'more input features have invalid '
attrs = [] 'geometry.'))
attrs.extend(atMapA) break
attrs.extend(atMapB) try:
outFeat.setAttributes(attrs) if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
writer.addFeature(outFeat) outFeat.setGeometry(int_geom)
except: attrs = []
ProcessingLog.addToLog(ProcessingLog.LOG_INFO, attrs.extend(atMapA)
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.')) attrs.extend(atMapB)
continue outFeat.setAttributes(attrs)
except: writer.addFeature(outFeat)
break except:
ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
continue
del writer del writer
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Intersection')
self.group, self.i18n_group = self.trAlgorithm('Vector overlay tools')
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addParameter(ParameterVector(self.INPUT2,
self.tr('Intersect layer'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Intersection')))

View File

@ -25,13 +25,18 @@ __copyright__ = '(C) 2014, Alexander Bruy'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from qgis.core import QgsFeature, QgsGeometry, QgsFeatureRequest, NULL from qgis.core import QGis, QgsFeature, QgsGeometry, QgsFeatureRequest, NULL
from processing.core.ProcessingLog import ProcessingLog from processing.core.ProcessingLog import ProcessingLog
from processing.core.GeoAlgorithm import GeoAlgorithm from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.core.parameters import ParameterVector from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector from processing.tools import dataobjects, vector
GEOM_25D = [QGis.WKBPoint25D, QGis.WKBLineString25D, QGis.WKBPolygon25D,
QGis.WKBMultiPoint25D, QGis.WKBMultiLineString25D,
QGis.WKBMultiPolygon25D]
class SymmetricalDifference(GeoAlgorithm): class SymmetricalDifference(GeoAlgorithm):
@ -58,12 +63,14 @@ class SymmetricalDifference(GeoAlgorithm):
providerA = layerA.dataProvider() providerA = layerA.dataProvider()
providerB = layerB.dataProvider() providerB = layerB.dataProvider()
GEOS_EXCEPT = True geomType = providerA.geometryType()
FEATURE_EXCEPT = True if geomType in GEOM_25D:
raise GeoAlgorithmExecutionException(
self.tr('Input layer has unsupported geometry type {}').format(geomType))
fields = vector.combineVectorFields(layerA, layerB) fields = vector.combineVectorFields(layerA, layerB)
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter( writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(
fields, providerA.geometryType(), providerA.crs()) fields, geomType, providerA.crs())
featB = QgsFeature() featB = QgsFeature()
outFeat = QgsFeature() outFeat = QgsFeature()
@ -86,20 +93,24 @@ class SymmetricalDifference(GeoAlgorithm):
for i in intersects: for i in intersects:
providerB.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB) providerB.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
tmpGeom = QgsGeometry(featB.geometry()) tmpGeom = QgsGeometry(featB.geometry())
try: if diffGeom.intersects(tmpGeom):
if diffGeom.intersects(tmpGeom): diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))
diffGeom = QgsGeometry(diffGeom.difference(tmpGeom)) if not diffGeom.isGeosValid():
except: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
add = False self.tr('GEOS geoprocessing error: One or '
GEOS_EXCEPT = False 'more input features have invalid '
break 'geometry.'))
add = False
break
if add: if add:
try: try:
outFeat.setGeometry(diffGeom) outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs) outFeat.setAttributes(attrs)
writer.addFeature(outFeat) writer.addFeature(outFeat)
except: except:
FEATURE_EXCEPT = False ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
continue continue
count += 1 count += 1
@ -117,30 +128,27 @@ class SymmetricalDifference(GeoAlgorithm):
for i in intersects: for i in intersects:
providerA.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB) providerA.getFeatures(QgsFeatureRequest().setFilterFid(i)).nextFeature(featB)
tmpGeom = QgsGeometry(featB.geometry()) tmpGeom = QgsGeometry(featB.geometry())
try: if diffGeom.intersects(tmpGeom):
if diffGeom.intersects(tmpGeom): diffGeom = QgsGeometry(diffGeom.difference(tmpGeom))
diffGeom = QgsGeometry(diffGeom.difference(tmpGeom)) if not diffGeom.isGeosValid():
except: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
add = False self.tr('GEOS geoprocessing error: One or '
GEOS_EXCEPT = False 'more input features have invalid '
break 'geometry.'))
add = False
break
if add: if add:
try: try:
outFeat.setGeometry(diffGeom) outFeat.setGeometry(diffGeom)
outFeat.setAttributes(attrs) outFeat.setAttributes(attrs)
writer.addFeature(outFeat) writer.addFeature(outFeat)
except: except:
FEATURE_EXCEPT = False ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
continue continue
count += 1 count += 1
progress.setPercentage(int(count * total)) progress.setPercentage(int(count * total))
del writer del writer
if not GEOS_EXCEPT:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Geometry exception while computing symmetrical difference'))
if not FEATURE_EXCEPT:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Feature exception while computing symmetrical difference'))

View File

@ -33,6 +33,19 @@ from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector from processing.core.outputs import OutputVector
from processing.tools import dataobjects, vector from processing.tools import dataobjects, vector
wkbTypeGroups = {
'Point': (QGis.WKBPoint, QGis.WKBMultiPoint, QGis.WKBPoint25D, QGis.WKBMultiPoint25D,),
'LineString': (QGis.WKBLineString, QGis.WKBMultiLineString, QGis.WKBLineString25D, QGis.WKBMultiLineString25D,),
'Polygon': (QGis.WKBPolygon, QGis.WKBMultiPolygon, QGis.WKBPolygon25D, QGis.WKBMultiPolygon25D,),
}
for key, value in wkbTypeGroups.items():
for const in value:
wkbTypeGroups[const] = key
GEOM_25D = [QGis.WKBPoint25D, QGis.WKBLineString25D, QGis.WKBPolygon25D,
QGis.WKBMultiPoint25D, QGis.WKBMultiLineString25D,
QGis.WKBMultiPolygon25D]
class Union(GeoAlgorithm): class Union(GeoAlgorithm):
@ -40,18 +53,29 @@ class Union(GeoAlgorithm):
INPUT2 = 'INPUT2' INPUT2 = 'INPUT2'
OUTPUT = 'OUTPUT' OUTPUT = 'OUTPUT'
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Union')
self.group, self.i18n_group = self.trAlgorithm('Vector overlay tools')
self.addParameter(ParameterVector(Union.INPUT,
self.tr('Input layer'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addParameter(ParameterVector(Union.INPUT2,
self.tr('Input layer 2'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addOutput(OutputVector(Union.OUTPUT, self.tr('Union')))
def processAlgorithm(self, progress): def processAlgorithm(self, progress):
vlayerA = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT)) vlayerA = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT))
vlayerB = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT2)) vlayerB = dataobjects.getObjectFromUri(self.getParameterValue(Union.INPUT2))
GEOS_EXCEPT = True
FEATURE_EXCEPT = True
vproviderA = vlayerA.dataProvider() vproviderA = vlayerA.dataProvider()
geomType = vproviderA.geometryType()
if geomType in GEOM_25D:
raise GeoAlgorithmExecutionException(
self.tr('Input layer has unsupported geometry type {}').format(geomType))
fields = vector.combineVectorFields(vlayerA, vlayerB) fields = vector.combineVectorFields(vlayerA, vlayerB)
names = [field.name() for field in fields]
ProcessingLog.addToLog(ProcessingLog.LOG_INFO, unicode(names))
writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields, writer = self.getOutputFromName(Union.OUTPUT).getVectorWriter(fields,
vproviderA.geometryType(), vproviderA.crs()) geomType, vproviderA.crs())
inFeatA = QgsFeature() inFeatA = QgsFeature()
inFeatB = QgsFeature() inFeatB = QgsFeature()
outFeat = QgsFeature() outFeat = QgsFeature()
@ -77,8 +101,8 @@ class Union(GeoAlgorithm):
except: except:
# This really shouldn't happen, as we haven't # This really shouldn't happen, as we haven't
# edited the input geom at all # edited the input geom at all
raise GeoAlgorithmExecutionException( ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Feature exception while computing union')) self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
else: else:
for id in intersects: for id in intersects:
count += 1 count += 1
@ -93,9 +117,9 @@ class Union(GeoAlgorithm):
if int_geom is None: if int_geom is None:
# There was a problem creating the intersection # There was a problem creating the intersection
raise GeoAlgorithmExecutionException( ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Geometry exception while computing ' self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
'intersection')) int_geom = QgsGeometry()
else: else:
int_geom = QgsGeometry(int_geom) int_geom = QgsGeometry(int_geom)
@ -105,38 +129,52 @@ class Union(GeoAlgorithm):
for i in temp_list: for i in temp_list:
if i.type() == geom.type(): if i.type() == geom.type():
int_geom = QgsGeometry(i) int_geom = QgsGeometry(i)
try: try:
outFeat.setGeometry(int_geom) outFeat.setGeometry(int_geom)
attrs = [] outFeat.setAttributes(atMapA + atMapB)
attrs.extend(atMapA) writer.addFeature(outFeat)
attrs.extend(atMapB) except:
outFeat.setAttributes(attrs) ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
writer.addFeature(outFeat) self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
except Exception as err: else:
raise GeoAlgorithmExecutionException( # Geometry list: prevents writing error
self.tr('Feature exception while computing union')) # in geometries of different types
# produced by the intersection
# fix #3549
if int_geom.wkbType() in wkbTypeGroups[wkbTypeGroups[int_geom.wkbType()]]:
try:
outFeat.setGeometry(int_geom)
outFeat.setAttributes(atMapA + atMapB)
writer.addFeature(outFeat)
except:
ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
# the remaining bit of inFeatA's geometry
# if there is nothing left, this will just silently fail and we're good
diff_geom = QgsGeometry(geom)
if len(lstIntersectingB) != 0:
intB = QgsGeometry.unaryUnion(lstIntersectingB)
diff_geom = diff_geom.difference(intB)
if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
if diff_geom.wkbType() == 0 or QgsWKBTypes.flatType(diff_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
temp_list = diff_geom.asGeometryCollection()
for i in temp_list:
if i.type() == geom.type():
diff_geom = QgsGeometry(i)
try: try:
# the remaining bit of inFeatA's geometry
# if there is nothing left, this will just silently fail and we're good
diff_geom = QgsGeometry(geom)
if len(lstIntersectingB) != 0:
intB = QgsGeometry.unaryUnion(lstIntersectingB)
diff_geom = diff_geom.difference(intB)
if diff_geom.wkbType() == 0 or QgsWKBTypes.flatType(int_geom.geometry().wkbType()) == QgsWKBTypes.GeometryCollection:
temp_list = diff_geom.asGeometryCollection()
for i in temp_list:
if i.type() == geom.type():
diff_geom = QgsGeometry(i)
outFeat.setGeometry(diff_geom) outFeat.setGeometry(diff_geom)
outFeat.setAttributes(atMapA) outFeat.setAttributes(atMapA)
writer.addFeature(outFeat) writer.addFeature(outFeat)
except Exception as err: except:
raise GeoAlgorithmExecutionException( ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Feature exception while computing union')) self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
length = len(vproviderA.fields()) length = len(vproviderA.fields())
atMapA = [None] * length
featuresA = vector.features(vlayerB) featuresA = vector.features(vlayerB)
nFeat = len(featuresA) nFeat = len(featuresA)
@ -154,53 +192,41 @@ class Union(GeoAlgorithm):
outFeat.setGeometry(geom) outFeat.setGeometry(geom)
outFeat.setAttributes(atMap) outFeat.setAttributes(atMap)
writer.addFeature(outFeat) writer.addFeature(outFeat)
except Exception as err: except:
raise GeoAlgorithmExecutionException( ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Feature exception while computing union')) self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
else: else:
for id in intersects: for id in intersects:
request = QgsFeatureRequest().setFilterFid(id) request = QgsFeatureRequest().setFilterFid(id)
inFeatB = vlayerA.getFeatures(request).next() inFeatB = vlayerA.getFeatures(request).next()
atMapB = inFeatB.attributes() atMapB = inFeatB.attributes()
tmpGeom = QgsGeometry(inFeatB.geometry()) tmpGeom = QgsGeometry(inFeatB.geometry())
try:
if diff_geom.intersects(tmpGeom): if diff_geom.intersects(tmpGeom):
add = True add = True
diff_geom = QgsGeometry( diff_geom = QgsGeometry(diff_geom.difference(tmpGeom))
diff_geom.difference(tmpGeom)) if diff_geom.isGeosEmpty() or not diff_geom.isGeosValid():
else: ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
self.tr('GEOS geoprocessing error: One or more input features have invalid geometry.'))
else:
try:
# Ihis only happends if the bounding box # Ihis only happends if the bounding box
# intersects, but the geometry doesn't # intersects, but the geometry doesn't
outFeat.setGeometry(diff_geom) outFeat.setGeometry(diff_geom)
outFeat.setAttributes(atMap) outFeat.setAttributes(atMap)
writer.addFeature(outFeat) writer.addFeature(outFeat)
except Exception as err: except:
raise GeoAlgorithmExecutionException( ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
self.tr('Geometry exception while computing intersection')) self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
if add: if add:
try: try:
outFeat.setGeometry(diff_geom) outFeat.setGeometry(diff_geom)
outFeat.setAttributes(atMap) outFeat.setAttributes(atMap)
writer.addFeature(outFeat) writer.addFeature(outFeat)
except Exception as err: except:
raise err ProcessingLog.addToLog(ProcessingLog.LOG_INFO,
FEATURE_EXCEPT = False self.tr('Feature geometry error: One or more output features ignored due to invalid geometry.'))
nElement += 1 nElement += 1
del writer del writer
if not GEOS_EXCEPT:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Geometry exception while computing intersection'))
if not FEATURE_EXCEPT:
ProcessingLog.addToLog(ProcessingLog.LOG_WARNING,
self.tr('Feature exception while computing intersection'))
def defineCharacteristics(self):
self.name, self.i18n_name = self.trAlgorithm('Union')
self.group, self.i18n_group = self.trAlgorithm('Vector overlay tools')
self.addParameter(ParameterVector(Union.INPUT,
self.tr('Input layer'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addParameter(ParameterVector(Union.INPUT2,
self.tr('Input layer 2'), [ParameterVector.VECTOR_TYPE_ANY]))
self.addOutput(OutputVector(Union.OUTPUT, self.tr('Union')))