欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

计算几何-判断两条线段是否相交模板

程序员文章站 2022-06-03 19:45:01
...

给定两个点:

typedef  struct {

  double  x, y;

} Point;

Point A1,A2,B1,B2;

首先引入两个实验:

a.快速排斥实验

设以线段A1A2和线段B1B2为对角线的矩形为M,N;

若M,N 不相交,则两个线段显然不相交;

所以:满足第一个条件时:两个线段可能相交。

 

b.跨立实验

 

如果两线段相交,则两线段必然相互跨立对方.若A1A2跨立B1B2,则矢量( A1 - B1 ) 和(A2-B1)位于矢量(B2-B1)的两侧,

计算几何-判断两条线段是否相交模板

即(A1-B1) × (B2-B1) * (A2-B1) × (B2-B1)<0。

上式可改写成(A1-B1) × (B2-B1) * (B2-B1) × (A2-A1)>0。

应该判断两次,即两条线段都要为直线,判断另一直线的两端点是否在它两边,若是则两线段相交。

若积极满跨立实验是不行的,如下面的情况:

计算几何-判断两条线段是否相交模板

 

即两条线段在同一条直线上。所以我们要同时满足两次跨立和快速排斥实验。

 

总体分析:

当(A1-B1) × (B2-B1)=0时,说明(A1-B1)和(B2-B1)共线,但是因为已经通过快速排斥试验,所以 A1一定在线段 B1B2上;同理,(B2-B1)×(A2-B1)=0 说明A2一定在线段B1B2上。所以判断A1A2跨立B1B2的依据是:(A1-B1) × (B2-B1) * (B2-B1) × (A2-B1) >= 0。

同理判断B1B2跨立A1A2的依据是:(B1-A1) × (A2-A1) * (A2-A1) × (B2-A1) >= 0。

如图:

计算几何-判断两条线段是否相交模板

 

代码:

#include<algorithm>
#include<iostream>
#include<fstream>
#include<complex>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iomanip>
#include<string>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cctype>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
using namespace std;
#define pt(a) cout<<a<<endl
#define debug test
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
#define eps 1e-10
#define PI acos(-1.0)
typedef pair<int,int> PII;
const ll mod = 1e9+7;
const int N = 1e6+10;

ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qp(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
int to[4][2]={{-1,0},{1,0},{0,-1},{0,1}};

ll t,n,m;

struct pt {///点
    ll x,y;
}p[10];
struct ln{///线段
    pt s,e;
};

ll mul(pt a,pt b,pt c) {///向量叉积
    return (b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y);
}

int is(ln a,ln b) {///判断线段是否相交
    if( min(a.s.x,a.e.x) <= max(b.s.x,b.e.x) &&
        max(a.s.x,a.e.x) >= min(b.s.x,b.e.x) &&
        min(a.s.y,a.e.y) <= max(b.s.y,b.e.y) &&
        max(a.s.y,a.e.y) >= min(b.s.y,b.e.y) &&
        mul(b.s,a.s,b.e)*mul(b.s,b.e,a.e) >= 0 &&
        mul(a.s,b.s,a.e)*mul(a.s,a.e,b.e) >= 0 )
    return 1;
    else return 0;
}

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);

    return 0;
}