From 35b545b3ab72db715d836afa8479bf24524def58 Mon Sep 17 00:00:00 2001 From: Sandro Santilli Date: Wed, 4 Jan 2012 18:33:06 +0000 Subject: [PATCH] Complete implementation and regress test for toTopoGeom (#1017) You can start playing with this. Lacks documentation. Expect troubles. Feel free to report them. git-svn-id: http://svn.osgeo.org/postgis/trunk@8671 b70326c6-7e19-0410-871a-916f4a2858ee --- topology/sql/topogeometry/totopogeom.sql | 64 ++++++++++++++++++++--- topology/test/regress/totopogeom.sql | 52 ++++++++++++++++++ topology/test/regress/totopogeom_expected | 14 +++++ 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/topology/sql/topogeometry/totopogeom.sql b/topology/sql/topogeometry/totopogeom.sql index d9ce690fc..c9f9e95e6 100644 --- a/topology/sql/topogeometry/totopogeom.sql +++ b/topology/sql/topogeometry/totopogeom.sql @@ -23,6 +23,11 @@ $$ DECLARE layer_info RECORD; topology_info RECORD; + rec RECORD; + tg topology.TopoGeometry; + elems topology.TopoElementArray = '{{0,0}}'; + sql TEXT; + typ TEXT; BEGIN -- Get topology information @@ -63,48 +68,91 @@ BEGIN -- - -- Check type compatibility + -- Check type compatibility and create empty TopoGeometry -- 1:puntal, 2:lineal, 3:areal, 4:collection -- - IF geometrytype(ageom) = 'GEOMETRYCOLLECTION' THEN + typ = geometrytype(ageom); + IF typ = 'GEOMETRYCOLLECTION' THEN -- A collection can only go collection layer IF layer_info.feature_type != 4 THEN RAISE EXCEPTION 'Layer "%" of topology "%" is %, cannot hold a collection feature.', layer_info.layer_id, topology_info.name, layer_info.typename; END IF; - ELSIF ST_Dimension(ageom) = 0 THEN -- puntal + tg := topology.CreateTopoGeom(atopology, 4, alayer); + ELSIF typ = 'POINT' OR typ = 'MULTIPOINT' THEN -- puntal -- A point can go in puntal or collection layer IF layer_info.feature_type != 4 and layer_info.feature_type != 1 THEN RAISE EXCEPTION 'Layer "%" of topology "%" is %, cannot hold a puntal feature.', layer_info.layer_id, topology_info.name, layer_info.typename; END IF; - ELSIF ST_Dimension(ageom) = 1 THEN -- lineal + tg := topology.CreateTopoGeom(atopology, 1, alayer); + ELSIF typ = 'LINESTRING' or typ = 'MULTILINESTRING' THEN -- lineal -- A line can go in lineal or collection layer IF layer_info.feature_type != 4 and layer_info.feature_type != 2 THEN RAISE EXCEPTION 'Layer "%" of topology "%" is %, cannot hold a lineal feature.', layer_info.layer_id, topology_info.name, layer_info.typename; END IF; - ELSIF ST_Dimension(ageom) = 2 THEN -- areal + tg := topology.CreateTopoGeom(atopology, 2, alayer); + ELSIF typ = 'POLYGON' OR typ = 'MULTIPOLYGON' THEN -- areal -- An area can go in areal or collection layer IF layer_info.feature_type != 4 and layer_info.feature_type != 3 THEN RAISE EXCEPTION 'Layer "%" of topology "%" is %, cannot hold an areal feature.', layer_info.layer_id, topology_info.name, layer_info.typename; END IF; + tg := topology.CreateTopoGeom(atopology, 3, alayer); ELSE -- Should never happen RAISE EXCEPTION 'Unexpected feature dimension %', ST_Dimension(ageom); END IF; - -- TODO: handle empty + -- Now that we have a topogeometry, we loop over components + -- and add them to the definition of it. We add them as soon + -- as possible so that each element can further edit the + -- definition by splitting + FOR rec IN SELECT (ST_Dump(ageom)).geom LOOP + IF ST_IsEmpty(rec.geom) THEN + RAISE DEBUG 'Skipped empty component'; + ELSIF ST_Dimension(rec.geom) = 0 THEN + sql := 'INSERT INTO ' || quote_ident(atopology) + || '.relation(topogeo_id, layer_id, element_type, element_id) SELECT ' + || id(tg) || ', ' || alayer || ', 1, topogeo_addPoint(' + || quote_literal(atopology) || ', ' + || quote_literal(rec.geom::text) || '::geometry, ' || atolerance + || ');'; + RAISE DEBUG '%', sql; + EXECUTE sql; + ELSIF ST_Dimension(rec.geom) = 1 THEN + sql := 'INSERT INTO ' || quote_ident(atopology) + || '.relation(topogeo_id, layer_id, element_type, element_id) SELECT ' + || id(tg) || ', ' || alayer || ', 2, topogeo_addLineString(' + || quote_literal(atopology) || ', ' + || quote_literal(rec.geom::text) || '::geometry, ' || atolerance + || ');'; + RAISE DEBUG '%', sql; + EXECUTE sql; + ELSIF ST_Dimension(rec.geom) = 2 THEN + sql := 'INSERT INTO ' || quote_ident(atopology) + || '.relation(topogeo_id, layer_id, element_type, element_id) SELECT ' + || id(tg) || ', ' || alayer || ', 3, topogeo_addPolygon(' + || quote_literal(atopology) || ', ' + || quote_literal(rec.geom::text) || '::geometry, ' || atolerance + || ');'; + RAISE DEBUG '%', sql; + EXECUTE sql; + ELSE + RAISE EXCEPTION 'Unexpected dimension % for component %', ST_Dimension(rec.geom), ST_AsText(rec.geom); + END IF; + + END LOOP; - RAISE EXCEPTION 'toTopoGeometry not implemented yet'; + RETURN tg; END $$ -LANGUAGE 'plpgsql' STABLE STRICT; +LANGUAGE 'plpgsql' VOLATILE STRICT; -- } diff --git a/topology/test/regress/totopogeom.sql b/topology/test/regress/totopogeom.sql index d011b308e..4f5fe68dd 100644 --- a/topology/test/regress/totopogeom.sql +++ b/topology/test/regress/totopogeom.sql @@ -41,7 +41,59 @@ select totopogeom('MULTIPOINT(0 0, 10 10)'::geometry, 'tt', 4); -- invalid (area select totopogeom('POLYGON((0 0, 10 10, 10 0, 0 0))'::geometry, 'tt', 1); -- invalid (puntal) layer select totopogeom('POLYGON((0 0, 10 10, 10 0, 0 0))'::geometry, 'tt', 3); -- invalid (lineal) layer +-- Convert a point +with inp as ( select 'POINT(0 0)' ::geometry as g) +select St_AsText(g), ST_Equals(totopogeom(g, 'tt', 1)::geometry, g) from inp; +-- Convert a line +with inp as ( select 'LINESTRING(0 10, 10 10)' ::geometry as g) +select St_AsText(g), ST_Equals(totopogeom(g, 'tt', 3)::geometry, g) from inp; + +-- Convert a polygon +with inp as ( select +'POLYGON((0 20, 10 20, 5 30, 0 20),(2 22, 8 22, 5 28, 2 22))' + ::geometry as g) +select St_AsText(g), ST_Equals(totopogeom(g, 'tt', 4)::geometry, g) from inp; + +-- Convert a multipoint +with inp as ( select 'MULTIPOINT((0 -10),(5 -10))' ::geometry as g) +select St_AsText(g), ST_Equals(totopogeom(g, 'tt', 1)::geometry, g) from inp; + +-- Convert a multiline +with inp as ( select 'MULTILINESTRING((-1 10, -10 10),(-10 8, -2 9))' ::geometry as g) +select St_AsText(g), ST_Equals(totopogeom(g, 'tt', 3)::geometry, g) from inp; + +-- Convert a multipolygon +with inp as ( select +'MULTIPOLYGON(((100 20, 110 20, 105 30, 100 20),(102 22, 108 22, 105 28, 102 22)),((80 20, 90 20, 90 60, 80 20)))' + ::geometry as g) +select St_AsText(g), ST_Equals(totopogeom(g, 'tt', 4)::geometry, g) from inp; + +-- Convert a collection +with +inp as ( select +'GEOMETRYCOLLECTION( + POINT(-100 -100), + LINESTRING(-100 -90,-90 -90), + POLYGON((-100 -80,-90 -80,-95 -70,-100 -80),(-98 -78,-92 -78,-95 -72,-98 -78)), + MULTIPOINT(-100 -110,-95 -110), + LINESTRING EMPTY, + MULTILINESTRING((-101 -90,-110 -90),(-110 -92,-102 -91)), + MULTIPOLYGON(((0 -80,10 -80,5 -70,0 -80),(2 -78,8 -78,5 -72,2 -78)),((-20 -80,-10 -80,-10 -40,-20 -80))) +)' + ::geometry as g), +tg as ( select totopogeom(g, 'tt', 5) as g from inp ) +select St_AsText(inp.g), st_astext(tg.g::geometry) from inp, tg; + + +-- Convert some empties +SELECT ST_AsText(toTopoGeom('POINT EMPTY', 'tt', 1)::geometry); +SELECT ST_AsText(toTopoGeom('MULTIPOINT EMPTY', 'tt', 1)::geometry); +SELECT ST_AsText(toTopoGeom('LINESTRING EMPTY', 'tt', 3)::geometry); +SELECT ST_AsText(toTopoGeom('MULTILINESTRING EMPTY', 'tt', 3)::geometry); +SELECT ST_AsText(toTopoGeom('POLYGON EMPTY', 'tt', 4)::geometry); +SELECT ST_AsText(toTopoGeom('MULTIPOLYGON EMPTY', 'tt', 4)::geometry); +SELECT ST_AsText(toTopoGeom('GEOMETRYCOLLECTION EMPTY', 'tt', 5)::geometry); DROP TABLE tt.f_coll; DROP TABLE tt.f_areal; diff --git a/topology/test/regress/totopogeom_expected b/topology/test/regress/totopogeom_expected index 8fbcabf77..ce5d19a9d 100644 --- a/topology/test/regress/totopogeom_expected +++ b/topology/test/regress/totopogeom_expected @@ -15,4 +15,18 @@ ERROR: Layer "3" of topology "tt" is lineal, cannot hold a puntal feature. ERROR: Layer "4" of topology "tt" is areal, cannot hold a puntal feature. ERROR: Layer "1" of topology "tt" is puntal, cannot hold an areal feature. ERROR: Layer "3" of topology "tt" is lineal, cannot hold an areal feature. +POINT(0 0)|t +LINESTRING(0 10,10 10)|t +POLYGON((0 20,10 20,5 30,0 20),(2 22,8 22,5 28,2 22))|t +MULTIPOINT(0 -10,5 -10)|t +MULTILINESTRING((-1 10,-10 10),(-10 8,-2 9))|t +MULTIPOLYGON(((100 20,110 20,105 30,100 20),(102 22,108 22,105 28,102 22)),((80 20,90 20,90 60,80 20)))|t +GEOMETRYCOLLECTION(POINT(-100 -100),LINESTRING(-100 -90,-90 -90),POLYGON((-100 -80,-90 -80,-95 -70,-100 -80),(-98 -78,-92 -78,-95 -72,-98 -78)),MULTIPOINT(-100 -110,-95 -110),LINESTRING EMPTY,MULTILINESTRING((-101 -90,-110 -90),(-110 -92,-102 -91)),MULTIPOLYGON(((0 -80,10 -80,5 -70,0 -80),(2 -78,8 -78,5 -72,2 -78)),((-20 -80,-10 -80,-10 -40,-20 -80))))|GEOMETRYCOLLECTION(MULTIPOLYGON(((-100 -80,-95 -70,-90 -80,-100 -80),(-98 -78,-92 -78,-95 -72,-98 -78)),((0 -80,5 -70,10 -80,0 -80),(2 -78,8 -78,5 -72,2 -78)),((-20 -80,-10 -40,-10 -80,-20 -80))),MULTILINESTRING((-110 -92,-102 -91),(-101 -90,-110 -90),(-100 -90,-90 -90)),MULTIPOINT(-100 -110,-100 -100,-95 -110)) +POINT EMPTY +POINT EMPTY +LINESTRING EMPTY +LINESTRING EMPTY +POLYGON EMPTY +POLYGON EMPTY +GEOMETRYCOLLECTION EMPTY Topology 'tt' dropped -- 2.40.0