數學知識三 點在三角形內

2021-06-18 01:14:37 字數 3627 閱讀 2039

設計思想:

設三角形三個點

a(a1,a2),b(b1,b2),c(c1,c2)

三條邊方程

bc:fa(x,y)=0

ac:fb(x,y)=0

ab:fc(x,y)=0

以bc為例,在三角形內的點必須與點a在bc的同側

所以對於點d(x,y)

在三角形內首先要滿足fa(x,y)*fa(a1,a2)>0

其他邊也同理

所以只要比較

fa(x,y)*fa(a1,a2)

fb(x,y)*fb(b1,b2)

fc(x,y)*fc(c1,c2)

這三個數的正負性

1三個數都是正數:d在三角形內

2至少有乙個負數:d在三角形外

3有且只有乙個0,另兩個為正數:在三角形邊上

4有且只有乙個0,乙個正數乙個負數:在三角形邊的延長線上,也算在三角形外,因為滿足2

5有二個0:在三角形的頂點上

6不可能出現3個0,或3個負數,或乙個0兩個負數的情況

bool pointin********(const vector3 & a, const vector3 & b, const vector3 & c, const vector3 & p)

float v = (dot00 * dot12 - dot01 * dot02) * inverdeno ;

if (v < 0 || v > 1) // if v out of range, return directly

return u + v <= 1 ;

}

網路中的其他方法:

假定在右手座標系中的三角形3點座標為a,b,c,判斷p是否在abc之內

( 主要來自 3d引擎研發qq群(38224573 )的各位朋友的討論 ,我僅僅算做個總結吧,特別感謝各位朋友的熱情支援。 )

方法1:三個perplane的方法

設ab,bc,ac邊上的垂直平面為perplane[3],垂直朝向內側的法向為n[3]

1)先根據任意兩邊叉出法向n

n = ab.crossproduct(ac); 

n.normalize();

d = a.dotproduct( n );

2)如果p在三角形所在平面之外,可直接判定不在平面之內( 假定方程為 ax+by+cz+d = 0 )

if( p.dotproduct( n ) + d > 0 ) return false; 

3)然後法向和各邊叉出垂直平面的法向

n[0] = n.crossproduct(ab); //朝向內側

n[0].normalize();

perplane[0].dist = a.dotproduct(n[0]);

perplane[0].normal = n[0];

同樣方法求得perplane[1],perlane[2];

3)因為三個perplane都朝向三角形內側,p在三角形內的條件是同時在三個perplane前面;如果給定點p在任意乙個垂直平面之後,那麼可判定p在三角形外部

for( int i = 0;i<3;j++ )

if( p.dotproduct( perplane[i].normal ) + perplane[i].dist < 0 )

return false;

return true;//如果p沒有在任意一條邊的外面,可判斷定在三角形之內,當然包括在邊上的情況

方法2:三個部分面積與總面積相等的方法

s(pab) + s(pac) + s( pbc) = s(abc) 則判定在三角形之內

用向量代數方法計算三角形的面積為

s = 1/2*|a|*|b|*sin(theta)

= 1/2*|a|*|b|*sqrt(1-cos^2(theta))

= 1/2*|a|*|b|*sqrt(1- (a.dotproduct(b)/(|a|*|b|))^2);

另一種計算面積的方法是 s = 1/2*|a.crossproduct(b)|

比較一下,發現後者的精確度和效率都高於前者,因為前者需要開方和求向量長度,向量長度相當於一次點乘,三個點乘加乙個開方,顯然不如

後者一次叉乘加一次向量長度(注,一次叉乘計算相當於2次點乘,一次向量長度計算相當於一次點乘),後者又對又快。

s(abc)  = ab.crossproduct(ac);//*0.5;

s(pab)  = pa.crossproduct(pb);//*0.5;

s(pbc)  = pb.crossproduct(pc);//*0.5;

s(pac)  = pc.crossproduct(pa);//*0.5;

if( s(pab) + s(pbc) + s(pac) == s(abc)  )

return true;

return false;

另一種計算三角形面積的向量方法是 1/2*a.crossprodcuct(b) ,crossproduct = ( y1*z2 - y2*z1 , x1*z2 - x2*z1, x1*y2 - x2*z1 )

可以看到crossproduct 的計算要比dotproduct多3個乘法計算,效率沒有上面的方法高

方法3:三個向量歸一化後相加為0

這個方法很怪異,發現自 下面的乙個回帖

如上圖三角形abc,p為ab外側一點,n1,n2,n3 分別為bp,ap,cp的歸一化向量;nm為n1,n2夾角的角平分線

可以看出角a-p-b是三角形內角,必然小於180度,那麼角n1-p-n2等於a-p-b;nm是n1-p-n2的角平分線,那麼角b-p-n等於角n-p-a,而cpn必然小於其中乙個,

即小於180/2 = 90度。結論是角n1,n2的合向量方向與n3的夾角為銳角。所以n1,n2,n3的合向量模大於1.

這裡注意,n3不一定在n1,n2之間,不能假定n2-p-n3 和n3-p-n1這兩個角一定是銳角

同樣可以推導出如果p在三角形內,n1+n2+n3必然小於0;若n1+n2+n3 = 0則p在三角形的邊上。

有沒有更簡單的推導方法?

這個方法看起來很精巧,但是善於優化的朋友會立刻發現,三個向量歸一化,需要三個開方。迭代式開方太慢了,而快速開方有的時候又不滿足精度要求。

方法4:重心座標之和為1

barycenter = ( s(pab)/s(pabc),s(pbc)/s(pabc),s(pac)/s(pabc)) // 點p在三角形內的重心座標

if( barycenter.x + barycenter.y + barycenter.z >0.f )

return false

return true;

其中s(pab),s(abc),s(pbc),s(pbc) 用上述的方法二種提到的計算三角形面積方法計算。 

綜合比較

方法1必須求叉乘,雖然可以通過首先排除不在平面內的點,但是後面仍要求三個叉乘和3個點乘(當然還可排除法優化)

方法2看起來之需要求4個點乘,如果用叉乘方法計算面積,可能會導致效率低下

方法3是看起來是最精巧的方法,但是效率也不能保證...3個開方

方法4和方法2的效率差不多

判斷點在三角形內

二維向量叉乘公式a x1,y1 b x2,y2 則a b x1y2 x2y1 設有向線段ab,兩端點a xa,ya b xb,yb 另一點c xc,yc float f xb xa yc ya xc xa yb ya if f 0 點c位於有向線段ab的左側 else if f 0 點c位於有向線段...

程式設計之美4 4 點在三角形內

第一種方法 面積相等法 如果點在三角形內部,則如果將三角形的三個頂點與這個點相連所得的三個小三角形的面積之和與原三角形的面積相等 s a,b,d s a,c,d s b,c,d s a,b,c 第二種方法 向量叉積法 判斷點p3是否在向向p1p2的左邊,只需要通過兩個向量p1p2 p1p3做叉積就可...

如何判斷一點在三角形內

假定在右手座標系中的三角形3點座標為a,b,c,判斷p是否在abc之內 主要來自 3d引擎研發 38224573 的各位朋友的討論 我僅僅算做個總結吧,特別感謝各位朋友的熱情支援。方法1 三個perplane的方法 設ab,bc,ac邊上的垂直平面為perplane 3 垂直朝向內側的法向為n 3 ...