Files
wiki/tasks/enduro-trails/BRD_PHASE3.1.md
2026-05-04 17:10:05 +03:00

274 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BRD: Enduro Trails — Фаза 3.1 «Улучшение роутинга»
**Версия:** 1.0
**Дата:** 2026-05-04
**Автор:** Стрим 🌊
**Статус:** На согласовании
---
## 1. Контекст и цели
### Что уже есть (Фаза 23)
- OSRM с кастомным профилем `enduro.lua` — один маршрут A→B, до 5 альтернатив
- Роутинг предпочитает грунтовки (rate=100) и избегает асфальт (rate=14)
- Статистика покрытия: % грунт / асфальт / тропа
### Проблемы
1. **Мало альтернативных маршрутов** — OSRM часто даёт 12 варианта вместо 35. Пользователь видит один путь и не может сравнить
2. **Шлагбаумы не блокируют проезд**`result.barrier = true` добавляет penalty, но маршрут всё равно идёт через шлагбаум. Эндурист не знает — открыт шлагбаум или нет
3. **Тротуары включены в роутинг**`footway` rate=60, OSRM считает тротуары «проезжей» дорогой. В городе маршрут может пойти по тротуару — это незаконно и опасно
4. **Нет визуального предупреждения** — пользователь не видит где на маршруте шлагбаумы, броды, частные территории
### Цель
Сделать роутинг **безопасным и разнообразным**: больше вариантов на выбор, нет маршрутов через шлагбаумы и тротуары, визуальные предупреждения об препятствиях.
---
## 2. Фичи
---
### F-07: Исключить шлагбаумы из роутинга
#### Описание
Дороги с шлагбаумами (gate, bollard, lift_gate), блокпостами (border_control), цепями (chain), столбиками (cycle_barrier, motorcycle_barrier) **полностью исключаются** из графа OSRM. Маршрут никогда не пойдёт через шлагбаум.
#### Зачем
Шлагбаум может быть закрыт. Эндурист приезжает — и путь заблокирован. Приходится искать объезд на месте. Лучше сразу строить маршрут без шлагбаумов.
#### Use Cases
**UC-07.1 — Маршрут без шлагбаумов**
> Слава строит маршрут через лесной массив. Раньше OSRM мог провести через дорогу с шлагбаумом. Теперь маршрут обходит шлагбаум, даже если путь длиннее.
**UC-07.2 — Шлагбаум на единственной дороге**
> Единственная дорога к точке B перекрыта шлагбаумом. OSRM не находит маршрут. Пользователь видит: «Маршрут не найден: на пути есть препятствия (шлагбаумы)».
#### Исключаемые типы препятствий (OSM tag `barrier=*`)
| barrier | Описание | Действие |
|---------|----------|----------|
| `gate` | Ворота, шлагбаум | ❌ Исключить |
| `lift_gate` | Шлагбаум с подъёмником | ❌ Исключить |
| `bollard` | Столбик / боллард | ❌ Исключить |
| `chain` | Цепь | ❌ Исключить |
| `cycle_barrier` | Велобарьер | ❌ Исключить |
| `motorcycle_barrier` | Мотобарьер | ❌ Исключить |
| `border_control` | Блокпост | ❌ Исключить |
| `cattle_grid` | Коровья решётка | ⚠️ Оставить (проезжая) |
| `ford` | Брод | ⚠️ Оставить (отдельная фича) |
| `block` | Блок | ❌ Исключить |
#### Реализация
В `enduro.lua``process_node`: заменить `result.barrier = true` на `result.barrier = false` + `result.forward_mode = mode.inaccessible` (полная блокировка ноды).
```lua
function process_node(profile, node, result)
local barrier = node:get_value_by_key("barrier")
if barrier == "gate" or barrier == "bollard" or barrier == "lift_gate"
or barrier == "chain" or barrier == "cycle_barrier"
or barrier == "motorcycle_barrier" or barrier == "border_control"
or barrier == "block" then
result.barrier = false -- НЕ penalty, а полный запрет
result.forward_mode = mode.inaccessible
result.backward_mode = mode.inaccessible
end
end
```
⚠️ **Требуется пересборка OSRM графа** (~40 мин). Это разовая операция.
---
### F-08: Исключить тротуары из роутинга
#### Описание
Дороги с `highway=footway`, `highway=pedestrian`, `highway=steps` **исключаются** из графа OSRM. Маршрут не пойдёт по тротуару или пешеходной улице.
#### Зачем
Тротуар — не дорога для мотоцикла. В городе OSRM может провести маршрут по тротуару (rate=60 — довольно привлекательный). Это незаконно, опасно для пешеходов, и эндуристу не нужно.
#### Use Cases
**UC-08.1 — Маршрут без тротуаров**
> Слава строит маршрут в черте города. Раньше OSRM мог провести по тротуару вдоль дороги. Теперь маршрут идёт только по проезжей части.
**UC-08.2 — Пешеходная зона**
> Точка B находится на пешеходной улице. OSRM не может доехать прямо до точки — строит маршрут до ближайшей проезжей дороги.
#### Исключаемые типы дорог
| highway | Описание | Действие |
|---------|----------|----------|
| `footway` | Тротуар / пешеходная дорожка | ❌ Исключить из роутинга |
| `pedestrian` | Пешеходная зона / улица | ❌ Исключить |
| `steps` | Лестница | ❌ Исключить |
| `corridor` | Крытый переход | ❌ Исключить |
#### Реализация
В `enduro.lua``process_way`: убрать `footway` из `highway_rate` и добавить проверку:
```lua
-- Дороги, исключаемые из роутинга (тротуары и пешеходные зоны)
local excluded_highways = {
footway = true,
pedestrian = true,
steps = true,
corridor = true,
}
function process_way(profile, way, result)
local highway = way:get_value_by_key("highway")
if not highway then return end
-- Исключаем тротуары и пешеходные зоны
if excluded_highways[highway] then return end -- пропускаем эту дорогу
local rate = highway_rate[highway]
if not rate then return end
...
```
⚠️ **Требуется пересборка OSRM графа** (~40 мин). Вместе с F-07 — одна пересборка.
---
### F-09: Больше альтернативных маршрутов
#### Описание
Предложить пользователю **до 5 существенно разных маршрутов**, не только варианты от OSRM.
#### Зачем
OSRM `alternatives` даёт маршруты, которые расходятся на ~510% пути. Они визуально почти одинаковые. Пользователь хочет видеть принципиально разные пути: через лес А vs через лес Б vs через поля.
#### Подход
**Шаг 1: Максимизировать OSRM-альтернативы**
- Запросить `alternatives=5` с `radiuses` для лучшего снэппинга
- При `TooBig` — fallback на 3→1 (уже реализовано)
**Шаг 2: Дополнительно — штрафование уже найдённых путей**
После получения первого маршрута — запросить OSRM повторно, но «заштрафить» дороги, через которые прошёл первый маршрут. Для этого:
- Увеличить вес дорог на маршруте (concept: «penalized re-query»)
- OSRM `annotations=true` возвращает список way-узлов маршрута
**Реализация (упрощённая):**
1. Запрос 1: `alternatives=5` — получаем N маршрутов от OSRM
2. Если N < 3 — сделать повторный запрос с другим `snapping` или `radiuses`
3. Дедупликация: убрать маршруты, которые отличаются менее чем на 10% от уже найденных (по дистанции)
**Критерий «существенно разный маршрут»:**
- Отличается по дистанции на ≥10%
- Или проходит через разные ключевые точки (определяется по перекрытию геометрии: Jaccard similarity < 0.7)
#### Use Cases
**UC-09.1 — Выбор из 3+ маршрутов**
> Слава строит маршрут 200 км. Получает 3 варианта: через лес (180 км, 92% грунт), через поля (210 км, 95% грунт), комбинированный (195 км, 85% грунт). Каждый визуально отличается на карте.
**UC-09.2 — Только один путь**
> Точки A и B в одном лесу — один разумный путь. Система показывает 1 маршрут, подпись «Альтернативных маршрутов не найдено».
---
### F-10: Слой препятствий на карте
#### Описание
На карте отображаются **шлагбаумы, броды, блокпосты** как отдельный слой с иконками. Пользователь видит препятствия ДО построения маршрута.
#### Зачем
Даже если маршрут обходит шлагбаум — полезно видеть где они. «Ага, тут шлагбаум, значит объехать можно через ту грунтовку». Без слоя — пользователь не знает о препятствиях пока не упрётся.
#### Use Cases
**UC-10.1 — Просмотр препятствий**
> Слава включает слой «Препятствия». На карте появляются иконки: 🚧 шлагбаумы, 🌊 броды, ⛔ блокпосты. Видит что на интересной грунтовке стоит шлагбаум — решает построить маршрут через другую дорогу.
**UC-10.2 — Препятствие на маршруте**
> Маршрут построен. Слава видит брод на маршруте. Кликает — попап: «Брод. Возможен проезд только в сухое время года». Решает выбрать другой маршрут.
#### Источники данных (OSM теги)
| Тип | OSM тег | Иконка | Цвет |
|-----|---------|--------|------|
| Шлагбаум | `barrier=gate/lift_gate` | 🚧 | 🟠 оранжевый |
| Столбик | `barrier=bollard/block` | ⛔ | 🔴 красный |
| Брод | `ford=yes` или `highway=ford` | 🌊 | 🔵 голубой |
| Блокпост | `barrier=border_control` | 🛂 | 🔴 красный |
| Частная территория | `access=private/no` | 🔒 | 🟡 жёлтый |
#### Реализация
**Бэкенд:**
1. Добавить парсинг препятствий в `scripts/parse.py` — таблица `obstacles`:
```sql
CREATE TABLE obstacles (
id INTEGER PRIMARY KEY,
osm_id INTEGER,
obstacle_type TEXT, -- gate, bollard, ford, border_control, private
name TEXT,
lon REAL,
lat REAL
);
CREATE INDEX idx_obstacles_bbox ON obstacles(lon, lat);
```
2. Добавить POI-слой `obstacles` в `build_mvt()` — точки с `obstacle_type` в props.
**Фронт:**
1. Слой в style.json: `obstacles-circles` — цветные круги по типу
2. Кнопка в хедере: 🚧 Препятствия (toggle on/off)
3. Попап при клике: тип, название, предупреждение
⚠️ Требует **перепарсинга PBF** — добавить extract точек barrier из OSM данных.
---
## 3. Приоритет реализации
| # | Фича | Приоритет | Сложность | Зависимости |
|---|------|-----------|-----------|-------------|
| F-07 | Исключить шлагбаумы | 🔴 Высокий | Низкая (lua) + средняя (пересборка графа ~40 мин) | Пересборка OSRM |
| F-08 | Исключить тротуары | 🔴 Высокий | Низкая (lua) + средняя (пересборка) | Пересборка OSRM |
| F-09 | Больше альтернатив | 🟡 Средний | Высокая (алгоритм) | — |
| F-10 | Слой препятствий | 🟡 Средний | Средняя (parse + style + UI) | Перепарсинг PBF |
**Рекомендуемый порядок:**
1. **F-07 + F-08 вместе** — одна правка `enduro.lua`, одна пересборка графа
2. **F-09** — улучшение альтернативных маршрутов (на уже исправленном графе)
3. **F-10** — слой препятствий (перепарсинг + UI)
---
## 4. Пересборка OSRM графа
F-07 и F-08 требуют пересборки — это ~40 минут на сервере mva154.
**Порядок:**
1. Обновить `enduro.lua` (убрать footway из rate + заблокировать barrier nodes)
2. Запустить пересборку:
```bash
cd /home/slin/enduro-trails/osrm
docker compose run --rm osrm-prepare
```
3. Перезапустить роутер:
```bash
docker compose restart osrm-routed
```
4. Проверить: маршрут не идёт через шлагбаумы и тротуары
---
## 5. Открытые вопросы для Славы
1. **Шлагбаумы — всегда блокировать?** Некоторые шлагбаумы открыты всегда (например, на въезде в дачный посёлок). Полная блокировка означает что маршрут НИКОГДА не пойдёт через шлагбаум. Ок, или хочешь опцию «показывать предупреждение но не блокировать»?
2. **Тротуары vs тропы**`footway` в лесу это тропа (можно проехать), `footway` в городе это тротуар (нельзя). Различать по контексту (город/лес) сложно. Предлагаю: исключить все `footway`, а тропы оставить как `path`/`bridleway` (rate=85/90). Норм?
3. **Слой препятствий** — стоит ли перепарсить PBF сейчас, или отложить на потом? Перепарсинг ~30 мин + пересборка OSRM ещё ~40 мин. Итого ~70 мин работы сервера.
4. **Альтернативы — алгоритм** — проще всего оставить OSRM alternatives как есть, но добавить дедупликацию (убрать визуально одинаковые). Или хочешь чтобы я исследовала «penalized re-query» подход для принципиально разных маршрутов? Это сложнее и дольше.
---
*Документ готов к согласованию. После ответов — обновлю и передам Dev-агенту.*