web-dev-qa-db-ja.com

2Dポリゴンの面積を計算するにはどうすればよいですか?

自己交差しない2D空間内の一連のポイントを想定すると、結果のポリゴンの面積を決定する効率的な方法は何ですか?

補足として、これは宿題ではなく、コードを探していません。独自のメソッドを実装するために使用できる説明を探しています。点のリストから一連の三角形を引き出すことについての私の考えはありますが、私はおそらく捕まらない凸面と凹面の多角形に関する多くのエッジケースがあることを知っています。

74
Jason Z

標準的な方法 、知る限りです。基本的に、各頂点の外積を合計します。三角測量よりもはるかに簡単です。

Pythonコードは、(x、y)頂点座標のリストとして表されるポリゴンを与えられ、最後の頂点から最初の頂点まで暗黙的にラップします。

_def area(p):
    return 0.5 * abs(sum(x0*y1 - x1*y0
                         for ((x0, y0), (x1, y1)) in segments(p)))

def segments(p):
    return Zip(p, p[1:] + [p[0]])
_

David Lehaviのコメント:このアルゴリズムがなぜ機能するのかを言及する価値があります。これは、関数-yおよびxに対する Greenの定理 の適用です。 planimeter が機能する方法とまったく同じです。すなわち:

上記の式=
integral_over_perimeter(-y dx + x dy) =
integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
_2 Area_

100
Darius Bacon

クロス積は古典的です。

そのような計算が無数にある場合は、半分以下の乗算を必要とする次の最適化バージョンを試してください。

area = 0;
for( i = 0; i < N; i += 2 )
   area += x[i+1]*(y[i+2]-y[i]) + y[i+1]*(x[i]-x[i+2]);
area /= 2;

わかりやすくするために配列の添字を使用します。ポインターを使用する方が効率的です。優れたコンパイラーがあなたのためにそれをしますが。

ポリゴンは「閉じている」と見なされます。つまり、最初のポイントを下付き文字Nのポイントとしてコピーします。また、ポリゴンのポイント数が偶数であると想定します。 Nが偶数でない場合、最初のポイントの追加コピーを追加します。

このアルゴリズムは、古典的な外積アルゴリズムの2つの連続した反復を展開して組み合わせることによって得られます。

数値の精度に関して、2つのアルゴリズムがどのように比較されるかはよくわかりません。私の印象では、乗算は減算の精度の損失を回復する傾向があるため、上記のアルゴリズムは古典的なアルゴリズムよりも優れているということです。 GPUのようにフロートを使用するように制約されている場合、これは大きな違いを生む可能性があります。

編集: "三角形と多角形の面積2D&3D" は、さらに効率的な方法を説明しています

// "close" polygon
x[N] = x[0];
x[N+1] = x[1];
y[N] = y[0];
y[N+1] = y[1];

// compute area
area = 0;
for( size_t i = 1; i <= N; ++i )
  area += x[i]*( y[i+1] - y[i-1] );
area /= 2;
14
chmike

このページ は、式が

enter image description here

次のように簡略化できます。

enter image description here

いくつかの用語を書き出し、xiの一般的な要因に従ってそれらをグループ化する場合、等式を確認するのは難しくありません。

最終合計は、2nの代わりにn乗算のみを必要とするため、より効率的です。

def area(x, y):
    return abs(sum(x[i] * (y[i + 1] - y[i - 1]) for i in xrange(-1, len(x) - 1))) / 2.0

私はこの単純化をJoe Kingtonから学びました ここ


NumPyを使用している場合、このバージョンはより高速です(非常に小さなアレイを除くすべて)。

def area_np(x, y):        
    x = np.asanyarray(x)
    y = np.asanyarray(y)
    n = len(x)
    shift_up = np.arange(-n+1, 1)
    shift_down = np.arange(-1, n-1)    
    return (x * (y.take(shift_up) - y.take(shift_down))).sum() / 2.0
9
unutbu

他の制約のないポイントのセットは、必ずしもポリゴンを一意に定義するわけではありません。

