值得注意的是,这不是作业,我也不在寻找代码。我希望找到一种方法的描述,以便能实现自己的方法。我有一些想法,比如从点集合中获取三角形序列,但是我知道对于凸多边形和凹多边形之类的特殊情况可能会出现问题。
这是我所知道的标准方法,在这里可以找到详细信息。基本上是对每个顶点周围的叉积求和。比三角剖分要简单得多。
以下是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定理,就像平面积分器的工作方式一样。更具体地说:
上述公式 =
integral_over_perimeter(-y dx + x dy) =
integral_over_area((-(-dy)/dy+dx/dx) dy dx) =
2 Area
abs()
函数会去除符号。 - 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;
我使用数组下标以提高可读性,但是使用指针更有效率。尽管好的编译器会为你完成这项工作。// "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;
这个网页展示了一个公式:
可以简化为:
如果你将一些项写出来并按照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(这里)学到了这个简化方法。
如果您有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
一组没有其他约束的点不一定能唯一地定义一个多边形。
因此,您首先需要决定从这些点中构建什么样的多边形——也许是凸包?http://en.wikipedia.org/wiki/Convex_hull
然后三角剖分并计算面积。http://www.mathopenref.com/polygonirregulararea.html
计算多边形的面积
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);
}
cross()
函数需要 3 个参数,但你只给了 2 个吗? - oarfish可以使用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
或者进行等高线积分。斯托克斯定理允许您将面积积分表示为等高线积分。再加上一点高斯求积,就大功告成了。