这是我很久以前写的一些东西,可能会让你朝着正确的方向前进。
虽然您要求使用 VB.Net,但您真正需要的是一个查询,该查询执行“Great Circle Distance”计算以确定由纬度和经度标识的两点之间的距离。
所以,做以下假设:
- 您的邮政编码数据位于一个表中。
- 所述表具有 lat 和 lon 属性,它们是邮政编码的近似质心
您可以使用 LINQ to SQL 查询,使用类似的方法生成所需的结果集
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 代码实现了这个——我不记得是从哪里来的。谷歌搜索应该可以让你到达那里。
第一个查询 (zipQry) 以度数和弧度返回起始邮政编码的纬度和经度。然后将这些结果用于执行第二个查询。
第二个查询中WHERE子句的第一部分:
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) _
只是缩小了要检查的邮政编码列表,使查询运行得更快。它在纬度和经度上添加了任意数量,这样您在搜索加利福尼亚州的半径时就不会检查俄亥俄州的所有邮政编码。其余的都是前面提到的大圆距离算法的一部分。
这本可以在一个查询中完成以提高效率,但当时我需要这种方式,现在我已经失去了原因。