判斷兩個線段是否相交02


寫在前面
在其他博客中看到這方面的知識,很多都是重復,並且說的總是雲里霧里的,所以這里我就自己總結一下這種問題如何求解,判斷兩個線段是否相交在前面我們提到了會用到叉積的一點知識,那么這里就來詳細說一下怎么判斷兩個線段是否相交

算法詳解
首先我們看一下快速排斥實驗,快速排斥實驗也就是以兩條線段作為對角線做矩形,判斷兩個矩形是否相交,那么我們這里可以知道:

1)如果兩個矩形不相交,那么線段一定不相交

2)如果兩個矩形相交,那么線段不一定相交,如下圖

 

 

所以這里我們首先就要判斷兩條線段形成的矩形是否相交,只有相交我們才要繼續進行判斷后面的線段是否相交.......

跨立實驗:前面我們知道叉積可以用來判斷兩個向量之間的位置關系(順時針還是逆時針關系),那么這里我們就會用到這個性質

我們知道如果兩個線段相交的話,那么一條線段兩邊的兩個點要位於另一條線段的兩邊,只有兩條線段都滿足這個條件,我們就可以判定這兩條直線相交了,那么我們這里所說的一條線段兩個端點位於另一條線段的兩邊,這就是其他博客中提到的跨立吧

那么我們就用叉積來對是否滿足這個條件進行判斷:

 

 

 

 

取其中一個向量作為中間向量,中間向量中開始端點作為另外兩個向量的起點,判斷三個向量之間的位置關系即可:

第一個圖中: (ca × cd)(cd × cb) >= 0 我們即可判斷滿足跨立條件

第二個圖中: (bc × ba)(ba × bd) >=0 我們即可判斷滿足跨立條件

第三個圖中: (bc × ba)(ba × bd)  < 0不滿足跨立條件

第四個圖中: (ca × cd)(cd × cb) >= 0我們即可判斷滿足跨立條件

 

即計算(ca × cd)(cd × cb) 與(bc × ba)(ba × bd)的結果必須同時大於零,這兩個線段才是相交的;

當然,單獨判斷其中一個,可以獲得一個線段所在的直線是否與另一個線段相交。

 

那么我們就可以知道上面條件就是判斷跨立是否成立的條件了,那么這樣我們線段是否相交就已經可以解決了.
栗子及模板
zoj1648

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define INF 0x3f3f3f3f

using namespace std;
const int MAXN = 2100;
struct Point
{
double x,y;
}line[MAXN][2];

double mult(Point p0,Point p1,Point p2) //叉積計算,p0為公用節點
{
return (p0.x - p1.x) * (p0.y - p2.y) - (p0.y - p1.y) * (p0.x - p2.x);
}
//aa、bb屬於同一個矩形 cc、dd屬於同一個矩形 相交返回true,不相交返回false
bool Judge(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(aa,cc,bb) * mult(aa,bb,dd) < 0) return false; //正確的話也就是aa,bb要在cc或者dd的兩邊
if(mult(cc,aa,dd) * mult(cc,dd,bb) < 0) return false;
return true;
}

int main()
{
int n;
while(~scanf("%d",&n))
{
bool flag = true;
for(int i = 0;i < n;i ++)
scanf("%lf%lf%lf%lf",&line[i][0].x,&line[i][0].y,&line[i][1].x,&line[i][1].y);
for(int i = 0;i < n;i ++)
for(int j = i+1;j < n;j ++)
{
if(Judge(line[i][0],line[i][1],line[j][0],line[j][1])) // 判斷兩條直線是否相交
{
flag = false;
break;
}
if(!flag) break;
}
if(!flag) printf("burned!\n");
else printf("ok!\n");
}
return 0;
}
參考博客
https://blog.csdn.net/Dacc123/article/details/51219491

https://blog.csdn.net/sizaif/article/details/79192165
---------------------
作者:阿_波_
來源:CSDN
原文:https://blog.csdn.net/li1615882553/article/details/80372202
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

 

C#代碼

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MathTool : MonoBehaviour
{

    public Transform A, B, C, D;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        Debug.Log(IsIntersection0(A.position, B.position, C.position, D.position));
    }

//不優化的情況下 bool IsIntersection0(Vector3 a, Vector3 b, Vector3 c, Vector3 d) { Vector3 ca = A.position - C.position; Vector3 cb = B.position - C.position; Vector3 cd = D.position - C.position; Vector3 ba = A.position - B.position; Vector3 bc = C.position - B.position; Vector3 bd = D.position - B.position; Vector3 c1 = Vector3.Cross(ca, cd); Vector3 c2 = Vector3.Cross(cd, cb); float f1 = Vector3.Dot(c1, c2); Vector3 c3 = Vector3.Cross(bc, ba); Vector3 c4 = Vector3.Cross(ba, bd); float f2 = Vector3.Dot(c3, c4); //必須f1,f2同時滿足大於等於0才能算相交 if (f1 >= 0&&f2>=0) return true; else return false; } }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM