13

I am using QGIS and I am looking for a script, or a plugin, that can create a large number of perpendicular lines from a point layer to lines in a separate line layer.

So far, I've tried to use the Hub Distance function in MMQGIS (turning the lines into points and then connecting the points to the nearest hub) and the respective tool of the QGIS geoalgorithms. Neither worked. Both take more than 2 hours and create either lines all of the layer or lines that are not perpendicular or connected to the points.

In the picture, you can see the present status of the project. The perpendicular lines should run from the points to the nearest line. In the end, I would like to use intersection points with a line between the points and the country borders to create a buffer of 4-sided polygons that is two polygons deep. I mention this in case that there is an easier way of doing this. enter image description here enter image description here

I know that there are some posts on how to create perpendicular lines, but neither of them solved my problem.

2
  • 1
    @Germán Carrillo This question is not an exact duplicate of existing question "Drawing perpendicular lines in PyQGIS?" (gis.stackexchange.com/questions/59169/…) because the answer doesn't use 'closestSegmentWithContext' method in a loop for exploring each interaction between points and features line for taking minimum distance to create a line memory layer. It's impossible because this answer only uses points. Please, review it again.
    – xunilk
    Commented Mar 20, 2017 at 6:27
  • 1
    I still find the other answer a good basis to solve this question. The OP should have mentioned in the original question that he/she was aware of related posts AND tell us why they didn't work for him/her. Nonetheless, good answer, thanks for posting! Commented Mar 20, 2017 at 14:25

2 Answers 2

9

Next script automated creation of perpendicular lines between a point layer and a line layer. The perpendicular segments (features of a memory layer) created run from the points to the nearest feature of line layer.

mapcanvas = iface.mapCanvas()

layers = mapcanvas.layers()

p_lyr = layers[0]
l_lyr = layers[1]

epsg = p_lyr.crs().postgisSrid()

uri = "LineString?crs=epsg:" + str(epsg) + "&field=id:integer""&field=distance:double(20,2)&index=yes"

dist = QgsVectorLayer(uri, 
                      'dist', 
                      'memory')

QgsMapLayerRegistry.instance().addMapLayer(dist)

prov = dist.dataProvider()

lines_features = [ line_feature for line_feature in l_lyr.getFeatures() ] 
points_features = [ point_feature for point_feature in p_lyr.getFeatures() ]

feats = []

for p in points_features:

    minDistPoint = min([l.geometry().closestSegmentWithContext( p.geometry().asPoint() ) for l in lines_features])[1]
    feat = QgsFeature()
    feat.setGeometry(QgsGeometry.fromPolyline([p.geometry().asPoint(), minDistPoint]))
    feat.setAttributes([points_features.index(p),feat.geometry().length()])
    feats.append(feat)

prov.addFeatures(feats)

I tried it out with a situation very similar to presented in the question:

enter image description here

After running the code at the Python Console of QGIS it was obtained:

enter image description here

3
  • Worked marvelously. I will have to clean it up a bit as I get some misfits like in your example, but otherwise it only took seconds and looks perfect. Thank you very, very much.
    – Monody
    Commented Mar 20, 2017 at 5:38
  • Does this code save features in the attribute table? It seems like output layer is empty.
    – Case Msee
    Commented Jul 27, 2020 at 1:45
  • This code is for QGIS 2.18 and, in this case, it worked adequately. For actual version of QGIS 3, you can watch an updated answer below.
    – xunilk
    Commented Jul 27, 2020 at 1:59
7

Here is the same code as in accepted answer only adjusted to work with Python 3.x (or QGIS v3.x):

from qgis.core import QgsProject

mapcanvas = iface.mapCanvas()

layers = mapcanvas.layers()

p_lyr = layers[0]
l_lyr = layers[1]

epsg = p_lyr.crs().postgisSrid()

uri = "LineString?crs=epsg:" + str(epsg) + "&field=id:integer""&field=distance:double(20,2)&index=yes"

dist = QgsVectorLayer(uri,
                      'dist',
                      'memory')

QgsProject.instance().addMapLayer(dist)

prov = dist.dataProvider()

lines_features = [ line_feature for line_feature in l_lyr.getFeatures() ]
points_features = [ point_feature for point_feature in p_lyr.getFeatures() ]

feats = []

for p in points_features:

    minDistPoint = min([l.geometry().closestSegmentWithContext( p.geometry().asPoint() ) for l in lines_features])[1]
    feat = QgsFeature()
    feat.setGeometry(QgsGeometry.fromPolylineXY([p.geometry().asPoint(), minDistPoint]))
    feat.setAttributes([points_features.index(p),feat.geometry().length()])
    feats.append(feat)

prov.addFeatures(feats)

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.