There is a concave hull option in QGIS but it's available in the Processing toolbox only; it only works on points, so you have to extract nodes before you run it.
- Extract nodes;
- Open Processing toolbox and select Concave Hull from the QGIS geoalgorithms;
- Choose the point layer from (1), and select a threshold - '1' is just like a convex hull, and the smaller the number the more concave the result (experiment!).
This can be done more easily using a model, without the need to save intermediate sets of nodes:
- Open the Processing toolbox and select
Models|Tools|Create new model
.
- Add two parameters (drag from parameters list on left) - one will be the input vector (any type of vector - point, polygon, line) and the other (drag a 'Number' parameter across) will be the threshold as per the 'Concave hull' dialog:
- Switch from the Parameters tab to the Algorithms tab in the modelbuilder, find the 'Extract nodes' and drag that into the model. The input vector should automatically be indicated as the input layer; click 'ok'.
- Find and drag in the Concave hull algorithm. Change three options:
- The "Input point layer" should be "Output layer from algorithm 'Extract Nodes'";
- The threshold should be the number parameter you gave a name to in 3 - 'level' in my example below;
- Give the output a name in the last text box, i.e. concave_hull.
- The graphical model should now look something like this:
- Enter a group name (i.e. 'Test') and a model name ('concave hull'), then save the model in the default location.
To run, add a set of points, lines or polygons, then double-click the model and run it on your layer:
From what you say, it seems like you wanted to start from the points
layer. As you want the number of points within the polygon
layer, it's easier to place the logic in the polygon
layer (also allowing you to use the native label positioning features, centroid by default).
You can use this formula in the polygon
layer Label (or as a Virtual Field in the polygon
Attribute Table)
to_string(
round(
array_length(overlay_intersects('points', $id)) ---number of points in the polygon
/
aggregate('points','count',$id) ---number of points in points layer
,2)*100
) || ' %'
If you want this to automatically apply to any new Point layer, you can update the code to be the following
:
to_string(
round(
array_length(overlay_intersects( array_to_string( array_filter( @map_layer_ids ,@element!=@layer_id)), $id)) ---number of points in the polygon
/
aggregate( array_to_string( array_filter( @map_layer_ids ,@element!=@layer_id)),'count',$id) ---number of points in points layer
,2)*100
) || ' %'
with the point
layer name replaced by array_to_string( array_filter( @map_layer_ids ,@element!=@layer_id))
which is the only active layer besides the polygon one. If there are other 'static' layers you want to exclude, you can add them to the filter.
Swithching to another point layer, without changing the Style in the polygon layer:
If you have static layers that you want to keep active: add them to the layer filter. Set the filter part to:
@element not in (@layer_id, 'any other layer name you need to remove', 'any other layer to remove',...)
`@layer_id' filters the polygon layer, then add a comma separated list of layers you want to keep active.
For instance I added an OtherLayer displayed on the map.
Use the @map_layer_ids to identify its id
and added it to the filter list
to_string(round(array_length(overlay_intersects( array_to_string( array_filter( @map_layer_ids ,@element not in (@layer_id,'OtherLayer_a9983d8b_9323_4fac_83de_e8e24e78c8a1'))), $id)) /aggregate( array_to_string( array_filter( @map_layer_ids ,@element not in (@layer_id,'OtherLayer_a9983d8b_9323_4fac_83de_e8e24e78c8a1'))),'count',$id) ,1)*100) || ' %'
Best Answer
The trick is to first collect the points within each polygon with the functions
collect()
andoverlay_within()
. Use this expression:Red point created with the expression from above; red line: concave hull, created with the same expression, without the
centroid()
part:To draw a line from the initial points to the centroid of the concave hull, simple add
make_line ($geometry,
at the beginning of the expression and add a closing bracket)
at the end of the expression, see: