线段相交判断
我们分两步确定两条线段是否相交:
(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
上式可改写成
( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) > 0
当( P1 - Q1 ) × ( Q2 - Q1 ) = 0 时,说明( P1 - Q1 ) 和 ( Q2 - Q1 )共线,但是因为已经通过快速排斥试验,所以 P1 一定在线段 Q1Q2上;
同理,( Q2 - Q1 ) ×(P2 - Q1 ) = 0 说明 P2 一定在线段 Q1Q2上。
所以判断P1P2跨立Q1Q2的依据是:
( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) ≥ 0
同理判断Q1Q2跨立P1P2的依据是:
( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) ≥ 0
代码实现:
#include <stdio.h>
#include <algorithm>
#define N 1010
using namespace std;
struct points
{double x,y;};
struct lines{points a,b;void read();};
lines u,v;
double Max(double a,double b) {return a>b?a:b;}
double Min(double a,double b) {return a<b?a:b;}
void lines::read()
{
scanf("%lf %lf",&a.x,&a.y);
scanf("%lf %lf",&b.x,&b.y);
}
double multi(points p1,points p2,points p0)//叉乘
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
bool across()
{
if(
Max(u.a.x,u.b.x)>=Min(v.a.x,v.b.x)&& //判断 第一个直线的横坐标(取两个点大的横坐标)是否大于或等于第二个直线的横坐标(取两个点小的横坐标),如果小于的话,说明第二个直线在第一个直线的左边,两直线不相交
Max(v.a.x,v.b.x)>=Min(u.a.x,u.b.x)&& //同上
Max(u.a.y,u.b.y)>=Min(v.a.y,v.b.y)&&//判断 第一个直线的纵坐标(取两个点大的纵坐标),是否大于或等于第二个直线的纵坐标(取两个点小的纵坐标)如果小于的话,说明第二个直线在第一个直线的上面,两直线不相交
Max(v.a.y,v.b.y)>=Min(u.a.y,u.b.y)&&//同上
(multi(u.b,v.a,u.a)*multi(u.b,v.b,u.a))<=0&& //跨立实验
(multi(v.b,u.a,v.a)*multi(v.b,u.b,v.a))<=0
)
return true;
else return false;
}

浙公网安备 33010602011771号