Update of "topo-advanced"
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview

Artifact ID: d18b2d9912f37fdffd12154f3bf5fab8af3b3d42
Page Name:topo-advanced
Date: 2015-11-16 19:36:04
Original User: sandro
Parent: c15fac57cb65ab441e8072262af019c2dfc44b31 (diff)
Next 6f7a773f5cdcded8b13b08cb1fae4967a3fa25f0
Content

Topology-Geometry: an advanced tutorial

previous page back to index next page

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:
  1. 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.
  2. uncompress the downloaded db-file (tuscany-census-2011.sqlite).
  3. 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.
  1. 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).
  2. 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).
  3. finally we'll detach the now useless external db-file.

TopoLayers / TopoFeatures: layout of DB Tables and corresponding relationships

<topo-prefix>_topolayers
SELECT * FROM census2011_topolayers;
The TopoLayers table contains a distinct row for every TopoLayer defined on the current Topology.

Each TopoLayer is identified by an id and by a name; both are required to by unique values.
"census2011_topolayers"
topolayer_id topolayer_name
1census_areas
2ppl
3com
4prov
5reg
<topo-prefix>_topofeatures_<topolayer-id>
SELECT * FROM census2011_topofeatures_2;

SELECT * FROM census2011_topofeatures_4;
The same Topology can contain more than a single TopoFeatures table, and each TopoFeatures table corresponds to a single TopoLayer.
Every table one has a specific layout on its own (strictly reflecting the information attributes for each layer), anyway all them will have a unique TopoFeature identifier (fid) acting in the Primary Key role.
The correspondency between table names and TopoLayers is established by appending a numeric suffix to the common name that must exactly match the topoloayer_id value declared in the TopoLayers main table.

As is shown in this example the first table census2011_topofeatures_2 (topolayer_id=2) contains all TopoFeatures associated to the TopoLayer ppl (Populated Places).

The second table census2011_topofeatures_4 (topolayer_id=4) contains all TopoFeatures associated to the TopoLayer prov (Provinces).
"census2011_topofeatures_2"
fid cod_ppl cod_com name pop_2011 m_2011 f_2011
120514270545001Albiano Magra1907919988
220514270645001Aulla432120462275
320514271045001Caprigliola482226256

10181410775415100007Sasseta285137148
10191410785415100007Terrigoli537264273

"census2011_topofeatures_4"
fid cod_prov cod_reg name abbrev pop_2011 m_2011 f_2011
1459Massa CarraraMS19965095754103896
2469LuccaLU388327186183202144
3479PistoiaPT287866138054149812

9539GrossetoGR220564105585114979
101009PratoPO245916119088126828
<topo-prefix>_topofeatures
SELECT * FROM census2011_topofeatures;
The TopoFeatures-geometries table is intended to permanently store all relations between TopoFeatures and Topology primitives required in order to correctly build the expected output Geometry for each TopoFeature.
  • uid is the Primary Key, and is simply intended to be an unique identifier for each row but doesn't intends any special meaning.
  • node_id, edge_id and face_id are Foreign Keys directly referencing a Topology primitive; two of these values are always expected to be NULL, and only one is expected to effectively reference a Topology primitive depending on its type.
  • topolayer_id and fid together are intended to establish a relational reference to some specific TopoFeature.

Example #1: all Topology primitives directly referenced by rows declaring topolayer_id=2 and fid=3 must be aggregated in order to build the output Geometry corresponding to the Populated Place of Caprigliola.
Example #2: all primitives referenced by rows declaring topolayer_id=4 and fid=9 must be aggregated in order to build the output Geometry corresponding to the Province of Grosseto.
"census2011_topofeatures"
uid node_id edge_id face_id topolayer_id fid
1NULLNULL111
2NULLNULL212
3NULLNULL313

28870NULLNULL28864128867
28871NULLNULL28868128868

