Построение маршрутов для автомобиля

Построение автомобильных маршрутов является одной из ключевых возможностей HERE Maps API. Сервис маршрутизации анализирует дорожную сеть, ограничения движения, типы дорог, дорожные правила и дополнительные параметры, после чего возвращает оптимальный путь между заданными точками.

В современных версиях платформы HERE используется Routing API v8, предоставляющий маршруты для различных видов транспорта:

  • автомобиль (car)
  • грузовой транспорт (truck)
  • пешеход (pedestrian)
  • велосипед (bicycle)
  • общественный транспорт (publicTransport)
  • такси (taxi)

Для автомобильной навигации используется режим car.


Подключение необходимых модулей

Для отображения карты и маршрутов необходимо подключить основные библиотеки HERE Maps.

<script src="https://js.api.here.com/v3/3.1/mapsjs-core.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-service.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-ui.js"></script>
<script src="https://js.api.here.com/v3/3.1/mapsjs-mapevents.js"></script>

<link
    rel="stylesheet"
    href="https://js.api.here.com/v3/3.1/mapsjs-ui.css"
/>

Инициализация карты:

const platform = new H.service.Platform({
    apikey: 'YOUR_API_KEY'
});

const defaultLayers = platform.createDefaultLayers();

const map = new H.Map(
    document.getElementById('map'),
    defaultLayers.vector.normal.map,
    {
        zoom: 10,
        center: { lat: 55.7558, lng: 37.6176 }
    }
);

const beh * avior = new H.mapevents.Behavior(
    new H.mapevents.MapEvents(map)
);

const ui = H.ui.UI.createDefault(map, defaultLayers);

После создания карты можно переходить к расчету маршрутов.


Создание сервиса маршрутизации

Для работы с маршрутами требуется объект Routing Service.

const router = platform.getRoutingService(null, 8);

Второй параметр определяет версию API маршрутизации.


Минимальный пример построения маршрута

Маршрут рассчитывается между двумя координатами.

const routingParameters = {
    transportMode: 'car',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351',
    return: 'polyline'
};

router.calculateRoute(
    routingParameters,
    onSuccess,
    onError
);

Описание параметров:

Параметр Назначение
transportMode Тип транспорта
origin Начальная точка
destination Конечная точка
return Возвращаемые данные

Получение результата маршрута

После успешного расчета маршрут передается в обработчик.

function onSuccess(result) {
    console.log(result);
}

Структура ответа содержит массив маршрутов:

result.routes

Каждый маршрут состоит из секций:

result.routes[0].sections

Секция представляет отдельный участок пути.


Отображение маршрута на карте

Для визуализации используется полилиния.

function onSuccess(result) {

    const route = result.routes[0];

    route.sections.forEach(section => {

        const linestring =
            H.geo.LineString.fromFlexiblePolyline(
                section.polyline
            );

        const routeLine = new H.map.Polyline(
            linestring,
            {
                style: {
                    strokeColor: '#0066ff',
                    lineWidth: 5
                }
            }
        );

        map.addObject(routeLine);
    });
}

Здесь происходит:

  1. Получение закодированной линии маршрута.
  2. Декодирование Flexible Polyline.
  3. Создание объекта Polyline.
  4. Добавление маршрута на карту.

Автоматическое масштабирование маршрута

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

function onSuccess(result) {

    const route = result.routes[0];

    route.sections.forEach(section => {

        const linestring =
            H.geo.LineString.fromFlexiblePolyline(
                section.polyline
            );

        const routeLine =
            new H.map.Polyline(linestring);

        map.addObject(routeLine);

        map.getViewModel().setLookAtData({
            bounds: routeLine.getBoundingBox()
        });
    });
}

Карта автоматически подберет оптимальный масштаб.


Отображение начальной и конечной точки

Для повышения наглядности часто добавляют маркеры.

const startMarker = new H.map.Marker({
    lat: 55.7558,
    lng: 37.6176
});

const finishMarker = new H.map.Marker({
    lat: 59.9343,
    lng: 30.3351
});

map.addObjects([
    startMarker,
    finishMarker
]);

Получение длины маршрута

HERE Routing API возвращает информацию о расстоянии.

const section = result.routes[0].sections[0];

console.log(section.summary.length);

Пример результата:

634512

Значение возвращается в метрах.

Преобразование в километры:

const distanceKm =
    section.summary.length / 1000;

console.log(distanceKm.toFixed(1));

Получение времени в пути

Сервис рассчитывает ориентировочное время движения.

const duration =
    section.summary.duration;

console.log(duration);

Результат:

28750

Значение указывается в секундах.

Перевод в часы:

const hours = duration / 3600;

console.log(hours.toFixed(2));

Маршруты через промежуточные точки

Автомобильный маршрут может содержать несколько остановок.

