Альтернативные маршруты

В веб-картографии под альтернативными маршрутами понимается набор различных траекторий движения между одной и той же парой точек, рассчитанных с учётом различных критериев оптимизации. Классическая задача кратчайшего пути не ограничивается единственным решением: при изменении параметров стоимости ребёр графа появляются маршруты, отличающиеся по длине, времени, количеству поворотов, дорожным ограничениям или дорожной обстановке.

В рамках веб-клиентов визуализация таких маршрутов реализуется поверх интерактивных картографических библиотек, среди которых ключевую роль занимает MapLibre GL JS, обеспечивающая рендеринг векторных слоёв и динамическое обновление геометрий через источники данных.


Источники данных маршрутизации и генерация альтернатив

MapLibre GL JS не выполняет маршрутизацию самостоятельно. Она оперирует результатами внешних routing-движков, которые формируют геометрию маршрутов в формате GeoJSON или polyline.

На практике используются специализированные серверные решения:

  • OSRM
  • GraphHopper
  • Valhalla

Каждый из них способен возвращать несколько альтернативных маршрутов при включённой соответствующей опции запроса.

Пример логики генерации:

  1. Построение графа дорог (узлы — перекрёстки, рёбра — сегменты дорог)
  2. Назначение весов ребрам (длина, время, штрафы)
  3. Выполнение поиска нескольких кратчайших путей
  4. Фильтрация схожих маршрутов по коэффициенту перекрытия
  5. Возврат набора альтернатив

В случае OSRM параметр alternatives=true инициирует поиск дополнительных маршрутов с ограничением на степень отклонения от основного пути.


Представление альтернативных маршрутов в GeoJSON

Типовая структура ответа маршрутизатора включает массив маршрутов:

{
  "routes": [
    {
      "geometry": "...",
      "distance": 12000,
      "duration": 900
    },
    {
      "geometry": "...",
      "distance": 12500,
      "duration": 870
    }
  ]
}

Каждый маршрут преобразуется в GeoJSON LineString:

{
  "type": "Feature",
  "geometry": {
    "type": "LineString",
    "coordinates": [[lon, lat], [lon, lat]]
  },
  "properties": {
    "id": 1,
    "distance": 12000,
    "duration": 900
  }
}

Такая структура позволяет MapLibre GL JS рендерить каждый маршрут как отдельный слой или как набор feature внутри одного source.


Организация слоёв маршрутов в MapLibre GL JS

В MapLibre GL JS альтернативные маршруты обычно реализуются через один GeoJSON source и несколько line layers.

Базовая схема:

  • один источник данных route-source

  • несколько слоёв:

    • основной маршрут
    • альтернативные маршруты
    • подсветка выбранного маршрута
map.addSource('routes', {
  type: 'geojson',
  data: routesGeojson
});

Далее добавляются слои:

map.addLayer({
  id: 'route-alt',
  type: 'line',
  source: 'routes',
  filter: ['==', ['get', 'selected'], false],
  paint: {
    'line-color': '#888',
    'line-width': 4,
    'line-opacity': 0.6
  }
});

map.addLayer({
  id: 'route-main',
  type: 'line',
  source: 'routes',
  filter: ['==', ['get', 'selected'], true],
  paint: {
    'line-color': '#2E86FF',
    'line-width': 6,
    'line-opacity': 1
  }
});

Такое разделение позволяет отделить визуально основной маршрут от альтернатив без дублирования источников.


Динамическое переключение маршрута

Альтернативные маршруты предполагают интерактивность: выбор одного варианта изменяет состояние карты.

Механизм обновления данных:

function setSelectedRoute(index) {
  const updated = {
    type: 'FeatureCollection',
    features: routes.features.map((f, i) => ({
      ...f,
      properties: {
        ...f.properties,
        selected: i === index
      }
    }))
  };

  map.getSource('routes').setData(updated);
}

MapLibre GL JS перерасчитывает стили слоёв без перерисовки всей сцены, что критично для производительности при частых обновлениях.


Визуальная дифференциация маршрутов

