2

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)
)
6
  • 1
    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
    – Taras
    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.
    – Babel
    Dec 23, 2023 at 11:53
  • 1
    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
    – Babel
    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.
    – Taras
    Dec 23, 2023 at 12:07
  • Yes, and I try to find out how to construct these arcs.
    – Babel
    Dec 23, 2023 at 12:09

2 Answers 2

2

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

2

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

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)
        radians (@azim-90)
    ),
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
        )
    )
)))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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