Port split with lines to new API

Improvements:
- handle transparent reprojection if layer and lines are in different CRS
This commit is contained in:
Nyall Dawson 2017-07-27 15:38:55 +10:00
parent 516249cea7
commit e23617a83d
3 changed files with 90 additions and 82 deletions

View File

@ -112,6 +112,7 @@ from .Smooth import Smooth
from .SnapGeometries import SnapGeometriesToLayer from .SnapGeometries import SnapGeometriesToLayer
from .SpatialiteExecuteSQL import SpatialiteExecuteSQL from .SpatialiteExecuteSQL import SpatialiteExecuteSQL
from .SpatialIndex import SpatialIndex from .SpatialIndex import SpatialIndex
from .SplitWithLines import SplitWithLines
from .SumLines import SumLines from .SumLines import SumLines
from .SymmetricalDifference import SymmetricalDifference from .SymmetricalDifference import SymmetricalDifference
from .TextToFloat import TextToFloat from .TextToFloat import TextToFloat
@ -154,7 +155,6 @@ from .ZonalStatistics import ZonalStatistics
# from .SetRasterStyle import SetRasterStyle # from .SetRasterStyle import SetRasterStyle
# from .SelectByAttributeSum import SelectByAttributeSum # from .SelectByAttributeSum import SelectByAttributeSum
# from .HypsometricCurves import HypsometricCurves # from .HypsometricCurves import HypsometricCurves
# from .SplitWithLines import SplitWithLines
# from .FieldsMapper import FieldsMapper # from .FieldsMapper import FieldsMapper
# from .Datasources2Vrt import Datasources2Vrt # from .Datasources2Vrt import Datasources2Vrt
# from .OrientedMinimumBoundingBox import OrientedMinimumBoundingBox # from .OrientedMinimumBoundingBox import OrientedMinimumBoundingBox
@ -205,7 +205,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
# PointsFromLines(), PointsToPaths(), # PointsFromLines(), PointsToPaths(),
# SetVectorStyle(), SetRasterStyle(), # SetVectorStyle(), SetRasterStyle(),
# HypsometricCurves(), # HypsometricCurves(),
# SplitWithLines(), CreateConstantRaster(), # CreateConstantRaster(),
# FieldsMapper(), SelectByAttributeSum(), Datasources2Vrt(), # FieldsMapper(), SelectByAttributeSum(), Datasources2Vrt(),
# OrientedMinimumBoundingBox(), # OrientedMinimumBoundingBox(),
# DefineProjection(), # DefineProjection(),
@ -291,6 +291,7 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
SnapGeometriesToLayer(), SnapGeometriesToLayer(),
SpatialiteExecuteSQL(), SpatialiteExecuteSQL(),
SpatialIndex(), SpatialIndex(),
SplitWithLines(),
SumLines(), SumLines(),
SymmetricalDifference(), SymmetricalDifference(),
TextToFloat(), TextToFloat(),

View File

