计算几何之线段性质(一):判断两线段相交

来源:互联网 发布:吴昕的淘宝店名 编辑:程序博客网 时间:2024/06/05 18:20

在研究线段相交之前,我们首先来看一下点定位中是如何判断点是否在线段上的:

设有点Q及线段P1P2,判断Q在线段P1P2上包括两条依据:

(1)(Q-P1)×(P2-P1)=0(这里×表示叉积);

(2)Q在以P1P2为对角线的矩形内。

前者保证了Q在直线P1P2上,后者保证了点Q不在线段P1P2的延长线或反向延长线上。

代码入下:

typedef struct node{    double x,y;}Point;bool on_segment(Point p1,Point p2,Point q){    if((q.x-p1.x)*(p2.y-p1.y)==(p2.x-p1.x)*(1.y-p1.y)&&min(p1.x,p2.x)<=q.x&&q.x<=max(p1.x,p2.x)&&min(p1.y,p2.y)<=q.y&&q.y<=max(p1.y,p2.y))      return true;    else return false;}


有了点定位的概念,接下来我们看一下如何判断两线段相交:

 

对于给定4个点确定的两条线段A1A2,B1B2:

typedef  struct {  double  x, y;} Point;Point A1,A2,B1,B2;

 

判断两线段是否相交需要分两步确定:

 

1.快速排斥实验

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

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

判断矩形相交,只需判断某一矩形是否有顶点在另一个矩形内即可。

所以:只有当满足第一个条件时,两个线段才可能相交。

 

2.跨立实验

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

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

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

(A1-B1) × (B2-B1)=0时,说明A1B1和B2B1共线,但前面已经通过了快速排斥实验,所以A1一定在B1B2上,所以判断线段A1A2是否跨立B1B2的依据就是::((A1-B1) × (B2-B1)) · ((B2-B1) × (A2-B1))>=0。

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

如图:

应用:

1.       判断两个线段相交

2.       判断线段与直线相交

3.       判断点在矩形内

代码如下:

/*若线段v1和线段v2的界限框同时在x方向和y方向相交且v1(或者v2)跨立于v2(或者v1)所在的直线,则返回true,否则返回false*/typedef struct node{    double x,y;}Point;typedef struct line{    Point start,end;}vector;double multi(Point p1,Point p2,Point p0){    return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}bool cross(vector v1,vector v2){    if(max(v1.start.x,v1.end.x)>=min(v2.start.x,v2.end.x)&&max(v2.start.x,v2.end.x)>=min(v1.start.x,v1.end.x)&&max(v1.start.y,v1.end.y)>=min(v2.start.y,v2.end.y)&&max(v2.start.y,v2.end.y)>=min(v1.start.y,v1.end.y)&&multi(v2.start,v1.end,v1.start)*multi(v1.end,v2.end,v1.start)>=0&&multi(v1.start,v2.end,v2.start)*multi(v2.end,v1.end,v2.start)>=0)      return true;    return false;}



 

0 0