Auteur : Nicolas Rouanne
Date : 12 février 2026
Je voulais construire un prototype fonctionnel pour explorer comment identifier les bâtiments adaptés à l’hybridation urbaine (« surélévation ») à Marseille. Le contexte : un client avait besoin d’un outil SIG capable d’aller au-delà de la simple visualisation cartographique pour qualifier les bâtiments qui pourraient être « CHUTTés » — surélevés avec des étages supplémentaires sur leurs toitures. Plutôt que de partir d’un document de spécifications, j’ai décidé de construire quelque chose de concret en utilisant uniquement des données ouvertes de l’État français.
L’objectif était clair : prendre les données bâtimentaires de l’IGN BD TOPO, les afficher en 3D, permettre aux utilisateurs de cliquer sur des bâtiments pour les sélectionner, et superposer des données de risques environnementaux comme les zones inondables. Le tout fonctionnant dans le navigateur, sans backend nécessaire pour le prototype.
Le prototype est une application Next.js statique utilisant MapLibre GL JS pour la cartographie. Pas de Mapbox, pas de service de tuiles propriétaire — tout provient d’API gouvernementales françaises :
Ce choix était délibéré. Le projet commercial devra à terme croiser plusieurs jeux de données gouvernementaux (cadastre, PLUi, conformité SRU), donc prouver que nous savons travailler avec ces API dès le prototype était important.
La fonctionnalité clé est le rendu 3D des bâtiments avec un code couleur basé sur le matériau des murs. La BD TOPO inclut un champ materiaux_des_murs avec des codes CEREMA — on associe le premier chiffre à une couleur : pierre (gris), brique (terre cuite), béton (ardoise), bois (marron).
Quand un utilisateur clique sur un bâtiment, le prototype extrait la géométrie du polygone et crée une extrusion avec un dégradé doré, ajoutant 10 mètres pour simuler à quoi ressemblerait un bâtiment surélevé. Cela utilise un algorithme de ray-casting point-dans-polygone projeté en coordonnées écran — nécessaire car la détection de clic native de MapLibre n’est pas assez précise quand la caméra est inclinée à 52°.
// Ray-casting pour trouver le polygone réellement cliqué
export function findClickedPolygonPrecise(
point: maplibregl.Point,
features: maplibregl.MapGeoJSONFeature[],
map: maplibregl.Map
): maplibregl.MapGeoJSONFeature | null {
for (const feature of features) {
const geometry = feature.geometry;
if (geometry.type === "Polygon") {
for (const ring of geometry.coordinates) {
const projectedRing = ring.map((coord) =>
map.project(new maplibregl.LngLat(coord[0], coord[1]))
);
if (isPointInPolygon(point, projectedRing)) {
return feature;
}
}
}
}
return null;
}
Chaque bâtiment sélectionné voit également son adresse résolue par géocodage inverse, avec annulation via AbortController pour éviter les conditions de concurrence quand les utilisateurs cliquent rapidement.
Le prototype démontre plusieurs choses de manière convaincante :