園子里有很多關於點是否在三角形內的文章,提供了各種方法。這讓人很糾結,到底該用哪種算法?這里提供一套我認為最優的算法。如果你有不同的意見,亦或有更好的算法,歡迎來討論。
算法使用的是同向法,其原理是:假設點P位於三角形ABC內,會有這樣一個規律:三角形的每一個邊,其對角點與P在邊的同一側;或者說三角形的每一個頂點與P在其對角邊的同一側。
(1)代碼
// 2D vector
class Vec2 { public: Vec2() { x = 0.0f; y = 0.0f; } Vec2(float fx, float fy) :x(fx), y(fy) { } // Add
Vec2 operator + (const Vec2& v) const { return Vec2(x + v.x, y + v.y); } // Subtract
Vec2 operator - (const Vec2& v) const { return Vec2(x - v.x, y - v.y) ; } public: float x, y; };
1 // Dot product
2 inline float Vec2Dot(const Vec2& v1, const Vec2& v2) 3 { 4 return v1.x * v2.x + v1.y * v2.y; 5 } 6
7 // Cross product
8 inline float Vec2Cross(const Vec2& v1, const Vec2& v2) 9 { 10 return v1.x * v2.y - v1.y * v2.x; 11 } 12
13 // Determine whether two vectors v1 and v2 point to the same direction 14 // 判斷C和P在直線AB的同一側
15 inline bool IsSameSide(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& P) 16 { 17 Vec2 AB = B - A; 18 Vec2 AC = C - A; 19 Vec2 AP = P - A; 20
21 float f1 = Vec2Cross(AB, AC); 22 float f2 = Vec2Cross(AB, AP); 23
24 // f1 and f2 should to the same direction
25 return f1*f2 >= 0.0f; 26 } 27
28 // Same side method 29 // Determine whether point P in triangle ABC
30 inline bool IsPointInTriangle(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& P) 31 { 32 return IsSameSide(A, B, C, P) &&
33 IsSameSide(B, C, A, P) &&
34 IsSameSide(C, A, B, P); 35 } 36
37 // Determine whether point P in angle ABC 38 // 點P是否在角ABC內
39 inline bool IsPointInAngle(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& P) 40 { 41 return IsSameSide(A, B, C, P) && IsSameSide(B, C, A, P); 42 }
算法中沒有使用三角函數的調用,因為這一原因,我認為它是最優的算法。
(2)測試效果
我生成一幅1024*1024大小的圖像,並設置三個頂點,對圖像中的所有像素調用IsPointInAngle函數,以測試其效率:
圖中顯示出圖像生成時間為868.758毫秒,這是DEBUG版本的。