Для работы с альтернативами важна читаемость, особенно при пересечении геометрий.

Используются следующие техники:

  • различие толщины линий
  • прозрачность второстепенных маршрутов
  • пунктирная линия для менее предпочтительных вариантов
  • цветовое кодирование по стоимости

Пример стилизации:

'line-dasharray': [2, 2]

или градиент:

'line-gradient': [
  'interpolate',
  ['linear'],
  ['line-progress'],
  0, '#00c853',
  1, '#d50000'
]

Сравнение маршрутов по метрикам

Каждый альтернативный маршрут сопровождается метаданными:

  • расстояние
  • время в пути
  • количество поворотов
  • тип дорог
  • штрафы (например, платные дороги)

Эти параметры используются не только для отображения, но и для ранжирования.

Пример функции выбора:

function score(route) {
  return route.distance * 0.5 + route.duration * 0.5;
}

На практике весовые коэффициенты зависят от домена: логистика, пешеходная навигация, автомобильная навигация.


Объединение альтернатив в единую геометрию

В некоторых архитектурах альтернативные маршруты не разделяются на слои, а объединяются в MultiLineString:

{
  "type": "Feature",
  "geometry": {
    "type": "MultiLineString",
    "coordinates": [
      [[lon, lat], [lon, lat]],
      [[lon, lat], [lon, lat]]
    ]
  }
}

В таком случае MapLibre GL JS использует один слой, а различие маршрутов задаётся через feature-state или свойства.


Использование feature-state для интерактивности

Feature-state позволяет изменять визуальные свойства без пересоздания GeoJSON:

map.setFeatureState(
  { source: 'routes', id: 1 },
  { selected: true }
);

И в стиле слоя:

'line-color': [
  'case',
  ['boolean', ['feature-state', 'selected'], false],
  '#2E86FF',
  '#999'
]

Такой подход снижает нагрузку при большом количестве альтернатив.


Обновление маршрутов в реальном времени

При изменении условий движения альтернативные маршруты могут пересчитываться:

  • изменение пробок
  • закрытие дорог
  • изменение точки назначения
  • изменение профиля транспорта

Архитектура обновления обычно включает:

  1. запрос новых маршрутов
  2. дифф между текущими и новыми маршрутами
  3. частичное обновление source
  4. сохранение состояния выбранного маршрута

Работа с большими наборами альтернатив

При увеличении числа альтернатив возникают проблемы производительности:

  • рост числа line vertices
  • увеличение времени рендеринга WebGL
  • перегрузка GPU при сложных стилях

Оптимизации:

  • упрощение геометрии (Douglas-Peucker)
  • ограничение числа альтернатив (обычно 2–5)
  • использование zoom-dependent visibility
  • кэширование результатов маршрутизации

Интеграция с пользовательскими сценариями навигации

Альтернативные маршруты часто интегрируются в интерфейсы:

  • выбор “самый быстрый / самый короткий”
  • режим “избегать платных дорог”
  • экологический маршрут
  • маршрут с минимальным количеством поворотов

MapLibre GL JS выступает только как слой визуализации, тогда как логика выбора реализуется на уровне бизнес-логики приложения.


Геометрические особенности пересекающихся маршрутов

При наложении альтернатив возникают проблемы визуального перекрытия. Для их решения применяются:

  • смещение линий (line offset)
  • z-index через порядок слоёв
  • сегментация маршрута на части
  • разделение по zoom-level

Пример:

'line-translate': [2, 2]

Заключительная техническая модель

Система альтернативных маршрутов в связке с MapLibre GL JS представляет собой многоуровневую архитектуру:

  • слой маршрутизации (OSRM / GraphHopper / Valhalla)
  • транспортная модель графа дорог
  • сервис агрегации маршрутов
  • GeoJSON-слой в MapLibre GL JS
  • визуальная система слоёв и стилей
  • интерактивный слой выбора и состояния

Такая декомпозиция позволяет масштабировать навигационные сценарии от простых картографических визуализаций до полноценных навигационных систем с динамическим выбором маршрутов.