2

With the following expression I am trying to create a set of convex hulls from a layer with a point geometry that complies two variable conditions: a minimum number of points can be declared and a maximum distance can be declared.

My first approximation to get these goal is the following expression. In this work example case, the minimum number of points is 6 and the maximum distance is 200 meters:

convex_hull(
    collect_geometries(
        array_foreach(
            array_filter(
                overlay_nearest('punts', $geometry, limit:=6, max_distance:=200),
                distance($geometry, @element) > (
                    array_sort(
                        array_agg(
                            distance($geometry, @element)
                        )
                    )[1] * 3
                )
            ),
            @element
        )
    )
)

Expression description:

My idea to create a convex hull with a variable number of nearest points and a maximum distance I use overlay_nearest function in combinaction with convex_hull function and a expression to calculate the minimum distance. Here are the steps:

1- limit:=6 → variable to number of nearest points I want to consider

2- max_distance:=200 → variable to the maximum distance I want to consider

3- [1] * 3 → variable to minimum distance factor I want to use

I write this expression with the idea to works by first using the overlay_nearest function to finds specified number of nearest points to each feature in the layer within the specified maximum distance. I then filters out any points that are closer than specified minimum distance factor using array_filter function and the distance function. Finally, it collects all the filtered points into single multipoint geometry and creates a convex hull polygon.

Result of the previous expression in which I have made a correction in adding the max_distance parameter:

enter image description here

Then I add the conditions like this but with this expression the result is NULL:

CASE
WHEN count(overlay_nearest('punts', $geometry, limit:=6, max_distance:=200)) >= 6 THEN
convex_hull(collect_geometries(array_foreach(generate_series(1,6), 
convex_hull(
    collect_geometries(
        array_foreach(
            array_filter(
                overlay_nearest('punts',$geometry,limit:=6, max_distance:=200),
                distance($geometry, @element) > (
                    array_sort(
                        array_agg(
                            distance($geometry, @element)
                        )
                    )[0] * 3
                )
            ),
            @element
        )
    )
))))
ELSE
NULL
END

Result of this expression after adding the correction proposed by user Tom Brennan:

enter image description here

So far the result is not as expected. I don't know if this approach is good, or if the problem I want to solve is not so trivial and requires a more sophisticated expression that takes into consideration a different approach. Any help is welcome.

The expected result would be something like this:

enter image description here

I don't know if I am approaching the problem well with this expression I am building, or there is some other more simplified approach.

7
  • 1
    Can you explain your first expression? It looks like you are saying that the distance to any feature in the group should be no more than 3 times the distance to the closest feature in that group, but you haven't mentioned this anywhere else. How does this relate to the 200m? Commented Oct 9, 2023 at 21:00
  • Yes, of course. I try to make the description of the expression in the text above Commented Oct 10, 2023 at 6:02
  • 1
    Start by replacing "count" with "array_length". I don't think it will fully solve your problem(!), but it will fix the reason that you're getting NULL for everything. "overlay_nearest" returns an array, so you need to test the length of the array. Commented Oct 10, 2023 at 7:36
  • 1
    The core issue you have is that each point feature will have its own convex hull (or NULL if it fails the test) because the initial logic is looking for the nearest 6 points to that point within 200m. Your final diagram assumes that you will only end up with say 4 convex hulls, but you can see from the previous diagram that it's potentially quite a few more than that. Your problem statement has similarities with: gis.stackexchange.com/questions/468119/… Commented Oct 10, 2023 at 11:44
  • 1
    You probably need to refine your conditions more precisely, and also accept that it may be too hard to do with just the Geometry Generator ie may need to create a helper layer. For example, if you were to just restrict to a maximum distance between points, and a minimum number of points, you could use a buffer layer similar to the solution above. Commented Oct 10, 2023 at 22:59

1 Answer 1

1

I suggest you split the workflow in two (three) steps:

  1. Run DB-Scan clustering with you settings: Minimum of 6 points per cluster, within 200 m. I only got three clusters out of my random points, but that should suffice (green are points not in a cluster): enter image description here
  2. Use the minimum bounding geometry tool, asking it to return convex hulls, and taking into account the CLUSTER_ID the DB-Scan gave us: enter image description here
  3. Manually remove the largest convex hull, which covers all points.

You could automate this whole process using the graphical modeler, even allowing different cluster sizes and distances by requesting them as part of the model. The last step of removing the largest convex hull could be done by selecting and deleting the hull with the largest area.

2
  • Thanks Erik for this proposed solution but it is not what I am looking for In my case (45 points cloud, the DBScan clustering algorithm with 6 min size points, and with 200 max distance, only returns me 1 cluster On the other hand, I would like to solve this goal with the Styling Geometry Generator options to avoid preprocessing and data storage Thanks anyway Commented Oct 9, 2023 at 10:40
  • I'm sorry if I did not explain myself well at the beginning of the question Commented Oct 9, 2023 at 11:01

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.