BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
# IMPLEMENTATION_PLAN: встраивание BRouter в BalDav
|
|
|
|
|
|
|
|
|
|
|
|
Основано на `docs/brouter-findings.md`. Цель — оффлайн-роутинг внутри BalDav (движок BRouter
|
|
|
|
|
|
встроен в Android-модуль, `btools.router.RoutingEngine` в процессе, MIT). Две прикладные фичи:
|
|
|
|
|
|
идея 1 (заполнение GPS-пропусков по дороге) и идея 2 (оффлайн-планирование маршрута по точкам).
|
|
|
|
|
|
|
|
|
|
|
|
Ключевые решения: встраивание (вариант B); сегменты `.rd5` качаются по проводу внутри BalDav в
|
|
|
|
|
|
app data dir; профиль trekking (идея 2) и shortest (идея 1); лицензия MIT (положить `LICENSE-brouter`).
|
|
|
|
|
|
|
|
|
|
|
|
Мост как у GPS-сервиса: JS → Rust `invoke` → Kotlin (движок) → результат обратно. Данные:
|
|
|
|
|
|
профили — assets в apk; сегменты — app data dir (скачиваются). Движок зовём напрямую (без RouteServer).
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Stage 1 — Встраивание движка + спайк «проложи 2 точки»
|
|
|
|
|
|
**Goal:** движок компилируется в составе BalDav и возвращает маршрут по паре точек на телефоне.
|
|
|
|
|
|
**Changes:**
|
|
|
|
|
|
- Извлечь `brouter-1.6.3-all.jar` в `src-tauri/gen/android/app/libs/`, подключить в gradle
|
|
|
|
|
|
(`implementation files('libs/brouter-1.6.3-all.jar')`), включить desugaring при необходимости.
|
|
|
|
|
|
- Профили в assets: `assets/brouter/profiles2/{lookups.dat,trekking.brf,shortest.brf}`.
|
|
|
|
|
|
- Kotlin `BRouterService`/функция: копирует профили из assets в files, зовёт
|
|
|
|
|
|
`btools.router.RoutingEngine(segmentsDir, profilesDir, profile, waypoints, outGpx)`, читает результат.
|
|
|
|
|
|
- Rust-команда `brouter_route(lonlats, profile) -> String(geojson/gpx)` в plugin bridge.
|
|
|
|
|
|
- JS-обёртка (новый `frontend/js/router.js` или в gps.js): `BRouter.route(points, profile)`.
|
|
|
|
|
|
- `LICENSE-brouter` (MIT-нотис) в корень.
|
|
|
|
|
|
**Success:** на телефоне с вручную положенным тайлом региона (adb push для спайка) вызов
|
|
|
|
|
|
`BRouter.route([[lon,lat],[lon,lat]], "shortest")` возвращает дорожный GPX/GeoJSON, а не ошибку.
|
|
|
|
|
|
**Tests:** ручной вызов из DevTools (CDP) + лог движка; сверить, что трек идёт по дорогам.
|
2026-09-09 01:07:24 +03:00
|
|
|
|
**Status:** DONE (проверено на устройстве 2026-09-09). `shortest` Ростов 5.4км за 3.2с;
|
|
|
|
|
|
`trekking` кросс-тайл Ростов→город 44.8км/набор 316м за 1.2с; GPX с track-length/ascend/cost.
|
|
|
|
|
|
ВАЖНО: bundled `lookups.dat` из 1.6.3 — версии 10, а живые сегменты brouter.de/segments4 — v11
|
|
|
|
|
|
(«lookup version mismatch»). Ассеты заменены на v11 из репозитория (abrensch/brouter master:
|
|
|
|
|
|
misc/profiles2/{lookups.dat,trekking.brf,shortest.brf}); движок 1.6.3 их принимает. Профили/lookups
|
|
|
|
|
|
ОБЯЗАНЫ совпадать по версии с сегментами.
|
BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
|
|
|
|
|
|
## Stage 2 — Экран загрузки сегментов по проводу
|
|
|
|
|
|
**Goal:** пользователь скачивает тайлы `.rd5` региона внутри BalDav в app data dir.
|
|
|
|
|
|
**Changes:**
|
|
|
|
|
|
- Экран/настройка «Сегменты дорог»: список нужных тайлов по региону (карта/выбор), кнопка скачать
|
|
|
|
|
|
с `brouter.de/brouter/segments4/<tile>.rd5`, прогресс, размер, дата. Хранить в app data dir
|
|
|
|
|
|
(путь, который читает Stage 1).
|
|
|
|
|
|
- Управление: список скачанного, удалить/обновить.
|
2026-09-09 01:11:20 +03:00
|
|
|
|
**Success:** дома по проводу тайлы региона (E35_N45/E40_N45 — подтверждены) скачиваются и лежат так,
|
BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
что Stage 1 их читает; в поле сеть не нужна.
|
|
|
|
|
|
**Tests:** скачать тайл, проложить маршрут офлайн (сеть выключить) — работает.
|
2026-09-09 01:11:20 +03:00
|
|
|
|
**Status:** ПРИМИТИВ ГОТОВ (компилируется; тест на железе завтра). Kotlin качает тайл в
|
|
|
|
|
|
files/brouter/segments4 (путь детерминирован — качает сам Kotlin, без Rust-догадок): команды
|
|
|
|
|
|
`dltile:<tile>`/`listtiles` в processBrouterCommand, прогресс/статус в brouter_dl_<tile>.json.
|
|
|
|
|
|
Rust-реле: `brouter_download_tile`/`brouter_download_status`/`brouter_list_tiles`. JS:
|
2026-09-09 11:10:24 +03:00
|
|
|
|
`BRouter.downloadTile/downloadStatus/listTiles/downloadTileAndWait`.
|
|
|
|
|
|
ПРОВЕРЕНО НА УСТРОЙСТВЕ 2026-09-09: E40 (14.1 МБ) скачан самим BalDav (done за ~55с), маршрут на
|
|
|
|
|
|
скачанном тайле — кросс-тайл trekking 44.8км/316м за 1.66с (метрики = ПК-версии, тайл валиден),
|
|
|
|
|
|
listTiles отдаёт оба. Прежний стоп на 7922 байтах был из-за того, что BalDav не входил в
|
|
|
|
|
|
сплит-туннель устройства (НЕ сеть/код), — исправлено на устройстве. Загрузчик сделан устойчивым к
|
|
|
|
|
|
рывковой связи: HTTP Range-докачка (продолжает с места обрыва), readTimeout 60с, до 30 попыток.
|
2026-09-09 17:33:11 +03:00
|
|
|
|
UI СДЕЛАН (экран «Сегменты» на карте дорог → модалка `showBrouterSegments`: тайлы региона
|
|
|
|
|
|
E35_N45/E40_N45, статус «есть», кнопка Скачать/Обновить с прогрессом через
|
|
|
|
|
|
BRouter.downloadTileAndWait). Компилируется; загрузку с зеркала на устройстве проверить при телефоне.
|
BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
|
2026-09-09 11:48:50 +03:00
|
|
|
|
ЗЕРКАЛО (по решению пользователя, 2026-09-09): данные качаются НЕ с brouter.de напрямую, а со
|
|
|
|
|
|
своего зеркала. Источники в загрузчике по порядку: LAN `http://192.168.1.1:88/brouter/segments4`
|
|
|
|
|
|
→ WAN `http://mirror.invalid:8088/brouter/segments4` → brouter.de (запас). Зеркало на роутере
|
|
|
|
|
|
(Keenetic uhttpd :88, docroot /opt/share/www → файлы в /opt/share/www/brouter/{segments4,profiles2},
|
|
|
|
|
|
USB, всегда включён). ПРОВЕРЕНО: телефон качает тайл с LAN-зеркала за <2с, маршрут на нём ок.
|
|
|
|
|
|
Плюс BRouter RouteServer на ПК (jar, /mnt/02F6E7F6F6E7E7BD/brouter-mirror, systemd brouter.service —
|
|
|
|
|
|
автостарт без логина) как удалённый роутинг-эндпоинт пользователя (НЕ для BalDav — тот роутит
|
|
|
|
|
|
встроенным движком). WAN-пробросы на Keenetic (PPPoE0): :8088→192.168.1.1:88 (зеркало),
|
|
|
|
|
|
:17777→192.168.1.18:17777 (RouteServer) — outward-facing, ставятся с подтверждением.
|
|
|
|
|
|
|
BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
## Stage 3 — Идея 2: оффлайн-планирование по опорным точкам
|
|
|
|
|
|
**Goal:** тап опорных точек → дорожный маршрут trekking → существующий предпросмотр/профиль.
|
|
|
|
|
|
**Changes:**
|
|
|
|
|
|
- В `showRouteEditor` (frontend/js/main.js): между опорными точками звать `BRouter.route(...,
|
|
|
|
|
|
"trekking")` вместо прямых отрезков; результат (GPX/GeoJSON) парсить существующим `parseRouteGPX`,
|
|
|
|
|
|
дальше работает `showRouteDetail`/`routeElevStats`/`drawRoutePolyline`.
|
|
|
|
|
|
- Фолбэк на прямую линию, если движок/сегмент недоступны.
|
|
|
|
|
|
**Success:** тап точек даёт маршрут по дорогам с профилем высоты; сохраняется как маршрут.
|
|
|
|
|
|
**Tests:** спланировать знакомый маршрут офлайн, сверить с онлайн-BRouter (та же геометрия).
|
2026-09-09 17:33:11 +03:00
|
|
|
|
**Status:** СДЕЛАНО (компилируется; backend роутинга проверен). В `showRouteEditor` кнопка-тумблер
|
|
|
|
|
|
«🚲 По дорогам»: waypoints остаются редактируемыми маркерами, линия между ними прокладывается
|
|
|
|
|
|
BRouter'ом (`brouterMode`/`routeGeom`, debounce 450мс), сохраняется дорожная геометрия. Роутинг —
|
|
|
|
|
|
`BRouter.route` (router.js): Android → встроенный движок, иначе (десктоп/дом) → PC-RouteServer по
|
|
|
|
|
|
HTTP (`http_request`, мимо CSP; хосты LAN 192.168.1.18:17777 / WAN mirror.invalid:17777). Проверено:
|
|
|
|
|
|
RouteServer на 3 точки trekking отдал 83 trkpt (3594м); `parseRouteGPX` читает trkpt. ОСТАЛОСЬ:
|
|
|
|
|
|
сквозной прогон в UI (тап точек → дорожная линия) — на десктопе/телефоне.
|
BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
|
|
|
|
|
|
## Stage 4 — Идея 1: заполнение GPS-пропусков по дороге
|
|
|
|
|
|
**Goal:** GPS-разрыв заполняется дорожным путём (shortest), с фолбэком на хорду.
|
|
|
|
|
|
**Changes:**
|
|
|
|
|
|
- В ветке `isGap` `computeStats`/при обработке трека: проложить `BRouter.route(предгэп, послегэп,
|
|
|
|
|
|
"shortest")`; если длина по графу > ~3× хорды (константа, подобрать на практике) — оставить хорду.
|
|
|
|
|
|
- Точки-заполнители помечать `estimated`; решить зачёт дорожной дистанции (по умолчанию — считать
|
|
|
|
|
|
дорожную длину, но с лимитом гэпа).
|
|
|
|
|
|
**Success:** записанный трек с дропаутом GPS показывает дорожный фолловинг вместо хорды, кроме
|
|
|
|
|
|
случая «дорога в разы длиннее».
|
|
|
|
|
|
**Tests:** трек с известным дропаутом на дороге → заполнение по дороге; дропаут на поле → хорда.
|
2026-09-09 17:43:56 +03:00
|
|
|
|
**Status:** СДЕЛАНО (v1, non-destructive). `GPS.fillGaps(points)` (gps.js): для каждого гэпа
|
|
|
|
|
|
(dt>gapThreshold и хорда>60м) прокладывает `shortest`, вставляет дорожные точки (флаг `estimated`);
|
|
|
|
|
|
фолбэк на хорду если дорога > 3× хорды. Кнопка «🧩» на детали трека — рисует дорожно-заполненный
|
|
|
|
|
|
путь голубым пунктиром оверлеем (данные не меняет). Пересчёт статистики по заполненным точкам —
|
|
|
|
|
|
следующий шаг (сейчас только визуализация).
|
|
|
|
|
|
|
|
|
|
|
|
## Release-хардненинг (item 4, сделано)
|
|
|
|
|
|
- `network_security_config.xml` (res/xml): cleartext OFF глобально в release, разрешён только хостам
|
|
|
|
|
|
зеркала/RouteServer (192.168.1.1 / 192.168.1.18 / mirror.invalid); `debug-overrides` — всё в debug.
|
|
|
|
|
|
Подключён в AndroidManifest (`android:networkSecurityConfig`).
|
|
|
|
|
|
- `proguard-rules.pro`: `-keep class btools.** { *; }` + `-dontwarn btools.**` — минификация release
|
|
|
|
|
|
не вырежет встроенный движок.
|
BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
|
|
|
|
|
|
## Stage 5 — Полировка (опционально)
|
|
|
|
|
|
**Goal:** удобство и корректность.
|
|
|
|
|
|
**Changes:** настройка «избегать подъёмов» (крутилка `uphillcost` в trekking); обновление сегментов;
|
|
|
|
|
|
доки (README/PROJECT_MAP), лог сессии; проверка размера apk.
|
|
|
|
|
|
**Status:** not started
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2026-09-09 13:33:05 +03:00
|
|
|
|
## Stage 6 — POI-оверлеи на картах BalDav (АНАЛИЗ, вне BRouter, запрошено 2026-09-09)
|
|
|
|
|
|
**Идея:** показывать OSM-объекты (amenity/shop/tourism) на картах BalDav — при трекинге и просмотре:
|
|
|
|
|
|
ATM, банк, скамейка, туалеты, вода, кафе/бар/фастфуд/ресторан/паб, велопарковка/веломастерская,
|
|
|
|
|
|
автобусная остановка, пекарня/супермаркет/кофе, смотровая, укрытие, пикник и т.д. (набор — как в
|
|
|
|
|
|
brouter-web overlays, см. скрины). С фильтром категорий (тумблеры), иконки скачать и рисовать.
|
|
|
|
|
|
**Что проанализировать перед реализацией:**
|
|
|
|
|
|
- Источник данных POI ОФФЛАЙН: Overpass-выгрузка по региону (bbox ~100км вокруг город) в
|
|
|
|
|
|
локальный стор (SQLite/JSON, как seed/tiles), т.к. сеть в поле недоступна. rd5 не годится как
|
|
|
|
|
|
POI-хранилище. Обновление — по проводу с зеркала (как тайлы/сегменты).
|
|
|
|
|
|
- Иконки: взять набор (напр. используемый brouter-web / maki / OSM-carto sprites), лицензия,
|
|
|
|
|
|
положить в assets, рисовать как Leaflet divIcon/marker с кластеризацией на низком зуме (перф).
|
|
|
|
|
|
- UI: панель категорий с чекбоксами (как в brouter-web), сохранение выбора (localStorage),
|
|
|
|
|
|
z-order (POI над тайлами/дорогами, под треком/паком).
|
|
|
|
|
|
- Перф: сотни-тысячи точек — кластеризация/культинг по зуму и bbox видимой области.
|
POI overlay on maps: circular contrasting icons + category filter (offline)
Points of interest (cafe, shops, water, toilets, bank/ATM, bus, shelter,
viewpoint, ...) as circular contrasting badges (emoji in a white/dark circle,
readable on light and dark tiles) — not pins. A 📍 control toggles the layer
and opens a per-category filter (checkboxes, remembered). Markers are culled to
the visible bounds and shown from zoom 13 (cap 500/view), on the recording,
track-detail and roads maps.
Data is bundled and fully offline: frontend/data/pois.json ([{la,lo,c,n}], 358KB,
5662 POIs) fetched once from Overpass for ~100km around region (the whole
bbox returned in one query; adaptive subdivision was ready if it had truncated).
Verified functionally on device: 124 badges rendered in view at z16 over
region with correct bounds/category culling; the live visual could not be
screenshotted (the WebView surface is black under CDP). frontend/data + poi.js.
2026-09-09 16:51:58 +03:00
|
|
|
|
**Статус:** v1 СДЕЛАНО (проверено функционально на устройстве). Данные: Overpass по ~100км вокруг
|
|
|
|
|
|
город (адаптивная выгрузка — дробить не понадобилось, весь bbox отдал 5662 POI одним
|
|
|
|
|
|
запросом), компактный `frontend/data/pois.json` [{la,lo,c,n}] (358КБ, бандл, оффлайн). Отрисовка:
|
|
|
|
|
|
`frontend/js/poi.js` — круглые контрастные значки (эмодзи в кружке, `.poi-badge`, светлый/тёмный
|
|
|
|
|
|
под `body.dark-map`), куллинг по видимым границам + от zoom 13, cap 500/кадр; Leaflet-контрол 📍 с
|
|
|
|
|
|
панелью категорий (чекбоксы), выбор в localStorage. Привязан к картам записи/деталей/дорог
|
|
|
|
|
|
(`POI.attach`). Проверено: 124 значка в кадре z16 над город, границы/фильтр корректны.
|
|
|
|
|
|
ОСТАЛОСЬ: визуальная проверка на живом экране (WebView в CDP не рисует — скрин чёрный); при желании —
|
|
|
|
|
|
расширить область за 100км и добавить недостающие категории (сейчас все 21 категория есть).
|
2026-09-09 13:33:05 +03:00
|
|
|
|
|
|
|
|
|
|
## Stage 7 — Тёмные тайлы карты в BalDav (запрошено 2026-09-09)
|
|
|
|
|
|
**Идея:** заменить фон OSM на тёмный (пользователю нравится ÖPNV, но хочет тёмное). ВАЖНО (проверено
|
|
|
|
|
|
2026-09-09): хорошего тёмного растра БЕЗ ключа сейчас нет — CARTO Dark теперь тоже требует ключ
|
|
|
|
|
|
(без ключа отдаёт тайлы с ватермаркой "API KEY REQUIRED"). Кандидаты: Thunderforest Transport Dark
|
|
|
|
|
|
(ÖPNV-стиль тёмный, ближе всего к желаемому — бесплатный ключ), CARTO Dark (ключ), Stadia (ключ);
|
|
|
|
|
|
без ключа и чисто — только светлые (ÖPNVKarte/OpenTopoMap/OSM) или спутник Esri. Источник в
|
|
|
|
|
|
`frontend/js/tilecache.js` хардкодом
|
|
|
|
|
|
`https://a.tile.openstreetmap.org/{z}/{x}/{y}.png` (3 места); оффлайн-тайлы — в `tiles_*.db` (OSM).
|
|
|
|
|
|
**РЕШЕНО (2026-09-09): живой CSS-фильтр, без перепаковки.** Провайдеров тёмных тайлов (CARTO/
|
|
|
|
|
|
Thunderforest/2GIS/Yandex) отмели — ключи/квоты/ToS/проекция/недоступность в РФ. Транспортная карта
|
|
|
|
|
|
инвертом плохо (город). ПОБЕДИЛО: OSM-стандарт (те тайлы, что уже есть) + фильтр
|
|
|
|
|
|
`invert(1) hue-rotate(180deg) brightness(1.5)` на `.leaflet-tile-pane` — достойно и в городе, и на селе.
|
|
|
|
|
|
Реализация: класс `body.dark-map` + одно CSS-правило (только слой тайлов, оверлеи цветные), тумблер
|
|
|
|
|
|
`☾` на экранах записи/деталей трека/дорог (`toggleDarkMap`/`applyDarkMap`/`addDarkMapControl` в main.js),
|
|
|
|
|
|
выбор в localStorage `baldav_dark_map`. Работает одинаково на оффлайн-БД и онлайне, без ключей/квот.
|
|
|
|
|
|
**Статус:** DONE (проверено на устройстве: фильтр на тайлах, overlay `none`, кнопка активна, персист).
|
|
|
|
|
|
|
BRouter: analysis + embed the offline routing engine (Stage 1)
Analysis in docs/brouter-findings.md: how BRouter knows roads (.rd5
segments), routes and reaches low elevation gain (profile uphill/downhill
cost + kinematics), the three call surfaces, and an evaluation of two ideas
— fill GPS gaps along roads, and offline waypoint route planning. License is
MIT; the engine has no desktop-only deps, so it embeds on Android ART.
Stage 1 (embed + bridge, compiles into the apk; on-device route not yet run):
- vendored brouter-1.6.3-all.jar into the Android module (dexes cleanly) and
bundled the trekking/shortest profiles + lookups.dat as assets, copied to
files/brouter/profiles2 on launch
- MainActivity: a brouter_command.txt handler on the existing FileObserver
runs btools.router.RoutingEngine off the UI thread (recipe taken via javap
from ServerHandler) and returns the track as GPX
- Rust brouter_route command: same file bridge as GPS (request + command,
poll for the result), registered in the invoke handler
- frontend/js/router.js: BRouter.route(points, profile) -> GPX (parseRouteGPX)
- LICENSE-brouter (MIT notice) kept alongside the vendored engine
Segments (.rd5, ~13-23 MB per 5x5 tile) are delivered later (Stage 2, wired
download inside BalDav). IMPLEMENTATION_PLAN.md tracks the 5 stages.
2026-09-09 00:56:13 +03:00
|
|
|
|
## Потенциальные проблемы
|
|
|
|
|
|
- Desugaring/`java.lang.invoke` при dex — проверить сборку (AGP обычно тянет).
|
|
|
|
|
|
- Размер/имена тайлов региона на brouter.de — уточнить при Stage 2.
|
|
|
|
|
|
- Время роутинга на телефоне на больших `.rd5` — замерить (может понадобиться таймаут/поток).
|
|
|
|
|
|
- Формат вывода: GeoJSON проще парсить, чем GPX; выбрать при Stage 1.
|
|
|
|
|
|
- Заполнение гэпов не должно ломать существующие фильтры высоты/скорости (estimated-флаг).
|