Расчет расстояния между двумя точками (широта, долгота)


Я пытаюсь вычислить расстояние между двумя позициями на карте. Я сохранил в своих данных: долгота, широта, X POS, Y POS.

Я ранее использовал приведенный ниже фрагмент.

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

однако я не доверяю данным, выходящим из этого, похоже, дает немного неточные результаты.

некоторые образцы данных в случае, если вам это нужно

Latitude        Longitude     Distance 
53.429108       -2.500953     85.2981833133896

может кто-нибудь помочь мне с моим код, я не возражаю, если вы хотите исправить то, что я уже есть, если у вас есть новый способ достижения этого, что было бы здорово.

пожалуйста, укажите, в какой единице измерения находятся ваши результаты.

6 67

6 ответов:

так как вы используете SQL Server 2008, у вас есть geography тип данных доступен, который предназначен именно для такого рода данных:

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

SELECT @source.STDistance(@target)

дает

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

(1 row(s) affected)

говорит нам, что это около 538 км от (рядом) Лондона до (рядом) Эдинбурга.

естественно, сначала будет много учиться, но как только вы это узнаете, это намного проще, чем реализовать свой собственный расчет Haversine; плюс вы получаете много функциональность.


если вы хотите сохранить существующую структуру данных, вы можете использовать STDistance, путем построения соответствующей geography экземпляров с помощью 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

ниже функция дает расстояние между двумя географические координаты в милях

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 

ниже функция дает расстояние между двумя географические координаты в километрах

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

ниже функция дает расстояние между двумя географические координаты в километрах используя география тип данных, который был введен в 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);

использование:

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

ссылки:машине ref1,Ref2

Как вы используете SQL 2008 или более поздней версии, я бы рекомендовал проверить география тип данных. SQL имеет встроенную поддержку геопространственных запросов.

например, у вас будет столбец в таблице типа GEOGRAPHY, который будет заполнен геопространственным представлением координат (см. ссылку MSDN, связанную выше для примеров). Этот тип данных затем предоставляет методы, позволяющие выполнять целый ряд геопространственных запросов (например, поиск расстояния между 2 точками)

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

использование:

выберите dbo.DistanceKM(37.848832506474, 37.848732506474, 27.83935546875, 27.83905546875)

выходы:

0,02849639

вы можете изменить параметр @R с помощью комментируемых поплавков.

в дополнение к предыдущим ответам, вот способ рассчитать расстояние внутри выбора:

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

использование:

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

Я надеюсь, что это может помочь кому-то.

похоже, что Microsoft вторглась в мозги всех других респондентов и заставила их писать как можно более сложные решения. Вот это самый простой способ без каких-либо дополнительных функций/операторов declare:

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

просто замените ваши данные вместо LATITUDE_1,LONGITUDE_1,LATITUDE_2,LONGITUDE_2 например:

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