# Selecting point features on the outside of line curves - QGIS 3

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? • From the view of a computer: how would you define "curve"? Apr 1 at 8:09

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: Changing the value in line 2 to `5` leads to a reduction of selected points: Screenshot for step 4, version 2: see the selected points highlighted in yellow: • I admire your knowledge of QGIS expressions. :) Apr 1 at 23:31
• Thanks, I appreciate it! If I only would know half of your Python knowledge! 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. Apr 5 at 22:34

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')
pointlayer = QgsProject.instance().mapLayersByName('point')
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: 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.