I am having trouble with a script.
The last script here in this link is working on QGIS 2.x and I tried to modify it to use it in QGIS 3.x but I can't till now
Merging adjacent lines in QGIS
I am trying till this moment this is the script in QGIS v2
##Lines=vector line
from qgis.core import *
import processing
def find_adjacent(selected_ids): # for finding adjacent features
outlist = []
outinds = []
outset = set()
for j, l in enumerate(selected_ids):
as_set = set(l)
inds = []
for k in outset.copy():
if outlist[k] & as_set:
outset.remove(k)
as_set |= outlist[k]
inds.extend(outinds[k])
outset.add(j)
outlist.append(as_set)
outinds.append(inds + [j])
outinds = [outinds[j] for j in outset]
del outset, outlist
result = [[selected_ids[j] for j in k] for k in outinds]
return result
layer = processing.getObject(Lines) #get input layer from GUI
crs = layer.crs().toWkt()
Create the output layer
outLayer = QgsVectorLayer('Linestring?crs='+ crs, 'snapped' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()
already_processed = []
for feat in layer.getFeatures():
attrs = feat.attributes()
geom = feat.geometry()
curr_id = feat["id"]
if curr_id not in already_processed:
query = '"id" = %s' % (curr_id)
selection = layer.getFeatures(QgsFeatureRequest().setFilterExpression(query))
selected_ids = [k.geometry().asPolyline() for k in selection]
feedback.pushInfo("selected_ids")
feedback.pushInfo(str(selected_ids))
adjacent_feats = find_adjacent(selected_ids)
feedback.pushInfo("adjacent_feats")
feedback.pushInfo(str(adjacent_feats))
for f in adjacent_feats:
first = True
for x in xrange(0, len(f)):
geom = (QgsGeometry.fromPolyline([QgsPoint(w) for w in f[x]]))
if first:
outFeat = QgsFeature()
outFeat.setGeometry(geom)
outGeom = outFeat.geometry()
first = False
else:
outGeom = outGeom.combine(geom)
outFeat.setAttributes(attrs)
outFeat.setGeometry(outGeom)
prov.addFeatures([outFeat])
already_processed.append(curr_id)
else:
continue
Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)
and this is my attempt to modify the code in QGIS 3.x
from PyQt5.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsFeature,
QgsFeatureRequest,
QgsGeometry,
QgsPoint,
QgsProject
)
import processing
class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return ExampleProcessingAlgorithm()
def name(self):
return 'myscript'
def displayName(self):
return self.tr('My Script')
def group(self):
return self.tr('Example scripts')
def groupId(self):
return 'examplescripts'
def shortHelpString(self):
return self.tr("Example algorithm short description")
def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr('Input layer'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
self.addParameter(
QgsProcessingParameterFeatureSink(
self.OUTPUT,
self.tr('Output layer')
)
)
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
source = self.parameterAsSource(
parameters,
self.INPUT,
context
)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
(sink, dest_id) = self.parameterAsSink(
parameters,
self.OUTPUT,
context,
source.fields(),
source.wkbType(),
source.sourceCrs()
)
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
def find_adjacent(selected_ids): # for finding adjacent features
outlist = []
outinds = []
outset = set()
for j, l in enumerate(selected_ids):
as_set = set(l)
inds = []
for k in outset.copy():
if outlist[k] & as_set:
outset.remove(k)
as_set |= outlist[k]
inds.extend(outinds[k])
outset.add(j) #1st iteration outset = {0}
outlist.append(as_set) #1st iteration outlist = { l }
outinds.append(inds + [j]) #1st iteration outinds = [0]
outinds = [outinds[j] for j in outset]
del outset, outlist
result = [[selected_ids[j] for j in k] for k in outinds]
return result
# Compute the number of steps to display within the progress bar and
# get features from source
total = 100.0 / source.featureCount() if source.featureCount() else 0
features = source.getFeatures()
already_processed = []
for current, feature in enumerate(features):
# Stop the algorithm if cancel button has been clicked
if feedback.isCanceled():
break
attrs = feature.attributes()
geom = feature.geometry()
curr_id = feature["strahler"]
if curr_id not in already_processed:
query = '"strahler" = %s' % (curr_id)
selection = source.getFeatures(QgsFeatureRequest().setFilterExpression(query))
selected_ids = [k.geometry().asMultiPolyline() for k in selection] #here I tried asPolyline as the QGIS v2 but it tells me "TypeError: MultiLineString geometry cannot be converted to a polyline. Only single line or curve types are permitted." so I made it as MultiPolyline
#feedback.pushInfo(str(selected_ids))
adjacent_feats = find_adjacent(selected_ids[0][0])
feedback.pushInfo(str(adjacent_feats))
for f in adjacent_feats:
first = True
for x in range(0, len(f)):
geom = (QgsGeometry.fromPolyline([QgsPoint(w) for w in f[x]]))
if first:
outFeat = QgsFeature()
outFeat.setGeometry(geom)
outGeom = outFeat.geometry()
first = False
else:
outGeom = outGeom.combine(geom)
outFeat.setAttributes(attrs)
outFeat.setGeometry(outGeom)
sink.addFeatures([outFeat])
already_processed.append(curr_id)
else:
continue
# Add the layer to the Layers panel
return {self.OUTPUT: sink}
the output of this code is merging all features that had the common feature in one feature not the adjacent ones ---> because of asMultiPolyline