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)
This commit is contained in:
Antoine Jacquin
2026-08-31 19:02:14 +02:00
parent 8ca65155db
commit ed3e90ea89
7 changed files with 412 additions and 37 deletions

View File

@ -235,7 +235,18 @@ def test_build_index_generates_html(tmp_path):
assert (assets / "app.css").read_text(encoding='utf-8').startswith('/*')
app_js = (assets / "app.js").read_text(encoding='utf-8')
assert "Couches" in app_js or "layers" in app_js
# Barre de génération : sélecteur multi-visualisations (wavelet, aniso_open,
# openness positive, pente...) et envoi du champ viz à /api/generate
assert 'id="genViz"' in content
assert 'value="wavelet"' in content
assert 'value="aniso_open"' in content
assert 'value="pos_open"' in content
assert 'value="slope"' in content
assert "genViz" in app_js and "viz: vizSel.length" in app_js
assert 'assets/app.css' in content
# Bouton d'actualisation des couches (détection des nouveautés sur disque)
assert 'id="layerRefresh"' in content
assert "/api/layers" in app_js and "/api/rebuild" in app_js
assert 'assets/app.js' in content
# Vérifie les vignettes générées
thumb_dir = output_dir / "index_thumbs"
@ -244,6 +255,22 @@ def test_build_index_generates_html(tmp_path):
assert len(thumbs) >= 2 # au moins hillshade pour chaque tuile
def test_subtiled_viz_covers_generation_choices():
"""Les viz générables depuis la carte sont sous-tuilées (affichage fluide)."""
from lidar_pipeline.index import _CARTO_SUBTILED_VIZ
for key in ('aspect', 'hillshade_multi', 'slope', 'positive_openness',
'aniso_open', 'wavelet'):
assert key in _CARTO_SUBTILED_VIZ
def test_panel_restricted_to_requested_layers():
"""Le panneau et le sélecteur ne proposent que la base aspect + les 4 couches demandées."""
from lidar_pipeline.index import PANEL_VIZ, GEN_VIZ_CHOICES
assert PANEL_VIZ == ('aspect', 'slope', 'positive_openness', 'aniso_open', 'wavelet')
assert {name for name, _ in GEN_VIZ_CHOICES} == {
'aspect', 'slope', 'pos_open', 'aniso_open', 'wavelet'}
def test_build_index_regenerates_stale_thumbnails(tmp_path):
"""Une tuile recalculée (source plus récente) régénère sa vignette."""
import os