Dans la base de données OpenStreetMap, les informations sur les entités administratives (communes, départements, etc.) se trouvent généralement sur le noeud
place=*
qui est membre de la relation du type boundary
avec le rôle admin_centre
. Si on a besoin de ces informations, comme par exemple population ou name:xx, pour choisir le style du polygone ou y assigner un libellée, les structures des données crées par les outils ne permettent pas d'accéder aux informations du noeud admin_centre
à partir du polygone. Cet article présente des solutions pour les bases de données PostGis crées avec osm2pgsql
et les fichiers shape crées avec osmium.PostGis / osm2pgsql
osm2pgsql reporte bien les attributs des chemins «outer» sur le polygone qu'il crée pour une relation du type «boundary» mais pas les attributs du centre administratif. En mode «slim» osm2pgsql crée bien une table<prefix>_rels
qui contient pour chaque relation ses attributs et ses membres avec le rôle et l'id, mais sous une forme qui n'est pas directement exploitable avec SQL. Un exemple :
psql -d osm -c "select members from planet_osm_rels\
where hstore(tags)->'name'='Corneilla-la-Rivière';"
members
----------------------------------------------------------------------------
{w121772197,outer,w100006391,outer,w121772204,outer,n287557758,admin_centre}
On trouve les membres d'une relation dans un array, deux valeurs par membre, le type et l'identificateur du membre et son rôle. Une petite fonction SQL permet d'acceder à l'identificateur de l'admin_centre :
CREATE OR REPLACE FUNCTION admin_centre(anyarray)
RETURNS bigint
LANGUAGE sql
AS $function$
SELECT cast(substring($1[i] from 2) as bigint)
FROM generate_series(array_lower($1,1),array_upper($1,1),2) i
WHERE $1[i+1]='admin_centre';$function$
Cette fonction permet de faire des requêtes sur les relations des limites administratives avec les attributs de leurs centres administratifs :
select poly.name, point.name, point."name:ca", point.population
from planet_osm_rels r,
planet_osm_polygon poly,
planet_osm_point point
where poly.admin_level='8'
and admin_centre(r.members) = point.osm_id
and r.id = -poly.osm_id ;
Si ce type de requête n'est pas suffisamment efficace on peut copier les attributs des noeuds sur les polygones ou bien créer un table de références :
create table admin_rel
as select -id as rel_id,
admin_centre(members) as admin_centre
from planet_osm_rels
where hstore(tags)->'boundary'='administrative' and
hstore(tags)->'admin_level' in ('8','6','4');
fichiers «shape»
On utilise pour cela l'outilosmjs
et QGis. osmjs
basé sur la bibliothèque osmium
permet d'extraire des objets d'un fichier osm sous forme de fichier «shape». Comme osm2pgsql
, cet outil crée des polygones pour les relations «boundary» mais ne tient pas compte du rôle admin_centre
. Par contre il est possible de produire un fichier csv qui contient les identificateurs des polygones et de leurs noeuds admin_centre
:
/*
Osmium Javascript Example: shape_export.js
run with: osmjs -2 -m -l sparsetable -j shape_export.js OSMFILE
*/
var shp_places = Osmium.Output.Shapefile.open('./places', 'point');
shp_places.add_field('id', 'string', 12);
shp_places.add_field('type', 'string', 32);
shp_places.add_field('name', 'string', 32);
var shp_boundaries = Osmium.Output.Shapefile.open('./boundaries', 'polygon');
shp_boundaries.add_field('id', 'integer', 10);
shp_boundaries.add_field('type', 'string', 32);
shp_boundaries.add_field('boundary', 'string', 255);
shp_boundaries.add_field('admin_level', 'string', 255);
var csv_file = Osmium.Output.CSV.open("./rels.csv");
var node_tags = {
place: { village: 'villaget', city: 'city', town: 'town'} //,
//shop: { supermarket: 'supermarket' }
}
Osmium.Callbacks.init = function() {
print("Init");
}
Osmium.Callbacks.node = function() {
for (var key in this.tags) {
if (node_tags[key]) {
var type = node_tags[key][this.tags[key]];
if (type) {
shp_places.add(this.geom, { id: this.id, type: type, name: this.tags.name });
}
}
}
}
Osmium.Callbacks.area = function() {
if (this.tags.boundary) {
shp_boundaries.add(this.geom, { id: this.id, type: this.tags.boundary, admin_level: this.tags.admin_level});
}
}
Osmium.Callbacks.relation = function() {
for (var key in this.members) {
for (var key2 in this.members[key]) {
if (key2=='role' && this.members[key].role=='admin_centre'){
csv_file.print(this.id*2+1, this.members[key].ref,
this.members[key].role, this.members[key].type);
}
}
}
}
Osmium.Callbacks.end = function() {
shp_places.close();
shp_boundaries.close();
csv_file.close();
print("Done");
}
Ce scripte produit un fichier shape avec les polygones, un avec les noeuds et und fichier csv qui relie les uns aux autres par leurs identificateurs. Il tient compte du fait que osmjs
assigne des pseudo-identificatuers aux polygones qu'il calcule avec la formule [2 * osm_id de la relation + 1
.
On charge ces trois fichers dans QGis. On crée une jointure des données csv avec la couche des noeuds et ensuite une jointure de la couche des polygones avec les données csv. La couche polygone a maintenant accès aux données des noeuds associés. Si on enregistre la couche polygone dans un ficher au format shape, ce fichier contiendra toutes les données et peut être utilisé avec mapnik / tilemill.