В процессе автоматизации транспортной логистики перед разработчиками 1С часто возникает задача построения оптимальных маршрутов доставки. Для этого необходимо оперативно получать точные данные о расстоянии и времени в пути между множеством адресов. Это классическая задача коммивояжера (хоть и в упрощенном виде), когда у нас есть список точек, и нам нужно построить оптимальную матрицу переездов. В этой статье мы подробно разберем, как решить проблему построения маршрутов более чем по двум точкам с использованием различных геоинформационных сервисов, проанализируем их финансовую целесообразность и приведем готовые примеры интеграции на стороне 1С.
Обычные веб-сервисы построения маршрутов (например, стандартный Google Directions API или базовый Яндекс.Локатор) отлично работают, когда нам нужно построить путь от точки А до точки Б. Однако, когда точек становится больше (например, 10–15 адресов доставки), последовательный опрос сервиса в цикле по парам точек приводит к лавинообразному росту количества HTTP-запросов. Это моментально исчерпывает бесплатные лимиты, снижает скорость работы системы 1С и повышает риск блокировки со стороны провайдера карт.
Для решения этой проблемы все ведущие геосервисы предоставляют специализированный инструмент — API Матрицы расстояний (Distance Matrix API). Вместо построения отдельных маршрутов мы отправляем один запрос с массивом всех координат, а в ответ получаем готовую JSON-структуру, содержащую попарные расстояния и время в пути между всеми точками.
Если специфика вашего бизнеса позволяет использовать зарубежные сервисы, можно задействовать API матрицы расстояний от Google. Для обхода ограничения в две точки мы используем параметры origins (точки отправления) и destinations (точки прибытия).
Рассмотрим ключевые особенности работы с Google:
Многие разработчики отказываются от Яндекса, пугаясь тарифов комплексного продукта «Яндекс Маршрутизация» (VRS), стоимость которого может составлять сотни тысяч рублей в год. Однако для простых учетных задач нет необходимости покупать тяжелое логистическое ПО. Яндекс предоставляет отдельный инструмент — API Матрицы расстояний.
Проанализируем особенности этого решения:
Если бюджет компании ограничен, или вам необходимо обрабатывать сотни тысяч точек ежедневно без затрат, лучшим выбором станет развертывание собственного сервера OSRM (Open Source Routing Machine) на базе карт OpenStreetMap (OSM).
Выясним преимущества данного подхода:
/table/v1/, который принимает на вход массив координат, а возвращает чистую JSON-строку с матрицами времени (durations) и расстояний (distances).Если ваш транспорт работает преимущественно в регионах России и за пределами МКАД, незаменимым инструментом станет API Матрицы расстояний от 2ГИС. Данный сервис славится детальной прорисовкой проездов внутри дворов и точной информацией о шлагбаумах и ограничениях.
Рассмотрим сильные стороны 2ГИС:
Давайте подробно разберем, как написать универсальный код для интеграции 1С с геосервисами на примере бесплатного локального сервера OSRM (для других сервисов логика работы с HTTPСоединение и обработкой JSON будет идентичной, изменятся лишь структура URL и параметры запроса).
Представим, что у нас есть массив точек с координатами (широта и долгота). Нам нужно отправить их на сервер OSRM, получить JSON-ответ, распарсить его средствами 1С и вывести результат.
Посмотрим на пример реализации функции отправки запроса и разбора ответа в 1С:
&НаСервереБезКонтекста
Функция РассчитатьМатрицуРасстоянийOSRM(МассивТочек) Экспорт
// Шаг 1. Формируем строку координат в формате OSRM (долгота,широта через точку с запятой)
СтрокаКоординат = "";
Для Каждого Точка Из МассивТочек Цикл
// Форматируем координаты, заменяя запятую на точку в вещественных числах
ШиротаСтр = Формат(Точка.Широта, "ЧРД=.; ЧГ=0");
ДолготаСтр = Формат(Точка.Долгота, "ЧРД=.; ЧГ=0");
Если ЗначениеЗаполнено(СтрокаКоординат) Тогда
СтрокаКоординат = СтрокаКоординат + ";";
КонецЕсли;
// В OSRM координаты передаются в формате: Долгота,Широта
СтрокаКоординат = СтрокаКоординат + ДолготаСтр + "," + ШиротаСтр;
КонецЦикла;
// Если точек нет, возвращаем пустой результат
Если Не ЗначениеЗаполнено(СтрокаКоординат) Тогда
Возврат Неопределено;
КонецЕсли;
// Шаг 2. Настройка HTTP-соединения со своим сервером OSRM
// Допустим, ваш сервер развернут локально на порту 5000
СерверАдрес = "localhost";
Порт = 5000;
Соединение = Новый HTTPСоединение(СерверАдрес, Порт,,,,, Новый ЗащищенноеСоединениеOpenSSL());
// Формируем путь к методу Table Service с получением и расстояний (distances), и времени (durations)
АдресРесурса = "/table/v1/driving/" + СтрокаКоординат + "?annotations=duration,distance";
Запрос = Новый HTTPЗапрос(АдресРесурса);
Попытка
// Отправляем GET-запрос на сервер
Ответ = Соединение.Получить(Запрос);
Исключение
ЗаписьЖурналаРегистрации("ИнтеграцияOSRM", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
ВызватьИсключение "Не удалось установить соединение с сервером маршрутизации.";
КонецПопытки;
// Шаг 3. Обработка ответа сервера
Если Ответ.КодСостояния = 200 Тогда
// Читаем полученную JSON-строку
ТелоJSON = Ответ.ПолучитьТелоКакСтроку();
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку(ТелоJSON);
// Десериализуем JSON в структуру 1С
ДанныеРасчета = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
// Проверяем успешность статуса в JSON
Если ДанныеРасчета.Свойство("code") И ДанныеРасчета.code = "Ok" Тогда
Возврат ДанныеРасчета; // Возвращаем структуру с матрицами distances и durations
Иначе
ВызватьИсключение "Сервер OSRM вернул ошибку: " + ДанныеРасчета.code;
КонецЕсли;
Иначе
ВызватьИсключение "Ошибка сервера OSRM. Код состояния: " + Ответ.КодСостояния;
КонецЕсли;
КонецФункции
Разберем подробнее структуру возвращаемого значения. Переменная ДанныеРасчета будет содержать соответствие или структуру 1С. Внутри нее будут находиться два ключевых двумерных массива:
durations — массив массивов, где элемент durations[i][j] указывает время в секундах, необходимое для переезда из точки i в точку j.distances — массив массивов, содержащий расстояния в метрах между соответствующими точками.Проанализируем пример обработки полученной структуры на стороне 1С для вывода матрицы в лог или таблицу значений:
&НаСервере
Процедура ВывестиМатрицуРасстоянийВЛог(ДанныеРасчета)
Если ДанныеРасчета = Неопределено Тогда
Возврат;
КонецЕсли;
МатрицаРасстояний = ДанныеРасчета.distances;
МатрицаВремени = ДанныеРасчета.durations;
КоличествоТочек = МатрицаРасстояний.Количество();
Для СтрокаИндекс = 0 По КоличествоТочек - 1 Цикл
Для КолонкаИндекс = 0 По КоличествоТочек - 1 Цикл
РасстояниеМетры = МатрицаРасстояний[СтрокаИндекс][КолонкаИндекс];
ВремяСекунды = МатрицаВремени[СтрокаИндекс][КолонкаИндекс];
// Переводим данные в более читаемый вид
РасстояниеКм = Окр(РасстояниеМетры / 1000, 2);
ВремяМинуты = Окр(ВремяСекунды / 60, 1);
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = СтрШаблон("Из точки %1 в точку %2: %3 км, %4 мин.",
СтрокаИндекс + 1,
КолонкаИндекс + 1,
РасстояниеКм,
ВремяМинуты);
Сообщение.Сообщить();
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Мы проанализировали основные доступные варианты для интеграции 1С с геоинформационными системами в рамках логистических задач. Выбор конкретного инструмента зависит от приоритетов вашего бизнеса:
Использование встроенных в платформу 1С объектов HTTPСоединение и ЧтениеJSON позволяет осуществить любую из этих интеграций силами одного программиста буквально за несколько часов.