diff --git a/src/pg/sql/11_cdb_union_adjacent.sql b/src/pg/sql/11_cdb_union_adjacent.sql new file mode 100644 index 0000000..e90bf28 --- /dev/null +++ b/src/pg/sql/11_cdb_union_adjacent.sql @@ -0,0 +1,43 @@ +CREATE OR REPLACE FUNCTION _cdb_final_union_adjacent( joined_geoms geometry[] ) +RETURNS geometry[] AS $$ +BEGIN + RETURN joined_geoms; +END +$$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION _cdb_state_update_union_adjacent(clusters geometry[], new_geom geometry) +RETURNS geometry[] AS $$ +DECLARE + joins geometry[] :='{}'; + unjoined geometry[] :='{}'; + i integer; + combined geometry; +BEGIN + joins := (select array_agg(g) + from unnest(clusters) a(g) + where ST_TOUCHES(g, new_geom)); + + unjoined := (select array_agg(g) + from unnest(clusters) a(g) + where ST_TOUCHES(g, new_geom) = false); + + IF array_length(joins, 1) > 0 THEN + joins := array_append(joins, new_geom); + combined := ST_UNION(joins); + ELSE + combined := new_geom; + END IF; + + unjoined := array_append(unjoined, combined); + RETURN unjoined; +END +$$ +LANGUAGE plpgsql; + +CREATE AGGREGATE cdb_union_adjacent(geometry)( + SFUNC=_cdb_state_update_union_adjacent, + STYPE=geometry[], + FINALFUNC=_cdb_final_union_adjacent, + INITCOND='{}' +); \ No newline at end of file diff --git a/src/pg/test/expected/11_cdb_union_adjacent.out b/src/pg/test/expected/11_cdb_union_adjacent.out new file mode 100644 index 0000000..06276aa --- /dev/null +++ b/src/pg/test/expected/11_cdb_union_adjacent.out @@ -0,0 +1,21 @@ +\i test/fixtures/touching_polygons.sql +-- test table (polygons, some of which touch and some which dont) +CREATE TABLE touching_polygons(cartodb_id integer, the_geom geometry); +INSERT INTO touching_polygons VALUES +(1, ST_GeomFromText('POLYGON ((0 0, 1 0,1 1, 0 1, 0 0 ))')), +(2, ST_GeomFromText('POLYGON ((1 0, 2 0, 2 1, 1 1, 1 0))')), +(1, ST_GeomFromText('POLYGON ((0 1, 1 1,1 2, 0 2, 0 1 ))')), +(4, ST_GeomFromText('POLYGON ((3 0, 4 0, 4 1, 3 1, 3 0))')), +(5, ST_GeomFromText('POLYGON ((3 1, 4 1, 4 2, 3 2, 3 1))')); +WITH joined_polygons AS ( + SELECT cdb_crankshaft.cdb_union_adjacent(the_geom) the_geom FROM touching_polygons +), +unnested_polygons as ( + select unnest(joined_polygons.the_geom) the_geom from joined_polygons +) +select ST_ASTEXT(unnested_polygons.the_geom) from unnested_polygons; + st_astext +------------------------------------------------ + POLYGON((1 0,0 0,0 1,0 2,1 2,1 1,2 1,2 0,1 0)) + POLYGON((4 1,4 0,3 0,3 1,3 2,4 2,4 1)) +(2 rows) diff --git a/src/pg/test/fixtures/touching_polygons.sql b/src/pg/test/fixtures/touching_polygons.sql new file mode 100644 index 0000000..574eb84 --- /dev/null +++ b/src/pg/test/fixtures/touching_polygons.sql @@ -0,0 +1,8 @@ +-- test table (polygons, some of which touch and some which dont) +CREATE TABLE touching_polygons(cartodb_id integer, the_geom geometry); +INSERT INTO touching_polygons VALUES +(1, ST_GeomFromText('POLYGON ((0 0, 1 0,1 1, 0 1, 0 0 ))')), +(2, ST_GeomFromText('POLYGON ((1 0, 2 0, 2 1, 1 1, 1 0))')), +(1, ST_GeomFromText('POLYGON ((0 1, 1 1,1 2, 0 2, 0 1 ))')), +(4, ST_GeomFromText('POLYGON ((3 0, 4 0, 4 1, 3 1, 3 0))')), +(5, ST_GeomFromText('POLYGON ((3 1, 4 1, 4 2, 3 2, 3 1))')); \ No newline at end of file diff --git a/src/pg/test/sql/11_cdb_union_adjacent_test.sql b/src/pg/test/sql/11_cdb_union_adjacent_test.sql new file mode 100644 index 0000000..dd51cb6 --- /dev/null +++ b/src/pg/test/sql/11_cdb_union_adjacent_test.sql @@ -0,0 +1,9 @@ +\i test/fixtures/touching_polygons.sql + +WITH joined_polygons AS ( + SELECT cdb_crankshaft.cdb_union_adjacent(the_geom) the_geom FROM touching_polygons +), +unnested_polygons as ( + select unnest(joined_polygons.the_geom) the_geom from joined_polygons +) +select ST_ASTEXT(unnested_polygons.the_geom) from unnested_polygons;