問題描述:已知兩條線段P1P2和Q1Q2,判斷P1P2和Q1Q2是否相交,若相交,求出交點。
兩條線段的位置關係可以分為三類:有重合部分、無重合部分但有交點、無交點。
演算法的步驟如下:
1.快速排斥實驗。
設以線段P1P2為對角線的矩形為R,設以線段Q1Q2為對角線的矩形為T,如果R和T不相交,則兩線段不相交。
2.跨立實驗。
如果兩線段相交,則兩線段必然相互跨立對方。
若P1P2跨立Q1Q2,則向量(P1-Q1)和(P2-Q1)位於向量(Q2-Q1)的兩側,即( P1 - Q1 ) × ( Q2 - Q1 ) * ( P2 - Q1 ) × ( Q2 - Q1 ) < 0。
若Q1Q2跨立P1P2,則向量(Q1-P1)和(Q2-P1)位於向量(P2-P1)的兩側,即( Q1 - P1 ) × ( P2 - P1 ) * ( Q2 - P1 ) × ( P2 - P1 ) < 0。
排斥實驗和跨立實驗的示例如下圖所示。
3.計算交點。
當判定兩條線段相交後,可以進行交點的求解,求交點可以用平面幾何方法,列點斜式方程來完成。但由於點斜式方程難以處理斜率為0的特殊情況,不方便求解。因而,參用向量法求解交點。
設交點為(x0,y0),則下列方程組成立:
根據以上方程組,消除引數k1和k2,得到如下方程:
然後求解(x0,y0),結果如下所示:
1 typedef struct Point 2 { 3 int x; 4 int y; 5 }Point; 6 //排斥實驗 7 bool IsRectCross(const Point &p1,const Point &p2,const Point &q1,const Point &q2) 8 { 9 bool ret = min(p1.x,p2.x) <= max(q1.x,q2.x) && 10 min(q1.x,q2.x) <= max(p1.x,p2.x) && 11 min(p1.y,p2.y) <= max(q1.y,q2.y) && 12 min(q1.y,q2.y) <= max(p1.y,p2.y); 13 return ret; 14 } 15 //跨立判斷 16 bool IsLineSegmentCross(const Point &pFirst1,const Point &pFirst2,const Point &pSecond1,const Point &pSecond2) 17 { 18 long line1,line2; 19 line1 = pFirst1.x * (pSecond1.y - pFirst2.y) + 20 pFirst2.x * (pFirst1.y - pSecond1.y) + 21 pSecond1.x * (pFirst2.y - pFirst1.y); 22 line2 = pFirst1.x * (pSecond2.y - pFirst2.y) + 23 pFirst2.x * (pFirst1.y - pSecond2.y) + 24 pSecond2.x * (pFirst2.y - pFirst1.y); 25 if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0)) 26 return false; 27 28 line1 = pSecond1.x * (pFirst1.y - pSecond2.y) + 29 pSecond2.x * (pSecond1.y - pFirst1.y) + 30 pFirst1.x * (pSecond2.y - pSecond1.y); 31 line2 = pSecond1.x * (pFirst2.y - pSecond2.y) + 32 pSecond2.x * (pSecond1.y - pFirst2.y) + 33 pFirst2.x * (pSecond2.y - pSecond1.y); 34 if (((line1 ^ line2) >= 0) && !(line1 == 0 && line2 == 0)) 35 return false; 36 return true; 37 } 38 39 bool GetCrossPoint(const Point &p1,const Point &p2,const Point &q1,const Point &q2,long &x,long &y) 40 { 41 if(IsRectCross(p1,p2,q1,q2)) 42 { 43 if (IsLineSegmentCross(p1,p2,q1,q2)) 44 { 45 //求交點 46 long tmpLeft,tmpRight; 47 tmpLeft = (q2.x - q1.x) * (p1.y - p2.y) - (p2.x - p1.x) * (q1.y - q2.y); 48 tmpRight = (p1.y - q1.y) * (p2.x - p1.x) * (q2.x - q1.x) + q1.x * (q2.y - q1.y) * (p2.x - p1.x) - p1.x * (p2.y - p1.y) * (q2.x - q1.x); 49 50 x = (int)((double)tmpRight/(double)tmpLeft); 51 52 tmpLeft = (p1.x - p2.x) * (q2.y - q1.y) - (p2.y - p1.y) * (q1.x - q2.x); 53 tmpRight = p2.y * (p1.x - p2.x) * (q2.y - q1.y) + (q2.x- p2.x) * (q2.y - q1.y) * (p1.y - p2.y) - q2.y * (q1.x - q2.x) * (p2.y - p1.y); 54 y = (int)((double)tmpRight/(double)tmpLeft); 55 return true; 56 } 57 } 58 return false; 59 }