S02E07:多边形定义

475 阅读2分钟

说明

这里我们讨论的,都是简单多边形。它没有自相交,各个边连续且共面。简单多边形还可定义为:

1.周界不自交的多边形。
2.满足条件:
1)顶点与顶点不重合。
2)顶点不在边上。
3.边与边不相交的多边形。
我们这里所处理的,都是简单多边形,可以再分为凸多边形和凹多边形两种。

上面给出的定义确保了以下属性:
1.多边形包围一个总是具有可测量区域的区域(称为其内部)。
2.构成多边形(称为边)的线段仅在其端点(称为顶点)或更少的正式“角”处相遇。
3.两个边缘完全相交。
4.边数总是等于顶点数。

几何

判断共面其实有两种方法:

  • 判断每个顶点处的法线,是否与第一个点的法线平行。即先用叉乘求出每个顶点的法线,归一化之后,再用点乘判断是否等于 1,等于 1 才是平行。
  • 判断每条边和第一个顶点片的法线,是否垂直。即先用叉乘求出第一点的法线,判断每条边与法线的点乘是否等于 0,等于 0 才是垂直。

所以第一种方法,不仅计算量大,还因为三角函数的问题,判断是否等于 1 精度较差。所以这里使用了第二种方法计算。

注意:在实际项目中,可能会存在两点重合问题。这里我们没有判断两点重合的情况,即当某个边长度为 0 时,法线也是 0。因为我们重复使用了第一个顶点的法线,如果第一个点的法线是 0,那后面所有边都会被“误判”为垂直于法线。如果第一个顶点法线不为 0,那后面某个边长为 0 并无影响。

代码

//定义多边形
struct Polygon {
    let points:[simd_float3]
    var count: Int {
        get{
            return points.count
        }
    }
}
///是否是多边形:多于 3 个点,且共面
static func isPolygon(points:[simd_float3]) -> Bool {
    if points.count < 3 {
        return false
    }
    let d1 = points[0] - points[points.count - 1]
    let d2 = points[1] - points[0]
    let n = cross(d1, d2)
    
    var lastPoint = points[1]
    
    for i in 2..<points.count {
        let point = points[i]
        let vector = point - lastPoint
        if abs(dot(vector, n)) > Float.leastNormalMagnitude   {
            return false
        }
        lastPoint = point
    }
    return true
}