Commit Graph

48 Commits

Author SHA1 Message Date
64eaad751c L'interface webapp ne peut plus rester silencieusement périmée
La webapp légère bâchait app.js/app.css dans l'image au build : après une
évolution de l'interface, le Pi servait l'ancienne carte sans aucun signal
(tuiles invisibles, vieux fichiers). Désormais l'interface embarque sa
version (hash CSS+JS) que le serveur de données publie via /api/tiles : en
cas de divergence, bandeau « interface périmée » dans la carte + log d'alerte
côté webapp. Les assets sont servis en revalidation (jamais immutable) et
une page ouverte depuis plus de 15 min se recharge seule au retour au premier
plan — l'ancienne interface n'est plus jamais affichée après un déploiement.
2026-09-21 23:43:19 +02:00
2d5a9b2a46 Assombrir les tuiles OSM pour supprimer les cadres blancs au dézoom
Les tuiles OpenStreetMap standard ont un fond blanc : au dézoom, les zones
sans données LiDAR laissent apparaître ce blanc à travers l'opacité du pane
(45 %), créant des cadres blancs autour des tuiles. Un filtre CSS
(brightness 0.35 + contrast 1.1 + saturate 0.7) assombrit le fond OSM pour
le fondre dans le thème sombre de la carte.
2026-09-20 17:29:11 +02:00
e0173e0b39 Rendre les tuiles jointives sur la carte et supprimer le cadre blanc au dézoom
Les sous-tuiles voisines ne partageaient pas leurs bords (interpolation
bilinéaire évaluée deux fois sur des fractions différentes), créant une ligne
claire entre images au zoom moyen. Les points de bord sont désormais calculés
une fois par dalle et partagés entre sous-tuiles adjacentes.

Le cadre blanc autour des tuiles au dézoom venait du outline CSS dessiné
par-dessus les bords d'images non jointives : supprimé (le survol garde son
halo). La bascule overview ↔ vignettes oscillait d'un cran de zoom, d'où une
hystérésis. Les seuils de paliers sont revus pour ne jamais étirer la
vignette intermédiaire au-delà de 1:1.
2026-09-20 16:47:26 +02:00
5f03359fc3 Preset « plop » comme configuration par défaut des couches
La config enregistrée (aspect 74 % en bas, openness positive au-dessus,
fond OSM sombre) devient le preset intégré « Défaut » et les défauts du
panneau. DEFAULT_VIZ reste le relief archéologique (positive_openness).
2026-09-20 15:18:28 +02:00
1d722ff10c Ne pas générer d overview locale sur la webapp légère (géométrie divergente du worker) 2026-09-20 01:05:08 +02:00
b622d55720 Résoudre paresseusement la div des mosaïques d overview (icône non posée à l eval) 2026-09-20 00:57:46 +02:00
b5f3faa14d Projeter les coins du bbox de zone (PROJ) au lieu d exiger un rectangle plein 2026-09-20 00:45:45 +02:00
eec8421f23 Une mosaïque d overview par zone géographique, pas une grille globale 2026-09-20 00:40:32 +02:00
4a13cdb3f5 Tolérer les coquilles HTML sans const OVERVIEW (alias gardé dans app.js) 2026-09-20 00:28:59 +02:00
342a0d2213 Vue dézoomée en mosaïque d'overview et cache immutable des images versionnées 2026-09-20 00:26:18 +02:00
900bf5ee89 Réessayer le sous-tuilage quand la dalle source est en cours d'écriture 2026-09-19 21:43:56 +02:00
3a374a3ab4 AVIF q60 par défaut et sélecteur de mode de fusion par couche 2026-09-19 21:26:13 +02:00
5f018fe2b6 Raccorder les bords de tuiles voisines et encadrer les rendus en cours
Le MNT de chaque dalle s'étend d'une bande de 100 m remplie avec les
points sol des 8 tuiles voisines (option « Raccord des bords ») : les
rendus à grand noyau (openness, SVF, LRM) deviennent continus d'une
dalle à l'autre, les images restent recadrées sur le kilomètre exact.

Pendant une génération, la carte encadre les dalles du run : orange
pulsant en cours de rendu, rouge en échec — les coins WGS84 sont portés
par /api/status pour toutes les dalles non terminées.

