Как рассчитать азимут (угол к северу) между двумя координатами WGS84

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

есть ли простой способ рассчитать Азимут линии между этими точками, то есть угол к северу?

наивным подходом было бы предположить декартову систему координат (потому что эти точки так близко друг к другу) и просто использовать

sin (a) = abs (L2 - L1) / sqrt(sqr(L2-L1) + sqr (B2-B1))

a = Азимут Л1, Л2 = долготы Б1, Б2 = широте

ошибка будет больше, поскольку координаты удаляются от экватора, потому что там расстояние между двумя продольными градусами становится все меньше, чем расстояние между двумя широтными градусами (которое остается постоянным).

Я нашел некоторые довольно сложные формулы, которые я действительно не хочу реализовывать, потому что они кажутся излишними для точек, которые так близко друг к другу, и я не нужна очень высокая точность (достаточно двух десятичных знаков, один, вероятно, прекрасен, так как есть другие факторы, которые уменьшают точность в любом случае, например, тот, который возвращает GPS).

возможно, я мог бы просто определить приблизительный коэффициент продольной коррекции в зависимости от широты и использовать что-то вроде этого:

sin (a) = abs(L2*f-L1*f) / sqrt(sqr(L2*f-L1*f) + sqr(B2-B1))

где F-поправочный коэффициент

какие-то намеки?

(Я не для этого необходимо использовать любые библиотеки, особенно те, которые требуют лицензий среды выполнения. Любой источник Mpled Delphi будет отличным.)

5 ответов


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

uses Math, ...;
...

const
  cNO_ANGLE=-999;

...

function getAngleBetweenPoints(X1,Y1,X2,Y2:double):double;
var
  dx,dy:double;
begin
  dx := X2 - X1;
  dy := Y2 - Y1;

  if (dx > 0) then  result := (Pi*0.5) - ArcTan(dy/dx)   else
  if (dx < 0) then  result := (Pi*1.5) - ArcTan(dy/dx)   else
  if (dy > 0) then  result := 0                          else
  if (dy < 0) then  result := Pi                         else
                    result := cNO_ANGLE; // the 2 points are equal

  result := RadToDeg(result);
end;
  • Не забудьте обработать ситуацию, когда 2 точки равны (проверьте, равен ли результат cNO_ANGLE, или измените функцию, чтобы вызвать исключение);

  • эта функция предполагает, что вы находитесь на плоской поверхности. С небольшими расстояниями, о которых вы упомянули, это все. хорошо, но если вы собираетесь вычислять заголовок между городами по всему миру, вы можете посмотреть на что-то, что принимает форму Земли в графе;

  • лучше всего предоставить этой функции координаты, которые уже сопоставлены с плоской поверхностью. Вы можете подать широту WGS84 непосредственно в Y (и lon в X), чтобы получить грубое приближение.


вот решение C#. Испытания для 0, 45, 90, 135, 180, 225, 270 и 315 углы.

редактировать Я заменил свое предыдущее уродливое решение переводом решения Ваутера на C#:

public double GetAzimuth(LatLng destination)
{
    var longitudinalDifference = destination.Lng - this.Lng;
    var latitudinalDifference = destination.Lat - this.Lat;
    var azimuth = (Math.PI * .5d) - Math.Atan(latitudinalDifference / longitudinalDifference);
    if (longitudinalDifference > 0) return azimuth;
    else if (longitudinalDifference < 0) return azimuth + Math.PI;
    else if (latitudinalDifference < 0) return Math.PI;
    return 0d;
}

public double GetDegreesAzimuth(LatLng destination)
{
    return RadiansToDegreesConversionFactor * GetAzimuth(destination);
}

Я нашел эту ссылку

http://williams.best.vwh.net/avform.htm

дано в ответе на

Lat / Lon + Расстояние + Направление --> Lat / Lon

Это выглядит многообещающим, особенно приближение плоской Земли, данное ближе к концу.


Это будет работать только для небольших различиях. В противном случае вы не можете просто "latitudinalDifference / longitudinalDifference".


Я бы рекомендовал реализовать поправочный коэффициент, основанный на долготе. Однажды я внедрил процедуру simular, чтобы вернуть все геокодированные записи в пределах x миль от определенного места и столкнулся с проблемами simular. К сожалению, у меня больше нет кода, и я не могу вспомнить, как я добрался до номера исправления, но вы на правильном пути.