方向が不明な場合の線の結合


8

私はこの問題に苦労しています。複数のセグメントで構成されるポリラインがあります。各セグメントはポイントで構成され、各ポイントは3D空間で座標と標高によって識別されます。一緒にプロットすると、セグメントは多かれ少なかれ連続した線を構成します(セグメント間に切れ目がある可能性があります)が、セグメント自体は連続しておらず、すべてのセグメントの点が同じ移動方向に従っていない。
問題は、ポイント間の距離とラインの全長を測定できるように、これらの非連続セグメントから単一のラインをPythonを使用してできればどのように作成できるかです。
行の最初のセグメントか最後のセグメントかはわかりませんが、どういうわけか、それらを正しい順序で配置し、すべてが同じ方向を指していることを確認して、測定できるようにする必要があります。
助けてくれてありがとう 追加の情報やデータなどを提供させていただきます。実際のpythonコードを要求するのではなく(拒否するわけではありません...)、戦略だけを強調します。ボブ


ポリラインのセグメントは他のセグメントと交差していますか?その場合、これらの交差点でセグメントを分割する必要がありますか?
カークカイケンダル

回答:


6

セグメントは、それらがノードの役割を果たす抽象的なグラフGを形成するために使用できます。ポイントPからポイントQ、PQへのセグメント(アーク)であるノードを考えます。RをPの他のすべてのセグメントエンドポイントの中で最も近いエンドポイントとし、SをRのセグメントの他のエンドポイントとします。 次に、GにはノードPQからノードRSへのエッジが含まれており、このエッジにポイントPおよびRのラベルを付けます。

成功する場合、Gは線形グラフまたは単一サイクルのいずれかです。エッジを作成するときにノードの次数を保存することで、どちらがどれであるかを検出できます。(ノードの次数は、そのノードから発生するエッジをカウントします。)ノードのうちの2つを除くすべてのノードは、次数2でなければなりません。他の2つは両方とも次数2(サイクルの場合)または次数1を持っている必要があります。ポリラインの端。最初のケースでは、任意のノードを選択してポリラインの作成を開始します。2番目のケースでは、次数1のいずれかを選択します。他の次数の組み合わせはエラーになります。

ポリラインは開始ノード(円弧)に初期化されます。エッジの一つを見ては、電子、このノードに入射する:そのほかのノードは、次の処理にどのアークがわかりますし、そのラベルは、これらの弧の頂点が参加しているかを示します。(同じ座標がない場合は、頂点を新しい線分セグメントに結合します。)この方法で成長するポリラインを更新し、同時に、グラフGからエッジeを削除します。エラーが発生するまで(およびエッジが非分岐接続ポリラインを形成しないことを報告するまで)、またはすべてのエッジが削除されるまで続行します。エラーが発生しない場合は、作成したポリラインを出力します。

弧のスケッチ

この図では、弧はAB、CD、EF、FGです。したがって、グラフのノードは{AB、CD、EF、FG}です。エッジはAB--CD(BおよびCのラベルが付いている)、CD-EF(EおよびFのラベルが付いている)、およびEF--FG(FおよびFのラベルが付いている)です。ABとFGの次数は1ですが、CDとEFの次数は2です。抽象グラフとそのエッジラベルの概略は次のとおりです。

グラフ

次数1のノードの1つであるFGから始めましょう。次数が1であるため、それに接続された一意のエッジEF--FGがあり、Fのラベルが付いています。ポリラインを弧G-> Fで初期化します。ラベルはGFとEFの共通のエンドポイントを指定しているため、新しい接続を作成する必要はありません。グラフからエッジEF--FGを削除し、G-> F-> Eを介してEFでポリラインを延長します。

このエッジの削除により、EFの度合いが2から1に減り、EとDのラベルが付いた円弧CDへの単一のエッジが残ります。これにより、ポリラインをEからD(そこに新しいラインセグメント)まで延長し、そこからポリラインを延長するように指示します。アークCD:G-> F-> E-> D-> C。同様に、エッジED--CDを削除した後、ポリラインをさらに最終フォームG-> F-> E-> D-> C-> B-> Aに延長します。すべてのエッジがグラフから削除されたため、停止しました。これは、手順が成功したことを示しています。


Whuberさん、ありがとうございます。私はあなたの提案を評価するために少し時間が必要になりますが、私はすでにいくつかの質問があります:あなたは「Rを最も近いエンドポイントにしよう」と言います。これが問題の核心だと私は信じています。セグメント間には、x、y、およびz座標の3つの潜在的な接触点があります。ラインが完全にフラットである可能性があるためにZ座標を削除しても、2つの選択肢が残ります。ソリューションは(Pythonで)プログラムする必要があることに注意してください。視覚的な選択はできません。

私の現在の考えは、Matplotlibを使用して、シーケンスに関係なくセグメントをプロットすることです。これにより、ラインが作成されますが、ポイントを再作成する必要があります。どうやって?

