2009-09-14 9 views

Odpowiedz

26

Wzór Haversine zakłada kulisty ziemi. Jednak kształt ucha jest bardziej złożony. Spłaszczony model sferoidalny da lepsze wyniki.

Jeśli taka dokładność jest potrzebna, powinieneś lepiej użyć Vincenty odwrotnej formuły. Aby uzyskać szczegółowe informacje, patrz http://en.wikipedia.org/wiki/Vincenty's_formulae. Za jego pomocą można uzyskać dokładność 0,5 mm dla modelu sferoidalnego.

Nie ma idealnej formuły, ponieważ prawdziwy kształt Ziemi jest zbyt skomplikowany, aby można go było wyrazić za pomocą formuły. Co więcej, kształt Ziemi zmienia się z powodu zdarzeń klimatycznych (patrz http://www.nasa.gov/centers/goddard/earthandsun/earthshape.html), a także zmienia się w czasie z powodu obrotu Ziemi.

Należy również zauważyć, że powyższa metoda nie uwzględnia wysokości i przyjmuje sferoidalny obłok na poziomie morza.

Edycja 10-Jul-2010: I okazało się, że są rzadkie sytuacje, dla których formuła Wincenty odwrotna nie zbiegają do deklarowanej dokładności. Lepszym pomysłem jest użycie GeographicLib (patrz http://sourceforge.net/projects/geographiclib/), który jest również dokładniejszy.

+2

+1 to złapało całkiem sporo osób na straży u poprzedniego pracodawcy. –

+0

Rzeczywiście. Gdy wartości nie mogą być dłuższe niż kilka metrów, to pytanie staje się o wiele bardziej skomplikowane. – PeterAllenWebb

+0

+1 za "odpowiedź zależy od wymaganego stopnia dokładności" – Piskvor

4

Szukasz

Haversine formula

formuła haversine jest równaniem ważne w nawigacji, dając odległości pra-kole pomiędzy dwiema punktów na kuli z ich długościami i strefa. Jest to specjalny przypadek o bardziej ogólnej formule w sferycznej trygonometrii, prawo haversines, odnoszące się do boków i kątów sferycznych "trójkątów".

2

This link ma wszystkie potrzebne informacje, albo na nim lub połączone.

4

Spójrz na to .. ma również przykład javascript.

Find Distance

+0

Bardzo fajnie! miło znaleźć –

5

Zastosuj formułę Haversine, aby znaleźć odległość. Zobacz kod C# poniżej, aby znaleźć odległość między 2 współrzędnymi.Jeszcze lepiej, jeśli chcesz powiedzieć, znaleźć listę sklepów w określonym promieniu, można zastosować klauzulę WHERE w SQL lub filtr LINQ w C# do niego.

Formuła tutaj znajduje się w kilometrach, należy zmienić odpowiednie numery i będzie działać dla mil.

E.g: Konwertuj 6371.392896 na mile.

DECLARE @radiusInKm AS FLOAT 
    DECLARE @lat2Compare AS FLOAT 
    DECLARE @long2Compare AS FLOAT 
    SET @radiusInKm = 5.000 
    SET @lat2Compare = insert_your_lat_to_compare_here 
    SET @long2Compare = insert_you_long_to_compare_here 

    SELECT * FROM insert_your_table_here WITH(NOLOCK) 
    WHERE (6371.392896*2*ATN2(SQRT((sin((radians(GeoLatitude - @lat2Compare))/2) * sin((radians(GeoLatitude - @lat2Compare))/2)) + (cos(radians(GeoLatitude)) * cos(radians(@lat2Compare)) * sin(radians(GeoLongitude - @long2Compare)/2) * sin(radians(GeoLongitude - @long2Compare)/2))) 
    , SQRT(1-((sin((radians(GeoLatitude - @lat2Compare))/2) * sin((radians(GeoLatitude - @lat2Compare))/2)) + (cos(radians(GeoLatitude)) * cos(radians(@lat2Compare)) * sin(radians(GeoLongitude - @long2Compare)/2) * sin(radians(GeoLongitude - @long2Compare)/2))) 
    ))) <= @radiusInKm 

Jeśli chcesz wykonać wzór Haversine w C#,

double resultDistance = 0.0; 
    double avgRadiusOfEarth = 6371.392896; //Radius of the earth differ, I'm taking the average. 

    //Haversine formula 
    //distance = R * 2 * aTan2 (square root of A, square root of 1 - A) 
    //     where A = sinus squared (difference in latitude/2) + (cosine of latitude 1 * cosine of latitude 2 * sinus squared (difference in longitude/2)) 
    //     and R = the circumference of the earth 

    double differenceInLat = DegreeToRadian(currentLatitude - latitudeToCompare); 
    double differenceInLong = DegreeToRadian(currentLongitude - longtitudeToCompare); 
    double aInnerFormula = Math.Cos(DegreeToRadian(currentLatitude)) * Math.Cos(DegreeToRadian(latitudeToCompare)) * Math.Sin(differenceInLong/2) * Math.Sin(differenceInLong/2); 
    double aFormula = (Math.Sin((differenceInLat)/2) * Math.Sin((differenceInLat)/2)) + (aInnerFormula); 
    resultDistance = avgRadiusOfEarth * 2 * Math.Atan2(Math.Sqrt(aFormula), Math.Sqrt(1 - aFormula)); 

DegreesToRadian jest funkcją Mam zwyczaj stworzony, jego jest prosty 1 wyłożenie "Math.PI * angle/180.0

My blog entry - SQL Haversine

-1

wystarczy użyć wzoru odległości: Sqrt((x2-x1)^2 + (y2-y1)^2)

1

o to skrzypce ze znalezieniem miejsca/Near lokalizacje na długo/szer przez danego IP:

http://jsfiddle.net/bassta/zrgd9qc3/2/

i tutaj jest funkcja używam obliczyć odległość w linii prostej:

function distance(lat1, lng1, lat2, lng2) { 
     var radlat1 = Math.PI * lat1/180; 
     var radlat2 = Math.PI * lat2/180; 
     var radlon1 = Math.PI * lng1/180; 
     var radlon2 = Math.PI * lng2/180; 
     var theta = lng1 - lng2; 
     var radtheta = Math.PI * theta/180; 
     var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta); 
     dist = Math.acos(dist); 
     dist = dist * 180/Math.PI; 
     dist = dist * 60 * 1.1515; 

     //Get in in kilometers 
     dist = dist * 1.609344; 

     return dist; 
    } 

Zwraca odległość w kilometrach

0

Poniżej modułu (kodowane w F90) zawierającej trzy wzorach omówionych w poprzednich odpowiedzi. Możesz umieścić ten moduł na górze swojego programu (przed PROGRAM MAIN) lub skompilować go oddzielnie i dołączyć katalog modułów podczas kompilacji.

module spherical_dists 
contains 
subroutine haversine_formula(lon1,lat1,lon2,lat2,dist) 
implicit none 
real,intent(in)::lon1,lon2,lat1,lat2 
real,intent(out)::dist 
real,parameter::pi=3.141592,mean_earth_radius=6371.0088 
real::lonr1,lonr2,latr1,latr2 
real::delangl,dellon,dellat,a 
lonr1=lon1*(pi/180.);lonr2=lon2*(pi/180.) 
latr1=lat1*(pi/180.);latr2=lat2*(pi/180.) 
dellon=lonr2-lonr1 
dellat=latr2-latr1 
a=(sin(dellat/2))**2+cos(latr1)*cos(latr2)*(sin(dellon/2))**2 
delangl=2*asin(sqrt(a)) !2*asin(sqrt(a)) 
dist=delangl*mean_earth_radius 
end subroutine 
subroutine great_circle_distance(lon1,lat1,lon2,lat2,dist) 
implicit none 
real,intent(in)::lon1,lon2,lat1,lat2 
real,intent(out)::dist 
real,parameter::pi=3.141592,mean_earth_radius=6371.0088 
real::lonr1,lonr2,latr1,latr2 
real::delangl,dellon 
lonr1=lon1*(pi/180.);lonr2=lon2*(pi/180.) 
latr1=lat1*(pi/180.);latr2=lat2*(pi/180.) 
dellon=lonr2-lonr1 
delangl=acos(sin(latr1)*sin(latr2)+cos(latr1)*cos(latr2)*cos(dellon)) 
dist=delangl*mean_earth_radius 
end subroutine 
subroutine vincenty_formula(lon1,lat1,lon2,lat2,dist) 
implicit none 
real,intent(in)::lon1,lon2,lat1,lat2 
real,intent(out)::dist 
real,parameter::pi=3.141592,mean_earth_radius=6371.0088 
real::lonr1,lonr2,latr1,latr2 
real::delangl,dellon,nom,denom 
lonr1=lon1*(pi/180.);lonr2=lon2*(pi/180.) 
latr1=lat1*(pi/180.);latr2=lat2*(pi/180.) 
dellon=lonr2-lonr1 
nom=sqrt((cos(latr2)*sin(dellon))**2. + (cos(latr1)*sin(latr2)-sin(latr1)*cos(latr2)*cos(dellon))**2.) 
denom=sin(latr1)*sin(latr2)+cos(latr1)*cos(latr2)*cos(dellon) 
delangl=atan2(nom,denom) 
dist=delangl*mean_earth_radius 
end subroutine 
end module 
0

mam zrobić za pomocą zapytania SQL

wybrać (ACO (sin (input_lat 0.01745329) * sin (Lattitude * 0,01745329) + cos (input_lat * 0,01745329) * cos (Lattitude * 0,01745329) * cos ((input_long-longitude) 0.01745329)) 57.29577951) * 69.16 Jako D z nazwa_tabeli

Powiązane problemy