Ajouter une carte à tuiles XYZ (image lidar-maps) réutilisable dans OSM

L'ancienne carte n'est pas une carte à tuiles : une div Leaflet par dalle,
rotée en CSS pour coller la grille Lambert 93 sur le Web Mercator, trois
paliers d'images choisis à la main, un plafond d'images pleine résolution et
une mosaïque d'overview pour boucher les trous au dézoom. Des centaines de
nœuds DOM, des AVIF de 2500² à 5000² décodés dans le navigateur, un LOD
maison — et rien de réutilisable hors de cette page.

Nouvelle image légère (Pillow + pyproj, ni GDAL ni PDAL, port 8975) servant
une pyramide XYZ EPSG:3857 au schéma OpenStreetMap, rendue à la demande
depuis les dalles et mise en cache dans output/index_xyz/ :

- tiles.py : grille XYZ, reprojection par transformation projective dalle par
  dalle (calage mesuré < 1 px), choix du palier source parmi ceux que le
  pipeline produit déjà (vignette, intermédiaire, quadrant, dalle), cache
  périmé dès qu'une dalle contributrice est plus récente, marqueur .empty
  pour les zones sans donnée, cache d'images sources à budget mémoire ;
- mapserve.py : /tiles/{couche}/{z}/{x}/{y}.png (256 px canonique) et
  @2x.webp (512 px, interface), TileJSON, WMTS, josm.imagery.xml, CORS —
  les rendus deviennent un fond d'imagerie pour JOSM, iD, QGIS, uMap ;
- mapui.py : une L.tileLayer par couche dans un pane isolé — LOD, cache et
  animation natifs de Leaflet ; pile réordonnable (glisser avec barre
  d'insertion, ou boutons ▲▼ au doigt), modes de fusion CSS par couche,
  configuration figeable comme défaut de tous les navigateurs.

Deux amonts pour les déploiements en deux machines : LIDAR_SOURCE_URL
(webapp du pipeline — inventaire complet, dalles rapatriées à la demande) et
LIDAR_MAPS_URL (autre instance carte). Charge bornée et réglable, taillée
par défaut pour une petite machine : 2 rendus et 2 téléchargements
simultanés, 192 Mo de cache de sources.

Mesuré sur 849 dalles réelles : première tuile d'une zone 0,9–3,2 s
(téléchargement compris), ~1 ms ensuite ; un chemin OSM se superpose
exactement à la trace du rendu de pente, et les coutures entre tuiles
restent sous le bruit naturel du terrain.

L'interface historique (port 8973) n'est pas touchée : génération et export
y restent, les deux cartes coexistent.
This commit is contained in:
Antoine Jacquin
2026-09-23 14:47:38 +02:00
parent 64eaad751c
commit 053eb2f529
12 changed files with 3722 additions and 2 deletions

42
docker-compose.maps.yml Normal file
View File

@ -0,0 +1,42 @@
# Carte à tuiles XYZ (style OpenStreetMap / Google Maps) — cf. docs/MAPS.md.
#
# Coexiste avec la webapp historique (port 8973) : même dossier output/, aucune
# interférence. Les tuiles sont rendues à la demande et mises en cache dans
# output/index_xyz/.
#
# docker compose -f docker-compose.maps.yml up -d --build
# docker compose -f docker-compose.maps.yml logs -f maps
# docker compose -f docker-compose.maps.yml down
services:
maps:
build:
context: .
dockerfile: Dockerfile.maps
image: lidar-maps
container_name: lidar-maps
init: true
user: "1000:1000"
ports:
- "8975:8975"
volumes:
# Lecture des dalles + écriture du cache de tuiles (output/index_xyz/)
- ./output:/data/output
environment:
- TZ=Europe/Paris
- LIDAR_OUTPUT_DIR=/data/output
# Serveur de DALLES amont (webapp du pipeline) : sans données locales,
# l'inventaire vient de son /api/tiles et les images sont rapatriées à
# la demande dans ./output — de quoi servir tout un catalogue distant.
# - LIDAR_SOURCE_URL=http://192.168.1.50:8973
# Serveur de TUILES amont (autre instance lidar-maps) pour une carte
# déportée (Raspberry Pi) : une tuile absente localement y est rapatriée.
# - LIDAR_MAPS_URL=http://192.168.1.50:8975
# Mention d'attribution servie dans TileJSON, WMTS, JOSM et la carte.
# - LIDAR_ATTRIBUTION=LiDAR HD &copy; IGN — Licence Ouverte 2.0
# Charge maximale : rendus et téléchargements simultanés, mémoire du
# cache d'images sources. Défauts taillés pour une petite machine ;
# à relever sur un serveur confortable.
# - LIDAR_TILE_WORKERS=2
# - LIDAR_TILE_FETCH_WORKERS=2
# - LIDAR_TILE_SOURCE_CACHE_MB=192
restart: unless-stopped