wiki:UsersWikiSplitPolygonWithLineString

Note: As of PostGIS 2.0, ST_Split returns a collection of geometries resulting by splitting a geometry.

Split Polygon With Line String

This example demonstrates how to Split a Polygon into multiple polygons using a Line.

James asks:

I think the steps below will work but I have one question. I am creating an application that allows a user to split a polygon by drawing a linestring across the polygon they wish to change. The crossing linestring has parts that are outside the polygon and I want to remove that before I geomunion. What's the easiest way to do that?

  • extract the lines that make up the polygon
  • add to this your crossing linestring
  • geomunion the lines together.
  • polygonize the union-ed set

Thanks,

Jim

--THE BELOW solution may not work with holes ---

Kevin answers:

Here's an example splitting a polygon with a line. Note that the dangling cutlines outside the polygon are quietly dropped.

SELECT ST_AsText(geom )
FROM ST_Dump ((

SELECT ST_Polygonize(ST_Union(ST_Boundary(poly), line)) AS mpoly
FROM
   (SELECT 'POLYGON ((1 1, 1 3, 3 3, 3 1, 1 1 ))'::geometry AS poly) AS a,
   (SELECT 'LINESTRING (0 2, 4 2)'::geometry AS line) AS b

));

Result:

              st_astext
--------------------------------
  POLYGON((1 1,1 2,3 2,3 1,1 1))
  POLYGON((1 2,1 3,3 3,3 2,1 2))
(2 rows)

Cheers, Kevin

Regina asks:

This doesn't work with holes does it?

Kevin answers

Things would get a little bit more complicated when holes are involved, but I don't think overly so.

The polygonizer builds polygons from all linework - this includes building polygons for what should be holes. What you would need to do as a post-process is remove all polygons that don't belong. (In the following example, I use contains and pointonsurface to determine which polygons I should exclude from the final result.

Here is another sample polygon splitting, this time the polygon has two holes where one is intersected by the splitting line.

CREATE TABLE poly AS
   SELECT 'POLYGON (( 1 1, 1 7, 7 7, 7 1, 1 1 ),
                    ( 2 3, 4 3, 4 5, 2 5, 2 3 ),
                    ( 5 5, 6 5, 6 6, 5 6, 5 5 ))'::geometry AS geom;

CREATE TABLE line AS
   SELECT 'LINESTRING (0 4, 8 4)'::geometry AS geom;

CREATE TABLE split_polys AS
SELECT geom FROM ST_Dump ((
   SELECT polygonize(ST_Union(ST_Boundary(poly.geom), line.geom))
   FROM poly, line
));

DELETE FROM split_polys a
USING poly b
WHERE NOT ST_Contains(b.geom, ST_PointOnSurface(a.geom));

SELECT ST_AsText(geom) FROM split_polys;

Result:

                                 st_astext
----------------------------------------------------------------------
  POLYGON((1 1,1 4,2 4,2 3,4 3,4 4,7 4,7 1,1 1))
  POLYGON((1 4,1 7,7 7,7 4,4 4,4 5,2 5,2 4,1 4),(5 5,6 5,6 6,5 6,5 5))
(2 rows)

----------------------------------------------------------------------

You can also make mosaic from polygons from one table. When you have for example this table

CREATE TABLE geoms
(
  id serial NOT NULL,
  geom geometry,
  CONSTRAINT geoms_pkey PRIMARY KEY (id),
  CONSTRAINT enforce_dims_geom CHECK (ndims(geom) = 2),
  CONSTRAINT enforce_srid_geom CHECK (srid(geom) = (-1))
)
WITH (OIDS=FALSE);

This is the query that returns mosaic:

SELECT geom FROM (SELECT (ST_Dump(g)).geom as geom FROM (
	SELECT ST_Polygonize(g) as g FROM (
		SELECT ST_Union(ST_Boundary(geom)) as g FROM geoms
	) r
)t) a WHERE EXISTS (SELECT geom FROM geoms b WHERE ST_Contains(b.geom, ST_PointOnSurface(a.geom)));

Yo!Zik

Function: ST_SplitPolygon

A custom function can be used to split a [Multi]Polygon with a [Multi]LineString blade.

CREATE OR REPLACE FUNCTION ST_SplitPolygon(poly geometry, blade geometry) RETURNS geometry AS
'SELECT ST_Collect((d).geom)
FROM (SELECT ST_Dump(ST_Polygonize(ST_Union(ST_Boundary($1), $2))) AS d) f
WHERE ST_Area(ST_Intersection($1, (d).geom)) / ST_Area((d).geom) >= 1 - 1e-10;' LANGUAGE sql IMMUTABLE STRICT COST 100;

For example:

SELECT ST_AsText(ST_SplitPolygon(poly, blade)) AS result
FROM (
  SELECT 'POLYGON ((20 30, 100 180, 160 20, 20 30), (70 70, 92 105, 110 50, 70 70))'::geometry AS poly,
    'MULTILINESTRING ((150 90, 90 70, 60 20), (50 140, 90 70))'::geometry AS blade
) f;

           result
-----------------------------------------
MULTIPOLYGON(((20 30,64.8275862068966 114.051724137931,80.4761904761905 86.6666666666667,
  70 70,85.3846153846154 62.3076923076923,64.1095890410959 26.8493150684932,20 30)),
((64.8275862068966 114.051724137931,100 180,135.555555555556 85.1851851851852,
  102.131147540984 74.0437158469945,92 105,80.4761904761905 86.6666666666667,
  64.8275862068966 114.051724137931)),
((135.555555555556 85.1851851851852,160 20,64.1095890410959 26.8493150684932,
  85.3846153846154 62.3076923076923,110 50,102.131147540984 74.0437158469945,
  135.555555555556 85.1851851851852)))
Last modified 10 years ago Last modified on 04/06/15 17:27:32
Note: See TracWiki for help on using the wiki.