I have some PostGIS SQL that generates uniformly distributed point cluster centroids within polygons (loosely based on this tutorial). The number of point cluster centroids generated is based on the polygon area. The purpose of this is to create uniformly distributed sample points by area within forest stand polygons.
Here is an example of the output:
And here is the SQL (including sample data) to generate this:
-- Make up some data
CREATE TABLE polys(poly_id, geom) AS (
VALUES (1, 'POLYGON((1 1, 1 5, 4 5, 4 4, 2 4, 2 2, 4 2, 4 1, 1 1))'::GEOMETRY),
(2, 'POLYGON((6 6, 6 10, 8 10, 9 7, 8 6, 6 6))'::GEOMETRY)
);
-- Create point clusters within each polygon
CREATE TABLE pnt_clusters AS
SELECT polys.poly_id,
CASE
WHEN ST_Area(polys.geom) >9 THEN ST_ClusterKMeans(pts.geom, 8) OVER(PARTITION BY polys.poly_id)
ELSE ST_ClusterKMeans(pts.geom, 2) OVER(PARTITION BY polys.poly_id)
END AS cluster_id,
pts.geom
FROM polys,
LATERAL ST_Dump(ST_GeneratePoints(polys.geom, 1000, 1)) AS pts
;
-- Create centroids from point clusters, making sure all centroids are within a polygon
CREATE TABLE centroids AS
SELECT cluster_id, ST_PointOnSurface(ST_collect(geom)) AS geom
FROM pnt_clusters
GROUP BY poly_id, cluster_id;
The "C" shaped polygon on the left contains centroids that are too close to the polygon boundary for my needs. Based on feedback, there seem to be two approaches to handle this situation:
Generate a negative buffer of the polygons and generate the centroids within those negative buffer areas.
Snap the centroids that are within 0.4 units of the original polygon boundary to the closest location on a negative buffer boundary
Option 1 will not work because the density of the point cluster centroids will be too biased toward the center of the polygons. For example, if I generated point cluster centroids within the green negative buffer region, you can imagine the points would be biased too far toward the center of the original forest stand (blue) polygons:
How can I snap the point cluster centroids (red points) that are within 0.4 units of their polygon boundary (blue polygons) to the closest location on the negative buffer polygon boundary (green polygon)?
1000 * ST_Area(<negative_buffer>) / ST_Area(<original_polygon>)
. – geozelot Oct 27 '20 at 9:30