不規則な形状の面積を計算する方法は?


17

面積を計算する必要があるループ線セグメントのコレクションによって定義された部屋オブジェクトがあります。クラスは次のように記述できます(擬似コードで)。

class Point {
    float x; 
    float y;
    ...
    float distanceFrom(Point p);
}

class Segment {
    Point start;
    Point end;
    ...
    float length();
}

class Room {
    List<Segment> walls;
    ...
    float area();
}

部屋の壁はどこでも交差することはできませんが、セグメントの端点と作成された「サブループ」も新しい部屋に分離されます。解は完全に正確である必要はなく(10%の誤差が許容されます)、あまり頻繁に計算されません(<1 / s)。


7
sのRoomリストをPoint含めてから、各ポイントを接続してセグメントを取得し、それをループバックする方が理にかなっています。それ以外の場合、現在の設定では、不正な値を取得することは非常に東です(閉じられていない部屋、壁が真ん中にある部屋など)。これが最良のオプションです。
MCMastery

別のオプションは、シェイプを上三角化して、各三角形の面積を計算することです。難しい部分は三角測量です。実行可能ですが、必ずしもきれいではありません。靴紐の答えはまだずっと良いです。
Draco18s

@MCMastery Roomsが常に完全である必要があるため、このソリューションは機能しません。s Roomを使用してsを作成するプレーヤーがある場合はそうではないかもしれませんSegment。また、クローズドルーム関数の定義は簡単です(Segmentsをループして、必ずルームを作成するようにしてください)。

回答:


31

ガウスの靴ひも式を使用できます:

すべてのポイントのx座標を取得し、それらに次のポイントのy座標を乗算し、次に現在のポイントのy座標に次のポイントのx座標を乗算して結果から減算し、それらを合計面積に追加する必要があります。すべてのポイントでこれを行った後、合計面積を半分にして、ポリゴンの実際の面積を取得します。現在のポイントが最後のポイントである場合、次が最初です。

A = 0

for (i = 0; i < points.length; i++) do

    A += points[i].x * points[(i + 1) % points.length].y - points[i].y * points[(i + 1) % points.length].x

end

A /= 2

2
私はいつもそれが2つのベクトルの外積は、それが靴紐アルゴリズムと呼ばれていた知らなかっ計算するために使用される
Sidar

3
これは、三角形でできた不規則な3Dオブジェクトの体積を計算するために拡張でき、微積分の基本定理の些細なケースと見なすことができることに注意してください。
ディートリッヒエップ

5
ここのエリアは署名されています。他の方向にポイントを通過すると、最終Aは無効になります。目標によっては、A = |A|が必要になる場合があります。負の市外局番では、点の内側と外側のリスト(逆順の1つ)を使用して、不規則なドーナツ上の領域を見つけることができます。
chux-モニカの復活

6
もちろん、ガウスまたはオイラーのいずれかに式があります。
corsiKa

0

モンテカルロ法も使用できます。

任意の形状の周りに長方形を描きます。均一に配布されたPRNGソースを取得します。その後、モジュロ関数を使用して、長方形のX、Yの長さで出力をバインドします。いいえを数えます シェイプの内側に着くランダムポイントの。生成されたポイントの合計量で割ります。その商に長方形の面積を掛けます。各反復で、真の領域に収束します。このアルゴリズムは途方もなく並列化可能であり、R ^ N座標が形状のR ^ N境界内にあるかどうかを判別できる限り、任意の寸法形状の「ボリューム」を計算するために使用できます。

ここで誰かがこの方法を使用して円領域を見つけ、それを使用してパイを計算しますhttps://www.youtube.com/watch?v=VJTFfIqO4TU


2
-1:モジュロを使用して範囲内に収めたくない、均一分布またはその他の分布を使用したい、モジュロ法を使用すると、あらゆる種類の統計上の問題が発生します。
user1997744

12
この方法は、単純なポリゴンではなく、フラクタルやメタボールのブロブのように境界を表現するのが難しい何らかの暗黙の形状を持っている場合に役立ちます。ただし、質問のようなポリゴンの場合、不必要に高価になるようです。
DMGregory

@DMGregoryが指摘したように、これは私が探していたものではありません。しかし、他の誰かがそれを必要とする場合には、+ 1に値すると思います。

これは興味深いですが、包含テストのコストは法外に高くならないでしょうか?つまり、このアプローチを保証するのに十分に複雑な形状を持っている場合、包含テストも非常に費用がかかるので、それらを大量に行いたくないでしょうか?(多角形を想定)
Mattia

Ok moduloは確かに問題がありますが、簡単な解決策です。本当に得られるのはランダムなP = 1/2ビット0/1なので、得られるのは数値の均一な分布です。0から7までの3ビットの場合、乱数が6または7の場合、rand%5を実行すると、1または2にマッピングされ、1,2の周波数が事実上増加して分布が不均一になります。それを避けるためには、マッピングを回転させるステートマシンのようなものが必要です。6,7は1,2にマップし、その後3,4にマップし、次に5,0にマップします。彼らが現れたときはいつでも6,7を捨てることもできます。とにかく、それはライブラリ実装の問題です。
FranG

-1

別のアプローチ:しないでください。

代わりに:

while (Segments.Count > 3)
{
    Segment A = Segments[Segments.Count - 2];
    Segment B = Segments[Segments.Count - 1];
    Segment C = new Segment(B.End, A.Start);
    Triangle T = new Triangle(A, B, C);
    Segments[Segments.Count - 2] = C;
    Segments.RemoveAt(Segments.Count - 1);
    if (B is inside the new shape Segments)
        Area -= T.Area;
    else
        Area += T.Area;
}
Area += new Triangle(Segments[0], Segments[1], Segments[2]).Area;

基本的に、三角形を切り落とします。三角形の面積は単純です。そのため、残りのセグメント数を1つ減らしました。残っているものが三角形になるまで繰り返します。


2
ガウスの靴ひも式は、計算の数を半分または3分の1に短縮したものです。それを解決します。
ピーターギアケンズ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.