# Force a collection of unknown number of points to be a polygon

I am working with point clusters and want to create the rough shape of the cluster in the form of a polygon using ST_ConvexHull(). I'm having problems with single outliers though, as they don't convert to a polygon but to a POINT:

SELECT ST_AsText(ST_ConvexHull(ST_Collect(point))) ...

POLYGON((13.01741532 52.40118295,13.382100866593 52.516280103729, ...))
POINT(12.5 51.5)


Is there a way to force small geometries (single or double points) into a polygon? I want to simplify the subsequent processing by guaranteeing polygons; accuracy is not a high priority in this case, making a minimal triangle out of a single point is fine, even if not exact.

-
may be you could buffer them? –  iant Jun 26 '13 at 11:09
I suppose that's a way, but that may produce unnecessarily complex geometries. I'd be a lot happier with a minimal bounding triangle. :) –  deceze Jun 26 '13 at 11:33
A "minimal bounding triangle" would be a point or a line segment. @iant is correct: any solution would be a prima facie buffer so the only questions are what shape that buffer should have and how large it ought to be. –  whuber Jun 26 '13 at 13:34
OK, I guess buffering it is then. Anyone care to put this into an answer so I can accept it? :) –  deceze Jun 26 '13 at 14:12

ST_ConvexHull can return Points, Linestrings, or Polygons so you'll need to buffer anything that isn't a polygon. As @whuber states, the exact buffering is up to you. The following query illustrates the general idea.

WITH pts(pt, grp) AS (
VALUES
-- single point
(ST_MakePoint(1,1), 1),
-- two points
(ST_MakePoint(1,1), 2),
(ST_MakePoint(1,2), 2),
-- linear points - makes a linestring
(ST_MakePoint(1,1), 3),
(ST_MakePoint(1,2), 3),
(ST_MakePoint(1,3), 3),
-- expected case
(ST_MakePoint(1,1), 4),
(ST_MakePoint(1,2), 4),
(ST_MakePoint(2,1), 4)
), hulls AS (
SELECT ST_ConvexHull(ST_Collect(pt)) AS hull
FROM pts
GROUP BY grp
)
SELECT
ST_GeometryType(hull) AS hull_type,
ST_AsText(hull) AS hull,
ST_AsText(
CASE
WHEN ST_GeometryType(hull) = 'ST_Polygon' THEN hull
ELSE ST_Buffer(hull, 0.01)
END) AS always_polygon
FROM hulls;

-