TransWikia.com

Creating precise shapes using list of coordinates?

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
        ) );

2 Answers

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:

  • Compute the centroid of the set of points
  • For each point in the set, compute the azimuth (angle) from the centroid to the point
  • Join up the points in order of the azimuth and create a polygon from them

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:

enter image description here

(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 enter image description here

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

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP