2012-10-19 9 views

Odpowiedz

62

Odległość między dwoma współrzędnymi na Ziemi jest zwykle obliczana za pomocą Haversine formula. Ta formuła uwzględnia kształt i promień ziemi. Jest to kod, którego używam do obliczania odległości w metrach.

def distance loc1, loc2 
    rad_per_deg = Math::PI/180 # PI/180 
    rkm = 6371     # Earth radius in kilometers 
    rm = rkm * 1000    # Radius in meters 

    dlat_rad = (loc2[0]-loc1[0]) * rad_per_deg # Delta, converted to rad 
    dlon_rad = (loc2[1]-loc1[1]) * rad_per_deg 

    lat1_rad, lon1_rad = loc1.map {|i| i * rad_per_deg } 
    lat2_rad, lon2_rad = loc2.map {|i| i * rad_per_deg } 

    a = Math.sin(dlat_rad/2)**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin(dlon_rad/2)**2 
    c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1-a)) 

    rm * C# Delta in meters 
end 

puts distance [46.3625, 15.114444],[46.055556, 14.508333] 
# => 57794.35510874037 
+6

Formuła Haversine jest również używana w [Geocoder] (http://rubygems.org/gems/geocoder), patrz plik [calculations.rb] (https: //github.com/alexreisner/geocoder/blob/master/lib/geocoder/calculations.rb#L72). –

+2

Ta metoda modyfikuje wartości 'a' i' b', co jest nieoczekiwane. Domyślam się, że nie trzeba używać '.map!' Zamiast '.map' lub ponownie używać' a'. – joscas

+1

Edytowane tak, aby już nie było. – Lunivore

2

Spójrz gem Geocoder (railscast)

Jeśli przechowywać swoje współrzędne w db, obliczyć odległość za pomocą Baza danych. Ale działa również w innych przypadkach.

+0

Jak czy uzyskałbym dostęp do metody w https://github.com/alexreisner/geocoder/blob/master/lib/geocoder/calculations.rb? –

+0

podobnie jak w przypadku '' 'Geocoder :: Calculations.coordinates_present?' '' –

5

Możesz użyć geokit ruby gem. Wykonuje te obliczenia wewnętrznie, ale obsługuje także rozwiązywanie adresów za pośrednictwem Google i innych usług, jeśli jest to potrzebne.

require 'geokit' 

current_location = Geokit::LatLng.new(37.79363,-122.396116) 
destination = "37.786217,-122.41619" 
current_location.distance_to(destination) 

# Returns distance in miles: 1.211200074136264 

Możesz również dowiedzieć się bearing_to (kierunek wyrażoną jako pływaka w stopniach pomiędzy 0-360) i midpoint_to (zwraca obiekt można uruchomić metod .latitude i .longitude on).

3

Tylko trochę krótsza & oddzielone wersja parametr @ odpowiedź Lunivore za

RAD_PER_DEG = Math::PI/180 
RM = 6371000 # Earth radius in meters 

def distance_between(lat1, lon1, lat2, lon2) 
    lat1_rad, lat2_rad = lat1 * RAD_PER_DEG, lat2 * RAD_PER_DEG 
    lon1_rad, lon2_rad = lon1 * RAD_PER_DEG, lon2 * RAD_PER_DEG 

    a = Math.sin((lat2_rad - lat1_rad)/2) ** 2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * Math.sin((lon2_rad - lon1_rad)/2) ** 2 
    c = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1 - a)) 

    RM * C# Delta in meters 
end 
1

Stary przyjętej odpowiedź Swift 3.1 (działa na Xcode 8.3), w przypadku każdego, kto potrzebuje go:

public static func calculateDistanceMeters(departure: CLLocationCoordinate2D, arrival: CLLocationCoordinate2D) -> Double { 

    let rad_per_deg = Double.pi/180.0 // PI/180 
    let rkm = 6371.0     // Earth radius in kilometers 
    let rm = rkm * 1000.0    // Radius in meters 

    let dlat_rad = (arrival.latitude - departure.latitude) * rad_per_deg // Delta, converted to rad 
    let dlon_rad = (arrival.longitude - departure.longitude) * rad_per_deg 

    let lat1_rad = departure.latitude * rad_per_deg 
    let lat2_rad = arrival.latitude * rad_per_deg 

    let sinDlat = sin(dlat_rad/2) 
    let sinDlon = sin(dlon_rad/2) 
    let a = sinDlat * sinDlat + cos(lat1_rad) * cos(lat2_rad) * sinDlon * sinDlon 
    let c = 2.0 * atan2(sqrt(a), sqrt(1-a)) 

    return rm * c 
} 
Powiązane problemy