Home > Software design >  SQL Server Spatial approach to merging sets of overlapping polygons
SQL Server Spatial approach to merging sets of overlapping polygons

Time:05-14

We have a need to merge sets of overlapping geometry polygons. Usually easy enough in desktop GIS using Dissolve or similar functions. However we have >10 million polygons to test and desktop GIS is not coping - not a surprise.

So I'm attempting this in SQL Server which I've used for intersection analysis for intersection analysis of similar numbers of polygons and lines, but I'm stumped on this.

With the following test data of 9 squares I would expect a result of 5 merged squares, 2 merged squares and two single adjacent squares unmerged.

CREATE TABLE [dbo].[TestPolygons](
        [OBJECTID] [int] IDENTITY(1,1) NOT NULL,
        [GeomPoly] [geometry] NULL,
     CONSTRAINT [PK_TestPolygons] PRIMARY KEY CLUSTERED 
    (
        [OBJECTID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO

    -- Overlapping pair   
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((0 0, 40 0, 40 40, 0 40, 0 0))',27700));
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((30 30, 70 30, 70 70, 30 70, 30 30))',27700));

    -- no overlapping, just adjacent
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((120 0, 160 0, 160 40, 120 40, 120 0))',27700));
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((160 40, 200 40, 200 80, 160 80, 160 40))',27700));

    -- additional overlaps
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((60 60, 100 60, 100 100, 60 100, 60 60))',27700));
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((90 90, 130 90, 130 130, 90 130, 90 90))',27700));
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((60 0, 100 0, 100 40, 60 40, 60 0))',27700));

    -- overlapping pair
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((220 0, 260 0, 260 40, 220 40, 220 0))',27700));
    insert into dbo.TestPolygons (GeomPoly) values (geometry::STGeomFromText('POLYGON ((250 30, 290 30, 290 70, 250 70, 250 30))',27700));

enter image description here

I've got as far as merging everything into one record of two polygons, but this has dropped the unmerged records. This is the code;

select geometry::UnionAggregate(inter_geometry) as intersection_union
from
(
    select P.objectid as id1, T.objectid as id2, P.GeomPoly.STUnion(T.GeomPoly) as inter_geometry
    from dbo.TestPolygons P
    inner join dbo.TestPolygons T on P.objectid < T.objectid
    where P.GeomPoly.STOverlaps(T.GeomPoly) = 1
) N

enter image description here Hopefully someone can help - I've found StackOverflow very useful in the past, but this is my first question.

Adrian

CodePudding user response:

The result I'm after for the test data is four records; 1 record of a merged set of the five squares that serially overlap, 1 record of a merged set of the two overlapping squares, 2 records each of a single square.

Cool. UnionAggregate does all the hard work for you knitting the shapes together into a single multipolygon. Then you just have to enumerate the geometries that make it up, something like this:

with q as
(
    select geometry::UnionAggregate(GeomPoly) g
    from TestPolygons
), n as
(
  select top 10000 row_number() over (order by (select null)) i
  from (values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10))       v1(i)

) 
select q.g.STGeometryN(n.i) 
from q
cross apply (select i from n where i <= q.g.STNumGeometries())  n

which outputs four rows:

enter image description here

  • Related