risposta-alla-domanda-sullo-sviluppo-web-bd.com

Calcolo della distanza tra due punti (latitudine, longitudine)

Sto cercando di calcolare la distanza tra due posizioni su una mappa. Ho memorizzato nei miei dati: Longitudine, Latitudine, X POS, Y POS.

In precedenza ho utilizzato lo snippet di seguito.

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

Tuttavia, non mi fido dei dati che ne derivano, sembra dare risultati leggermente imprecisi.

Alcuni dati di esempio in caso di necessità

Latitude        Longitude     Distance 
53.429108       -2.500953     85.2981833133896

Qualcuno potrebbe darmi una mano con il mio codice, non mi dispiace se vuoi sistemare quello che ho già se avessi un nuovo modo di raggiungere questo sarebbe fantastico.

Indicare in quale unità di misura sono presenti i risultati.

77
Waller

Dato che stai usando SQL Server 2008, hai a disposizione il tipo di dati geography , progettato esattamente per questo tipo di dati:

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

SELECT @source.STDistance(@target)

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

(1 row(s) affected)

Dicendoci che è a circa 538 km da (vicino) Londra a (vicino) Edimburgo.

Naturalmente ci sarà una quantità di apprendimento da fare prima, ma una volta che lo saprai è molto più semplice che implementare il tuo calcolo Haversine; inoltre avrai MOLTE funzionalità.


Se vuoi conservare la tua struttura di dati esistente, puoi comunque usare STDistance, costruendo istanze geography appropriate usando il metodo 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 funzione seguente fornisce distanza tra due geocoordinati in miglia

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 funzione seguente fornisce distanza tra due geocoordinati in chilometri

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 funzione seguente fornisce distanza tra due geocoordinati in chilometri utilizzando Geografia tipo di dati introdotto in 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);

Uso:

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

Riferimento: Ref1 , Ref2

38
Durai Amuthan.H

Sembra che Microsoft abbia invaso il cervello di tutti gli altri intervistati e li abbia fatti scrivere soluzioni il più complicate possibile. Ecco il modo più semplice senza funzioni aggiuntive/dichiarazioni dichiarate:

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

Sostituisci semplicemente i tuoi dati anziché LATITUDE_1, LONGITUDE_1, LATITUDE_2, LONGITUDE_2 per esempio.:

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

Dato che stai usando SQL 2008 o versioni successive, ti consiglio di dare un'occhiata al tipo di dati GEOGRAFIA . SQL ha integrato il supporto per le query geospaziali.

per esempio. avresti una colonna nella tua tabella di tipo GEOGRAFIA che verrebbe popolata con una rappresentazione geospaziale delle coordinate (controlla il riferimento MSDN linkato sopra per esempi). Questo tipo di dati espone quindi metodi che consentono di eseguire un'intera serie di query geospaziali (ad es. Trovare la distanza tra 2 punti)

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

sage:

seleziona dbo.DistanceKM (37.848832506474, 37.848732506474, 27.83935546875, 27.83905546875)

scite:

0,02849639

È possibile modificare il parametro @R con float commentati.

4
Fatih K.

Oltre alle risposte precedenti, ecco un modo per calcolare la distanza all'interno di 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

Uso:

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

Anche le funzioni scalari funzionano ma sono molto inefficienti quando si elaborano grandi quantità di dati.

Spero che questo possa aiutare qualcuno.

1
Thurfir