如何计算不规则形状的面积?


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
Room包含Points 的列表,然后通过将每个点连接在一起来获得分段,然后将其循环回去,这将更有意义。否则,在您当前的设置下,获取不正确的值(例如,不封闭的房间,中间有墙的房间等)在很东边。这将是最佳选择。
MCMastery '17

另一个选择是对形状进行三角剖分并计算每个三角形的面积。困难的部分是三角剖分。可行,但并不总是很漂亮。鞋带的答案仍然更好。
Draco18s不再信任SE

@MCMastery该解决方案将无法正常工作,因为它要求Rooms始终是完整的,如果我让播放器Room使用Segments来构建s ,情况可能并非如此。另外,闭室功能很容易定义(只需遍历Segments并确保它们创建了一个房间)。

Answers:


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
我一直用它来计算两个向量的叉积,但从未知道它被称为鞋带算法
Sidar,2017年

3
注意,可以将其扩展为计算由三角形组成的不规则3D对象的体积,并且可以将其视为微积分基本定理的平凡情况。
Dietrich Epp's

5
这里的区域已签名。沿相反方向遍历各个点,则最终结果A否定。根据目标,A = |A|可能需要一个。如果使用负面积号,则可以使用内部和外部点列表(顺序相反)找到不规则甜甜圈上的区域。
chux-恢复莫妮卡

6
当然,由于高斯或欧拉都有一个公式。
corsiKa '17

0

我们还可以使用蒙特卡洛方法。

围绕任意形状绘制一个矩形。以统一分发的PRNG源为例。mersenne捻线器,然后使用模函数将输出约束为矩形的X,Y长度。数数 落在您的形状内的随机点。除以生成的总积分。将该商乘以矩形的面积。每次迭代都将收敛到真实区域。只要您可以确定R ^ N坐标是否落在形状的R ^ N边界内,该算法就可荒谬地实现可并行化,并且可用于计算任意尺寸的形状“体积”。

在这里,有人在使用此方法查找圆圈区域,然后使用该区域来计算pi https://www.youtube.com/watch?v=VJTFfIqO4TU


2
-1:您不想使用取模来获得范围,您想要使用统一分布或其他分布,以取模的方式进行统计有各种各样的问题。
user1997744 '17

12
当我们没有简单的多边形,而是某种难以表达其边界的隐式形状(例如分形或元球斑点)时,此方法可能会很有用。对于问题中的多边形,似乎不必要地昂贵。
DMGregory

正如@DMGregory指出的那样,这不是我想要的。但是,我认为它值得+1,以防别人需要它。

这很有趣,但是包含测试的成本不会变得过高吗?即,如果您的形状足够复杂以至于不能采用这种方法,那么包含测试也不会真的很昂贵,因此您不想进行大量测试吗?(假设多边形)
Mattia

好的模数确实是有问题的,但这是一个简单的解决方案。我们真正得到的是随机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;

基本上,倒三角形。三角形的面积很简单,因此我们将剩余部分的段数减少了一个。重复直到剩下的是三角形。


2
高斯的Shoelace公式是将计算数量减半或三分之二的简写。解决它。
彼得·格肯斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.