4

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

Polygon with filled region inside hole

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.

4

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
4

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

enter image description here...

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; 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.