[GIS] Create normal vector and calculate distance between start point and intersection

field-calculatorlinepointqgis

I have one line-layer which pictures a street net and a point-layer which defines certain locations. Please see in the picture below:
enter image description here

What I am trying to do is to create a normal vector through a point and its nearest line for each point. Then I would like to calculate the distance between the line's starting point and the intersection of the normalvector. This should look like this:
enter image description here

As I have lots of points, I need to find a way to solve this generically.

I know that the plugin NNJoin gives me the nearest edge to a point, but how do I create normal vectors and how can I then calculate the lengths?

Do I have to write a python script to realize this or is there an other way?

Best Answer

I absolutely recommend to check out PostgreSQL/PostGIS, especially if your datasets are large and dynamic!

However, if you want to stick to QGIS for now, try the Virtual Layers. They provide full integration of SpataLite functions to be used on any existing vector layer opened in the project.

The following query will identify the closest line to each point via MIN(ST_Distance(...)) in conjunction with the GROUP BY statement and calculates the distance to the line's start point (in direction of digitizing) with ST_Line_Locate_Point (this function does those two things you are looking for: finding the closest point on the line, i.e. the normal vector intersection, and returning the distance to the start point of the line as a fraction of it's total lenght; thus the part where the ST_Length(...) is multiplied by that fraction):

SELECT sub.pt_id,
       sub.ln_id,
       ST_Length(sub.ln_geom) * ST_Line_Locate_Point(sub.ln_geom, sub.pt_geom) AS length
FROM (
    SELECT p.<id> AS pt_id,
           l.<id> AS ln_id,
           p.geometry AS pt_geom,
           l.geometry AS ln_geom,
           MIN(ST_Distance(p.geometry, l.geometry))
    FROM <points_layer> AS p
      CROSS JOIN <lines_layer> AS l
    GROUP BY p.<id>
) AS sub

This assumes your geometries (i.e. the respective layers) use a projection with meter as unit! DonĀ“t forget to fill in the correct layer and column names.

This returns the id of the point, the id of it's closest line and the distance as the layers attribute table.

Note: the subquery is a rather inefficient construct, yet the only approach I know of, without using the VirtualKNN tables (SpatiaLite starts support of VirtualKNNI with version 4.4.0 and QGIS 2.X and 3.0 come only with SpatiaLite 4.3.0); The whole query might get slow on larger tables.