web-dev-qa-db-fra.com

Calcul de la distance entre deux points (latitude, longitude)

J'essaie de calculer la distance entre deux positions sur une carte. J'ai enregistré dans mes données: Longitude, Latitude, X POS, Y POS.

J'ai déjà utilisé l'extrait ci-dessous.

DECLARE @orig_lat DECIMAL
DECLARE @orig_lng DECIMAL
SET @orig_lat=53.381538 set @orig_lng=-1.463526
SELECT *,
    3956 * 2 * ASIN(
          SQRT( POWER(SIN((@orig_lat - abs(dest.Latitude)) * pi()/180 / 2), 2) 
              + COS(@orig_lng * pi()/180 ) * COS(abs(dest.Latitude) * pi()/180)  
              * POWER(SIN((@orig_lng - dest.Longitude) * pi()/180 / 2), 2) )) 
          AS distance
--INTO #includeDistances
FROM #orig dest

Cependant, je ne fais pas confiance aux données qui en résultent, cela semble donner des résultats légèrement inexacts.

Quelques exemples de données en cas de besoin

Latitude        Longitude     Distance 
53.429108       -2.500953     85.2981833133896

Quelqu'un pourrait-il m'aider avec mon code, cela ne me dérange pas si vous voulez réparer ce que j'ai déjà si vous avez un nouveau moyen d'y parvenir, ce serait génial.

Veuillez indiquer dans quelle unité de mesure vos résultats sont exprimés.

77
Waller

Puisque vous utilisez SQL Server 2008, vous disposez du type de données geography , qui est conçu pour ce type de données:

DECLARE @source geography = 'POINT(0 51.5)'
DECLARE @target geography = 'POINT(-3 56)'

SELECT @source.STDistance(@target)

Donne

----------------------
538404.100197555

(1 row(s) affected)

En nous disant que c'est environ 538 km de (proche) Londres à (près) Edimbourg.

Naturellement, vous devrez d'abord apprendre beaucoup de choses à faire, mais une fois que vous le savez, c'est beaucoup plus facile que de mettre en œuvre votre propre calcul Haversine; De plus, vous obtenez BEAUCOUP de fonctionnalités.


Si vous souhaitez conserver votre structure de données existante, vous pouvez toujours utiliser STDistance en construisant des instances appropriées de geography à l'aide de la méthode Point :

DECLARE @orig_lat DECIMAL(12, 9)
DECLARE @orig_lng DECIMAL(12, 9)
SET @orig_lat=53.381538 set @orig_lng=-1.463526

DECLARE @orig geography = geography::Point(@orig_lat, @orig_lng, 4326);

SELECT *,
    @orig.STDistance(geography::Point(dest.Latitude, dest.Longitude, 4326)) 
       AS distance
--INTO #includeDistances
FROM #orig dest
114
AakashM

La fonction ci-dessous donne distance entre deux coordonnées géographiques en miles

create function [dbo].[fnCalcDistanceMiles] (@Lat1 decimal(8,4), @Long1 decimal(8,4), @Lat2 decimal(8,4), @Long2 decimal(8,4))
returns decimal (8,4) as
begin
declare @d decimal(28,10)
-- Convert to radians
set @Lat1 = @Lat1 / 57.2958
set @Long1 = @Long1 / 57.2958
set @Lat2 = @Lat2 / 57.2958
set @Long2 = @Long2 / 57.2958
-- Calc distance
set @d = (Sin(@Lat1) * Sin(@Lat2)) + (Cos(@Lat1) * Cos(@Lat2) * Cos(@Long2 - @Long1))
-- Convert to miles
if @d <> 0
begin
set @d = 3958.75 * Atan(Sqrt(1 - power(@d, 2)) / @d);
end
return @d
end 

La fonction ci-dessous donne distance entre deux coordonnées géographiques en kilomètres

CREATE FUNCTION dbo.fnCalcDistanceKM(@lat1 FLOAT, @lat2 FLOAT, @lon1 FLOAT, @lon2 FLOAT)
RETURNS FLOAT 
AS
BEGIN

    RETURN ACOS(SIN(PI()*@lat1/180.0)*SIN(PI()*@lat2/180.0)+COS(PI()*@lat1/180.0)*COS(PI()*@lat2/180.0)*COS(PI()*@lon2/180.0-PI()*@lon1/180.0))*6371
