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:
@ -149,15 +149,20 @@ def _env_flag(name):
|
||||
in ("1", "true", "yes", "on", "oui"))
|
||||
|
||||
|
||||
def _bg_scale():
|
||||
return 1 if os.environ.get("LIDAR_TILE_BACKGROUND_SCALE", "2").strip() == "1" else 2
|
||||
|
||||
|
||||
def _bg_conf():
|
||||
"""Réglages de la maintenance (relus au démarrage des fils, cf. doc)."""
|
||||
return {
|
||||
"interval": max(10.0, float(os.environ.get(
|
||||
"LIDAR_TILE_BACKGROUND_INTERVAL", "120") or 120)),
|
||||
# Défaut : jusqu'au natif (18@2x = 0,2 m/px) — pyramide complète.
|
||||
"max_z": max(tiles_mod.TILE_MIN_Z, int(os.environ.get(
|
||||
"LIDAR_TILE_BACKGROUND_MAX_Z", "16") or 16)),
|
||||
"scale": 1 if (os.environ.get(
|
||||
"LIDAR_TILE_BACKGROUND_SCALE", "2").strip() == "1") else 2,
|
||||
"LIDAR_TILE_BACKGROUND_MAX_Z", "") or (tiles_mod.TILE_MAX_NATIVE_Z - (
|
||||
0 if _bg_scale() == 1 else 1)))),
|
||||
"scale": _bg_scale(),
|
||||
"fmt": (os.environ.get("LIDAR_TILE_BACKGROUND_FMT", "avif")
|
||||
or "avif").strip(),
|
||||
"pause": max(0.0, float(os.environ.get(
|
||||
@ -169,17 +174,20 @@ def _bg_conf():
|
||||
|
||||
_bg = {"threads": [], "stop": threading.Event(), "queue": deque(),
|
||||
"queued": set(), "guard": threading.Lock(), "snapshot": None,
|
||||
"prefetch": deque(),
|
||||
"prefetch": deque(), "incomplete": {},
|
||||
"running": False,
|
||||
"stats": {"rendues": 0, "a_jour": 0, "vides": 0, "scans": 0,
|
||||
"dernier_scan": None, "ajouts_dernier_scan": 0}}
|
||||
|
||||
|
||||
def _bg_enqueue(items, front=False):
|
||||
def _bg_enqueue(items, front=False, rejected=None):
|
||||
"""Ajoute des tuiles (layer, z, x, y) à la file : dédupliquée, bornée.
|
||||
|
||||
rejected : ensemble complété des tuiles refusées faute de place.
|
||||
front=True : en tête de file, dans l'ordre donné (dalles tout juste
|
||||
rendues) ; une tuile déjà en file y est remontée.
|
||||
rendues) ; une tuile déjà en file y est remontée. L'arriéré n'est pas
|
||||
tronqué pour leur faire place (ses dalles ne seraient jamais reprises) :
|
||||
la file déborde alors brièvement de la tête ajoutée.
|
||||
"""
|
||||
added = 0
|
||||
with _bg["guard"]:
|
||||
@ -189,12 +197,18 @@ def _bg_enqueue(items, front=False):
|
||||
rest = [it for it in _bg["queue"] if it not in keep]
|
||||
_bg["queue"].clear()
|
||||
_bg["queue"].extend(fresh[:_bg_conf()["queue_max"]])
|
||||
_bg["queue"].extend(rest[:max(0, _bg_conf()["queue_max"] - len(_bg["queue"]))])
|
||||
_bg["queue"].extend(rest)
|
||||
if rejected is not None:
|
||||
rejected.update(fresh[_bg_conf()["queue_max"]:])
|
||||
added = sum(1 for it in fresh if it not in _bg["queued"])
|
||||
_bg["queued"] = set(_bg["queue"])
|
||||
return added
|
||||
for item in items:
|
||||
if item in _bg["queued"] or len(_bg["queue"]) >= _bg_conf()["queue_max"]:
|
||||
if item in _bg["queued"]:
|
||||
continue
|
||||
if len(_bg["queue"]) >= _bg_conf()["queue_max"]:
|
||||
if rejected is not None:
|
||||
rejected.add(item)
|
||||
continue
|
||||
_bg["queue"].append(item)
|
||||
_bg["queued"].add(item)
|
||||
@ -223,6 +237,7 @@ def background_scan(output_dir=None):
|
||||
first_scan = _bg["snapshot"] is None
|
||||
snapshot = {}
|
||||
changed = {}
|
||||
resume = {} # dalle inchangée, pyramide pas encore toute en file → reprise
|
||||
for layer, per_cell in tiles_mod.source_index(output_dir, force=True).items():
|
||||
for (col, row), tiers in per_cell.items():
|
||||
newest = 0.0
|
||||
@ -234,6 +249,9 @@ def background_scan(output_dir=None):
|
||||
snapshot[(layer, col, row)] = newest
|
||||
if (_bg["snapshot"] is not None
|
||||
and _bg["snapshot"].get((layer, col, row)) == newest):
|
||||
if (layer, col, row) in _bg["incomplete"]:
|
||||
resume[(layer, col, row)] = _bg["incomplete"][(layer, col, row)]
|
||||
changed.setdefault(layer, []).append((col, row))
|
||||
continue
|
||||
changed.setdefault(layer, []).append((col, row))
|
||||
_bg["snapshot"] = snapshot
|
||||
@ -253,20 +271,41 @@ def background_scan(output_dir=None):
|
||||
if src.url is not None and key not in pending and not src.path.is_file():
|
||||
_bg["prefetch"].append(src)
|
||||
pending.add(key)
|
||||
items = []
|
||||
# File bornée (queue_max) : sur un grand territoire, le premier scan la
|
||||
# remplissait et le reste de la pyramide n'était jamais généré. Chaque
|
||||
# dalle garde donc sa position : les tuiles refusées faute de place sont
|
||||
# reprises aux scans suivants (en queue, derrière l'arriéré), à partir de
|
||||
# la première refusée. Les dalles qui viennent de changer passent en
|
||||
# tête (la pyramide suit le rendu en cours, hors premier scan).
|
||||
order = lambda t: (t[1], t[0], t[2], t[3]) # noqa: E731 — bas niveaux d'abord
|
||||
items, retry, per_cell = [], [], {}
|
||||
for layer, cells in changed.items():
|
||||
for col, row in cells:
|
||||
cell = (layer, col, row)
|
||||
bbox = tiles_mod.cell_bounds_wgs84(col, row)
|
||||
mine = []
|
||||
for z in range(tiles_mod.TILE_MIN_Z, conf["max_z"] + 1):
|
||||
if not (tiles_mod.zoom_supported(z, conf["scale"])
|
||||
and tiles_mod.zoom_cached(z, conf["scale"])):
|
||||
continue
|
||||
for x, y in tiles_mod.tiles_in_bounds(bbox, z):
|
||||
items.append((layer, z, x, y))
|
||||
items.sort(key=lambda t: (t[1], t[0], t[2], t[3])) # bas niveaux d'abord
|
||||
# Dalles qui viennent de changer : en tête de file, devant l'arriéré —
|
||||
# la pyramide suit le rendu en cours (hors premier scan, qui construit tout).
|
||||
added = _bg_enqueue(items, front=first_scan is False)
|
||||
mine.append((layer, z, x, y))
|
||||
mine.sort(key=order)
|
||||
start = resume.get(cell, 0)
|
||||
per_cell[cell] = (start, mine)
|
||||
(retry if cell in resume else items).extend(mine[start:])
|
||||
items.sort(key=order)
|
||||
retry.sort(key=order)
|
||||
rejected = set()
|
||||
added = _bg_enqueue(items, front=first_scan is False, rejected=rejected)
|
||||
added += _bg_enqueue(retry, rejected=rejected)
|
||||
incomplete = {}
|
||||
for cell, (start, mine) in per_cell.items():
|
||||
for i in range(start, len(mine)):
|
||||
if mine[i] in rejected:
|
||||
incomplete[cell] = i
|
||||
break
|
||||
_bg["incomplete"] = incomplete
|
||||
_bg["stats"]["scans"] += 1
|
||||
_bg["stats"]["dernier_scan"] = time.time()
|
||||
_bg["stats"]["ajouts_dernier_scan"] = added
|
||||
|
||||
Reference in New Issue
Block a user