[GIS] Draw a perpendicular line between point and line layer

perpendicularpyqgisqgis

I have to iterate over a point and line layer to draw the perpendicular line from each point to the nearest line. The QGIS geoalgorithm "DISTANCE TO NEAREST HUB" isn't helpful because the nearest hub isn't perpendicular.

I found this code, but how can I call the points in the Point Layer and the lines in the Line layer generally? How can I can iterate over them with a loop to find/create the perpendicular line in between?

# basic example with PyQGIS
# the end points of the line
line_start = QgsPoint(50,50)
line_end = QgsPoint(100,150)
# the line
line = QgsGeometry.fromPolyline([line_start,line_end])
# the point
point = QgsPoint(30,120)

enter image description here

def intersect_point_to_line(point, line_start, line_end):
     ''' Calc minimum distance from a point and a line segment and intersection'''
      # sqrDist of the line (PyQGIS function = magnitude (length) of a line **2)
      magnitude2 = line_start.sqrDist(line_end) 
      # minimum distance
      u = ((point.x() - line_start.x()) * (line_end.x() - line_start.x()) + (point.y() - line_start.y()) * (line_end.y() - line_start.y()))/(magnitude2)
      # intersection point on the line
      ix = line_start.x() + u * (line_end.x() - line_start.x())
      iy = line_start.y() + u * (line_end.y() - line_start.y())
      return QgsPoint(ix,iy)

line = QgsGeometry.fromPolyline([point,intersect_point_to_line(point, line_start, line_end)])

enter image description here

Best Answer

You need a reference to the layers. I do that with QgsMapCanvas class in the next code. PyQGIS also has classes to find 'Closest Segments'. For this reason you can avoid to use your 'intersect_point_to_line' function. I used 'closestSegmentWithContext' of QgsGeometry instead.

mapcanvas = iface.mapCanvas()

layers = mapcanvas.layers()

feat_points = [ feat for feat in layers[0].getFeatures() ]

feat_line = layers[1].getFeatures().next()

geoms = [ feat_line.geometry().closestSegmentWithContext(feat.geometry().asPoint())
          for feat in feat_points ]

#geom is a tupla. I need only second term, geom[1], that is a QgsPoint
for i, geom in enumerate(geoms):
    closest_line = QgsGeometry.fromPolyline([ feat_points[i].geometry().asPoint(), 
                                             geom[1] ])

    print closest_line.exportToWkt()

I employed above code with next layers; where you can have two possible situations.

enter image description here

After running the code, at the Python Console of QGIS were printed two Line Strings in WKT format. By using QuickWKT plugin of QGIS I got:

enter image description here

You can observe that, in one case, second closest segment is not perpendicular.