2009-09-14 4 views

Répondre

26

La formule Haversine assume une terre sphérique. Cependant, la forme de l'oreille est plus complexe. Un modèle sphéroïde oblat donnera de meilleurs résultats.

Si une telle précision est nécessaire, mieux vaut utiliser Vincenty formule inverse. Voir http://en.wikipedia.org/wiki/Vincenty's_formulae pour plus de détails. En l'utilisant, vous pouvez obtenir une précision de 0,5 mm pour le modèle sphéroïde.

Il n'y a pas de formule parfaite, car la forme réelle de la terre est trop complexe pour être exprimée par une formule. De plus, la forme de la terre change en raison des événements climatiques (voir http://www.nasa.gov/centers/goddard/earthandsun/earthshape.html), et change également avec le temps en raison de la rotation de la terre.

Vous devriez également noter que la méthode ci-dessus ne prend pas en compte les altitudes et suppose un sphéroïde oblique au niveau de la mer.

Édition 10-Jul-2010: J'ai découvert qu'il existe des situations rares pour lesquelles la formule inverse de Vincenty ne converge pas vers la précision déclarée. Une meilleure idée est d'utiliser GeographicLib (voir http://sourceforge.net/projects/geographiclib/) qui est aussi plus précis.

+2

+1 cela attrapé assez peu de gens au dépourvu chez un employeur précédent. –

+0

En effet. Lorsque les valeurs ne peuvent être éloignées de plus de quelques mètres, cette question devient beaucoup plus compliquée. – PeterAllenWebb

+0

+1 pour "réponse dépend du degré de précision requis" – Piskvor

4

Vous cherchez

Haversine formula

La formule Haversine est une équation importante dans la navigation, donnant distances grand cercle entre deux points sur une sphère de leurs longitudes et latitudes. C'est un cas particulier d'une formule plus générale en trigonométrie sphérique, la loi de haversines, reliant les côtés et angles de "triangles" sphériques.

2

This link a toutes les informations dont vous avez besoin, soit sur elle ou liées.

4

Jetez un oeil à ceci .. a également un exemple javascript.

Find Distance

+0

Très cool! belle trouvaille –

9

est ici un: http://www.movable-type.co.uk/scripts/latlong.html

En utilisant la formule 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

Appliquez la formule de Haversine pour trouver la distance. Voir le code C# ci-dessous pour trouver la distance entre 2 coordonnées.Mieux encore si vous voulez dire trouver une liste de magasins dans un certain rayon, vous pouvez appliquer une clause WHERE dans SQL ou un filtre LINQ dans C#.

La formule ici est en kilomètres, vous devrez changer les chiffres pertinents et cela fonctionnera pendant des miles.

E.g: Convertissez 6371.392896 en milles.

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 

Si vous souhaitez effectuer la formule Haversine en 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 est une fonction que j'ai créé sur mesure, son est un simple 1 doublure de "Math.PI * angle/180.0

My blog entry - SQL Haversine

-1

il suffit d'utiliser la formule de distance Sqrt((x2-x1)^2 + (y2-y1)^2)

1

ici est un violon pour trouver des endroits/endroits près de latitude/longitude par IP donnée:

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

Et est la fonction ici que j'utilise pour calculer la distance en ligne droite:

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

Renvoie la distance en kilomètres

0

ci-après le module (codé en f90) contenant trois formules discutées dans les réponses précédentes. Vous pouvez soit mettre ce module en haut de votre programme (avant PROGRAM PRINCIPAL) ou le compiler séparément et inclure le répertoire du module lors de la compilation.

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

Je suis fait à l'aide requête SQL

sélectionnez , (ACOS (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 Comme D à partir de table_name

Questions connexes