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

Я пытаюсь рассчитать расстояние между двумя позициями на карте. Я сохранил в своих данных: долготу, широту, 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

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

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

Ответ 1

Поскольку вы используете 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

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

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 с комментариями float.