Ne pas générer d overview locale sur la webapp légère (géométrie divergente du worker)
This commit is contained in:
@ -1100,7 +1100,7 @@ def _collect_tile_metadata(tile, dtm_dir):
|
|||||||
return meta
|
return meta
|
||||||
|
|
||||||
|
|
||||||
def build_index(output_dir, output_format='avif'):
|
def build_index(output_dir, output_format='avif', generate_overview=True):
|
||||||
"""Génère la carte interactive HTML des tuiles traitées, organisée par zones.
|
"""Génère la carte interactive HTML des tuiles traitées, organisée par zones.
|
||||||
|
|
||||||
Scanne output_dir/visualisations/, collecte les métadonnées de génération,
|
Scanne output_dir/visualisations/, collecte les métadonnées de génération,
|
||||||
@ -1110,6 +1110,10 @@ def build_index(output_dir, output_format='avif'):
|
|||||||
Args:
|
Args:
|
||||||
output_dir: dossier de sortie racine (contient visualisations/).
|
output_dir: dossier de sortie racine (contient visualisations/).
|
||||||
output_format: format des images ('avif' ou 'webp') — pour info.
|
output_format: format des images ('avif' ou 'webp') — pour info.
|
||||||
|
generate_overview: False sur la webapp légère (LIDAR_GENERATION_URL) :
|
||||||
|
ses mosaïques, bâties sur un cache partiel, auraient une géométrie
|
||||||
|
différente de celles du worker sous le même nom de fichier —
|
||||||
|
l'index distant fusionné après coup fournit les bonnes.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Path vers index.html si succès, None si échec ou aucune tuile.
|
Path vers index.html si succès, None si échec ou aucune tuile.
|
||||||
@ -1278,8 +1282,9 @@ def build_index(output_dir, output_format='avif'):
|
|||||||
logger.info(f" {n_sous} sous-tuiles générée(s) pour {n_dalles} dalle(s)")
|
logger.info(f" {n_sous} sous-tuiles générée(s) pour {n_dalles} dalle(s)")
|
||||||
|
|
||||||
# Mosaïques d'overview (vue dézoomée) : une image par zone et par couche,
|
# Mosaïques d'overview (vue dézoomée) : une image par zone et par couche,
|
||||||
# assemblée depuis les vignettes des dalles de la zone.
|
# assemblée depuis les vignettes des dalles de la zone. Webapp légère :
|
||||||
overview = _build_overview(zone_records, output_dir)
|
# générées par la machine de traitement (cf. generate_overview).
|
||||||
|
overview = _build_overview(zone_records, output_dir) if generate_overview else {}
|
||||||
if overview:
|
if overview:
|
||||||
n_items = sum(len(v['items']) for v in overview.values())
|
n_items = sum(len(v['items']) for v in overview.values())
|
||||||
first = next(iter(overview.values()))['items'][0]
|
first = next(iter(overview.values()))['items'][0]
|
||||||
|
|||||||
@ -340,7 +340,7 @@ def test_rebuild_flag_synchronous(monkeypatch):
|
|||||||
|
|
||||||
go = threading.Event()
|
go = threading.Event()
|
||||||
|
|
||||||
def slow_build(out):
|
def slow_build(out, **kw):
|
||||||
go.wait(2) # rebuild artificiellement long
|
go.wait(2) # rebuild artificiellement long
|
||||||
|
|
||||||
monkeypatch.setattr(index_mod, "build_index", slow_build)
|
monkeypatch.setattr(index_mod, "build_index", slow_build)
|
||||||
@ -855,13 +855,38 @@ def test_available_layers_scans_disk(tmp_path, monkeypatch):
|
|||||||
assert "aspect" not in layers
|
assert "aspect" not in layers
|
||||||
|
|
||||||
|
|
||||||
|
def test_local_rebuild_skips_overview(tmp_path, monkeypatch):
|
||||||
|
"""Webapp légère (GENERATION_URL) : pas de mosaïques d'overview locales.
|
||||||
|
|
||||||
|
Bâties sur un cache partiel, leur géométrie diffère (autre px/km, autre
|
||||||
|
étendue) de celles du worker sous le MÊME nom de fichier : plus récentes
|
||||||
|
(mtime), elles seraient servies à la place et désaligneraient le payload.
|
||||||
|
"""
|
||||||
|
import time
|
||||||
|
import lidar_pipeline.webapp as webapp
|
||||||
|
import lidar_pipeline.index as index_mod
|
||||||
|
|
||||||
|
monkeypatch.setattr(webapp, "OUTPUT_DIR", tmp_path)
|
||||||
|
monkeypatch.setattr(webapp, "GENERATION_URL", "http://distant:8973")
|
||||||
|
seen = {}
|
||||||
|
monkeypatch.setattr(index_mod, "build_index",
|
||||||
|
lambda out, **kw: seen.update(kw) or None)
|
||||||
|
webapp._rebuild.update({"running": False})
|
||||||
|
assert webapp._start_rebuild()["demarré"] is True
|
||||||
|
for _ in range(200):
|
||||||
|
if not webapp._rebuild["running"]:
|
||||||
|
break
|
||||||
|
time.sleep(0.02)
|
||||||
|
assert seen.get("generate_overview") is False
|
||||||
|
|
||||||
|
|
||||||
def test_rebuild_index_background(tmp_path, monkeypatch):
|
def test_rebuild_index_background(tmp_path, monkeypatch):
|
||||||
"""POST /api/rebuild lance build_index en arrière-plan puis termine."""
|
"""POST /api/rebuild lance build_index en arrière-plan puis termine."""
|
||||||
import time as _time
|
import time as _time
|
||||||
import lidar_pipeline.webapp as webapp
|
import lidar_pipeline.webapp as webapp
|
||||||
import lidar_pipeline.index as index_mod
|
import lidar_pipeline.index as index_mod
|
||||||
calls = []
|
calls = []
|
||||||
monkeypatch.setattr(index_mod, "build_index", lambda out: calls.append(out))
|
monkeypatch.setattr(index_mod, "build_index", lambda out, **kw: calls.append(out))
|
||||||
assert webapp.rebuild_index()["demarré"] is True
|
assert webapp.rebuild_index()["demarré"] is True
|
||||||
for _ in range(100):
|
for _ in range(100):
|
||||||
if not webapp.rebuild_status()["running"]:
|
if not webapp.rebuild_status()["running"]:
|
||||||
@ -1024,7 +1049,7 @@ def test_sync_is_rebuild_only(tmp_path, monkeypatch):
|
|||||||
import lidar_pipeline.webapp as webapp
|
import lidar_pipeline.webapp as webapp
|
||||||
import lidar_pipeline.index as index_mod
|
import lidar_pipeline.index as index_mod
|
||||||
calls = []
|
calls = []
|
||||||
monkeypatch.setattr(index_mod, "build_index", lambda out: calls.append(out))
|
monkeypatch.setattr(index_mod, "build_index", lambda out, **kw: calls.append(out))
|
||||||
webapp._rebuild["done"] = None # ignore l'état d'un test précédent
|
webapp._rebuild["done"] = None # ignore l'état d'un test précédent
|
||||||
assert webapp.sync_and_rebuild()["demarré"] is True
|
assert webapp.sync_and_rebuild()["demarré"] is True
|
||||||
for _ in range(200):
|
for _ in range(200):
|
||||||
|
|||||||
@ -1153,7 +1153,11 @@ def _start_rebuild():
|
|||||||
def _run():
|
def _run():
|
||||||
try:
|
try:
|
||||||
from .index import build_index
|
from .index import build_index
|
||||||
build_index(OUTPUT_DIR)
|
# Overview : générée par la machine de traitement — une mosaïque
|
||||||
|
# locale (cache partiel, autre géométrie) sous le même nom de
|
||||||
|
# fichier serait servie à la place de la sienne (mtime plus
|
||||||
|
# récente) et désalignerait le payload distant.
|
||||||
|
build_index(OUTPUT_DIR, generate_overview=not GENERATION_URL)
|
||||||
# Mode deux machines : le rebuild local ne voit que le cache —
|
# Mode deux machines : le rebuild local ne voit que le cache —
|
||||||
# on y fusionne l'index du worker pour que coquille embarquée et
|
# on y fusionne l'index du worker pour que coquille embarquée et
|
||||||
# /api/tiles servent la même vue complète dès le 1er chargement.
|
# /api/tiles servent la même vue complète dès le 1er chargement.
|
||||||
|
|||||||
Reference in New Issue
Block a user