これが私がかなり前に書いたもので、正しい方向にあなたを始めるかもしれません。
VB.Netを要求しているときに、本当に必要なのは、「GreatCircle」を実行するクエリです。距離 「緯度と経度で識別される2点間の距離を決定するための計算。
したがって、次の仮定を行います。
- 郵便番号データは1つのテーブルにあります。
- 上記のテーブルには、郵便番号のおおよその重心であるlatとlonの属性があります
このようなものを使用して目的の結果セットを生成するLINQtoSQLクエリを使用できます
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検索でそこにたどり着くはずです。
最初のクエリ(zipQry)は、開始郵便番号の緯度と経度を度とラジアンの両方で返します。これらの結果は、2番目のクエリを実行するために使用されます。
2番目のクエリの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) _
調査する郵便番号のリストを絞り込んだだけで、クエリの実行が大幅に高速化されます。カリフォルニアで半径を検索するときにオハイオ州のすべての郵便番号をチェックしないように、緯度と経度に任意の量を追加します。残りはすべて、前述の大圏距離アルゴリズムの一部です。
これは、効率を上げるために1つのクエリで実行できた可能性がありますが、当時はこの方法で必要だったため、理由がわかりませんでした。