From: Sandro Santilli Date: Fri, 25 Feb 2011 08:45:03 +0000 (+0000) Subject: topology.GetEdgeByPoint: implementation and regress test, by Andrea Peri. Ticket... X-Git-Tag: 2.0.0alpha1~1937 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=54ec9a6b4ff3ec56bf2005bc4355826882ede260;p=postgis topology.GetEdgeByPoint: implementation and regress test, by Andrea Peri. Ticket #793 git-svn-id: http://svn.osgeo.org/postgis/trunk@6864 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/topology/Makefile.in b/topology/Makefile.in index 76ee49814..5cd4eb33b 100644 --- a/topology/Makefile.in +++ b/topology/Makefile.in @@ -42,7 +42,7 @@ endif $(SQL_OBJS): %.in: %.in.c $(CPP) -traditional-cpp $< | grep -v '^#' > $@ -topology.sql.in: sql/sqlmm.sql sql/populate.sql sql/gml.sql +topology.sql.in: sql/sqlmm.sql sql/populate.sql sql/gml.sql sql/query/getnodebypoint.sql check: topology.sql $(MAKE) -C test $@ diff --git a/topology/sql/query/getnodebypoint.sql b/topology/sql/query/getnodebypoint.sql new file mode 100644 index 000000000..87bbf0bb5 --- /dev/null +++ b/topology/sql/query/getnodebypoint.sql @@ -0,0 +1,89 @@ +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- PostGIS - Spatial Types for PostgreSQL +-- http://postgis.refractions.net +-- +-- Copyright (C) 2011 Andrea Peri +-- +-- This is free software; you can redistribute and/or modify it under +-- the terms of the GNU General Public Licence. See the COPYING file. +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +-- { +-- +-- Andrea Peri (19 Jan 2011) creation +-- Andrea Peri (14 Feb 2011) minor issues +-- +-- getnodebypoint(atopology, point, tolerance) +-- +-- Retrieve a Node ID given a POINT and a tolerance +-- tolerance = 0 mean exactly intersection +-- +-- Returns the integer ID if there is a Node on the Point. +-- +-- If there isn't any node in the Point, GetNodeByPoint return 0. +-- +-- if near the point there are two or more nodes it throw an exception. +-- +CREATE OR REPLACE FUNCTION topology.GetNodeByPoint(atopology varchar, apoint geometry, tol1 float8) + RETURNS int +AS +$$ +DECLARE + sql text; + idnode int; +BEGIN + -- + -- Atopology and apoint are required + -- + IF atopology IS NULL OR apoint IS NULL THEN + RAISE EXCEPTION 'Invalid null argument'; + END IF; + + -- + -- Apoint must be a point + -- + IF substring(geometrytype(apoint), 1, 5) != 'POINT' + THEN + RAISE EXCEPTION 'Node geometry must be a point'; + END IF; + + -- + -- Tolerance must be >= 0 + -- + IF tol1 < 0 + THEN + RAISE EXCEPTION 'Tolerance must be >=0'; + END IF; + + + if tol1 = 0 then + sql := 'SELECT a.node_id FROM ' + || quote_ident(atopology) + || '.node as a WHERE ' + || '(a.geom && ' || quote_literal(apoint::text)||'::geometry) ' + || ' AND (ST_Intersects(a.geom,' || quote_literal(apoint::text)||'::geometry) );'; + else + sql := 'SELECT a.node_id FROM ' + || quote_ident(atopology) + || '.node as a WHERE ' + || '(ST_DWithin(a.geom,' || quote_literal(apoint::text)||'::geometry,' || tol1::text || ') );'; + end if; + + BEGIN + EXECUTE sql INTO STRICT idnode; + EXCEPTION + WHEN NO_DATA_FOUND THEN + idnode = 0; + WHEN TOO_MANY_ROWS THEN + RAISE EXCEPTION 'Two or more nodes founded'; + END; + + RETURN idnode; + +END +$$ +LANGUAGE 'plpgsql' STRICT; +--} GetNodeByPoint + diff --git a/topology/test/Makefile b/topology/test/Makefile index 0733e74d8..2de17963a 100644 --- a/topology/test/Makefile +++ b/topology/test/Makefile @@ -31,7 +31,8 @@ TESTS = regress/legacy_validate.sql regress/legacy_predicate.sql \ regress/topoelementarray_agg.sql \ regress/droptopology.sql \ regress/createtopogeom.sql \ - regress/gml.sql + regress/gml.sql \ + regress/getnodebypoint.sql check: topo_predicates.sql load_topology.sql load_topology-4326.sql $(MAKE) -C ../../regress postgis.sql staged-install diff --git a/topology/test/regress/getnodebypoint.sql b/topology/test/regress/getnodebypoint.sql new file mode 100644 index 000000000..9182fa944 --- /dev/null +++ b/topology/test/regress/getnodebypoint.sql @@ -0,0 +1,30 @@ +set client_min_messages to WARNING; + +SELECT topology.CreateTopology('schema_topo') > 0; + +select topology.AddEdge('schema_topo',ST_GeomFromText('LINESTRING(1 4, 4 7)')) = 1; +select topology.AddEdge('schema_topo',ST_GeomFromText('LINESTRING(4 7, 6 9)')) = 2; +select topology.AddEdge('schema_topo',ST_GeomFromText('LINESTRING(2 2, 4 4)')) = 3; +select topology.AddEdge('schema_topo',ST_GeomFromText('LINESTRING(4 4, 5 5, 6 6)')) = 4; +select topology.AddEdge('schema_topo',ST_GeomFromText('LINESTRING(6 6, 6 9)')) = 5; + +-- ask on a Point with tolerance zero +select topology.GetNodeByPoint('schema_topo',ST_GeomFromText('POINT(5 5)'), 0::float8); + +-- ask on a Point on a node with tolerance +select topology.GetNodeByPoint('schema_topo',ST_GeomFromText('POINT(4 4)'), 0::float8); + +-- Ask for a point outside from an edge with a tolerance sufficient to include one node +select topology.GetNodeByPoint('schema_topo',ST_GeomFromText('POINT(4.1 4)'), 0.3::float8); + +-- Ask for a point where there isn't a node +select topology.GetNodeByPoint('schema_topo',ST_GeomFromText('POINT(5 5.5)'), 0::float8) = 0; + + +-- Failing cases (should all raise exceptions) ------- + +-- Ask for a Point with a tollerance too high +select topology.GetNodeByPoint('schema_topo',ST_GeomFromText('POINT(4 7)'), 5::float8); + + +SELECT topology.DropTopology('schema_topo'); diff --git a/topology/test/regress/getnodebypoint_expected b/topology/test/regress/getnodebypoint_expected new file mode 100644 index 000000000..fc0d7a393 --- /dev/null +++ b/topology/test/regress/getnodebypoint_expected @@ -0,0 +1,12 @@ +t +t +t +t +t +t +0 +5 +5 +t +ERROR: Two or more nodes founded +Topology 'schema_topo' dropped diff --git a/topology/topology.sql.in.c b/topology/topology.sql.in.c index 293abfd78..3914c6143 100644 --- a/topology/topology.sql.in.c +++ b/topology/topology.sql.in.c @@ -2411,6 +2411,9 @@ LANGUAGE 'plpgsql' VOLATILE STRICT; --=} POSTGIS-SPECIFIC topology predicates +-- Querying +#include "sql/query/getnodebypoint.sql" + -- Editing #include "sql/populate.sql"