Vous appréciez mon travail ?
Je serais ravi de prendre un café !

Vous prenez du plaisir à lire mes articles ? Vous apprenez de nouvelles choses ? Je serais ravis que vous supportiez mon travail avec une petite participation

1 café Merci, vous financez ma dose quotidienne de théïne (oui, en vrai je ne bois pas de café).
5 cafés Génial, ça couvre mes frais de serveur mensuels.
10 cafés Fantastique, avec ça je peux investir dans du matériel et approfondir mes connaissances.
BazinGa's - Tips & tuto IT

Overpass – Introduction rapide à l’export OSM

OpenStreetMap (OSM) est une immense base de données cartographiques accessible à tous (par ici) et qui possède la particularité d’être alimentée par un communautés de cartographes bénévoles. Ainsi, en plus d’être gratuit et ouvert, les données sont mises à jour rapidement et vous pouvez contribuer vous-même.

Ce qui est très intéressant, c’est qu’en plus de pouvoir consulter la données, il est possible de l’extraire pour l’utiliser dans toutes sortes de projets cartographiques.

Source des données

Plusieurs sites proposent des extractions quotidiennes complètes selon des emprises définies (pays, région…) :

Le site officiel d’OpenStreetMap permet également de faire des extractions de données depuis l’interface cartographique : https://www.openstreetmap.org/export

Mais il existe également une API qui permet de sélectionner un ensemble spécifique de données, il s’agit d’Overpass. C’est une API web qui est optimisée pour récupérer rapidement un ensemble de données depuis la base d’OpenStreetMap.

Utiliser l’API

La documentation de l’API est disponible sur le wiki d’OSM mais en voici un résumé.

Il existe deux façons d’interroger l’API :

  • En l’interrogeant directement via une requête web sur l’URL https://overpass-api.de/api/interpreter en passant la requête en langage Overpass XML ou en langage Overpass Query Language via le paramètre data (avec les méthodes GET ou POST, au choix).
  • En utilisant overpass-turbo, une interface web interactive permettant d’exécuter une requête Overpass puis de visualiser les données retournées.

Voici un exemple de requête GET vers l’API Overpass :

https://overpass-api.de/api/interpreter?data=contenu_de_ma_requete_overpass_query_language

Il existe deux langages de requêtage avec Overpass :

  • Overpass XML
  • Overpass Query Language

Je n’aborderai que le langage Overpass Query Langage.

Overpass Query Language

Pour maitriser l’API, il faut en maitriser son langage : Ovepass Query Language (Overpass QL ou OQL). C’est avec lui que les requêtes sont construites dans le paramètre data.

La documentation qui existe actuellement n’est pas des plus simple à aborder et surtout ne permet pas vraiment un démarrage rapide mais vous pouvez retenir ces deux liens :

Voici donc de quoi maitriser les bases afin d’exploiter ce formidable outil.

Veuillez notez que :

  • Chaque instruction se termine par un point-virgule ;.
  • Il est possible d’ajouter des commentaires :
    • Multilignes en débutant par /* et en terminant par */.
    • Sur une ligne avec //.

Pour les exemples, vous pouvez lancer vos requêtes dans Overpass turbo en utilisant ce cadre :

// La sortie est en xml
[out:xml];

/* 
Listes des instructions
*/

// Export des données
out;

Paramètres

Une requête débute toujours par un ensemble de paramètres.

On retrouve des paramètres « généraux » :

  • timeout : temps de requêtage maximum (en seconde).
  • maxsize : mémoire RAM (en octets) maximum allouée.
  • out : format de sortie (xml, json, csv, custom, popup).
    Notez que le format xml est compatible avec l’outil d’import osm2pgql (voir plus bas).

Ainsi que des paramètres de filtrage qui vont limiter l’étendue des données récupérées :

  • bbox : selon un rectangle englobant (Sud, Ouest, Nord, Est).
  • date : pour une date et une heure de création/modification spécifique (temps UTC).
  • diff : entre deux dates de création/modification spécifiques (temps UTC).
  • adiff : comme diff mais avec les informations sur les éléments supprimés.

Voici un exemple de paramétrage :

// Toutes les données requêtées doivent se trouver sur Genève
// La sortie est en xml
[bbox:46.20127,6.14578,46.20768,6.16262] [out:xml];
// Toutes les données requêtées doivent avoir été créée entre le 3 et le 4 juillet 2020
// La sortie est en xml
[diff:"2020-07-03T00:00:00Z","2020-07-04T23:59:59Z"] [out:xml];
// Toutes les données requêtées doivent avoir été créée entre le 16 aout 2023 et maintenant
// La sortie est en xml
[diff:"2020-08-16T00:00:00Z"] [out:xml];

Données et ensembles

Modèle de données

Dans OSM, les données sont stockées en tant qu’objets possédant un nombre illimité d’attributs sous la forme de couple « clé/valeur » (très similaire au format json).

Il existe trois types d’objets :

  • Les nœuds, constitués de coordonnées X et Y.
    Les nœuds peuvent représenter des objets ponctuels ou être simplement des sommets élémentaires (et sans attributs spécifique) des chemins.
  • Les chemins, constitués d’une liste de références à des nœuds. Un même chemin peut référencer plusieurs fois le même nœud (cas des chemins fermés ou s’intersectant eux-mêmes).
    Les chemins peuvent représenter des routes ou des cours d’eau par exemple.
  • Les relations, constituées d’une liste de références à des membres pouvant être des nœuds, des chemins ou des relations.
    Le principe est d’associer plusieurs éléments ensemble comme dans le cas d’un itinéraire de ligne de bus par exemple (succession de portions de routes).

Notez que chaque objet possède un identifiant numérique unique pour le type considéré. Il existe donc un identifiant « 1 » pour les nœuds, un pour les chemins et un pour les relations.

Pour en savoir plus sur le modèle de données d’OSM, vous pouvez consulter cette documentation.

Extraction

Overpass QL permet de récupérer des données par le biais de fonctions que voici :

  • node : permet de récupéré des nœud.
  • way : permet de récupérer des chemins.
  • rel : permet de récupérer des relations.
  • nw : permet de récupérer des nœuds et des chemins.
  • nr : permet de récupérer des nœuds et des relations.
  • wr : permet de récupérer des chemins et des relations.
  • nwr : permet de récupérer des nœuds, des chemins et des relations.

Ensembles

Lorsque vous récupérez des données avec Overpass QL, celles-ci sont stockées dans des « ensembles », une sorte de conteneur. Il est possible de définir plusieurs ensembles et ensuite d’effectuer des opérations entre ceux-ci.

Un ensemble est nommé par une suite de caractères constituée de lettres, de chiffres et/ou du trait de soulignement (« _ ») sans commencer par un chiffre. Il existe un ensemble par défaut nommé _ (trait de soulignement).

Voici les règles d’utilisation des ensembles :

  • Pour appeler un ensemble, il faut le préfixer par un point.
    Par exemple, ._ pour appeler l’ensemble par défaut.
  • L’assignation des données issues d’une opération (par exemple la fonction node) à un ensemble se fait de la façon suivante :
    opération -> .nom_ensemble
  • L’utilisation des données d’un ensemble se fait de la façon suivante :
    opération.nom_ensemble
  • La combinaison des deux précédents se fait de la façon suivante :
    opération.nom_ensemble -> .nom_ensemble_2
  • Lorsqu’un ensemble est réassigné, son contenu est entièrement remplacé comme dans l’exemple suivant :
    opération.nom_ensemble -> .nom_ensemble
  • Si aucun ensemble n’est spécifié, l’ensemble par défaut est utilisé :
    opération équivaut à opération -> ._
    Notez que l’ensemble par défaut est initialement vide.

Voici un exemple qui permet de récupérer tous les nœuds et les chemins dans un ensemble puis de copier les nœuds de cet ensemble dans un autre :

// Toutes les données requêtées doivent se trouver sur Genève
// La sortie est en xml
[bbox:46.20127,6.14578,46.20768,6.16262] [out:xml];

// Récupérer tous les nœuds et chemins depuis la BDD OSM
nw -> .ensemble_noeuds_et_chemins;

// Copier tous les nœuds de l'ensemble précédent vers un nouvel ensemble
node.ensemble_noeuds_et_chemins -> .ensemble_noeuds;

// Export des données
.ensemble_noeuds out;

Filtres

Maintenant que nous pouvons récupérer des données, il faut pouvoir les filtrer.

Plusieurs filtres sont disponibles, je n’en présenterai que quelques uns.

Par attribut

Les attributs sont un excellent moyen de filtrer les entités.

Pour cela la syntaxe utilise des crochets [] pour encadrer chaque filtre.

Voici différentes syntaxes possibles :

  • ["highway"] : possède la clé « highway ».
  • [!"highway"] : ne possède pas la clé « highway ».
  • ["highway"="primary"] : la clé « highway » vaut « primary ».
  • ["name"~"boulevard h.*"] : la clé « name » commence par « boulevard h »
    On utilise ici une expression régulière avec « ~ », l’expression est sensible à la casse.
  • ["name"~"boulevard h.*", i] : la clé « name » commence par « boulevard h ».
    On ne tient pas compte de la casse grâce au drapeau « i » (« Boulevard h… », « boulevard H… », « Boulevard H… » seront acceptés).
  • ["name"~"^$"] : possède la clé « name » mais elle est vide.
  • [~"^$"~".+"] : possède une clé «  » (vide) ayant une valeur d’au moins un caractère.
  • [~"^$"~"^$"] : possède une clé «  » (vide) ayant une valeur vide.
  • [~"name:.+"~".+"] : possède une (ou plusieurs) clé(s) « name:xyz » (« name:fr », « name:es », « name:de »…) ayant une valeur.
  • [~".*"~"Boulevard Helvétique"] : possède une clé (n’importe laquelle) ayant la valeur « Boulevard Helvétique ».
    Attention, l’utilisation d’une expression régulière pour le nom d’une clé doit obligatoirement être utilisée avec une expression régulière pour la valeur.

La connaissance des expressions régulières est un avantage indéniable pour ce filtre. Vous pouvez vous aider de ce site : https://regex101.com/.

Il est possible de combiner les filtres par attribut :

  • ["highway"="primary"]["maxspeed"="50"] : toutes les routes de grande importance ayant une valeur maximale de 50 km/h.

Voici un exemple d’utilisation :

// Toutes les données requêtées doivent se trouver sur Genève
// La sortie est en xml
[bbox:46.20127,6.14578,46.20768,6.16262] [out:xml];

// Récupération de tous les objets en lien avec les routes
nwr["highway"] -> .route;

// Création d'un ensemble ne contenant que les traversées piétonnes et les cheminements piétons.
nwr["highway"~"crossing|footway"].route -> .pedestre;

// Export des données
.pedestre out;

Notez que pour sélectionner un objet par son identifiant il faut utiliser une syntaxe avec des parenthèses tel que suivant : (000) ou (id:000) (en remplaçant les zéros par l’identifiant de l’objet).

Par exemple :

// La sortie est en xml
[out:xml];

// Mon objet spécifique
nwr(id:25648096) -> .mon_objets_spe;

// Export des données
.mon_objets_spe out;

Par géométrie

Il est possible de filtrer selon la géométrie des objets par rapport à :

  • Un rectangle englobant : (sud, ouest, nord, est)
    Par exemple : nwr(46.20127,6.14578,46.20768,6.16262).
  • Un ensemble : (around.mon_ensemble:rayon)
    Par exemple : nwr(around.ensemble_route_communales:100)
  • Un polygone : (poly:"lat_1 long_1 lat_2 long_2 lat_3 long_3...")
    Par exemple : nwr(poly:"46.2034 6.2690 46.2375 6.3542 46.1885 6.3950 46.1544 6.3098 46.2034 6.2690")

Par date

La date de modification des objets peut être interrogée :

  • Plus récent que : (newer:"2024-05-20T07:00:00Z")
  • Modifié depuis : (changed:"2024-05-20T07:00:00Z")
  • Modifié entre : (changed:"2024-05-20T00:00:00Z","2024-05-25T23:59:59Z")

Exemple complexe

Voici un exemple complexe combinant les différents filtres que nous avons vus :

// La sortie est en xml
[out:xml];

// Emprise de la commune de Lucinges (74380)
nwr["boundary"="administrative"]["admin_level"=8]["name"="Lucinges"] -> .emprise_lucinges;

// Récupération des chemins de type "route" (possédant la clé highway) dans un périmètre de 1km autour de Lucinges
way(around.emprise_lucinges:1000)["highway"] -> .route_lucinges;

// Sélection des routes de Lucinges créées après le 1er janvier 2024 dans la base OSM
way.route_lucinges(newer:"2024-01-01T00:00:00Z") -> .route_recente;

// Export des données
.route_recente out;

Instructions de blocs

Il est possible d’opérer des transformations sur les ensembles de données.

  • Les unions : (ensemble_1; ensemble_2) -> .ensemble_3;
    Tous les éléments présents dans « ensemble_1 » plus tous les éléments présents dans « ensemble_2 ».
    Notez que l’union retire tous les doublons.
  • Les différences : (ensemble_1; - ensemble_2) -> .ensemble_3;
    Tous les éléments présents dans « ensemble_1 » qui ne sont pas présent dans « ensemble_2 ».

