且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

查找邮政编码指定距离内的所有邮政编码

更新时间:2022-02-04 23:12:28

这是我很久以前写的东西,可能会使您朝正确的方向前进.

Here's something I wrote quite a while back that may start you in the correct direction.

当您请求VB.Net时,您真正需要的是一个执行"好"的查询圆距离"计算,以确定经纬度标识的两个点之间的距离.

While you asked for VB.Net, what you really need is a query that does a "Great Circle Distance" calculation to determine the distance between two points identified by latitude and longitude.

因此,请进行以下假设:

So, making the following assumptions:

  1. 您的邮政编码数据在一个表中.
  2. 所说的表具有lat和lon的属性,它们是邮政编码的近似质心

您可以使用LINQ to SQL查询,并使用类似的方法生成所需的结果集

You could use a LINQ to SQL query that produces the desired result set using something like this

Const EARTH_RADIUS As Single = 3956.0883313286095
Dim radCvtFactor As Single = Math.PI / 180
Dim zipCodeRadius As Integer = <Your Radius Value>

Dim zipQry = From zc In db.ZipCodes 
             Where zc.Zip = "<Your Zip Code>" _
             Select zc.Latitude, 
                    zc.Longitude, 
                    ZipLatRads = RadCvtFactor * zc.Latitude, 
                    ZipLonRads = RadCvtFactor * zc.Longitude
Dim zipRslt = zipQry.SingleOrDefault()
If zipRslt IsNot Nothing Then
    Dim zcQry = From zc In db.ZipCodes _
                Where zc.Latitude >= (zipRslt.Latitude - 0.5) And zc.Latitude <= (zipRslt.Latitude + 0.5) _
                And zc.Longitude >= (zipRslt.Longitude - 0.5) And (zc.Longitude <= zipRslt.Longitude + 0.5) _
                And Math.Abs(EARTH_RADIUS * (2 * Math.Atan2(Math.Sqrt(Math.Pow(Math.Sin(((RadCvtFactor * zc.Latitude) - zipRslt.ZipLatRads) / 2), 2) + _
                Math.Cos(zipRslt.ZipLatRads) * Math.Cos(RadCvtFactor * zc.Latitude) * _
                Math.Pow(Math.Sin(((RadCvtFactor * zc.Longitude) - zipRslt.ZipLonRads) / 2), 2)), _
                Math.Sqrt(1 - Math.Pow(Math.Sin(((RadCvtFactor * zc.Latitude) - zipRslt.ZipLatRads) / 2), 2) + _
                Math.Cos(zipRslt.ZipLatRads) * Math.Cos(RadCvtFactor * zc.Latitude) * _
                Math.Pow(Math.Sin((RadCvtFactor * zc.Longitude) / 2), 2))))) <= zipCodeRadius _
                Select zc
End If

它看起来很复杂,因为确实如此. SO上有更聪明的人可以解释算法.我只是从在互联网上找到的一些SQL代码中实现了这一点-我不记得在哪里. Google搜索可以带您到达那里.

It looks complicated, because it is. There are far smarter people here on SO that can explain the algorithm. I merely implemented this from some SQL code I found on the internet - I can't recall from where. A Google search should get you there.

第一个查询(zipQry)以度和弧度返回起始邮政编码的纬度和经度.然后将这些结果用于执行第二个查询.

The first query (zipQry) returns the lat and lon of the starting zip code in both degrees and radians. These results are then used to execute the second query.

第二个查询中WHERE子句的第一部分:

The first part of the WHERE clause in the second query:

Where zc.Latitude >= (zipRslt.Latitude - 0.5) And zc.Latitude <= (zipRslt.Latitude + 0.5) _
And zc.Longitude >= (zipRslt.Longitude - 0.5) And (zc.Longitude <= zipRslt.Longitude + 0.5) _

只需缩小要检查的邮政编码列表,即可使查询运行得更快.它会向纬度和经度添加任意数量,以便在加利福尼亚搜索半径时不会检查俄亥俄州的所有邮政编码.其余都是上述大圆距离"算法的一部分.

Just narrowed down the list of zip codes to be examined, making the query run much faster. It adds an arbitrary amount to the lat and lon so that you're not checking all the zipcodes in Ohio when searching for a radius in California. The rest is all part of the aforementioned Great Circle Distance algorithm.

可能可以在一个查询中完成此操作,以提高效率,但当时我需要这种方式,原因现在就消失了.

This could probably have been done in one query for greater efficiency, but I needed it in this fashion at the time, the reasons now lost to me.