线段相交判断

我们分两步确定两条线段是否相交:

(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;

}

 

posted @ 2012-07-08 18:58  Wheat″  阅读(182)  评论(0)    收藏  举报