S02E10:多边形重心

951 阅读1分钟

说明

多边形重心需要对多边形分割,分成小三角形来进行计算,因为计算时面积是有符号的,所以对于凹多边形也是适用的。

几何

我们依次取多边形的两个顶点,再加上坐标原点(0, 0, 0),就构成了一个小三角形。这个小三角形的重心很好求,就是两个顶点的平均值,而面积也可以用向量叉乘来计算。 需要注意的是,我们要计算的面积是带有符号的,也就是可能是负的。所以不能直接用叉乘后得到向量的长度来计算,需要先计算出一个法线,再将代表小三角形面积的叉乘向量与法线比较,判断正负。

我们这里,直接用第一个小三角形的法线,代表了整个多边形的法线,并将其归一化,也就令其长度为一。再将各个小三角形的叉乘向量与该法线点乘,就得到了带有符号的小三角形面积。

代码

///重心
static func barycenter(polygon:Polygon) -> simd_float3 {
    var center = simd_float3.zero
    if polygon.count <= 3 {
        for point in polygon.points {
            center += point
        }
        return center / Float(polygon.count)
    }
    
    var area:Float = 0
    var first = polygon.points[polygon.count - 1]
    var second = polygon.points[0]
    //归一化的法线
    let n = normalize(cross(first, second))
    for point in polygon.points {
        second = point
        //计算以 first、second 和 原点(0,0,0) 组成的三角形,重心及有向面积
        let triangleCenter = (first + second)/2
        let triangleArea = dot(cross(first, second), n)
        center += triangleCenter * triangleArea
        first = second
        area += triangleArea
    }
    
    return center / area / 3
}