1. 概述
平面中判斷點在三角形內外有很多中算法,文獻1中提到了一種同向法,我認為是比較好的解法,兼顧了效率和可理解性。不過這個算法有兩個要注意的地方。
2. 詳論
2.1. 原理與實現
同向法的具體算法摘錄如下:
關鍵的實現代碼如下:
//空間三角形
//按照逆時針順序插入值並計算法向量
template <class T>
class Triangle
{
public:
Vec3<T> v0;
Vec3<T> v1;
Vec3<T> v2;
Triangle()
{
}
Triangle(Vec3<T> v0, Vec3<T> v1, Vec3<T> v2)
{
this->v0 = v0;
this->v1 = v1;
this->v2 = v2;
}
// v1 = Cross(AB, AC)
// v2 = Cross(AB, AP)
// 判斷矢量v1和v2是否同向
bool SameSide(Vec3<T>& A, Vec3<T>& B, Vec3<T>& C, Vec3<T>& P)
{
Vec3<T> AB = B - A ;
Vec3<T> AC = C - A ;
Vec3<T> AP = P - A ;
Vec3<T> v1 = AB ^ AC;
Vec3<T> v2 = AB ^ AP;
// v1 and v2 should point to the same direction
return v1*v2 >= 0 ;
//return v1 * v2 > 0 ;
}
// 判斷平面點P是否在平面三角形內
bool PointInTriangle2D(Vec3<T>& P)
{
Vec3<T> A(v0.x(), v0.y(), 0);
Vec3<T> B(v1.x(), v1.y(), 0);
Vec3<T> C(v2.x(), v2.y(), 0);
return SameSide(A, B, C, P) && SameSide(B, C, A, P) && SameSide(C, A, B, P);
}
};
2.2. 注意事項
第一個要注意的是,為了方便表達出向量的叉積,使用了三維向量而不是二維向量。但是這個算法是針對的是平面而不是空間,也就是判斷空間中點是否在三角形內是無效的。並且,傳入的三維向量的第三分量最好都為0,否則,無法保證算法的有效性。
第二是點是通過點積來判斷是否同向:
bool SameSide(Vec3<T>& A, Vec3<T>& B, Vec3<T>& C, Vec3<T>& P)
{
Vec3<T> AB = B - A ;
Vec3<T> AC = C - A ;
Vec3<T> AP = P - A ;
Vec3<T> v1 = AB ^ AC;
Vec3<T> v2 = AB ^ AP;
// v1 and v2 should point to the same direction
return v1*v2 >= 0 ;
//return v1 * v2 > 0 ;
}
理論上,兩點積等於0,說明兩向量是直角。但是這里的>=0考慮的是零向量的問題,零向量點乘任何點向量還是0。那么什么時候會出現零向量呢?當點正好在三角形的邊界上的時候(兩個相同的向量的叉積為零向量)。也就是說,這里的=0可以判斷點正好在三角形的邊界或者頂點上,而>0才是判斷點是否在三角形的內部。使用的時候可以靈活掌握。