如何根据点坐标计算多边形的面积

1,260 阅读2分钟

我们通常会使用多个点序列来表示一个多边形。这些点都是按照一定的顺序(顺时针或者逆时针)来排列的。那么,已知这么一个多边形,怎么计算这个多边形的面积呢?

如下图:

screenshot-20211122-204825.png

我们首先需要计算绿色部分的面积,绿色部分的面积可以看成 4 个直角梯形的面积之和,按照梯形的面积公式,最左边的那个直角梯形面积为:

S=(y1+y2)(x2x1)2S=\frac{(y_1+y_2)(x_2-x_1)}{2}

其余 3 个的面积也是这么算的,即绿色部分的面积为:

Sgreen=i=14(yi+yi+1)(xi+1xi)2S_{green}=\sum_{i=1}^4 \frac{(y_i+y_{i+1})(x_{i+1}-x_i)}{2}

但是,这个绿色部分的面积并不是我们最终需要的面积,我们还得减掉下面的面积,如图,红色部分的面积需要减掉:

screenshot-20211122-204838.png

和上面的计算方法一样,红色部分的面积就是 3 个红色的梯形的面积之和。我们添加第八个点,它和第一个点的坐标一样,这样,我们就可以应用计算公式如下:

Sred=i=57(yi+yi+1)(xixi+1)2S_{red}=\sum_{i=5}^7 \frac{(y_i+y_{i+1})(x_i-x_{i+1})}{2}

最终,我们需要计算的面积就是绿色的面积减去红色的面积。即:

S=SgreenSred=i=14(yi+yi+1)(xi+1xi)2i=57(yi+yi+1)(xixi+1)2S=S_{green}-S_{red}=\sum_{i=1}^4 \frac{(y_i+y_{i+1})(x_{i+1}-x_i)}{2}-\sum_{i=5}^7 \frac{(y_i+y_{i+1})(x_i-x_{i+1})}{2}

我们发现,绿色面积和红色面积的公式就差 x 上的一个符号,我们可以交换下符号,保持公式的一致,即:

S=i=14(yi+yi+1)(xi+1xi)2+i=57(yi+yi+1)(xi+1xi)2=i=17(yi+yi+1)(xi+1xi)2S=\sum_{i=1}^4 \frac{(y_i+y_{i+1})(x_{i+1}-x_i)}{2}+\sum_{i=5}^7 \frac{(y_i+y_{i+1})(x_{i+1}-x_{i})}{2}=\sum_{i=1}^7 \frac{(y_i+y_{i+1})(x_{i+1}-x_{i})}{2}

此时,公式就很简洁了,对于任意多边形,其面积为:

S=i=17(yi+yi+1)(xi+1xi)2S=\sum_{i=1}^7 \frac{(y_i+y_{i+1})(x_{i+1}-x_{i})}{2}

注意,这个计算结果根据你给的点的顺序(顺时针还是逆时针)是有关系的,所以,如果顺序不一致(上面的公式是按照顺时针推导的),就会出现结果为负数的情况,所以,最终的计算中还需要取一下绝对值。

下面,贴上 Python 的实现代码:

def calculate_area(pts: list[Point]) -> float:
    """
    计算多边形的面积,无论凸凹。
    注意,传入的坐标默认单位 1 米,如果是经纬度请自行转换。
    """
    area = 0
    # 计算面积的点必须至少 3 个
    if len(pts) < 3:
        raise RuntimeError('pts length should be at least 3')
    # 点序列要求首尾连接,如果最后一个点不是第一个点,需要补齐
    if pts[-1] != pts[0]:
        pts.append(pts[0])
    
    for i in range(0, len(pts) - 1):
        x0, y0 = pts[i].x, pts[i].y
        x1, y1 = pts[i+1].x, pts[i+1].y
        area += x0 * y1 - x1 * y0

    return abs(area * 0.5)