2011-01-17 39 views
8

Tôi có một số người dùng đã đăng ký trong ứng dụng Django và tôi muốn đơn giản có thể tìm ra khoảng cách, về mặt địa lý, giữa hai người dùng dựa trên mã zip của họ và sau đó sắp xếp danh sách dựa trên đó. Tôi sẽ tưởng tượng chức năng này không được xây dựng thành Django. Tôi đã nhìn vào một số tùy chọn và vấp trên geodjango mà có vẻ như nó có thể là overkill cho những gì nhu cầu của tôi.Django - làm thế nào tôi có thể tìm thấy khoảng cách giữa hai địa điểm?

+0

Đây là [công thức ActiveState] (http://code.activestate.com/recipes/393241-calculating-the-distance-between-zip-codes/) cho mục đích này. Nó gần như chắc chắn không được xây dựng thành Django. –

+1

Hãy xem [Dự án Cơ sở dữ liệu Mã Zip] (http://zips.sourceforge.net/). Họ cũng cung cấp mã Python để tính toán khoảng cách trên trang được liên kết. –

+1

@Sven Marnach - đăng dự án Cơ sở dữ liệu mã zip như một câu trả lời - đó là một câu trả lời hay. (Và có, GeoDjango có lẽ là quá mức cần thiết cho điều này.) – tcarobruce

Trả lời

6

Tiếp theo đề nghị của tcarobruce, đây là bình luận trên của tôi như là một câu trả lời:

Các Zip Code Database Project có một cơ sở dữ liệu của các vĩ độ và kinh độ của các mã zip Mỹ, hoặc như SQL hoặc CSV. Chúng cũng cung cấp mã sau đây để tính toán khoảng cách (slighlty do tôi chỉnh sửa):

from math import sin, cos, radians, degrees, acos 

def calc_dist(lat_a, long_a, lat_b, long_b): 
    lat_a = radians(lat_a) 
    lat_b = radians(lat_b) 
    long_diff = radians(long_a - long_b) 
    distance = (sin(lat_a) * sin(lat_b) + 
       cos(lat_a) * cos(lat_b) * cos(long_diff)) 
    return degrees(acos(distance)) * 69.09 

Lưu ý rằng kết quả được đưa ra theo luật định.

Chỉnh sửa: Sửa chữa do John Machin.

+0

Bạn nên chống lại sự cám dỗ để chỉnh sửa một chút mã gốc mà không cần kiểm tra kết quả. Xem câu trả lời của tôi. –

0

http://code.google.com/apis/maps/documentation/directions/

Bạn có thể chỉ đường cho từng vị trí. Tổng khoảng cách được đưa ra. API dường như xuất ra JSON; bạn có thể phân tích cú pháp câu trả lời ở phía máy chủ hoặc có khoảng cách được tính bằng JavaScript.

+0

Làm điều này sẽ trái với điều khoản dịch vụ của Google, trừ khi bạn là khách hàng của Maps for Business, btw. – Jordan

18

Đây là một nhận xét lớn về chất béo trên mã được đăng trong câu trả lời (hiện được chấp nhận) bởi @Sven Marnach.

đang gốc từ trang web của dự án zip, với thụt đầu dòng thay đổi nội dung bởi tôi:

from math import * 
def calcDist(lat_A, long_A, lat_B, long_B): 
    distance = (sin(radians(lat_A)) * 
     sin(radians(lat_B)) + 
     cos(radians(lat_A)) * 
     cos(radians(lat_B)) * 
     cos(radians(long_A - long_B))) 
    distance = (degrees(acos(distance))) * 69.09 
    return distance 

Mã đăng bởi Sven:

from math import sin, cos, radians, degrees 

def calc_dist(lat_a, long_a, lat_b, long_b): 
    lat_a = radians(lat_a) 
    lat_b = radians(lat_b) 
    distance = (sin(lat_a) * sin(lat_b) + 
       cos(lat_a) * cos(lat_b) * cos(long_a - long_b)) 
    return degrees(acos(distance)) * 69.09 

Vấn đề 1: SẼ KHÔNG CHẠY: nhu cầu nhập khẩu acos

Bài toán 2: SAI TRẢ LỜI: cần chuyển đổi sự khác biệt kinh độ thành radian ở dòng cuối cùng thứ hai

Bài toán 3: Tên biến "khoảng cách" là một từ sai cùng cực. Số lượng đó thực sự là cos của góc giữa hai dòng từ trung tâm của trái đất đến các điểm đầu vào. Thay đổi thành "cos_x"

Bài toán 4: Không cần phải chuyển đổi góc x thành độ. Đơn giản chỉ cần nhân x bằng bán kính trái đất trong đơn vị được lựa chọn (km, nm, hay "dặm quy chế")

Sau khi sửa chữa tất cả những gì chúng tôi nhận được:

from math import sin, cos, radians, acos 

# http://en.wikipedia.org/wiki/Earth_radius 
# """For Earth, the mean radius is 6,371.009 km (˜3,958.761 mi; ˜3,440.069 nmi)""" 
EARTH_RADIUS_IN_MILES = 3958.761 

def calc_dist_fixed(lat_a, long_a, lat_b, long_b): 
    """all angles in degrees, result in miles""" 
    lat_a = radians(lat_a) 
    lat_b = radians(lat_b) 
    delta_long = radians(long_a - long_b) 
    cos_x = (
     sin(lat_a) * sin(lat_b) + 
     cos(lat_a) * cos(lat_b) * cos(delta_long) 
     ) 
    return acos(cos_x) * EARTH_RADIUS_IN_MILES 

Lưu ý: Sau khi sửa chữa vấn đề 1 và 2, điều này là "luật hình cầu của các cô gái" như thường được thực hiện. Có thể áp dụng cho các ứng dụng như "khoảng cách giữa hai mã zip của Hoa Kỳ".

Giới hạn 1: Không chính xác cho khoảng cách nhỏ như từ cửa trước của bạn ra đường, rất nhiều để nó có thể cung cấp khoảng cách khác 0 hoặc tăng ngoại lệ (cos_x> 1.0) nếu hai điểm giống nhau ; tình huống này có thể là đặc biệt.

caveat 2: Nếu hai điểm là đối xứng (đường thẳng đi qua trung tâm của trái đất), nó có thể tăng ngoại lệ (cos_x < -1.0). Bất cứ ai lo lắng về điều đó có thể kiểm tra cos_x trước khi thực hiện acos (cos_x).

Ví dụ:

SFO (37,676, -122,433) để NYC (40,733, -73,917)

calcDist -> 2570,7758043869976
calc_dist -> 5038,599866130089
calc_dist_fixed -> 2570,9028268899356

Một Trang web của chính phủ Hoa Kỳ (http://www.nhc.noaa.gov/gccalc.shtml) -> 2569

Trang web này (http://www.timeanddate.com /worldclock/distanceresult.html?p1=179 & p2 = 224), từ mà tôi nhận được tọa độ SFO và NYC, -> 2577

+0

@Sven Marnach: Kiểm tra lại mã của bạn. Có chính xác hai lần xuất hiện của 'radian', mỗi lần áp dụng cho vĩ độ, không áp dụng cho kinh độ. Kiểm tra lại mã của tôi. 'radian' được áp dụng ONCE cho chênh lệch kinh độ. Hãy thử kiểm tra các mã và giải thích lý do tại sao mã của bạn là kỳ quặc. –

+0

@Sven Marnach: Thật buồn cười; Tôi có thể thề rằng tôi thấy một bình luận mà bạn nói rằng mã của tôi đã sai. SO cần một đường mòn kiểm toán :-) –

+0

Xin lỗi vì điều đó. Lời nhận xét đã ở đó trong vài giây, nhưng tôi ngay lập tức nhận ra tôi đã sai. Không nghĩ rằng bạn đã tải trang trong khung thời gian nhỏ bé đó :) –

0

Một cách đơn giản:

Dưới hàm trả về khoảng cách giữa hai vị trí sau khi tính toán vĩ độ và kinh độ từ mã zip.

lat1, long1 là các vĩ độ và kinh độ của vị trí đầu tiên.

lat2, long2 là các vĩ độ và kinh độ của vị trí thứ hai.

from decimal import Decimal 
from math import sin, cos, sqrt, atan2, radians 

def distance(lat1, lat2, long1, long2): 
    r = 6373.0 

    lat1 = radians(lat1) 
    lat2 = radians(lat2) 
    long1 = radians(long1) 
    long2 = radians(long2) 

    d_lat = lat2 - lat1 
    d_long = long2 - long1 

    a = (sin(d_lat/2))**2 + cos(lat1) * cos(lat2) * (sin(d_long/2))**2 
    c = 2 * atan2(sqrt(a), sqrt(1-a)) 

    # distance in miles 
    dis = r * c 

    # distance in KM 
    dis /= 1.609344 

    return dis 
Các vấn đề liên quan