Générer d'avance toute la pyramide jusqu'au natif, plafonner la carte au zoom 19 et reprendre les dalles refusées par la file pleine

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Antoine Jacquin
2026-09-27 13:00:49 +02:00
parent 34152269aa
commit 3d415de86c
7 changed files with 149 additions and 43 deletions

View File

@ -206,7 +206,7 @@ def test_map_meta(tmp_path, monkeypatch):
assert {l["key"] for l in meta["layers"]} == {"relief_oriente", "aspect", "slope"}
assert all(l["label"] for l in meta["layers"])
assert meta["tile_url"] == "tiles/{layer}/{z}/{x}/{y}@2x.avif"
assert meta["even_levels"] is True
assert meta["even_levels"] is False # pyramide complète générée d'avance
assert meta["tile_size"] == 512 and meta["zoom_offset"] == -1
assert meta["max_native_zoom"] == 19
assert meta["bounds"] and meta["stamp"] > 0
@ -581,6 +581,7 @@ def _reset_bg(mapserve):
mapserve._bg["queue"].clear()
mapserve._bg["queued"].clear()
mapserve._bg["snapshot"] = None
mapserve._bg["incomplete"] = {}
mapserve._bg["stats"].update(rendues=0, a_jour=0, vides=0, scans=0,
dernier_scan=None, ajouts_dernier_scan=0)
@ -1190,3 +1191,59 @@ def test_zoom_animation_transforms_only_on_all_tile_layers():
assert re.search(r"const base = new ZoomAnimTileLayer\(", _MAP_JS)
assert "const EvenLevelTileLayer = ZoomAnimTileLayer.extend(" in _MAP_JS
assert "L.tileLayer(" not in _MAP_JS.replace("L.tileLayer` standard", "")
def test_default_policy_pregenerates_every_level_up_to_native(monkeypatch):
"""Par défaut, toute la pyramide jusqu'au natif (18@2x = 0,2 m/px) est
stockée et générée d'avance : aucun niveau rendu à la volée."""
import importlib
import lidar_pipeline.mapserve as mapserve
from lidar_pipeline import tiles
for name in ("LIDAR_TILE_CACHE_MAX_Z", "LIDAR_TILE_EVEN_LEVELS",
"LIDAR_TILE_BACKGROUND_MAX_Z", "LIDAR_TILE_BACKGROUND_SCALE"):
monkeypatch.delenv(name, raising=False)
try:
importlib.reload(tiles)
assert all(tiles.zoom_cached(z, 2) for z in range(tiles.TILE_MIN_Z, 19))
assert all(tiles.zoom_cached(z, 1) for z in range(tiles.TILE_MIN_Z, 20))
assert mapserve._bg_conf()["max_z"] == 18 and mapserve._bg_conf()["scale"] == 2
monkeypatch.setenv("LIDAR_TILE_BACKGROUND_SCALE", "1")
assert mapserve._bg_conf()["max_z"] == 19
finally:
importlib.reload(tiles)
def test_background_scan_retries_cells_beyond_queue_max(tmp_path, monkeypatch):
"""File pleine : les dalles dont la pyramide n'a pas trouvé place sont
reprises aux scans suivants jusqu'à ce que toutes leurs tuiles passent."""
import collections
import lidar_pipeline.mapserve as mapserve
from lidar_pipeline import tiles
monkeypatch.setattr(tiles, "TILE_EVEN_LEVELS", False)
monkeypatch.setattr(tiles, "TILE_CACHE_MAX_Z", 19)
_setup(tmp_path, monkeypatch)
_make_dalle(tmp_path, 1055, 6882, ["aspect"])
conf = dict(mapserve._bg_conf(), max_z=18, scale=2, queue_max=40)
monkeypatch.setattr(mapserve, "_bg_conf", lambda: conf)
for key, val in (("queue", collections.deque()), ("queued", set()),
("snapshot", None), ("prefetch", collections.deque()),
("incomplete", {})):
monkeypatch.setitem(mapserve._bg, key, val)
expected = set()
for layer, per_cell in tiles.source_index(tmp_path, force=True).items():
for col, row in per_cell:
bbox = tiles.cell_bounds_wgs84(col, row)
for z in range(tiles.TILE_MIN_Z, 19):
expected.update((layer, z, x, y) for x, y in tiles.tiles_in_bounds(bbox, z))
assert len(expected) > 3 * conf["queue_max"]
seen = set()
for _ in range(100):
mapserve.background_scan(tmp_path)
seen.update(mapserve._bg["queue"])
mapserve._bg["queue"].clear() # file vidée par les rendeurs
mapserve._bg["queued"].clear()
if not mapserve._bg["incomplete"]:
break
assert seen == expected
# Pyramide passée en entier : les scans suivants se taisent
assert mapserve.background_scan(tmp_path) == 0