La file de génération trie les dalles du nord au sud et passe à 10
workers GPU.
2026-09-19 20:44:44 +02:00
204b2ad111 Preset Défaut : masquer la pente (openness + aspect 50 % + fond OSM 30 %) 2026-09-19 19:08:45 +02:00
2310676886 Preset Défaut : fond OSM visible à 30 % sous la pile de couches 2026-09-19 19:07:21 +02:00
4c189834c6 Inverser la pile du preset Défaut : openness en base, aspect 50 %, pente au sommet 2026-09-19 19:06:43 +02:00
2751d0fea1 Préconfiguration intégrée unique (pente 0, aspect 50, openness 100) 2026-09-19 19:03:56 +02:00
9546173c07 Préréglage carte par défaut et serve-webapp.sh compatible Traefik 2026-09-19 11:05:16 +02:00
e8a9b0187c Porter la carte au zoom 20 et passer le worker à 5 workers 2026-09-19 10:55:44 +02:00
41206f65de Caler les faisceaux de vol, décimer l'openness et cibler les couches affichées
Trois chantiers liés à la qualité et au coût des rendus :

- Calage vertical des faisceaux : les passes d'une tuile peuvent être biaisées
  de quelques cm (±2,5 cm mesurés sur 1000_6882), créant des marches aux
  recouvrements. Les offsets par PointSourceId sont mesurés sur les points
  sol de la tuile (réf. médiane itérée) et retranchés ≥ 0,5 cm avant
  rastérisation, avec sidecar de cache et application au plancher bare-earth.
- Openness décimée ×2 : lancé de rayons sur grille par blocs (max/min) puis
  rééchantillonnage bilinéaire — 532 s → 40 s par tuile à 0,2 m sur CPU,
  signal archéologique préservé. Réglable --openness-downsample.
- Génération webapp concentrée sur les couches affichées : les défauts
  /api/generate, /api/preview et le sélecteur génèrent le panneau complet
  (slope, aspect, pos_open) au lieu d'aspect seul.
2026-09-19 00:53:22 +02:00
91d31bcdf9 Numéroter les zones après tri, lire le journal par la fin et corriger l'aide -g 2026-09-18 21:24:57 +02:00
5e13151998 Fermer les images PIL et borner le cache de cartes de localisation 2026-09-18 21:20:14 +02:00
de8d84b94b Échapper les noms de dalles injectés dans l'interface (HTML et <script> inline) 2026-09-18 21:16:01 +02:00
ac182da55e Sert l'interface (app.js/app.css) depuis l'image, plus depuis le volume
- Les assets de l'interface étaient écrits dans le volume (output/assets)
  et servis d'ici : sur la webapp légère, un app.js périmé restait servi
  même après rebuild de l'image.
- app.js/app.css (+ Leaflet vendorisé) sont désormais bâchés dans l'image
  au build (Dockerfile.webapp) et servis depuis l'image ; le volume ne
  porte que les données (index.html, vignettes, tuiles).
- _write_ui_assets() génère les assets dans un dossier cible ; repli de
  régénération au démarrage si non bâchés (dev). build_index continue
  d'écrire output/assets/ pour le mode serveur statique.
2026-09-17 00:42:12 +02:00
6fb2c4ee97 Ne plus réadopter les runs de génération vidés au rechargement de la page
- Le bouton « Vider » ne retirait que les tâches du côté client : au
  rechargement, la « dernière génération » du serveur
  (.generation.job.json) était réadoptée et les tâches finies
  réappaissaient.
- Les runs retirés sont mémorisés par horodatage serveur (sessionStorage) ;
  l'adoption au chargement les ignore désormais.
- Les tâches lancées immédiatement (sans passer par la file) captent
  l'horodatage de leur run à la fin, pour être retirables sans réadoption.
2026-09-16 23:48:27 +02:00
f024514427 Sélection de tuiles au clic, file d'attente et rafraîchissement fiable
- Clic sur la carte pour choisir des dalles précises, même sans données
  existantes (via /api/cell) ; les zones dessinées s'ajoutent à la
  sélection au lieu de la remplacer
- Une demande lancée pendant un run part en file d'attente côté serveur
  et démarre à la fin du travail en cours (plus de refus 409), file
  vidable depuis l'interface
