如何基于经纬度的半径搜索

本文关键字:搜索 何基于 经纬度 | 更新日期: 2023-09-27 18:17:26

我想显示基于指定半径的经纬度的数据。

的例子:

我有一条记录,纬度55.0628,经度-162.3056,没有指定状态。

如何使用entity to linq只显示一个状态内的记录?

如果我有佛罗里达州来显示在佛罗里达州内的记录

Table Data
id            item             latitude                 longitude
1             townhome          55.0628                 -162.3056

Table postal codes
id               state                 city            latitude            longitude
1                alaska                Akutan          54.143              -165.7854
2                Alabama               Huntsville      34.7448             -86.6704

如何基于经纬度的半径搜索

我将尽可能接近实际数据执行查询(这可能意味着绕过LINQ并调用存储过程)。

下面是一个SQL用户定义的函数,我用它来计算两个位置之间的距离。它利用了SQL Server 2008中引入的新的地理功能。
CREATE FUNCTION [dbo].[GetDistanceBetween]
(
    @Lat1 float,
    @Long1 float,
    @Lat2 float,
    @Long2 float
)
RETURNS float
AS
BEGIN
    DECLARE @RetVal float;
    SET @RetVal = ( SELECT geography::Point(@Lat1, @Long1, 4326).STDistance(geography::Point(@Lat2, @Long2, 4326)) / 1609.344 );
RETURN @RetVal;
END

函数以英里为单位返回距离,并且在我的经验中非常快(这显然取决于需要进行多少次比较)。

你可以这样称呼它:

DECLARE @StartingLatitude FLOAT, @StartingLongitude FLOAT;
DECLARE @MaxDistance FLOAT = 50;
SELECT * FROM PostalCodes 
WHERE dbo.GetDistanceBetween(@StartingLatitude, @StartingLongitude, latitude, longitude) <= @MaxDistance;

要知道一个目的地在一个给定的更大的区域内,你不仅需要有大区域中一个点的坐标,还需要有映射出它的整个边界的坐标。

如果你有这些数据,它就变成了多边形中的点问题。我发现光线追踪在SQL和c#中都很容易实现,所以这是一个很好的函数,你可以让linq感知,尽管我只做了Linq2SQL而不是Linq2Entities。

如果你只有中心点的坐标,你可以用STDistance找到最近的中心点。然而,这很容易将靠近较大国家边界的位置误认为是较小国家的位置,因为它比较大国家更靠近较小国家的中心。

如果你这样做,但你没有使用SQL 2008(所以没有STDistance),你可以通过在((lat1 - lat2) * (lat1 - lat2)) + ((lng1 - lng2) * (lng1 - lng2))上排序得到一个粗略的近似值。这给出了相对距离,就好像世界真的是一个矩形,就像墨卡托投影所显示的那样。距离赤道越远,不准确性就越差,所以对于美国各州来说,这可能还可以忍受,但对于加拿大各省来说,这就不合适了。

正确和最快的方法是从邮政编码的纵向配对开始,找到给定距离(半径)的东、西、北、南点。点击此链接获取相关公式。然后使用这些点从数据库中获取邮政编码;比如:

select *
from zipcodes
where
    lat >= South
    and lat <= North
    and lon >= West
    and lon <= East
    -- and state = 'FL' -- use it optionally

现在在由东、北、西和南点(作为线)定义的正方形内拥有所有zip记录,继续进行距离计算(使用Tim的代码),并仅保留半径内的记录。(如果正方形中的所有点都有记录,那么大约22%的点将超出半径)。显然,如果您使用CTE,您将只使用一个查询来执行整个sql操作。