@Bob最も近いポイントを見つけることは、比較的単純なGIS操作です(3Dでも)。各セグメントPQには2つのエンドポイントPとQがあります。まず、すべてのセグメントのエンドポイントのコレクション(PQ自体は含まない)の中でPに最も近い点を見つけます。これは、いくつかの異なるセグメントRSのエンドポイントRです。PおよびRでラベル付けされたエッジPQ-> RSを作成します。端点Qを基準にして検索を繰り返し、他のエッジを取得します。私が気づかなかったことの1つ:許容しきい値が必要です。最も近い点が許容値より大きい場合、最も近い点はないと結論付けます。
whuber

手順全体の実際の難しさは、互いに素なセグメントを接続すると、小さな自己交差が作成される可能性があることです(セグメントのエンドポイントが正確に一致しない理由と方法によって異なります)。これは一般に修正するのが面倒です。このような問題が発生した場合は、ポリラインをクリーンアップして、このような欠陥を取り除くことを検討してください。
whuber

3

whuberの回答に続いて、Pythonでこれを行う場合は、グラフ、ノード、エッジに関連するあらゆる種類の機能を備えたNetworkXライブラリご覧ください。whuberが記述していることを実装しているのはTraversal関数だと思います。また、基本的な描画機能も含まれています。

ライン注文を取得したら、Shapelyでジオメトリを簡単に構築して、さらにGISタイプの分析を行ったり、MatPlotLibに表示したり、GeoJSONにエクスポートしたりできます。


2

各開始セグメントと終了セグメントの間の距離を計算し、それらの間の距離が最も短いものを結合しますか?


私もそう思いました。それが一般的な解決策として機能するかどうかはわかりません。
George Silva

@ジョージあなたは正しいです。@nathanvdaの投稿へのコメントで説明したのと同様の状況で問題が発生します。すべてのソリューションでエンドポイントからエンドポイントまでの距離を使用したい。@johanvdwの提案は、距離がこの意味で理解されている場合に実装できます。これは、ポイントのコレクションのユークリッド最小全域木を構築するための標準的な手法に似ています。
whuber

あなたが正しいです。私は開始を意味し、ノードのエンドへのノードの代わりに、セグメントを。
johanvdw 2011

それは確かに私が同様に
言っ

1

多くのセグメントがあり、特定の順序や向きはありません。実際に接触または重複しているのがどれで、どちらが単に近いかはわかりません。

各セグメントでは、開始と終了のみが重要です。目標は、1つの大きなポリラインを作成することです。そのポリラインの方向は重要ではないと思います。

その場合、セグメントのセット/配列を作成します。最初のセグメントから始めます。これは完全にランダムです。

擬似コードで次のようなことをしてください

all_segments = set of all segments

# take the first segment out of set
new_polyline = all_segments.pop

until all_segments.empty?
  start_segm = find_segment_closest_to(new_polyline.start_point)
  remove_from_all_segments(start_segm)
  expand_polyline_at_begin(new_polyline, start_segm) 
  end_segm = find_segment_closest_to(new_polyline.end_point)
  expand_polyline_at_end(new_polyline, end_segm)
  remove_from_all_segments(end_segm)
end

そんな感じ?それは非常に高いレベルです。境界ケースを処理する必要があります。私はあなたが知っているか、可能な限り最大のギャップ/距離を知っていると思います、何故か見つけられたポイントを除外することができる必要があるからです:最も近い可能なポイントがオプションではないよりもポリラインの反対側にある場合:)これを処理する最も簡単な方法は、最大ギャップ距離を定義することです。これにより、各セグメントについて調べる必要があるポイントの数も制限されます。

[編集:詳細をfind_segment_closes_to]

クローズセグメントを見つける方法を完全に明確にするために、最初に非常に大まかなアプローチを記述します。

def find_segment_closes_to(point)
  closest_point = nothing
  closest_distance = MAX_GAP_RANGE
  all_segments.each do |segment|
    if distance(segment.end_point, point) < closest_distance
      closest_point = segment.end_point
      closest_segment = segment
      closest_distance = distance(segment.end_point, point)
   else if distance(segment.start_point, point) < closest_distance
      closest_point = segment.start_point
      closest_segment = segment
      closest_distance = distance(segment.start_point, point)
    end       
  end  
  # the closest segment
  return closest_segment
end     

これは非常に大雑把なアプローチであり、すべてのセグメントを反復処理し、最も近い各エンドポイントをチェックします。

理想的には、範囲内にあるすべての始点と終点を要求し、それらの中から最も近い点のみを見つけることができるいくつかのデータ構造があるでしょう。

それは役に立ちますか?それがあなたが始められることを願っています。


1
「find_segment_closest_to」は、場合によっては誤った結果を生成します。ほぼ閉じているが、完全ではないポリラインを想像してください。このポリラインの1つの頂点は、別のセグメントの中央に非常に近い可能性がありますが、そのセグメントに接続してはなりません。 これが、正しいアルゴリズムがポイントツーセグメント比較ではなくポイントツーポイント比較に依存している理由です。
whuber

はい、確かに:セグメントの始点と終点のみを確認する必要があります。多分あなたはあなたの解決策でほとんど同じことを言ったかもしれませんが、私は読んで理解するのが非常に難しいと思いました。
nathanvda

アルゴリズムに関する文献を読みたい場合は、グラフ理論の言語と基本技術を理解することが不可欠です。
whuber

@whuber先端をありがとう。それを調べます。
nathanvda
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.