[postgis-users] Re: computing unions of intersecting polygons
Martin Davis
mbdavis at refractions.net
Wed Jan 14 16:32:31 PST 2009
Beauty, eh!
Reid Priedhorsky wrote:
> On 01/13/2009 11:44 AM, Martin Davis wrote:
> >
>> The way I'd look at doing this is to compute a relation which
>> contains pairs (poly_id1, poly_id2) for all polygons which
>> intersect. Then compute the transitive closure of this relation to
>> find all connected sets of polygons. (Until the recursive CTE
>> support emerges in PostgresQL 8.4, you'll probably need to do this
>> procedurally in pgplsql). Label each group with the smallest id in
>> that group. Then you can use an aggregate query over the transitive
>> closure table to compute unions and counts.
>
> Thanks, Martin!
>
> I ended up doing it procedurally, though without the intermediate
> table you suggest, because in our case it was OK to muck with the
> table itself (wh_raw) to keep track of progress!
>
> Below is my solution! It runs in about 2 minutes, compared to the
> st_union solution which takes about 6.5 hours!
>
> Thanks,
>
> Reid
>
>
>> /* This function compacts the table wh_raw by the transitive closure
>> over
>> intersection: for each set of polygons in wh_raw that intersect on
>> another
>> (transitively), remove each member of that set and insert the
>> union! This
>> solution is procedural to work around PostGIS's limitations on this
>> operation! */
>> create function my_union() returns void
>> as $$
>> declare
>> id_i int;
>> count_i int;
>> geometry_i geometry;
>> count_u int;
>> union_u geometry;
>> begin
>> loop
>> -- Fetch row from the table which is not done!
>> select id, count_, geometry
>> into id_i, count_i, geometry_i
>> from wh_raw where not done limit 1;
>> -- If no such rows, algorithm is complete!
>> exit when not found;
>> -- Fetch the union of all rows that intersect that row!
>> select sum(count_),
>> ST_MakePolygon(ST_ExteriorRing(ST_Union(geometry)))
>> into count_u, union_u
>> from wh_raw
>> where not done and ST_Intersects(geometry_i, geometry);
>> if (count_i = count_u) then
>> -- There's only one; we're done with that set!
>> update wh_raw set done = True where id = id_i;
>> else
>> -- Update the initial row with the union and remove others!
>> update wh_raw
>> set count_ = count_u, geometry = union_u
>> where id = id_i;
>> delete from wh_raw
>> where id != id_i and ST_Intersects(geometry_i, geometry);
>> end if;
>> end loop;
>> end;
>> $$ language plpgsql;
>>
>> select my_union();
>> drop function my_union();
>>
>> \qecho -- (sanity check: this should give no results!)
>> select a.id, b.id
>> from wh_raw a join wh_raw b on (a.id != b.id
>> and ST_Intersects(a.geometry,
>> b.geometry));
>
>
> _______________________________________________
> postgis-users mailing list
> postgis-users at postgis.refractions.net
> http://postgis.refractions.net/mailman/listinfo/postgis-users
>
--
Martin Davis
Senior Technical Architect
Refractions Research, Inc.
(250) 383-3022
More information about the postgis-users
mailing list