2011-02-17 35 views
62

緯度+経度の場所のデータベース(たとえば、40.8120390、-73.4889650)を指定すると、特定の場所?指定された緯度経度の場所から特定の距離内のすべての緯度経度の場所を見つけるアルゴリズム

DBからすべての場所を選択し、開始位置から距離を取得して指定された距離以内にあるかどうかを確認するのは非常に効率的ではないようです。 DBから最初に選択した場所を絞り込む良い方法はありますか?一度狭くなった場所のセットを取得したら、それを1つずつ調べて距離を確認しますか、それとも良い方法がありますか?

私がこれを行う言語は、実際問題ではありません。ありがとう!

+4

これはあなたが必要なものかもしれません:http://en.wikipedia.org/wiki/K-d_tree – biziclop

+1

1つのSQLクエリで解決できませんでしたか? SELECT * FROM Places WHERE(Lat - :Lat)^ 2 +(Long - :Long)^ 2 <=:Distance^2(ofc、地球が球形であり、すべてがこれに該当します) – Dialecticus

+0

あなたはまだ@ valeraの答えを見つけましたか? –

答えて

1

あなたは、空間検索で必要なもの。 Solr Spatial searchを使用できます。また、緯度/経度データ型が組み込まれています(check here)。

+0

これは理論的に質問に答えるかもしれませんが、答えの本質的な部分をここに含め、参照のためのリンクを提供することが望ましいです(// meta.stackoverflow.com/q/8259)。 –

6

PostgreSQL GIS extensionsのように役立つ可能性があります。既に実装しようとしている機能の多くを実装している可能性があります。

34

まず、緯度間の距離を比較します。緯度はそれぞれ約69マイル(111キロメートル)離れています。範囲は、赤道で68.703マイル(110.567 km)から極で69.407(111.699 km)に変化します(地球のわずかに楕円形のため)。 2つの位置間の距離は、それらの緯度間の距離と等しいか、またはそれよりも大きくなります。

これは経度については当てはまりません。各経度の長さは緯度によって異なります。ただし、データがある地域(たとえば単一の国)に限定されている場合は、経度の最小値と最大値の境界も計算できます。


球面地球を想定し、低精度、高速距離計算意志続行:

座標を持つ2つの点間の大圏距離d {LAT1、lon1}及び{LAT2、lon2}は、で与えられます。 :

d = acos(sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2)) 

短い距離のための丸め誤差を受けにくい数学的に等価な式である:

Dはラジアン

distance_km ≈ radius_km * distance_radians ≈ 6371 * d 

における距離(6371キロがaverage radius of the earthある)

計算要件がmimimalあり、この方法です。しかし、結果は小距離では非常に正確です。


次に、特定の距離以内にある場合は、より正確な方法を使用してください。

GeographicLibは私が知っている最も正確な実装ですが、Vincenty inverse formulaも使用できます。


あなたがRDBMSを使用している場合は、プライマリキーとセカンダリキーとして経度緯度などを設定しました。上記のように緯度範囲または緯度/経度範囲を照会し、結果セットの正確な距離を計算します。

すべての主要なRDBMSの現代版は、地理​​的なデータ型とクエリをネイティブにサポートしています。

+0

ちょうど頭が上がって、最初のリンクが壊れています。 – kunruh

+0

@kunruh:ありがとう。このリンクは現在、オフラインになっているようなEd WilliamsのAviation Formularyを指していました。私はリンクを式に置き換えました。 –

2

biziclopが言及しているように、何らかの種類のメトリックスペースツリーがおそらく最良のオプションです。私はkd木とクワッドツリーを使ってこれらの種類の範囲クエリを実行した経験があり、驚くほど高速です。彼らはまた、書くのは難しいことではありません。これらの構造の1つを調べることをお勧めします。これは、他の興味深い質問に答えることもできます。「これは私のデータセットの最も近い点です。

+0

これは問題を解決するための貴重なヒントになるかもしれませんが、答えは本当に解決策を示す必要があります。あなたが意味することを示すサンプルコードを提供するために[編集]してください。代わりに、これをコメントとして書くことを検討してください。 –

+1

私は実際にはここのコードは気を散らすと思う - それは木構造と選択された特定の言語を含むライブラリにはあまりにも具体的なものになるだろう(この質問には言語でタグ付けされていないことに注意してください) – templatetypedef

4

は良い解決策のためにこれを試してみてください:Geolocation Search

+1

これは理論的に、ここの答えの本質的な部分を含めることが望ましいでしょう(// meta.stackoverflow.com/q/8259)。 –

0

あなたは距離を計算するためにあなたを助けるかもしれメトリック形式であるUTMフォーマットに緯度・経度を変換することができます。次に、ポイントが特定の場所に該当するかどうかを簡単に判断できます。

+0

これは問題を解決するための貴重なヒントになるかもしれませんが、答えは本当に解決策を示す必要があります。あなたが意味することを示すサンプルコードを提供するために[編集]してください。代わりに、これをコメントとして書くことを検討してください。 –

8

現在のユーザーの緯度、経度、および検索したい距離に基づいて、SQLクエリを以下に示します。

SELECT * FROM(
    SELECT *,(((acos(sin((@latitude*pi()/180)) * sin((Latitude*pi()/180))+cos((@latitude*pi()/180)) * cos((Latitude*pi()/180)) * cos(((@longitude - Longitude)*pi()/180))))*180/pi())*60*1.1515*1.609344) as distance FROM Distances) t 
WHERE distance <= @distance 

@latitudeと@litudeitudeは、ポイントの緯度と経度です。 緯度と経度は距離表の列です。 PIの値は7分の22

+0

ヨギング、あなたは伝説です! – Illuminati

3

Tank's Yogihosting

私はオープン・ストリープ地図から自分のデータベース内のテーブルの1 goupsを持っていると私は成功したテストです。

距離はメートル単位で問題なく動作します。

SET @orig_lat=-8.116137; 
SET @orig_lon=-34.897488; 
SET @dist=1000; 

SELECT *,(((acos(sin((@orig_lat*pi()/180)) * sin((dest.latitude*pi()/180))+cos((@orig_lat*pi()/180))*cos((dest.latitude*pi()/180))*cos(((@orig_lon-dest.longitude)*pi()/180))))*180/pi())*60*1.1515*1609.344) as distance FROM nodes AS dest HAVING distance < @dist ORDER BY distance ASC LIMIT 100; 
+0

世界は球ではありません! –

+0

あなたの提案は何ですか? –

-2

あなたはこの方程式 を確認することができ、私はそれが

SELECT id, (3959 * acos(cos(radians(37)) * cos(radians(lat)) * cos(radians(lng) - radians(-122)) + sin(radians(37)) * sin(radians(lat)))) AS distance FROM markers HAVING distance < 25 ORDER BY distance LIMIT 0 , 20; 
+0

このコードは問題を解決するのに役立つかもしれませんが、質問に答える_why_および/または_how_を説明しません。この追加の文脈を提供することは、長期的な教育的価値を大幅に改善するだろう。どのような制限や仮定が適用されるかなど、あなたの答えを解説してください。特に、魔法の値3959と37はどこから来たのでしょうか? –

0

あなたは、任意の言語が受け入れ可能であると言うので、自然な選択は、PostGISのある役立つと思う:あなたの場合は

SELECT * FROM places 
WHERE ST_DistanceSpheroid(geom, $location, $spheroid) < $max_metres; 

をWGSデータを使用したい場合は、$spheroid'SPHEROID["WGS 84",6378137,298.257223563]'

012に設定する必要があります

placesのインデックスがgeomの列であると仮定すると、これはかなり効率的です。

関連する問題