294 lines
16 KiB
Markdown
294 lines
16 KiB
Markdown
# BRD: Enduro Trails — Фаза 4 «Продвинутый роутинг»
|
||
|
||
**Версия:** 1.0
|
||
**Дата:** 2026-05-04
|
||
**Автор:** Стрим 🌊
|
||
**Статус:** Согласовано ✅
|
||
|
||
---
|
||
|
||
## 1. Контекст и цели
|
||
|
||
### Что уже есть
|
||
- Роутинг A→B «Дикий путь» (OSRM, до 5 альтернатив)
|
||
- Статистика покрытия (% грунт/асфальт/тропа)
|
||
- Промежуточные точки, GPX экспорт
|
||
- POI в БД: water, peak, viewpoint, ruins, ford, cave_entrance (14K штук)
|
||
|
||
### Проблема
|
||
«Дикий путь» даёт маршрут от A до B с максимумом грунтовок. Но эндуристу часто нужно другое:
|
||
- **«Покататься красиво»** — замкнутый круг от дома, через живописные места, и обратно
|
||
- **«Найти грунтовки рядом»** — не знаешь куда ехать, покажи что есть вокруг
|
||
- **«Соединить два трека»** — есть два хороших участка, как их связать грунтовками
|
||
|
||
### Цель
|
||
Дать эндуристу 3 новых режима роутинга, которые закрывают типичные сценарии: покататься, разведать, связать.
|
||
|
||
---
|
||
|
||
## 2. Фичи
|
||
|
||
---
|
||
|
||
### F-11: «Красивый маршрут» (Scenic Route)
|
||
|
||
#### Описание
|
||
Пользователь указывает **точку старта** и **желаемую дистанцию**. Система строит **замкнутый кольцевой маршрут**, который проходит через максимально живописные места: озёра, видовые точки, заброшки, горы.
|
||
|
||
#### Зачем
|
||
Самый частый сценарий эндуриста: «Хочу покататься км на 150 от дома, но не по асфальту, а красиво». Сейчас нужно вручную ставить точки и строить маршрут. «Красивый маршрут» делает это автоматически.
|
||
|
||
#### Use Cases
|
||
|
||
**UC-11.1 — Покататься от дома**
|
||
> Слава нажимает 🎨 «Красивый маршрут». Кликает на карте — точка старта (дом). Вводит дистанцию: 150 км. Система строит кольцевой маршрут: дом → озеро Сенеж → видовая точка → заброшка → грунтовки → дом. 142 км, 89% грунт.
|
||
|
||
**UC-11.2 — Короткая поездка**
|
||
> Слава хочет покататься на 50 км. Маршрут: дом → лесной массив → грунтовки → дом. 48 км, 94% грунт.
|
||
|
||
**UC-11.3 — Несколько вариантов**
|
||
> Система предлагает 2–3 кольцевых маршрута: северный (через озёра), восточный (через леса), южный (через поля). Слава выбирает северный — через озёра красивее.
|
||
|
||
**UC-11.4 — Нет красивых мест рядом**
|
||
> Слава в степи, рядом нет озёр и видов. Система строит максимально грунтовый кольцевой маршрут, но без бонусных точек. Подпись: «Живописных объектов поблизости не найдено, маршрут по грунтовкам».
|
||
|
||
#### Алгоритм
|
||
|
||
**Шаг 1: Найти привлекательные POI в радиусе**
|
||
- Радиус = желаемая дистанция × 0.6 (примерное кольцо)
|
||
- Выбрать POI с оценкой аттрактивности:
|
||
|
||
| POI тип | Баллы | Вес |
|
||
|---------|-------|-----|
|
||
| `natural=water` (озёра, реки) | 10 | Высокий |
|
||
| `tourism=viewpoint` (видовые точки) | 15 | Очень высокий |
|
||
| `historic=ruins` (заброшки) | 10 | Высокий |
|
||
| `natural=peak` (вершины) | 12 | Высокий |
|
||
| `natural=cave_entrance` (пещеры) | 8 | Средний |
|
||
| `ford=yes` (броды) | 5 | Низкий |
|
||
|
||
**Шаг 2: Выбрать 3–5 POI для маршрута**
|
||
- Жадный алгоритм: начать со старта, на каждом шаге выбирать ближайший POI с максимальными баллами
|
||
- Суммарная дистанция до POI ≤ желаемая дистанция × 0.8 (оставить запас на возврат)
|
||
- После последнего POI — маршрут обратно к старту
|
||
|
||
**Шаг 3: Построить маршрут через POI**
|
||
- Использовать OSRM: старт → POI1 → POI2 → ... → старт
|
||
- Каждый сегмент — запрос к OSRM с `alternatives=false`
|
||
|
||
**Шаг 4: Проверить дистанцию**
|
||
- Если итоговая дистанция > желаемая × 1.3 — уменьшить кол-во POI, перестроить
|
||
- Если < желаемая × 0.5 — добавить POI, перестроить
|
||
|
||
**Шаг 5: Альтернативы**
|
||
- Повторить с другим набором POI (другое направление от старта)
|
||
- Дать 2–3 варианта
|
||
|
||
#### UI
|
||
|
||
**Кнопка:** 🎨 «Красивый маршрут» (рядом с 🗺️ «Дикий путь»)
|
||
|
||
**Панель:**
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ 🎨 Красивый маршрут │
|
||
│ │
|
||
│ 📍 Точка старта: кликни на карте│
|
||
│ 📏 Дистанция: [150] км │
|
||
│ │
|
||
│ [Построить маршрут] │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
**Карточка маршрута (после построения):**
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ 🎨 Северный маршрут 142 км │
|
||
│ ████████████░░░ 4 ч 20 мин │
|
||
│ 89% грунт · 11% асфальт │
|
||
│ │
|
||
│ 💊 Живописные объекты: │
|
||
│ 💧 Озеро Сенеж │
|
||
│ 👁 Смотровая «Высокая» │
|
||
│ 🏚 Заброшенная ферма │
|
||
│ │
|
||
│ [📥 GPX] [Выбрать маршрут] │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
#### Требования
|
||
- Время построения ≤ 15 секунд (несколько OSRM запросов)
|
||
- Дистанция: ввод от 20 до 500 км
|
||
- Кольцевой маршрут = старт и финиш на одной точке
|
||
- POI на маршруте показаны в карточке
|
||
- Спиннер на время построения
|
||
- До 3 вариантов маршрутов
|
||
|
||
---
|
||
|
||
### F-14: «Разведка» (Recon Mode)
|
||
|
||
#### Описание
|
||
Пользователь кликает на карту → система показывает **все грунтовые дороги в радиусе X км** с краткой статистикой: сколько дорог, какая длина, какие типы.
|
||
|
||
#### Зачем
|
||
«Приехал на новое место — что тут есть?». Не нужно строить маршрут — просто посмотреть какие грунтовки рядом, оценить стоит ли ехать сюда.
|
||
|
||
#### Use Cases
|
||
|
||
**UC-14.1 — Разведка в новом месте**
|
||
> Слава приехал на дачу в незнакомый район. Нажимает 📍 «Разведка», кликает на карту. Появляется круг радиусом 20 км с выделенными грунтовками. Статистика: «124 грунтовки, 380 км грунтовых дорог, 85% grade3-5, 12 бродов».
|
||
|
||
**UC-14.2 — Оценка перед поездкой**
|
||
> Слава планирует поездку на выходные. Кликает на место на карте — видит что там всего 3 короткие грунтовки. Решает ехать в другое место.
|
||
|
||
**UC-14.3 — Настройка радиуса**
|
||
> По умолчанию радиус 20 км. Слава меняет на 50 км — видит больше грунтовок.
|
||
|
||
#### Алгоритм
|
||
|
||
1. Получить координаты клика (lat, lon)
|
||
2. Запрос к БД:
|
||
```sql
|
||
SELECT highway_type, track_type, surface, length_m, name
|
||
FROM trails
|
||
WHERE min_lon <= ? AND max_lon >= ? AND min_lat <= ? AND max_lat >= ?
|
||
AND length_m >= 100
|
||
```
|
||
где bbox = центр ± радиус (0.18° для 20 км, 0.45° для 50 км)
|
||
3. Агрегировать: количество, суммарная длина, распределение по типам
|
||
4. Отрисовать круг на карте + подсветить грунтовки внутри
|
||
|
||
#### UI
|
||
|
||
**Кнопка:** 📍 «Разведка» (рядом с 🗺️ и 🎨)
|
||
|
||
**Попап при клике:**
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ 📍 Разведка — 20 км радиус │
|
||
│ │
|
||
│ 🛤 124 грунтовки · 380 км │
|
||
│ │
|
||
│ 🟡 Lev1-2: 45 шт · 120 км │
|
||
│ 🔴 Lev3-5: 68 шт · 210 км │
|
||
│ 🔴 Тропы: 11 шт · 50 км │
|
||
│ │
|
||
│ 💧 Озёра: 3 · 👁 Виды: 2 │
|
||
│ 🌊 Броды: 12 · 🏚 Руины: 1 │
|
||
│ │
|
||
│ Радиус: [20] [50] [100] км │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
**На карте:**
|
||
- Круг (Circle) с полупрозрачной заливкой
|
||
- Грунтовки внутри круга подсвечены (увеличена толщина / opacity)
|
||
|
||
#### Требования
|
||
- Радиус по умолчанию: 20 км, опции: 20 / 50 / 100
|
||
- Запрос к БД ≤ 2 секунды
|
||
- Круг визуально не мешает карте
|
||
- Статистика в попапе обновляется при изменении радиуса
|
||
|
||
---
|
||
|
||
### F-13: «Связка» (Link Route)
|
||
|
||
#### Описание
|
||
Пользователь указывает **два трека / точки на карте** → система строит **маршрут между ними по грунтовкам**, минуя асфальт.
|
||
|
||
#### Зачем
|
||
«Ехал по отличной грунтовке, потом по другой — а между ними 10 км асфальта. Можно ли как-то по грунтовкам перейти?»
|
||
|
||
#### Use Cases
|
||
|
||
**UC-13.1 — Связать два участка**
|
||
> Слава проехал грунтовку А и грунтовку Б. Между ними 8 км асфальта. Нажимает 🔗 «Связка», ставит конечную точку А и начальную точку Б. Система находит обход по грунтовкам: 12 км вместо 8 км асфальта, но 100% грунт.
|
||
|
||
**UC-13.2 — Нет грунтовой связки**
|
||
> Между двумя точками нет никаких грунтовок — только асфальт. Система: «Грунтовая связка не найдена, кратчайший путь — 5 км по асфальту».
|
||
|
||
#### Алгоритм
|
||
Это просто роутинг A→B через «Дикий путь» — уже реализовано. Отличие только в UI:
|
||
- Вместо кнопки «Дикий путь» — кнопка 🔗 «Связка»
|
||
- Маркеры: не A/B, а «Трек 1 (конец)» и «Трек 2 (начало)»
|
||
- Карточка показывает только % грунта (асфальт — нежелательный элемент)
|
||
|
||
#### UI
|
||
|
||
**Кнопка:** 🔗 «Связка»
|
||
|
||
**Панель:**
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ 🔗 Связка │
|
||
│ │
|
||
│ 1️⃣ Конец трека: кликни на карте│
|
||
│ 2️⃣ Начало трека: кликни │
|
||
│ │
|
||
│ [Найти грунтовую связку] │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
**Карточка:**
|
||
```
|
||
┌─────────────────────────────────┐
|
||
│ 🔗 Связка 12 км │
|
||
│ ██████████████████░ 24 мин │
|
||
│ 92% грунт · 8% асфальт │
|
||
│ │
|
||
│ [📥 GPX] [Выбрать] │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
#### Требования
|
||
- Использует тот же OSRM «Дикий путь» роутинг
|
||
- Отличие от «Дикого пути» — только UI (другие маркеры, акцент на минимизацию асфальта)
|
||
- До 3 альтернативных связок
|
||
|
||
---
|
||
|
||
## 3. Нефункциональные требования
|
||
|
||
### Производительность
|
||
- «Красивый маршрут» — ≤ 15 сек (3–5 OSRM запросов)
|
||
- «Разведка» — ≤ 2 сек (один SQL запрос)
|
||
- «Связка» — ≤ 5 сек (один OSRM запрос)
|
||
|
||
### UI
|
||
- 3 новые кнопки в панели управления: 🎨 🔗 📍
|
||
- Режимы взаимоисключающие: активный режим деактивирует остальные
|
||
- При переключении режима — сброс предыдущего состояния
|
||
|
||
---
|
||
|
||
## 4. Приоритет реализации
|
||
|
||
| # | Фича | Приоритет | Сложность | Ценность |
|
||
|---|------|-----------|-----------|----------|
|
||
| F-14 | «Разведка» | 🔴 Высокий | Низкая | Высокая |
|
||
| F-13 | «Связка» | 🟡 Средний | Низкая | Средняя |
|
||
| F-11 | «Красивый маршрут» | 🔴 Высокий | Высокая | Очень высокая |
|
||
|
||
**Рекомендуемый порядок:**
|
||
1. **F-14 «Разведка»** — простая SQL-агрегация, быстрый результат, высокая ценность
|
||
2. **F-13 «Связка»** — почти готово (переиспользуем OSRM), минимум нового кода
|
||
3. **F-11 «Красивый маршрут»** — самый сложный (алгоритм выбора POI, несколько OSRM запросов), но самый ценный
|
||
|
||
---
|
||
|
||
## 5. Решения (согласовано 2026-05-04)
|
||
|
||
| # | Вопрос | Решение |
|
||
|---|--------|--------|
|
||
| 1 | Ввод дистанции | Текстовое поле + пресеты (50/100/150/200 км) |
|
||
| 2 | Направление маршрута | Система сама подбирает (без выбора направления) |
|
||
| 3 | Радиус «Разведки» | 20/50/100 км — ок |
|
||
| 4 | Точки «Связки» | Клик на карту (как «Дикий путь») |
|
||
| 5 | Сезонность | Пока не учитываем |
|
||
|
||
---
|
||
|
||
*Документ согласован. Готов к передаче Dev-агенту.*
|