Записки охотника

Измерение расстояния по координатам

Тематические статьи
Рвав-рвав, собака Смайл нынче землемер!

Собака Смайл все глубже погружается в процесс создания пользовательских функций, а поскольку теория без практики мертва, стараемся сразу подыскать им практическое применение. Поэтому сегодня мы рассмотрим такую задачу, как определение расстояния по координатам.
Вообще надо сказать, что, пока обдумывал материал в голове, что отделаюсь "легким испугом", типа: ну вот будет у меня 1-я точка как 0, и вторая как 25, чего не посчитать-то? А вот фига, все оказалось куда интереснее. При том то, что удалось нарыть, можно еще и оптимизировать дополнительно.

Демонстрационный пример

Таблица "Маршруты" содержит название маршрута, а также координаты начальной и конечной точки каждого маршрута:
Таблица маршрутов

Задача

На основе представленных данных необходимо определить расстояние между 2-мя точками маршрута, используя два уровня вычисления, а именно Power Query и DAX.

Уровень Power Query

Поскольку наша задача связана с некоторыми специфическими вычислениями, придется вспоминать такую науку, как "Тригонометрия".
Для решения поставленной задачи при помощи Power Query необходимо последовательно выполнить следующие шаги:
  • Всем географическим координатам необходимо присвоить правильные типы данных ("Десятичное число"):
Обработка данных
Рвав-рвав, а вот дальше начинается самое интересное!
Оказывается, нельзя просто так взять координаты, и получить нормальный результат точки старта и точки финиша. И планета наша не шар, а эллипс, и расчеты в зависимости от единиц измерения разные...
Подробные пояснения этого всего от скромного собакена здесь не ждите, если есть соответствующее желание, то Гугл вам поможет :-)
  • Далее, для начала расчета, необходимо перевести заданные координаты в радианы. Можно было создать еще 4 дополнительных столбца, и вписать в них данные вручную, но лучше написать следующую функцию с незамысловатым названием:
Пользовательская функция
Код созданной пользовательской функции "RadiansCoordinates" весьма простой:
(Radians) =>
Radians / 180 * Number.PI
  • Применив указанную функцию к нашим данным, и затем изменив тип данных в столбцах, мы получим искомые значения:
Применение пользовательской функции
  • После осуществления пересчета в качестве последнего шага необходимо добавить настраиваемый столбец, нажав соответствующую кнопку, расположенную на закладке "Добавление столбца":
Кнопка создания настраиваемого столбца
  • Создаваемый настраиваемый столбец "Расстояние в километрах" имеет следующую формулу:
Number.Acos(
      Number.Sin([#"Широта - старт"])
        * Number.Sin([#"Широта - финиш"]) + Number.Cos([#"Широта - старт"])
        * Number.Cos([#"Широта - финиш"])
        * Number.Cos([#"Долгота - финиш"] - [#"Долгота - старт"])
    )
      * 6371
Рвав-рвав, на всякий случай: значение "6371" это общепринятый радиус нашей планеты в километрах.
  • Последним шагом решения задачи на уровне Power Query является изменение типа данных в указанном столбце:
Настраиваемый столбец

Уровень DAX

Решение, используемое на уровне DAX, гораздо короче, но, естественно, не проще.
Для решения поставленной задачи при помощи DAX необходимо последовательно выполнить следующие шаги:
  • Создать вычисляемый столбец "Расстояние в километрах", используя следующую формулу:
Расстояние в километрах =
VAR _NumberPI = 3.141592653589794
VAR _ValueDegrees = 180
VAR _CorrectionFactor =
    DIVIDE ( _NumberPI, _ValueDegrees, 0 )
VAR _RadiusEarth = 6371 //Общепринятая веричина радиуса Земли в километрах, для расчета в милях нужно использовать 3959
RETURN
    ACOS (
        SIN ( 'Маршруты DAX'[Широта - старт] * _CorrectionFactor )
            * SIN ( 'Маршруты DAX'[Широта - финиш] * _CorrectionFactor )
            + COS ( 'Маршруты DAX'[Широта - старт] * _CorrectionFactor )
                * COS ( 'Маршруты DAX'[Широта - финиш] * _CorrectionFactor )
                * COS ( ( 'Маршруты DAX'[Долгота - финиш] * _CorrectionFactor ) - ( 'Маршруты DAX'[Долгота - старт] * 0.0174532925199433 ) )
    ) * _RadiusEarth
  • Проверить получившийся результат:

Независимая проверка

Для итоговой проверки можно воспользоваться каким-нибудь интернет-сервисом:
Расстояние, равное 635-ти километрам, соответствует полученным нами результатам.
Рвав-рвав, вот такие дела.
При промышленном применении данного функционала нужно иметь ввиду, как минимум, следующие моменты: расстояние считается по прямой, и маршрут по городам из примера "Санкт-Петербург → Москва" на самом деле несколько не верен, поскольку его величина рассчитывается от Дворцовой площади до Красной площади.

Ваш Смайл