- Tuiles et interface toujours fraîches : images servies sans cache
  navigateur (revalidation 304), rechargement de la carte seulement une
  fois le rebuild de l'index terminé
- serve-webapp.sh : sous-commande update retirée, documentation de
  déploiement corrigée en conséquence
2026-09-16 22:37:53 +02:00
26c05319fd Tuiles jointives : grille en outline et assets versionnés
La bordure 1px des tuiles insettait l'image (box-sizing: border-box) et
creusait un espace vide entre deux tuiles ; la grille est désormais un
outline dessiné par-dessus le bord des images, sans consommer de place
(hover/sélection/export/régénération adaptés). Les URLs de app.css et
app.js portent un hash de contenu : chaque évolution force le
rechargement chez tous les navigateurs, même avec une entrée de cache
antérieure aux en-têtes no-cache.
2026-09-16 21:42:46 +02:00
328af123ad Zoom animé : tuiles scalées d'un bloc comme le fond de carte
Les marqueurs Leaflet glissent pendant l'animation de zoom sans changer
de taille : les tuiles LiDAR nageaient sur le fond OSM puis sautaient à
la fin du zoom. Elles vivent désormais dans un pane dédié (lidarTiles)
qui reçoit la même mise à l'échelle que les couches de dalles (translate
+ scale au zoomanim, transition CSS partagée leaflet-zoom-animated) ;
markerZoomAnimation est désactivé pour éviter le double mouvement.
2026-09-16 21:34:44 +02:00
daed457adb Alléger la carte : rugosité retirée, vignettes 160 px, cap mémoire
Retire la couche Rugosité du panneau (DEFAULT_LAYERS restreint panneau,
presets et sélecteur de génération). Réduit la mémoire du navigateur :
vignettes de sous-tuiles à 160 px (régénérées sans ré-encoder les AVIF),
pleine résolution plafonnée à 24 images les plus proches du centre, src
des <img> libéré hors écran. Les changements de palier pré-décodent
l'image avant échange (zoom et pan sans flash).
2026-09-16 21:23:24 +02:00
8d29f03191 Rendre l'échelle de rugosité jointive entre tuiles
Le z-score par tuile et le vmax au percentile 98 par tuile donnaient une
échelle de couleur non jointive (écart-type variant de 0,05 a 0,58 m selon
la dalle). Références de normalisation figées (médianes mesurées sur 20
dalles réelles) et vmax fixe 3,8 (p98 médian) : même rugosité physique =
même couleur partout.
2026-09-16 20:33:56 +02:00
cea671c0ac Afficher l'IP client (x-forwarded-for) dans les logs des requêtes API 2026-09-14 19:30:08 +02:00
df462ea86e Inclure les niveaux de transparence du fond de carte dans les presets
Les presets portent désormais les niveaux de transparence complets :
opacité de chaque visualisation + fond de carte OSM (visibilité,
opacité, mode sombre). Les libellés du sélecteur affichent les
niveaux (ex. « Relief — Aspect 100% · Openness positive 65% · Fond
masqué ») et l'application d'un preset resynchronise la ligne du fond
de carte.
2026-09-13 23:28:24 +02:00
d847068288 Ajouter des préconfigurations de couches (couches, transparences, ordre)
L'onglet Couches propose un sélecteur de presets : cinq presets
intégrés (Relief, Pentes, Cavités, Rugosité, Tout) définissent les
couches visibles, leurs transparences et l'ordre de pile. 💾 enregistre
l'état actuel comme preset personnel (persisté en localStorage), ✕ le
supprime depuis la liste « Mes presets ».
2026-09-13 23:17:11 +02:00
0d3aa41008 Filtrer les couches retirées du flux /api/tiles et de la fusion en direct
Au rechargement de la page, l'index obsolète du worker (16 couches)
polluait le /api/tiles fusionné et mergeTilesData réajoutait les couches
retirées au menu. viz_meta est désormais filtré aux couches du panneau
(PANEL_VIZ) côté serveur, et le panneau client est figé au chargement
(clés VIZ_META initiales) : aucun flux ne peut réintroduire de couche
hors panneau, même avec un index distant périmé.
2026-09-13 23:06:08 +02:00
f79608a92f Panéau et couches par défaut limités aux 4 couches conservées
La carte ne conserve que Pente, Aspect, Openness positive et Rugosité :
PANEL_VIZ est restreint à DEFAULT_LAYERS, le sélecteur de génération
suit le panneau, et ces 4 couches sont allumées par défaut via
default_layers (index.html + index_tiles.json). Les autres couches ne
sont plus ni affichées ni proposées.
2026-09-13 21:44:56 +02:00
e2533bac48 Centrer la carte sur le GPS du téléphone (HTTPS terminé par le proxy)
Le bouton ⌖ recentre la carte sur la position GPS du téléphone. L'API
Geolocation exige un contexte sécurisé : la webapp sert désormais du HTTP
et le TLS est porté par le reverse proxy (Traefik, labels dans l'override
local) ; le webapp est transparent au proxy (URLs relatives, X-Forwarded-For
pour la restriction LIDAR_REGEN_CIDR). Ajoute le modèle d'override
docker-compose.webapp.override.yml.example, un rebuild d'index à la demande
et met à jour doc/déploiement ; les tuiles sont servies à la demande.
2026-09-13 19:57:09 +02:00
24897367e0 Partage de vue : lien avec couches, transparences et fond OSM
Bouton « Partager » dans l'onglet Couches : copie un lien URL encodant
la vue (zoom/lat/lng), la pile de couches avec visibilité et opacité,
et le fond OSM (affiché, opacité, mode sombre). Le destinataire reçoit
l'état exact, le lien prime sur son localStorage local. Hash étendu :
#zoom,lat,lng&L=clé:opacité:visible,...&O=on:opacité:dark — le hash
simple #zoom,lat,lng reste rétro-compatible.
2026-09-12 23:43:36 +02:00
bc94ae3df0 Découpler le suffixe de résolution de l'import du pipeline dans l'index
_res_suffix_str importait LidarArchaeoPipeline (donc dtm→numpy) juste pour
le nommage des fichiers : sur la webapp légère sans numpy, build_index
échouait avec « No module named 'numpy' » et l'index n'était jamais
régénéré. Logique réimplémentée localement, synchronisée avec
pipeline._res_suffix et _strip_res_suffix.
2026-09-12 20:52:15 +02:00
8e55fc5f98 Arrêt de génération et reclassification optionnelle depuis l'interface
- POST /api/stop : SIGTERM au pipeline (groupe isolé via start_new_session),
  SIGKILL du groupe après 15 s ; forwardé au worker en mode deux machines
- « Régénérer » n'implique plus la reclassification : le DTM en cache est
  réutilisé tant que la méthode ne change pas ; nouvelle case « Reclasser le
  sol » (--force-classification) et rappel de la classification existante
- Tâche marquée « Interrompu » (returncode négatif ou nul) au lieu d'Échec
2026-09-12 20:27:52 +02:00
68272cabf0 Tuiles visibles en direct après régénération et déploiement webapp distante
- URLs images versionnées (?v=mtime) : une tuile recalculée change d'URL et
  force le rechargement navigateur (cache heuristique contourné), y compris
  en plein run via /api/tiles ; veille permanente 15 s sur la carte
- simulation locale du mode deux machines (docker-compose.local-2m.yml) :
  worker GPU :8974 + webapp légère :8973 au cache séparé output-webapp/
- override webapp pour le Pi 5 (192.168.3.3) : volume /srv/lidar/output,
  rsync vers le worker, labels Traefik (proxy/websecure/myresolver)
- purge 0,5 m : worker/process et politique générale passés à 0,2 m seul
- intègre le travail parallèle non commité : export mosaïque multi-dalles
  (export.py + /api/export), sous-tuilage intégral des couches, légendes
  VIZ_LEGENDS, docs et tests associés (213 tests verts)
2026-09-12 17:48:37 +02:00
cd5bf54066 Fix dangerous pkill, circular import, and dedup _res_suffix
- Scope pkill to 'pdal pipeline' (avoids killing unrelated PDAL jobs)
- Inline _strip_lidar_ext in dtm.py to remove circular import from pipeline
- _res_suffix_str now delegates to LidarArchaeoPipeline._res_suffix
2026-09-07 21:21:57 +02:00
23969c9e14 Add Leaflet interactive map, tile generator compose, auto-sync cache, deploy docs
index.py rewritten as a continuous Leaflet map: rotated L93 tiles, stackable
visualization layers (per-layer opacity, drag-reorder persisted in
localStorage), tile info panel, live rebuild after each tile during a run.
Leaflet is vendored in assets/vendor/ so the map works fully offline;
georeferencing falls back rasterio -> pyproj -> affine so the lightweight
webapp (no GDAL) is supported.

