Ajouter la fiche de dalle IGN et la rose des vents, imposer la génération
Un clic sélectionne toujours la dalle sous le curseur (cadre sur la carte), générée ou non : emprise, rendu et recalage des passes s'affichent tout de suite ; la fiche IGN (date et heure du scan LiDAR, capteurs, mission, édition, nombre de points, lien de téléchargement du .copc.laz) arrive à part via /api/map/ign, mise en cache, sans jamais bloquer la sélection. Une rose des vents donne la couleur de chaque orientation de pente du relief orienté, avec la même formule CIELAB que le rendu. La génération impose la classification IGN (sol) et le raccord de 100 m avec les dalles voisines : plus de réglage dans la carte, défauts CLI alignés. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@ -697,7 +697,6 @@ def test_generate_validates_request(tmp_path, monkeypatch):
|
||||
mapserve = _gen_setup(tmp_path, monkeypatch)
|
||||
for kwargs in ({"tiles": []},
|
||||
{"tiles": [[1054]]},
|
||||
{"tiles": [[1054, 6882]], "ground_class": "inconnue"},
|
||||
{"tiles": [[c, 6882] for c in range(500)]}):
|
||||
req = mapserve.GenerateRequest(**kwargs)
|
||||
with pytest.raises(HTTPException) as e:
|
||||
@ -819,13 +818,29 @@ def test_tiles_inventory_endpoint(tmp_path, monkeypatch):
|
||||
assert light["tiles"] is None
|
||||
|
||||
|
||||
def test_generation_always_ign_with_edge_buffer(tmp_path, monkeypatch):
|
||||
"""Classification IGN (sol) et raccord des bords de 100 m imposés, quel
|
||||
que soit ce que le client envoie."""
|
||||
mapserve = _gen_setup(tmp_path, monkeypatch)
|
||||
cmd = mapserve._build_command([(1054, 6882)])
|
||||
i = cmd.index("--edge-buffer")
|
||||
assert cmd[i + 1] == "100"
|
||||
assert cmd[cmd.index("--ground-classification") + 1] == "ign"
|
||||
assert cmd[cmd.index("--ign-classes") + 1] == "sol"
|
||||
req = mapserve.GenerateRequest(tiles=[[1054, 6882]], ground_class="csf", edge_buffer=False)
|
||||
assert not hasattr(req, "ground_class") or getattr(req, "ground_class", None) != "csf"
|
||||
|
||||
|
||||
def test_ui_offers_generation_controls():
|
||||
"""L'interface embarque les contrôles de génération (+ Zone, options, run)."""
|
||||
from lidar_pipeline.mapui import _MAP_CSS, _MAP_HTML, _MAP_JS
|
||||
assert 'id="btnZone"' in _MAP_HTML and 'id="btnComplete"' in _MAP_HTML
|
||||
assert 'id="gencard"' in _MAP_HTML and 'id="genGo"' in _MAP_HTML
|
||||
assert 'id="genStop"' in _MAP_HTML and 'id="genQueueClear"' in _MAP_HTML
|
||||
assert 'id="genViz"' in _MAP_HTML and 'id="genEdge"' in _MAP_HTML
|
||||
assert 'id="genViz"' in _MAP_HTML
|
||||
# Classification et raccord des bords imposés : plus de réglage
|
||||
for gone in ('id="genClass"', 'id="genIgnClasses"', 'id="genReclass"', 'id="genEdge"'):
|
||||
assert gone not in _MAP_HTML
|
||||
# Boutons masqués par défaut : révélés seulement si /api/status autorise
|
||||
assert "GEN.available && GEN.allowed" in _MAP_JS
|
||||
# Dessin de zone + cadres de run + sondage d'état
|
||||
@ -869,3 +884,41 @@ def test_cache_only_fetches_missing_tile_upstream(tmp_path, monkeypatch):
|
||||
assert tiles.tile_cache_path(tmp_path, "aspect", z, x, y, 2, "webp").is_file()
|
||||
finally:
|
||||
monkeypatch.delenv("LIDAR_TILE_CACHE_ONLY")
|
||||
|
||||
|
||||
def test_tile_selection_always_answers(tmp_path, monkeypatch):
|
||||
"""La sélection d'une dalle répond toujours, sans appel réseau : dalle
|
||||
absente comprise, avec nom, emprise L93 et cadre de sélection."""
|
||||
mapserve = _setup(tmp_path, monkeypatch, layers=("relief_oriente",))
|
||||
def boom(*a, **k):
|
||||
raise AssertionError("aucun appel IGN dans /api/map/tile")
|
||||
monkeypatch.setattr("lidar_pipeline.fetch_ign.tile_ign_metadata", boom)
|
||||
d = mapserve.map_tile_info(lat=48.0, lng=2.0) # loin de toute dalle
|
||||
assert d["found"] is False and d["name"].startswith("LHD_FXX_")
|
||||
assert len(d["corners"]) == 4 and d["l93_bbox"][2] - d["l93_bbox"][0] == 1000
|
||||
|
||||
|
||||
def test_ign_metadata_cached_and_resilient(tmp_path, monkeypatch):
|
||||
"""Fiche IGN : un seul appel au catalogue (cache disque) ; catalogue
|
||||
injoignable = message, jamais d'exception."""
|
||||
mapserve = _setup(tmp_path, monkeypatch)
|
||||
calls = []
|
||||
def fake(col, row, timeout=10):
|
||||
calls.append((col, row))
|
||||
return {"found": True, "download_url": "https://data.geopf.fr/x.copc.laz",
|
||||
"acquisition_start": "2022-03-05T16:20:51Z"}
|
||||
monkeypatch.setattr("lidar_pipeline.fetch_ign.tile_ign_metadata", fake)
|
||||
a = mapserve.map_tile_ign(col=1004, row=6832)
|
||||
b = mapserve.map_tile_ign(col=1004, row=6832)
|
||||
assert a["download_url"].endswith(".copc.laz") and b == a and len(calls) == 1
|
||||
def down(col, row, timeout=10):
|
||||
raise OSError("réseau coupé")
|
||||
monkeypatch.setattr("lidar_pipeline.fetch_ign.tile_ign_metadata", down)
|
||||
assert mapserve.map_tile_ign(col=1, row=2)["found"] is False
|
||||
|
||||
|
||||
def test_ui_tile_card_and_wind_rose():
|
||||
from lidar_pipeline.mapui import _MAP_HTML, _MAP_JS
|
||||
assert 'id="rose"' in _MAP_HTML and 'id="roseCanvas"' in _MAP_HTML
|
||||
assert "api/map/ign?col=" in _MAP_JS and "Télécharger le nuage LiDAR" in _MAP_JS
|
||||
assert "compass + 90" in _MAP_JS # même repère que le rendu (aspect = boussole + 90°)
|
||||
|
||||
Reference in New Issue
Block a user