const params = {
    transportMode: 'car',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351',
    via: [
        '56.8389,60.6057',
        '58.0105,56.2502'
    ],
    return: 'polyline'
};

Промежуточные точки заставляют алгоритм прокладывать путь через указанные координаты.


Использование альтернативных маршрутов

Система способна возвращать несколько вариантов движения.

const params = {
    transportMode: 'car',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351',
    alternatives: 3,
    return: 'polyline'
};

В ответе будет содержаться несколько маршрутов:

result.routes

Каждый маршрут можно отображать отдельным цветом.

const colors = [
    '#0066ff',
    '#00aa44',
    '#ff5500'
];

Получение пошаговых инструкций

Для навигационных приложений необходимы маневры.

Запрос:

const params = {
    transportMode: 'car',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351',
    return: 'polyline,actions,instructions'
};

Обработка:

const actions =
    result.routes[0]
          .sections[0]
          .actions;

actions.forEach(action => {
    console.log(action.instruction);
});

Пример инструкций:

Двигайтесь прямо
Поверните направо
Сверните на съезд
Продолжайте движение

Получение ограничений скорости

При необходимости маршрут может содержать сведения о дорожных сегментах.

const params = {
    transportMode: 'car',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351',
    return: 'polyline,travelSummary'
};

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


Исключение платных дорог

При расчете маршрута допускается настройка предпочтений.

const params = {
    transportMode: 'car',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351',
    avoid: {
        features: ['tollRoad']
    },
    return: 'polyline'
};

Доступные варианты:

tollRoad
ferry
tunnel
dirtRoad
controlledAccessHighway

Исключение паромов

const params = {
    transportMode: 'car',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351',
    avoid: {
        features: ['ferry']
    }
};

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


Выбор самого быстрого маршрута

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

const params = {
    transportMode: 'car',
    routingMode: 'fast',
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351'
};

Возможные значения:

fast
short
balanced

Описание:

Режим Назначение
fast Минимальное время
short Минимальное расстояние
balanced Компромиссный вариант

Учет дорожного движения

HERE использует актуальные транспортные данные.

const params = {
    transportMode: 'car',
    routingMode: 'fast',
    traffic: true,
    origin: '55.7558,37.6176',
    destination: '59.9343,30.3351'
};

В расчет включаются:

  • пробки;
  • замедления движения;
  • перекрытия;
  • текущая скорость потока транспорта.

Построение кольцевого маршрута

Иногда требуется маршрут с возвратом в исходную точку.

const start = '55.7558,37.6176';

const params = {
    transportMode: 'car',
    origin: start,
    destination: start,
    via: [
        '55.90,37.70',
        '55.80,37.20'
    ],
    return: 'polyline'
};

Подобный подход используется для логистики и курьерских сервисов.


Очистка старого маршрута

Перед построением нового маршрута обычно удаляются предыдущие объекты.

map.removeObjects(map.getObjects());

Либо только линии маршрута:

routeLines.forEach(line => {
    map.removeObject(line);
});

routeLines = [];

Асинхронное построение маршрута через Promise

Для современных приложений удобно использовать Promise.

function calculateRoute(params) {

    return new Promise((resolve, reject) => {

        router.calculateRoute(
            params,
            resolve,
            reject
        );

    });
}

Использование:

async function buildRoute() {

    try {

        const result =
            await calculateRoute(params);

        console.log(result);

    } catch(error) {

        console.error(error);

    }
}

Обработка ошибок маршрутизации

Необходимо учитывать возможные сбои.

function onError(error) {

    console.error(
        'Ошибка маршрутизации:',
        error
    );
}

Типичные причины:

  • некорректные координаты;
  • отсутствие дороги между точками;
  • недействительный API Key;
  • превышение лимитов запросов;
  • сетевые ошибки.

Практическая архитектура модуля маршрутизации

В крупных приложениях логика обычно разделяется на несколько уровней.

Сервис маршрутизации

class RoutingService {

    constructor(platform) {
        this.router =
            platform.getRoutingService(null, 8);
    }

    calculate(params) {

        return new Promise(
            (resolve, reject) => {

                this.router.calculateRoute(
                    params,
                    resolve,
                    reject
                );

            }
        );
    }
}

Слой отображения

class RouteRenderer {

    constructor(map) {
        this.map = map;
    }

    render(route) {

        route.sections.forEach(section => {

            const line =
                H.geo.LineString
                 .fromFlexiblePolyline(
                    section.polyline
                 );

            this.map.addObject(
                new H.map.Polyline(line)
            );

        });
    }
}

Использование

const routing =
    new RoutingService(platform);

const renderer =
    new RouteRenderer(map);

const result =
    await routing.calculate(params);

renderer.render(
    result.routes[0]
);

Подобная структура упрощает поддержку кода, повторное использование компонентов и дальнейшее развитие автомобильной навигации на базе HERE Maps API.