Как в 1С 8.3 рассчитать расстояние между двумя точками или адресами через геосервисы и формулы?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

Выясним, какие варианты решения существуют, чем отличается расчет по прямой от расчета по дорожной сети и как правильно реализовать интеграцию в 1С:Предприятии.

Вариант 1. Математический расчет расстояния по прямой (ортодромия)

Если для бизнес-задачи достаточно знать приблизительное расстояние по прямой (например, для быстрой фильтрации ближайших складов или распределения зон), расчет можно выполнить без постоянных обращений к внешним сервисам.

Для расчета расстояния на сфере применяется формула длины дуги большого круга. Рассмотрим, как реализовать такой расчет на встроенном языке 1С без использования внешних библиотек и устаревших COM-объектов:


&НаСервере
Функция ВычислитьРасстояниеПоПрямой(Знач Широта1, Знач Долгота1, Знач Широта2, Знач Долгота2) Экспорт

    // Радиус Земли в метрах
    РадиусЗемли = 6372795;
    ЧислоПи = 3.14159265358979323846;

    // Перевод градусов в радианы
    Лат1 = Число(Широта1) * ЧислоПи / 180;
    Лат2 = Число(Широта2) * ЧислоПи / 180;
    Лонг1 = Число(Долгота1) * ЧислоПи / 180;
    Лонг2 = Число(Долгота2) * ЧислоПи / 180;

    // Тригонометрические вычисления
    КЛат1 = Cos(Лат1);
    КЛат2 = Cos(Лат2);
    СЛат1 = Sin(Лат1);
    СЛат2 = Sin(Лат2);
    
    ДельтаДолготы = Лонг2 - Лонг1;
    КДельта = Cos(ДельтаДолготы);
    СДельта = Sin(ДельтаДолготы);

    // Вычисление центрального угла
    У = Sqrt(Pow(КЛат2 * СДельта, 2) + Pow(КЛат1 * СЛат2 - СЛат1 * КЛат2 * КДельта, 2));
    Х = СЛат1 * СЛат2 + КЛат1 * КЛат2 * КДельта;
    
    Если Х = 0 И У = 0 Тогда
        Возврат 0;
    КонецЕсли;
    
    Угол = ACos((КЛат1 * КЛат2 * КДельта + СЛат1 * СЛат2));
    
    // Расстояние в метрах
    РасстояниеВМетрах = Угол * РадиусЗемли;

    Возврат Окр(РасстояниеВМетрах, 0);

КонецФункции

Важное замечание: на форумах часто встречается решение через MSScriptControl.ScriptControl с кодом на JavaScript. Обратите внимание, что объект MSScriptControl работает исключительно в 32-разрядных версиях платформы Windows. При выполнении на 64-разрядном сервере 1С или в среде Linux такой вызов вызовет аварийное завершение с ошибкой создания COM-объекта. Все математические вычисления рекомендуется выполнять нативно на языке 1С.

Вариант 2. Расчет реального расстояния по дорогам через HTTP REST API

Для построения автомобильного маршрута и расчета фактического пробега с учетом развязок и улиц необходимо обращаться к сервисам маршрутизации. Для этого используются специализированные HTTP API, которые принимают координаты точек и возвращают протяженность пути и время движения в формате JSON.

Разберем по шагам типовой алгоритм отправки запроса и парсинга ответа в 1С 8.3:

  1. Формируем URL-адрес запроса с указанием координат начальной и конечной точек.
  2. Создаем объекты HTTPСоединение и HTTPЗапрос с необходимыми заголовками.
  3. Отправляем GET- или POST-запрос на сервер сервиса.
  4. Считываем тело ответа с помощью объекта ЧтениеJSON и метода ПрочитатьJSON() для преобразования JSON в структуры и массивы 1С.
  5. Извлекаем числовое значение дистанции (обычно в метрах) и времени (в секундах).

Посмотрим на пример универсальной процедуры обработки JSON-ответа маршрутизатора в 1С:


&НаСервере
Функция ПолучитьРасстояниеПоМаршруту(ПараметрыПодключения, СтрокаКоординат)

    HTTPСоединение = Новый HTTPСоединение(
        ПараметрыПодключения.Сервер,
        ПараметрыПодключения.Порт,
        ,,,
        ПараметрыПодключения.Таймаут,
        Новый ЗащищенноеСоединениеOpenSSL()
    );

    Запрос = Новый HTTPЗапрос(ПараметрыПодключения.ПутьКРесурсу + СтрокаКоординат);
    Ответ = HTTPСоединение.Получить(Запрос);

    Если Ответ.КодСостояния = 200 Тогда
        Чтение = Новый ЧтениеJSON;
        Чтение.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
        
        Данные = ПрочитатьJSON(Чтение);
        Чтение.Закрыть();

        // Структура ответа зависит от API провайдера
        // Например, извлечение расстояния в километрах:
        Если Данные.Свойство("routes") И Данные.routes.Количество() > 0 Тогда
            РасстояниеМетры = Данные.routes[0].distance;
            Возврат Окр(РасстояниеМетры / 1000, 2);
        КонецЕсли;
    КонецЕсли;

    Возврат 0;

КонецФункции

Важные технические и лицензионные нюансы

При внедрении сервисов расчета маршрутов обязательно учитывайте следующие особенности:

  1. Лицензионные условия провайдеров карт: большинство бесплатных версий картографических API запрещают серверные фоновые расчеты, кэширование координат и использование данных без визуального отображения карты пользователю (например, в элементе ПолеHTMLДокумента). Для фонового пакетного расчета маршрутов требуется коммерческий тариф либо открытые решения.
  2. Порядок следования координат: сервисы используют разные стандарты передачи точек. Некоторые ожидают формат Долгота, Широта (Lon, Lat), другие — Широта, Долгота (Lat, Lon). Всегда сверяйтесь со спецификацией конкретного API.
  3. Использование автономных движков (OSRM, GraphHopper): при больших объемах расчетов оптимальным решением является развертывание собственного локального сервиса маршрутизации на базе OpenStreetMap. Это снимает лимиты на число обращений в секунду и позволяет выполнять расчеты внутри закрытого контура предприятия без абонентской платы.
  4. Кэширование матрицы расстояний: для ускорения работы и экономии трафика сохраняйте результаты расчетов между регулярными точками (склады, распределительные центры, частые клиенты) в периодический или непериодический регистр сведений 1С.
← На главную