Géographe - Urbaniste
OSM et la 3D : comment enrichir les hauteurs de bâtiments manquantes
En construisant une carte 3D de Bangkok avec Mapbox, je me suis vite heurté à un problème de volume : presque tous les bâtiments avaient exactement la même hauteur. C'est la valeur par défaut d'OpenStreetMap quand la hauteur est inconnue, 4 mètres. Résultat, une ville parfaitement plate, aucune silhouette urbaine. Sur la carte 3D, une tour de 30 étages ressemble à la même chose qu'une maison résidentielle.
Voici la méthodologie que j'ai mise au point pour corriger ça dans QGIS, à partir de données ouvertes. Elle peut se reproduire sur n'importe quelle ville.
Un problème universel
Avant de chercher une solution, un petit audit des bâtiments OSM de Bangkok :
0,2 %des bâtiments ont un tag height avec une valeur différente du défaut de 4 m
2,2 %ont un tag building:levels
84,6 %sont à la valeur par défaut de 4 mètres
Aujourd'hui, quasiment tous les fournisseurs cartographiques s'appuient sur la même donnée OSM. La couverture est correcte en Allemagne, aux Pays-Bas et dans quelques villes américaines ou japonaises. Partout ailleurs, c'est le même constat.
La méthodologie en quatre étapes
L'idée : si un bâtiment n'a pas de hauteur, on identifie d'abord le quartier administratif auquel il appartient, on lui donne ensuite la médiane des bâtiments voisins du même quartier qui en ont une, puis on cale une hauteur minimale par type.
1. Convertir les niveaux en hauteurs
Les contributeurs OSM renseignent aussi le nombre d'étages via le tag building:levels. On peut valoriser cette donnée en créant un champ height_estimate à la calculatrice de champs :
CASE
WHEN "height" IS NOT NULL THEN to_real("height")
WHEN "building:levels" IS NOT NULL AND "building" IN ('commercial','retail','office')
THEN to_real("building:levels") * 3.5
WHEN "building:levels" IS NOT NULL
THEN to_real("building:levels") * 3
END
3 mètres par étage, 3,5 pour le commercial où les plafonds sont plus hauts.
2. Rattacher chaque bâtiment à son sous-district
Bangkok est découpée en sous-districts administratifs. L'outil Joindre les attributs par localisation reporte l'identifiant du sous-district sur chaque bâtiment (prédicat « est à l'intérieur de »). C'est l'unité de référence qui servira à l'imputation.
3. Imputer la médiane par sous-district
Pour chaque bâtiment sans hauteur, on prend la médiane des bâtiments du même sous-district qui en ont une vraie (supérieure à 4 m, pour exclure les valeurs par défaut). On n'impute que si le sous-district compte au moins 10 bâtiments fiables, sinon il n'y a pas assez d'info locale pour le faire sans bruit. La calculatrice de champs fait tout en une seule expression grâce à aggregate() :
CASE
WHEN "height_estimate" IS NOT NULL THEN "height_estimate"
WHEN aggregate('batiments','count',"height_estimate",
filter:="subdistrict" = attribute(@parent,'subdistrict') AND "height_estimate" > 4) >= 10
THEN aggregate('batiments','median',"height_estimate",
filter:="subdistrict" = attribute(@parent,'subdistrict') AND "height_estimate" > 4)
END
J'avais d'abord fixé le seuil à 20. Le descendre à 10 a quadruplé le nombre de bâtiments enrichis, passant d'environ 20 000 à 88 000.
4. Définir une hauteur minimale par type
Certains types ont des contraintes physiques connues, indépendamment du contexte local. Une école ou un hôtel descend rarement à 4 mètres. On applique donc une hauteur minimale aux bâtiments restants, toujours à la calculatrice de champs :
CASE
WHEN "height_imputed" IS NOT NULL THEN "height_imputed"
WHEN "building" = 'school' THEN 12
WHEN "building" = 'university' THEN 15
WHEN "building" = 'hotel' THEN 24
WHEN "building" = 'industrial' THEN 8
WHEN "building" = 'warehouse' THEN 8
WHEN "building" = 'commercial' THEN 6
WHEN "building" = 'house' THEN 6
WHEN "building" = 'semidetached_house' THEN 6
WHEN "building" = 'apartments' THEN 9
ELSE 4
END
Le champ height_final sert ensuite directement à l'extrusion dans la vue 3D de QGIS, ou comme attribut de hauteur dans votre carte web (Mapbox, MapLibre). La grille complète des hauteurs par catégorie de bâtiment que j'ai utilisée pour Bangkok est en fin d'article.
Les résultats
Bâtiments à la valeur par défaut : de 84,6 % à 19,1 %
Bâtiments mis à jour : 105 807
Via médiane sous-district : 88 273
Via hauteur minimale de type : 12 884
Les limites
C'est de l'imputation statistique, et elle sert uniquement à valoriser l'esthétique de votre cartographie 3D. Cette méthode n'est bien entendu pas valable pour un travail statistique ou scientifique.
La médiane lisse les écarts intra-quartier : une tour de 35 étages et une maison en bois de deux niveaux peuvent cohabiter à 50 mètres dans le même sous-district, et la médiane leur attribuera la même hauteur. Les 19 % restants sont surtout des bâtiments yes sans type ni niveau, dans des zones peu denses où le seuil de 10 n'est pas atteint, souvent du périurbain où la 3D est de toute façon moins sollicitée.
Données et ressources
Je recommande de passer par Geofabrik pour récupérer tous les bâtiments OSM. Le découpage par subdistricts est également disponible via OpenStreetMap, sur Geofabrik ou via une requête Overpass.
La carte 3D de Bangkok qui a motivé tout ça intègre une visualisation des risques d'inondation par niveau d'eau sur 154 000 bâtiments, disponible ici.
Grille de référence réutilisable
Les hauteurs minimales par type appliquées à l'étape 4, calées sur le contexte Bangkok. À adapter à votre ville, mais utilisables comme point de départ.
| Type de bâtiment | Hauteur minimale |
|---|---|
school | 12 m |
university | 15 m |
hotel | 24 m |
industrial / warehouse | 8 m |
commercial | 6 m |
house / semidetached_house | 6 m |
apartments | 9 m |