Final remarks

  1. both TopoGeo_CreateTopoLayer() and TopoGeo_InitTopoLayer() will register the TopoLayer into the TopoLayers table, and will create and populate the corresponding TopoFeatures table by importing all information attributes for each Feature defined by the reference table (or reference view).
  2. anyway only TopoGeo_CreateTopoLayer() will automatically populate the TopoFeatures-geometry table, and will do such a thing by identifying all relationships existing between the Geometries found into the reference table or view and the Topology primitives via the intermediation of the TopoSeeds.
  3. on the other hand TopoGeo_InitTopoLayer() will never attempt to identify the relationships intercurring between output Geometries and Topology primitives. This task will always be deferred.
    You could e.g. manually cherry pick all Topology primitives corresponding to a single TopoFeature; or more probably you could perform this task in a second time by executing some appropriate SQL statement (as we'll seen soon in the next example).


TopoGeo_ExportTopoLayer: exporting a full TopoLayer into a GeoTable

exporting the Census Areas TopoLayer
We'll start by exporting first the only completely defined TopoLayer we have at this point in the test DB-file, i.e. census_areas
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.
elba-chloropleth


Building a full hierarchy of Administrative Levels by SQL statements

As we've already seen before we are now expected to complete someway the TopoFeatures definitions supporting the Populated Places, Municipalities, Provinces and Region TopoLayers we've previously created by calling TopoGeo_InitTopoLayer().

Happily enough all these administrative levels are simply based on direct aggretations of Census Areas, so we just have to execute few appropriate SQL statements.
INSERT INTO census2011_topofeatures
SELECT NULL, c.node_id, c.edge_id, c.face_id, 2, a.fid
FROM census2011_topofeatures_2 AS a
JOIN census2011_topofeatures_1 AS b ON (b.cod_ppl = a.cod_ppl)
JOIN census2011_topofeatures AS c ON (c.topology_id = 1 AND c.fid = b.fid);
  • census2011_topofeatures_1 is the TopoFeatures table corresponding to Census Areas.
  • census2011_topofeatures_2 is the corresponds to Populated Places; the clause b.cod_ppl = a.cod_ppl will relationally join each Populated Place to its underlaying Census Areas.
  • so we can duly insert into the TopoFeatures-geometry table (i.e. census2011_topofeatures) a new level of references to Topology primtives by simply copying all definitions already stored into the previous hierarchical level.
    And to do such a thing we simply have to read from topolayer=1 then inserting into topolayer=2 after setting the appropriate fid values.
    Really not a difficult task.
INSERT INTO census2011_topofeatures
SELECT NULL, c.node_id, c.edge_id, c.face_id, 3, a.fid
FROM census2011_topofeatures_3 AS a
JOIN census2011_topofeatures_1 AS b ON (b.cod_com = a.cod_com)
JOIN census2011_topofeatures AS c ON (c.topology_id = 1 AND c.fid = b.fid);
We can adopt exactly the same identical approach in order to complete topolayer=3 corresponding to Municipalities.
INSERT INTO census2011_topofeatures
SELECT NULL, c.node_id, c.edge_id, c.face_id, 4, a.fid
FROM census2011_topofeatures_4 AS a
JOIN census2011_topofeatures_3 AS b ON (b.cod_prov = a.cod_prov)
JOIN census2011_topofeatures AS c ON (c.topology_id = 3 AND c.fid = b.fid);
More or less the same is for deriving topolayer=4 corresponding to Provinces; this time we'll simply aggretate the underlying Municipalities from topolayer=3. We can adopt exactly the same identical approach in order to complete topolayer=3 corresponding to Municipalities.
INSERT INTO census2011_topofeatures
SELECT NULL, c.node_id, c.edge_id, c.face_id, 5, a.fid
FROM census2011_topofeatures_5 AS a
JOIN census2011_topofeatures_4 AS b ON (b.cod_reg = a.cod_reg)
JOIN census2011_topofeatures AS c ON (c.topology_id = 4 AND c.fid = b.fid);
And finally we can derive topolayer=5 corresponding to Regions by directly aggregating the underlying Provinces from topolayer=4.

step #1: exporting the Region TopoLayer
SELECT TopoGeo_ExportTopoLayer('census2011', 'reg', 'out_reg_2011', 1);
We are now definitely ready to export any other Administrative Level.
For the sake of clearity we'll follow a top-bottom order, so we'll start by exporting first the whole Tuscany.
topolayer-region
step #2: exporting the Provinces TopoLayer
SELECT TopoGeo_ExportTopoLayer('census2011', 'prov', 'out_prov_2011', 1);
We'll continue by exporting all the Tuscany Provinces.
topolayer-provinces
step #3: exporting the Municipalities TopoLayer
SELECT TopoGeo_ExportTopoLayer('census2011', 'com', 'out_com_2011', 1);
Then we'll export all the Tuscany Municipalities.
For betterl clearity the figure shows a magnified detail centered around the Island of Elba.
topolayer-municipalities
step #4: exporting the Populated Places TopoLayer
SELECT TopoGeo_ExportTopoLayer('census2011', 'ppl', 'out_ppl_2011', 1);
And we'll finally export all Populated Places.

Conclusion: we started by importing into a Topology just a single layer (Census Areas) and now we have a complete set of Administrative Boundaries:
topolayer-populated-places

previous page

back to index next page