Docs: elevation/slope accuracy + brouter ford avoidance (plan, session log, README)
This commit is contained in:
parent
85aa87edb0
commit
9d510931ad
3 changed files with 149 additions and 2 deletions
|
|
@ -34,9 +34,9 @@
|
|||
- **OTA обновления** — проверка BUILD_NUMBER на роутере (LAN) или VPS, скачивание через браузер.
|
||||
- **Ручные маршруты** — рисование трека на карте тапами, elevation из прошлых треков или open-meteo API.
|
||||
- **Сохранённые маршруты** — импорт GPX-маршрутов, нарисованных заранее (например, в конструкторе Яндекс.Карт: формат `<rtept>`), выбор активного, наложение цветной линией поверх карты во время записи И на экране просмотра прошлого трека — для визуальной навигации. Управление на отдельной странице (импорт/переименование/цвет/удаление, один активный за раз), переключение линии кнопкой-тогглом. Цвета «проезженных дорог» настраиваются раздельно для вело/пеших/бега.
|
||||
- **Высоты маршрута (рельеф до поездки)** — экран предпросмотра маршрута (тап по названию): профиль высоты (крутые участки красным), длина/набор/сброс/макс. уклон, тап по точке — высота и уклон, разворот карты на весь экран. Топографическая обводка линии с тогглом **уклон/высота**: уклон дискретными полосами по 1% (зелёный→жёлтый→красный→коричневый→чёрный, ≥10% чёрный) или гипсометрия по высоте (зелёный→жёлтый→коричневый). Обводка и тоггл доступны и в оверлее на карте записанного трека и во время записи; маршрут рисуется ПОД треком. Высоты (`<ele>` из GPX или онлайн) тянутся по цепочке: **GPXZ** (Copernicus GLO-30, точнее для уклонов; ключ в GPS-настройках, хранится только на устройстве) → open-elevation → open-meteo → OpenTopoData (без ключа). Калории пересчитываются по сглаженным точкам; для уклона высоты сглаживаются (гасит вертикальный шум SRTM).
|
||||
- **Высоты маршрута (рельеф до поездки)** — экран предпросмотра маршрута (тап по названию): профиль высоты (крутые участки красным), длина/набор/сброс/макс. уклон, тап по точке — высота и уклон, разворот карты на весь экран. Топографическая обводка линии с тогглом **уклон/высота**: уклон по НАПРАВЛЕНИЮ движения, полосами по 1%: подъём зелёный→жёлтый→красный→коричневый→чёрный, спуск зелёный→cyan→синий→navy (≥10% крайний), или гипсометрия по высоте (зелёный→жёлтый→коричневый). Обводка и тоггл доступны и в оверлее на карте записанного трека и во время записи; маршрут рисуется ПОД треком. Высоты (`<ele>` из GPX или онлайн) тянутся по цепочке: **GPXZ** (Copernicus GLO-30, точнее для уклонов; ключ в GPS-настройках, хранится только на устройстве) → open-elevation → open-meteo → OpenTopoData (без ключа). Калории пересчитываются по сглаженным точкам; уклон считается по дистанционному окну ~30м (одна ячейка DEM), чтобы ступенька SRTM не давала ложный крутой уклон на одном коротком сегменте. **Поправка высот по проездам**: где катал >=N раз, SRTM-высота в превью сдвигается вверх/вниз на медиану (измеренная−SRTM) по ячейкам ~20м (SRTM остаётся базой, недеструктивно; `get_elev_correction`).
|
||||
- **Редактор маршрутов** — создание («Новый маршрут») и правка сохранённого маршрута прямо в приложении: тап по карте — добавить точку в конец, **тап по линии — вставить точку** (широкая зона попадания), долгий тап по линии — переключить отрезок дорога/прямая, тащить точку — двигать, тап по точке — удалить. Роутинг **по-сегментный**: каждый отрезок между опорными точками отдельно либо по дорогам (BRouter, профиль trekking, высоты из BRouter), либо прямой; по дорогам по умолчанию, где дороги/сегментов нет — молча прямая; кнопка **«🚲 По дорогам»** задаёт режим сразу всем. Маршрут в редакторе рисуется **оковкой с раскраской уклон/высота** как в детали; тумблеры день/ночь, уклон/высота и кнопка «моё место» на карте. Сохраняются и **опорные точки** (5-6, для правки — при повторном открытии столько же), и плотная дорожная геометрия с высотами (для показа и профиля уклона).
|
||||
- **Оффлайн-роутинг (BRouter)** — движок BRouter встроен в приложение (Android): маршруты строятся по дорогам без сети, сегменты `.rd5` региона качаются с домашнего зеркала прямо в приложении (экран дорог → «Сегменты»). Используется в редакторе маршрутов («По дорогам») и для заполнения GPS-пропусков. На десктопе/дома движка нет — те же вызовы уходят на домашний BRouter-RouteServer по HTTP.
|
||||
- **Оффлайн-роутинг (BRouter)** — движок BRouter встроен в приложение (Android): маршруты строятся по дорогам без сети, сегменты `.rd5` региона качаются с домашнего зеркала прямо в приложении (экран дорог → «Сегменты»). Используется в редакторе маршрутов («По дорогам») и для заполнения GPS-пропусков. На десктопе/дома движка нет — те же вызовы уходят на домашний BRouter-RouteServer по HTTP. Профиль `trekking` по умолчанию **избегает бродов** (`ford`), заброшенных грунтовок (`tracktype=grade5`) и троп с плохой видимостью (`trail_visibility=bad|horrible|no`); тумблер `%allow_adventure%` (деф. false). Показ опасных участков на превью + опт-ин «испытать удачу» — в работе.
|
||||
- **Заполнение GPS-пропусков по дороге** — на детали трека кнопка **«🧩»** прокладывает дорожный путь (BRouter, профиль shortest) через каждый GPS-дропаут (разрыв по времени + реальная хорда) и показывает **предпросмотр только достроенных пропусков** (голубым, с бело-чёрной оковкой; недостроенные — красным пунктиром) плюс панель «Достроено N (+X км), M не удалось» с кнопками **Сохранить/Отмена**. Сохранение — **обратимый патч на месте**: достроенные точки помечаются `estimated` и добавляются в трек (оригинал цел), статистика пересчитывается; повторный тап предлагает **«Убрать достройку»** (удаляет только достроенное). Достраиваются только реальные длинные потери сигнала (по умолчанию разрыв > 60с и хорда > 150м); пропуск не достраивается, если дорога заметно длиннее хорды (крюк, > 2×) или почти совпадает с прямой (мостить нечего) — чтобы не перерисовывать нормальные участки объездами.
|
||||
- **Непроезжие места (nogo)** — красные круги, которые роутинг ОБЪЕЗЖАЕТ. Ставятся кнопкой **⛔**: в планировщике — тапом по карте/линии, на карте записи — «здесь нет проезда» (текущее место). Показываются на картах планировщика, записи и детали трека; тап по кругу — убрать. Избегание работает и через домашний RouteServer, и встроенным движком офлайн (BRouter nogopoints). Web-BRouter умеет nogo сам.
|
||||
- **Объезд с возвратом на маршрут (на ходу)** — на карте записи кнопка **«↪»**: если активный маршрут ведёт через непроезжее место, строит от текущей позиции объезд обратно НА маршрут за местом затыка (отступ ~1.5 км вперёд, растёт при неудаче до конца маршрута), избегая nogo и разворота на 180° (учитывает курс). Показывается ярким навигационным оверлеем (не меняет сохранённый маршрут и не прерывает запись); долгий тап по кнопке убирает оверлей.
|
||||
|
|
|
|||
91
docs/plans/2026-10-26-elevation-slope-brouter.md
Normal file
91
docs/plans/2026-10-26-elevation-slope-brouter.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# План: точность высот/уклона в предпросмотре + безопасность маршрутов (brouter)
|
||||
|
||||
## Context
|
||||
Пять замечаний по предпросмотру маршрута и маршрутизации (baldav):
|
||||
1. Режим «уклон» врёт: рисует крутой подъём там, где его нет (и наоборот). Высоты из DEM
|
||||
квантуются по ячейкам 30м, точки внутри ячейки имеют одну высоту, на границе - скачок, и вся
|
||||
Δ падает на один короткий сегмент = ложный крутой уклон. (Второе - «не рисует где есть» - предел
|
||||
разрешения SRTM 30м, не чинится без более точного DEM.)
|
||||
2. Спуски красить иначе: сейчас уклон красится по МОДУЛЮ (вверх и вниз одинаково). Спуски по
|
||||
направлению движения должны уходить из зелёного в голубой -> navy.
|
||||
3. brouter трижды завёл к бродам/ледяной воде (ford - теги OSM в данных brouter, не SRTM). Нужно:
|
||||
избегать бродов/сложных троп/крутых спусков по умолчанию, ПОКАЗЫВАТЬ оставшиеся опасные участки
|
||||
на предпросмотре заранее, и дать опцию «разрешить (испытать удачу)». Полный объём.
|
||||
4. Кнопка объезда ↪ на записи срабатывает всегда и ведёт «к первому вейпоинту»: нет проверки, что
|
||||
впереди реально есть затык, а цель выбирается по глобально ближайшей точке маршрута (ломается на
|
||||
петлях и вдали от маршрута).
|
||||
5. Уточнять высоты по многим проездам. Решение пользователя: база - SRTM, медиана высот из треков
|
||||
берётся ТОЛЬКО как поправка вверх/вниз к SRTM (не замена), там где катал.
|
||||
|
||||
Общее: раскраска уклон/высота и расчёт уклона - в ОДНИХ функциях, используются в предпросмотре
|
||||
маршрута, детали записанного трека, редакторе и на экране записи. Правка общих функций чинит везде;
|
||||
проверить надо каждое место (WT4: починил A - проверь B и C в той же области).
|
||||
|
||||
## Критичные файлы и функции
|
||||
- `frontend/js/gps.js`: `GPS.routeElevStats` (расчёт `grades[]`/`smoothed[]`), `GPS.filterAndSmoothAlt`
|
||||
(сглаживание высот - сейчас по ТОЧКАМ, окно 5), `GPS.fillGaps`/`get_ride_graph` (сетка ~20м - база для п.5).
|
||||
- `frontend/js/main.js`: `routeSlopeColor` + `ROUTE_SLOPE_BANDS` + `slopeLegendHtml` (п.2),
|
||||
`drawRoutePolyline`/`showRouteDetail` (предпросмотр), `rejoinReroute` (п.4), `fetchElevations` (п.5).
|
||||
- `src-tauri/gen/android/app/src/main/assets/brouter/profiles2/trekking.brf` (п.3, избегание) +
|
||||
копия в `tools/brouter-web-staging/profiles2/trekking.brf` (единый источник - править обе).
|
||||
- `MainActivity.kt` `routeBrouter` (п.3, вытащить теги путей из `OsmTrack.messageList` рядом с GPX).
|
||||
- `src-tauri/src/lib.rs` `get_ride_graph`/новый агрегат высот (п.5).
|
||||
|
||||
## Подход по пунктам
|
||||
|
||||
### П.1 - уклон по дистанционному окну (вместо ступенек ячейки)
|
||||
В `GPS.routeElevStats` считать `grades[i]` как центральную разность высоты по РАССТОЯНИЮ окном
|
||||
~30м (одна ячейка DEM), а не между соседними точками: для точки i найти вперёд j и назад k так,
|
||||
чтобы суммарная дистанция >= W (конфиг `gradeWindowM`, дефолт 30), grade = (smoothed[j]-smoothed[k])/dist.
|
||||
Так одиночная ступенька ячейки размазывается по всей ячейке. `maxGrade` и профиль - по тем же
|
||||
сглаженным. «Не рисует где есть» - записать как предел разрешения SRTM; реально улучшает п.5.
|
||||
|
||||
### П.2 - направленная раскраска спусков
|
||||
`routeSlopeColor(gradePct)` сделать знакочувствительной: подъём (>=0) - тёплый веер (как сейчас
|
||||
green->yellow->red->brown->black), спуск (<0) - холодный веер green->cyan->blue->navy по модулю.
|
||||
Два массива полос + обновить `slopeLegendHtml` (две шкалы: подъём/спуск). Направление = порядок
|
||||
точек (он же направление движения в треке/маршруте).
|
||||
|
||||
### П.3 - brouter: избегать + показывать + опция
|
||||
- Профиль `trekking.brf`: добавить штрафы (через `assign` в `---context:way`) на `ford=yes`,
|
||||
пересечение waterway без моста, `tracktype=grade4|grade5`, `trail_visibility=bad|horrible`,
|
||||
высокий `sac_scale`/`mtb:scale`; крутой спуск уже есть через `downhillcost`. Параметр
|
||||
`%allow_adventure%` (дефолт false) - при true штрафы снимаются («испытать удачу»).
|
||||
- Показ опасного: в `routeBrouter` рядом с GPX вернуть JSON тегов сегментов из `OsmTrack.messageList`
|
||||
(btools даёт теги путей); нужен короткий спайк - проверить, что messageList заполняется и какие
|
||||
поля. На превью (`drawRoutePolyline`/`showRouteDetail`) пометить участки ford/вода/крутой спуск
|
||||
отдельным стилем + счётчик «броды: N, крутые спуски: M». Тумблер «разрешить броды/сложные тропы»
|
||||
(localStorage + `%allow_adventure%` в вызов BRouter).
|
||||
- Если messageList тегов не отдаёт - запасной путь: крутые спуски берём из уклона (уже есть), броды -
|
||||
пометить честно как «не выяснено без тегов» и решить отдельно. Спайк решает.
|
||||
|
||||
### П.4 - объезд ↪ только при реальном затыке впереди
|
||||
В `rejoinReroute`: (а) спроецировать текущую позицию на маршрут -> индекс прогресса (не глобально
|
||||
ближайший - ломается на петлях), учитывать направление движения; (б) объезд строить ТОЛЬКО если
|
||||
есть nogo на маршруте ВПЕРЕДИ в пределах окна (напр. до +1.5км по маршруту); иначе toast «впереди
|
||||
затыка нет» и ничего не строить. Цель rejoin - первая точка маршрута за nogo + запас.
|
||||
|
||||
### П.5 - поправка высот по проездам (база SRTM + медиана как сдвиг)
|
||||
- Rust (`lib.rs`, рядом с `get_ride_graph`): агрегат по сетке ~20-30м из `gps_points.altitude`:
|
||||
на ячейку median(alt) и count. Новый command, напр. `get_elev_correction`.
|
||||
- JS (`fetchElevations`/`routeElevStats`): после получения SRTM-высот, где у ячейки count>=порога,
|
||||
скорректировать: `elev = SRTM + smooth(median_ridden - SRTM)`. SRTM остаётся базой и формой; треки
|
||||
только двигают вверх/вниз где катал. Порог проездов и сглаживание сдвига - в конфиг.
|
||||
- GPS-высота шумная -> median по многим точкам/проездам + отбрасывание выбросов; барометр DJI
|
||||
(отдельный TODO) улучшит позже.
|
||||
|
||||
## Порядок и коммиты
|
||||
Пункты независимы. Делать по одному, коммит на каждый (commit-before-test), сборка через
|
||||
`./build.sh -d -i android`, проверка на телефоне; follow-up фиксы - отдельными коммитами.
|
||||
Рекомендуемый порядок: 2 (быстрый, визуальный) -> 1 -> 4 -> 5 -> 3 (самый большой, со спайком).
|
||||
|
||||
## Проверка (на устройстве + где можно на ПК)
|
||||
- П.1/П.2: открыть предпросмотр реального маршрута с известным рельефом; переключить уклон/высота;
|
||||
убедиться, что крутой цвет только на реально крутом, спуски холодные. Вёрстку/цвета можно глянуть
|
||||
на ПК в dev (reference_verify_record_screen). Проверить ВСЕ места раскраски: превью маршрута,
|
||||
деталь записанного трека, редактор, экран записи.
|
||||
- П.3: построить маршрут через известный брод/грунтовку -> по умолчанию объезжает; включить
|
||||
«разрешить» -> ведёт через, но помечено на превью. Спайк messageList - логом из routeBrouter.
|
||||
- П.4: на записи вдали от затыка нажать ↪ -> «впереди затыка нет»; поставить nogo на маршруте
|
||||
впереди -> объезд строится за него, не к старту.
|
||||
- П.5: взять ячейки, где много проездов, сравнить профиль до/после коррекции; где не катал - SRTM.
|
||||
56
docs/session-logs/2026-10-26_elevation-slope-brouter.md
Normal file
56
docs/session-logs/2026-10-26_elevation-slope-brouter.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# 2026-10-26 - Точность высот/уклона в предпросмотре + безопасность маршрутов (brouter)
|
||||
|
||||
Работали по утверждённому плану `docs/plans/` (финальный вариант - см. ниже «План»). Пять пунктов
|
||||
по предпросмотру маршрута и маршрутизации. Телефон в ходе работы отключился - часть проверок на
|
||||
устройстве ждёт переподключения (отмечено).
|
||||
|
||||
## Что сделано (по пунктам плана)
|
||||
|
||||
### П.2 - направленная раскраска спусков (коммит 27c60a4)
|
||||
`routeSlopeColor` стала знакочувствительной: подъём - тёплый веер (green->yellow->red->brown->black),
|
||||
спуск по направлению движения - холодный (green->cyan->blue->navy). Легенда показывает обе шкалы.
|
||||
Один общий `routeSlopeColor`/`drawRoutePolyline` -> чинит везде (превью, деталь трека, редактор,
|
||||
оверлей на записи). Проверка на устройстве: ЖДЁТ (нужен реальный маршрут с рельефом).
|
||||
|
||||
### П.1 - уклон по дистанционному окну (коммит 80ddff9)
|
||||
`GPS.routeElevStats`: `grades[i]` теперь центральная разность высоты по РАССТОЯНИЮ окном ~30м
|
||||
(config `gradeWindowM`), а не между соседними точками. Ступенька ячейки DEM (30м) размазывается по
|
||||
ячейке - уходит ложный крутой уклон на одном коротком сегменте. `maxGrade` - по тем же.
|
||||
«Не рисует где есть» - предел разрешения SRTM 30м, не чинится без более точного DEM (улучшает П.5).
|
||||
Проверка: ЖДЁТ устройство.
|
||||
|
||||
### П.4 - объезд ↪ только при реальном затыке впереди (коммит ac37f36)
|
||||
`rejoinReroute`: (а) прогресс = ближайшая точка маршрута к позиции; (б) направление по компасу; (в)
|
||||
объезд строится ТОЛЬКО если nogo реально на маршруте впереди в окне ~2.5км, иначе toast «впереди
|
||||
затыка нет». Цель - первая точка за nogo + 300м. Раньше строил всегда и прыгал «к первому вейпоинту»
|
||||
(глобально ближайшая точка на петле). Проверка: ЖДЁТ устройство (поставить nogo впереди/без nogo).
|
||||
|
||||
### П.5 - поправка высот по проездам: база SRTM + медиана как сдвиг (коммит 0d5a598)
|
||||
Rust `get_elev_correction(minPasses)`: по ячейке ~20м медиана (`altitude_gps_m` − `altitude_srtm_m`)
|
||||
по >= N разным сессиям-проездам. SRTM остаётся базой; это только сдвиг вверх/вниз там, где катал.
|
||||
JS `applyRiddenElevCorrection` применяет сглаженную дельту к высотам маршрута в превью
|
||||
(`showRouteDetail`), недеструктивно (копия; нет покрытия -> без изменений). Порог проездов -
|
||||
`localStorage baldav_elev_corr_passes` (деф. 3). Проверка: ЖДЁТ (ячейки с многими проездами).
|
||||
|
||||
### П.3 - brouter: ИЗБЕГАТЬ (Part A, коммит 85aa87e). Part B - следующим заходом.
|
||||
Профиль `trekking.brf` (asset + staging синхронно): штраф на броды (`ford=yes|stepping_stones`,
|
||||
node и way), `tracktype=grade5`, `trail_visibility=bad|horrible|no`; тумблер `%allow_adventure%`
|
||||
(деф. false = избегать). Теги подтверждены в lookups.dat. Синтаксис сверен с грамматикой BRouter,
|
||||
но локального brouter-jar нет -> ПРОВЕРКА СИНТАКСИСА только маршрутизацией на устройстве (ошибка
|
||||
профиля = routeBrouter бросает ошибку = безопасный отказ, не кривой маршрут).
|
||||
|
||||
## НЕ сделано (объявлено явно)
|
||||
- **П.3 Part B** - показать опасность на превью + опция «испытать удачу»: нужен (1) спайк, отдаёт ли
|
||||
btools `OsmTrack.messageList` теги путей рядом с GPX в `routeBrouter`; (2) если да - пометить
|
||||
ford/вода/крутой спуск на превью + счётчик; (3) отдельный профиль `trekking-adventure.brf`
|
||||
(allow_adventure=true) + тумблер в редакторе (профиль выбирается по ИМЕНИ файла, параметры в
|
||||
btools рантаймом не пробрасываются). Пока включён только default-avoid.
|
||||
- Все проверки на устройстве (телефон отключился): П.1/П.2/П.4/П.5 + синтаксис профиля П.3.
|
||||
|
||||
## Критичные места (для продолжения)
|
||||
- `frontend/js/gps.js`: `routeElevStats` (grades окно), `filterAndSmoothAlt`.
|
||||
- `frontend/js/main.js`: `routeSlopeColor`/`ROUTE_SLOPE_UP`/`ROUTE_SLOPE_DOWN`/`slopeLegendHtml`,
|
||||
`drawRoutePolyline`, `rejoinReroute`, `loadElevCorrection`/`applyRiddenElevCorrection`.
|
||||
- `src-tauri/src/lib.rs`: `get_elev_correction`.
|
||||
- `.../assets/brouter/profiles2/trekking.brf` (+ `tools/brouter-web-staging/profiles2/trekking.brf`).
|
||||
- `MainActivity.kt` `routeBrouter` (для Part B - messageList).
|
||||
Loading…
Add table
Add a link
Reference in a new issue