2

I need to select points that fall on the outside of line curves using QGIS3.

I have evaluated the curvature of the road and used that to select points that are within 20m of a "curved road" (statistically classified using ZScores). However, I am now interested in selecting the points that fall on the outside of the curve. Ideally, I would like to identify these points by flagging "yes" in an attribute field called "OutsideCurve". This process will be repeated on a wider road network.

The image below shows the data I am working with and I have highlighted the points which I deem to be on the outside of a curve.

Could someone please recommend a method/tool/plugin that may help to identify points on the outside of curves?

enter image description here

1
  • 1
    From the view of a computer: how would you define "curve"? – MrXsquared Apr 1 at 8:09
3

You can achieve this using QGIS expressions to create new geomet.

  1. Create points in a regular interval along your line (street). The interval should be in a distance so that curves are covered by several points. Use Menu Processing / Toolbox / Points along geometry. All further steps will be applied on the layer created with this tool.

  2. Create for each point the azimuth (angle) of the line connecting each point with the next point with Field calculator to create a new field azimuth using this expression:

degrees (
    azimuth (
        geometry (
            get_feature_by_id (
                @layer, 
                $id
            )
        ),
        geometry (
            get_feature_by_id (
                @layer, 
                $id+1
            )
        )
    )
)
  1. Create again a new field called az_change, calculating how the azimuth of each point differs from the azimuth of the next point using this expression. Delete the abs() part of the expression to be able to differentiate if the curve is going to the left or to the right (positive/negative values for change of azimuth):
round (
    abs( attribute (
            get_feature_by_id (
                @layer, 
                $id
            ), 
            'azimuth' 
        ) -
        attribute (
            get_feature_by_id (
                @layer, 
                $id+1
            ), 
            'azimuth' 
        )
    ),
    1
)

  1. version 1: Now createt the points you're interested in. You can set a condition (line 2 of the expression) as how large the azimuth change should be this section of the line to be considered "a curve": I chose 2, feel free to play around with different values. In line 5, change 'point' with the name of the layer that contains the points from whicht you want to select. Use the following expression to create a new point geometry - be aware the overlay_nearest function is available since QGIS 3.16:
if (
     "az_change"  >2,
    array_first (
        overlay_nearest( 
            'point', 
            $geometry, 
            limit:=1    
        )
    ), 
    NULL
)   
  1. version 2: use select by expression, applied this time on the layer with the original points from where you want to select some, and paste this expression (replace points_on_line with the name of your layer created in step 1) - again, you can change the number 2 at the end to get an optimal result: array_first (overlay_nearest( 'points_on_line', az_change)) > 2. You can now use this selection to create a new attribute field outside_curve.

Screenshot for step 4, version 1: original line (street: black) and points along the street (blue). White dots are the points created in step 1. Their label shows the value of the azimuth change (field created in step 3). The red cross symbolizes the points created in step 4: the solution you're looking for: enter image description here

Changing the value in line 2 to 5 leads to a reduction of selected points: enter image description here

Screenshot for step 4, version 2: see the selected points highlighted in yellow: enter image description here

3
  • I admire your knowledge of QGIS expressions. :) – Kadir Şahbaz Apr 1 at 23:31
  • Thanks, I appreciate it! If I only would know half of your Python knowledge! – Babel Apr 1 at 23:36
  • Thanks for your great response! Is there a way to distinguish between inside a curve and outside a curve? I am most interested in the points highlighted on the right-hand side of the image as they are outside the curve. – PollyGone Apr 5 at 22:34
1

Here is an idea how this could be done using PyQGIS. The code surely can be improved though by means of performance and rules.

The basic idea:

  • loop through the vertices of the line
  • calculate the azimuth of the previous vertex to the current vertex
  • calculate the azimuth of the current vertex to the next vertex
  • if the difference between these two azimuths is within a given threshold, buffer this vertex by a given size
  • check if there is a point inside this buffer, if yes, select it
linelayer = QgsProject.instance().mapLayersByName('line')[0]
pointlayer = QgsProject.instance().mapLayersByName('point')[0]
azimuth_threshold = 1
buffer_size = 0.01 # in CRS units

pointlayer.removeSelection()
selection = []
bufferlist = []
for feat in linelayer.getFeatures():
    vertices = feat.geometry().asPolyline()
    for v in range(1,len(vertices)-1):
        vert1 = vertices[v-1]
        vert2 = vertices[v]
        vert3 = vertices[v+1]
        azimuth_before = vert1.azimuth(vert2)
        azimuth_after = vert2.azimuth(vert3)
        #print('abs before: ' + str(abs(azimuth_before)))
        #print('abs after: ' + str(abs(azimuth_after)))
        #print('before minus after: ' + str(abs(azimuth_before) - abs(azimuth_after)))
        if ((abs(azimuth_before)-abs(azimuth_after)) > azimuth_threshold) or ((abs(azimuth_before)-abs(azimuth_after)) < azimuth_threshold*-1):
            geom = QgsGeometry.fromPointXY(vert2)
            buffer = geom.buffer(buffer_size, 5)
            for point in pointlayer.getFeatures():
                if point.geometry().intersects(buffer):
                    selection.append(point.id())
pointlayer.select(selection)

An example:

enter image description here

1

Here's one way:

Every 3 consecutive points on your curve give two azimuths. The sign of the difference tells you if the curve is turning right or left.

All points you are assessing can be projected to the curve, where they intersect with a segment formed by one pair of points from the curved line.

The azimuth of this segment relative to the azimuth of the projection tells you if the point is left or right of the line. Dot product should do it.

If the point is on the left of the line, and the line is curving to the right, then the point is outside the curve. Etc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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