Skip to content

Commit 02bf88c

Browse files
committedJul 15, 2017
Port Line Intersection algorithm to new API
Improvements - allow different CRS between layers - instead of optionally allowing selection of a single field to keep from both inputs, allow selection of multiple fields
1 parent eaad18c commit 02bf88c

File tree

3 files changed

+116
-98
lines changed

3 files changed

+116
-98
lines changed
 

‎python/plugins/processing/algs/qgis/LinesIntersection.py

Lines changed: 81 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,26 @@
3131

3232
from qgis.core import (QgsFeatureRequest, QgsFeature, QgsGeometry,
3333
QgsFeatureSink,
34-
QgsWkbTypes, QgsFields,
35-
QgsProcessingUtils)
34+
QgsWkbTypes,
35+
QgsFields,
36+
QgsSpatialIndex,
37+
QgsProcessing,
38+
QgsProcessingParameterFeatureSource,
39+
QgsProcessingParameterField,
40+
QgsProcessingParameterFeatureSink)
3641

3742
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
38-
from processing.core.parameters import ParameterVector
39-
from processing.core.parameters import ParameterTableField
40-
from processing.core.outputs import OutputVector
4143
from processing.tools import dataobjects, vector
4244

4345
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4446

4547

4648
class LinesIntersection(QgisAlgorithm):
4749

48-
INPUT_A = 'INPUT_A'
49-
INPUT_B = 'INPUT_B'
50-
FIELD_A = 'FIELD_A'
51-
FIELD_B = 'FIELD_B'
50+
INPUT = 'INPUT'
51+
INTERSECT = 'INTERSECT'
52+
INPUT_FIELDS = 'INPUT_FIELDS'
53+
INTERSECT_FIELDS = 'INTERSECT_FIELDS'
5254

5355
OUTPUT = 'OUTPUT'
5456

@@ -62,22 +64,23 @@ def __init__(self):
6264
super().__init__()
6365

6466
def initAlgorithm(self, config=None):
65-
self.addParameter(ParameterVector(self.INPUT_A,
66-
self.tr('Input layer'), [dataobjects.TYPE_VECTOR_LINE]))
67-
self.addParameter(ParameterVector(self.INPUT_B,
68-
self.tr('Intersect layer'), [dataobjects.TYPE_VECTOR_LINE]))
69-
self.addParameter(ParameterTableField(
70-
self.FIELD_A,
71-
self.tr('Input field to keep (leave as [not set] to keep all fields)'),
72-
self.INPUT_A,
73-
optional=True))
74-
self.addParameter(ParameterTableField(
75-
self.FIELD_B,
76-
self.tr('Intersect field to keep (leave as [not set] to keep all fields)'),
77-
self.INPUT_B,
78-
optional=True))
79-
80-
self.addOutput(OutputVector(self.OUTPUT, self.tr('Intersections'), datatype=[dataobjects.TYPE_VECTOR_POINT]))
67+
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
68+
self.tr('Input layer'), [QgsProcessing.TypeVectorLine]))
69+
self.addParameter(QgsProcessingParameterFeatureSource(self.INTERSECT,
70+
self.tr('Intersect layer'), [QgsProcessing.TypeVectorLine]))
71+
72+
self.addParameter(QgsProcessingParameterField(
73+
self.INPUT_FIELDS,
74+
self.tr('Input fields to keep (leave empty to keep all fields)'),
75+
parentLayerParameterName=self.INPUT,
76+
optional=True, allowMultiple=True))
77+
self.addParameter(QgsProcessingParameterField(
78+
self.INTERSECT_FIELDS,
79+
self.tr('Intersect fields to keep (leave empty to keep all fields)'),
80+
parentLayerParameterName=self.INTERSECT,
81+
optional=True, allowMultiple=True))
82+
83+
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Intersections'), QgsProcessing.TypeVectorPoint))
8184

8285
def name(self):
8386
return 'lineintersections'
@@ -86,67 +89,82 @@ def displayName(self):
8689
return self.tr('Line intersections')
8790

