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

В последнее время довольно много приходится работать с KML и, в принципе, со всякими расчётами, связанными с географическими и местными системами координат. Так, например, в прошлый раз мне понадобилось отстроить в KML линию, зная её начальные координаты. длины и направление. Были и другие расчёты, такие как поиск координат середины пути, наклона линии, заданной двумя точками, расстояния между двумя точками и так далее. В итоге, все эти расчёты я решил свести в один модуль Delphi для геодезических расчётов. Возможно, что кому-то он понадобится для работы.

Сразу стоит оговориться, что модуль Geodesy.pas — это, по сути, частичный перевод из JavaScript-функций, описанных здесь, а также дополненный другими функциями и методами, найденными на просторах Интернета (к сожалению, не все ссылки сохранились).

Скачать модуль для геодезических расчётов в Delphi можно по ссылке в конце статьи, а пока я расскажу, что этот модуль на умеет на данный момент. Сейчас в модуле содержится всего один класс TGeodesy в котором собраны необходимые функции и процедуры для расчётов:

type
  TGeodesy = class
  private
     Lat1, Lon1, Lat2, Lon2: double;
     procedure ToRadians(Latitude, Longitude: double; var ALatRad, ALongRad: double);
  public
    function HaversineDistance(Latitude1, Longitude1, Latitude2, Longitude2: double): double;
    function SLCDistance(Latitude1, Longitude1, Latitude2, Longitude2: double): double;
    function Bearing(Latitude1, Longitude1, Latitude2, Longitude2: double):double;
    procedure Midpoint(Latitude1, Longitude1, Latitude2, Longitude2: double; var MidLat, MidLong: double);
    procedure IntermediatePoint(Latitude1, Longitude1, Latitude2, Longitude2, PathFraction: double; var IntLat, IntLong: double);
    procedure DestinationPoint(Latitude, Longtitude, Bearing, Distance: double; var DestLat, DestLong: double);
  end;

Первое на что следует обратить внимание — это на то, что все входные параметры методов задаются:

  1. Угловые величины (широта, долгота, наклон) — в градусах;
  2. Расстояния — в метрах.

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

Функции расчёта расстояний

Это, наверное, самые востребованные, по крайней мере для меня, методы. Вообще, есть несколько методов расчёта расстояний между двумя точками на Земле. В модуле реализованы два из них:

  1. Расчёт по формуле Haversine
function HaversineDistance(Latitude1, Longitude1, Latitude2, Longitude2: double): double

2. Расчёт по сферической теореме косинусов

function SLCDistance(Latitude1, Longitude1, Latitude2, Longitude2: double): double;

Оба этих метода дают практически идентичные результаты, но различаются по скорости выполнения (SLCDistance работает чуть по-быстрее).
Для того, чтобы воспользоваться этими методами необходимо задать координаты (широту и долготу) начальной и конечных точек.
Например, зададим координаты точек, представленных на рисунке:

И выведем расчёт расстояния между двумя точками в Memo:

var Geo: TGeodesy;
begin
  Geo:=TGeodesy.Create;
  try
    Memo1.Lines.Clear;
    Memo1.Lines.Add('Расстояние 1: '+Geo.HaversineDistance(55.024107,
                                                         73.365083,
                                                         55.009024,
                                                         73.364918).ToString);
    Memo1.Lines.Add('Расстояние 2: '+Geo.SLCDistance(55.024107,
                                                   73.365083,
                                                   55.009024,
                                                   73.364918).ToString);
 
  finally
    FreeAndNil(Geo);
  end;
end;

Результат выполнения функций будет следующий:

Расстояние 1: 1679,06490449157
Расстояние 2: 1679,06490449169
В Google Earth результат будет следующий:

Учитывая, что линия в Google Earth строилась «на глазок», можно сказать, что расстояние между двумя точками рассчитывается достаточно точно.

Расчёт начального направления

Для расчёта начального направления используется функция:

function Bearing(Latitude1, Longitude1, Latitude2, Longitude2: double):double;

Для проверки функции используем те же точки, что и в предыдущем примере:

Memo1.Lines.Add('Направление: '+Geo.Bearing(55.024107,
73.365083,
55.009024,
73.364918).ToString);

Результат:

Направление: -179,640576262826
Google Earth показывает положительное значение, то есть, чтобы сравнить то, что показывает Google и рассчитывает модуль, необходимо привести значение угла к диапазоны от 0 до 360 градусов и получим ровно то, что показывает Google Earth, то есть 180,35. Я такие приведения не делаю, так как для моей работы необходимо знать углы в диапазоне от -180 до 180 градусов.

Расчёт середины пути и промежуточной точки на пути

Ещё две достаточно полезные для меня процедуры. Первая процедура определяет координаты точки, лежащей ровно по середине пути (путь задается двумя точками):

procedure Midpoint(Latitude1, Longitude1, Latitude2, Longitude2: double; var MidLat, MidLong: double);

Вторая процедура определяет координаты точки лежащей на заданной части пути:

procedure IntermediatePoint(Latitude1, Longitude1, Latitude2, Longitude2, PathFraction: double; var IntLat, IntLong: double);

в этой процедуре переменная PathFraction определяет часть пути координаты конечной точки которого надо найти, например, если задать PathFraction = 0, то метод должен вернуть первую точку пути, то есть значения Latitude1, Longitude1. Соответственно, если задать PathFraction = 1, то вернется вторая точка (Latitude2, Longitude2).
Пример использования процедур:

  Geo.Midpoint(55.024107, 73.365083, 55.009024, 73.364918, MidLat, MidLong);
    Memo1.Lines.Add('Средняя точка: широта '+MidLat.ToString+' долгота '+MidLong.ToString);
    Geo.IntermediatePoint(55.024107, 73.365083, 55.009024, 73.364918, 0.5, MidLat, MidLong);
    Memo1.Lines.Add('Промежуточная точка: широта '+MidLat.ToString+' долгота '+MidLong.ToString);

Для нахождения промежуточной точки пути я использовал значение PathFraction  = 0.5 для того, чтобы можно было проверить результат работы сразу двух методов. Результат:

Средняя точка: широта 55,0165655000279 долгота 73,3650005
Промежуточная точка: широта 55,0165655000279 долгота 73,3650004844822
В Google Earth точка будет выглядеть вот так:

Определение конечной точки пути

Про этот метод я рассказывал здесь, когда добавлял в модуль для работы с KML новые возможности построения прямых линий.

procedure DestinationPoint(Latitude, Longtitude, Bearing, Distance: double; var DestLat, DestLong: double);

В результате выполнения метод возвращает широту и долготу точки, соответствующей концу пути. Bearing — наклон (направление) пути в градусах, Distance — длина пути.

Пример использования:

Geo.DestinationPoint(55.024107, 73.365083, -179.640576, 1679.0649 ,MidLat, MidLong);

В результате выполнения мы получим вторую точку пути:

Конечная точка точка: широта 55,009024 долгота 73,364918

На текущий момент это пока все возможности модуля. Остальные методы будут добавляться по мере работы над своим проектом, о котором, возможно, расскажу позднее.

Скачать модуль Delphi для геодезических расчётов можно здесь:

Исходники Delphi — Прочие
5 1 голос
Рейтинг статьи
уважаемые посетители блога, если Вам понравилась, то, пожалуйста, помогите автору с лечением. Подробности тут.
Подписаться
Уведомить о
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии