Как определить координаты точки на заданном расстоянии от маршрута для расчета зоны доставки в 1С

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

В логистических задачах часто возникает необходимость определить границы зоны обслуживания. Одной из типичных задач является расчет "коридора" вдоль маршрута: например, если точка доставки находится в пределах 20 км от основной трассы, доставка считается бесплатной. В этой статье мы подробно разберем, как вычислить географические координаты (широту и долготу) на заданном расстоянии от точек пути и как правильно организовать проверку вхождения адреса в эту зону.

Постановка задачи и выбор метода

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

  1. Упрощенный метод (плоская Земля): подходит для малых расстояний и небольших широт.
  2. Метод прямого геодезического расчета (сферическая тригонометрия): позволяет точно найти координаты "боковых" точек по азимуту.
  3. Алгоритм Cross-track distance: расчет кратчайшего расстояния от точки до линии (сегмента пути).

Метод 1: Упрощенный расчет через длину градуса

Рассмотрим самый простой способ, который предложили участники обсуждения. На небольших расстояниях (до 50-100 км) кривизной Земли можно пренебречь и считать, что 1 градус широты и долготы имеет фиксированную длину в километрах.

Важный нюанс: длина 1 градуса широты всегда составляет примерно 111.1 км. Однако длина 1 градуса долготы уменьшается при движении от экватора к полюсам. Проанализируем формулу расчета:

ДлинаГрадусаДолготы = 111.3 * Cos(ШиротаВРадианах)

Для реализации в 1С нам потребуется перевести широту из градусов в радианы. Разберем пример функции:


Функция ПолучитьСмещениеКоординат(ЦентральнаяТочка, РасстояниеКМ)
    Пи = 3.14159265358979;
    РадиусЗемли = 6371;
    
    // Широта точки в радианах
    ШиротаРад = ЦентральнаяТочка.Широта * Пи / 180;
    
    // Длина одного градуса в данной точке
    КмВГрадусеШироты = 111.1;
    КмВГрадусеДолготы = 111.1 * Cos(ШиротаРад);
    
    // Смещение в градусах
    СмещениеШироты = РасстояниеКМ / КмВГрадусеШироты;
    СмещениеДолготы = РасстояниеКМ / КмВГрадусеДолготы;
    
    Результат = Новый Структура;
    Результат.Вставить("Север", ЦентральнаяТочка.Широта + СмещениеШироты);
    Результат.Вставить("Юг",    ЦентральнаяТочка.Широта - СмещениеШироты);
    Результат.Вставить("Восток", ЦентральнаяТочка.Долгота + СмещениеДолготы);
    Результат.Вставить("Запад",  ЦентральнаяТочка.Долгота - СмещениеДолготы);
    
    Возврат Результат;
КонецФункции

Этот метод позволяет быстро получить "ограничивающий прямоугольник" (Bounding Box). Однако для построения точных точек по бокам маршрута этого недостаточно, так как нужно учитывать направление (азимут) движения транспорта.

Метод 2: Нахождение координат по азимуту и расстоянию

Чтобы найти точку С на расстоянии 20 км строго перпендикулярно маршруту АВ, нам нужно сначала вычислить азимут (направление) от А к В, прибавить к нему 90 градусов и решить "прямую геодезическую задачу".

Рассмотрим формулу для сферы, которую можно внедрить в код 1С:

Широта2 = arcsin( sin(lat1) * cos(d/R) + cos(lat1) * sin(d/R) * cos(θ) )

Долгота2 = lon1 + atan2( sin(θ) * sin(d/R) * cos(lat1), cos(d/R) - sin(lat1) * sin(lat2) )

Где d — расстояние, R — радиус Земли, θ — азимут в радианах.

Разберем по шагам, как это реализовать. Сначала вычислим азимут между двумя точками маршрута:


Функция ВычислитьАзимут(Лат1, Лон1, Лат2, Лон2)
    Пи = 3.14159265358979;
    ф1 = Лат1 * Пи / 180;
    ф2 = Лат2 * Пи / 180;
    дЛ = (Лон2 - Лон1) * Пи / 180;
    
    y = Sin(дЛ) * Cos(ф2);
    x = Cos(ф1) * Sin(ф2) - Sin(ф1) * Cos(ф2) * Cos(дЛ);
    Рез = Atan2(y, x);
    
    Возврат Рез; // Азимут в радианах
КонецФункции

Теперь, зная направление сегмента дороги, мы можем вычислить координаты точек "справа" и "слева" от дороги, прибавив или отняв Пи/2 (90 градусов) к полученному азимуту.

Метод 3: Оптимальная проверка через Cross-track distance

Проанализируем ситуацию: пользователь предложил искать ближайшую точку (узел) маршрута и считать расстояние до нее. Это неверный подход для длинных перегонов. Если дорога прямая и длится 100 км, а точка доставки находится посередине в 5 км от дороги, то расстояние до ближайшего "узла" (начала или конца дороги) составит 50 км. Система ошибочно определит, что доставка платная.

Правильное решение — вычислять Cross-track distance (отклонение от пути). Это кратчайшее расстояние от точки (адреса клиента) до дуги большого круга (сегмента дороги).

Формула расчета в радианах:

dxt = arcsin( sin(d13/R) * sin(θ13 - θ12) ) * R

Где:

Практические рекомендации по реализации в 1С

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

  1. Предварительный расчет (Кеширование): При сохранении маршрута в справочнике создавайте массив "контрольных точек" или полигон (зону).
  2. Использование внешних API: Если точность критична, можно отправить запрос к API Яндекс.Карт или Google Maps. У них есть готовые методы для работы с геометрией (например, isPointInPolygon или расчет дистанции до ломаной линии).
  3. Гео-индексы в SQL: Если ваша база 1С работает на PostgreSQL, используйте расширение PostGIS. Функция ST_DWithin(geometry, geometry, distance) моментально определит, находится ли точка клиента в пределах 20 км от всей линии маршрута, используя пространственные индексы.
  4. Библиотека Turf.js: В управляемых формах 1С можно использовать поле HTML-документа. Подключив туда небольшую JS-библиотеку Turf.js, вы получите доступ к функции turf.buffer(), которая автоматически строит зону любой сложности вокруг маршрута.

Резюме: Для простых задач в пределах одного города достаточно использовать упрощенный метод с расчетом длины градуса долготы через косинус широты (Метод 1). Для межрегиональных маршрутов (как в примере 350 км) необходимо использовать либо расчет отклонения от пути (Cross-track distance), либо специализированные ГИС-инструменты, чтобы избежать ошибок, связанных с кривизной земной поверхности.

← На главную