8891
def processAlgorithm(self, parameters, context, feedback):
89-
layerA = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_A), context)
90-
layerB = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_B), context)
91-
fieldA = self.getParameterValue(self.FIELD_A)
92-
fieldB = self.getParameterValue(self.FIELD_B)
93-
94-
idxA = layerA.fields().lookupField(fieldA)
95-
idxB = layerB.fields().lookupField(fieldB)
96-
97-
if idxA != -1:
98-
fieldListA = QgsFields()
99-
fieldListA.append(layerA.fields()[idxA])
92+
sourceA = self.parameterAsSource(parameters, self.INPUT, context)
93+
sourceB = self.parameterAsSource(parameters, self.INTERSECT, context)
94+
95+
fieldsA = self.parameterAsFields(parameters, self.INPUT_FIELDS, context)
96+
fieldsB = self.parameterAsFields(parameters, self.INTERSECT_FIELDS, context)
97+
98+
fieldListA = QgsFields()
99+
field_indices_a = []
100+
if len(fieldsA) > 0:
101+
for f in fieldsA:
102+
idxA = sourceA.fields().lookupField(f)
103+
if idxA >= 0:
104+
field_indices_a.append(idxA)
105+
fieldListA.append(sourceA.fields()[idxA])
100106
else:
101-
fieldListA = layerA.fields()
102-
103-
if idxB != -1:
104-
fieldListB = QgsFields()
105-
fieldListB.append(layerB.fields()[idxB])
107+
fieldListA = sourceA.fields()
108+
field_indices_a = [i for i in range(0, fieldListA.count())]
109+
110+
fieldListB = QgsFields()
111+
field_indices_b = []
112+
if len(fieldsB) > 0:
113+
for f in fieldsB:
114+
idxB = sourceB.fields().lookupField(f)
115+
if idxB >= 0:
116+
field_indices_b.append(idxB)
117+
fieldListB.append(sourceB.fields()[idxB])
106118
else:
107-
fieldListB = layerB.fields()
119+
fieldListB = sourceB.fields()
120+
field_indices_b = [i for i in range(0, fieldListB.count())]
108121

109122
fieldListB = vector.testForUniqueness(fieldListA, fieldListB)
110123
for b in fieldListB:
111124
fieldListA.append(b)
112125

113-
writer = self.getOutputFromName(self.OUTPUT).getVectorWriter(fieldListA, QgsWkbTypes.Point, layerA.crs(),
114-
context)
126+
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
127+
fieldListA, QgsWkbTypes.Point, sourceA.sourceCrs())
115128

116-
spatialIndex = QgsProcessingUtils.createSpatialIndex(layerB, context)
129+
spatialIndex = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)
117130

118131
outFeat = QgsFeature()
119-
features = QgsProcessingUtils.getFeatures(layerA, context)
120-
total = 100.0 / layerA.featureCount() if layerA.featureCount() else 0
121-
hasIntersections = False
122-
132+
features = sourceA.getFeatures(QgsFeatureRequest().setSubsetOfAttributes(field_indices_a))
133+
total = 100.0 / sourceA.featureCount() if sourceA.featureCount() else 0
123134
for current, inFeatA in enumerate(features):
135+
if feedback.isCanceled():
136+
break
137+
138+
if not inFeatA.hasGeometry():
139+
continue
140+
124141
inGeom = inFeatA.geometry()
125-
hasIntersections = False
142+
has_intersections = False
126143
lines = spatialIndex.intersects(inGeom.boundingBox())
127144

128145
engine = None
129146
if len(lines) > 0:
130-
hasIntersections = True
147+
has_intersections = True
131148
# use prepared geometries for faster intersection tests
132149
engine = QgsGeometry.createGeometryEngine(inGeom.geometry())
133150
engine.prepareGeometry()
134151

135-
if hasIntersections:
152+
if has_intersections:
136153
request = QgsFeatureRequest().setFilterFids(lines)
137-
for inFeatB in layerB.getFeatures(request):
154+
request.setDestinationCrs(sourceA.sourceCrs())
155+
request.setSubsetOfAttributes(field_indices_b)
156+
157+
for inFeatB in sourceB.getFeatures(request):
158+
if feedback.isCanceled():
159+
break
160+
138161
tmpGeom = inFeatB.geometry()
139162

140163
points = []
141-
attrsA = inFeatA.attributes()
142-
if idxA != -1:
143-
attrsA = [attrsA[idxA]]
144-
attrsB = inFeatB.attributes()
145-
if idxB != -1:
146-
attrsB = [attrsB[idxB]]
147-
148164
if engine.intersects(tmpGeom.geometry()):
149165
tempGeom = inGeom.intersection(tmpGeom)
166+
out_attributes = [inFeatA.attributes()[i] for i in field_indices_a]
167+
out_attributes.extend([inFeatB.attributes()[i] for i in field_indices_b])
150168
if tempGeom.type() == QgsWkbTypes.PointGeometry:
151169
if tempGeom.isMultipart():
152170
points = tempGeom.asMultiPoint()
@@ -155,10 +173,9 @@ def processAlgorithm(self, parameters, context, feedback):
155173