docker-compose.worker.yml adds the tile generator service (full image + GPU)
that remote webapps call via LIDAR_GENERATION_URL, plus a one-shot process
profile. webapp.py gains LIDAR_AUTO_SYNC_SECONDS periodic cache refresh and
LIDAR_REGEN_CIDR restricting generation to the local network. run.sh
--serve-webapp now mounts ~/.ssh read-only so the rsync sync works.

docs/DEPLOY_WEBAPP.md completed for Raspberry Pi deployment: prerequisites,
git clone install, SSH key setup, first sync, update procedure and
troubleshooting.
2026-09-04 21:36:14 +02:00
422f58d772 Split webapp for Raspberry Pi deployment, remote generation API and sync
La webapp (carte + vignettes) et la génération de tuiles se déploient sur
deux machines : image légère Dockerfile.webapp (FastAPI + Pillow AVIF
natif + pyproj) sur Raspberry Pi, pipeline complet sur la machine de
traitement. LIDAR_GENERATION_URL délègue /api/generate, /api/preview et
/api/status ; /api/sync ramène les tuiles par rsync puis régénère
vignettes et index localement. Token partagé optionnel
(LIDAR_API_TOKEN/LIDAR_REMOTE_TOKEN). Retire du dépôt les journaux
internes (.swival, audit-findings) et les données (data/, notebooks/).
Doc : docs/DEPLOY_WEBAPP.md.
2026-09-02 19:44:39 +02:00
ed3e90ea89 Add visualization picker to zone generation and unify tile colors
- Web map: multi-select picker in the generation bar (aspect, slope,
  positive openness, anisotropic openness, wavelet) passed to the API;
  the layer panel is restricted to the same shortlist (PANEL_VIZ) and
  a refresh button rebuilds the index when new layers appear on disk;
  jobs started outside the UI are now adopted into the visible queue
- Uniform colors across tiles: openness/anisotropic/sailore now store
  local z-scores, and all renderers use fixed ranges (0-3 sigma, SVF
  0-1 physical, slope 0-30 deg) instead of per-tile percentile stretches
- Ray-tracing falls back to CPU when VRAM is exhausted so openness and
  SVF no longer fail silently on shared GPUs
- build_index merges visualizations available at only one resolution
  into the displayed tile so in-progress layers stay visible
- 11 new tests (142 passing)
2026-08-31 19:02:14 +02:00
8ca65155db Add web map with zone generation API, side job queue, and restore historical DTM hole rendering
- webapp.py: FastAPI serving the continuous map (port 8973) with
  /api/preview, /api/generate and /api/status; tiles are downloaded
  from IGN and processed in a logged subprocess, tracked live in a
  side "File de génération" panel that survives page reloads
- fetch_ign.py: download missing 1 km LiDAR HD tiles from the IGN
  geoplateforme before processing
- index.py: tile thumbnails and 500 m subtiles are now invalidated by
  mtime so regenerating a tile refreshes its cached images; progress
  logging per tile
- dtm.py: back to the historical gap handling (small gaps filled by
  fillnodata only, larger holes left as nodata rendered black);
  lowest-return floor only via --bare-earth, IGN class selection via
  --ign-classes
- cli.py: positional input now optional (--rebuild-index works alone)
- docker-compose.yml: serve (GPU, port 8973) and process services;
  launch via docker compose only (documented in AGENTS.md/AGENTS.md)
- tests: 131 passing, incl. regressions for thumbnail staleness,
  --rebuild-index without input, and nodata rendering
2026-08-31 18:07:14 +02:00
35bd827790 fix: modal click handler + colormap gradient color format 2026-07-29 00:11:50 +02:00
3d79a5ee72 carte continue: cropped images + continuous map + PDF download via jsPDF 2026-07-28 23:37:40 +02:00
54dbec145e prepare: add index module, update pipeline, tests, Dockerfile, and run.sh 2026-07-28 23:20:20 +02:00