線段A(x1,y1)-B(x2,y2),所在直線L1方程爲F(x,y)=0;
線段C(x3,y3)-D(x4,y4),所在直線L2方程爲G(x,y)=0;
思路:(即問題的充要條件)
(點A與點B在直線L2兩側) AND (點C與點D在直線L1兩側);
方法:
如果點P(Xp,Yp)不在直線a*x+b*y+c=0上,則a*Xp+b*Yp+c<>0;
如果用兩個點的座標代入同一直線方程a*x+b*y+c計算出的值異號,則兩點在直線兩側;
解法:
(G(x1,y1)*G(x2,y2)<0) AND ( F(x3,y3)*F(x4,y4)<0 )
利用向量的叉積性質,當其中一條線段的兩個端點在另一條線段的同一側時,不相交。
否則,相交。
*向量的叉積 向量的叉積性質都忘完了……但是它可以用來判斷點在直線的某側。進而可以解決點是否在三角形內,兩個矩形是否重疊等問題。向量的叉積的模表示這兩個向量圍成的平行四邊形的面積。
設矢量P = ( x1, y1 ),Q = ( x2, y2 ),則矢量叉積定義爲由(0,0)、p1、p2和p1+p2所組成的平行四邊形的帶符號的面積,
即:P×Q = x1*y2 - x2*y1,其結果是一個僞矢量。
顯然有性質 P × Q = - ( Q × P ) 和 P × ( - Q ) = - ( P × Q )。
叉積的一個非常重要性質是可以通過它的符號判斷兩矢量相互之間的順逆時針關係:
若 P × Q > 0 , 則P在Q的順時針方向。
若 P × Q < 0 , 則P在Q的逆時針方向。
若 P × Q = 0 , 則P與Q共線,但可能同向也可能反向。
叉積的方向與進行叉積的兩個向量都垂直,所以叉積向量即爲這兩個向量構成平面的法向量。
如果向量叉積爲零向量,那麼這兩個向量是平行關係。
因爲向量叉積是這兩個向量平面的法向量,如果兩個向量平行無法形成一個平面,其對應也沒有平面法向量。所以,兩個向量平行時,其向量叉積爲零
已知:由點A和點B組成的線段1, 由點C和點D組成的線段2
方法:當點A和點B在線段2的兩側 並且點C和點D在線段1的兩側時
兩線段相交 否則不是
算法1:
///----------alg 1------------
struct Point
{
double x, y;
};
bool between(double a, double X0, double X1)
{
double temp1= a-X0;
double temp2= a-X1;
if ( ( temp1<1e-8 && temp2>-1e-8 ) || ( temp2<1e-6 && temp1>-1e-8 ) )
{
return true;
}
else
{
return false;
}
}
// 判斷兩條直線段是否有交點,有則計算交點的座標
// p1,p2是直線一的端點座標
// p3,p4是直線二的端點座標
bool detectIntersect(Point p1, Point p2, Point p3, Point p4)
{
double line_x,line_y; //交點
if ( (fabs(p1.x-p2.x)<1e-6) && (fabs(p3.x-p4.x)<1e-6) )
{
return false;
}
else if ( (fabs(p1.x-p2.x)<1e-6) ) //如果直線段p1p2垂直與y軸
{
if (between(p1.x,p3.x,p4.x))
{
double k = (p4.y-p3.y)/(p4.x-p3.x);
line_x = p1.x;
line_y = k*(line_x-p3.x)+p3.y;
if (between(line_y,p1.y,p2.y))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else if ( (fabs(p3.x-p4.x)<1e-6) ) //如果直線段p3p4垂直與y軸
{
if (between(p3.x,p1.x,p2.x))
{
double k = (p2.y-p1.y)/(p2.x-p1.x);
line_x = p3.x;
line_y = k*(line_x-p2.x)+p2.y;
if (between(line_y,p3.y,p4.y))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
double k1 = (p2.y-p1.y)/(p2.x-p1.x);
double k2 = (p4.y-p3.y)/(p4.x-p3.x);
if (fabs(k1-k2)<1e-6)
{
return false;
}
else
{
line_x = ((p3.y - p1.y) - (k2*p3.x - k1*p1.x)) / (k1-k2);
line_y = k1*(line_x-p1.x)+p1.y;
}
if (between(line_x,p1.x,p2.x)&&between(line_x,p3.x,p4.x))
{
return true;
}
else
{
return false;
}
}
}
///------------alg 1------------
算法2:
///------------alg 2------------
//叉積
double mult(Point a, Point b, Point c)
{
return (a.x-c.x)*(b.y-c.y)-(b.x-c.x)*(a.y-c.y);
}
//aa, bb爲一條線段兩端點 cc, dd爲另一條線段的兩端點 相交返回true, 不相交返回false
bool intersect(Point aa, Point bb, Point cc, Point dd)
{
if ( max(aa.x, bb.x)<min(cc.x, dd.x) )
{
return false;
}
if ( max(aa.y, bb.y)<min(cc.y, dd.y) )
{
return false;
}
if ( max(cc.x, dd.x)<min(aa.x, bb.x) )
{
return false;
}
if ( max(cc.y, dd.y)<min(aa.y, bb.y) )
{
return false;
}
if ( mult(cc, bb, aa)*mult(bb, dd, aa)<0 )
{
return false;
}
if ( mult(aa, dd, cc)*mult(dd, bb, cc)<0 )
{
return false;
}
return true;
}
///------------alg 2------------
算法3:http://dec3.jlu.edu.cn/webcourse/t000096/graphics/chapter5/01_1.
<code>c-sharp
///------------alg 3------------
double determinant(double v1, double v2, double v3, double v4) // 行列式
{
return (v1*v3-v2*v4);
}
bool intersect3(Point aa, Point bb, Point cc, Point dd)
{
double delta = determinant(bb.x-aa.x, cc.x-dd.x, bb.y-aa.y, cc.y-dd.y);
if ( delta<=(1e-6) && delta>=-(1e-6) ) // delta=0,表示兩線段重合或平行
{
return false;
}
double namenda = determinant(cc.x-aa.x, cc.x-dd.x, cc.y-aa.y, cc.y-dd.y) / delta;
if ( namenda>1 || namenda<0 )
{
return false;
}
double miu = determinant(bb.x-aa.x, cc.x-aa.x, bb.y-aa.y, cc.y-aa.y) / delta;
if ( miu>1 || miu<0 )
{
return false;
}
return true;
}
///------------alg 3------------
main函數測試:
int main()
{
Point p1, p2, p3, p4;
p1.x = 1;
p1.y = 4;
p2.x = 3;
p2.y = 0;
p3.x = 0;
p3.y = 1;
p4.x = 4;
p4.y = 3;
int i=0, j=0;
bool flag = false;
flag = intersect3(p1, p2, p3, p4);
// alg 2
time_t seconds1 = time (NULL);
for ( ; i!=20000; ++i )
{
for ( j=0; j!=60000; ++j )
{
flag = detectIntersect(p1, p2, p3, p4);
}
}
time_t seconds2 = time (NULL);
cout << "Time used in alg 1:" << seconds2-seconds1 << " seconds." << endl;
// alg 2
time_t seconds3 = time (NULL);
i=0;
j=0;
for ( ; i!=20000; ++i )
{
for ( j=0; j!=60000; ++j )
{
flag = intersect(p1, p2, p3, p4);
}
}
time_t seconds4 = time (NULL);
cout << "Time used in alg 2:" << seconds4-seconds3 << " seconds." << endl;
// alg 3
time_t seconds5 = time (NULL);
i=0;
j=0;
for ( ; i!=20000; ++i )
{
for ( j=0; j!=60000; ++j )
{
flag = intersect3(p1, p2, p3, p4);
}
}
time_t seconds6 = time (NULL);
cout << "Time used in alg 3:" << seconds6-seconds5 << " seconds." << endl;
return 0;
}
VS2008編譯器環境下測試結果:
Debug模式下:
alg 1: 315 seconds;
alg 2: 832 seconds;
alg 3: 195 seconds;
Release模式下:
alg 1: 157 seconds;
alg 2: 169 seconds;
alg 3: 122 seconds;
結論: 使用算法3,時間複雜度最低。