如何计算二维多边形的面积?

时间:2009-01-16 18:18:08

标签: algorithm geometry 2d

假设2d空间中的一系列点不是自相交的,那么确定结果多边形面积的有效方法是什么?

作为旁注,这不是家庭作业,我不是在寻找代码。我正在寻找一个可以用来实现我自己的方法的描述。我有关于从点列表中拉出一系列三角形的想法,但我知道有一些关于凸多边形和凹多边形的边缘情况,我可能无法捕捉到。

16 个答案:

答案 0 :(得分:100)

这是the standard method,AFAIK。基本上将每个顶点周围的叉积相加。比三角测量简单得多。

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评论:值得一提的是为什么这个算法有效:它是Green's theorem的函数-y和x的应用;完全符合planimeter的工作方式。更具体地说:

以上公式=
 integral_over_perimeter(-y dx + x dy) =
 integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
 2 Area

答案 1 :(得分:14)

交叉产品是经典之作。

如果您要进行大量此类计算,请尝试以下需要减少一半乘法的优化版本:

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不均匀,则附加第一个点的附加副本。

通过展开和组合经典叉积算法的两个连续迭代来获得算法。

我不太确定两种算法在数值精度方面的比较。我的印象是上述算法优于经典算法,因为乘法往往会恢复减法精度的损失。当受限制使用浮动时,与GPU一样,这可以产生显着差异。

编辑:"Area of Triangles and Polygons 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;

答案 2 :(得分:8)

This page显示公式

enter image description here

可以简化为:

enter image description here

如果你写出一些术语并根据xi的共同因素对它们进行分组,那么平等就不难看出。

最终求和更有效,因为它只需要n次乘法而不是2n

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那里学到了这种简化,here


如果你有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

答案 3 :(得分:4)

没有任何其他约束的一组点不一定唯一地定义多边形。

所以,首先你必须决定从这些点构建多边形 - 也许是凸包? http://en.wikipedia.org/wiki/Convex_hull

然后三角测量并计算面积。 http://www.mathopenref.com/polygonirregulararea.html

答案 4 :(得分:4)

要扩展三角形和和三角形区域,如果您碰巧有一个凸多边形,或者您碰巧选择的点不会生成与多边形相交的每个其他点的线。

对于一般的非交叉多边形,您需要将向量(参考点,点a),(参考点,点b)的叉积相加,其中a和b是“下一个”。

假设您有一个按顺序定义多边形的点列表(顺序是点i和i + 1形成多边形的一行):

总和(叉积((点0,点i),(点0,点i + 1))i = 1到n - 1.

取出十字产品的大小,你就有了表面积。

这将处理凹多边形,而不必担心选择一个好的参考点;产生不在多边形内部的三角形的任何三个点将具有指向多边形内任何三角形的相反方向的叉积,因此区域可以正确求和。

答案 5 :(得分:3)

计算多边形的面积

  
    

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);
}    

答案 6 :(得分:2)

或者做一个轮廓积分。 Stokes定理允许您将区域积分表示为轮廓积分。有点高斯正交,鲍勃是你的叔叔。

答案 7 :(得分:1)

一种方法是decompose the polygon into triangles,计算三角形的面积,并将和作为多边形的面积。

答案 8 :(得分:1)

  1. 设置基点(最凸点)。这将是三角形的支点。
  2. 计算最左边的点(任意),而不是你的基点。
  3. 计算最左边第二个点以完成三角形。
  4. 保存这个三角区域。
  5. 每次迭代向右移动一个点。
  6. 对三角区域求和

答案 9 :(得分:1)

比求和三角形更好的是在笛卡尔空间中对梯形求和:

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;
}

答案 10 :(得分:1)

语言无关解决方案:

GIVEN:多边形总是可以由不重叠的n-2个三角形组成(n =点数或边数)。 1个三角形= 3个边多边形= 1个三角形; 1平方= 4边多边形= 2个三角形;等令人厌恶的QED

因此,可以通过“切掉”三角形来减少多边形,并且总面积将是这些三角形的面积之和。尝试使用一张纸和一把剪刀,最好是在跟踪之前将过程可视化。

如果你在多边形路径中取任何3个连续点并使用这些点创建一个三角形,那么你将只有三个可能场景中的一个:

  1. 生成的三角形完全位于原始多边形
  2. 生成的三角形完全在原始多边形之外
  3. 生成的三角形部分包含在原始多边形
  4. 我们只对第一个选项(完全包含)中的情况感兴趣。

    每当我们找到其中之一时,我们将其切掉,计算其面积(容易腻,不会在这里解释公式)并制作一个新的多边形,少一边(相当于多边形,这个三角形被切掉)。直到我们只剩下一个三角形。

    如何以编程方式实现:

    创建一个(连续)点数组,表示多边形的路径。从点0开始。从点x,x + 1和x + 2运行制作三角形(一次一个)的数组。将每个三角形从一个形状转换为一个区域,并将其与从多边形创建的区域相交。如果得到的交点与原始三角形相同,则所述三角形完全包含在多边形中并且可以被切断。从数组中删除x + 1并从x = 0重新开始。否则(如果三角形在[部分或完全]多边形之外),移动到数组中的下一个点x + 1。

    另外,如果您希望与地图集成并从地理点开始,则必须首先从地理点转换为屏幕点。这需要决定地球形状的建模和公式(虽然我们倾向于认为地球是一个球体,它实际上是一个不规则的卵形(蛋形),有凹痕)。有很多模型,进一步的信息维基。一个重要的问题是你是否会将该区域视为一个平面或弯曲。一般来说,如果考虑平面而不是凸面,那些点相距几公里的“小”区域不会产生明显的误差。

答案 11 :(得分:1)

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写了这个答案,我在这里只提一下这里有一个完整的解决方案列表。

答案 12 :(得分:0)

我倾向于简单地开始切掉三角形。我看不出有什么可以避免毛茸茸的毛茸茸。

取三个构成多边形的连续点。确保角度小于180.您现在有一个新的三角形,应该没有问题要计算,从多边形的点列表中删除中间点。重复,直到你只剩下三个点。

答案 13 :(得分:0)

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;
}

答案 14 :(得分:0)

  

我将给出一些简单的函数来计算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;
}

答案 15 :(得分:0)

Python代码

如下所述:http://www.wikihow.com/Calculate-the-Area-of-a-Polygon

使用pandas

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