2009-03-13 19 views
7

Tengo dos coordenadas WGS84, latitud y longitud en grados. Estos puntos son más bien juntos, p. solo un metro de distancia.Cómo calculo el acimut (ángulo al norte) entre dos coordenadas WGS84

¿Hay alguna manera fácil de calcular el acimut de la línea entre estos puntos, es decir, el ángulo hacia el norte?

El enfoque ingenuo sería suponer un sistema de coordenadas cartesiano (debido a que estos puntos están tan cerca juntos) y sólo tiene que utilizar

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

a = acimut L1, L2 = longitud B1, B2 = latitud

el error será más grande que las coordenadas se mueven lejos del ecuador debido a que la distancia entre dos grados longitudinales se vuelven cada vez más pequeños que el que está entre dos grados latitudinales (que permanece c onstant).

Encontré algunas fórmulas bastante complejas que realmente no quiero implementar porque parecen ser excesivas para los puntos que están muy juntos y no necesito una precisión muy alta (dos decimales son suficientes, uno es probablemente bien, ya que hay otros factores que reducen la precisión de todos modos, como el que devuelve el GPS).

Tal vez podría simplemente determinar un factor de corrección longitudinal aproximada en función de la latitud y usar algo como esto:

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

donde f es el factor de corrección

¿Alguna pista?

(no quiero utilizar ninguna biblioteca para esto, sobre todo, no los que requieren licencias de tiempo de ejecución. Cualquier MPLed Fuente Delphi sería grande.)

+1

Por lo que vale la pena, el término que está buscando es "la partida". – hobbs

Respuesta

10

Las fórmulas a las que se refiere en el texto son para calcular la distancia de círculo máximo entre 2 puntos.Así es como puedo calcular el ángulo entre los puntos:

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; 
  • Recordar para manejar la situación en la que 2 puntos son iguales (comprobar si el resultado es igual cNO_ANGLE, o modificar la función para lanzar una excepción);

  • Esta función supone que estás en una superficie plana. Con las pequeñas distancias que usted ha mencionado todo esto está bien, pero si usted va a ser el cálculo de la partida entre las ciudades de todo el mundo que puede que desee ver en algo que toma la forma de la tierra en el recuento;

  • Lo mejor es proporcionar esta función con coordenadas que ya están asignados a una superficie plana. Podría alimentar WGS84 Latitude directamente en Y (y lon en X) para obtener una aproximación aproximada.

+0

¡Gran solución! Lo traduje a C# para reemplazar mi respuesta anterior. –

+1

¿No es solo atan2()? –

+1

@ Martin Beckett: Sí, atan2 también hace esto con 'Atan2 (dy; dx)', pero por supuesto una dx negativo devolverá un valor negativo que tendrá que ser añadido a 360. Y 0 a tener que ser tratado por separado. – MPelletier

0

recomendaría la aplicación de un factor de corrección basado en la longitud. Implementé una rutina simular una vez para devolver todos los registros geocodificados dentro de x millas de un punto específico y encontré problemas similares. Lamentablemente, ya no tengo el código y no puedo recordar cómo llegué al número de corrección, pero estás en el camino correcto.

5

Aquí está la solución C#. Probado para 0, 45, 90, 135, 180, 225, 270 y 315 ángulos.

Editar reemplacé mi solución fea anterior, por el C# traducción de solución de Wouter:

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); 
} 
+1

¿No es mejor utilizar Math.atan2 en lugar de Math.atan para evitar la división, y en particular para evitar la división por cero. La ventaja adicional es que da una respuesta con un rango de -π ... + π, obviando así las correcciones que realiza al final. –

2

esto funcionaría sólo para pequeñas diferencias. De lo contrario, no puede simplemente "diferencia latitudinal/diferencia longitudinal".

Cuestiones relacionadas