Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining cardinal (compass) direction between points

Is there a way to know in SQL Server 2008R2 if a point is at the south,east,etc...of another point?

For example, I have an origin point(lat1,lng1) and I want to know where point(lat2,lng2) is located from that origin: north, west,etc...

I'm trying to construct a wind rose graph and this might be useful to me.

like image 978
user1848515 Avatar asked Jun 12 '26 13:06

user1848515


2 Answers

I came up with a way of calculating the bearing using a fairly straightforward use of standard SQL functions.

The ATAN function does most of the real work; the two CASE statements are just special case corrections. 1 is the source and 2 is the destination.

atan(([Longitude2]-[Longitude1])/(10e-10+[Latitude2]-[Latitude1]))*360/pi()/2
+case when [Latitude2]<[Latitude1] then 180 else 0 end
+case when [Longitude2]<[Longitude1] and [Latitude2]>[Latitude1] then 360 else 0 end
like image 88
David Robinson Avatar answered Jun 17 '26 23:06

David Robinson


In order to calculate the bearing between two coordinates while using the Geography type in SQL Server 2008 R2, you can use this function:

CREATE FUNCTION [dbo].[CalculateBearing] 
(
    @pointA as geography
    ,@pointB as geography
)

RETURNS decimal(18,12)

AS

    BEGIN

    -- Declare the return variable
    DECLARE @bearing decimal(18,12)

    -- Declare the local variables
    DECLARE @x decimal(18,12)
    DECLARE @y decimal(18,12)
    DECLARE @dLat decimal(18,12)
    DECLARE @dLong decimal(18,12)
    DECLARE @rLat1 decimal(18,12)
    DECLARE @rLat2 decimal(18,12)

    IF(@pointA.STIsEmpty() = 1 OR @pointB.STIsEmpty() = 1)
        set @bearing = null
    ELSE
        BEGIN

        -- Calculate delta between coordinates
        SET @dLat = RADIANS(@pointB.Lat - @pointA.Lat)
        SET @dLong = RADIANS(@pointB.Long - @pointA.Long)

        -- Calculate latitude as radians
        SET @rLat1 = RADIANS(@pointA.Lat)
        SET @rLat2 = RADIANS(@pointB.Lat)

        SET @y = SIN(@dLong)*COS(@rLat2)
        SET @x = COS(@rLat1)*SIN(@rLat2)-SIN(@rLat1)*COS(@rlat2)*COS(@dLong)

        IF (@x = 0 and @y = 0)
            SET @bearing = null
        ELSE
            BEGIN
                SET @bearing = CAST((DEGREES(ATN2(@y,@x)) + 360) as decimal(18,12)) % 360
            END
    END

    -- Return the result of the function
    RETURN @bearing

END

GO

And after this, you can use this function like this:

DECLARE @pointA as geography
DECLARE @pointB as geography

SET @pointA = geography::STGeomFromText('POINT(3 45)', 4326)
SET @pointB = geography::STGeomFromText('POINT(4 47)', 4326)

SELECT [dbo].[CalculateBearing](@pointA, @pointB)

UPDATE: Adding a schema

Bearing explanation

like image 43
Nicolas Boonaert Avatar answered Jun 17 '26 21:06

Nicolas Boonaert