@ -26,26 +26,23 @@ __copyright__ = '(C) 2014, Bernhard Ströbl'
__revision__ = '$Format:%H$' __revision__ = '$Format:%H$'
from qgis.core import (QgsApplication, from qgis.core import (QgsFeatureRequest,
QgsFeatureRequest,
QgsFeature, QgsFeature,
QgsFeatureSink, QgsFeatureSink,
QgsGeometry, QgsGeometry,
QgsSpatialIndex, QgsSpatialIndex,
QgsWkbTypes, QgsWkbTypes,
QgsMessageLog, QgsProcessingParameterFeatureSource,
QgsProcessingUtils) QgsProcessing,
QgsProcessingParameterFeatureSink)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector
from processing.tools import dataobjects
from processing.tools import vector from processing.tools import vector
class SplitWithLines(QgisAlgorithm): class SplitWithLines(QgisAlgorithm):
INPUT_A = 'INPUT_A' INPUT = 'INPUT'
INPUT_B = 'INPUT_B' LINES = 'LINES'
OUTPUT = 'OUTPUT' OUTPUT = 'OUTPUT'
@ -56,12 +53,13 @@ class SplitWithLines(QgisAlgorithm):
super().__init__() super().__init__()
def initAlgorithm(self, config=None): def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_A, self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer, single geometries only'), [dataobjects.TYPE_VECTOR_POLYGON, self.tr('Input layer, single geometries only'), [QgsProcessing.TypeVectorLine,
dataobjects.TYPE_VECTOR_LINE])) QgsProcessing.TypeVectorPolygon]))
self.addParameter(ParameterVector(self.INPUT_B, self.addParameter(QgsProcessingParameterFeatureSource(self.LINES,
self.tr('Split layer'), [dataobjects.TYPE_VECTOR_LINE])) self.tr('Split layer'), [QgsProcessing.TypeVectorLine]))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Split')))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Split')))
def name(self): def name(self):
return 'splitwithlines' return 'splitwithlines'
@ -70,34 +68,37 @@ class SplitWithLines(QgisAlgorithm):
return self.tr('Split with lines') return self.tr('Split with lines')
def processAlgorithm(self, parameters, context, feedback): def processAlgorithm(self, parameters, context, feedback):
layerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_A), context) source = self.parameterAsSource(parameters, self.INPUT, context)
splitLayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_B), context) line_source = self.parameterAsSource(parameters, self.LINES, context)
sameLayer = self.getParameterValue(self.INPUT_A) == self.getParameterValue(self.INPUT_B) sameLayer = parameters[self.INPUT] == parameters[self.LINES]
fieldList = layerA.fields()
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fieldList, QgsWkbTypes.multiType(layerA.wkbType()), (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
layerA.crs(), context) source.fields(), QgsWkbTypes.multiType(source.wkbType()), source.sourceCrs())
spatialIndex = QgsSpatialIndex() spatialIndex = QgsSpatialIndex()
splitGeoms = {} splitGeoms = {}
request = QgsFeatureRequest() request = QgsFeatureRequest()
request.setSubsetOfAttributes([]) request.setSubsetOfAttributes([])
request.setDestinationCrs(source.sourceCrs())
for aSplitFeature in line_source.getFeatures(request):
if feedback.isCanceled():
break
for aSplitFeature in QgsProcessingUtils.getFeatures(splitLayer, context, request):
splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry() splitGeoms[aSplitFeature.id()] = aSplitFeature.geometry()
spatialIndex.insertFeature(aSplitFeature) spatialIndex.insertFeature(aSplitFeature)
# honor the case that user has selection on split layer and has setting "use selection" # honor the case that user has selection on split layer and has setting "use selection"
outFeat = QgsFeature() outFeat = QgsFeature()
features = QgsProcessingUtils.getFeatures(layerA, context) features = source.getFeatures()
if QgsProcessingUtils.featureCount(layerA, context) == 0: total = 100.0 / source.featureCount() if source.featureCount() else 100
total = 100
else:
total = 100.0 / layerA.featureCount() if layerA.featureCount() else 0
for current, inFeatA in enumerate(features): for current, inFeatA in enumerate(features):
if feedback.isCanceled():
break
inGeom = inFeatA.geometry() inGeom = inFeatA.geometry()
attrsA = inFeatA.attributes() attrsA = inFeatA.attributes()
outFeat.setAttributes(attrsA) outFeat.setAttributes(attrsA)
@ -141,6 +142,9 @@ class SplitWithLines(QgisAlgorithm):
split_geom_engine.prepareGeometry() split_geom_engine.prepareGeometry()
while len(inGeoms) > 0: while len(inGeoms) > 0:
if feedback.isCanceled():
break
inGeom = inGeoms.pop() inGeom = inGeoms.pop()
if inGeom.isNull(): # this has been encountered and created a run-time error if inGeom.isNull(): # this has been encountered and created a run-time error
@ -154,7 +158,7 @@ class SplitWithLines(QgisAlgorithm):
try: try:
result, newGeometries, topoTestPoints = inGeom.splitGeometry(splitterPList, False) result, newGeometries, topoTestPoints = inGeom.splitGeometry(splitterPList, False)
except: except:
QgsMessageLog.logMessage(self.tr('Geometry exception while splitting'), self.tr('Processing'), QgsMessageLog.WARNING) feedback.reportError(self.tr('Geometry exception while splitting'))
result = 1 result = 1
# splitGeometry: If there are several intersections # splitGeometry: If there are several intersections
@ -179,6 +183,9 @@ class SplitWithLines(QgisAlgorithm):
parts = [] parts = []
for aGeom in inGeoms: for aGeom in inGeoms:
if feedback.isCanceled():
break
passed = True passed = True
if QgsWkbTypes.geometryType(aGeom.wkbType()) == QgsWkbTypes.LineGeometry: if QgsWkbTypes.geometryType(aGeom.wkbType()) == QgsWkbTypes.LineGeometry:
@ -196,7 +203,7 @@ class SplitWithLines(QgisAlgorithm):
if len(parts) > 0: if len(parts) > 0:
outFeat.setGeometry(QgsGeometry.collectGeometry(parts)) outFeat.setGeometry(QgsGeometry.collectGeometry(parts))
writer.addFeature(outFeat, QgsFeatureSink.FastInsert) sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
feedback.setProgress(int(current * total)) feedback.setProgress(int(current * total))
del writer return {self.OUTPUT: dest_id}

View File

@ -1716,56 +1716,56 @@ tests:
name: expected/create_points.gml name: expected/create_points.gml
type: vector type: vector
# - algorithm: qgis:splitwithlines - algorithm: qgis:splitwithlines
# name: Split lines with lines (new alg) name: Split lines with lines (new alg)
# params: params:
# INPUT_A: INPUT:
# name: lines.gml name: lines.gml
# type: vector type: vector
# INPUT_B: LINES:
# name: custom/lines2.gml name: custom/lines2.gml
# type: vector type: vector
# results: results:
# OUTPUT: OUTPUT:
# name: expected/split_lines_with_lines.gml name: expected/split_lines_with_lines.gml
# type: vector type: vector
# compare: compare:
# geometry: geometry:
# precision: 7 precision: 7
#
# - algorithm: qgis:splitwithlines - algorithm: qgis:splitwithlines
# name: Split poly with lines name: Split poly with lines
# params: params:
# INPUT_A: INPUT:
# name: polys.gml name: polys.gml
# type: vector type: vector
# INPUT_B: LINES:
# name: lines.gml name: lines.gml
# type: vector type: vector
# results: results:
# OUTPUT: OUTPUT:
# name: expected/split_polys_with_lines.gml name: expected/split_polys_with_lines.gml
# type: vector type: vector
# compare: compare:
# geometry: geometry:
# precision: 7 precision: 7
#
# - algorithm: qgis:splitwithlines - algorithm: qgis:splitwithlines
# name: Split lines with same lines name: Split lines with same lines
# params: params:
# INPUT_A: INPUT:
# name: lines.gml name: lines.gml
# type: vector type: vector
# INPUT_B: LINES:
# name: lines.gml name: lines.gml
# type: vector type: vector
# results: results:
# OUTPUT: OUTPUT:
# name: expected/split_lines_with_lines_same.gml name: expected/split_lines_with_lines_same.gml
# type: vector type: vector
# compare: compare:
# geometry: geometry:
# precision: 7 precision: 7
- algorithm: qgis:dropgeometries - algorithm: qgis:dropgeometries
name: Drop geometries name: Drop geometries