79 lines
6.8 KiB
Markdown
79 lines
6.8 KiB
Markdown
|
|
# 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) + лог движка; сверить, что трек идёт по дорогам.
|
|||
|
|
**Status:** not started
|
|||
|
|
|
|||
|
|
## Stage 2 — Экран загрузки сегментов по проводу
|
|||
|
|
**Goal:** пользователь скачивает тайлы `.rd5` региона внутри BalDav в app data dir.
|
|||
|
|
**Changes:**
|
|||
|
|
- Экран/настройка «Сегменты дорог»: список нужных тайлов по региону (карта/выбор), кнопка скачать
|
|||
|
|
с `brouter.de/brouter/segments4/<tile>.rd5`, прогресс, размер, дата. Хранить в app data dir
|
|||
|
|
(путь, который читает Stage 1).
|
|||
|
|
- Управление: список скачанного, удалить/обновить.
|
|||
|
|
**Success:** дома по проводу тайлы региона (E35_N45/E40_N45 — уточнить) скачиваются и лежат так,
|
|||
|
|
что Stage 1 их читает; в поле сеть не нужна.
|
|||
|
|
**Tests:** скачать тайл, проложить маршрут офлайн (сеть выключить) — работает.
|
|||
|
|
**Status:** not started
|
|||
|
|
|
|||
|
|
## Stage 3 — Идея 2: оффлайн-планирование по опорным точкам
|
|||
|
|
**Goal:** тап опорных точек → дорожный маршрут trekking → существующий предпросмотр/профиль.
|
|||
|
|
**Changes:**
|
|||
|
|
- В `showRouteEditor` (frontend/js/main.js): между опорными точками звать `BRouter.route(...,
|
|||
|
|
"trekking")` вместо прямых отрезков; результат (GPX/GeoJSON) парсить существующим `parseRouteGPX`,
|
|||
|
|
дальше работает `showRouteDetail`/`routeElevStats`/`drawRoutePolyline`.
|
|||
|
|
- Фолбэк на прямую линию, если движок/сегмент недоступны.
|
|||
|
|
**Success:** тап точек даёт маршрут по дорогам с профилем высоты; сохраняется как маршрут.
|
|||
|
|
**Tests:** спланировать знакомый маршрут офлайн, сверить с онлайн-BRouter (та же геометрия).
|
|||
|
|
**Status:** not started
|
|||
|
|
|
|||
|
|
## Stage 4 — Идея 1: заполнение GPS-пропусков по дороге
|
|||
|
|
**Goal:** GPS-разрыв заполняется дорожным путём (shortest), с фолбэком на хорду.
|
|||
|
|
**Changes:**
|
|||
|
|
- В ветке `isGap` `computeStats`/при обработке трека: проложить `BRouter.route(предгэп, послегэп,
|
|||
|
|
"shortest")`; если длина по графу > ~3× хорды (константа, подобрать на практике) — оставить хорду.
|
|||
|
|
- Точки-заполнители помечать `estimated`; решить зачёт дорожной дистанции (по умолчанию — считать
|
|||
|
|
дорожную длину, но с лимитом гэпа).
|
|||
|
|
**Success:** записанный трек с дропаутом GPS показывает дорожный фолловинг вместо хорды, кроме
|
|||
|
|
случая «дорога в разы длиннее».
|
|||
|
|
**Tests:** трек с известным дропаутом на дороге → заполнение по дороге; дропаут на поле → хорда.
|
|||
|
|
**Status:** not started
|
|||
|
|
|
|||
|
|
## Stage 5 — Полировка (опционально)
|
|||
|
|
**Goal:** удобство и корректность.
|
|||
|
|
**Changes:** настройка «избегать подъёмов» (крутилка `uphillcost` в trekking); обновление сегментов;
|
|||
|
|
доки (README/PROJECT_MAP), лог сессии; проверка размера apk.
|
|||
|
|
**Status:** not started
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## Потенциальные проблемы
|
|||
|
|
- Desugaring/`java.lang.invoke` при dex — проверить сборку (AGP обычно тянет).
|
|||
|
|
- Размер/имена тайлов региона на brouter.de — уточнить при Stage 2.
|
|||
|
|
- Время роутинга на телефоне на больших `.rd5` — замерить (может понадобиться таймаут/поток).
|
|||
|
|
- Формат вывода: GeoJSON проще парсить, чем GPX; выбрать при Stage 1.
|
|||
|
|
- Заполнение гэпов не должно ломать существующие фильтры высоты/скорости (estimated-флаг).
|