Googleマップに多数のポリゴンがあります。
ここに私が興味を持っている問題があります:緯度、経度の点を考えると、この点があるすべてのポリゴンを決定する最良の方法は何ですか?
明らかな方法は、各ポリゴンに対して「ポリゴン内のポイント」アルゴリズムを繰り返し実行することですが、特に数千のポリゴンがある場合、そのようなクエリに答える効率的なアルゴリズムがあるのではないかと思いました。
Googleマップに多数のポリゴンがあります。
ここに私が興味を持っている問題があります:緯度、経度の点を考えると、この点があるすべてのポリゴンを決定する最良の方法は何ですか?
明らかな方法は、各ポリゴンに対して「ポリゴン内のポイント」アルゴリズムを繰り返し実行することですが、特に数千のポリゴンがある場合、そのようなクエリに答える効率的なアルゴリズムがあるのではないかと思いました。
回答:
ほとんどすべてのこのような質問と同様に、最適なアプローチは「ユースケース」と機能の表現方法に依存します。 ユースケースは通常、(a)各レイヤーにオブジェクトが多いか少ないか、および(b)レイヤーのいずれか(または両方)がいくつかのデータ構造を事前計算できるかどうかによって区別されます。つまり、どちらか一方または両方が十分に静的で不変であるかどうかにかかわらず、事前計算に投資する価値があります。
この場合、これにより次のシナリオが生成されます。通常、ポイントは動的です。つまり、事前に与えられていません。(事前に、または非常に大きなグループで利用可能な場合は、並べ替えに基づいたいくつかの最適化が利用可能になります。)Qをクエリポイントの数、Pを多角形の頂点の数とします。
(1)ポイントが少なく、toto内のポリゴン頂点が少ない。従来の回線突き刺しアルゴリズムなどのブルートフォース手順を使用します。適切な方法の場合、コストはO(P * Q)です。これは、ポイントをポリゴンエッジと比較するのにO(1)時間かかり、そのような比較をすべて行う必要があるためです。
(2)おそらく多くのポリゴン頂点がありますが、それらは動的です:クエリでポイントが使用されるたびに、ポリゴンがすべて変更されている可能性があります。再度、ブルートフォースアルゴリズムを使用します。コストはまだO(P * Q)であり、Pは大きくなるため大きくなりますが、それを助けることはできません。変更が小さいか、制御されている場合(たとえば、ポリゴンの形状がわずかに変化している、または単純にゆっくり動き回っている)、次のバージョンのソリューションを使用して、ポリゴンの変化に応じてデータ構造を更新する効率的な方法を見つけることができます。それはおそらく独創的な研究の問題でしょう。
(3)多くのポリゴン頂点と静的ポリゴン(つまり、ポリゴンレイヤーはほとんど変化しません)。検索をサポートするためにデータ構造を事前計算します(ラインスイープまたはクアッドツリーアルゴリズムに基づく場合があります)。これらのアルゴリズムの事前計算のコストはO(P * log(P))ですが、クエリのコストはO(Q * log(P))になるため、合計コストはO((P + Q)* log( P))。
次のような特別な場合にいくつかの改善が利用可能です
(a)すべての多角形は凸面です(多角形の前処理をより迅速に行うことができます)、
(b)すべてのポリゴンの内部は互いに素であり、その場合、それらの結合は単一のポリゴンであると考えることができます(これにより、三角測量に基づくアルゴリズムなどの簡単で効率的なアルゴリズムが可能になり、
(c)ほとんどのポリゴンはあまり曲がりくねっていません -つまり、バウンディングボックスの大部分を占めています-この場合、バウンディングボックスのみに基づいて初期テストを実行し、そのソリューションを改良できます。これは一般的な最適化です。
(d)ポイントの数が多い。 それらをソートすると、タイミングが改善される場合があります。たとえば、左から右へのラインスイープポイントインポリゴンアルゴリズムを実装する場合、最初の座標でポイントをソートし、ポリゴンエッジをスイープすると同時にポイントをスイープできるようにします。このような最適化が公開されたことを知りません。ただし、公開されているものの1つは、すべてのポイントとポリゴン頂点の結合の制約付き三角測量を実行することです。三角測量が完了すると、内部ポイントの特定が迅速になります。計算コストは、O(Q * log(Q)+(P + Q)* log(P + Q))としてスケーリングされます。
これは非常に簡単です。ポリゴンレイヤーをバイナリインジケーターラスタとして表示します(1 =ポリゴンの内側、0 =外側)。(これには、ラスタ値を内部/外部インジケータに変換するためにルックアップテーブルが必要になる場合があります。)各ポイントプローブは、ラスタセルにインデックスを付けてその値を読み取るためにO(1)を必要とします。総努力はO(Q)です。
素敵なハイブリッドソリューション多くの静的ベクトルポリゴン(上記のベクトルケース3)の場合、最初はおそらく粗い解像度でポリゴンをラスタライズし、今回はポリゴン境界の任意の部分と交差するセルを区別します(たとえば、値2を指定します) 。ラスタープローブ(コスト:O(1))を使用すると、通常、明確な回答が得られます(ポイントは内部または外部にあることがわかっています)が、不明確な回答が得られることもあります(ポイントは、少なくとも1つのエッジが通るセルに含まれます)パス)、この場合、より高価なO(log(P))ベクトルクエリが作成されます。この方法では、ラスターに追加のストレージコストがかかりますが、多くの場合、小さなラスター(1 MBで{0,1,2、null}値を格納する2000 x 2000ラスターが可能)でも計算時間に大きな利点があります。 。漸近的に、
PostGISのではST_Intersectsは最初の検索に使用するインデックスポイントは、ポリゴンのバウンディングボックス内にあるし、それが本当に多角形の内部にあるかどうかを確認するために再検査を行う場合。それは高速で、多くの場合非常に高速です。
PostGISにデータを保存している場合、データベースが計算を行うのに適切な場所であることは間違いありません。それ以外の場合は、ポリゴンを中間またはクライアントプログラムに送信する必要があります。つまり、それ自体は計算を行うよりもはるかに時間がかかり、関連するポリゴンを取得するだけです。
/ Nicklas