线段相交(快速排斥和跨立)

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1264

本来想用斜率来算,后来觉得要分太多情况,上网发现用快速排斥+跨立就能做

快速排斥的意思是当两条线段分别构成的矩形范围没有相交,那么两直线肯定没没有交点,如下图

如何判断两个矩形相交?一种错误的思路是一个矩形中的点在另一个矩形里,单如果是十字相交的矩形就不成立

我的方法是找到两个矩形的中心点C1,C2,设两个矩形的宽和高分别为W1,H1,W2,H2

那么只要满|C1.x-C2.x|<=(W1+W2)/2 && |C1.y-C2.y|<=(H1+H2)/2就是相交

bool MBR(rec a1,rec a2)
{
    p c[3];
    double w[3],h[3];
    c[1].x=(a1.left.x+a1.right.x)/2;
    c[1].y=(a1.left.y+a1.right.y)/2;
    c[2].x=(a2.left.x+a2.right.x)/2;
    c[2].y=(a2.left.y+a2.right.y)/2;
    w[1]=a1.right.x-a1.left.x;
    w[2]=a2.right.x-a2.left.x;
    h[1]=a1.left.y-a1.right.y;
    h[2]=a2.left.y-a2.right.y;
    if(abs(c[1].x-c[2].x)<=(w[1]+w[2])/2&&abs(c[1].x-c[2].x)<=(w[1]+w[2])/2)
        return true;
    return false;
    
}

排除必然不相交的情况后再来看哪些情况相交,这里用到跨立

跨立即一向量跨过另一向量,如下图只需AC向量和AD向量在AB向量两侧,同时CA向量和CB向量在CD向量的两侧即可证明

怎么实现在两侧?用向量叉乘(ACxAB)·(ABXAD)<=0即可说明AC与AD在AB两侧(要注意考虑重合的情况)

以下是完整代码

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

struct p
{
    double x,y;
};
struct vec
{
    double x,y;
};
struct rec
{
    p left,right;
};

rec rectangle(p a1,p a2)
{
    rec r;
    
    r.left.x=min(a1.x,a2.x);
    r.left.y=max(a1.y,a2.y);
    r.right.x=max(a1.x,a2.x);
    r.right.y=min(a1.y,a2.y);
    return r;    
}
vec vector(p a1,p a2)
{
    vec v;
    
    v.x=a2.x-a1.x;
    v.y=a2.y-a1.y;
    return v;
}
double vec_pro(vec v1,vec v2)
{
    return v1.x*v2.y-v1.y*v2.x;
}
bool MBR(rec a1,rec a2)
{
    p c[3];
    double w[3],h[3];
    c[1].x=(a1.left.x+a1.right.x)/2;
    c[1].y=(a1.left.y+a1.right.y)/2;
    c[2].x=(a2.left.x+a2.right.x)/2;
    c[2].y=(a2.left.y+a2.right.y)/2;
    w[1]=a1.right.x-a1.left.x;
    w[2]=a2.right.x-a2.left.x;
    h[1]=a1.left.y-a1.right.y;
    h[2]=a2.left.y-a2.right.y;
    if(abs(c[1].x-c[2].x)<=(w[1]+w[2])/2&&abs(c[1].x-c[2].x)<=(w[1]+w[2])/2)
        return true;
    return false;
    
}
int main()
{
    int t;
    
    cin>>t;
    while(t--)
    {    
        rec r[3];
        p a[5];
        bool is_intersect=true,need_judge=true;
        for(int i=1;i<=4;i++)
            cin>>a[i].x>>a[i].y;
            r[1]=rectangle(a[1],a[2]);
            r[2]=rectangle(a[3],a[4]);
            if(!MBR(r[1],r[2]))
            {
                is_intersect=false;
                need_judge=false;
            }
            if(need_judge)
            {
                vec AB=vector(a[1],a[2]);
                vec AC=vector(a[1],a[3]);
                vec AD=vector(a[1],a[4]);
                vec CA=vector(a[3],a[1]);
                vec CB=vector(a[3],a[2]);
                vec CD=vector(a[3],a[4]);
                if(vec_pro(AB,AC)*vec_pro(AB,AD)<=0&&vec_pro(CD,CA)*vec_pro(CD,CB)<=0)
                    is_intersect=true;
                else
                    is_intersect=false;
            }
            if(is_intersect)
                cout<<"Yes"<<endl;
            else
                cout<<"No"<<endl;
    }
}

 

posted @ 2017-08-30 10:50  小九xD  阅读(760)  评论(0编辑  收藏  举报