2009-02-20 23 views

Respuesta

23

La forma tradicional de calcular la distancia entre dos puntos (cada par de waypoints en su archivo GPX) es con la fórmula Haversine.

Tengo una función de SQL Server que implementa el algoritmo. Esto debería ser fácil de traducir a otros idiomas:

create function dbo.udf_Haversine(@lat1 float, @long1 float, 
        @lat2 float, @long2 float) returns float begin 
    declare @dlon float, @dlat float, @rlat1 float, 
       @rlat2 float, @rlong1 float, @rlong2 float, 
       @a float, @c float, @R float, @d float, @DtoR float 

    select @DtoR = 0.017453293 
    select @R = 3959  -- Earth radius 

    select 
     @rlat1 = @lat1 * @DtoR, 
     @rlong1 = @long1 * @DtoR, 
     @rlat2 = @lat2 * @DtoR, 
     @rlong2 = @long2 * @DtoR 

    select 
     @dlon = @rlong1 - @rlong2, 
     @dlat = @rlat1 - @rlat2 

    select @a = power(sin(@dlat/2), 2) + cos(@rlat1) * 
        cos(@rlat2) * power(sin(@dlon/2), 2) 
    select @c = 2 * atn2(sqrt(@a), sqrt([email protected])) 
    select @d = @R * @c 

    return @d 
end 

Esto devuelve la distancia en millas. Para kilómetros, reemplace el radio de tierra con su equivalente de km.

Here es una explicación más detallada.

Editar: Esta función es lo suficientemente rápida y precisa para hacer búsquedas de radio con una base de datos de código postal. Ha estado haciendo un gran trabajo en this site durante años (pero ya no funciona, ya que el enlace está roto ahora).

+0

Muchas gracias. Voy a portarlo a Java y publicarlo aquí. ¿Qué significa @DtoR? Distancia a Radio? – guerda

+1

Ese es el factor que convierte grados en radianes, pi/180. – cdonner

+0

Gracias por el enlace. Voy a publicar mi versión de Java pronto – guerda

1

La implementación de Delphi de Vincenty formulae se puede encontrar en here.

+0

¿Tiene un enlace actualizado para esto? –

+0

@ Adam Carter: Revisé la URL y todavía está bien. – menjaraz

1

Aquí hay una implementación de Scala.

3958.761 es el mean radius of the Earth en millas. Para obtener un resultado en km (o en alguna otra unidad) solo modifique este número.

// The Haversine formula 
def haversineDistance(pointA: (Double, Double), pointB: (Double, Double)): Double = { 
    val deltaLat = math.toRadians(pointB._1 - pointA._1) 
    val deltaLong = math.toRadians(pointB._2 - pointA._2) 
    val a = math.pow(math.sin(deltaLat/2), 2) + math.cos(math.toRadians(pointA._1)) * math.cos(math.toRadians(pointB._1)) * math.pow(math.sin(deltaLong/2), 2) 
    val greatCircleDistance = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) 
    3958.761 * greatCircleDistance 
} 

// A sequence of gpx trackpoint lat,long pairs parsed from the track GPX data 
val trkpts: Seq[(Double, Double)] = { 
    val x = scala.xml.XML.loadString(track) 
    (x \\ "trkpt").map(trkpt => ((trkpt \ "@lat").text.toDouble, (trkpt \ "@lon").text.toDouble)) 
} 

// Distance of track in miles using Haversine formula 
val trackDistance: Double = { 
    trkpts match { 
    case head :: tail => tail.foldLeft(head, 0.0)((accum, elem) => (elem, accum._2 + haversineDistance(accum._1, elem)))._2 
    case Nil => 0.0 
    } 
} 
0

Esta pregunta es bastante antigua, pero me gustaría agregar una opción de pitón para completarla. GeoPy tiene great-circle distance y Vincenty distance.

Cuestiones relacionadas