2009-09-14 25 views

risposta

26

La formula Haversine assume una terra sferica. Tuttavia, la forma dell'orecchio è più complessa. Un modello sferoidale oblato darà risultati migliori.

Se è necessaria tale precisione, è preferibile utilizzare formula inversa inversa. Vedere http://en.wikipedia.org/wiki/Vincenty's_formulae per dettagli. Usandolo, è possibile ottenere una precisione di 0,5 mm per il modello sferoide.

Non esiste una formula perfetta, poiché la forma reale della terra è troppo complessa per essere espressa da una formula. Inoltre, la forma della terra cambia a causa di eventi climatici (vedi http://www.nasa.gov/centers/goddard/earthandsun/earthshape.html), e cambia anche nel tempo a causa della rotazione della terra.

Si noti inoltre che il metodo sopra riportato non tiene conto delle altitudini e presuppone uno sferoide oblato a livello del mare.

Modifica 10-Jul-2010: Ho scoperto che ci sono situazioni rare per le quali la formula inversa di Vincenty non converge all'accuratezza dichiarata. Un'idea migliore è usare GeographicLib (vedi http://sourceforge.net/projects/geographiclib/) che è anche più preciso.

+2

+1 questo catturato un bel po 'di persone di guardia a un precedente datore di lavoro. –

+0

Infatti. Quando i valori non possono essere più di pochi metri, questa domanda diventa molto più complicata. – PeterAllenWebb

+0

+1 per "la risposta dipende dal grado di precisione richiesto" – Piskvor

4

Siete alla ricerca di

Haversine formula

La formula haversine è un'equazione importante nella navigazione, dando distanze grande-cerchio tra due punti su una sfera dalle loro longitudini e latitudini. È un caso speciale di una formula più generale in trigonometria sferica, la legge di haversine, relativa ai lati e agli angoli di "triangoli" sferici.

2

This link ha tutte le informazioni necessarie, sia su di esso o collegate.

4

Dai un'occhiata a questo .. ha un esempio javascript pure.

Find Distance

+0

Molto bello! bella scoperta –

9

Ecco uno: http://www.movable-type.co.uk/scripts/latlong.html

Usando la formula Haversine:

R = earth’s radius (mean radius = 6,371km) 
Δlat = lat2− lat1 
Δlong = long2− long1 
a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2) 
c = 2.atan2(√a, √(1−a)) 
d = R.c 
5

Applicare la formula di Haversine per trovare la distanza. Vedere il codice C# qui sotto per trovare la distanza tra 2 coordinate.Meglio ancora se vuoi dire di trovare una lista di negozi entro un certo raggio, potresti applicare una clausola WHERE in SQL o un filtro LINQ in C#.

La formula qui è in chilometri, dovrai cambiare i numeri rilevanti e funzionerà per miglia.

E.g: Convertire 6371.392896 in miglia.

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 

Se si desidera eseguire la formula Haversine in 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 è una funzione che ho personalizzato creato, il suo è un semplice 1 fodera di "Math.PI * angle/180.0

My blog entry - SQL Haversine

-1

basta usare la formula della distanza Sqrt((x2-x1)^2 + (y2-y1)^2)

1

ecco un violino con trovare luoghi/vicina a posizioni a lungo LAT/dal dato IP:

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

E qui è la funzione che uso per calcolare la distanza in linea retta:

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; 
    } 

Restituisce la distanza in Kilometers

0

seguito è il modulo (codificato in f90) contenente tre formule discusse nelle risposte precedenti. È possibile inserire questo modulo nella parte superiore del programma (prima di PROGRAMMA MAIN) o compilarlo separatamente e includere la directory del modulo durante la compilazione.

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

mi sono fatto utilizzando query SQL

selezionare , (OAC (sin (input_lat ,01,745329 millions) * sin (lattitude * ,01,745329 millions) + cos (input_lat * ,01,745329 millions) * cos (lattitude * ,01,745329 millions) * cos ((input_long -longitude) 0.01745329)) 57.29577951) * 69.16 As D da table_name

Problemi correlati