156174
for j in points:
157175
outFeat.setGeometry(tempGeom.fromPoint(j))
158-
attrsA.extend(attrsB)
159-
outFeat.setAttributes(attrsA)
160-
writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
176+
outFeat.setAttributes(out_attributes)
177+
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
161178

162179
feedback.setProgress(int(current * total))
163180

164-
del writer
181+
return {self.OUTPUT: dest_id}

‎python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
from .ImportIntoPostGIS import ImportIntoPostGIS
6565
from .ImportIntoSpatialite import ImportIntoSpatialite
6666
from .Intersection import Intersection
67+
from .LinesIntersection import LinesIntersection
6768
from .LinesToPolygons import LinesToPolygons
6869
from .Merge import Merge
6970
from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
@@ -91,7 +92,6 @@
9192
from .ZonalStatistics import ZonalStatistics
9293

9394
# from .ExtractByLocation import ExtractByLocation
94-
# from .LinesIntersection import LinesIntersection
9595
# from .MeanCoords import MeanCoords
9696
# from .PointDistance import PointDistance
9797
# from .UniqueValues import UniqueValues
@@ -184,7 +184,7 @@ def __init__(self):
184184

185185
def getAlgs(self):
186186
# algs = [MeanCoords(),
187-
# LinesIntersection(), UniqueValues(), PointDistance(),
187+
# UniqueValues(), PointDistance(),
188188
# ExportGeometryInfo(),
189189
# SinglePartsToMultiparts(),
190190
# ExtractNodes(),
@@ -258,6 +258,7 @@ def getAlgs(self):
258258
ImportIntoPostGIS(),
259259
ImportIntoSpatialite(),
260260
Intersection(),
261+
LinesIntersection(),
261262
LinesToPolygons(),
262263
Merge(),
263264
NearestNeighbourAnalysis(),

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,38 +1112,38 @@ tests:
11121112
# OUTPUT_LAYER:
11131113
# hash: 7fe0e0174185fd743e23760f33615adf10f771b4275f320db6f7f4f8
11141114
# type: rasterhash
1115-
#
1116-
# # Case 1: Keep all fields
1117-
# - algorithm: qgis:lineintersections
1118-
# name: Line Intersection Keep All Fields from Both
1119-
# params:
1120-
# INPUT_A:
1121-
# name: lines.gml
1122-
# type: vector
1123-
# INPUT_B:
1124-
# name: simplify_lines.gml
1125-
# type: vector
1126-
# results:
1127-
# OUTPUT:
1128-
# name: expected/line_intersection.gml
1129-
# type: vector
1130-
#
1131-
# # Case 2: Keep fid field from both layers
1132-
# - algorithm: qgis:lineintersections
1133-
# name: Line Intersection Keep fid from Both
1134-
# params:
1135-
# FIELD_A: fid
1136-
# FIELD_B: fid
1137-
# INPUT_A:
1138-
# name: lines.gml
1139-
# type: vector
1140-
# INPUT_B:
1141-
# name: simplify_lines.gml
1142-
# type: vector
1143-
# results:
1144-
# OUTPUT:
1145-
# name: expected/line_intersection.gml
1146-
# type: vector
1115+
1116+
# Case 1: Keep all fields
1117+
- algorithm: qgis:lineintersections
1118+
name: Line Intersection Keep All Fields from Both
1119+
params:
1120+
INPUT:
1121+
name: lines.gml
1122+
type: vector
1123+
INTERSECT:
1124+
name: simplify_lines.gml
1125+
type: vector
1126+
results:
1127+
OUTPUT:
1128+
name: expected/line_intersection.gml
1129+
type: vector
1130+
1131+
# Case 2: Keep fid field from both layers
1132+
- algorithm: qgis:lineintersections
1133+
name: Line Intersection Keep fid from Both
1134+
params:
1135+
INPUT_FIELDS: fid
1136+
INTERSECT_FIELDS: fid
1137+
INPUT:
1138+
name: lines.gml
1139+
type: vector
1140+
INTERSECT:
1141+
name: simplify_lines.gml
1142+
type: vector
1143+
results:
1144+
OUTPUT:
1145+
name: expected/line_intersection.gml
1146+
type: vector
11471147

11481148
- algorithm: qgis:sumlinelengths
11491149
name: Sum line lengths

0 commit comments

Comments
 (0)
Please sign in to comment.