Skip to content

Commit

Permalink
[processing] restore intersection algorithm (#4849)
Browse files Browse the repository at this point in the history
  • Loading branch information
nirvn committed Jul 13, 2017
1 parent 93a8025 commit d3ad913
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 43 deletions.
70 changes: 43 additions & 27 deletions python/plugins/processing/algs/qgis/Intersection.py
Expand Up @@ -34,13 +34,13 @@
QgsFeatureSink,
QgsGeometry,
QgsWkbTypes,
QgsMessageLog,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsSpatialIndex,
QgsProcessingUtils)

from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector
from processing.tools import vector

pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
Expand All @@ -58,7 +58,7 @@
class Intersection(QgisAlgorithm):

INPUT = 'INPUT'
INPUT2 = 'INPUT2'
OVERLAY = 'OVERLAY'
OUTPUT = 'OUTPUT'

def icon(self):
Expand All @@ -71,11 +71,12 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer')))
self.addParameter(ParameterVector(self.INPUT2,
self.tr('Intersect layer')))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Intersection')))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterFeatureSource(self.OVERLAY,
self.tr('Intersection layer')))

self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Intersection')))

def name(self):
return 'intersection'
Expand All @@ -84,33 +85,45 @@ def displayName(self):
return self.tr('Intersection')

def processAlgorithm(self, parameters, context, feedback):
vlayerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
vlayerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT2), context)
sourceA = self.parameterAsSource(parameters, self.INPUT, context)
sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)

geomType = QgsWkbTypes.multiType(sourceA.wkbType())
fields = vector.combineFields(sourceA.fields(), sourceB.fields())

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, sourceA.sourceCrs())

geomType = QgsWkbTypes.multiType(vlayerA.wkbType())
fields = vector.combineVectorFields(vlayerA, vlayerB)
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fields, geomType, vlayerA.crs(), context)
outFeat = QgsFeature()
index = QgsProcessingUtils.createSpatialIndex(vlayerB, context)
selectionA = QgsProcessingUtils.getFeatures(vlayerA, context)
total = 100.0 / vlayerA.featureCount() if vlayerA.featureCount() else 0
for current, inFeatA in enumerate(selectionA):
feedback.setProgress(int(current * total))
geom = inFeatA.geometry()
atMapA = inFeatA.attributes()
intersects = index.intersects(geom.boundingBox())
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())))

total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 1
count = 0

for featA in sourceA.getFeatures():
if feedback.isCanceled():
break

geom = featA.geometry()
atMapA = featA.attributes()
intersects = indexB.intersects(geom.boundingBox())

request = QgsFeatureRequest().setFilterFids(intersects)
request.setDestinationCrs(sourceA.sourceCrs())

engine = None
if len(intersects) > 0:
# use prepared geometries for faster intersection tests
engine = QgsGeometry.createGeometryEngine(geom.geometry())
engine.prepareGeometry()

for inFeatB in vlayerB.getFeatures(request):
tmpGeom = inFeatB.geometry()
for featB in sourceB.getFeatures(request):
if feedback.isCanceled():
break

tmpGeom = featB.geometry()
if engine.intersects(tmpGeom.geometry()):
atMapB = inFeatB.attributes()
atMapB = featB.attributes()
int_geom = QgsGeometry(geom.intersection(tmpGeom))
if int_geom.wkbType() == QgsWkbTypes.Unknown or QgsWkbTypes.flatType(int_geom.geometry().wkbType()) == QgsWkbTypes.GeometryCollection:
int_com = geom.combine(tmpGeom)
Expand All @@ -130,11 +143,14 @@ def processAlgorithm(self, parameters, context, feedback):
attrs.extend(atMapA)
attrs.extend(atMapB)
outFeat.setAttributes(attrs)
writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
except:
raise GeoAlgorithmExecutionException(
self.tr('Feature geometry error: One or more '
'output features ignored due to invalid '
'geometry.'))

del writer
count += 1
feedback.setProgress(int(count * total))

return {self.OUTPUT: dest_id}
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Expand Up @@ -61,6 +61,7 @@
from .GridPolygon import GridPolygon
from .ImportIntoPostGIS import ImportIntoPostGIS
from .ImportIntoSpatialite import ImportIntoSpatialite
from .Intersection import Intersection
from .Merge import Merge
from .PointsLayerFromTable import PointsLayerFromTable
from .PostGISExecuteSQL import PostGISExecuteSQL
Expand Down Expand Up @@ -98,7 +99,6 @@
# from .ConvexHull import ConvexHull
# from .FixedDistanceBuffer import FixedDistanceBuffer
# from .VariableDistanceBuffer import VariableDistanceBuffer
# from .Intersection import Intersection
# from .RandomSelection import RandomSelection
# from .RandomSelectionWithinSubsets import RandomSelectionWithinSubsets
# from .SelectByLocation import SelectByLocation
Expand Down Expand Up @@ -194,7 +194,6 @@ def getAlgs(self):
# PolygonsToLines(), LinesToPolygons(), ExtractNodes(),
# ConvexHull(), FixedDistanceBuffer(),
# VariableDistanceBuffer(),
# Intersection(),
# RandomSelection(), RandomSelectionWithinSubsets(),
# SelectByLocation(),
# ExtractByLocation(),
Expand Down Expand Up @@ -260,6 +259,7 @@ def getAlgs(self):
GridPolygon(),
ImportIntoPostGIS(),
ImportIntoSpatialite(),
Intersection(),
Merge(),
PointsLayerFromTable(),
PostGISExecuteSQL(),
Expand Down
28 changes: 14 additions & 14 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -115,20 +115,20 @@ tests:
# # check this behavior.
# # This test should stay in place because for shapefiles there should always
# # be a polygon result created since it does not support geometry collections.
# - name: Intersection (Collection Fallback)
# algorithm: qgis:intersection
# params:
# INPUT:
# name: multipolys.gml
# type: vector
# INPUT2:
# name: polys.gml
# type: vector
# results:
# OUTPUT:
# name: expected/intersection_collection_fallback.shp
# type: vector
#
- algorithm: qgis:intersection
name: Intersects multipolygons with polygons
params:
INPUT:
name: multipolys.gml
type: vector
OVERLAY:
name: polys.gml
type: vector
results:
OUTPUT:
name: expected/intersection_collection_fallback.shp
type: vector

- name: Densify geometries
algorithm: qgis:densifygeometries
params:
Expand Down

0 comments on commit d3ad913

Please sign in to comment.