Polygon – How to Insert Equally Distributed N Points into Polygons Using QGIS

pointpolygonqgis-3voronoi-thiessen

I know the "Random Points inside Polygons" tool in QGIS. It generates the below output.

Screenshot of agricultural parcels with some points

What I want to achieve however are 8 equally distributed points for each of the polygons. I thought of dividing the polygons Voronoi-style by the random points and then generating new (equally distributed) points, but I don't seem to be able to do so. Using "Voronoi Polygons" in the toolbox, I only get a Voronoi diagram that's bounded by a rectangle. No way to divide the whole polygon by it:

Screenshot of agricultural parcels with some points and Voronoi

How can I get 8 equally distributed points inside each of the polygons?

Best Answer

I implemented Cyril's comment. This is the input test polygon:

test polygon

  1. Polygon to Lines

test polygon to lines

  1. Split lines by maximum length using $length / 7 in the expression builder. (8 vertices)

test polygon split at max length

  1. Extract specific vertices (0 stands for start point)

test extract specific vertices

  1. Voronoi Polygons with 100% buffer to make sure that parts of the polygon do not lie outside the generated Voronoi (in theory they may still lie outside, but 100% is quite big)

test Voronoi from vertices

  1. Intersect Voronoi and test polygon

test intersect Voronoi and polygon

  1. Point on surface (centroids could fall into holes)

test point on surface

The resulting 8 points look like this inside the test polygon:

result: test polygon with points


I will now try to automate this procedure and edit my answer when I have results.

Update 5.12.2019: I haven't been able to automate this task.
Update 4.1.2022: Here is an implementation in Shapely:

from itertools import count, islice

from shapely.geometry import MultiPoint, Polygon
from shapely.ops import substring, voronoi_diagram


def _get_voronoi_starting_points(polygon: Polygon, point_count: int) -> MultiPoint:
    perimeter = polygon.exterior
    segment_length = perimeter.length / point_count
    segment_starts = islice(count(0, segment_length), 0, point_count)

    return MultiPoint([substring(perimeter, start, start) for start in segment_starts])

polygon =  # shapely.geometry.Polygon
point_count = 8

voronoi = voronoi_diagram(_get_voronoi_starting_points(polygon, point_count))
equally_distributed_points = MultiPoint(
    [part.intersection(polygon).representative_point() for part in voronoi.geoms]
)