如何根据纬度和经度搜索半径?

时间:2011-12-11 22:06:50

标签: c# asp.net linq-to-entities

我想根据指定半径的纬度和经度显示数据。

示例:

我有一张纬度为55.0628且经度为-162.3056且没有指定状态的记录。

如何只显示一个州内的记录,使用实体到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

3 个答案:

答案 0 :(得分:4)

我会尽可能接近实际数据执行查询(这可能意味着绕过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;

答案 1 :(得分:1)

要知道某个目的地位于一个给定的较大区域内,您不仅需要在较大区域中拥有一个点的坐标,而且还需要具有映射其整个边界的坐标。

如果您有这些数据,则会成为Point in Polygon问题。我发现光线跟踪很容易在SQL和C#中实现,所以一个很好的实现,你可以使Linq感知,虽然我只做Linq2SQL而不是Linq2Entities。

如果您只有中心点的坐标,则可以使用STDistance找到最接近的点。但是,这可能很容易错误地将较大状态边界附近的位置误识别为处于较小状态,因为它比较大状态更接近较小状态的中心。

如果您使用它,但是您没有使用SQL 2008(因此没有STDistance),您可以通过((lat1 - lat2) * (lat1 - lat2)) + ((lng1 - lng2) * (lng1 - lng2))订购来获得粗略的近似值。这给出了相对距离,好像世界真的像墨卡托投影所暗示的那样是一个矩形。赤道越远,不准确性就越差,因此对于美国各州来说可能是可以忍受的,但加拿大各省却失败了。

答案 2 :(得分:0)

正确而快速的方法是从你的lat-lon邮政编码对开始,找到给定距离(半径)的东,西,北和南点。关注this link以获取相关公式。然后使用这些点从数据库中获取邮政编码;类似的东西:

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

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