Discussion:
Creating a simple polygon encompassing a given number of points
René Fournier
2012-09-10 18:39:12 UTC
Permalink
I've written a script to migrate location data from MySQL to PostGIS.
Each region contains 5-20 locations. I would like my script to create a simple polygon for each region that encompasses its locations (lat/lng points). I say simple in the sense of not too many vertices (< 10), even if the region contains 20 points.(The easiest thing would be a bounding box, but I would like it a bit more defined than that.) Additionally, I would like the polygon to be a bit bigger (say, by 10 meters) than the points it contains.

Just wondering if this is something that can be done in a PostGIS query or PHP using some algorithm for simple. What would you recommend? Thanks!

...Rene
Nicolas Ribot
2012-09-10 18:46:37 UTC
Permalink
Hi,

You could use st_convexHull on the point set and then buffer it with st_buffer.
(st_concaveHull may give you better results on polygon approximation
(see: http://postgis.refractions.net/documentation/manual-2.0/ST_ConcaveHull.html)

Nicolas
Post by René Fournier
I've written a script to migrate location data from MySQL to PostGIS.
Each region contains 5-20 locations. I would like my script to create a simple polygon for each region that encompasses its locations (lat/lng points). I say simple in the sense of not too many vertices (< 10), even if the region contains 20 points.(The easiest thing would be a bounding box, but I would like it a bit more defined than that.) Additionally, I would like the polygon to be a bit bigger (say, by 10 meters) than the points it contains.
Just wondering if this is something that can be done in a PostGIS query or PHP using some algorithm for simple. What would you recommend? Thanks!
...Rene
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
René Fournier
2012-09-11 01:44:11 UTC
Permalink
Thanks Nicolas,

I've gotten a bit farther. Stuck again though. This works:

SELECT ST_AsText(ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455 -111.868842, 50.569992 -111.898634, 50.583764 -111.907919, 50.569452 -111.868859)') ) ));
st_astext
--------------------------------------------------------------------------------------------------------------------------
POLYGON((50.583764 -111.907919,50.569992 -111.898634,50.569452 -111.868859,50.569455 -111.868842,50.583764 -111.907919))

But for some reason, I can't update:

UPDATE territories SET border = ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455 -111.868842, 50.569992 -111.898634, 50.583764 -111.907919, 50.569452 -111.868859)') ) ) WHERE id = 3014;
ERROR: cannot use aggregate function in UPDATE
LINE 1: UPDATE territories SET border = ST_ConvexHull(ST_Collect(ST_...

Any ideas? I'm new to these functions.. Ultimately, I want to update territory with a set of points from a SELECT, e.g.:

SELECT location FROM addresses WHERE territory_id = 3014;

Table "public.addresses"
Column | Type | Modifiers | Storage | Description
-----------------+--------------------------+--------------------------------------------------------+----------+-------------
id | integer | not null default nextval('addresses_id_seq'::regclass) | plain |
territory_id | integer | not null | plain |
location | geography(Point,4326) | | main |
Post by Nicolas Ribot
Hi,
You could use st_convexHull on the point set and then buffer it with st_buffer.
(st_concaveHull may give you better results on polygon approximation
(see: http://postgis.refractions.net/documentation/manual-2.0/ST_ConcaveHull.html)
Nicolas
Post by René Fournier
I've written a script to migrate location data from MySQL to PostGIS.
Each region contains 5-20 locations. I would like my script to create a simple polygon for each region that encompasses its locations (lat/lng points). I say simple in the sense of not too many vertices (< 10), even if the region contains 20 points.(The easiest thing would be a bounding box, but I would like it a bit more defined than that.) Additionally, I would like the polygon to be a bit bigger (say, by 10 meters) than the points it contains.
Just wondering if this is something that can be done in a PostGIS query or PHP using some algorithm for simple. What would you recommend? Thanks!
...Rene
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
Paolo Corti
2012-09-11 07:18:58 UTC
Permalink
Post by René Fournier
Thanks Nicolas,
UPDATE territories SET border =
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455 -111.868842,
50.569992 -111.898634, 50.583764 -111.907919, 50.569452 -111.868859)') ) )
WHERE id = 3014;
ERROR: cannot use aggregate function in UPDATE
LINE 1: UPDATE territories SET border = ST_ConvexHull(ST_Collect(ST_...
Using a sub-select should work:

UPDATE territories SET border = (SELECT
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455
-111.868842, 50.569992 -111.898634, 50.583764 -111.907919, 50.569452
-111.868859)') ) ))
WHERE id = 3014;

regards
p
--
Paolo Corti
Geospatial software developer
web: http://www.paolocorti.net
twitter: @capooti
skype: capooti
René Fournier
2012-09-12 15:42:56 UTC
Permalink
Yes, this works great.

UPDATE territories SET border = (SELECT ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(-111.868842 50.569455, -111.898634 50.569992, -111.907919 50.583764, -111.868859 50.569452)') ) )) WHERE id = 3014;

Now... I'm trying to figure out, how to do the same, except create the border (polygon) from points in another table, e.g.:

UPDATE territories SET border = (SELECT ST_ConvexHull(ST_Collect(
SELECT location FROM addresses WHERE territory_id = 3014
))) WHERE id = 3014;

...returns "ERROR: function st_collect(geography) does not exist HINT: No function matches the given name and argument types. You might need to add explicit type casts."

So I'm wondering, since both border (final polygon) and location (source of points) are of type geography, what's the best way to go about this? Or should I have just used geometry types? Sorry for the dumb questions, I'm trying to define the schemas by best practices so I don't have to fix them later. Geography seemed right when I started the project.
Post by Paolo Corti
Post by René Fournier
Thanks Nicolas,
UPDATE territories SET border =
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455 -111.868842,
50.569992 -111.898634, 50.583764 -111.907919, 50.569452 -111.868859)') ) )
WHERE id = 3014;
ERROR: cannot use aggregate function in UPDATE
LINE 1: UPDATE territories SET border = ST_ConvexHull(ST_Collect(ST_...
UPDATE territories SET border = (SELECT
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455
-111.868842, 50.569992 -111.898634, 50.583764 -111.907919, 50.569452
-111.868859)') ) ))
WHERE id = 3014;
regards
p
--
Paolo Corti
Geospatial software developer
web: http://www.paolocorti.net
skype: capooti
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
Sandro Santilli
2012-09-12 16:04:22 UTC
Permalink
Post by René Fournier
Yes, this works great.
UPDATE territories SET border = (SELECT ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(-111.868842 50.569455, -111.898634 50.569992, -111.907919 50.583764, -111.868859 50.569452)') ) )) WHERE id = 3014;
UPDATE territories SET border = (SELECT ST_ConvexHull(ST_Collect(
SELECT location FROM addresses WHERE territory_id = 3014
))) WHERE id = 3014;
...returns "ERROR: function st_collect(geography) does not exist HINT: No function matches the given name and argument types. You might need to add explicit type casts."
So I'm wondering, since both border (final polygon) and location (source of points) are of type geography, what's the best way to go about this? Or should I have just used geometry types? Sorry for the dumb questions, I'm trying to define the schemas by best practices so I don't have to fix them later. Geography seemed right when I started the project.
Collecting a geography seems so easy, dunno why it's not supported.
Anyway you can cast your geographies to geometry for the sake of computation
and then cast back to geography.

I just hope none of your territories cross the dateline

--strk;
Nicolas Ribot
2012-09-12 16:04:55 UTC
Permalink
Hi,

I think you could cast geography to geometry to collect, then cast
back to geography to store ?
Post by René Fournier
Yes, this works great.
UPDATE territories SET border = (SELECT
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(-111.868842 50.569455,
-111.898634 50.569992, -111.907919 50.583764, -111.868859 50.569452)') ) ))
WHERE id = 3014;
Now... I'm trying to figure out, how to do the same, except create the
UPDATE territories SET border = (SELECT ST_ConvexHull(ST_Collect( SELECT
location FROM addresses WHERE territory_id = 3014 ))) WHERE id = 3014;
...returns "ERROR: function st_collect(geography) does not exist HINT: No
function matches the given name and argument types. You might need to add
explicit type casts."
So I'm wondering, since both border (final polygon) and location (source of
points) are of type geography, what's the best way to go about this? Or
should I have just used geometry types? Sorry for the dumb questions, I'm
trying to define the schemas by best practices so I don't have to fix them
later. Geography seemed right when I started the project.
Thanks Nicolas,
UPDATE territories SET border =
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455 -111.868842,
50.569992 -111.898634, 50.583764 -111.907919, 50.569452 -111.868859)') ) )
WHERE id = 3014;
ERROR: cannot use aggregate function in UPDATE
LINE 1: UPDATE territories SET border = ST_ConvexHull(ST_Collect(ST_...
UPDATE territories SET border = (SELECT
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455
-111.868842, 50.569992 -111.898634, 50.583764 -111.907919, 50.569452
-111.868859)') ) ))
WHERE id = 3014;
regards
p
--
Paolo Corti
Geospatial software developer
web: http://www.paolocorti.net
skype: capooti
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
René Fournier
2012-09-12 18:31:12 UTC
Permalink
Yes, casting to/from did the trick:

UPDATE territories SET border = (
SELECT ST_ConvexHull(ST_Collect(location::geometry)) FROM addresses WHERE territory_id = 3014
)::geography WHERE id = 3014;

Now, is it possible process all territory borders with one query? For example, this works for a single territory:

UPDATE territories SET border = (
SELECT ST_ConvexHull(ST_Collect(addresses.location::geometry)) FROM addresses WHERE addresses.territory_id = territories.id
)::geography WHERE id = 3014;
UPDATE 1

But if I leave out the WHERE clause, it doesn't:

UPDATE territories SET border = (
SELECT ST_ConvexHull(ST_Collect(addresses.location::geometry)) FROM addresses WHERE addresses.territory_id = territories.id
)::geography;
ERROR: Geometry type (LineString) does not match column type (Polygon)

Just wondering, is this kind of update query with a subselect possible?
Post by Nicolas Ribot
Hi,
I think you could cast geography to geometry to collect, then cast
back to geography to store ?
Post by René Fournier
Yes, this works great.
UPDATE territories SET border = (SELECT
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(-111.868842 50.569455,
-111.898634 50.569992, -111.907919 50.583764, -111.868859 50.569452)') ) ))
WHERE id = 3014;
Now... I'm trying to figure out, how to do the same, except create the
UPDATE territories SET border = (SELECT ST_ConvexHull(ST_Collect( SELECT
location FROM addresses WHERE territory_id = 3014 ))) WHERE id = 3014;
...returns "ERROR: function st_collect(geography) does not exist HINT: No
function matches the given name and argument types. You might need to add
explicit type casts."
So I'm wondering, since both border (final polygon) and location (source of
points) are of type geography, what's the best way to go about this? Or
should I have just used geometry types? Sorry for the dumb questions, I'm
trying to define the schemas by best practices so I don't have to fix them
later. Geography seemed right when I started the project.
Thanks Nicolas,
UPDATE territories SET border =
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455 -111.868842,
50.569992 -111.898634, 50.583764 -111.907919, 50.569452 -111.868859)') ) )
WHERE id = 3014;
ERROR: cannot use aggregate function in UPDATE
LINE 1: UPDATE territories SET border = ST_ConvexHull(ST_Collect(ST_...
UPDATE territories SET border = (SELECT
ST_ConvexHull(ST_Collect(ST_GeomFromText('MULTIPOINT(50.569455
-111.868842, 50.569992 -111.898634, 50.583764 -111.907919, 50.569452
-111.868859)') ) ))
WHERE id = 3014;
regards
p
--
Paolo Corti
Geospatial software developer
web: http://www.paolocorti.net
skype: capooti
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
_______________________________________________
postgis-users mailing list
http://postgis.refractions.net/mailman/listinfo/postgis-users
p***@pcreso.com
2012-09-10 22:16:56 UTC
Permalink
Hi Rene,

Perhaps something like this?

select region, ST_simplify(ST_buffer(ST_convexhull(ST_collect(geom), n),n/3)) from table group by region;


ST_simplify removes extraneous vertices - increase the n/3 parameter to remove more vertices, but you'll also need to increase n to ensure all the points lie within the simplified polygon - you don't have to use n/3, just a value off the top of my head

ST_buffer will create a new polygon distance n outside the original one

ST_convexhull will create a polygon encompassing the points. ST_concavehull might also work, but I've found it problematic.

ST_collect will create a group of points to work with

all grouped by region.



HTH,

   Brent Wood


--- On Tue, 9/11/12, René Fournier <***@renefournier.com> wrote:

From: René Fournier <***@renefournier.com>
Subject: [postgis-users] Creating a simple polygon encompassing a given number of points
To: "PostGIS Users Discussion" <postgis-***@postgis.refractions.net>
Date: Tuesday, September 11, 2012, 6:39 AM

I've written a script to migrate location data from MySQL to PostGIS.
Each region contains 5-20 locations. I would like my script to create a simple polygon for each region that encompasses its locations (lat/lng points). I say simple in the sense of not too many vertices (< 10), even if the region contains 20 points.(The easiest thing would be a bounding box, but I would like it a bit more defined than that.)  Additionally, I would like the polygon to be a bit bigger (say, by 10 meters) than the points it contains.

Just wondering if this is something that can be done in a PostGIS query or PHP using some algorithm for simple. What would you recommend? Thanks!

...Rene
Continue reading on narkive:
Loading...