1

I would like to snap line features (.shp) to the corresponding point features based on a common attribute field they have (and not according to any distance). I have around 150 different attribute values, and for each I do have only one corresponding point feature but several lines to snap to it.


I thought of doing the following steps to achieve this goal:

1) Creating a list of values containing uniques values from the line attribute field

2) Iterating over the point and the line layer to select features corresponding to each unique value

3) Snap the selected lines to the selected point


I did the first step but I do not manage to code the following steps in PyQGIS. Does someone have any ideas how it could be done?


Here is my network in the first place : Here is my network in the first place :

Here the result after snapping the lines to the plot outlet : Here the result after snapping the lines to the plot outlet :

2
  • 1
    I don't understand what you mean by "snapping". What should the result geometry look like and what attributes should be present? Maybe you could provide an excerpt of your points and lines in the question, and an explanation of what the result should look like in terms of geometry and attributes.
    – til_b
    Sep 23, 2020 at 13:34
  • I am working with agricultural plots and it want to connect all the drainage networks within each plot to corresponding plot outlet to the river. That is why I only want to move the last vertex of the lines (I want to have an influence on the geometry but not on the attributes).
    – Jess8070
    Sep 24, 2020 at 13:53

1 Answer 1

1

Try this code:

linelyr = QgsProject.instance().mapLayersByName('Single parts')[0] #Change to match you layername
lineidfield = 'id' #Change
pointlyr = QgsProject.instance().mapLayersByName('New scratch layer')[0] #Change
pointidfield = 'id' #Change

max_distance = 500 #Change. It is the maximum distance to search for points to snap to

d = {} #Dictionary to store each lines id and the point it should be snapped to
for line in linelyr.getFeatures():
    verts = [v for v in line.geometry().vertices()]
    lastvert = verts[-1]
    potential_points = []
    for p in pointlyr.getFeatures():
        potential_points = []
        dist = p.geometry().distance(QgsGeometry.fromPointXY(QgsPointXY(lastvert)))
        if dist <=max_distance and line[lineidfield]==p[pointidfield]:
            potential_points.append([QgsPoint(p.geometry().asPoint()), dist])
            d[line.id()] = min(potential_points, key=lambda x: x[1])[0] #If multiple points with the same id as the line, then snap to the closest point 
    
#d is each lines id and the point it should be snapped to:
#{1: <QgsGeometry: Point (340686.33727786090457812 6426865.10069382563233376)>, 4: <QgsGeometry: Point (337979.94456608395557851 6427246.28276590723544359)>}

#Update line geometries using dictionary
with edit(linelyr):
    for f in linelyr.getFeatures():
        if f.id() in d:
            g = [v for v in f.geometry().vertices()]
            g[-1] = d[f.id()] #Replace last vertice (-1) with the point from the dictionary
            f.setGeometry(QgsGeometry.fromPolyline(g))
            linelyr.updateFeature(f)

From: enter image description here To: enter image description here

1
  • 1
    That is awesome, it worked super well! Thank you very much!
    – Jess8070
    Oct 7, 2020 at 13:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.