# Recreating the shape of curved arrows with QGIS Geometry Generator

In QGIS, I have a line layer with straight lines, consisting only of two vertices: start- end endpoint. I can now use Geometry Generator (see below for the expression I use) to create a third point in the middle of the line and shift it perpendicular to the line to get a triangle-shape line (see screenshot: yellow point, black dotted line). This is to apply an arrow symbol-layer style with curved arrows (blue arrows).

If I use the same Geometry Generator expression to create the triangle, but add a `smooth()` function, I also a curved line (red line), however, it's a different shape.

Question: what does the arrow line represent, how is it geometrically constructed? I would like to recreate the blue (arrow) line with Geometry Generator. It seems to look like a circular segment, however, I'm not sure how to construct it.

Screenshot: highlighted in yellow the expression to create the red lines:

The expression I use to create the triangle-shaped line looks as follows:

``````make_line (
start_point(\$geometry),
project(
centroid(\$geometry),
400,
azimuth(
start_point(\$geometry),
end_point(\$geometry)
),
end_point(\$geometry)
)
``````
• Check my answer (Solution 3) here: gis.stackexchange.com/a/463435/99589. Chaikin's Algorithm is implemented via the `smooth()` function. You can read more in this PDF: cs.unc.edu/~dm/UNC/COMP258/LECTURES/Chaikins-Algorithm.pdf Dec 23, 2023 at 11:47
• This is a great answer and helps to understand how `smooth()` works. However, as far as I see, it does not address the question how to create a curved line through all three points. Dec 23, 2023 at 11:53
• No, I want to recreate the blue (arrow) line: a curve through 1) line's start point, 2) yellow point, 3) line's end point Dec 23, 2023 at 12:02
• Maybe check the Changelog for QGIS 2.16, where it says: "In curved mode, nodes of the line layer this symbol layer is applied to are used as control points for circle arcs." Basically a Circular arc built through three points. Dec 23, 2023 at 12:07
• Yes, and I try to find out how to construct these arcs. Dec 23, 2023 at 12:09

Unfortunately, it is not a desirable Geometry Generator, however, I can suggest a PyQGIS approach. It is primarily based on the `segmentizeArc()` method of the `QgsGeometryUtils` class. Perhaps this tool would be a nice add-on to QGIS functions.

Let's assume there is a polyline layer (five features), see the image below. Line visualization imitates OP's example.

Proceed with `Plugins > Python Console > Show Editor` (Ctrl+Alt+P) and paste the script below:

``````# imports
from qgis.core import (QgsProject, QgsVectorLayer, QgsGeometryUtils,
QgsFeature, QgsGeometry, QgsPoint)

# getting the original polyline layer by its name
layer = QgsProject.instance().mapLayersByName("YOUR_LAYER_NAME")[0]

# creating a polyline layer for the output
vl = QgsVectorLayer(f"LineString?crs={layer.crs().authid()}&index=yes", "arrows_like", "memory")
provider = vl.dataProvider()
# adding all fields from the original layer
vl.updateFields()

# looping over each original feature
for feat in layer.getFeatures():
# initiating a new feature
new_feat = QgsFeature()

# accessing original polyline geometry as a list of QgsPointXY
geom_points = feat.geometry().asPolyline()
# converting each QgsPointXY to QgsPoint in the list
points = list(map(lambda point: QgsPoint(point), geom_points))
# building arcs from three points
arc_as_points_seq = QgsGeometryUtils.segmentizeArc(points[0], points[1], points[2])
# converting a sequence of points to a polyline
new_geom = QgsGeometry.fromPolyline(arc_as_points_seq)

# setting up new geometry
new_feat.setGeometry(new_geom)
# setting up initial attributes
new_feat.setAttributes(feat.attributes())
# finalizing a new feature

``````

Press `Run script` and get the output that will look like:

There is an option with Geometry Generator as well with the expression from below where you have the option to set the radius of the curve in line 8. If you change the value there to negative values, the curve will be created on the other side of the initial line.

Red lines created by the expression, based on the original black line:

The expression is as follows:

``````with_variable(
'azim',
degrees(azimuth (start_point (\$geometry), end_point (\$geometry))),
with_variable(
'point',
project(
centroid(\$geometry),
\$length*0.4,  -- change radius of curve here (smaller values result in larger radius)
),
with_variable(
'wedge_azim',
degrees(
azimuth(
@point,
intersection(
boundary(
make_circle (
@point,
distance (@point,start_point (\$geometry)),
100
)
),
extend (
make_line (@point, centroid(\$geometry)),
0,
length(\$geometry)
)
)
)
),
difference (
boundary(
wedge_buffer(
@point,
@wedge_azim,
2*degrees(
atan(
(length(\$geometry)/2) /
distance (@point, centroid(\$geometry))

)
),
distance (@point, start_point(\$geometry))
)
),
buffer (
make_line (start_point(\$geometry), @point, end_point(\$geometry)),
length(\$geometry)/10000
)
)
)))
``````