web-dev-qa-db-ja.com

2つのポリゴンを交差させる方法は?

これは自明ではないようですが(さまざまなフォーラムで非常に多くの質問が寄せられます)、より複雑なアルゴリズムの構成要素としてこれが絶対に必要です。

入力:2Dの2つのポリゴン(AとB)、それぞれエッジのリストとして与えられます[(x0, y0, x1, y2), ...]。ポイントはdoublesのペアで表されます。それらが時計回り、反時計回り、またはいずれかの方向に与えられているかどうかはわかりません。私doは、それらが必ずしも凸状であるとは限らないことを知っています。

出力:A、B、および交差するポリゴンABを表す3つのポリゴン。どちらも空の(?)ポリゴンである可能性があります。 null

最適化のヒント:これらのポリゴンは部屋と床の境界を表します。したがって、部屋の境界は、同じ平面上の別のフロアに属していない限り、通常はフロアの境界と完全に交差します(argh!)。

私は誰かがすでにc#でこれを行っており、この問題についてこれまでに見つけたことがかなり気が遠くなるので、彼らの戦略/コードを使用させてくれることを望んでいます。

[〜#〜]編集[〜#〜]:それで、私はこれをする見込みで気絶しているために完全に鶏ではないようです。これは特殊なケースであり、計算が簡単になる可能性があるため、ここで目的の出力を言い換えたいと思います。

出力:最初のポリゴンからすべての交差するビットを引いたもの、交差するポリゴン(複数形で問題ありません)。 2番目のポリゴンにはあまり興味がなく、最初のポリゴンとの交点だけに興味があります。

EDIT2:私は現在 GPC(General Polygon Clipper) ライブラリを使用しており、これを非常に簡単にしています!

30
Daren Thomas

あなたがすべきだと思うこと

あなたがそれを助けることができるならば、あなた自身でこれをしようとしないでください。代わりに、すでに存在する多くの利用可能なポリゴン交差アルゴリズムの1つを使用してください。

私は、デモコードの強度と、ほとんど/すべての奇妙なケースの処理について言及しているという事実に基づいて、次のコードベースを強く検討していました。商業的に使用する場合は、(あなた/あなたの会社が選択した)金額を寄付する必要がありますが、この種のコードの堅牢なバージョンを入手する価値はあります。

http://www.cs.man.ac.uk/~toby/gpc/

私が実際に行ったことは、Java2Dライブラリの一部であるポリゴン交差アルゴリズムを使用することでした。 MS独自のC#ライブラリで使用する類似のものを見つけることができるかもしれません。

他にもオプションがあります。 「ポリゴンクリッパー」または「ポリゴンクリッピング」を探してください。ポリゴンの交差を処理す​​るのと同じ基本的なアルゴリズムが、一般的なクリッピングの場合にも使用できる傾向があるためです。

実際にポリゴンクリッピングライブラリを作成したら、ポリゴンAからポリゴンBを減算して最初の出力を取得し、ポリゴンAとBを交差させて2番目の出力を取得する必要があります。

絶望的にマゾヒスティックなために、あなた自身を転がす方法

自分でローリングすることを検討していたとき、Weiler-Athertonアルゴリズムが一般的なポリゴンカットの可能性が最も高いことがわかりました。以下を参考にしました。

http://cs1.bradley.edu/public/jcm/weileratherton.html

http://en.wikipedia.org/wiki/Weiler-Atherton

彼らが言うように、詳細はここに含めるには密度が高すぎますが、今後数年間、Weiler-Athertonに関する参考資料を見つけることができることは間違いありません。基本的に、すべてのポイントを最終ポリゴンに入るポイントまたは最終ポリゴンから出るポイントに分割し、すべてのポイントからグラフを作成してから、適切な方向にグラフを歩いて、すべてのポリゴンピースを抽出します。欲しいです。 「入口」と「出口」のポリゴンを定義および処理する方法を変更することにより、いくつかの可能なポリゴン交差(AND、OR、XORなど)を実現できます。

実際にはかなり実装可能ですが、他の計算幾何学コードと同様に、悪魔は縮退しています。

10
jprete

Arash Partowの FastGEO ライブラリには、計算幾何学における多くの興味深いアルゴリズムの実装が含まれています。ポリゴン交差点もその1つです。 Pascalで書かれていますが、数学を実装しているだけなので、かなり読みやすくなっています。エッジを時計回りまたは反時計回りの順序にするために、エッジを少し前処理する必要があることに注意してください。

ETA:しかし、実際には、これを行う最善の方法はこれを行わないことです。任意のポリゴンの交差を含まない、問題にアプローチする別の方法を見つけてください。

17
David Seiler

.NET Frameworkでプログラミングしている場合は、 Microsoft SQL ServerシステムCLRタイプ として出荷された.NETアセンブリで使用可能なSqlGeometryクラスを確認することをお勧めします。

SqlGeometryクラスは STIntersection メソッドを提供します

SqlGeometry g1 = SqlGeometry.Parse("POLYGON ((...))");
SqlGeometry g2 = SqlGeometry.Parse("POLYGON ((...))");
SqlGeometry intersection = g1.STIntersection(g2);
12
mloskot

NetTopologySuite を確認するか、SQL Server2008とその空間ツールにインポートしてみることもできます。

2
oharab

ポリゴンは、点の順序付きリスト(P1、P2、...、Pn)によって完全に記述されます。エッジは(P1-P2)、(P2-P3)、...、(Pn-P1)です。オーバーラップする2つのポリゴンAとBがある場合、ポリゴンBで囲まれた領域内にあるポイントAn(ポリゴンAを説明するポイントのリストから)またはその逆になります(BのポイントはAにあります)。そのようなポイントが見つからない場合、ポリゴンはオーバーラップしません。そのような点が見つかった場合(つまりAi)、ポリゴンの隣接する点を確認しますA(i-1)およびA(i + 1)。領域の外側の点が見つかるまで繰り返します。すべてのポイントがチェックされます(最初のポリゴンは完全に2番目のポリゴン内にあります)。外側のポイントが見つかった場合は、交差点を計算できます。ポリゴンBの対応するエッジを見つけて、それに続いて役割を変更します。ポリゴンBのポリゴンA内にあります。このようにして、重なり合うポリゴンを表すポイントのリストを作成できます。必要に応じて、ポリゴンが同一であるかどうかを確認する必要があります(P1、P2、P3)===(P2、P3、P1 )。

これは単なるアイデアであり、おそらくもっと良い方法があります。実用的でテスト済みのソリューションを見つけた場合は、それを使用することをお勧めします...

ナロゼ

2
narozed

そのために、ArcObjects、TopologySuite、GEOS、OGRなどのGISツールを使用してみてください。これらのディストリビューションがすべて.netで利用できるかどうかはわかりませんが、すべて同じです。

2
George Silva

これ 学術論文 これを行う方法を説明します。

2
Charles Bretana

他の人のGPLC++コードをあえて見てみると、Inkscapeでどのようにそれを行っているかがわかります。

http://Bazaar.launchpad.net/~inkscape.dev/inkscape/trunk/view/head:/src/2geom/shape.cpp (126行目)

2
fortran

Clipperはオープンソースのフリーウェアポリゴンクリッピングライブラリ(DelphiおよびC++で記述)であり、まさにあなたが求めていることを実行します-- http:/ /sourceforge.net/projects/polyclipping/

私のテストでは、ClipperはGPCよりも大幅に高速であり、エラーが発生しにくいです(詳細な比較については、こちらをご覧ください http://www.angusj.com/delphi/clipper.php#features )。また、DelphiとC++の両方のソースコードがありますが、Clipperライブラリにはコンパイル済みのDLLも含まれているため、他の(Windows)言語でもクリッピング関数を非常に簡単に使用できます。

2
Angus Johnson