diff --git a/memory/2026-05-13.md b/memory/2026-05-13.md new file mode 100644 index 0000000..16b3de1 --- /dev/null +++ b/memory/2026-05-13.md @@ -0,0 +1,61 @@ +# 2026-05-13 — Terrain UI фикс + генерация тайлов + +## Что сделано + +### Terrain UI баги (из UI-тестов) +- **Попап terrain** — позиционирование исправлено (привязка к кнопке, а не top-right угол) +- **Подписи чекбоксов** — были невидимы из-за отсутствия шрифтов в headless Chromium. Установлены Noto Sans в тестовое окружение. В реальном браузере подписи были видны всегда. +- **"Зум 10+"** подсказка для hillshade — теперь вызывается при открытии попапа + стилизована заметно +- **Переименование:** Гипсометрия → "Высоты цветом", Отмывка → "Тени рельефа" +- **Opacity:** снижен с 0.85 → 0.65 для читаемости подписей населённых пунктов + +### Генерация hypso тайлов +- **Root cause пустых тайлов:** VRT создавался с относительными путями к HGT, сохранялся в другую директорию → GDAL не находил source files → все пиксели = 0 +- **Фикс:** VRT строится с абсолютными путями через `-input_file_list` +- **Тестовая генерация:** Чувашия (зумы 5-14) — подтверждена работоспособность +- **Полная генерация:** 81 HGT файл, зумы 5-12, ~48K тайлов + +### Скачивание недостающих SRTM +- Дыра E041-E046 (Владимир — Нижний Новгород — Чебоксары) закрыта +- 14 файлов скачаны с kurviger.de зеркала (User-Agent нужен!) +- Итого: 81 HGT файл (было 67) + +### Новый слой: Перепады (TRI — Terrain Ruggedness Index) +- Отдельный чекбокс "Перепады" в попапе рельефа +- Алгоритм: gdaldem TRI → color-relief с порогами от TRI=3 +- Цветовая шкала: прозрачный (плоско) → жёлтый (3-5) → оранжевый (5-10) → красный (10+) +- Первая версия порогов (TRI=10) была слишком высокой — среднее TRI=2.97 +- Пересгенерено с порогом от 3 — теперь видно + +### Деплой +- Статика отдаётся через контейнер `prototype-enduro-trails-1` (FastAPI) +- Файлы на хосте НЕ = файлы в контейнере (образ вкомпилен при сборке) +- Нужен `docker cp` после каждого изменения CSS/JS/HTML +- Nginx location `/enduro/terrain/` → `/home/slin/enduro-trails/data/terrain/` (тайлы с хоста напрямую) + +## Технические заметки + +### SRTM зеркала +- `firmware.ardupilot.org/SRTM/ap_srtm3/` — ненадёжно (0 байт) +- `srtm.kurviger.de/SRTM3/Eurasia/` — работает, но нужен User-Agent (403 без него) +- `viewfinderpanoramas.org/dem3/` — таймауты + +### Headless Chromium шрифты +- Контейнер OpenClaw не имеет шрифтов и fontconfig +- Установлены Noto Sans в `~/.local/share/fonts/` + fontconfig из deb +- Без этого кириллица не рендерится в скриншотах + +### TRI color ramp (финальный) +``` +0-2: прозрачный +3: жёлтый (alpha 60) +4: жёлтый (alpha 100) +5: оранжевый (alpha 140) +7: тёмно-оранжевый (alpha 180) +10: красный (alpha 200) +15+: тёмно-красный (alpha 220+) +``` + +## TODO +- [ ] Попап terrain: третий чекбокс обрезается на мобильном — нужен overflow/scroll или сдвиг позиции +- [ ] На зуме 10 MapLibre запрашивает тайлы зума 11 (devicePixelRatio?) — нужно генерить зум 11 тоже или разобраться с overzooming diff --git a/tasks/enduro-trails/scripts/download_west.py b/tasks/enduro-trails/scripts/download_west.py new file mode 100644 index 0000000..8ff0e36 --- /dev/null +++ b/tasks/enduro-trails/scripts/download_west.py @@ -0,0 +1,51 @@ +import urllib.request +import zipfile +import os + +SRTM_DIR = '/home/slin/enduro-trails/data/srtm' +BASE_URL = 'https://srtm.kurviger.de/SRTM3/Eurasia' + +# Smolensk ~32E to Solnechnogorsk ~37E +# Latitudes: N53-N56 (Smolensk is at 54.8N, Moscow at 55.7N) +tiles = [] +for lat in [53, 54, 55, 56]: + for lon in range(32, 37): + tiles.append(f'N{lat}E{lon:03d}') + +os.chdir(SRTM_DIR) +count = 0 + +opener = urllib.request.build_opener() +opener.addheaders = [('User-Agent', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36')] +urllib.request.install_opener(opener) + +for tile in tiles: + hgt = f'{tile}.hgt' + if os.path.exists(hgt): + print(f' EXISTS: {hgt}') + continue + + url = f'{BASE_URL}/{tile}.hgt.zip' + tmp = f'/tmp/{tile}.hgt.zip' + + try: + print(f' Downloading {tile}...', end=' ', flush=True) + urllib.request.urlretrieve(url, tmp) + + if os.path.getsize(tmp) > 0: + with zipfile.ZipFile(tmp, 'r') as z: + z.extractall('.') + os.remove(tmp) + size = os.path.getsize(hgt) if os.path.exists(hgt) else 0 + print(f'OK ({size // 1024}KB)') + count += 1 + else: + print('EMPTY') + os.remove(tmp) + except Exception as e: + print(f'FAIL: {e}') + if os.path.exists(tmp): + os.remove(tmp) + +print(f'\nDownloaded: {count} new files') +print(f'Total HGT: {len([f for f in os.listdir(".") if f.endswith(".hgt")])}')