最近、4つの円(中点と半径)があり、これらの円の和集合の面積を計算する必要があるという問題に遭遇しました。
画像の例:
2つの円は非常に簡単です。
三角形内にない各円の面積の割合を計算してから、三角形の面積を計算できます。
しかし、2つ以上の円があるときに使用できる賢いアルゴリズムはありますか?
最近、4つの円(中点と半径)があり、これらの円の和集合の面積を計算する必要があるという問題に遭遇しました。
画像の例:
2つの円は非常に簡単です。
三角形内にない各円の面積の割合を計算してから、三角形の面積を計算できます。
しかし、2つ以上の円があるときに使用できる賢いアルゴリズムはありますか?
回答:
外周上のすべての円の交点を見つけます(たとえば、次の図のB、D、F、H)。それらを対応する円の中心と一緒に接続して、多角形を形成します。円の結合の面積は、ポリゴンの面積+連続する交点とそれらの間の円の中心によって定義される円スライスの面積です。また、穴も考慮する必要があります。
賢いアルゴリズムは確かにあると思いますが、ここでは、それを探す必要をなくすためのばかげたアルゴリズムを紹介します。
確かにそれは馬鹿げているが、:
Ants Aasmaの答えは基本的な考えを与えましたが、私はそれをもう少し具体的にしたいと思いました。以下の5つの円とそれらが分解された方法を見てください。
これらの3種類のドットを識別するのは簡単です。ここで、ノードが青いドットと内部が白の赤いドットであるグラフデータ構造を作成します。すべての円について、円の中央(青い点)とその各交点(白い点が内側にある赤い点)の間に境界を作成します。
これにより、サークルユニオンは、元のユニオン(つまり、パーティション)をペアで分離し、カバーする一連のポリゴン(青の影)と円形のパイ(緑の影)に分解されます。ここの各ピースは、面積を計算するのが簡単なものなので、ピースの面積を合計することによって、ユニオンの面積を計算できます。
前のソリューションとは異なるソリューションでは、四分木を使用して任意の精度で推定を生成できます。
これは、正方形が内側か外側か、または形状と交差するかがわかる場合は、どの形状の結合でも機能します。
各セルには、空、完全、部分のいずれかの状態があります。
アルゴリズムは、低解像度(たとえば、4つのセルが空としてマークされている)から始めて、四分木に円を「描く」ことにあります。各セルは次のいずれかです。
完了したら、面積の推定値を計算できます。完全なセルは下限を示し、空のセルは上限を示し、部分的なセルは最大面積エラーを示します。
エラーが大きすぎる場合は、適切な精度が得られるまで部分セルを調整します。
これは、多くの特殊なケースを処理する必要がある幾何学的な方法よりも実装が簡単だと思います。
交差する2つの円の場合のアプローチが大好きです-より複雑な例に、同じアプローチのわずかなバリエーションを使用する方法を次に示します。
多数の半重複円のアルゴリズムを一般化するためのより良い洞察を与えるかもしれません。
ここでの違いは、中心をリンクすることから始めることです(したがって、円が交差する場所の間ではなく、円の中心間に頂点があります)これにより、より一般化できると思います。
(実際には、モンテカルロ法が価値があるかもしれません)
(ソース:secretGeek.net)
うーん、非常に興味深い問題です。私のアプローチはおそらく次のようなものになるでしょう:
(これは、円形など、どのような形状にも当てはまります)
area(A∪B) = area(A) + area(B) - area(A∩B)
ここA ∪ B
で、AはユニオンBをA ∩ B
意味し、AはBと交差します(これは最初のステップから実行できます)。
(これは上記と同じですが、にA
置き換えられていますA∪B
)
area((A∪B)∪C) = area(A∪B) + area(C) - area((A∪B)∩C)
area(A∪B)
私たちがたどり着いたところ、そしてarea((A∪B)∩C)
見つけることができる場所:
area((A∪B)nC) = area((A∩C)∪(B∩C)) = area(A∩C) + area(A∩B) - area((A∩C)∩(B∩C)) = area(A∩C) + area(A∩B) - area(A∩B∩C)
ここでも上からエリア(A∩B∩C)を見つけることができます。
トリッキーなビットは最後のステップです。サークルが追加されるほど、複雑になります。有限のユニオンとの交差の領域を計算するための拡張があると思います。あるいは、再帰的にそれを計算できるかもしれません。
モンテカルロを使用して境界の面積を概算することに関しても、任意の数の円の交点を、正確に計算できる4つの円の交点に減らすことができると信じています(これを行う方法がわからない)しかしながら)。
おそらくこれを行うにはもっと良い方法があるでしょう-余分な円が追加されるごとに複雑さが大幅に(おそらく指数関数的にですが、わかりません)増加します。
私は重なり合った星のフィールドをシミュレートする問題に取り組んでいます。密集したフィールドの実際のディスク領域から真の星の数を推定しようとしています。私も厳密な形式分析でこれを実行できることを望んでいましたが、タスクのアルゴリズムを見つけることができませんでした。青色の背景に緑色の円盤としてスターフィールドを生成することで解決しました。その直径は確率アルゴリズムによって決定されました。単純なルーチンでそれらをペアにして、重複があるかどうかを確認できます(星のペアが黄色に変わります)。次に、色のピクセル数により、観測された領域が生成され、理論上の領域と比較されます。これにより、真のカウントの確率曲線が生成されます。ブルートフォースかもしれませんが、問題なく動作するようです。(ソース:2from.com)
実際に実装するのが簡単で、任意に小さなエラーを生成するように調整できるアルゴリズムは次のとおりです。
手順2と3は、計算幾何学からの標準の見つけやすいアルゴリズムを使用して実行できます。
明らかに、各近似ポリゴンに使用する辺が多ければ多いほど、正確な回答に近づきます。正確な答えの境界を取得するために、内接および外接ポリゴンを使用して概算できます。
パワーダイアグラムと呼ばれるものを使用して、この問題に対する効率的な解決策があります。ただし、これは非常に重い数学であり、私がオフハンドで取り組みたいものではありません。「簡単な」ソリューションについては、ラインスイープアルゴリズムを調べてください。ここでの基本的な原則は、図をストリップに分割することです。各ストリップの面積の計算は比較的簡単です。
そのため、こすり落とさずにすべての円を含む図で、円の上部、円の下部、または2つの円の交点のいずれかの位置に水平線を描画します。これらのストリップの内側では、計算する必要があるすべての領域が同じように見えます。2つの辺が円形のセグメントに置き換えられた「台形」です。したがって、そのような形状を計算する方法を理解できる場合は、すべての個々の形状に対してそれを実行し、それらを一緒に追加するだけです。この単純なアプローチの複雑さはO(N ^ 3)です。ここで、Nは図の円の数です。いくつかの巧妙なデータ構造の使用により、このラインスイープメソッドをO(N ^ 2 * log(N))に改善できますが、本当に必要でない限り、問題を起こす価値はないでしょう。
このリンクは役に立つかもしれません。しかし、決定的な答えはないようです。 Googleが答えます。3つの円のもう1つの参照は、春樹の定理です。そこにも紙があります。
解決しようとしている問題によっては、上限と下限を取得するのに十分な場合があります。上限は簡単で、すべての円の合計です。下限については、円が重ならないように単一の半径を選択できます。円が重ならないように、各円の最大の半径(実際の半径まで)を見つけやすくします。完全に重なっている円を削除することもかなり簡単です(そのような円はすべて| P_a-P_b | <= r_aを満たします)。ここで、P_aは円Aの中心、P_bは円Bの中心、r_aはAの半径です。 )そしてこれは上限と下限の両方を改善します。また、すべての円の合計ではなく、任意のペアでペア式を使用すると、より良い上限を得ることができます。「ベスト」を選ぶ良い方法があるかもしれません
上限と下限を考えると、モンテカルロアプローチをより適切に調整できるかもしれませんが、具体的なことは何も思い浮かびません。別のオプション(これもアプリケーションによって異なります)は、円をラスタライズしてピクセルをカウントすることです。基本的には、分布が固定されたモンテカルロアプローチです。
これは、複雑なn ^ 2log(n)のグリーンの定理を使用して解決できます。グリーンの定理に詳しくなく、詳しく知りたい場合は、カーンアカデミーのビデオとメモをご覧ください。しかし、私たちの問題のために、私の説明で十分だと思います。
写真が掲載できないので写真へのリンクは申し訳ありません。(評判が足りません)
私が入れた場合はLとMは、このような
次に、RHSは単純に領域Rの面積であり、閉じた積分またはLHSを解くことによって取得できます。これがまさに私たちがやろうとしていることです。
すべてのユニオンは、交差するこのようなばらばらの円のセットに分割できます。
したがって、パスに沿って反時計回りに積分すると領域の面積が得られ、時計回りに積分すると面積の負の値が得られます。そう
AreaOfUnion =(反時計回りの赤い弧に沿った積分+時計回りの青い弧に沿った積分)
しかし、クールなトリックは、各円について、他の円の内側にない円弧を統合する場合に必要な領域を取得することです。つまり、すべての赤の円弧に沿って反時計回りの方向で統合し、時計回りの方向に沿ってすべての青の円弧に沿って統合します。仕事完了!!!
円が他の円と交差しない場合でさえ、注意が必要です。
ここに私のC ++コードへのGitHubリンクがあります
(@Loadmasterによって提案された)ピクセルペインティングアプローチは、さまざまな点で数学的なソリューションより優れています。
ピクセルペインティングの欠点の1つは、ソリューションの精度が有限であることです。しかし、状況に応じて、より大きなまたはより小さなキャンバスにレンダリングするだけで調整できます。また、2Dレンダリングコード(多くの場合、デフォルトでオンになっている)でのアンチエイリアシングは、ピクセルレベルを超える精度をもたらすことにも注意してください。したがって、たとえば、100x100の図を同じ寸法のキャンバスにレンダリングすると、1 /(100 x 100 x 255)= .000039%の精度が得られると思います...これはおそらく「十分に良い」最も厳しい問題以外はすべて。
<p>Area computation of arbitrary figures as done thru pixel-painting, in which a complex shape is drawn into an HTML5 canvas and the area determined by comparing the number of white pixels found in the resulting bitmap. See javascript source for details.</p>
<canvas id="canvas" width="80" height="100"></canvas>
<p>Area = <span id="result"></span></p>
// Get HTML canvas element (and context) to draw into
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Lil' circle drawing utility
function circle(x,y,r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI*2);
ctx.fill();
}
// Clear canvas (to black)
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Fill shape (in white)
ctx.fillStyle = 'white';
circle(40, 50, 40);
circle(40, 10, 10);
circle(25, 15, 12);
circle(35, 90, 10);
// Get bitmap data
var id = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixels = id.data; // Flat array of RGBA bytes
// Determine area by counting the white pixels
for (var i = 0, area = 0; i < pixels.length; i += 4) {
area += pixels[i]; // Red channel (same as green and blue channels)
}
// Normalize by the max white value of 255
area /= 255;
// Output result
document.getElementById('result').innerHTML = area.toFixed(2);