QGIS Geometry – Recreating the Shape of Curved Arrows with QGIS Geometry Generator

expressiongeometry-generatorlinepolyline-creationqgis

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:
enter image description here

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)
        )-radians(90)
    ),
    end_point($geometry)
)

Best Answer

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.

input

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
provider.addAttributes(layer.fields())
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
    provider.addFeature(new_feat)

QgsProject.instance().addMapLayer(vl)

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

output

Related Question