OpenStreeMap (OSM) constitue une formidable base de données cartographiques. La multitude de participants au projet permet actuellement d’avoir des données particulièrement à jour (en tout cas en France).
J’ai récemment eu besoin de créer des cartes de randonnées sur le territoire de la commune de Lucinges (74). Je me suis donc basée sur les données d’OSM qui étaient plus à jour que celles fournies par l’IGN. Voici les différentes étapes que j’ai suivit pour exporter puis exploiter les données.
Export des données
Les données d’OSM peuvent être exportées de différentes façons, soit depuis la base de données officielle, soit à partir de sites qui effectuent des copies de cette base.
Voici plusieurs sources :
- Le site officiel d’OSM qui permet d’exporter selon une emprise rectangulaire : https://www.openstreetmap.org/export
- L’API officielle d’OSM : Overpass, qui permet d’exporter selon une emprise mais qui peut aller beaucoup plus loin (avec notamment un filtrage des données) : https://overpass-api.de/
- Planet OSM qui fournit des jeux de données de la base complète à différent instants : https://planet.openstreetmap.org/
- Geofabrik qui fournit des jeux de données selon différentes emprises (continent, pays, région…) : https://download.geofabrik.de/
- Protomaps qui permet d’exporter les données suivant une emprise polygonale (pas forcément rectangulaire) : https://protomaps.com/extracts/
- Hot Export qui permet d’exporter des données selon une emprise polygonale et sous différents formats : https://export.hotosm.org/
Voici un exemple à partir du site officiel d’OSM et de l’API Overpass :
- Sur le site https://www.openstreetmap.org/export, tracez l’emprise d’export souhaité.
- Cliquez sur le bouton « exporter » situé sur le panneau de gauche.
Notez que si l’emprise est trop grande, un message vous indique que vous ne pouvez exporter. Cliquez alors sur le lien « API Overpass » sur le panneau de gauche.
Ce lien génère une requête Overpass sur l’emprise dessinée ce qui permet de télécharger des données sur une emprise plus importante. - Télécharger le fichier proposé. Attention, le fichier ne possède aucune extension, il faut l’ajouter manuellement en renommant le fichier :
.osm
.
Il est également possible de faire un export sur une emprise spécifique via le site protomaps, l’intérêt de celui-ci est de pouvoir utiliser une emprise plus précise que le rectangle englobant de l’outil précédent :
- Sur le site https://protomaps.com/extracts/ cliquez sur « draw polygon » afin de tracer l’emprise d’extraction des données.
- Cliquez sur « Create extract ».
- Téléchargez le fichier
.osm.pbf
.
Notez que vous pouvez également récupérer l’emprise de votre polygone en geojson.
Import des données dans PostgreSQL
Prérequis
L’import des données implique d’avoir à disposition une base PostgreSQL (de préférence en version 11 ou supérieur) dont l’encodage est l’UTF8 et avec les extensions suivantes :
- PostGIS (de préférence en version 2.4 ou supérieur).
- hstore : type de stockage de données sous la forme clé:valeur (similaire au json pour ceux qui connaissent).
Le traitement des données se fait via un utilitaire en ligne de commande : osm2pgsql.
osm2pgsql requiert au minimum 2 Go de mémoire vive et un système 64 bit.
Principes de fonctionnement
Pour correctement utiliser osm2pgsql, il faut bien comprendre son fonctionnement.
L’import des données se déroule en trois grandes étapes :
- La lecture des données.
- L’analyse des relations entre les différents objets (points, lignes, relations).
- La transformation des données et leur chargement dans la BDD.
Il faudra donc préciser différentes options pour chacune de ces étapes dans la ligne de commande.
voici Voici deux exemples d’utilisation :
# Exemple d'import osm2pgsql.exe --host 127.0.0.1 --port 5432 --username postgres --database osm --slim --hstore --input-reader pbf "C:\Users\emplacement\mon_fichier.osm.pbf" # Exemple de mise à jour osm2pgsql.exe --host 127.0.0.1 --port 5432 --username postgres --password --database osm --append --slim --hstore --input-reader pbf "C:\Users\emplacement\mon_fichier.osm.pbf"
Lecture des données (input)
Plusieurs modes de fonctionnement sont possibles :
- La création d’une base de données.
- La mise à jour d’une base de données (non abordé dans cet article).
La mise à jour des données d’une base ne sera pas abordée, elle repose sur le téléchargement des « fichiers diff », qui contiennent les modifications apportées dans OSM.
Le format des fichiers lus est déduit de l’extension mais il peut être forcé si besoin.
osm2pgsql permet d’importer plusieurs fichiers en une seule fois, par exemple plusieurs fichiers contenant différentes emprises, le tout sans dupliquer les objets qui seraient contenus dans plusieurs fichiers à la fois (objets en limite d’emprise par exemple). Cependant, tous les fichiers doivent partager le même horodatage d’extraction des données. Sinon, il serait possible d’avoir plusieurs version d’un même objet ce qui ferait échouer l’import.
Analyse des relations (middle)
osm2pgsql réalise une analyse des relations entre les différents objets constituants la données : les lignes, les points et les relations entre ces éléments. Le but est de pouvoir créer les objets voulus dans la sortie.
Pour cela, les données vont être stockées dans un cache temporaire qui peut être dont l’emplacement peut être définit. Il sera ainsi :
- Soit en mémoire vive (par défaut).
- Soit en BDD PostgreSQL.
- Soit dans un fichier à un emplacement défini (recommandé uniquement pour des imports de planète entière).
La création du cache entraine une consommation d’espace, selon la quantité de mémoire vive disponible sur la machine, il pourra être préférable de stocker le cache dans la BDD ou dans un fichier.
Afin de pouvoir mettre à jour la base, il est nécessaire de conserver le cache. Cela implique donc là aussi le stockage de celui-ci dans la BDD ou dans un fichier.
Différentes options permettent donc de gérer où stocker le cache et de quelle façon.
Import des données en BDD (output)
L’import des données peut être fait de différentes façons. On dit qu’il existe plusieurs sorties :
- La sortie flex : il s’agit de la sortie avec le plus de possibilités et permettant de choisir exactement la façon dont les données doivent être importer en base.
- La sortie pgsql : sortie originale de l’utilitaire, les possibilités offertes sont limitées.
- La sortie gazetteer : les données sont préparées pour leur utilisation avec l’outil de géocodage Nominatim uniquement.
- La sortie null : aucune données ne sont écrites, cette sortie est réservée pour les tests. Les données de cache sont conservées.
Les sorties flex et pgsql reposent sur l’utilisation d’un fichier de configuration (appelé fichier de style dans le cas de la sortie pgsql). Ces fichiers permettent de définir exactement la structure des tables qui seront créées/alimentées par l’utilitaire.
Cette page traitera uniquement de la sortie flex.
Utilisation
Ligne de commande
Voici les principales options qui peuvent être utilisées avec l’utilitaire :
Options générales :
-h
ou--help
: aide.-v
ou--verbose
: sortie verbale.--number-processes=n
: Nombre de processus parrallèles (défaut entre 1 et 4). Attention, chaque processus utilise plusieurs connexions avec la BDD, il faudra donc peut être vérifier la limite du nombre de connexion.-I
ou--disable-parallel-indexing
: Désactiver l’indexation concurrante des tables (les index seront créés les uns après les autres).
Options de connexion :
-H mon_hote
ou--host=mon_hote
: Hôte de la BDD.-P mon_port
ou--port=mon_port
: Port de la BDD.-d ma_bdd
ou--database=ma_bdd
: Nom de la BDD.-U mon_user
ou--username=mon_user
: Nom de l’utilisateur PostgreSQL.-W
ou--password
: Force la demande du mot de passe (sinon le mot de passe utilisé sera celui stocké dans la variable d’environnement PGPASSWORD).
Mode d’import des données :
-c
ou--create
: créer les données dans la base (supprime les données déjà présentes en base). Il s’agit du mode par défaut.-a
ou--append
: mettre à jour les données déjà présentes en base (obligatoirement avec l’option -s décrite plus bas).
Options d’entrée (input) :
-r mon_format
ou--input-reader=mon_format
: Format d’entré.auto
: Détection automatique (défaut).o5m
xml
pbf
Gestion du cache (middle) :
-s
ou--slim
: stocker le cache dans la BDD.--flat-nodes=emplacement/nom_du_fichier
: stocker le cache dans un fichier.--drop
: supprimer le cache après l’import (valable pour les options--slim
et--flat-nodes
) (les mises à jour ne seront donc plus possibles).
Paramètres spécifiques pour l’option --slim
:
--middle-schema=mon_schema
: schéma dans lequel les tables seront stockées (par défautpublic
).-p mon_prefixe
ou--prefix=mon_prefixe
: préfixe des tables créées (par défautplanet_osm
).--tablespace-slim-data=mon_tablespace
: tablespace utilisé pour stocker les tables de données.--tablespace-slim-index=mon_tablespace
: tablespace utilisé pour stocker les index créés.-C n
ou--cache=n
: quantité en Mo de mémoire vive utilisable (par défaut n = 800).
Options de sortie (output) :
-O sortie
ou--output=sortie
: format de sortie à choisir parmi flex, pgsql (défaut), gazetteer, multi et null.-S emplacement_fichier_style
ou--style=emplacement_fichier_style
: emplacement du fichier de style (de configuration) pour les sorties flex et pgsql.
Paramètres spécifiques pour la sortie pgsql :
- Paramètres généraux :
--output-pgsql-schema=mon_schema
: nom du schéma dans lequel seront stockées les données finales (par défautpublic
).-G
ou--multi-geometry
: créer des objets avec des multi-geometries.-K
ou--keep-coastlines
: conserver les lignes de côte (supprimées par défaut).--reproject-area
: ajouter une colonne contenant l’aire de chaque objet calculée en utilisant les coordonnées mercator sphérique.
- Projection des données :
-l
ou--latlong
: stockage des données en latitude longitude (degrés).-m
ou--merc
: stockage des données en coordonnées mercator sphérique (défaut).-E
ou--proj num
: stockage des données dans la projection indiquée.
- Options hstore (stockage clé/valeur) :
-k
ou--hstore
: ajouter les tags sans colonne à une colonne additionnel de type hstore.--hstore-match-only
: ne conserver que les objets qui ont une valeur dans au moins une colonne (autre que la colonne hstore).-j
ou--hstore-all
: ajouter tous les tags dans une colonne de type hstore.-z "nom_du_tag"
ou--hstore-column="nom_du_tag"
: ajouter uniquement les tags correspondant à une colonne de type hstore (par exemple--hstore-column="name:"
permet de ne stocker que les tagsname:xx
dans cette colonne spécifique).--hstore-add-index
: ajouter un index à la colonne de type hstore.
- Options de performance :
-i mon_tablespace
ou--tablespace-index=mon_tablespace
: nom du tablespace contenant tous les index (cette option affecte aussi les index créés lors de l’étape d’analyse).--tablespace-main-data=mon_tablespace
: nom du tablespace contenant les tables.--tablespace-main-index=mon_tablespace
: nom du tablespace contenant les index des tables principales.
Voici un exemple de ligne de commande avec la sortie flex (l’ordre des paramètres n’a pas d’importance sauf le fichier à traiter qui doit être en dernier) :
osm2pgsql --verbose --create --input-reader=pbf --slim --middle-schema=osm_import --cache=8192 --output=flex --style="emplacement/config.lua" --host=127.0.0.1 --port=5432 --database=data_sig --user=postgres -W "emplacement/mon_fichier.osm.pbf"
Fichier de configuration flex
La sortie flex ne possède pas d’options spécifiques à passer en ligne de commande. Tous se fait donc dans un fichier de configuration rédigé en lua.
La documentation officielle contient de préciseuses informations mais voici un fichier de configuration permettant de démarrer rapidement.
Le principe du fichier est de décrire les éléments qui seront créés en base (les tables) et leur structure ainsi que la façon dont les objets issus du fichier à importer doivent être analysés et traités. Pour cela plusieurs éléments doivent être présents dans le fichier de configuration :
La définition des tables qui contiendront les données grâce aux fonctions suivantes :
osm2pgsql.define_table(NAME, COLUMNS[, OPTIONS])
) : définition d’une table (le type de table sera à déterminer dans les paramètres)osm2pgsql.define_node_table(NAME, COLUMNS[, OPTIONS])
: définition d’une table de point.osm2pgsql.define_way_table(NAME, COLUMNS[, OPTIONS])
: définition d’une table de ligne.osm2pgsql.define_relation_table(NAME, COLUMNS[, OPTIONS])
: définition d’une table de relation.osm2pgsql.define_area_table(NAME, COLUMNS[, OPTIONS])
: définition d’une table de surface.
Il est possible de définir autant de tables que nécessaire. Il n’y a pas de limite, le but est de générer votre propre modèle de données avec sa structure spécifique.
Le traitement à appliquer à chaque type d’objet à importer avec les fonctions suivantes :
osm2pgsql.process_node(object)
: fonction appelée pour le traitement de chaque point.osm2pgsql.process_way(object)
: fonction appelée pour le traitement de chaque ligne.osm2pgsql.process_relation(object)
: fonction appelée pour le traitement de chaque relation.
Une (ou plusieurs) fonction peut ne pas être définit, le type d’objet associé ne sera alors pas traité.
Le contenu de la fonction permet d’indiquer ce qui doit être fait avec l’objet en cours de manipulation :
- Écrire l’objet dans une ou plusieurs tables.
- Ne rien renvoyer (l’objet n’est pas intéressant).
- Transformer l’objet avant de l’écrire.
Attention, aucune fonction n’est appelée pour la suppression des objets (cas des mises à jour uniquement). L’utilitaire supprime automatiquement tout objet de la base dérivant d’un objet supprimé dans le fichier d’import.
Différentes fonctions de traitement que vous aurez créées spécifiquement selon vos besoins.
Exemple
Voici une exemple de ligne de commande associée à un fichier lua que vous pouvez utiliser, il permet la sortie de 3 tables (ponctuel
, ligne
, surface
) dont la structure reprendra la définition faite en début de fichier (voir détail des commentaires) et détaillée dans le chapitre suivant.
SET PGPASSWORD=postgres osm2pgsql ^ --verbose ^ --create ^ --input-reader=pbf ^ --slim ^ --middle-schema=osm_import_test ^ --cache=8192 ^ --number-processes=8 ^ --output=flex ^ --style="C:\Users\Arthur\Mon_chemin_perso\config.lua" ^ --host=127.0.0.1 ^ --port=5432 ^ --database=postgres^ --user=postgres ^ -W "C:\temp\mon_fichier_osm.osm.pbf"
-- Fichier de configuration pour l'import des données OSM avec osm2pgsql -- Testé avec osm2pgsql v1.10.0 -- Variables ------------ -- Projection utilisée local var_srid = 3857 -- Schéma de destination des données local var_schema = 'osm_data_test' -- Définition des tables de destintation ---------------------------------------- -- Pour chaque table, un ensemble de paramètres doit être défini. -- Concernant les colonnes, les règles suivantes s'appliquent : -- - Les colonnes id, tags et geom sont traitées spécifiquement et doivent être spécifiées comme dans l'exemple ci-après sans aucun changement. -- - Les colonnes spécifiées dans la partie "colonnes supplémentaires" récupèreront la valeur du tag du même nom. -- - Si l'option input_tag_name = 'my_name' est utilisée, alors c'est la valeur du tag 'my_name' qui sera récupéré dans l'attribut -- - Utilisez la valeur input_tag_name = '' (vide) pour que la colonne soit créée sans aucune récupération de valeur -- Attention, les tags récupérés sont retirés de la liste des tags disponibles, il n'est donc pas possible d'envoyer la valeur d'un tag dans deux colonnes sauf -- si vous ajoutez l'option grab_tag = false, dans ce cas, la valeur du tag est copiée mais le tag restant présent dans le pool de tags. -- Variable de type tableau qui contiendra la définition des tables à créer en base local var_tables = {} -- Table des ponctuels var_tables.ponctuel = { def = { -- Schéma contenant la table schema = var_schema, -- Nom de la table name = 'ponctuel', -- Gestion de la colonne d'identifiant osm ids = { type = 'node', id_column = 'osm_id' }, -- Liste des colonnes à créer columns = { -- Colonne d'identifiant (de type sérial donc gérée automatiquement) { column = 'id', sql_type = 'serial', create_only = true }, -- Colonne contenant les tags { column = 'tags', type = 'hstore' }, -- Colonnes supplémentaires (qui reprendront la valeur de certains tags) { column = 'amenity', type = 'text' }, { column = 'historic', type = 'text' }, { column = 'highway', type = 'text' }, { column = 'name', type = 'text', input_tag_name = '' }, { column = 'name_test', type = 'text', input_tag_name = 'name', grab_tag = false }, { column = 'name_test2', type = 'text', input_tag_name = 'name', grab_tag = false }, { column = 'natural', type = 'text' }, { column = 'place', type = 'text' }, { column = 'shop', type = 'text' }, { column = 'tourism', type = 'text' }, -- Colonne géométrique { column = 'geom', type = 'point', projection = var_srid }, }, -- Liste des index à créer indexes = { { column = 'geom', method = 'gist' }, { column = 'tags', method = 'gist' } } } } -- Table des lignes var_tables.ligne = { def = { -- Schéma contenant la table schema = var_schema, -- Nom de la table name = 'ligne', -- Gestion de la colonne d'identifiant osm ids = { type = 'way', id_column = 'osm_id' }, -- Liste des colonnes à créer columns = { -- Colonne d'identifiants (de type sérial donc gérée automatiquement) { column = 'id', sql_type = 'serial', create_only = true }, -- Colonne contenant les tags { column = 'tags', type = 'hstore' }, -- Colonnes supplémentaires (qui reprendront la valeur de certains tags) { column = 'admin_level', type = 'text' }, { column = 'aeroway', type = 'text' }, { column = 'boundary', type = 'text' }, { column = 'highway', type = 'text' }, { column = 'name', type = 'text' }, { column = 'railway', type = 'text' }, { column = 'waterway', type = 'text' }, -- Colonne géométrique { column = 'geom', type = 'multilinestring', projection = var_srid }, }, -- Liste des index à créer indexes = { { column = 'geom', method = 'gist' }, { column = 'tags', method = 'gist' } } } } -- Table des surfaces var_tables.surface = { def = { -- Schéma contenant la table schema = var_schema, -- Nom de la table name = 'surface', -- Gestion de la colonne d'identifiant osm ids = { type = 'area', id_column = 'osm_id' }, -- Liste des colonnes à créer columns = { -- Colonne d'identifiants (de type sérial donc gérée automatiquement) { column = 'id', sql_type = 'serial', create_only = true }, -- Colonne contenant les tags { column = 'tags', type = 'hstore' }, -- Colonnes supplémentaires (qui reprendront la valeur de certains tags) { column = 'building', type = 'text' }, { column = 'landuse', type = 'text' }, { column = 'leisure', type = 'text' }, { column = 'natural', type = 'text' }, { column = 'water', type = 'text' }, -- Colonne géométrique { column = 'geom', type = 'multipolygon', projection = var_srid }, }, -- Liste des index à créer indexes = { { column = 'geom', method = 'gist' }, { column = 'tags', method = 'gist' } } } } -- Liste des tags qui seront supprimés -- Ces tags ne sont pas utiles (principalement des tags utilisés pour la numérisations) -- Le caractère '*' permet de spécifier "n'importe quel(s) charactère(s) (possiblement au pluriel)" local var_delete_keys = { -- "mapper" keys 'attribution', 'comment', 'created_by', 'fixme', 'note', 'note:*', 'odbl', 'odbl:note', 'source', 'source:*', 'source_ref', -- Corine Land Cover (CLC) (Europe) 'CLC:*', -- Geobase (CA) 'geobase:*', -- CanVec (CA) 'canvec:*', -- osak (DK) 'osak:*', -- kms (DK) 'kms:*', -- ngbe (ES) -- See also note:es and source:file above 'ngbe:*', -- Friuli Venezia Giulia (IT) 'it:fvg:*', -- KSJ2 (JA) -- See also note:ja and source_ref above 'KSJ2:*', -- Yahoo/ALPS (JA) 'yh:*', -- LINZ (NZ) 'LINZ2OSM:*', 'linz2osm:*', 'LINZ:*', 'ref:linz:*', -- WroclawGIS (PL) 'WroclawGIS:*', -- Naptan (UK) 'naptan:*', -- TIGER (US) 'tiger:*', -- GNIS (US) 'gnis:*', -- National Hydrography Dataset (US) 'NHD:*', 'nhd:*', -- mvdgis (Montevideo, UY) 'mvdgis:*', -- EUROSHA (Various countries) 'project:eurosha_2012', -- UrbIS (Brussels, BE) 'ref:UrbIS', -- NHN (CA) 'accuracy:meters', 'sub_sea:type', 'waterway:type', -- StatsCan (CA) 'statscan:rbuid', -- RUIAN (CZ) 'ref:ruian:addr', 'ref:ruian', 'building:ruian:type', -- DIBAVOD (CZ) 'dibavod:id', -- UIR-ADR (CZ) 'uir_adr:ADRESA_KOD', -- GST (DK) 'gst:feat_id', -- Maa-amet (EE) 'maaamet:ETAK', -- FANTOIR (FR) 'ref:FR:FANTOIR', -- 3dshapes (NL) '3dshapes:ggmodelk', -- AND (NL) 'AND_nosr_r', -- OPPDATERIN (NO) 'OPPDATERIN', -- Various imports (PL) 'addr:city:simc', 'addr:street:sym_ul', 'building:usage:pl', 'building:use:pl', -- TERYT (PL) 'teryt:simc', -- RABA (SK) 'raba:id', -- DCGIS (Washington DC, US) 'dcgis:gis_id', -- Building Identification Number (New York, US) 'nycdoitt:bin', -- Chicago Building Import (US) 'chicago:building_id', -- Louisville, Kentucky/Building Outlines Import (US) 'lojic:bgnum', -- MassGIS (Massachusetts, US) 'massgis:way_id', -- Los Angeles County building ID (US) 'lacounty:*', -- Address import from Bundesamt für Eich- und Vermessungswesen (AT) 'at_bev:addr_date', -- "import" keys 'import', 'import_uuid', 'OBJTYPE', 'SK53_bulk:load', 'mml:class' } --- -- Fin des paramétrages -- Le reste du fichier permet un traitement automatisé et n'a pas besoin d'être modifié --- -- Fonctions ------------ -- Fonction de nettoyage des tags -- La fonction make_clean_tags_func() créé une nouvelle fonction à partir d'une liste de tag, qui permet de supprimer ces tags d'un objet. -- Cette nouvelle fonction renvoie "vrai" si tous les tags ont été retirés. local clean_tags = osm2pgsql.make_clean_tags_func(var_delete_keys) -- Fonction permettant de déterminer si l'objet est une surface function has_area_tags(tags) if tags.area == 'yes' then return true end if tags.area == 'no' then return false end -- Si le tag "area" n'existe pas, on retourne la valeur du premier tag possédant une valeur return tags.aeroway or tags.amenity or tags.building or tags.harbour or tags.historic or tags.landuse or tags.leisure or tags.man_made or tags.military or tags.natural or tags.office or tags.place or tags.power or tags.public_transport or tags.shop or tags.sport or tags.tourism or tags.water or tags.waterway or tags.wetland or tags['abandoned:aeroway'] or tags['abandoned:amenity'] or tags['abandoned:building'] or tags['abandoned:landuse'] or tags['abandoned:power'] or tags['area:highway'] or tags['building:part'] end -- Fonction d'insertion des données dans une table function insert_data(table_data, object) -- Ajout d'un objet à la table des ponctuels -- Création d'un objet à insérer data_to_insert = {} -- Récupération des colonnes for key, data in pairs(table_data.def.columns) do -- Récupération du tag correspondant à la colonne : -- La colonne id est de type serial, la colonne geom reçoit la géométrie, la colonne tags reçoit les tags restants donc pas besoin de définir la valeur pour ceux-ci if ( data.column ~= 'id' and data.column ~= 'geom' and data.column ~= 'tags' ) then -- Si input_tag_name est non défini, on récupère le tag portant le nom de la colonne if data.input_tag_name == nil then tag_to_grab = data.column -- Si input_tag_name est différent de vide ('') on récupère le tag dont le nom correspond à sa valeur elseif data.input_tag_name ~= '' then tag_to_grab = data.input_tag_name end end if tag_to_grab ~= nil then -- Récupération de la valeur d'un tag : if data.grab_tag == false then -- object.tags.mon_tag = valeur du tag indiqué (le tag reste présent dans l'objet object.tags) data_to_insert[data.column] = object.tags[tag_to_grab] else -- object:grab_tag('mon_tag') = valeur du tag indiqué (le tag est supprimé de l'objet object.tags, pratique pour éviter d'avoir deux fois la donnée) data_to_insert[data.column] = object:grab_tag(tag_to_grab) end end -- Gestion de la géométrie if data.column == 'geom' then -- Gestion de la géométrie if data.type == 'point' then data_to_insert['geom'] = object:as_point() elseif data.type == 'multipoint' then data_to_insert['geom'] = object:as_multipoint() elseif data.type == 'linestring' then data_to_insert['geom'] = object:as_linestring() elseif data.type == 'multilinestring' then data_to_insert['geom'] = object:as_multilinestring() elseif data.type == 'polygon' then data_to_insert['geom'] = object:as_polygon() elseif data.type == 'multipolygon' then data_to_insert['geom'] = object:as_multipolygon() else data_to_insert['geom'] = object:as_geometrycollection() end end end -- Ajout des tags restant data_to_insert['tags'] = object.tags -- Insertion de la données table_data.construct:insert(data_to_insert) end -- Construction des tables -------------------------- -- Chaque table est construite vai la fonction define_table() for table, data in pairs(var_tables) do var_tables[table]['construct'] = osm2pgsql.define_table(data.def) end -- Fonction de traitement des objets ------------------------------------ -- Traitement des noeuds function osm2pgsql.process_node(object) -- Si le nettoyage des tags ne laisse aucun tag : on ne renvoie rien : on ne conserve pas l'objet if clean_tags(object.tags) then return end -- Insertion des données dans la table via une fonction spéciale insert_data(var_tables.ponctuel, object) end -- Traitement des chemins function osm2pgsql.process_way(object) -- Si le nettoyage des tags ne laisse aucun tag : on ne conserve pas l'objet if clean_tags(object.tags) then return end -- Si l'objet est fermé et qu'il est considéré comme une surface if object.is_closed and has_area_tags(object.tags) then -- Insertion des données dans la table via une fonction spéciale insert_data(var_tables.surface, object) else -- Insertion des données dans la table via une fonction spéciale insert_data(var_tables.ligne, object) end end -- Traitement des relations function osm2pgsql.process_relation(object) -- Si le nettoyage des tags ne laisse aucun tag : on ne conserve pas l'objet if clean_tags(object.tags) then return end -- Les relations de type "route" sont envoyées dans la table des itineraires if object.tags.type == 'itineraire' then -- On créé une ligne à partir de la relation -- Insertion des données dans la table via une fonction spéciale insert_data(var_tables.ligne, object) return end -- Les relations de type "frontière" ou "multipolygon" mais avec le tags "boundary" sont envoyées dans la table des limites if object.tags.type == 'boundary' or (object.tags.type == 'multipolygon' and object.tags.boundary) then -- On créé une ligne à partir de la relation -- Insertion des données dans la table via une fonction spéciale insert_data(var_tables.ligne, object) -- On créé également un polygone à partir de la relation (les limites seront donc à la fois dans la table limite ET dans la table des surfaces) -- Insertion des données dans la table via une fonction spéciale insert_data(var_tables.surface, object) return end -- Les relations de type "multipolygon" sont envoyées dans la table des surfaces if object.tags.type == 'multipolygon' then -- On créé un polygone à partir de la relation -- Insertion des données dans la table via une fonction spéciale insert_data(var_tables.surface, object) end end
Résultat
Après toutes ces étapes, le résultat devrait être le suivant :
Un schéma osm_import
contenant le cache d’osm2pgsql et constitué des trois tables suivantes :
planet_osm_nodes
planet_osm_rels
planet_osm_ways
Le paramètre --drop
permet de supprimer celui-ci automatiquement à la fin de l’import.
Un schéma osm_data
contenant les données importées selon le modèle décrit dans le fichier de configuration et constitué des tables et colonnes suivantes :
ligne
osm_id
(int8) : identifiant OSMid
(int4) : identifianttags
(hstore) : liste des tagsadmin_level
(text)aeroway
(text)boundary
(text)highway
(text)name
(text)railway
(text)waterway
(text)geom
(geometry) : géométrie
ponctuel
osm_id
(int8) : identifiant OSMid
(int4) : identifianttags
(hstore) : liste des tagsamenity
(text)historic
(text)highway
(text)name
(text)natural
(text)place
(text)power
(text)shop
(text)tourism
(text)geom
(geometry) : géométrie
surface
osm_id
(int8) : identifiant OSMid
(int4) : identifianttags
(hstore) : liste des tagsbuilding
(text)landuse
(text)leisure
(text)natural
(text)water
(text)geom
(geometry) : géométrie
Il est maintenant possible d’utiliser les données d’OSM directement dans un logiciel de SIG comme QGIS par exemple.
Selon les besoins, n’hésitez pas à adapter votre fichier de configuration pour ajouter ou retirer les champs nécessaires à votre projet. Notez qu’il est plus rapide de travailler sur une valeur stockée dans son propre champ plutôt que d’avoir à l’extraire du champ tags
(de type hstore) à chaque requête.
Pour aller plus loin
Vous pourrez trouver plus d’informations sur ces sites :
Cet article fait parti du cours sur PostgreSQL, partie 8 du Vade-mecum.
Cet article vous a plu ?
N'hésitez pas à le partager, il interessera surement certains de vos contacts.
Les thèmes suivants contiennent des articles en lien avec celui-ci, allez faire un tour :
BDDPostGISPostgreSQLSIG flexluaOpenStreetMap