Geographic Information Systems Asked on August 2, 2021
I am using st_concavehull
to create boundaries/shapes. This works, however, the shape is not precisely tracing the coordinates. It is more puffy, as if trying to even out or “clean up” the actual shape.
How can I create a more cleaner/neater boundary? I’ve tried numbers from -1 to 1 and nothing seems to produce the actual shape I’m expecting; they all have curved edges and “cover” the coordinates instead of tracing them.
Example/My Code:
st_concavehull(
st_collect(array[
st_transform(st_setsrid(st_makepoint(-97.5660461, 30.4894905), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5657216, 30.4902173), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5608779, 30.4896142), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5605001, 30.491422), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5588115, 30.4911697), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5588262, 30.4910204), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5585742, 30.4909966), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5578045, 30.4909263), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5574653, 30.4908877), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5571534, 30.4908375), 4326),4269),
st_transform(st_setsrid(st_makepoint(-97.5560964, 30.4907427), 4326),4269),
...
]), -0.15) as polygon
) concavehull
) );
One way to produce a polygon which uses all points in a set is to create a star polygon around the centroid of the points. Whether this produces an acceptable result depends on the positions of the points. But in this case it seems like this will do exactly what is required.
The algorithm is simple:
Here's sample code to do this for the data given:
WITH pts(pt) AS (VALUES
(st_transform(st_setsrid(st_makepoint(-97.5660461, 30.4894905), 4326),4269) ),
(st_transform(st_setsrid(st_makepoint(-97.5657216, 30.4902173), 4326),4269) ),
(st_transform(st_setsrid(st_makepoint(-97.5608779, 30.4896142), 4326),4269) ),
(st_transform(st_setsrid(st_makepoint(-97.5605001, 30.491422), 4326),4269) ),
(st_transform(st_setsrid(st_makepoint(-97.5588115, 30.4911697), 4326),4269) ),
(st_transform(st_setsrid(st_makepoint(-97.5588262, 30.4910204), 4326),4269) ),
(st_transform(st_setsrid(st_makepoint(-97.5588262, 30.4910204), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5585742, 30.4909966), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5578045, 30.4909263), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5574653, 30.4908877), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5571534, 30.4908375), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5560964, 30.4907427), 4326),4269))
),
centroid AS (SELECT ST_Centroid( ST_Collect(pt) ) AS centroid FROM pts),
line AS (SELECT ST_MakeLine( pt ORDER BY ST_Azimuth( centroid, pt ) ) AS geom
FROM pts CROSS JOIN centroid),
poly AS (SELECT ST_MakePolygon( ST_AddPoint( geom, ST_StartPoint( geom ))) AS geom
FROM line)
SELECT geom FROM poly;
and here is the result:
(This would make a nice function for PostGIS, either built-in or as a community contribution in PL/pgSQL)
CREATE OR REPLACE FUNCTION ST_PointsInStarPolygon(
geom GEOMETRY
)
RETURNS GEOMETRY AS
$BODY$
WITH
pts(geom) AS (SELECT (ST_DumpPoints(geom)).geom geom),
centroid AS (SELECT ST_Centroid(ST_Collect(geom)) AS centroid FROM pts),
line AS (SELECT ST_MakeLine(geom ORDER BY ST_Azimuth(centroid, geom)) AS geom
FROM pts CROSS JOIN centroid),
poly AS (SELECT ST_MakePolygon(ST_AddPoint(geom, ST_StartPoint(geom))) AS geom
FROM line)
SELECT geom FROM poly;
$BODY$
LANGUAGE SQL
Run:
SELECT ST_PointsInStarPolygon(geom) geom FROM (SELECT ST_Collect(geom) AS geom FROM pts) a;
Answered by dr_jts on August 2, 2021
Here's another simple, customizable geoinstrument:
Run Postgre/PostGIS SQL in PGAdmin:
WITH pts(geom) AS (VALUES
(st_transform(st_setsrid(st_makepoint(-97.5660461, 30.4894905), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5657216, 30.4902173), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5608779, 30.4896142), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5605001, 30.491422), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5588115, 30.4911697), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5588262, 30.4910204), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5588262, 30.4910204), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5585742, 30.4909966), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5578045, 30.4909263), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5574653, 30.4908877), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5571534, 30.4908375), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5560964, 30.4907427), 4326),4269))),
tbla AS (SELECT ST_Centroid(ST_Collect(geom)) geom FROM pts),
tblb AS (SELECT geom FROM pts UNION SELECT geom FROM tbla),
tblc AS (SELECT ST_MakeLine(a.geom, b.geom) geom FROM tbla a CROSS JOIN pts b),
tbld AS (SELECT ST_Union(ST_Buffer(ST_MakeLine(ST_LineInterpolatePoint(a.geom, 0.9), b.geom),0.00001)) geom FROM tblc a CROSS JOIN tbla b),
tble AS (SELECT ((ST_Dump(ST_DelaunayTriangles(ST_Collect(geom)))).geom) geom FROM tblb)
SELECT ST_Union(a.geom) geom FROM tble a JOIN tbld b ON ST_Intersects(a.geom, b.geom);
See the figure below for the result
Original solutions.
The script is called: ST_PointsInStarPolygonFromDelaunayTriangles
Memo: As long as there is no universal geoinstrument that solves any geometric problems, the geo-space is much more complicated ?...
OR
WITH pts(geom) AS (VALUES
(st_transform(st_setsrid(st_makepoint(-97.5660461, 30.4894905), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5657216, 30.4902173), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5608779, 30.4896142), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5605001, 30.491422), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5588115, 30.4911697), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5588262, 30.4910204), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5588262, 30.4910204), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5585742, 30.4909966), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5578045, 30.4909263), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5574653, 30.4908877), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5571534, 30.4908375), 4326),4269)),
(st_transform(st_setsrid(st_makepoint(-97.5560964, 30.4907427), 4326),4269))),
tbla AS (SELECT ST_Centroid(ST_Collect(geom)) geom FROM pts),
tblb AS (SELECT ST_MakeLine(a.geom, b.geom) geom FROM tbla a CROSS JOIN pts b),
tblc AS (SELECT ST_Union(ST_Buffer(ST_MakeLine(ST_LineInterpolatePoint(a.geom, 0.9), b.geom),0.00001)) geom FROM tblb a CROSS JOIN tbla b),
tbld AS (SELECT ((ST_Dump(ST_DelaunayTriangles(ST_Collect(geom)))).geom) geom FROM pts)
SELECT ST_Union(a.geom) geom FROM tbld a JOIN tblc b ON ST_Intersects(a.geom, b.geom);
for your geodata set, the function will look like this:
CREATE OR REPLACE FUNCTION ST_PointsInStarPolygonFromDelaunayTriangles(
geom GEOMETRY
)
RETURNS GEOMETRY AS
$BODY$
WITH
tbla AS (SELECT (ST_DumpPoints(geom)).geom geom),
tblb AS (SELECT ST_Centroid(ST_Collect(geom)) geom FROM tbla),
tblc AS (SELECT geom FROM tbla UNION SELECT geom FROM tblb),
tbld AS (SELECT ST_MakeLine(a.geom, b.geom) geom FROM tblb a CROSS JOIN tbla b),
tble AS (SELECT ST_Union(ST_Buffer(ST_MakeLine(ST_LineInterpolatePoint(a.geom, 0.9), b.geom),0.00001)) geom FROM tbld a CROSS JOIN tblb b),
tblf AS (SELECT ((ST_Dump(ST_DelaunayTriangles(ST_Collect(geom)))).geom) geom FROM tblc)
SELECT ST_Union(a.geom) geom FROM tblf a JOIN tble b ON ST_Intersects(a.geom, b.geom)
$BODY$
LANGUAGE SQL
Run:
SELECT ST_PointsInStarPolygonFromDelaunayTriangles(geom) geom FROM (SELECT ST_Collect(geom) AS geom FROM pts) a;
Answered by Cyril Mikhalchenko on August 2, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP