Overpass
2025-04-13
OpenStreetMap est un projet dans lequel est construit une base de données[1] accessible pour des projets variés telle que l'emprise au sol des courts de tennis[2]. Overpass est le nom de l'API permettant d'extraire les données.
Langages
Les requêtes Overpass sont effectuées selon deux langages :
- Overpass XML ;
- Overpass Query Language[3].
Le second a été introduit suite à la mise à disposition de données plus riches via la requête HTTP, autrefois impossible. La construction de requête a été ainsi amplement simplifiée, si bien qu'il ne semble pas exister de documentation à destination du public du langage O-XML.
Généralités
Les requêtes se composent de « statements » (d'opérations) séparées par des points-virgules, avec généralement une sortie unique demandé via la commande `out` et correspondant au « set » (jeu) par défaut : `_`.
// Code simple node(1); out; // Code implicite node(1) -> ._; ._ out;
La sortie peut prendre différentes formes selon l'argument suffixé :
- ids pour l'identifiant ;
- tags pour l'identifiant et les attributs ;
- skel pour l'identifiant et la géométrie ;
- body pour l'identifiant, la géométrie, et les attributs (Valeur par défaut) ;
- meta pour l'identifiant, la géométrie, les attributs, et l'historique.
Opérations
À noter que les opérations se font de manière séquentielle. En absence de commande explicite, chaque opération s'effectue sur le jeu par défaut, défini précédemment. Ainsi, des paramètres d'opération peuvent être insérés via parenthèses, tandis que des paramètres globaux sont définis entre crochets. Exemple pour le « bbox » (rectangle englobant) défini dans le sens anti-horaire à commencer par la limite ouest.
// Paramètre global [bbox:-0.001835, -0.000963, 0.001706, 0.001489]; node; // Paramètre d'opération node(-0.001835, -0.000963, 0.001706, 0.001489); // Alternative via un polygone personnalisé (si le polygone est un chemin fermé OSM, voir section sur fonctions spatiales) node(poly:"-0.001835, -0.000963, 0.001706, 0.001489")
Les données de plusieurs opérations peuvent être combinées dans le jeu par défaut en les entrant entre parenthèses. C'est utile notamment dans le cas des relations et chemins qui sont définis par des points plutôt que des entités indépendantes, et qui nécessitent d'utiliser `>` ou `>>` comme opérateur de récursivité.
( relation(6759865); >>; );
Les opérateurs `<` et `<<` font l'inverse et permettent de remonter aux parents.
Filtres
Un filtre peut être appliqué à une opération. Pour cela il suffit d'entrer les variables entre crochets.
// Nœuds avec la clé amenity node["amenity"]; // Nœuds sans clé amenity node[!"amenity"]; // Nœuds dont le nom contient la séquence « Hair », merci les salons de coiffure node["name"~"Hair"]; // Nœuds dont le nom contient la séquence « Hair », et qui ne sont pas des salons de coiffure node["name"~"Hair"]["shop"!="hairdresser"]; // Alternative : nœuds dont le nom contient la séquence « Hair », et qui ne sont pas des salons de coiffure ( node["name"~"Hair"] - node["shop"="hairdresser"]; ); // Alternative : création d'un jeu intermédiaire `hair` duquel sont supprimé les salons, avant réinsertion au jeu par défaut node["name"~"Hair"] -> .hair; node.hair["shop"!="hairdresser"] -> ._;
Fonctions spatiales
Des fonctions peuvent être appliquées, dont `around`.
// Via un jeu intermédiaire « coiffure » node["shop"="hairdresser"] -> .coiffure; node(around.coiffure:100)["barrier"="bollard"]; // Alternative avec le jeu par défaut node["shop"="hairdresser"]; node(around:100)["barrier"="bollard"];
De la même manière, il est possible de travailler avec des zones. Des « areas » (zones) sont une classe d'éléments (similaires au nœuds, chemins, et relations) générées par Overpass de manière automatique, à défaut d'avoir clairement la main dessus, je préfère éviter de les utiliser et m'appuie exclusivement sur les données OpenStreetMap.
// Utilisation de is_in pour trouver les zones dont fait partie le nœud correspondant à la ville de Besançon, et de pivot pour générer leur géométrie. Preuve concrète du bourbier que sont les areas
(
node["name"="Besançon"]["place"="city"] -> .ville;
.ville is_in -> .areas;
way(pivot.areas);
>;
);
// Recherche des amenity dans Venise, tel que trouvé par Nominatim via la fonction geocodeArea, alors que je cherchais le village du Doubs ref:INSEE=25598
{{geocodeArea:"Venise"}} -> .recherche;
node(area.recherche)["amenity"];
// Recherche à partir de la fonction map_to_area dans laquelle a été insérée la relation avec l'identifiant IRIS d'un quartier
(
relation["ref:IRIS"="0402"] ->.iris;
.iris map_to_area ->.battant;
node["amenity"](area.battant);
>;
);
Cas d'étude
Si, par le plus grand des hasard une personne avait pour idée de localiser les feux tricolores[4] localisés sur des aménagements cyclables à Besançon, il suffirait ainsi de lancer le code suivant permettant de :
- Créer l'area Besançon (qui fonctionne par défaut, autrement passer par la fonction map_to_area ;
- Y localiser les aménagements cyclables définis par la famille de clés `cycleway` (on tronque également les informations redondantes avec des valeurs `no` ou `separate`) ;
- Insérer les données avec les nœuds dans un jeu intermédiaire ;
- Conserver les nœuds avec l'attribut `highway=traffic_signals`.
{{geocodeArea:Besançon}}->.searchArea;
(
(way(area.searchArea)[~"^cycleway.*$"~"."]; - way(area.searchArea)[~"^cycleway.*$"~"no"];);
(._ ; - way(area.searchArea)[~"^cycleway.*$"~"separate"];);
> -> .r11;
);
node.r11["highway"="traffic_signals"];
out geom;