auto-sync: 2026-05-04 17:10:01
This commit is contained in:
273
tasks/enduro-trails/BRD_PHASE3.1.md
Normal file
273
tasks/enduro-trails/BRD_PHASE3.1.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# BRD: Enduro Trails — Фаза 3.1 «Улучшение роутинга»
|
||||
|
||||
**Версия:** 1.0
|
||||
**Дата:** 2026-05-04
|
||||
**Автор:** Стрим 🌊
|
||||
**Статус:** На согласовании
|
||||
|
||||
---
|
||||
|
||||
## 1. Контекст и цели
|
||||
|
||||
### Что уже есть (Фаза 2–3)
|
||||
- OSRM с кастомным профилем `enduro.lua` — один маршрут A→B, до 5 альтернатив
|
||||
- Роутинг предпочитает грунтовки (rate=100) и избегает асфальт (rate=1–4)
|
||||
- Статистика покрытия: % грунт / асфальт / тропа
|
||||
|
||||
### Проблемы
|
||||
1. **Мало альтернативных маршрутов** — OSRM часто даёт 1–2 варианта вместо 3–5. Пользователь видит один путь и не может сравнить
|
||||
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` даёт маршруты, которые расходятся на ~5–10% пути. Они визуально почти одинаковые. Пользователь хочет видеть принципиально разные пути: через лес А 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-агенту.*
|
||||
Reference in New Issue
Block a user