-e '/^\(CREATE\|ALTER\) \(CAST\|TYPE\|TABLE\|SCHEMA\|DOMAIN\|TRIGGER\)/,/\;/d' \
$< > $@
-topology.sql.in: sql/sqlmm.sql sql/populate.sql sql/polygonize.sql sql/gml.sql sql/query/getnodebypoint.sql sql/query/getedgebypoint.sql sql/query/getfacebypoint.sql sql/query/GetRingEdges.sql sql/manage/TopologySummary.sql sql/manage/CopyTopology.sql sql/manage/ManageHelper.sql sql/topoelement/topoelement_agg.sql sql/topogeometry/type.sql sql/topogeometry/totopogeom.sql
+topology.sql.in: sql/sqlmm.sql sql/populate.sql sql/polygonize.sql sql/gml.sql sql/query/getnodebypoint.sql sql/query/getedgebypoint.sql sql/query/getfacebypoint.sql sql/query/GetRingEdges.sql sql/manage/TopologySummary.sql sql/manage/CopyTopology.sql sql/manage/ManageHelper.sql sql/topoelement/topoelement_agg.sql sql/topogeometry/type.sql sql/topogeometry/totopogeom.sql sql/predicates.sql
uninstall_topology.sql: topology.sql ../utils/create_undef.pl
$(PERL) ../utils/create_undef.pl $< $(POSTGIS_PGSQL_VERSION) > $@
--- /dev/null
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+--
+-- PostGIS - Spatial Types for PostgreSQL
+-- http://postgis.refractions.net
+--
+-- Copyright (C) 2011-2012 Sandro Santilli <strk@keybit.net>
+-- Copyright (C) 2005 Refractions Research Inc.
+--
+-- This is free software; you can redistribute and/or modify it under
+-- the terms of the GNU General Public Licence. See the COPYING file.
+--
+-- Author: Sandro Santilli <strk@keybit.net>
+--
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+--
+-- Overloaded spatial predicates for TopoGeometry inputs
+--
+-- FUNCTION intersects(TopoGeometry, TopoGeometry)
+-- FUNCTION equals(TopoGeometry, TopoGeometry)
+--
+-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+--{
+-- Intersects(TopoGeometry, TopoGeometry)
+--
+CREATE OR REPLACE FUNCTION topology.intersects(topology.TopoGeometry, topology.TopoGeometry)
+ RETURNS bool
+AS
+$$
+DECLARE
+ tg1 alias for $1;
+ tg2 alias for $2;
+ tgbuf topology.TopoGeometry;
+ rec RECORD;
+ toponame varchar;
+ query text;
+BEGIN
+ IF tg1.topology_id != tg2.topology_id THEN
+ RAISE EXCEPTION 'Cannot compute intersection between TopoGeometries from different topologies';
+ END IF;
+
+ -- Order TopoGeometries so that tg1 has less-or-same
+ -- dimensionality of tg1 (point,line,polygon,collection)
+ IF tg1.type > tg2.type THEN
+ tgbuf := tg2;
+ tg2 := tg1;
+ tg1 := tgbuf;
+ END IF;
+
+ --RAISE NOTICE 'tg1.id:% tg2.id:%', tg1.id, tg2.id;
+ -- Geometry collection are not currently supported
+ IF tg2.type = 4 THEN
+ RAISE EXCEPTION 'GeometryCollection are not supported by intersects()';
+ END IF;
+
+ -- Get topology name
+ SELECT name FROM topology.topology into toponame
+ WHERE id = tg1.topology_id;
+
+ -- Hierarchical TopoGeometries are not currently supported
+ query = 'SELECT level FROM topology.layer'
+ || ' WHERE '
+ || ' topology_id = ' || tg1.topology_id
+ || ' AND '
+ || '( layer_id = ' || tg1.layer_id
+ || ' OR layer_id = ' || tg2.layer_id
+ || ' ) '
+ || ' AND level > 0 ';
+
+ --RAISE NOTICE '%', query;
+
+ FOR rec IN EXECUTE query
+ LOOP
+ RAISE EXCEPTION 'Hierarchical TopoGeometries are not currently supported by intersects()';
+ END LOOP;
+
+ IF tg1.type = 1 THEN -- [multi]point
+
+
+ IF tg2.type = 1 THEN -- point/point
+ ---------------------------------------------------------
+ --
+ -- Two [multi]point features intersect if they share
+ -- any Node
+ --
+ --
+ --
+ query =
+ 'SELECT a.topogeo_id FROM '
+ || quote_ident(toponame) ||
+ '.relation a, '
+ || quote_ident(toponame) ||
+ '.relation b '
+ || 'WHERE a.layer_id = ' || tg1.layer_id
+ || ' AND b.layer_id = ' || tg2.layer_id
+ || ' AND a.topogeo_id = ' || tg1.id
+ || ' AND b.topogeo_id = ' || tg2.id
+ || ' AND a.element_id = b.element_id '
+ || ' LIMIT 1';
+ --RAISE NOTICE '%', query;
+ FOR rec IN EXECUTE query
+ LOOP
+ RETURN TRUE; -- they share an element
+ END LOOP;
+ RETURN FALSE; -- no elements shared
+ --
+ ---------------------------------------------------------
+
+
+ ELSIF tg2.type = 2 THEN -- point/line
+ ---------------------------------------------------------
+ --
+ -- A [multi]point intersects a [multi]line if they share
+ -- any Node.
+ --
+ --
+ --
+ query =
+ 'SELECT a.topogeo_id FROM '
+ || quote_ident(toponame) ||
+ '.relation a, '
+ || quote_ident(toponame) ||
+ '.relation b, '
+ || quote_ident(toponame) ||
+ '.edge_data e '
+ || 'WHERE a.layer_id = ' || tg1.layer_id
+ || ' AND b.layer_id = ' || tg2.layer_id
+ || ' AND a.topogeo_id = ' || tg1.id
+ || ' AND b.topogeo_id = ' || tg2.id
+ || ' AND abs(b.element_id) = e.edge_id '
+ || ' AND ( '
+ || ' e.start_node = a.element_id '
+ || ' OR '
+ || ' e.end_node = a.element_id '
+ || ' )'
+ || ' LIMIT 1';
+ --RAISE NOTICE '%', query;
+ FOR rec IN EXECUTE query
+ LOOP
+ RETURN TRUE; -- they share an element
+ END LOOP;
+ RETURN FALSE; -- no elements shared
+ --
+ ---------------------------------------------------------
+
+ ELSIF tg2.type = 3 THEN -- point/polygon
+ ---------------------------------------------------------
+ --
+ -- A [multi]point intersects a [multi]polygon if any
+ -- Node of the point is contained in any face of the
+ -- polygon OR ( is end_node or start_node of any edge
+ -- of any polygon face ).
+ --
+ -- We assume the Node-in-Face check is faster becasue
+ -- there will be less Faces then Edges in any polygon.
+ --
+ --
+ --
+ --
+ -- Check if any node is contained in a face
+ query =
+ 'SELECT n.node_id as id FROM '
+ || quote_ident(toponame) ||
+ '.relation r1, '
+ || quote_ident(toponame) ||
+ '.relation r2, '
+ || quote_ident(toponame) ||
+ '.node n '
+ || 'WHERE r1.layer_id = ' || tg1.layer_id
+ || ' AND r2.layer_id = ' || tg2.layer_id
+ || ' AND r1.topogeo_id = ' || tg1.id
+ || ' AND r2.topogeo_id = ' || tg2.id
+ || ' AND n.node_id = r1.element_id '
+ || ' AND r2.element_id = n.containing_face '
+ || ' LIMIT 1';
+ --RAISE NOTICE '%', query;
+ FOR rec IN EXECUTE query
+ LOOP
+ --RAISE NOTICE 'Node % in polygon face', rec.id;
+ RETURN TRUE; -- one (or more) nodes are
+ -- contained in a polygon face
+ END LOOP;
+
+ -- Check if any node is start or end of any polygon
+ -- face edge
+ query =
+ 'SELECT n.node_id as nid, e.edge_id as eid '
+ || ' FROM '
+ || quote_ident(toponame) ||
+ '.relation r1, '
+ || quote_ident(toponame) ||
+ '.relation r2, '
+ || quote_ident(toponame) ||
+ '.edge_data e, '
+ || quote_ident(toponame) ||
+ '.node n '
+ || 'WHERE r1.layer_id = ' || tg1.layer_id
+ || ' AND r2.layer_id = ' || tg2.layer_id
+ || ' AND r1.topogeo_id = ' || tg1.id
+ || ' AND r2.topogeo_id = ' || tg2.id
+ || ' AND n.node_id = r1.element_id '
+ || ' AND ( '
+ || ' e.left_face = r2.element_id '
+ || ' OR '
+ || ' e.right_face = r2.element_id '
+ || ' ) '
+ || ' AND ( '
+ || ' e.start_node = r1.element_id '
+ || ' OR '
+ || ' e.end_node = r1.element_id '
+ || ' ) '
+ || ' LIMIT 1';
+ --RAISE NOTICE '%', query;
+ FOR rec IN EXECUTE query
+ LOOP
+ --RAISE NOTICE 'Node % on edge % bound', rec.nid, rec.eid;
+ RETURN TRUE; -- one node is start or end
+ -- of a face edge
+ END LOOP;
+
+ RETURN FALSE; -- no intersection
+ --
+ ---------------------------------------------------------
+
+ ELSIF tg2.type = 4 THEN -- point/collection
+ RAISE EXCEPTION 'Intersection point/collection not implemented yet';
+
+ ELSE
+ RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
+ END IF;
+
+ ELSIF tg1.type = 2 THEN -- [multi]line
+ IF tg2.type = 2 THEN -- line/line
+ ---------------------------------------------------------
+ --
+ -- A [multi]line intersects a [multi]line if they share
+ -- any Node.
+ --
+ --
+ --
+ query =
+ 'SELECT e1.start_node FROM '
+ || quote_ident(toponame) ||
+ '.relation r1, '
+ || quote_ident(toponame) ||
+ '.relation r2, '
+ || quote_ident(toponame) ||
+ '.edge_data e1, '
+ || quote_ident(toponame) ||
+ '.edge_data e2 '
+ || 'WHERE r1.layer_id = ' || tg1.layer_id
+ || ' AND r2.layer_id = ' || tg2.layer_id
+ || ' AND r1.topogeo_id = ' || tg1.id
+ || ' AND r2.topogeo_id = ' || tg2.id
+ || ' AND abs(r1.element_id) = e1.edge_id '
+ || ' AND abs(r2.element_id) = e2.edge_id '
+ || ' AND ( '
+ || ' e1.start_node = e2.start_node '
+ || ' OR '
+ || ' e1.start_node = e2.end_node '
+ || ' OR '
+ || ' e1.end_node = e2.start_node '
+ || ' OR '
+ || ' e1.end_node = e2.end_node '
+ || ' )'
+ || ' LIMIT 1';
+ --RAISE NOTICE '%', query;
+ FOR rec IN EXECUTE query
+ LOOP
+ RETURN TRUE; -- they share an element
+ END LOOP;
+ RETURN FALSE; -- no elements shared
+ --
+ ---------------------------------------------------------
+
+ ELSIF tg2.type = 3 THEN -- line/polygon
+ ---------------------------------------------------------
+ --
+ -- A [multi]line intersects a [multi]polygon if they share
+ -- any Node (touch-only case), or if any line edge has any
+ -- polygon face on the left or right (full-containment case
+ -- + edge crossing case).
+ --
+ --
+ -- E1 are line edges, E2 are polygon edges
+ -- R1 are line relations.
+ -- R2 are polygon relations.
+ -- R2.element_id are FACE ids
+ query =
+ 'SELECT e1.edge_id'
+ || ' FROM '
+ || quote_ident(toponame) ||
+ '.relation r1, '
+ || quote_ident(toponame) ||
+ '.relation r2, '
+ || quote_ident(toponame) ||
+ '.edge_data e1, '
+ || quote_ident(toponame) ||
+ '.edge_data e2 '
+ || 'WHERE r1.layer_id = ' || tg1.layer_id
+ || ' AND r2.layer_id = ' || tg2.layer_id
+ || ' AND r1.topogeo_id = ' || tg1.id
+ || ' AND r2.topogeo_id = ' || tg2.id
+
+ -- E1 are line edges
+ || ' AND e1.edge_id = abs(r1.element_id) '
+
+ -- E2 are face edges
+ || ' AND ( e2.left_face = r2.element_id '
+ || ' OR e2.right_face = r2.element_id ) '
+
+ || ' AND ( '
+
+ -- Check if E1 have left-or-right face
+ -- being part of R2.element_id
+ || ' e1.left_face = r2.element_id '
+ || ' OR '
+ || ' e1.right_face = r2.element_id '
+
+ -- Check if E1 share start-or-end node
+ -- with any E2.
+ || ' OR '
+ || ' e1.start_node = e2.start_node '
+ || ' OR '
+ || ' e1.start_node = e2.end_node '
+ || ' OR '
+ || ' e1.end_node = e2.start_node '
+ || ' OR '
+ || ' e1.end_node = e2.end_node '
+
+ || ' ) '
+
+ || ' LIMIT 1';
+ --RAISE NOTICE '%', query;
+ FOR rec IN EXECUTE query
+ LOOP
+ RETURN TRUE; -- either common node
+ -- or edge-in-face
+ END LOOP;
+
+ RETURN FALSE; -- no intersection
+ --
+ ---------------------------------------------------------
+
+ ELSIF tg2.type = 4 THEN -- line/collection
+ RAISE EXCEPTION 'Intersection line/collection not implemented yet', tg1.type, tg2.type;
+
+ ELSE
+ RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
+ END IF;
+
+
+ ELSIF tg1.type = 3 THEN -- [multi]polygon
+
+ IF tg2.type = 3 THEN -- polygon/polygon
+ ---------------------------------------------------------
+ --
+ -- A [multi]polygon intersects a [multi]polygon if they share
+ -- any Node (touch-only case), or if any face edge has any of the
+ -- other polygon face on the left or right (full-containment case
+ -- + edge crossing case).
+ --
+ --
+ -- E1 are poly1 edges.
+ -- E2 are poly2 edges
+ -- R1 are poly1 relations.
+ -- R2 are poly2 relations.
+ -- R1.element_id are poly1 FACE ids
+ -- R2.element_id are poly2 FACE ids
+ query =
+ 'SELECT e1.edge_id'
+ || ' FROM '
+ || quote_ident(toponame) ||
+ '.relation r1, '
+ || quote_ident(toponame) ||
+ '.relation r2, '
+ || quote_ident(toponame) ||
+ '.edge_data e1, '
+ || quote_ident(toponame) ||
+ '.edge_data e2 '
+ || 'WHERE r1.layer_id = ' || tg1.layer_id
+ || ' AND r2.layer_id = ' || tg2.layer_id
+ || ' AND r1.topogeo_id = ' || tg1.id
+ || ' AND r2.topogeo_id = ' || tg2.id
+
+ -- E1 are poly1 edges
+ || ' AND ( e1.left_face = r1.element_id '
+ || ' OR e1.right_face = r1.element_id ) '
+
+ -- E2 are poly2 edges
+ || ' AND ( e2.left_face = r2.element_id '
+ || ' OR e2.right_face = r2.element_id ) '
+
+ || ' AND ( '
+
+ -- Check if any edge from a polygon face
+ -- has any of the other polygon face
+ -- on the left or right
+ || ' e1.left_face = r2.element_id '
+ || ' OR '
+ || ' e1.right_face = r2.element_id '
+ || ' OR '
+ || ' e2.left_face = r1.element_id '
+ || ' OR '
+ || ' e2.right_face = r1.element_id '
+
+ -- Check if E1 share start-or-end node
+ -- with any E2.
+ || ' OR '
+ || ' e1.start_node = e2.start_node '
+ || ' OR '
+ || ' e1.start_node = e2.end_node '
+ || ' OR '
+ || ' e1.end_node = e2.start_node '
+ || ' OR '
+ || ' e1.end_node = e2.end_node '
+
+ || ' ) '
+
+ || ' LIMIT 1';
+ --RAISE NOTICE '%', query;
+ FOR rec IN EXECUTE query
+ LOOP
+ RETURN TRUE; -- either common node
+ -- or edge-in-face
+ END LOOP;
+
+ RETURN FALSE; -- no intersection
+ --
+ ---------------------------------------------------------
+
+ ELSIF tg2.type = 4 THEN -- polygon/collection
+ RAISE EXCEPTION 'Intersection poly/collection not implemented yet', tg1.type, tg2.type;
+
+ ELSE
+ RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
+ END IF;
+
+ ELSIF tg1.type = 4 THEN -- collection
+ IF tg2.type = 4 THEN -- collection/collection
+ RAISE EXCEPTION 'Intersection collection/collection not implemented yet', tg1.type, tg2.type;
+ ELSE
+ RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
+ END IF;
+
+ ELSE
+ RAISE EXCEPTION 'Invalid TopoGeometry type %', tg1.type;
+ END IF;
+END
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+--} intersects(TopoGeometry, TopoGeometry)
+
+--{
+-- equals(TopoGeometry, TopoGeometry)
+--
+CREATE OR REPLACE FUNCTION topology.equals(topology.TopoGeometry, topology.TopoGeometry)
+ RETURNS bool
+AS
+$$
+DECLARE
+ tg1 alias for $1;
+ tg2 alias for $2;
+ rec RECORD;
+ toponame varchar;
+ query text;
+BEGIN
+
+ IF tg1.topology_id != tg2.topology_id THEN
+ RAISE EXCEPTION 'Cannot compare TopoGeometries from different topologies';
+ END IF;
+
+ -- Not the same type, not equal
+ IF tg1.type != tg2.type THEN
+ RETURN FALSE;
+ END IF;
+
+ -- Geometry collection are not currently supported
+ IF tg2.type = 4 THEN
+ RAISE EXCEPTION 'GeometryCollection are not supported by equals()';
+ END IF;
+
+ -- Get topology name
+ SELECT name FROM topology.topology into toponame
+ WHERE id = tg1.topology_id;
+
+ -- Two geometries are equal if they are composed by
+ -- the same TopoElements
+ FOR rec IN EXECUTE 'SELECT * FROM '
+ || ' topology.GetTopoGeomElements('
+ || quote_literal(toponame) || ', '
+ || tg1.layer_id || ',' || tg1.id || ') '
+ || ' EXCEPT SELECT * FROM '
+ || ' topology.GetTopogeomElements('
+ || quote_literal(toponame) || ', '
+ || tg2.layer_id || ',' || tg2.id || ');'
+ LOOP
+ RETURN FALSE;
+ END LOOP;
+
+ FOR rec IN EXECUTE 'SELECT * FROM '
+ || ' topology.GetTopoGeomElements('
+ || quote_literal(toponame) || ', '
+ || tg2.layer_id || ',' || tg2.id || ')'
+ || ' EXCEPT SELECT * FROM '
+ || ' topology.GetTopogeomElements('
+ || quote_literal(toponame) || ', '
+ || tg1.layer_id || ',' || tg1.id || '); '
+ LOOP
+ RETURN FALSE;
+ END LOOP;
+ RETURN TRUE;
+END
+$$
+LANGUAGE 'plpgsql' VOLATILE STRICT;
+--} equals(TopoGeometry, TopoGeometry)
+
#include "sql/manage/TopologySummary.sql"
#include "sql/manage/CopyTopology.sql"
---={ ----------------------------------------------------------------
--- POSTGIS-SPECIFIC topology predicates
---
--- This part contains function NOT in the SQL/MM specification
---
----------------------------------------------------------------------
-
---{
--- Intersects(TopoGeometry, TopoGeometry)
---
-CREATE OR REPLACE FUNCTION topology.intersects(topology.TopoGeometry, topology.TopoGeometry)
- RETURNS bool
-AS
-$$
-DECLARE
- tg1 alias for $1;
- tg2 alias for $2;
- tgbuf topology.TopoGeometry;
- rec RECORD;
- toponame varchar;
- query text;
-BEGIN
- IF tg1.topology_id != tg2.topology_id THEN
- RAISE EXCEPTION 'Cannot compute intersection between TopoGeometries from different topologies';
- END IF;
-
- -- Order TopoGeometries so that tg1 has less-or-same
- -- dimensionality of tg1 (point,line,polygon,collection)
- IF tg1.type > tg2.type THEN
- tgbuf := tg2;
- tg2 := tg1;
- tg1 := tgbuf;
- END IF;
-
- --RAISE NOTICE 'tg1.id:% tg2.id:%', tg1.id, tg2.id;
- -- Geometry collection are not currently supported
- IF tg2.type = 4 THEN
- RAISE EXCEPTION 'GeometryCollection are not supported by intersects()';
- END IF;
-
- -- Get topology name
- SELECT name FROM topology.topology into toponame
- WHERE id = tg1.topology_id;
-
- -- Hierarchical TopoGeometries are not currently supported
- query = 'SELECT level FROM topology.layer'
- || ' WHERE '
- || ' topology_id = ' || tg1.topology_id
- || ' AND '
- || '( layer_id = ' || tg1.layer_id
- || ' OR layer_id = ' || tg2.layer_id
- || ' ) '
- || ' AND level > 0 ';
-
- --RAISE NOTICE '%', query;
-
- FOR rec IN EXECUTE query
- LOOP
- RAISE EXCEPTION 'Hierarchical TopoGeometries are not currently supported by intersects()';
- END LOOP;
-
- IF tg1.type = 1 THEN -- [multi]point
-
-
- IF tg2.type = 1 THEN -- point/point
- ---------------------------------------------------------
- --
- -- Two [multi]point features intersect if they share
- -- any Node
- --
- --
- --
- query =
- 'SELECT a.topogeo_id FROM '
- || quote_ident(toponame) ||
- '.relation a, '
- || quote_ident(toponame) ||
- '.relation b '
- || 'WHERE a.layer_id = ' || tg1.layer_id
- || ' AND b.layer_id = ' || tg2.layer_id
- || ' AND a.topogeo_id = ' || tg1.id
- || ' AND b.topogeo_id = ' || tg2.id
- || ' AND a.element_id = b.element_id '
- || ' LIMIT 1';
- --RAISE NOTICE '%', query;
- FOR rec IN EXECUTE query
- LOOP
- RETURN TRUE; -- they share an element
- END LOOP;
- RETURN FALSE; -- no elements shared
- --
- ---------------------------------------------------------
-
-
- ELSIF tg2.type = 2 THEN -- point/line
- ---------------------------------------------------------
- --
- -- A [multi]point intersects a [multi]line if they share
- -- any Node.
- --
- --
- --
- query =
- 'SELECT a.topogeo_id FROM '
- || quote_ident(toponame) ||
- '.relation a, '
- || quote_ident(toponame) ||
- '.relation b, '
- || quote_ident(toponame) ||
- '.edge_data e '
- || 'WHERE a.layer_id = ' || tg1.layer_id
- || ' AND b.layer_id = ' || tg2.layer_id
- || ' AND a.topogeo_id = ' || tg1.id
- || ' AND b.topogeo_id = ' || tg2.id
- || ' AND abs(b.element_id) = e.edge_id '
- || ' AND ( '
- || ' e.start_node = a.element_id '
- || ' OR '
- || ' e.end_node = a.element_id '
- || ' )'
- || ' LIMIT 1';
- --RAISE NOTICE '%', query;
- FOR rec IN EXECUTE query
- LOOP
- RETURN TRUE; -- they share an element
- END LOOP;
- RETURN FALSE; -- no elements shared
- --
- ---------------------------------------------------------
-
- ELSIF tg2.type = 3 THEN -- point/polygon
- ---------------------------------------------------------
- --
- -- A [multi]point intersects a [multi]polygon if any
- -- Node of the point is contained in any face of the
- -- polygon OR ( is end_node or start_node of any edge
- -- of any polygon face ).
- --
- -- We assume the Node-in-Face check is faster becasue
- -- there will be less Faces then Edges in any polygon.
- --
- --
- --
- --
- -- Check if any node is contained in a face
- query =
- 'SELECT n.node_id as id FROM '
- || quote_ident(toponame) ||
- '.relation r1, '
- || quote_ident(toponame) ||
- '.relation r2, '
- || quote_ident(toponame) ||
- '.node n '
- || 'WHERE r1.layer_id = ' || tg1.layer_id
- || ' AND r2.layer_id = ' || tg2.layer_id
- || ' AND r1.topogeo_id = ' || tg1.id
- || ' AND r2.topogeo_id = ' || tg2.id
- || ' AND n.node_id = r1.element_id '
- || ' AND r2.element_id = n.containing_face '
- || ' LIMIT 1';
- --RAISE NOTICE '%', query;
- FOR rec IN EXECUTE query
- LOOP
- --RAISE NOTICE 'Node % in polygon face', rec.id;
- RETURN TRUE; -- one (or more) nodes are
- -- contained in a polygon face
- END LOOP;
-
- -- Check if any node is start or end of any polygon
- -- face edge
- query =
- 'SELECT n.node_id as nid, e.edge_id as eid '
- || ' FROM '
- || quote_ident(toponame) ||
- '.relation r1, '
- || quote_ident(toponame) ||
- '.relation r2, '
- || quote_ident(toponame) ||
- '.edge_data e, '
- || quote_ident(toponame) ||
- '.node n '
- || 'WHERE r1.layer_id = ' || tg1.layer_id
- || ' AND r2.layer_id = ' || tg2.layer_id
- || ' AND r1.topogeo_id = ' || tg1.id
- || ' AND r2.topogeo_id = ' || tg2.id
- || ' AND n.node_id = r1.element_id '
- || ' AND ( '
- || ' e.left_face = r2.element_id '
- || ' OR '
- || ' e.right_face = r2.element_id '
- || ' ) '
- || ' AND ( '
- || ' e.start_node = r1.element_id '
- || ' OR '
- || ' e.end_node = r1.element_id '
- || ' ) '
- || ' LIMIT 1';
- --RAISE NOTICE '%', query;
- FOR rec IN EXECUTE query
- LOOP
- --RAISE NOTICE 'Node % on edge % bound', rec.nid, rec.eid;
- RETURN TRUE; -- one node is start or end
- -- of a face edge
- END LOOP;
-
- RETURN FALSE; -- no intersection
- --
- ---------------------------------------------------------
-
- ELSIF tg2.type = 4 THEN -- point/collection
- RAISE EXCEPTION 'Intersection point/collection not implemented yet';
-
- ELSE
- RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
- END IF;
-
- ELSIF tg1.type = 2 THEN -- [multi]line
- IF tg2.type = 2 THEN -- line/line
- ---------------------------------------------------------
- --
- -- A [multi]line intersects a [multi]line if they share
- -- any Node.
- --
- --
- --
- query =
- 'SELECT e1.start_node FROM '
- || quote_ident(toponame) ||
- '.relation r1, '
- || quote_ident(toponame) ||
- '.relation r2, '
- || quote_ident(toponame) ||
- '.edge_data e1, '
- || quote_ident(toponame) ||
- '.edge_data e2 '
- || 'WHERE r1.layer_id = ' || tg1.layer_id
- || ' AND r2.layer_id = ' || tg2.layer_id
- || ' AND r1.topogeo_id = ' || tg1.id
- || ' AND r2.topogeo_id = ' || tg2.id
- || ' AND abs(r1.element_id) = e1.edge_id '
- || ' AND abs(r2.element_id) = e2.edge_id '
- || ' AND ( '
- || ' e1.start_node = e2.start_node '
- || ' OR '
- || ' e1.start_node = e2.end_node '
- || ' OR '
- || ' e1.end_node = e2.start_node '
- || ' OR '
- || ' e1.end_node = e2.end_node '
- || ' )'
- || ' LIMIT 1';
- --RAISE NOTICE '%', query;
- FOR rec IN EXECUTE query
- LOOP
- RETURN TRUE; -- they share an element
- END LOOP;
- RETURN FALSE; -- no elements shared
- --
- ---------------------------------------------------------
-
- ELSIF tg2.type = 3 THEN -- line/polygon
- ---------------------------------------------------------
- --
- -- A [multi]line intersects a [multi]polygon if they share
- -- any Node (touch-only case), or if any line edge has any
- -- polygon face on the left or right (full-containment case
- -- + edge crossing case).
- --
- --
- -- E1 are line edges, E2 are polygon edges
- -- R1 are line relations.
- -- R2 are polygon relations.
- -- R2.element_id are FACE ids
- query =
- 'SELECT e1.edge_id'
- || ' FROM '
- || quote_ident(toponame) ||
- '.relation r1, '
- || quote_ident(toponame) ||
- '.relation r2, '
- || quote_ident(toponame) ||
- '.edge_data e1, '
- || quote_ident(toponame) ||
- '.edge_data e2 '
- || 'WHERE r1.layer_id = ' || tg1.layer_id
- || ' AND r2.layer_id = ' || tg2.layer_id
- || ' AND r1.topogeo_id = ' || tg1.id
- || ' AND r2.topogeo_id = ' || tg2.id
-
- -- E1 are line edges
- || ' AND e1.edge_id = abs(r1.element_id) '
-
- -- E2 are face edges
- || ' AND ( e2.left_face = r2.element_id '
- || ' OR e2.right_face = r2.element_id ) '
-
- || ' AND ( '
-
- -- Check if E1 have left-or-right face
- -- being part of R2.element_id
- || ' e1.left_face = r2.element_id '
- || ' OR '
- || ' e1.right_face = r2.element_id '
-
- -- Check if E1 share start-or-end node
- -- with any E2.
- || ' OR '
- || ' e1.start_node = e2.start_node '
- || ' OR '
- || ' e1.start_node = e2.end_node '
- || ' OR '
- || ' e1.end_node = e2.start_node '
- || ' OR '
- || ' e1.end_node = e2.end_node '
-
- || ' ) '
-
- || ' LIMIT 1';
- --RAISE NOTICE '%', query;
- FOR rec IN EXECUTE query
- LOOP
- RETURN TRUE; -- either common node
- -- or edge-in-face
- END LOOP;
-
- RETURN FALSE; -- no intersection
- --
- ---------------------------------------------------------
-
- ELSIF tg2.type = 4 THEN -- line/collection
- RAISE EXCEPTION 'Intersection line/collection not implemented yet', tg1.type, tg2.type;
-
- ELSE
- RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
- END IF;
-
-
- ELSIF tg1.type = 3 THEN -- [multi]polygon
-
- IF tg2.type = 3 THEN -- polygon/polygon
- ---------------------------------------------------------
- --
- -- A [multi]polygon intersects a [multi]polygon if they share
- -- any Node (touch-only case), or if any face edge has any of the
- -- other polygon face on the left or right (full-containment case
- -- + edge crossing case).
- --
- --
- -- E1 are poly1 edges.
- -- E2 are poly2 edges
- -- R1 are poly1 relations.
- -- R2 are poly2 relations.
- -- R1.element_id are poly1 FACE ids
- -- R2.element_id are poly2 FACE ids
- query =
- 'SELECT e1.edge_id'
- || ' FROM '
- || quote_ident(toponame) ||
- '.relation r1, '
- || quote_ident(toponame) ||
- '.relation r2, '
- || quote_ident(toponame) ||
- '.edge_data e1, '
- || quote_ident(toponame) ||
- '.edge_data e2 '
- || 'WHERE r1.layer_id = ' || tg1.layer_id
- || ' AND r2.layer_id = ' || tg2.layer_id
- || ' AND r1.topogeo_id = ' || tg1.id
- || ' AND r2.topogeo_id = ' || tg2.id
-
- -- E1 are poly1 edges
- || ' AND ( e1.left_face = r1.element_id '
- || ' OR e1.right_face = r1.element_id ) '
-
- -- E2 are poly2 edges
- || ' AND ( e2.left_face = r2.element_id '
- || ' OR e2.right_face = r2.element_id ) '
-
- || ' AND ( '
-
- -- Check if any edge from a polygon face
- -- has any of the other polygon face
- -- on the left or right
- || ' e1.left_face = r2.element_id '
- || ' OR '
- || ' e1.right_face = r2.element_id '
- || ' OR '
- || ' e2.left_face = r1.element_id '
- || ' OR '
- || ' e2.right_face = r1.element_id '
-
- -- Check if E1 share start-or-end node
- -- with any E2.
- || ' OR '
- || ' e1.start_node = e2.start_node '
- || ' OR '
- || ' e1.start_node = e2.end_node '
- || ' OR '
- || ' e1.end_node = e2.start_node '
- || ' OR '
- || ' e1.end_node = e2.end_node '
-
- || ' ) '
-
- || ' LIMIT 1';
- --RAISE NOTICE '%', query;
- FOR rec IN EXECUTE query
- LOOP
- RETURN TRUE; -- either common node
- -- or edge-in-face
- END LOOP;
-
- RETURN FALSE; -- no intersection
- --
- ---------------------------------------------------------
-
- ELSIF tg2.type = 4 THEN -- polygon/collection
- RAISE EXCEPTION 'Intersection poly/collection not implemented yet', tg1.type, tg2.type;
-
- ELSE
- RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
- END IF;
-
- ELSIF tg1.type = 4 THEN -- collection
- IF tg2.type = 4 THEN -- collection/collection
- RAISE EXCEPTION 'Intersection collection/collection not implemented yet', tg1.type, tg2.type;
- ELSE
- RAISE EXCEPTION 'Invalid TopoGeometry type', tg2.type;
- END IF;
-
- ELSE
- RAISE EXCEPTION 'Invalid TopoGeometry type %', tg1.type;
- END IF;
-END
-$$
-LANGUAGE 'plpgsql' VOLATILE STRICT;
---} intersects(TopoGeometry, TopoGeometry)
-
---{
--- equals(TopoGeometry, TopoGeometry)
---
-CREATE OR REPLACE FUNCTION topology.equals(topology.TopoGeometry, topology.TopoGeometry)
- RETURNS bool
-AS
-$$
-DECLARE
- tg1 alias for $1;
- tg2 alias for $2;
- rec RECORD;
- toponame varchar;
- query text;
-BEGIN
-
- IF tg1.topology_id != tg2.topology_id THEN
- RAISE EXCEPTION 'Cannot compare TopoGeometries from different topologies';
- END IF;
-
- -- Not the same type, not equal
- IF tg1.type != tg2.type THEN
- RETURN FALSE;
- END IF;
-
- -- Geometry collection are not currently supported
- IF tg2.type = 4 THEN
- RAISE EXCEPTION 'GeometryCollection are not supported by equals()';
- END IF;
-
- -- Get topology name
- SELECT name FROM topology.topology into toponame
- WHERE id = tg1.topology_id;
-
- -- Two geometries are equal if they are composed by
- -- the same TopoElements
- FOR rec IN EXECUTE 'SELECT * FROM '
- || ' topology.GetTopoGeomElements('
- || quote_literal(toponame) || ', '
- || tg1.layer_id || ',' || tg1.id || ') '
- || ' EXCEPT SELECT * FROM '
- || ' topology.GetTopogeomElements('
- || quote_literal(toponame) || ', '
- || tg2.layer_id || ',' || tg2.id || ');'
- LOOP
- RETURN FALSE;
- END LOOP;
-
- FOR rec IN EXECUTE 'SELECT * FROM '
- || ' topology.GetTopoGeomElements('
- || quote_literal(toponame) || ', '
- || tg2.layer_id || ',' || tg2.id || ')'
- || ' EXCEPT SELECT * FROM '
- || ' topology.GetTopogeomElements('
- || quote_literal(toponame) || ', '
- || tg1.layer_id || ',' || tg1.id || '); '
- LOOP
- RETURN FALSE;
- END LOOP;
- RETURN TRUE;
-END
-$$
-LANGUAGE 'plpgsql' VOLATILE STRICT;
---} equals(TopoGeometry, TopoGeometry)
-
---=} POSTGIS-SPECIFIC topology predicates
+-- Spatial predicates
+#include "sql/predicates.sql"
-- Querying
#include "sql/query/getnodebypoint.sql"