如何判断2个线段相交
判斷 2 個線段相交有很多方法,最直接的方法就是直接計算兩條直線的交點,然后看看交點是否分別在這兩條線段上。這樣的方法很容易理解,但是代碼實現比較麻煩。
還有一種常用的方法是通過向量叉積來判斷的,這種方法不需要算出直線方程,在代碼實現上比較簡便。
用這種方法判別線段是否相交一般分為兩步:
1. 快速排斥實驗
2. 跨立實驗
快速排斥實驗
我們首先判斷兩條線段在 x 以及 y 坐標的投影是否有重合。
也就是判斷下一個線段中 x 較大的端點是否小于另一個線段中 x 較小的段點,若是,則說明兩個線段必然沒有交點,同理判斷下 y。
如上圖所示,代碼表示如下:
如果上面的四條判斷有一個為真,則代表兩線段必不可交,否則應該進行第二步判斷。
顯然,上圖通不過快速排斥實驗。
跨立實驗
矢量叉積
計算矢量叉積是與直線和線段相關算法的核心部分。
設矢量 P = (x1, y1),Q = ( x2, y2 ),則矢量叉積定義為:P × Q = x1*y2 - x2*y1,其結果是一個矢量,與為 P Q 向量所在平面的法向量。顯然有性質 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 分別在線段 CD 兩側,點 C 和 D 分別在線 AB 兩側。
判斷 A 點與 B 點是否在線段 DC 的兩側,即向量 A-D 與向量 B-D 分別在向量 C-D 的兩端,也就是其叉積是異號的,即 (A?D)×(C?D)?(B?D)×(C?D)<0 。
同時也要證明 C 點與 D 點在線段 AB 的兩端,兩個同時滿足,則表示線段相交。
然后我們來看看臨界情況,也就是上式恰好等于 0 的情況下:
當出現如上圖所示的情況的時候, (A?D)×(C?D)?(B?D)×(C?D)=0 ,顯然,這種情況是相交的。只要將等號直接補上即可。
再接得想一想,如果沒有第一步的快速排斥實驗,僅判斷第二步,會出現什么問題?
當出現如上所示的情況的時候,叉積都為 0, 可以通過跨立實驗,但是兩個線段并沒有交點。不過還好,這種情況在第一步快速排斥已經被排除了。
代碼
struct Line {double x1;double y1;double x2;double y2; };bool intersection(const Line &l1, const Line &l2) {//快速排斥實驗if ((l1.x1 > l1.x2 ? l1.x1 : l1.x2) < (l2.x1 < l2.x2 ? l2.x1 : l2.x2) ||(l1.y1 > l1.y2 ? l1.y1 : l1.y2) < (l2.y1 < l2.y2 ? l2.y1 : l2.y2) ||(l2.x1 > l2.x2 ? l2.x1 : l2.x2) < (l1.x1 < l1.x2 ? l1.x1 : l1.x2) ||(l2.y1 > l2.y2 ? l2.y1 : l2.y2) < (l1.y1 < l1.y2 ? l1.y1 : l1.y2)){return false;}//跨立實驗if ((((l1.x1 - l2.x1)*(l2.y2 - l2.y1) - (l1.y1 - l2.y1)*(l2.x2 - l2.x1))*((l1.x2 - l2.x1)*(l2.y2 - l2.y1) - (l1.y2 - l2.y1)*(l2.x2 - l2.x1))) > 0 ||(((l2.x1 - l1.x1)*(l1.y2 - l1.y1) - (l2.y1 - l1.y1)*(l1.x2 - l1.x1))*((l2.x2 - l1.x1)*(l1.y2 - l1.y1) - (l2.y2 - l1.y1)*(l1.x2 - l1.x1))) > 0){return false;}return true; }總結
以上是生活随笔為你收集整理的如何判断2个线段相交的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何判断两条直线是否相交
- 下一篇: 如何判断两条线段是否相交