Topology-Geometry: an advanced tutorial
|
TopoLayers and TopoFeatures
In the previous tutorial we've examined a first couple of SQL functions intended to export a GeoTable out from an existing Topology: TopoGeo_ToGeoTable() and TopoGeo_ToGeoTableGeneralize().
Anyway SpatiaLite supports an more sophisticated (and complex) approach based on TopoLayers and TopoFeatures specifically intended to support a very flexible mechanism for exporting a full set of GeoTable(s) directly deriving from a Topology.
a conceptual reference framework
- an ISO Topology is just intended to support a consistent set of Nodes, Edges and Faces primitives fully covering the plane.
Topology primitives correspond to pure geometries, and can never be directly associated to a corresponding set of information attributes.
Both Node and Edge primitives directly correspond to a real geometry, but Face primitives simply correspond to a virtual geometry thus necessarily requiring to be dynamically recontructed every time that they are referenced (and this could easily become a real bottleneck).
- on the other hand a GeoTable (aka layer, as in the common GIS parlance) is always based on many distinct features, and for each feature a Geometry and an associated set of information attributes are expected to be declared.
- there is further difference to be taken in proper account: Topology primitives necessarily are elementary. Feature Geometries can usually represent some complex type: MULTIPOINT, MULTILINESTRING, MULTIPOLYGON and, may be, GEOMETRYCOLLECTION. So it should be absolutely clear that a Feature Geometry does not necessarily corresponds to a single Topology primitive ; a Feature Geometry could easily be derived from aggregating many different Topology primites.
- that's not all: many different GeoTables could evenatually be derived from a single Topology; and the same Topology primitive could play a very different role in everyone of these GeoTables.
Just a basically simple example: imagine a Topology corresponding to some cadastral map. We'll surely have many potential layers: buildings, agricultural land, populated places, administrative boundaries, roads, ponds, rivers, fences and so on.
In such a context a fence could easily correspond to a Feature within the "fences" layer, could probably delimit two adjacent agricultural areas and could eventually be part of some administrative boundary.
- TopoLayers and TopoFeatures represent a complex and flexible structure intended to establish permanent explicit correspondences between Topology Primitives and GeoTable Features.
- each TopoLayer is uniquely identified by its name and directly corresponds to a single GeoTable to be exported from the Topology
An arbitrary number of TopoLayers can be created on the same Topology, and each one of them will act as a separate container.
- each TopoFeature is uniquely identified by its fid (feature-id) and corresponds to a single Feature containing an individual set of information attributes.
The Geometry for each TopoFeature is always indirectly defined by specifying a list of Topology primitives individually referenced by their IDs.
Such a geometry obviously is a virtual one, and will be actually materialized (by aggregating all referenced Topology primitives) only when exporting the destination GeoTable.
- The TopoLayers / TopoFeatures structure is practically implemented as a set of several closely related DB-tables )we'll examine later their respective layouts in full detail):
- <topo-prefix>_topolayers: this first table simply is a catalog of all TopoLayers supporting the same Topology.
Each TopoLayer is identified by its name and by its ID; both identifiers are granted to be unique.
- <topo-prefix>_topofeatures: this second table is intended to permanently store all cross-references existing between Topology primitives and TopoFeatures.
- <topo-prefix>_topofeatures_<topolayer-id>: for each single TopoLayer a separate table is required. The actual correspondence is established via the TopoLayer-ID suffix.
All these tables are intended to permanently store the information attributes for each TopoFeature in the same TopoLayer.
Different TopoLayers will obviosuly support a different set of information attributes thus requiring an individual table layout.
Anyway all these tables are always expected to declare a Primary Key of the INTEGER type named fid and intended to be an unique identifier for each TopoFeature.
- Several SQL functions are specifically intended to support processing operations based on TopoLayers and TopoFeatues; we'll examine later all them in full detail.
a quick practical exercise
Prerequisites:
- download the sample DB-file from here
It contains Census data (2011) kindly released by ISTAT under CC-BY license terms.
The original datasets have been slightly rearranged in a more convenient form.
All geometries are in the SRID 32632 (WGS 84 / UTM zone 32N):
- census_2011: all Census Areas (2011) covering Tuscany.
Note: several Census Areas are completely uninhabited (lakes, marshlands, high mountains and alike).
- ppl_2011: Populated Places (defined as an aggregation of Census Areas).
Note: not all Census Areas belong to a Populated Place: there are many self-standing dispersed rural areas.
- com_2011: Tuscany Municipalities / Local Councils 2011 (defined as an aggregations of Census Areas).
- com_2014_15: few new Municipalities created during years 2014/15 by merging pre-existing smaller Municipalities.
- prov_2011: Tuscany Provinces / Counties (defined as an aggregation of Municipalities).
- reg_2011: Tuscany Region (defined as an aggregation of Provinces).
- just census_2011 alone supports geometries; any other administrative level is simply defined by relational codes.
- uncompress the downloaded db-file (tuscany-census-2011.sqlite).
- now you can finally start a SpatiaLite session using your preferred SpatiaLite front end tool:
- Attention: you must not directly connect to tuscany-census-2011.sqlite; you are expected instead to connect a new (empty) DB-file named tuscany-topo-2011.sqlite
SELECT CreateTopology('census2011', 32632, 0, 0);
1
ATTACH DATABASE "./tuscany-census-2011.sqlite" AS istat;
SELECT TopoGeo_FromGeoTable('census2011', 'istat', 'census_2011', NULL, 0, 512, -1);
1
SELECT ST_ValidateTopoGeo('census2011');
NULL
SELECT * FROM TEMP.census2011_validate_topogeo;
SELECT TopoGeo_CreateTopoLayer('census2011', 'istat', 'census_2011', NULL, 'census_areas');
1
SELECT TopoGeo_InitTopoLayer('census2011', 'istat', 'pop_ppl_2011', 'ppl');
1
SELECT TopoGeo_InitTopoLayer('census2011', 'istat', 'pop_com_2011', 'com');
1
SELECT TopoGeo_InitTopoLayer('census2011', 'istat', 'pop_prov_2011', 'prov');
1
SELECT TopoGeo_InitTopoLayer('census2011', 'istat', 'pop_reg_2011', 'reg');
1
DETACH DATABASE istat;
We'll start this practical tutorial by duly replicating the same steps we've already examined in the intermetiate tutorial:
- we'll create a new 2D Topology named census2011 and located into SRID 32632.
- then we'll attach the tuscany-topo-2011.sqlite external DB-file.
- now we'll populate the census2011 Topology by importing the istat.census_2011 GeoTable, and then we'll immediatly check if this Topology is fully valid.
Now we are finally ready to start defining all TopoLayers based on the census2011 Topology; each single TopoLayer will precisely represent some administrative level, and all TopoLayers alltogether will completely represent the whole Tuscan administrative hierarchy.
- so we'll duly invoke TopoGeo_CreateTopoLayer() in order to completely define a first TopoLayer representing Census Areas.
Recall: the istat.census_2011 is the unique real GeoTable we have in our initial dataset, because it contains both information attributes and geometries; and each Census Area is expected to directly correspond to a single Topology Face. (we'll examine later in more depth how TopoLayer / TopoFeature relationships have been actually defined).
- then we'll continue by defining several further TopoLayers respectively corresponding to Populated Places, Municipalities, Provinces and Region administrative levels.
Recall: all these administrative levels in the initial dataset are simply defined by relational codes intended to aggregate lower level entities; in this case there are no explicit geometries at all. So are are not directly allowed to create a fully defined TopoLayer, and calling TopoGeo_CreateTopolayer() is just impossible because we lack any appropriate Geometry column.
Anyway we can invoke TopoGeo_InitTopoLayer(); this will initialize an only partially defined TopoLayer, but we can easily complete in a second time any missing information so to get a properly working TopoLayer (as we'll see later in full detail).
- finally we'll detach the now useless external db-file.
TopoGeo_ExportTopoLayer: exporting a full TopoLayer into a GeoTable |
SELECT TopoGeo_ExportTopoLayer('census2011', 'census_areas', 'out_census_2011', 1);
As you can easily check by yourself a new GeoTable named out_census_2011 has been created by TopoGeo_ExportTopoLayer():
- this GeoTable contains all TopoFeatures defined into the TopoLayer.
- each TopoFeature faithfully preserves its initial information attributes.
- all Geometries are precisely built by aggregating the corresponding Topology primitives as specified by TopoLayer / TopoFeatures relationships.
The image examplies a choropleth centered around the Island of Elba and based on the out_census_2011 GeoTable: all Census Areas are displayed by adopting a colour directly corresponding to their population density.
|
|
TopoLayers / TopoFeatures: layout of DB Tables and corresponding relationships
<topo-prefix>_topolayers e.g. "census2011_topolayers"
topolayer_id |
topolayer_name |
1 | census_areas |
2 | ppl |
3 | com |
4 | prov |
5 | reg |
<topo-prefix>_topofeatures e.g. "census2011_topofeatures"
uid |
node_id |
edge_id |
face_id |
topolayer_id |
fid |
1 | NULL | NULL | 1 | 1 | 1 |
2 | NULL | NULL | 2 | 1 | 2 |
3 | NULL | NULL | 3 | 1 | 3 |
|
28870 | NULL | NULL | 28864 | 1 | 28867 |
28871 | NULL | NULL | 28868 | 1 | 28868 |
<topo-prefix>_topofeatures_<topolayer-id> e.g. "census2011_topofeatures_1"
fid |
section_id |
cod_com |
cod_ppl |
pop_2011 |
m_2011 |
f_2011 |
1 | 450010000001 | 45001 | 205142706 | 10 | 7 | 3 |
2 | 450010000002 | 45001 | 205142706 | 155 | 69 | 86 |
3 | 450010000003 | 45001 | 205142706 | 208 | 97 | 111 |
|
28867 | 1000070000064 | 100007 | NULL | 0 | 0 | 0 |
28868 | 1000070000066 | 100007 | 1410775412 | 0 | 0 | 0 |
|