Program Tip

두 지점 사이의 거리 계산 (위도, 경도)

programtip 2020. 10. 9. 12:18
반응형

두 지점 사이의 거리 계산 (위도, 경도)


지도에서 두 위치 사이의 거리를 계산하려고합니다. 경도, 위도, 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

아무도 내 코드로 나를 도울 수 있습니까?이를 달성하는 새로운 방법이 있다면 이미 가지고있는 것을 고치고 싶다면 괜찮습니다.

결과의 측정 단위를 명시하십시오.


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)

런던 (근처)에서 에든버러 (근처)까지 약 538km입니다.

당연히 먼저 배워야 할 것이 많 겠지만 일단 알게되면 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에 도입 된 Geography 데이터 형식을 사용하여 지리 좌표 사이의 거리를 킬로미터 단위로 제공 합니다.

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


It looks like Microsoft invaded brains of all other respondents and made them write as complicated solutions as possible. Here is the simplest way without any additional functions/declare statements:

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

Simply substitute your data instead of LATITUDE_1, LONGITUDE_1, LATITUDE_2, LONGITUDE_2 e.g.:

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

As you're using SQL 2008 or later, I'd recommend checking out the GEOGRAPHY data type. SQL has built in support for geospatial queries.

e.g. you'd have a column in your table of type GEOGRAPHY which would be populated with a geospatial representation of the coordinates (check out the MSDN reference linked above for examples). This datatype then exposes methods allowing you to perform a whole host of geospatial queries (e.g. finding the distance between 2 points)


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

Usage:

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

Outputs:

0,02849639

You can change @R parameter with commented floats.


In addition to the previous answers, here is a way to calculate the distance inside a 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)

Scalar functions also work but they are very inefficient when computing large amount of data.

I hope this might help someone.

참고URL : https://stackoverflow.com/questions/13026675/calculating-distance-between-two-points-latitude-longitude

반응형