2012-10-19 73 views

Trả lời

62

Khoảng cách giữa hai tọa độ trên trái đất thường được tính bằng cách sử dụng Haversine formula. Công thức này xem xét hình dạng và bán kính của trái đất. Đây là mã tôi sử dụng để tính toán khoảng cách tính bằng mét.

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

Công thức Haversine cũng được sử dụng trong [Geocoder] (http://rubygems.org/gems/geocoder), xem tệp [comput.rb] (https: //github.com/alexreisner/geocoder/blob/master/lib/geocoder/calculations.rb#L72). –

+2

Phương pháp này sửa đổi các giá trị của 'a' và' b' không mong muốn. Tôi đoán không cần phải sử dụng '.map!' Thay vì '.map' hoặc để tái sử dụng' a' một lần nữa. – joscas

+1

Đã chỉnh sửa để không còn xảy ra nữa. – Lunivore

2

Nhìn vào viên ngọc Geocoder (railscast)

Nếu bạn lưu trữ tọa độ của bạn trong db, nó tính toán khoảng cách sử dụng cơ sở dữ liệu. Nhưng hoạt động tốt trong các trường hợp khác nữa.

+0

thế nào tôi có thể truy cập phương thức trong https://github.com/alexreisner/geocoder/blob/master/lib/geocoder/calculations.rb không? –

+0

giống như vậy '' 'Geocoder :: Calculations.coordinates_present?' '' –

5

Bạn có thể sử dụng geokit ruby gem. Nó thực hiện các tính toán này trong nội bộ, nhưng cũng hỗ trợ giải quyết các địa chỉ thông qua google và các dịch vụ khác nếu bạn cần nó.

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 

Bạn cũng có thể tìm ra bearing_to (hướng thể hiện như một phao trong độ giữa 0-360) và midpoint_to (trả về một đối tượng bạn có thể chạy các phương pháp .latitude và .longitude trên).

3

Chỉ cần một chút ngắn hơn & tách ra phiên bản thông số của @ câu trả lời Lunivore của

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

Chuyển Đổi câu trả lời chấp nhận Swift 3.1 (hoạt động trên Xcode 8.3), trong trường hợp bất cứ ai cần nó:

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 
} 
Các vấn đề liên quan