Récursion

Si vous avez testé mes exemples, vous avez pu voir apparaitre le message suivant pour certaines requêtes :

Cette requête n’a retourné aucun nœud. Dans OSM, seuls les nœuds contiennent des coordonnées. Par exemple, un chemin ne peut pas être affiché sans ses nœuds…

Overpass Turbo

Cela vient du fait que vous avez probablement récupéré des données qui ne possèdent pas de coordonnées comme des chemins ou des relations. Pour rappel, seuls les nœuds possèdent des coordonnées.

Ainsi, lorsque vous récupérez des chemins ou des relations, il faut également récupérer tous les nœuds qui s’y rattachent. C’est l’un des objectifs de la récursion.

Globalement, la récursion permet de récupérer les enfants ou les parents d’un éléments. On distingue plusieurs opérateurs de récursion dont les deux suivants :

  • .A > -> .B : récursion simple aval : récupère et stocke dans l’ensemble « B » :
    • Tous les nœuds faisant partie d’un chemin présent dans A.
    • Plus tous les nœuds et chemins faisant partie d’une relation dans A.
    • Plus tous les nœuds des chemins présents dans B.
      Il s’agit des chemins qui auraient été récupérés par la récursion et donc non présents dans A à l’origine.
  • .A < -> .B : récursion simple amont : récupère et stocke dans l’ensemble « B » :
    • Tous les chemins qui ont un nœud dans A.
    • Plus toutes les relations qui ont un nœud ou un chemin dans A.
    • Plus toutes les relations qui ont un chemin présent dans B.
      Il s’agit des chemins qui auraient été récupérés par la récursion et donc non présents dans A à l’origine.

Voici un exemple :

// La sortie est en xml
[out:xml];

// Emprise de la commune de Lucinges (74380)
rel["boundary"="administrative"]["admin_level"=8]["name"="Lucinges"] -> .emprise_lucinges;

// Récupération des chemins et des nœuds constitutifs de l'emprise (qui est une relation)
.emprise_lucinges > -> .chemin_et_noeud_emprise;

// Export des données
.chemin_et_noeud_emprise out;

Attention, la récusions ne récupère pas le lot d’entré. Il faudra le fusionner avec l’opérateur d’union si vous souhaitez avoir l’objet et ses constituants :

// La sortie est en xml
[out:xml];

// Emprise de la commune de Lucinges (74380)
rel["boundary"="administrative"]["admin_level"=8]["name"="Lucinges"] -> .emprise_lucinges;

// Récupération des chemins et des nœuds constitutifs de l'emprise (qui est une relation)
.emprise_lucinges > -> .chemin_et_noeud_emprise;

// Fusion des deux ensembles
(
  .emprise_lucinges;
  .chemin_et_noeud_emprise;
) -> .emprise_et_constituants_lucinges;

// Export des données
.emprise_et_constituants_lucinges out;

Sortie(s)

Pour que les données soient extraites, il faut utiliser l’instruction out.

Sans préfixe, tous les objets présents dans l’ensemble par défaut « _ » sont exportés, sinon il est possible de définir l’ensemble à traiter :

.mon_ensemble out;

Il est possible de l’utiliser plusieurs fois pour extraire plusieurs ensembles de données qui seront combinés dans la sortie finale :

.mon_ensemble_A out;

.mon_ensemble_B out;

Le code précédent est presque équivalent à :

(
  .mon_ensemble_A;
  .mon_ensemble_B;
) -> .mon_ensemble_C;

.mon_ensemble_C out;

Je dis presque car l’union permet de nettoyer les objets qui pourraient être en doublons entre les deux ensembles, la deuxième forme est plus pertinente.