END

La fonction ci-dessous donne distance entre deux coordonnées géographiques en kilomètres en utilisant Géographie type de données introduit dans SQL Server 2008

DECLARE @g geography;
DECLARE @h geography;
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326);
SET @h = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);
SELECT @g.STDistance(@h);

sage:

select [dbo].[fnCalcDistanceKM](13.077085,80.262675,13.065701,80.258916)

Référence:Ref1 , Ref2

38
Durai Amuthan.H

Il semble que Microsoft ait envahi le cerveau de tous les autres répondants et leur ait fait écrire des solutions aussi compliquées que possible. Voici le moyen le plus simple, sans aucune fonction/déclaration supplémentaire:

SELECT geography::Point(LATITUDE_1, LONGITUDE_1, 4326).STDistance(geography::Point(LATITUDE_2, LONGITUDE_2, 4326))

Remplacez simplement vos données au lieu de LATITUDE_1, LONGITUDE_1, LATITUDE_2, LONGITUDE_2 par exemple:

SELECT geography::Point(53.429108, -2.500953, 4326).STDistance(geography::Point(c.Latitude, c.Longitude, 4326))
from coordinates c
5
Stalinko

Si vous utilisez SQL 2008 ou une version ultérieure, je vous recommande de vérifier le type de données GEOGRAPHY . SQL prend en charge les requêtes géospatiales.

par exemple. vous auriez une colonne de type GEOGRAPHY dans votre table qui serait peuplée d'une représentation géospatiale des coordonnées (consultez la référence MSDN liée ci-dessus pour des exemples). Ce type de données expose ensuite des méthodes vous permettant d'effectuer toute une série de requêtes géospatiales (par exemple, déterminer la distance entre 2 points).

4
AdaTheDev
Create Function [dbo].[DistanceKM] 
( 
      @Lat1 Float(18),  
      @Lat2 Float(18), 
      @Long1 Float(18), 
      @Long2 Float(18)
)
Returns Float(18)
AS
Begin
      Declare @R Float(8); 
      Declare @dLat Float(18); 
      Declare @dLon Float(18); 
      Declare @a Float(18); 
      Declare @c Float(18); 
      Declare @d Float(18);
      Set @R =  6367.45
            --Miles 3956.55  
            --Kilometers 6367.45 
            --Feet 20890584 
            --Meters 6367450 


      Set @dLat = Radians(@lat2 - @lat1);
      Set @dLon = Radians(@long2 - @long1);
      Set @a = Sin(@dLat / 2)  
                 * Sin(@dLat / 2)  
                 + Cos(Radians(@lat1)) 
                 * Cos(Radians(@lat2))  
                 * Sin(@dLon / 2)  
                 * Sin(@dLon / 2); 
      Set @c = 2 * Asin(Min(Sqrt(@a))); 

      Set @d = @R * @c; 
      Return @d; 

End
GO

tilisation:

sélectionnez dbo.DistanceKM (37.848832506474, 37.848732506474, 27.83935546875, 27.83905546875)

Sorties:

0,02849639

Vous pouvez modifier le paramètre @R avec des flotteurs commentés.

4
Fatih K.

En plus des réponses précédentes, voici un moyen de calculer la distance à l’intérieur d’un SELECT:

CREATE FUNCTION Get_Distance
(   
    @La1 float , @Lo1 float , @La2 float, @Lo2 float
)
RETURNS TABLE 
AS
RETURN 
    -- Distance in Meters
    SELECT GEOGRAPHY::Point(@La1, @Lo1, 4326).STDistance(GEOGRAPHY::Point(@La2, @Lo2, 4326))
    AS Distance
GO

Usage:

select Distance
from Place P1,
     Place P2,
outer apply dbo.Get_Distance(P1.latitude, P1.longitude, P2.latitude, P2.longitude)

Les fonctions scalaires fonctionnent également, mais elles sont très inefficaces pour le traitement de grandes quantités de données.

J'espère que cela pourrait aider quelqu'un.

1
Thurfir