31
31
32
32
from qgis .core import (QgsFeatureRequest , QgsFeature , QgsGeometry ,
33
33
QgsFeatureSink ,
34
- QgsWkbTypes , QgsFields ,
35
- QgsProcessingUtils )
34
+ QgsWkbTypes ,
35
+ QgsFields ,
36
+ QgsSpatialIndex ,
37
+ QgsProcessing ,
38
+ QgsProcessingParameterFeatureSource ,
39
+ QgsProcessingParameterField ,
40
+ QgsProcessingParameterFeatureSink )
36
41
37
42
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
41
43
from processing .tools import dataobjects , vector
42
44
43
45
pluginPath = os .path .split (os .path .split (os .path .dirname (__file__ ))[0 ])[0 ]
44
46
45
47
46
48
class LinesIntersection (QgisAlgorithm ):
47
49
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 '
52
54
53
55
OUTPUT = 'OUTPUT'
54
56
@@ -62,22 +64,23 @@ def __init__(self):
62
64
super ().__init__ ()
63
65
64
66
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 ))
81
84
82
85
def name (self ):
83
86
return 'lineintersections'
@@ -86,67 +89,82 @@ def displayName(self):
86
89
return self .tr ('Line intersections' )
87
90
88
91
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 ])
100
106
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 ])
106
118
else :
107
- fieldListB = layerB .fields ()
119
+ fieldListB = sourceB .fields ()
120
+ field_indices_b = [i for i in range (0 , fieldListB .count ())]
108
121
109
122
fieldListB = vector .testForUniqueness (fieldListA , fieldListB )
110
123
for b in fieldListB :
111
124
fieldListA .append (b )
112
125
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 () )
115
128
116
- spatialIndex = QgsProcessingUtils . createSpatialIndex ( layerB , context )
129
+ spatialIndex = QgsSpatialIndex ( sourceB . getFeatures ( QgsFeatureRequest (). setSubsetOfAttributes ([]). setDestinationCrs ( sourceA . sourceCrs ())), feedback )
117
130
118
131
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
123
134
for current , inFeatA in enumerate (features ):
135
+ if feedback .isCanceled ():
136
+ break
137
+
138
+ if not inFeatA .hasGeometry ():
139
+ continue
140
+
124
141
inGeom = inFeatA .geometry ()
125
- hasIntersections = False
142
+ has_intersections = False
126
143
lines = spatialIndex .intersects (inGeom .boundingBox ())
127
144
128
145
engine = None
129
146
if len (lines ) > 0 :
130
- hasIntersections = True
147
+ has_intersections = True
131
148
# use prepared geometries for faster intersection tests
132
149
engine = QgsGeometry .createGeometryEngine (inGeom .geometry ())
133
150
engine .prepareGeometry ()
134
151
135
- if hasIntersections :
152
+ if has_intersections :
136
153
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
+
138
161
tmpGeom = inFeatB .geometry ()
139
162
140
163
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
-
148
164
if engine .intersects (tmpGeom .geometry ()):
149
165
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 ])
150
168
if tempGeom .type () == QgsWkbTypes .PointGeometry :
151
169
if tempGeom .isMultipart ():
152
170
points = tempGeom .asMultiPoint ()
@@ -155,10 +173,9 @@ def processAlgorithm(self, parameters, context, feedback):
155
173
156
174
for j in points :
157
175
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 )
161
178
162
179
feedback .setProgress (int (current * total ))
163
180
164
- del writer
181
+ return { self . OUTPUT : dest_id }
0 commit comments