计算几何---判断线段相交(二)

计算几何中最基本重要的算法之一~判断线段相交基础。

只需判断线段是否同时满足

1.快速排斥实验
2.跨立实验


1.快速排斥实验:

设以线段P1P2为对角线的矩形为T,以Q1Q2线段为对角线的矩形为R,那么下图这种状态时P1P2和Q1Q2肯定不相交

计算几何---判断线段相交(二)_第1张图片


判断P1 P2 Q1 Q2是否满足这种关系就是快速排斥实验。

max(p1.x,p2.x) < min(q1.x,q2,x) || max(q1.x,q2.x) < min(p1,x,p2,x) ||max(p1.y,p2.y) < min(q1.y,q2,y) || max(q1.y,q2.y) < min(p1.y,p2.y)

上式为真,则表明两个矩形不想交,一般是取上式的否定,直接判断是否满足矩形相交,即。

min(p1.x,p2.x) <= max(q1.x,q2,x) && min(q1.x,q2.x) <= max(p1,x,p2,x) &&min(p1.y,p2.y) <= max(q1.y,q2,y) && min(q1.y,q2.y) <= max(p1.y,p2.y)

2.跨立实验

前提:如果两线段相交,必定互相跨立。

计算几何---判断线段相交(二)_第2张图片

也即是说:

1.P1 P2 在Q1Q2的两侧

2.Q1Q2 在P1P2的两侧

判断两点是否在一条直线的两侧就用到叉乘了。

(Q1P1 x Q1Q2) * (Q1Q2 x Q1P2)  <= 0 表示P1P2在Q1Q2的两侧

(P1Q2 x P1P2)  *  (P1P2 x P1Q2)  <= 0 表示Q1Q2在P1P2的两侧

这就满足跨立实验的要求了~

小试一下:HDU 1086 http://acm.hdu.edu.cn/showproblem.php?pid=1086

#include<cstdio>
#include<cstdlib>
//注意题目说了线段与线段之间最多只有一个交点,不存在重合或者在一条直线的情况 
struct line{
    double x1,y1;
    double x2,y2;
};
long Judge(struct line Line1,struct line Line2)//跨立实验 
{
    double Xa1 = Line1.x1;
    double Ya1 = Line1.y1;
    double Xa2 = Line1.x2;
    double Ya2 = Line1.y2;
    double Xb1 = Line2.x1;
    double Yb1 = Line2.y1;
    double Xb2 = Line2.x2;
    double Yb2 = Line2.y2;

    if(((Xa2-Xa1)*(Yb1-Ya1)-(Xb1-Xa1)*(Ya2-Ya1))*((Xa2-Xa1)*(Yb2-Ya1)-(Xb2-Xa1)*(Ya2-Ya1))>0)
        return 0;
    if(((Xb2-Xb1)*(Ya1-Yb1)-(Xa1-Xb1)*(Yb2-Yb1))*((Xb2-Xb1)*(Ya2-Yb1)-(Xa2-Xb1)*(Yb2-Yb1))>0)
        return 0;
    return 1;
}
int main()
{
    struct line Line[100];
    int num;
    
    while(scanf("%d",&num) != EOF && num)
    {
        int count = 0;
        for(int i = 0 ; i < num ; ++i)
        	scanf("%lf%lf%lf%lf",&Line[i].x1,&Line[i].y1,&Line[i].x2,&Line[i].y2);
        for(int i = 0 ; i < num - 1 ; ++i)
            for(int j = i + 1 ; j < num ; ++j)
                if(Judge(Line[i],Line[j]))
                	count++;
        printf("%d\n",count);
	}	
    return 0;
}


你可能感兴趣的:(计算几何,判断线段相交二)