331 lines
16 KiB
Markdown
331 lines
16 KiB
Markdown
# Enduro Trails — Концепция и Архитектура
|
||
|
||
**Дата:** 02.05.2026
|
||
**Автор:** Стрим 🌊
|
||
**Статус:** Концепция, ожидает согласования со Славой
|
||
|
||
---
|
||
|
||
## 🎯 Проблема
|
||
|
||
Обычные OSM-карты оптимизированы для автомобилей — они ярко подсвечивают магистрали, а грунтовые дороги и тропы прячутся в шум. Для эндуро это **бесполезно**: асфальт не интересен, хочется увидеть где можно проехать по-настоящему.
|
||
|
||
## 💡 Решение
|
||
|
||
Создать карту, где **грунтовки/тропы — главный слой**, а асфальт — тусклый фон. Плюс фичи для поиска и построения красивых маршрутов.
|
||
|
||
---
|
||
|
||
## Архитектура
|
||
|
||
Схема архитектуры: `enduro_architecture.png`
|
||
|
||
```
|
||
OSM данные → ETL парсинг → Spatialite/PostGIS
|
||
├── Слой: Грунтовки
|
||
├── Слой: Рельеф (SRTM)
|
||
├── Слой: Препятствия
|
||
├── Роутинг (OSRM/GraphHopper)
|
||
└── Аттрактивность (озёра, виды)
|
||
↓
|
||
API Backend (FastAPI)
|
||
↓
|
||
┌───────────────────┼───────────────────┐
|
||
↓ ↓ ↓
|
||
Фронт (PWA) Экспорт GPX/KML Мобильный оффлайн
|
||
```
|
||
|
||
---
|
||
|
||
## Компоненты
|
||
|
||
### 1. Источник данных
|
||
|
||
| Метод | Плюсы | Минусы | Когда нужен |
|
||
|-------|--------|---------|-------------|
|
||
| **PBF дамп** (Geofabrik) | Один раз скачал → локально нет API limits | Обновление раз в неделю | Основной метод |
|
||
| **Overpass API** | Свежие данные (1-5 мин) | Rate limits, нужен интернет | По требованию / дельты |
|
||
|
||
**Рекомендация:** PBF как база + Overpass для свежих изменений
|
||
|
||
**Регион:** По умолчанию Центральный ФО, потом — расширение на всю Россию
|
||
|
||
### 2. ETL Парсинг
|
||
|
||
**Технология:** Pyrosm (Python + osmium) или нативный Osmium
|
||
|
||
**Что парсим:**
|
||
|
||
#### Дороги (highway=*)
|
||
- `track` — грунтовые дороги (основной фокус!)
|
||
- `tracktype=grade1-5` — классификация по твёрдости
|
||
- `surface=unpaved/gravel/sand/mud/earth` — покрытие
|
||
- `trail_visibility=yes/no/negative` — видимость тропы
|
||
- `path` — тропы (пешие + вел/мото)
|
||
- `mtb:scale=0-6` — сложность МТБ
|
||
- `sac_scale=hiking/alpine/demanding` — уровень
|
||
- `unclassified` + `residential` + `service` + `footway` — только для связки (фон)
|
||
- `motorway/trunk/primary/secondary/tertiary` — асфальт (фон, минимум деталей)
|
||
|
||
#### Рельеф
|
||
- SRTM DEM (30 м) или SRTM 90 м
|
||
- Тангенс угла наклона → визуализация крутизны
|
||
- Перепады высот для оценки аттрактивности
|
||
|
||
#### Препятствия и ориентиры
|
||
```
|
||
waterway=ditch + ford — броды и канавы (пройти или нет?)
|
||
waterway=stream + ford — ручьи с бродом
|
||
natural=wetland — болота (сложно!)
|
||
natural=sand — пески
|
||
natural=mud — грязевые участки
|
||
power=line + tower — ЛЭП как визуальные ориентиры
|
||
barrier=gate + bollard — шлагбаумы, столбики
|
||
highway=milestone — километровые столбы
|
||
abandoned=* — заброшенные дороги, шахты
|
||
ruins=yes — ruins, объекты интереса
|
||
leisure=nature_reserve — заповедники, ограничения
|
||
boundary=national_park — нацпарки
|
||
|
||
man_made=bridge
|
||
ford=yes — броды!
|
||
surface=water + highway=track — переправы
|
||
highway=construction — строящиеся дороги (проехать?)
|
||
```
|
||
|
||
### 3. Хранилище
|
||
|
||
**Основной выбор:** Spatialite (SQLite с SpatialExtensions)
|
||
- Меньше зависимостей, portable
|
||
- Файл .sqlite, легко бэкап/мигрировать
|
||
- Достаточно для одного региона
|
||
|
||
**Альтернатива:** PostGIS (есть на FR24 VM!)
|
||
- Если нужен мультирегион или больше данных
|
||
- Лучшая производительность на больших масштабах
|
||
- Уже есть инфраструктура
|
||
|
||
**Структура таблиц:**
|
||
|
||
```sql
|
||
-- Дороги
|
||
CREATE TABLE trails (
|
||
id INTEGER PRIMARY KEY,
|
||
osm_id INTEGER,
|
||
highway_type TEXT, -- track, path, etc.
|
||
track_type TEXT, -- grade1-5
|
||
surface TEXT, -- paved, gravel, sand, etc.
|
||
name TEXT,
|
||
geometry GEOMETRY, -- LINESTRING
|
||
length_m REAL, -- длина в метрах
|
||
start_elevation REAL, -- высота начала
|
||
end_elevation REAL, -- высота конца
|
||
max_slope REAL, -- макс уклон %
|
||
avg_slope REAL, -- средний уклон %
|
||
mtb_scale TEXT, -- mtb:scale
|
||
visibility TEXT, -- trail_visibility
|
||
access TEXT, -- access=private/no
|
||
bridge TEXT, -- yes/no
|
||
ford TEXT, -- yes/no
|
||
tags JSON -- остальные теги
|
||
);
|
||
|
||
-- Точки интереса (POI)
|
||
CREATE TABLE poi (
|
||
id INTEGER PRIMARY KEY,
|
||
osm_id INTEGER,
|
||
poi_type TEXT, -- lake, viewpoint, ruins, etc.
|
||
name TEXT,
|
||
geometry GEOMETRY, -- POINT
|
||
elevation REAL,
|
||
tags JSON
|
||
);
|
||
|
||
-- Слой рельефа
|
||
CREATE TABLE elevation_grid (
|
||
id INTEGER PRIMARY KEY,
|
||
geometry GEOMETRY, -- POLYGON (ячейка сетки)
|
||
min_elev REAL,
|
||
max_elev REAL,
|
||
avg_elev REAL,
|
||
slope_pct REAL -- наклон
|
||
);
|
||
```
|
||
|
||
### 4. Роутинг
|
||
|
||
**Технология:** OSRM (Open Source Routing Machine) или GraphHopper
|
||
|
||
**Кастомизация профиля "Enduro":**
|
||
|
||
| Фактор | Вес |
|
||
|--------|-----|
|
||
| Грунтовки grade3-5 | 🟢 Минимальный вес (привлекают!) |
|
||
| Асфальт primary+ | 🔴 Максимальный вес (избегать) |
|
||
| Рядом с озером/видом | 🟢 Бонус (притягивает маршрут) |
|
||
| Броды | ⚠️ Средний (зависит от настроек) |
|
||
| Болота/пески | 🔴 Высокий (сложность) |
|
||
| Частная территория | ⛔ Проклятие (не роутить!) |
|
||
| Макс уклон > 20% | ⚠️ Высокий (по желанию) |
|
||
|
||
### 5. Фичи для построения маршрутов
|
||
|
||
#### 🛤️ "Дикий путь" (Wild Route)
|
||
- **Вход:** точки А и Б
|
||
- **Цель:** максимизировать грунтовку, минимизировать асфальт
|
||
- **Реализация (v0.2, OSRM):**
|
||
- Кастомный профиль `enduro.lua` для `osrm-routed`
|
||
- `weight_name = 'routability'` — OSRM оптимизирует не по времени, а по предпочтительности дорог
|
||
- `forward_speed = 30` для всех типов дорог — duration одинаковый, выбор идёт ТОЛЬКО по `forward_rate`
|
||
- `forward_rate` (чем выше — тем предпочтительнее): track=100, bridleway=90, path=85, cycleway=70, motorway=0.1
|
||
- `tracktype` мультипликатор: grade1×1.3 (твёрдая грунтовка), grade3×1.0, grade5×0.8 (размытая тропа)
|
||
- `weight = distance / forward_rate` — самый короткий путь по грунтовкам, даже если ехать дольше
|
||
- U-turn penalty 20s, развороты разрешены
|
||
- Граф ~5.2 GB из `enduro.osm.pbf` (ЦФО + Чувашия), контейнер `osrm-routed` порт 5559
|
||
- **Проблемы:** может строить "вне дорог" через unmapped-связи между нодами OSM
|
||
|
||
#### 🎨 "Красивый маршрут" (Scenic Route)
|
||
- **Вход:** начальная точка, желаемая дистанция
|
||
- **Цель:** замкнутый круг через живописные места
|
||
- **Оценка аттрактивности:**
|
||
- Близость к водоёмам (+10)
|
||
- Перепад высот > 300 м (+15)
|
||
- Видовые точки на маршруте (+20)
|
||
- Наличие заброек/руин (+10)
|
||
- Тропы с trail_visibility=yes (+5)
|
||
- Прохождение через ЛЭП как ориентир (+3)
|
||
|
||
#### 🏔️ "Горка" (Elevation Route)
|
||
- **Вход:** точка старта, желаемый набор высоты
|
||
- **Цель:** максимизировать перепад высоты, минимизировать дистанцию
|
||
- **Использование:** тренировка, эндуро-кросс
|
||
|
||
#### 🔗 "Связка" (Link Route)
|
||
- **Вход:** два существующих трека
|
||
- **Цель:** соединить их грунтовками, не по асфальту
|
||
|
||
#### 📍 "Разведка" (Recon Mode)
|
||
- **Вход:** точка на карте
|
||
- **Выход:** все грунтовые дороги в радиусе X км
|
||
- **Использование:** посмотреть что есть вокруг, исследовать местность
|
||
|
||
#### 🚧 "Препятствия" (Obstacle Layer)
|
||
- Карта с подсветкой всех бродов, шлагбаумов, болот, ЛЭП
|
||
- Фильтр по сезонам: некоторые дороги непроходимы в межсезонье
|
||
- Отчёт "что тебя ждёт" перед поездкой
|
||
|
||
#### 📊 Статистика маршрута
|
||
- Общая дистанция, % грунтовки, % асфальта
|
||
- Набор/потеря высоты
|
||
- Максимальный уклон
|
||
- Прогноз времени (зависит от сложности)
|
||
- Техничность: 1-5 по grade дорогам
|
||
|
||
---
|
||
|
||
## Фронтенд
|
||
|
||
### Веб-приложение (основное)
|
||
- **Картографический движок:** MapLibre GL JS (open source форк Mapbox GL)
|
||
- **Стили:** кастомный Mapbox GL Style JSON с перевёрнутой логикой:
|
||
- Грунтовки = яркие, толстые, с градиентом по grade
|
||
- Асфальт = тонкие серые линии
|
||
- POI = иконки (озёра 💙, видовые точки 📷, заброек 🏚️)
|
||
- Рельеф = heatmap с тангенсом угла
|
||
- **Функции:**
|
||
- Клик → статистика дороги (название, длина, grade, покрытие)
|
||
- Рисование маршрута (ручной + автоматический роутинг)
|
||
- Поиск по названиям/тэгам
|
||
- Фильтр слоёв (вкл/выкл)
|
||
- Экспорт GPX/KML
|
||
|
||
### PWA (Mobile)
|
||
- Progressive Web App для работы оффлайн
|
||
- Кэш тайлов для оффлайн навигации
|
||
- GPS трекинг в реальном времени
|
||
- Оффлайн роутинг (загрузка графа в браузер)
|
||
|
||
---
|
||
|
||
## Данные и лицензии
|
||
|
||
### OpenStreetMap
|
||
- **Лицензия:** ODbL (Open Database License)
|
||
- **Требования:** атрибуция (© OpenStreetMap contributors)
|
||
- **Коммерческое использование:** разрешено с сохранением атрибуции
|
||
|
||
### SRTM (рельеф)
|
||
- **Источник:** NASA/USGS
|
||
- **Лицензия:** Public Domain
|
||
- **Качество:** 30 м (1 arc-second), 90 м для регионов без SRTM 30 м
|
||
|
||
### Overpass API
|
||
- **Термины использования:** https://wiki.openstreetmap.org/wiki/Overpass_API
|
||
- **Rate limits:** необходимо уважать (не чаще 1-2 запросов/сек)
|
||
- **Рекомендуемое использование:** для дельта-обновлений, not bulk download
|
||
|
||
---
|
||
|
||
## Технический стек (предварительный)
|
||
|
||
| Компонент | Технология | Обоснование |
|
||
|-----------|------------|-------------|
|
||
| Парсинг PBF | Pyrosm (Python) + Osmium | Простота, Python-стек |
|
||
| Хранилище | Spatialite | Портативность, zero-config |
|
||
| Роутинг | OSRM + кастомный профиль | Быстрый, проверенный |
|
||
| API Backend | FastAPI (Python) | Async, типизация |
|
||
| Тайлы | TileServer GL или самописный | Поддержка MapLibre |
|
||
| Фронт | MapLibre GL JS + React/Vanilla | Open source, производительность |
|
||
| Мобильный | PWA + Service Workers | Оффлайн, без store |
|
||
|
||
---
|
||
|
||
## Этапы реализации
|
||
|
||
### Фаза 1: MVP — ✅ ВЫПОЛНЕНО (02.05.2026)
|
||
- [x] Настройка PBF загрузки (ЦФО + Чувашия)
|
||
- [x] Парсинг и фильтрация highway=track/path/bridleway + surface
|
||
- [x] Импорт в Spatialite (1.1M треков, 14K POI)
|
||
- [x] FastAPI self-hosted MVT тайлы (вместо TileServer GL)
|
||
- [x] Веб-карта с MapLibre GL JS
|
||
|
||
### Фаза 2: Роутинг + UI — ✅ ВЫПОЛНЕНО (03.05.2026)
|
||
- [x] OSRM + кастомный профиль `enduro.lua` (порт 5559)
|
||
- [x] API endpoint `/api/route` (точки А→Б → маршрут)
|
||
- [x] "Дикий путь" — UI кнопка 🗺️, маркеры, дистанция/время
|
||
- [x] Поиск (Nominatim, debounce 400ms, flyTo)
|
||
- [x] Линейка 📏 (haversine, кружки + плашки)
|
||
- [x] Геолокация 📍, компас 🧭
|
||
|
||
### Фаза 3: Слои и фичи — ⏳ Бёклог
|
||
- [ ] Импорт SRTM DEM + расчёт уклонов
|
||
- [ ] Слой рельефа
|
||
- [ ] Флажки/метки на карте (localStorage)
|
||
- [ ] Слой препятствий (броды, шлагбаумы, болота)
|
||
|
||
### Фаза 4: Продвинутый роутинг — ⏳ Бёклог
|
||
- [ ] "Красивый маршрут" — через живописные места
|
||
- [ ] "Горка" — макс набор высоты
|
||
- [ ] "Разведка" — грунтовки вокруг точки
|
||
- [ ] Статистика маршрута (% грунт/асфальт), GPX экспорт
|
||
|
||
### Фаза 5: Мобильность — ⏳ Бёклог
|
||
- [ ] PWA с оффлайн тайлами
|
||
- [ ] GPS трекинг
|
||
- [ ] Интеграция с OsmAnd/Locus (экспорт)
|
||
|
||
---
|
||
|
||
## Вопросы для Славы
|
||
|
||
1. **Регион:** какой регион берём для начала? (ЦФО, вся Россия, конкретная область?)
|
||
2. **Хостинг:** разворачиваем FR24 VM (PostGIS) или локально на mva154?
|
||
3. **Бюджет на данные:** SRTM 30 м бесплатные, но если нужен ASTER (15 м) — $50/регион
|
||
4. **Мобильное:** PWA достаточно, или нужно нативное приложение (Android)?
|
||
5. **Совместное использование:** сделать публичным (кто хочет пользуется) или только для Славы?
|
||
6. **Приоритет:** что важней — роутинг, красивая визуализация, или оффлайн работа?
|
||
|
||
---
|
||
|
||
*Документ будет дорабатываться после согласования со Славой*
|