L’instruction out peut également être utilisée avec des drapeaux parmi les suivants permettant de :

  • Définir la structure de données (un au choix) :
    • ids : uniquement les identifiants des objets
    • skel : format ids auquel on ajoute les coordonnées pour les nœuds ainsi que la liste des constituants pour les chemins et les relations.
    • tags : format ids auquel on ajoute les attributs de l’objet.
    • body : combinaison des format skel et tags.
      Il s’agit de la valeur par défaut si aucun drapeau n’est utilisé.
    • meta : format body auquel on ajoute la version de l’objet et son horodatage.
  • Choisir le géométrie récupérée (plusieurs possible) :
    • geom : ajoute la géométrie de l’objet.
      Les objets de type chemin et relation se voient attribuer une géométrie sans qu’il n’y ai besoin de récupérer leurs nœuds par récursivité.
    • bb : ajoute le rectangle englobant de l’objet.
    • center : ajoute le centre de gravité de l’objet.
  • Trier les données :
    • asc : trier les données par id
  • Limiter le nombre d’objets :
    • En ajoutant une valeur numérique entière (25 par exemple), seul le nombre d’objet indiqué sera renvoyé.

Voici un exemple de sortie :

// Exporter les 30 premiers éléments de .mon_ensemble en y incluant toutes les données relative, géométrie y compris.
.mon_ensemble out body geom asc 30;

Notez que vous pouvez exporter des ensembles avec des drapeaux différents :

.mon_ensemble_A out skel;

.mon_ensemble_B out tags center;

Overpass et osm2pgsql

Si vous souhaitez utiliser les données exportées via l’API Overpass avec l’outil d’import osm2pgsql, les données doivent respecter un certain formalisme :

  • Le format d’export doit être le xml : [out:xml]
  • Les données ne doivent pas avoir de doublons : vous pouvez utiliser l’opérateur d’union pour retirer tous les doublons (ensemble_1; ensemble_2) -> .ensemble_3;.
  • Les données doivent être triées par type d’objet puis par identifiant : utilisez le drapeau asc.

Exemple complet

Voici un exemple complet d’une requête overpass :

/* Paramètres
Généraux :
- [timeout:180] : temps de requêtage maximum (en seconde)
- [maxsize:536870912] : mémoire RAM (en octets) maximum allouée
- [out:xml] : format de sortie (xml, json, csv, custom, popup)
Filtre global :
- [bbox:-90,-180,90,180] : rectangle englobant (Sud, Ouest, Nord, Est)
- [date:"2015-10-28T19:20:00Z"] : date de création/modification spécifique
- [diff:"2015-10-28T19:20:00Z"] : entre la date et maintenant
- [diff:"2015-10-28T19:20:00Z","2020-01-01T19:20:00Z"] : entre deux dates
- [adiff:"2015-10-28T19:20:00Z","2020-01-01T19:20:00Z"] : comme diff mais avec les informations sur les éléments supprimés.
*/
[out:xml];


/* Filtre spatial
Récupération des objets intersectant un polygone autour de la commune de Lucinges (74380 - France)
*/
nwr(poly:"46.203483742571834 6.269008170723939 46.23752435725205 6.354224775644609 46.18853590769547 6.395098121072051 46.15446492383131 6.309881516151381 46.203483742571834 6.269008170723939") -> .donnees_lucinges;



// Filtre des données récupérées par tags
(
  way.donnees_lucinges["highway"]["highway"!~"crossing|platform|cycleway"]["access"!~"private"]["area"!~"yes"]["tunnel"!~"yes"];
) -> .routes_lucinges;



/* Récursivité
Récupéreration de :
- Tous les noeuds appartenant aux chemins en entrée
- Tous les noeuds et chemins appartenant aux relations en entrée
- Tous les noeuds appartenant aux chemins en résultat
*/
.routes_lucinges > -> .donnees_liees;



/* Fusion
La fusion des données filtrées et des données liées permet de supprimer les éventuels doublons d'objet
*/
(
  .routes_lucinges;
  .donnees_liees;
) -> .donnees_total;



/* Sortie
Formats
- ids : identifiants
- skel : ids + coordonnées des noeuds + constituants des ways et relations
- tags : ids + tags de l'objet
- body : skel + tags (valeur par défaut si aucun drapeua n'est utilisé)
- meta : body + version de l'objet + timestamp de l'objet
Modificateur :
- geom : ajoute la géométrie de l'objet
- bb : ajoute le rectangle englobant de l'objet
- center : ajoute le centre de gravité
Tri :
- asc : trier les données par id
Limite :
- En ajoutant une valeur numérique entière (25 par exemple), seul le nombre d'objet indiqué sera renvoyé
*/
.donnees_total out body asc;

Pour en savoir sur l’utilisation des données d’OSM plus n’hésitez pas à consulter cet article du wiki : https://wiki.openstreetmap.org/wiki/Use_OpenStreetMap


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 :

SIG APIosmosm2pgsqloverpassoverpass turbo

50%