38
38
QgsProcessingException ,
39
39
QgsProcessingMultiStepFeedback ,
40
40
QgsWkbTypes ,
41
+ QgsProcessingParameterMultipleLayers ,
41
42
)
42
43
43
44
from .validationAlgorithm import ValidationAlgorithm
@@ -50,6 +51,9 @@ class MergeLinesAlgorithm(ValidationAlgorithm):
50
51
IGNORE_VIRTUAL_FIELDS = "IGNORE_VIRTUAL_FIELDS"
51
52
IGNORE_PK_FIELDS = "IGNORE_PK_FIELDS"
52
53
ALLOW_CLOSED_LINES_ON_OUTPUT = "ALLOW_CLOSED_LINES_ON_OUTPUT"
54
+ POINT_FILTER_LAYERS = "POINT_FILTER_LAYERS"
55
+ LINE_FILTER_LAYERS = "LINE_FILTER_LAYERS"
56
+ GEOGRAPHIC_BOUNDARY = "GEOGRAPHIC_BOUNDARY"
53
57
54
58
def initAlgorithm (self , config ):
55
59
"""
@@ -97,6 +101,30 @@ def initAlgorithm(self, config):
97
101
defaultValue = False ,
98
102
)
99
103
)
104
+ self .addParameter (
105
+ QgsProcessingParameterMultipleLayers (
106
+ self .POINT_FILTER_LAYERS ,
107
+ self .tr ("Point Filter Layers" ),
108
+ QgsProcessing .TypeVectorPoint ,
109
+ optional = True ,
110
+ )
111
+ )
112
+ self .addParameter (
113
+ QgsProcessingParameterMultipleLayers (
114
+ self .LINE_FILTER_LAYERS ,
115
+ self .tr ("Line Filter Layers" ),
116
+ QgsProcessing .TypeVectorLine ,
117
+ optional = True ,
118
+ )
119
+ )
120
+ self .addParameter (
121
+ QgsProcessingParameterVectorLayer (
122
+ self .GEOGRAPHIC_BOUNDARY ,
123
+ self .tr ("Geographic Boundary" ),
124
+ [QgsProcessing .TypeVectorPolygon ],
125
+ optional = True ,
126
+ )
127
+ )
100
128
101
129
def processAlgorithm (self , parameters , context , feedback ):
102
130
"""
@@ -124,7 +152,21 @@ def processAlgorithm(self, parameters, context, feedback):
124
152
allowClosedLines = self .parameterAsBool (
125
153
parameters , self .ALLOW_CLOSED_LINES_ON_OUTPUT , context
126
154
)
127
- nSteps = 8
155
+ pointFilterLyrList = self .parameterAsLayerList (
156
+ parameters , self .POINT_FILTER_LAYERS , context
157
+ )
158
+ lineFilterLyrList = self .parameterAsLayerList (
159
+ parameters , self .LINE_FILTER_LAYERS , context
160
+ )
161
+ geographicBoundaryLyr = self .parameterAsVectorLayer (
162
+ parameters , self .GEOGRAPHIC_BOUNDARY , context
163
+ )
164
+ nSteps = (
165
+ 9
166
+ + 3 * (pointFilterLyrList != [])
167
+ + 3 * (lineFilterLyrList != [])
168
+ + (geographicBoundaryLyr is not None )
169
+ )
128
170
multiStepFeedback = QgsProcessingMultiStepFeedback (nSteps , feedback )
129
171
currentStep = 0
130
172
multiStepFeedback .setCurrentStep (currentStep )
@@ -139,6 +181,21 @@ def processAlgorithm(self, parameters, context, feedback):
139
181
context = context ,
140
182
feedback = multiStepFeedback ,
141
183
)
184
+ if localCache .featureCount () == 0 :
185
+ return {}
186
+ currentStep += 1
187
+ multiStepFeedback .setCurrentStep (currentStep )
188
+ localCache = (
189
+ self .algRunner .runExtractByLocation (
190
+ inputLyr = localCache ,
191
+ intersectLyr = geographicBoundaryLyr ,
192
+ predicate = AlgRunner .Intersects ,
193
+ context = context ,
194
+ feedback = multiStepFeedback ,
195
+ )
196
+ if geographicBoundaryLyr is not None
197
+ else localCache
198
+ )
142
199
currentStep += 1
143
200
multiStepFeedback .setCurrentStep (currentStep )
144
201
nodesLayer = self .algRunner .runExtractSpecificVertices (
@@ -178,6 +235,86 @@ def processAlgorithm(self, parameters, context, feedback):
178
235
addEdgeLength = True ,
179
236
)
180
237
currentStep += 1
238
+ constraintNodeIds = set ()
239
+
240
+ if pointFilterLyrList :
241
+ # Merge point layers if multiple
242
+ multiStepFeedback .setCurrentStep (currentStep )
243
+ multiStepFeedback .pushInfo (
244
+ self .tr ("Identifying constraint nodes from point layers..." )
245
+ )
246
+ mergedPointLyr = self .algRunner .runMergeVectorLayers (
247
+ pointFilterLyrList , context , multiStepFeedback
248
+ )
249
+ currentStep += 1
250
+ multiStepFeedback .setCurrentStep (currentStep )
251
+ self .algRunner .runCreateSpatialIndex (
252
+ mergedPointLyr , context , multiStepFeedback , is_child_algorithm = True
253
+ )
254
+ currentStep += 1
255
+ multiStepFeedback .setCurrentStep (currentStep )
256
+ # Find nodes that intersect with points
257
+ nodesFromPoints = self .algRunner .runExtractByLocation (
258
+ inputLyr = nodesLayer ,
259
+ intersectLyr = mergedPointLyr ,
260
+ predicate = [self .algRunner .Intersects ],
261
+ context = context ,
262
+ feedback = multiStepFeedback ,
263
+ )
264
+ currentStep += 1
265
+
266
+ for nodeFeat in nodesFromPoints .getFeatures ():
267
+ geom = nodeFeat .geometry ()
268
+ geomWkb = geom .asWkb ()
269
+ constraintNodeIds .add (nodeDict [geomWkb ])
270
+
271
+ if lineFilterLyrList :
272
+ # Merge line layers if multiple
273
+ multiStepFeedback .setCurrentStep (currentStep )
274
+ multiStepFeedback .pushInfo (
275
+ self .tr ("Identifying constraint nodes from line layers..." )
276
+ )
277
+ mergedLineLyr = self .algRunner .runMergeVectorLayers (
278
+ lineFilterLyrList , context , multiStepFeedback
279
+ )
280
+ currentStep += 1
281
+ multiStepFeedback .setCurrentStep (currentStep )
282
+ self .algRunner .runCreateSpatialIndex (
283
+ mergedLineLyr , context , multiStepFeedback , is_child_algorithm = True
284
+ )
285
+ currentStep += 1
286
+ multiStepFeedback .setCurrentStep (currentStep )
287
+ # Find nodes that intersect with lines
288
+ nodesFromLines = self .algRunner .runExtractByLocation (
289
+ inputLyr = nodesLayer ,
290
+ intersectLyr = mergedLineLyr ,
291
+ predicate = [self .algRunner .Intersects ],
292
+ context = context ,
293
+ feedback = multiStepFeedback ,
294
+ )
295
+ currentStep += 1
296
+
297
+ for nodeFeat in nodesFromLines .getFeatures ():
298
+ geom = nodeFeat .geometry ()
299
+ geomWkb = geom .asWkb ()
300
+ constraintNodeIds .add (nodeDict [geomWkb ])
301
+ if geographicBoundaryLyr is not None :
302
+ currentStep += 1
303
+ multiStepFeedback .setCurrentStep (currentStep )
304
+ # Find nodes that intersect with points
305
+ nodesOutsideGeographicBounds = self .algRunner .runExtractByLocation (
306
+ inputLyr = nodesLayer ,
307
+ intersectLyr = geographicBoundaryLyr ,
308
+ predicate = [self .algRunner .Disjoint ],
309
+ context = context ,
310
+ feedback = multiStepFeedback ,
311
+ )
312
+ currentStep += 1
313
+
314
+ for nodeFeat in nodesOutsideGeographicBounds .getFeatures ():
315
+ geom = nodeFeat .geometry ()
316
+ geomWkb = geom .asWkb ()
317
+ constraintNodeIds .add (nodeDict [geomWkb ])
181
318
multiStepFeedback .setCurrentStep (currentStep )
182
319
multiStepFeedback .pushInfo (self .tr ("Finding mergeable edges" ))
183
320
outputGraphDict = graphHandler .find_mergeable_edges_on_graph (
@@ -211,6 +348,7 @@ def computeLambda(x):
211
348
isMulti = QgsWkbTypes .isMultiType (inputLyr .wkbType ()),
212
349
nodeIdDict = nodeIdDict ,
213
350
allowClosedLines = allowClosedLines ,
351
+ constraintNodeIds = constraintNodeIds ,
214
352
)
215
353
216
354
futures = set ()
0 commit comments