diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md index 53b5f33..3ec9099 100644 --- a/IMPLEMENTATION_PLAN.md +++ b/IMPLEMENTATION_PLAN.md @@ -26,8 +26,8 @@ app data dir; профиль trekking (идея 2) и shortest (идея 1); л **Success:** на телефоне с вручную положенным тайлом региона (adb push для спайка) вызов `BRouter.route([[lon,lat],[lon,lat]], "shortest")` возвращает дорожный GPX/GeoJSON, а не ошибку. **Tests:** ручной вызов из DevTools (CDP) + лог движка; сверить, что трек идёт по дорогам. -**Status:** DONE (проверено на устройстве 2026-09-09). `shortest` Ростов 5.4км за 3.2с; - `trekking` кросс-тайл Ростов→город 44.8км/набор 316м за 1.2с; GPX с track-length/ascend/cost. +**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 @@ -81,7 +81,7 @@ app data dir; профиль trekking (идея 2) и shortest (идея 1); л 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). - Сквозной прогон в редакторе: 3 точки по город → прямая 1.69км сменилась дорожной линией + Сквозной прогон в редакторе: 3 точки в городе → прямая 1.69км сменилась дорожной линией 2.25км по улицам (Буденновская → кольцо → Ермака). БАГ, найденный и исправленный при этой проверке: `doBrouter` в конце звал `changed()`, который обнулял `routeGeom` и заново ставил `doBrouter` в очередь — бесконечный цикл, дорожная линия никогда не рисовалась. Заменено на прямой @@ -127,7 +127,7 @@ ATM, банк, скамейка, туалеты, вода, кафе/бар/фа автобусная остановка, пекарня/супермаркет/кофе, смотровая, укрытие, пикник и т.д. (набор — как в brouter-web overlays, см. скрины). С фильтром категорий (тумблеры), иконки скачать и рисовать. **Что проанализировать перед реализацией:** -- Источник данных POI ОФФЛАЙН: Overpass-выгрузка по региону (bbox ~100км вокруг город) в +- Источник данных POI ОФФЛАЙН: Overpass-выгрузка по региону (bbox ~100км вокруг опорной точки) в локальный стор (SQLite/JSON, как seed/tiles), т.к. сеть в поле недоступна. rd5 не годится как POI-хранилище. Обновление — по проводу с зеркала (как тайлы/сегменты). - Иконки: взять набор (напр. используемый brouter-web / maki / OSM-carto sprites), лицензия, @@ -136,12 +136,12 @@ brouter-web overlays, см. скрины). С фильтром категори z-order (POI над тайлами/дорогами, под треком/паком). - Перф: сотни-тысячи точек — кластеризация/культинг по зуму и bbox видимой области. **Статус:** v1 СДЕЛАНО (проверено функционально на устройстве). Данные: Overpass по ~100км вокруг -город (адаптивная выгрузка — дробить не понадобилось, весь bbox отдал 5662 POI одним +опорной точки (адаптивная выгрузка — дробить не понадобилось, весь 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 над город, границы/фильтр корректны. +(`POI.attach`). Проверено: 124 значка в кадре z16 над регионом, границы/фильтр корректны. ОСТАЛОСЬ: визуальная проверка на живом экране (WebView в CDP не рисует — скрин чёрный); при желании — расширить область за 100км и добавить недостающие категории (сейчас все 21 категория есть). diff --git a/README.md b/README.md index f4b3863..cc83631 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ - **Оффлайн-роутинг (BRouter)** — движок BRouter встроен в приложение (Android): маршруты строятся по дорогам без сети, сегменты `.rd5` региона качаются с домашнего зеркала прямо в приложении (экран дорог → «Сегменты»). Используется в редакторе маршрутов («По дорогам») и для заполнения GPS-пропусков. На десктопе/дома движка нет — те же вызовы уходят на домашний BRouter-RouteServer по HTTP. - **Заполнение GPS-пропусков по дороге** — на детали трека тумблер **«🧩»** прокладывает дорожный путь (BRouter, профиль shortest) через каждый GPS-дропаут (разрыв по времени + реальная хорда) и рисует его голубым пунктиром поверх трека; если дорога в разы длиннее хорды — оставляет хорду. Оверлей, данные трека не меняет. - **Де-джиттер трека** — сглаживание дрожащего GPS-трека методом Савицкого-Голея (настраиваемое окно/число итераций, живое превью на карте детали трека). Хранится обратимо: оригинал и сглаженный вариант лежат раздельно, калории пересчитываются по сглаженным точкам, откат к оригиналу в один тап. Точность каждого фикса (`accuracy_m`) пишется в БД: при пересчёте трека точки хуже порога «Макс. погрешность GPS» исключаются из расчёта и линии (обратимо — точки в БД остаются; поднять порог = вернуть). Работает во всех пересчётах (кнопка «Пересчитать», «Пересчитать всё», после де-джиттера); импорт/старьё без точности и dead-reckoning заполнения не трогает. -- **POI на карте** — точки интереса (кафе, магазины, вода, туалеты, банки/ATM, остановки, укрытия, смотровые и т.д.) круглыми контрастными значками (эмодзи в кружке, читаемо на светлой и тёмной карте). Кнопка `📍` с панелью-фильтром категорий; рендер по видимой области от зума 13. Данные оффлайн (`data/pois.json`, ~100 км вокруг город, 5662 объекта из OSM/Overpass). На картах записи, деталей трека и дорог. +- **POI на карте** — точки интереса (кафе, магазины, вода, туалеты, банки/ATM, остановки, укрытия, смотровые и т.д.) круглыми контрастными значками (эмодзи в кружке, читаемо на светлой и тёмной карте). Кнопка `📍` с панелью-фильтром категорий; рендер по видимой области от зума 13. Данные оффлайн (`data/pois.json`, ~100 км вокруг опорной точки, 5662 объекта из OSM/Overpass). На картах записи, деталей трека и дорог. - **Тёмная карта** — тумблер `☾` на экранах записи, деталей трека и дорог: инвертирует ТОЛЬКО слой тайлов (`invert + hue-rotate 180° + brightness`, трек/маршрут/дороги остаются цветными), выбор запоминается. Работает одинаково на офлайн-тайлах и онлайне, без ключей/квот/перепаковки. - **Метки ветра** — кнопка «Ветер» на экране записи: тап открывает интервал встречного ветра, тап закрывает. Метки хранятся с треком (`wind_marks`) как эталон для проверки оценки ветра по треку; на расчёт калорий/мощности не влияют. Голосовые метки — на будущее. - **Экспорт/импорт** — свои продукты, рецепты и добавки одним файлом (JSON). diff --git a/docs/brouter-findings.md b/docs/brouter-findings.md index e69ede6..51cc6df 100644 --- a/docs/brouter-findings.md +++ b/docs/brouter-findings.md @@ -38,9 +38,9 @@ BRouter — **маршрутизатор без карты**: на вход оп - **Высоты** в сегментах берутся из **SRTM-90м** (CGIAR). Именно они дают BRouter'у профиль рельефа, по которому он считает набор высоты (см. §4). Без SRTM сегменты соберутся, но без высот — маршруты «с малым набором» не получатся. -- Для нашего региона (Ростовская обл., ~47N/40E) нужны тайлы, чьи SW-углы кратны 5: +- Для нашего региона (~47N/40E) нужны тайлы, чьи SW-углы кратны 5: **`E35_N45.rd5`** (35–40E, 45–50N, ~23.8 МБ) и **`E40_N45.rd5`** (40–45E, ~14.1 МБ) — - город ~40.1E попадает во второй (проверено загрузкой). Одноразовая загрузка по проводу — + опорная точка ~40.1E попадает во второй (проверено загрузкой). Одноразовая загрузка по проводу — тот же паттерн «скачать дома», что для DEM/прогноза. - **ВЕРСИЯ ДАННЫХ (важно, проверено на устройстве).** `lookups.dat` и профили ОБЯЗАНЫ совпадать по версии с сегментами, иначе «lookup version mismatch». Дистрибутив 1.6.3 несёт `lookups.dat` diff --git a/docs/session-logs/2026-09-07_brouter-findings.md b/docs/session-logs/2026-09-07_brouter-findings.md index eec0095..de1f0cf 100644 --- a/docs/session-logs/2026-09-07_brouter-findings.md +++ b/docs/session-logs/2026-09-07_brouter-findings.md @@ -43,8 +43,8 @@ README не трогал: пользовательской фичи пока н run-as cp), запустил через CDP. Первый вызов упал: «lookup version mismatch lookups.dat=10 rd5=11» — дистрибутив 1.6.3 несёт lookups.dat v10, а сегменты brouter.de/segments4 — v11. Взял v11 lookups.dat + trekking.brf + shortest.brf из abrensch/brouter master (misc/profiles2), заменил -вложенные ассеты; движок 1.6.3 их принял. Результаты: shortest Ростов ~5.4км за 3.2с (холодный), -trekking Ростов→город 44.8км/набор 316м за 1.2с (кросс-тайл), на зашитых в apk v11-данных +вложенные ассеты; движок 1.6.3 их принял. Результаты: shortest по региону ~5.4км за 3.2с (холодный), +trekking кросс-тайл в регионе 44.8км/набор 316м за 1.2с, на зашитых в apk v11-данных 617мс. Мост JS→Rust→Kotlin(движок)→GPX работает целиком. Этап 1 = DONE. Урок: профили и lookups.dat ОБЯЗАНЫ совпадать по версии с сегментами (сейчас v11). @@ -63,7 +63,7 @@ readTimeout 60с, до 30 попыток. Итог на устройстве: E4 ## Дополнение 2026-09-09 (3): своё зеркало вместо прямого brouter.de По решению пользователя данные берём со своего зеркала (не с brouter.de напрямую). Инфраструктура: -- Роутер Keenetic (белый IP mirror.invalid): на :88 уже uhttpd (docroot /opt/share/www, USB 23ГБ free). +- Роутер Keenetic (внешний адрес mirror.invalid): на :88 уже uhttpd (docroot /opt/share/www, USB 23ГБ free). Положил тайлы+профили в /opt/share/www/brouter/{segments4,profiles2} — раздаётся как http://192.168.1.1:88/brouter/... (uhttpd игнорирует Range → отдаёт файл целиком; на LAN неважно). - ПК: BRouter RouteServer (jar) в /mnt/02F6E7F6F6E7E7BD/brouter-mirror (segments4/profiles2/customs + @@ -81,7 +81,7 @@ readTimeout 60с, до 30 попыток. Итог на устройстве: E4 - BRouter RouteServer на ПК: /mnt/02F6E7F6F6E7E7BD/brouter-mirror, СИСТЕМНЫЙ systemd brouter.service (multi-user.target, автостарт без логина, поставил пользователь sudo). WAN :17777→ПК:17777. - BRouter-Web (nrenner 0.18.1) на зеркале: http://192.168.1.1:88/brouter-web/ (+WAN), config.js → RouteServer, - дефолт-слой ÖPNV (CARTO/др. — «needs key»), центр город. + дефолт-слой ÖPNV (CARTO/др. — «needs key»), центр — опорная точка. - Тёмная карта в BalDav: перебрали провайдеров (CARTO/Thunderforest/2GIS/Yandex — ключи/квоты/ToS/проекция/ недоступность в РФ; проба доступности из BalDav по мобильному Tele2: доступны OSM/CARTO/ÖPNV/Esri/2GIS, нет OpenTopo/Yandex-vec). Транспортную инвертом — плохо в городе. Решение: OSM-стандарт + CSS @@ -93,7 +93,7 @@ readTimeout 60с, до 30 попыток. Итог на устройстве: E4 на десктопе со скринами на виртуальном экране (Xvfb :99), не только по API. Прогон в реальном UI (`npx tauri dev` на Xvfb :99, драйв через xdotool, скрины `import`): -- Stage 3 «🚲 По дорогам»: 3 опорные точки по город. Прямая линия 1.69км сменилась +- Stage 3 «🚲 По дорогам»: 3 опорные точки в городе. Прямая линия 1.69км сменилась дорожной 2.25км по улицам (Буденновская → кольцо → просп. Ермака). Роутинг — PC-RouteServer (десктоп без встроенного движка), профиль trekking. - Stage 4 «🧩»: трек 2026-06-22 (session 1782115144011, 16.24км, два дропаута ~2км хорды) — @@ -105,7 +105,7 @@ readTimeout 60с, до 30 попыток. Итог на устройстве: E4 линия НИКОГДА не рисовалась (в UI линия оставалась прямой, дистанция не менялась). Исправлено: `doBrouter` рисует напрямую (`updatePolyline(); updateStats();`), `changed()` не трогает. Отдельным коммитом (цикл виден в истории). Для проверки временно уводил дефолт-центр редактора на -город — откатил. +опорную точку — откатил. Проверка на телефоне встроенным движком (Stage 3 планирование, Stage 4 гэпы, докачка сегментов) — когда тело подключат: `./build.sh install -d`. diff --git a/frontend/js/main.js b/frontend/js/main.js index db1d3bf..9de7ff9 100644 --- a/frontend/js/main.js +++ b/frontend/js/main.js @@ -4473,7 +4473,7 @@ let MAP_REGIONS = [ { name: "Москва", bounds: [[55.55, 37.35], [55.95, 37.85]] }, { name: "Санкт-Петербург", bounds: [[59.80, 30.05], [60.10, 30.55]] }, { name: "Ростов-на-Дону", bounds: [[47.15, 39.55], [47.35, 39.85]] }, - { name: "город + окрестности", bounds: [[47.35, 39.95], [47.52, 40.22]] }, + { name: "Мой регион", bounds: [[47.35, 39.95], [47.52, 40.22]] }, { name: "Краснодар", bounds: [[44.95, 38.85], [45.15, 39.15]] }, { name: "Казань", bounds: [[55.70, 49.00], [55.90, 49.30]] }, { name: "Новосибирск", bounds: [[54.90, 82.75], [55.10, 83.15]] }, @@ -5906,7 +5906,7 @@ let TILES_BASE_URL = "http://192.168.1.1:88/baldav/tiles/"; // Regions the packing tools know about. Shown even when the router has no .db for // them yet (greyed out) so nothing silently disappears from the list. let KNOWN_REGIONS = { - novocherkassk: "город", + novocherkassk: "Мой регион", rostov_city: "Ростов-на-Дону", rostov_oblast: "Ростовская обл.", moscow_city: "Москва", @@ -7397,8 +7397,8 @@ function formatDate(iso) { // from the mirror (LAN -> WAN -> brouter.de) by BRouter.downloadTileAndWait. async function showBrouterSegments() { let region = [ - { name: "E35_N45", label: "E35_N45 — Ростов, запад (35–40°E, 45–50°N)" }, - { name: "E40_N45", label: "E40_N45 — город, восток (40–45°E)" }, + { name: "E35_N45", label: "E35_N45 — запад (35–40°E, 45–50°N)" }, + { name: "E40_N45", label: "E40_N45 — восток (40–45°E)" }, ]; let haveSet = new Set(); try { (await BRouter.listTiles()).forEach(t => haveSet.add(t.name)); } catch (e) {} diff --git a/src-tauri/gen/android/app/src/main/java/dev/baldav/app/MainActivity.kt b/src-tauri/gen/android/app/src/main/java/dev/baldav/app/MainActivity.kt index f783d4c..525c29e 100644 --- a/src-tauri/gen/android/app/src/main/java/dev/baldav/app/MainActivity.kt +++ b/src-tauri/gen/android/app/src/main/java/dev/baldav/app/MainActivity.kt @@ -219,7 +219,7 @@ class MainActivity : TauriActivity() { // fine on the fast LAN. val bases = listOf( "http://192.168.1.1:88/brouter/segments4", // LAN mirror - "http://mirror.invalid:8088/brouter/segments4", // WAN mirror (router port-forward) + "http://mirror.invalid:8088/brouter/segments4", // WAN mirror (router port-forward; set real host locally) "https://brouter.de/brouter/segments4" // upstream fallback ) var total = -1L diff --git a/tools/brouter-web/README.md b/tools/brouter-web/README.md index 25d9172..28ab816 100644 --- a/tools/brouter-web/README.md +++ b/tools/brouter-web/README.md @@ -5,7 +5,7 @@ ## Файлы кастомизации (кладутся рядом с распакованным brouter-web) - `config.js` — host RouteServer (LAN 192.168.1.18:17777 / WAN mirror.invalid:17777), профили с зеркала, - базовые слои (ÖPNV дефолт, CARTO Dark «needs key» и т.д.), центр город, профили trekking/shortest. + базовые слои (ÖPNV дефолт, CARTO Dark «needs key» и т.д.), центр — опорная точка, профили trekking/shortest. - `baldav-custom.css` + `baldav-custom.js` — подключены в index.html после `dist/brouter-web.js`: тумблер день/ночь (☾/☀) в тулбаре → тёмная карта (invert только слой тайлов) + тёмная правая панель; авто-простановка нужных POI-оверлеев один раз (флаг localStorage `baldav_bw_overlays_v1`).