# Convert polygon with filled region inside hole into multiple polygons

Suppose you have a polygon with an inner ring representing a hole, and inside that hole is another inner ring (an "island"):

The above shape can be generated using:

``````SELECT
ST_MakePolygon(
ST_ExteriorRing(ST_Buffer(center, 10, 10)),
ARRAY[
ST_ExteriorRing(ST_Buffer(center, 6, 6)),
ST_ExteriorRing(ST_Buffer(center, 3, 3))
]
) AS geom
FROM ST_MakePoint(0, 0) AS center;
``````

While this can be represented as a single polygon, I have a requirement to convert this into multiple polygons. I am working with a library that supports polygons with holes, but does not support "islands" inside those holes - thus, I need to be able to extract those islands into separate polygons. And in case those islands also have holes that have even more "inner" islands - I need to be able to be able to extract those inner islands as well, such that no polygon in the result set contains "islands". Multiple holes (inner rings) are allowed - just no islands inside any of those holes (no inner ring wholly contained inside another inner ring).

How can I achieve this using PostGIS?

Also just to expand my knowledge... is there a more precise terminology I can use instead of "island"? I'm aware of "inner ring", but an inner ring can represent either a hole, or an "island" inside a hole. Just wondering if there is a more specific term for when an inner ring represents an island vs a hole.

They are two holes. Since they overlaps, the geometry is not valid.

``````SELECT ST_MakeValid(
(SELECT
ST_MakePolygon(
ST_ExteriorRing(ST_Buffer(center, 10, 10)),
ARRAY[
ST_ExteriorRing(ST_Buffer(center, 6, 6)),
ST_ExteriorRing(ST_Buffer(center, 3, 3))
]
) AS geom
FROM ST_MakePoint(0, 0) AS center
)
);
``````

Returns a multipolygon, one part with the exterior and the hole, and other part with the island ("nested hole" can be a more precise term).

• Thank you, I believe this is the more concise answer, though both were helpful. I didn't realize the example I had was technically not a valid geometry (inner rings cannot overlap), and so it's not a case I actually need to worry about for my application. And it's good to know about `ST_MakeValid` in case I do run across something that looks like that in my data. – Sergey K Feb 24 at 19:08

I'm not sure if I understood your question correctly, but judging by the picture, my answer is the following,

1. create three buffer zones of different radius from a point, for example, using part of your script

``````create table buffers1 as
SELECT
ST_Buffer(center, 3, 3) AS geom
FROM ST_MakePoint(0, 0) AS center;
``````
2. cut out a smaller one of your choice

``````CREATE TABLE Buffers32 AS
SELECT ST_Difference(a.geom, b.geom) AS geom
FROM Buffers3 a,
Buffers2 b
``````

Leave buffer 1, and the difference is buffer3 - buffer2, see figure

...

2 method Gabriel De Luca-Cyril what you need : -)...

``````SELECT (ST_Dump(ST_MakeValid(
(SELECT
ST_MakePolygon(
ST_ExteriorRing(ST_Buffer(center, 10, 10)),
ARRAY[
ST_ExteriorRing(ST_Buffer(center, 6, 6)),
ST_ExteriorRing(ST_Buffer(center, 3, 3))
]
))))).geom
FROM ST_MakePoint(0, 0) AS center;
``````