确定两点之间的基准方向(罗盘方向)

3

在SQL Server 2008R2中,是否有一种方法可以知道一个点位于另一个点的南部、东部等位置?

例如,我有一个起点point(lat1,lng1),我想知道point(lat2,lng2)相对于该起点的位置:北、西等。

我正在尝试构建一张风向图,这可能对我很有用。


如果第二个点的经度大于第一个点,则第二个点在更北的位置,否则在更南的位置,如果第二个点的经度小于第一个点。 如果第二个点的纬度大于第一个点,则第二个点在更东的位置,否则在更西的位置,如果第二个点的纬度小于第一个点。 - elvis
这不正确。随着你向北移动,你的纬度而非经度会增加。经度测量东/西,纬度测量南/北。例如,一个纬度为44.810901的点比一个纬度为37.42227的点更靠北。 - Chris
5个回答

5

我想出了一种使用标准 SQL 函数相当简单的计算方位角的方法。 ATAN 函数完成了大部分实际工作;两个 CASE 语句只是特殊情况的修正。1 是源,2 是目的地。

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

比其他解决方案容易得多。运行良好。谢谢。 - user3308241
1
只有一个提示。在某些情况下,数字是正确的,但是为负数。我在查询中添加了abs()函数,结果似乎每次都是正确的。 - user3308241

4
为了在使用SQL Server 2008 R2中的地理类型计算两个坐标之间的方位角,您可以使用以下函数:
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

在此之后,您可以像这样使用此函数:

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)

更新: 添加模式

轴承解释


你好,感谢你的答复。但是我必须说我不知道如何阅读或理解结果。对于这些坐标,该函数返回数字18.795229754601,这代表什么意思呢?谢谢。 - user1848515
它给出了朝向北方的方向。因此,它是由北点A点B(NAB)描述的角度,因此如果您使用模90,您可以确定点B是否位于点A的北、东、南或西侧。 - Nicolas Boonaert

3
今天早上,我需要提供范围和基本方位给用户,以便在我们的系统中搜索附近的订单。我看到了尼古拉斯在这里提供的答案,并且它大部分满足了我的需求。我创建了第二个函数,使用尼古拉斯的函数为我的UI获取简写的基本方位(N,NE,E等)。
结合https://en.wikipedia.org/wiki/Points_of_the_compass提供的值,使用尼古拉斯提供的方位角计算来确定每个基本方位的范围。
CREATE FUNCTION [dbo].[CalculateCardinalDirection] 
(
    @pointA as geography
    ,@pointB as geography
)

RETURNS varchar(2)

AS
BEGIN
    DECLARE @bearing decimal(18,12)
    -- Bearing calculation provided by https://dev59.com/WG7Xa4cB1Zd3GeqPmidS#14781032
    SELECT @bearing = dbo.CalculateBearing(@pointA, @pointB)

    RETURN CASE WHEN @bearing BETWEEN 0 AND 22.5 THEN 'N'
                WHEN @bearing BETWEEN 22.5 AND 67.5 THEN 'NE'
                WHEN @bearing BETWEEN 67.5 AND 112.5 THEN 'E'
                WHEN @bearing BETWEEN 112.5 AND 157.5 THEN 'SE'
                WHEN @bearing BETWEEN 157.5 AND 202.5 THEN 'S'
                WHEN @bearing BETWEEN 202.5 AND 247.5 THEN 'SW'
                WHEN @bearing BETWEEN 247.5 AND 292.5 THEN 'W'
                WHEN @bearing BETWEEN 292.5 AND 337.5 THEN 'NW'
                ELSE 'N' -- Catches NULL bearings and the 337.5 to 360.0 range
           END
END
GO

很好,这很有用!我会更新我的代码,在一个项目中添加一列。谢谢。 - Nicolas Boonaert

0
如果点数据类型为“几何”(如UTM坐标系),则可以使用以下公式:
DEGREES(ATAN((X2-X1)/(Y2-Y1)))
+case when Y2<Y1 then 180 else 0 end
+case when Y2>Y1 and X2<X1 then 360 else 0 end

这里是更明确的架构:

The Azimuth of a line which connects two points


0

X=X2-X1Y=Y2-Y1。 这是一个公式,可以计算出从0度(正Y轴)开始顺时针旋转的方位角,单位为360度。

  f(X,Y)=180-90*(1+SIGN(Y))*(1-SIGN(X^2))-45*(2+SIGN(Y))*SIGN(X)-180/PI()*SIGN(Y*X)*ATAN((ABS(Y)-ABS(X))/(ABS(Y)+ABS(X)))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接