だから、最初にこれらのポイントから構築するポリゴンを決定する必要があります-おそらく凸包? http://en.wikipedia.org/wiki/Convex_hull

次に、面積を三角測量して計算します。 http://www.mathopenref.com/polygonirregulararea.html

4
mbeckish

三角形の領域を拡大して三角形の領域を合計するために、凸多角形ORがある場合に機能します。

一般的な交差しないポリゴンの場合、ベクトル(基準点、点a)、(基準点、点b)の外積を合計する必要があります。ここで、aとbは互いに「隣接」しています。

順番にポリゴンを定義するポイントのリストがあると仮定します(ポイントiとi + 1の順番はポリゴンのラインを形成します):

Sum(外積((ポイント0、ポイントi)、(ポイント0、ポイントi + 1))i = 1からn-1.

その外積の大きさをとると、表面積が得られます。

これにより、適切な基準点を選択することを心配することなく、凹面ポリゴンを処理できます。多角形の内側にない三角形を生成する3つのポイントは、多角形の内側にある三角形の反対方向を指す外積を持つため、面積は正しく合計されます。

4
MSN

多角形の面積を計算するには

http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=geometry1#polygon_area

int cross(vct a,vct b,vct c)
{
    vct ab,bc;
    ab=b-a;
    bc=c-b;
    return ab.x*bc.y-ab.y*bc.x;
}    
double area(vct p[],int n)
{ 
    int ar=0;
    for(i=1;i+1<n;i++)
    {
        vct a=p[i]-p[0];
        vct b=p[i+1]-p[0];
        area+=cross(a,b);
    }
    return abs(area/2.0);
}    
3
Steve

または、等高線積分を行います。ストークスの定理により、面積積分を等高線積分として表すことができます。小さなガウス求積法とボブはあなたのおじです。

2
duffymo

三角形を合計するよりも、デカルト空間で台形を合計する方が優れています。

area = 0;
for (i = 0; i < n; i++) {
  i1 = (i + 1) % n;
  area += (vertex[i].y + vertex[i1].y) * (vertex[i1].x - vertex[i].x) / 2.0;
}
1
David Hanak

それを行う1つの方法は、 ポリゴンを三角形に分解する で、三角形の面積を計算し、合計をポリゴンの面積とすることです。

1
MattK
  1. 基点(最も凸の点)を設定します。これが三角形のピボットポイントになります。
  2. 基点以外の最も左の点(任意)を計算します。
  3. 左から2番目のポイントを計算して、三角形を完成させます。
  4. この三角形の領域を保存します。
  5. 反復ごとに1ポイント右にシフトします。
  6. 三角形の面積を合計します
1
Joe Phillips

Shoelace formula の実装はNumpyで行うことができます。これらの頂点を仮定:

import numpy as np
x = np.arange(0,1,0.001)
y = np.sqrt(1-x**2)

エリアを見つけるために次の関数を定義できます。

def PolyArea(x,y):
    return 0.5*np.abs(np.dot(x,np.roll(y,1))-np.dot(y,np.roll(x,1)))

そして結果を得る:

print PolyArea(x,y)
# 0.26353377782163534

ループを回避すると、この関数はPolygonAreaよりも約50倍高速になります。

%timeit PolyArea(x,y)
# 10000 loops, best of 3: 42 µs per loop
%timeit PolygonArea(Zip(x,y))
# 100 loops, best of 3: 2.09 ms per loop

注:別の question についてこの回答を書いたので、ソリューションの完全なリストを得るためにここでこれについて言及します。

1
Mahdi

言語に依存しないソリューション:

与えられた:ポリゴンは、常に重なり合わないn-2個の三角形で構成できます(n =ポイントの数OR辺)。1つの三角形= 3辺の多角形= 1つの三角形; 1つの正方形= 4両面ポリゴン= 2個の三角形;などad nauseam QED

したがって、三角形を「切り落とす」ことでポリゴンを減らすことができ、合計面積はこれらの三角形の面積の合計になります。一枚の紙とハサミで試してみてください。従う前にプロセスを視覚化するのが最善です。

ポリゴンパス内の連続する3つのポイントを取得し、これらのポイントで三角形を作成すると、3つのシナリオのうち1つだけになります。

  1. 結果の三角形は元のポリゴンの内側に完全に収まります
  2. 結果の三角形は元のポリゴンの完全に外側にあります
  3. 結果の三角形は元のポリゴンに部分的に含まれています

最初のオプション(完全に含まれる)に該当する場合にのみ関心があります。

これらのいずれかを見つけるたびに、それを切り取り、面積を計算し(ここでは簡単に説明できません)、辺が1つ少ない新しいポリゴンを作成します(この三角形が切り取られたポリゴンと同等)。三角形が1つだけになるまで。

プログラムでこれを実装する方法:

多角形の周りのパスを表す(連続した)ポイントの配列を作成します。ポイント0から開始します。ポイントx、x + 1、x + 2から(一度に1つずつ)三角形を作成して配列を実行します。各三角形をシェイプからエリアに変換し、ポリゴンから作成されたエリアと交差させます。結果の交差が元の三角形と同一である場合、その三角形は多角形に完全に含まれており、切り取ることができます。配列からx + 1を削除し、x = 0からやり直します。そうでない場合(三角形が[部分的または完全に]多角形の外側にある場合)、配列内の次のポイントx + 1に移動します。

さらに、マッピングとの統合を検討しており、ジオポイントから開始する場合は、ジオポイントからスクリーンポイントに最初に変換する必要があります。これには、地球の形状のモデリングと式を決定する必要があります(地球は球体と考える傾向がありますが、実際には、へこみのある不規則な卵形(卵形)です)。さらに詳しい情報のウィキのために、そこには多くのモデルがあります。重要な問題は、その領域を平面と見なすか、曲線と見なすかどうかです。一般に、点が最大で数km離れている「小さな」領域は、凸状ではなく平面状であると考えると、大きな誤差を生成しません。

1
user836725

私の傾向は、単純に三角形のスライスを開始することです。他の何かがひどく毛深いことを避けることができる方法がわかりません。

ポリゴンを構成する3つの連続したポイントを取ります。角度が180未満であることを確認します。これで、計算に問題のない新しい三角形ができました。多角形のポイントリストから中間ポイントを削除します。残り3点になるまで繰り返します。

0
Loren Pechtel

2Dポリゴンの面積を計算するための簡単な関数をいくつか紹介します。これは、凸ポリゴンと凹ポリゴンの両方で機能します。 ポリゴンを多数のサブトライアングルに単純に分割します。

//don't forget to include cmath for abs function
struct Point{
  double x;
  double y;
}
// cross_product
double cp(Point a, Point b){ //returns cross product
  return a.x*b.y-a.y*b.x;
}

double area(Point * vertices, int n){  //n is number of sides
  double sum=0.0;
  for(i=0; i<n; i++){
    sum+=cp(vertices[i], vertices[(i+1)%n]); //%n is for last triangle
  }
  return abs(sum)/2.0;
}
0
abe312

それを行うCの方法:

float areaForPoly(const int numVerts, const Point *verts)
{
    Point v2;
    float area = 0.0f;

    for (int i = 0; i<numVerts; i++){
        v2 = verts[(i + 1) % numVerts];
        area += verts[i].x*v2.y - verts[i].y*v2.x;
    }

    return area / 2.0f;
}
0
Joseph

Pythonコード

ここで説明されているとおり: http://www.wikihow.com/Calculate-the-Area-of-a-Polygon

パンダと

import pandas as pd

df = pd.DataFrame({'x': [10, 20, 20, 30, 20, 10, 0], 'y': [-10, -10, -10, 0, 10, 30, 20]})
df = df.append(df.loc[0])

first_product = (df['x'].shift(1) * df['y']).fillna(0).sum()
second_product = (df['y'].shift(1) * df['x']).fillna(0).sum()

(first_product - second_product) / 2
600
0
firelynx