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.
This commit is contained in:
Antoine Jacquin
2026-09-19 20:44:44 +02:00
parent 204b2ad111
commit 5f018fe2b6
15 changed files with 1075 additions and 247 deletions

View File

@ -158,6 +158,17 @@ def test_build_command_resolutions_match_completeness():
assert cmd[i + 1] == ",".join(str(r) for r in GENERATE_RESOLUTIONS)
def test_resolve_request_orders_tiles_north_to_south():
"""Les tuiles d'une demande partent du nord vers le sud (row décroissante)."""
from types import SimpleNamespace
from lidar_pipeline.webapp import _resolve_request
req = SimpleNamespace(viz=[], all_missing=False, regenerate=False,
tiles=[[1055, 6881], [1054, 6882], [1054, 6880], [1053, 6882]],
ground_class="ign")
tiles, _viz = _resolve_request(req)
assert tiles == [(1053, 6882), (1054, 6882), (1055, 6881), (1054, 6880)]
def test_job_state_persisted_across_reload(tmp_path, monkeypatch):
"""L'état du job survit au redémarrage du serveur (file .generation.job.json)."""
import lidar_pipeline.webapp as webapp
@ -189,6 +200,27 @@ def test_laz_cells_parses_input(tmp_path):
assert laz_cells(tmp_path) == [(1054, 6882), (1055, 6881), (1056, 6880)]
def test_attach_frame_bounds_only_unfinished():
"""Cadres de rendu : coins WGS84 sur les dalles non terminées seulement."""
from lidar_pipeline.webapp import _attach_frame_bounds
tiles = [
{"short": "1054-6882", "name": "LHD_FXX_1054_6882_PTS_LAMB93_IGN69",
"state": "running", "steps": []},
{"short": "1054-6881", "name": "LHD_FXX_1054_6881_PTS_LAMB93_IGN69",
"state": "done", "steps": []},
{"short": "inconnu", "name": "pas_une_dalle", "state": "failed", "steps": []},
]
_attach_frame_bounds(tiles)
assert tiles[0]["col"] == 1054 and tiles[0]["row"] == 6882
assert len(tiles[0]["corners"]) == 4 # SW, SE, NE, NW
lat = [c[0] for c in tiles[0]["corners"]]
lon = [c[1] for c in tiles[0]["corners"]]
assert abs(max(lat) - min(lat)) < 0.02 # ~1 km en degrés
assert abs(max(lon) - min(lon)) < 0.03
assert "corners" not in tiles[1] # terminée : pas de cadre
assert "corners" not in tiles[2] # nom hors grille LHD
def test_preview_all_missing(tmp_path, monkeypatch):
"""all_missing: seulement les dalles présentes dans input/ et incomplètes."""
import lidar_pipeline.webapp as webapp
@ -913,7 +945,8 @@ def test_generate_forwards_to_remote(monkeypatch):
{"tiles": [[1054, 6882]], "regenerate": False,
"reclassify": False,
"ground_class": "ign", "ign_classes": "sol",
"bare_earth": False, "viz": ["aspect"],
"edge_buffer": False,
"viz": ["aspect"],
"all_missing": False})]