Как рассчитать азимут (угол к северу) между двумя координатами 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. К сожалению, у меня больше нет кода, и я не могу вспомнить, как я добрался до номера исправления, но вы на правильном пути.