Name

ST_MakePolygon — Creates a Polygon from a shell and optional list of holes.

Synopsis

geometry ST_MakePolygon(geometry linestring);

geometry ST_MakePolygon(geometry outerlinestring, geometry[] interiorlinestrings);

Description

Creates a Polygon formed by the given shell and optional array of holes. Input geometries must be closed LineStrings (rings).

Variant 1: Accepts one shell LineString.

Variant 2: Accepts a shell LineString and an array of inner (hole) LineStrings. A geometry array can be constructed using the PostgreSQL array_agg(), ARRAY[] or ARRAY() constructs.

[Note]

This function does not accept MultiLineStrings. Use ST_LineMerge to generate a LineString, or ST_Dump to extract LineStrings.

This function supports 3d and will not drop the z-index.

Examples: Single input variant

Create a Polygon from a 2D LineString.

SELECT ST_MakePolygon( ST_GeomFromText('LINESTRING(75 29,77 29,77 29, 75 29)'));

Create a Polygon from an open LineString, using ST_StartPoint and ST_AddPoint to close it.

SELECT ST_MakePolygon( ST_AddPoint(foo.open_line, ST_StartPoint(foo.open_line)) )
FROM (
  SELECT ST_GeomFromText('LINESTRING(75 29,77 29,77 29, 75 29)') As open_line) As foo;

Create a Polygon from a 3D LineString

SELECT ST_AsEWKT( ST_MakePolygon( 'LINESTRING(75.15 29.53 1,77 29 1,77.6 29.5 1, 75.15 29.53 1)'));

st_asewkt
-----------
POLYGON((75.15 29.53 1,77 29 1,77.6 29.5 1,75.15 29.53 1))

Create a Polygon from a LineString with measures

SELECT ST_AsEWKT( ST_MakePolygon( 'LINESTRINGM(75.15 29.53 1,77 29 1,77.6 29.5 2, 75.15 29.53 2)' ));

st_asewkt
----------
POLYGONM((75.15 29.53 1,77 29 1,77.6 29.5 2,75.15 29.53 2))

Examples: Outer shell with inner holes variant

Create a donut Polygon with an extra hole

SELECT ST_MakePolygon( ST_ExteriorRing( ST_Buffer(ring.line,10)),
	ARRAY[  ST_Translate(ring.line, 1, 1),
		ST_ExteriorRing(ST_Buffer(ST_MakePoint(20,20),1)) ]
	)
FROM (SELECT ST_ExteriorRing(
	ST_Buffer(ST_MakePoint(10,10),10,10)) AS line ) AS ring;

Create a set of province boundaries with holes representing lakes. The input is a table of province Polygons/MultiPolygons and a table of water linestrings. Using a LEFT JOIN ensures all provinces are included even if they have no lakes.

[Note]

The CASE construct is used because passing a null array into ST_MakePolygon results in a NULL return value.

	SELECT p.gid, p.province_name,
		CASE WHEN array_agg(w.the_geom) IS NULL
		THEN p.the_geom
		ELSE  ST_MakePolygon( ST_LineMerge(ST_Boundary(p.the_geom)), array_agg(w.the_geom)) END
	FROM
		provinces p LEFT JOIN waterlines w
			ON (ST_Within(w.the_geom, p.the_geom) AND ST_IsClosed(w.the_geom))
	GROUP BY p.gid, p.province_name, p.the_geom;

Another technique is to utilize a correlated subquery and the ARRAY() constructor that converts a row set to an array.

	SELECT p.gid,  p.province_name,
		CASE WHEN EXISTS( SELECT w.the_geom
			FROM waterlines w
			WHERE ST_Within(w.the_geom, p.the_geom)
			AND ST_IsClosed(w.the_geom))
		THEN ST_MakePolygon(
			ST_LineMerge(ST_Boundary(p.the_geom)),
			ARRAY( SELECT w.the_geom
				FROM waterlines w
				WHERE ST_Within(w.the_geom, p.the_geom)
				AND ST_IsClosed(w.the_geom)))
		ELSE p.the_geom
		END AS the_geom
	FROM provinces p;

See Also

ST_Boundary, ST_AddPoint, ST_IsClosed, ST_LineMerge, ST_StartPoint, ST_BuildArea