给定两个纬度/经度,我如何判断它们是不是在 1 英里范围内?

Posted

技术标签:

【中文标题】给定两个纬度/经度,我如何判断它们是不是在 1 英里范围内?【英文标题】:Given two lat/longs, how can I tell if they are within 1 mile of each other?给定两个纬度/经度,我如何判断它们是否在 1 英里范围内? 【发布时间】:2016-03-25 01:53:42 【问题描述】:

我正在尝试执行一种非常有效的检查,以查看两个点是否彼此相距一英里。

关心他们是否在一英里内 - 距离对我来说其他无关紧要。

由于关注范围狭窄,我在寻找通用的“how far apart are these points”函数。

我目前的方法是计算Haversine distance,然后检查它是否小于一英里。

在这种情况下效率很重要,因为我必须为大型记录集计算这个是/否标志。

那么,判断两个纬度/经度点是否相距一英里的最有效方法是什么?

我在 T-SQL 中做这个检查,这并不重要。 我目前的haversine计算如下。

CREATE FUNCTION dbo.USR_UFN_HAVERSINE_DISTANCE
(
  @LAT1 FLOAT(18)
 ,@LONG1 FLOAT(18)
 ,@LAT2 FLOAT(18)
 ,@LONG2 FLOAT(18)
 ,@UnitOfMeasure NVARCHAR(10) = 'KILOMETERS'
)
RETURNS FLOAT(18)
AS
BEGIN
  DECLARE
    @R FLOAT(8)
   ,@DLAT FLOAT(18)
   ,@DLON FLOAT(18)
   ,@A FLOAT(18)
   ,@C FLOAT(18)
   ,@D FLOAT(18)
   ;
  SET @R =
    CASE @UnitOfMeasure
      WHEN 'MILES'      THEN 3956.55 
      WHEN 'KILOMETERS' THEN 6367.45
      WHEN 'FEET'       THEN 20890584
      WHEN 'METERS'     THEN 6367450
      ELSE 6367.45  --km
    END
  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;

【问题讨论】:

Fastest Way to Find Distance Between Two Lat/Long Points的可能重复 @KenY-N 感谢您指点我。我已经有一个通用功能来获取两点之间的距离。因为在这种情况下,我只关心距离是否在一英里之内,我希望有一种更快的方法,而不必实际计算完整距离。我已经编辑了这个问题,试图让这种区别变得清晰。 检查该链接问题的第二个答案?似乎正在朝着你想要的方向发展...... 游戏将首先检查 x 1° 的纬度大约是 69 英里,所以如果 Abs( @Lat1 - @Lat2 ) > 1.0 / 69.0 则距离至少为一英里。 1°的经度因纬度而异,例如约 50 英里,纬度 45°。根据您的数据,可能值得检查,例如Abs( @Lat1 ) <= 45 and Abs( @Lat2 ) <= 45 and Abs( @Long1 - @Long2 ) >= 1.0 / 50.0 那么它将至少有一英里。根据数据中纬度的分布,您可以使用具有预先计算的经度距离的多个纬度。 (为我之前睡眠不足的 cmets 道歉。) 【参考方案1】:

由于您指定需要在大型数据集上运行它,我建议使用表值函数。如果您可以预先计算地理点,那就更好了,但这一切都是内联的。

create function dbo.fn_areWithinOneMile(@long1 float, @lat1 float, @long2 float, @lat2 float)
returns table
as
return

    select cast(
        case when 
            geography::Point(@lat1, @long1, 4236).STDistance(geography::Point(@lat2, @long2, 4236)) > 1609.34 then 0 
            else 1 
        end as bit) as [withinOneMile?]

go

with cte as (select * from (values
    (42, 42),
    (43, 43),
    (44, 44)
    ) as x(lat, long)
), j as (
    select long, lat, lag(long, 1) over (order by lat) as long2, lag(lat, 1) over (order by lat) as lat2
    from cte
)
select *
from j
cross apply dbo.fn_areWithinOneMile(long, lat, long2, lat2) as o
where long2 is not null;

【讨论】:

【参考方案2】:
DECLARE 
    @pt1 geography,
    @pt2 geography;

    SET @pt1 = geography::Point(45.65100, -120.34900, 4326);
    SET @pt2 = geography::Point(44.65100, -120.37654, 4326);

    SELECT @pt1.STDistance(@pt2);

-返回值以米为单位,但您可以通过更改 SRID 来指定返回值。

-这里提供了 SRID 列表

 Select * from sys.spatial_reference_systems

【讨论】:

以上是关于给定两个纬度/经度,我如何判断它们是不是在 1 英里范围内?的主要内容,如果未能解决你的问题,请参考以下文章

如何判断经纬度是不是准确

给定两个位置,如何从谷歌地图获取所有纬度和经度

给定经度和纬度,如何找到国家

如何获取给定纬度和经度的状态(没有地图显示并且需要存储)?

如何使用它们的经度和纬度值计算两个位置之间的距离

给定纬度/经度,说明坐标是不是在美国大陆内