QGIS Expression – Drawing 10 Nearest Lines from Each Point to the Centroid of the 5 Nearest Points

geometry-generatorpolyline-creationproximityqgisqgis-expression

Starting from a layer with point geometry, my goal is to do two calculations in one Geometry Generator expression.

First, for each point, I would like to calculate the centroid for the 5 points nearest to it.

Next, for each calculated centroid I would like to draw the 10 nearest lines connecting to it.

To calculate the centroid I am working with the following expression:

centroid(collect_geometries (
        array_foreach (
            overlay_nearest (
                'TEST',
                $geometry,
                limit:=5
            ),
            make_line (
                $geometry,
                @element
            )
        )
    ))

To draw the line I used this expression:

collect_geometries (
    array_foreach (
        overlay_nearest (
            'CENTRO',
            $geometry,
            limit:=10
        ),
        make_line (
            $geometry,
            @element
        )
    )
)

Result:

enter image description here

My goal is to unify the two expressions in a single expression for the Geometry Generator that works with the original layer.

Best Answer

There are several things regarding your expression:

  • This is the most critical point, that has to do with the overlay_nearest() function. It will also consider the same feature as a closest taken from the same layer. See this thread for more details: QGIS expression: when using overlay_nearest sometimes a feature considers itself its nearest neighbour. It also refers to a QGIS discussion on the GitHub
  • For each point, you are attempting to calculate the centroid for the 5 points nearest to it. However, in your first expression, you are calculating the centroid for five lines instead, init?
  • Keep in mind, that for a vast data set, one should think of a better approach, even with a spatial index
  • Number of input points: N, number of centroids: N, number of lines N*10

Let's assume there is a point layer called 'points_in_polygon' (N=10), see the image below:

input

After using this expression:

collect_geometries(
    array_foreach(
        array_remove_at(
            overlay_nearest(
                layer:='points_in_polygon', -- change accordingly
                expression:=centroid(
                            collect_geometries(
                                array_remove_at(
                                    overlay_nearest(
                                        layer:='points_in_polygon', -- change accordingly
                                        expression:=$geometry,
                                        limit:=6 -- change correspondingly
                                        ),
                                    0)
                                )
                            ),
                limit:=11 -- change correspondingly
                ),
            0),
        make_line(
            @element,
            centroid(
                collect_geometries(
                    array_remove_at(
                        overlay_nearest(
                            layer:='points_in_polygon', -- change accordingly
                            expression:=$geometry,
                            limit:=6 -- change correspondingly
                            ),
                        0)
                    )
                )
            )
        )
    )

The above expression is sure can be optimized with the with_variable() to avoid double writings.

Afterwards, apply the "Multipart to singleparts" geoalgorithm.

And get the output like this (N=120):

output

Usage of the "Delete duplicate geometries" can also be feasible.