=Introduction

This module contains support for topological geometry modelling.
Functions exist to satisfy the ISO/SQLMM topology-geometry model
and more are provided to add an additional abstraction level for
topological features and layers, both simple and hierarchical.

You can see an ER diagram of the full conceptual model in the ER dir.
You need xfig (http://epb.lbl.gov/xfig/).

All routines, types and other management objects are stored in the
"topology" SCHEMA.

Comments welcome --strk(2011-10-04);

=Requirements

  Many ISO/SQLMM functions use GEOS-3.3.0+ signatures.
  The script is still buildable with previous GEOS versions
  but you'll need 3.3.0+ at runtime for most uses.

=Building

  To build the topology support:
 
  $ make

=Testing

  To run regression tests:

  $ make check

=Install, upgrade, uninstall

To enable topology support:

	$ psql -f topology.sql <your_postgis_enabled_db>

	It will create a 'topology' schema in <your_postgis_enabled_db>
	hosting all the topology functions. To be run with db-owner perms.
	Remember to grant execute to users.
	
To uninstall:

	psql -c 'drop schema topology cascade'

Upgrading currently requires uninstall.

=Usage

Topology data are stored in named SCHEMAs, where the topology
name is the name of the SCHEMA containing its data.

A catalogue of avalable topologies is kept under the
"topology"."topology" table.

==Creating a topology

To create a topology:

	SELECT topology.CreateTopology(<name>, [srid], [tolerance]);

Example:

	SELECT topology.CreateTopology('test_schema', 4326 , 0.0001);
	or
	-- unknown srid, 0 tolerance
	SELECT topology.CreateTopology('test_schema');

	NOTE: the new schema ('test_schema' in example) will be create
	      so it must not exist before.

==Destroying a topology

To destroy a topology:
		
	SELECT topology.DropTopology(<name>);

==Loading topology data

To load topology data in a topology you can use INSERT
statements filling up the Edge, Node and Face relations
under you topology schema:


	* Edge
	 * edge_id integer PRIMARY KEY
	 * start_node integer REFERENCES Node.node_id)
	 * end_node integer REFERENCES Node.node_id)
	 * next_left_edge integer REFERENCES abs(Edge.edge_id)
	 * next_right_edge integer REFERENCES abs(Edge.edge_id)
	 * left_face integer REFERENCES Face.face_id
	 * right_face integer REFERENCES Face.face_id
	 * geom geometry ( a linestring )
	

	* Node
	 * node_id integer PRIMARY KEY
	 * containing_face integer REFERENCES Face.face_id
	 * geom geometry ( a point )

	* Face
	 * face_id integer PRIMARY KEY
	 * mbr box2d ( can be NULL )

The next_*_edge of an edge is the edge you encounter next while going
around the specified face (right or left) in counterclockwise order
(so that the face is on your left). Note that due to this definition
the edge being considered is traversed in reverse order when traversing
its "right" face. The values are signed to indicate wheter the next edge
will be traversed in its original or reversed orientation.

More details on semantic are contained in the SQL/MM specification, which
this implementation follows as for these views structure.

==Validating topology data

To verify validity of a topology:

	SELECT * FROM topology.ValidateTopology(name);

==Defining TopoGeometry objects

Currently, TopoGeometry objects can only be defined by specifying their
component topology elements. We do support both basic TopoGeometry
and hierarchical TopoGeometry. Basic TopoGeometry objects are those
composed by base topolocal elements (faces, edges, nodes). Hierarchical
TopoGeometry objects are composed by other TopoGeometry objects.

Each TopoGeometry object belongs to a specific Layer of a specific
Topology. Before creating a TopoGeometry object you need to create
its Layer in the Topology. A Topology Layer is an association of
a feature-table with the topology. It also contain type and hierarchy
information. We create a layer using the AddTopoGeometryColumn() function:

	topology.AddTopoGeometryColumn(topology_name,
		schema_name, table_name, column_name, feature_type,
		[child_layer])

The function will both add the requested column to the table and add
a record to the topology.layer table with all the given info.

If you don't specify [child_layer] (or set it to NULL) this layer
would contain Basic TopoGeometries (composed by primitive topology
elements). Otherwise this layer will contain hierarchical TopoGeometries
(composed by TopoGeometries from the child_layer).

Once the layer is created (it's id is returned by the AddTopoGeometryColumn
function) you're ready to construct TopoGeometry objects in it: 

  	topology.CreateTopoGeom(

    		topology_name,

    		feature_type,	-- 1:[multi]point, 2:[multi]line,
		             	-- 3:[multi]poly, 4:collection

    		layer_id,    	-- as returned by AddTopoGeometryColumn

		TopoElementArray);

The TopoElementArray type is a bidimensional array of integers.
Value semantics depend on the type of the layer associated with
the TopoGeometry object. For Basic TopoGeometry objects this would
be:
	{{element_type, element_id}, ...}

For Hierarchical TopoGeometry objects this would be:

	{{child_layer_id, topogeoemtry_id}, ...}

==Getting simple Geometry values from TopoGeometry objects

You currently need to explicit call the TopoGeometry=>Geometry
cast function. This will probably be made implicit when the
code is more tested:

	SELECT topology.Geometry(TopoGeometry);

=Issues

==Topology tolerance

GEOS (and JTS) often fail due to input precision.
The CreateTopogeo() function currently accept a precision
specification, we might use this to enforce a precision
to the topology element geometries, by mean of SnapToGrid
calls, or alternatively, force use of a specific PrecisionModel
when using GEOS function. The former seems cleaner, but would
require a trigger to run on all inserts, even when the geometry
being input has already been snapped by caller.

==ST_GetFaceGeometry() implementation

The ST_GetFaceGeometry() function is currently implemented 
as a call to polygonize() receiving all edges with the
given Face on the left or right side. This reduces the number
of SQL queries to 1, but makes it hard to detect any
inconsistency in the underlying topology.
Also, the polygonize() function does not use *any* of the
metadata informations in the Edge table, so replacing it
with a more topology-aware function could speed it up.

==ValidateTopology() performance

The ValidateTopology() function, as for SQL/MM specification
uses ST_GetFaceGeometry() to check for Within() and Overlap()
conditions. This is an expensive task, and might be replaced
by topology-aware replacement of the two predicates. The
Face geometries might also be cached, but that might still
be slower then overloading the predicates.

==Topology table constraints 

In addition to the constraints defined in SQL/MM specification,
this implementation adds constraints to enforce Node and Edge
geometry types to be 'POINT' and 'LINESTRING' respectively.

===SRID constraint

One of the things that the ValidateTopology is required to
check is SRID consistency: all geometry value must be in
the same SRID. I avoided that check as any SRID mismatch
would be cought by spatial predicates and will result
in an exception being thrown.

We might add the check as a constraint on the topology tables
instead, possibly dropping the SRID after checking it. This
would reduce database, while topology SRID could be re-attached
to any output geometry reading it from the topology.topology
metadata table.

