简体   繁体   English

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

[英]How to search by radius based on latitude and longitude?

I want to show data based on latitude and longitude with specified radius. 我想基于指定半径的纬度和经度显示数据。

Example: 例:

I have a record with latitude 55.0628 and longitude -162.3056 without specified state. 我有一个北纬55.0628和经度-162.3056没有指定状态的记录。

How can I show only records that within one state, using entity to linq? 如何只显示一个州内的记录,使用实体到linq?

If I have state Florida to show just records that within Florida. 如果我有州佛罗里达州只显示佛罗里达州内的记录。

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

I would execute the query as close to the actual data as possible (which probably means circumventing LINQ and calling a stored procedure). 我会尽可能接近实际数据执行查询(这可能意味着绕过LINQ并调用存储过程)。

Here is a SQL user defined function that I use to calculate the distance between two locations. 这是一个SQL用户定义的函数,用于计算两个位置之间的距离。 It leverages the new geography functionality introduced in SQL Server 2008. 它利用了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

Function returns distance in miles and is very fast in my experience (this will obviously depend on how many comparisons you need to make). 函数以英里为单位返回距离并且在我的经验中非常快(这显然取决于您需要进行多少次比较)。

You could call it using something like: 您可以使用以下内容调用它:

DECLARE @StartingLatitude FLOAT, @StartingLongitude FLOAT;
DECLARE @MaxDistance FLOAT = 50;

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

To know a destination is within a given larger region, you need to not just have the coordinates of a point in the larger region, but coordinates that map out it's entire boundary. 要知道目标位于给定的较大区域内,您不仅需要在较大区域中具有点的坐标,而且还需要具有映射其整个边界的坐标。

If you have this data, it becomes a matter of the Point in Polygon problem. 如果您有这些数据,那就成了Point in Polygon问题。 I've found that ray-tracing was quite easy to implement in both SQL and C# so a nice one to have as a function that you make Linq-aware, though I only did it Linq2SQL not Linq2Entities. 我发现光线跟踪在SQL和C#中都很容易实现,所以一个很好的实现,你可以使Linq感知,虽然我只做了Linq2SQL而不是Linq2Entities。

If you only have the co-ordinates of central points, you can find the closest such point, using STDistance . 如果您只有中心点的坐标,则可以使用STDistance找到最接近的点。 This could though, easily mis-identify a location near the border of a larger state as being in the smaller state, because it is is close to the centre of the smaller state than the larger. 然而,这可能容易错误地将较大状态的边界附近的位置识别为处于较小状态,因为它比较大状态更接近较小状态的中心。

If you do go with that, but you aren't using SQL 2008 (so no STDistance) you can get a crude approximation by ordering on ((lat1 - lat2) * (lat1 - lat2)) + ((lng1 - lng2) * (lng1 - lng2)) . 如果你这样做,但你没有使用SQL 2008(所以没有STDistance)你可以通过排序((lat1 - lat2) * (lat1 - lat2)) + ((lng1 - lng2) * (lng1 - lng2))得到粗略的近似值((lat1 - lat2) * (lat1 - lat2)) + ((lng1 - lng2) * (lng1 - lng2)) This gives the relative distance as if the world really were a rectangle like the Mercator projection suggests. 这给出了相对距离,好像世界真的像墨卡托投影所暗示的那样是一个矩形。 The inaccuracy gets worse the further the points are from the equator, so it might be just about tolerable for US states, but fail with Canadian provinces. 赤道越远,不准确性就越差,因此对于美国各州来说可能是可以接受的,但加拿大各省却失败了。

The proper and fastest way is to start with your lat-lon pair of a zip code and find the East, West, North and South points for a given distance (radius). 正确和快速的方法是从您的lat-lon对邮政编码开始,找到给定距离(半径)的东,西,北和南点。 Follow this link for the relative formulas. 请点击此链接获取相关公式。 Then use these points to get zip codes from the database; 然后使用这些点从数据库中获取邮政编码; something like: 就像是:

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

Now having all zip records within the square defined by East, North, West and South points (as lines) proceed with distance calculations (use Tim's code) and keep only the records within the radius. 现在,在由东,北,西和南点(作为线)定义的正方形内的所有拉链记录进行距离计算(使用Tim的代码)并仅保留半径内的记录。 (If all points in the square where records, then something like 22% would be out of the radius). (如果广场上的所有点都有记录,那么22%的东西就会超出半径)。
Obviously if you use CTE you will perform the whole sql thing with only one query. 显然,如果你使用CTE,你将只用一个查询执行整个sql的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM