您的位置:首页 > 其它

杭电 1086 You can Solve a Geometry Problem too 判断线段是否相交.

2015-12-10 22:43 183 查看
判断两线段是否相交 有一个比较容易理解的快速排斥试验.
首先我们获得两条线段 我们首先需要把两个线段都自行扩张成为一个矩形 如下图:

根据观察就能知道 如果两个矩形不相交的话 两条线段是一定不会相交的.
所以通过快速排斥试验我们就能直接pass掉很多情况.
如果给出四个点(两条线段)我们可以通过以下代码实现判断快速排斥:

if(!(min(a.x,b.x)<=max(c.x,d.x) && min(c.y,d.y)<=max(a.y,b.y)&&
        min(c.x,d.x)<=max(a.x,b.x) && min(a.y,b.y)<=max(c.y,d.y)))


以下是跨立试验的过程:
判断线段是否相交问题.要用到叉乘向量的知识 这里贴上向量叉乘的函数:
struct point

{

      double x,y;

};

void chacheng(point  a,point b,point c)
{
    return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
}


在线段判断是否相交的函数中用处:
判断向量bc在向量ab的顺时针方向还是逆时针方向.
下边图是我盗来的图~对应理解一下吧0.0

现在请读者在纸上画出两个图 一个是线段ab和cd相交的图 一个是不相交的图
然后对应如下代码体会其作用:

u=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);//c.b.a//u的正负表示bc在ab的顺时针方向还是逆时针方向.
    v=(d.x-a.x)*(b.y-a.y)-(b.x-a.x)*(d.y-a.y);//d.b.a//同理

u。v只考虑其大于0小于0还是为0(只考虑其实正数 负数还是0)
表示两条线段的所处几何方向
这时候你画的图就有用了~
如果ab和cd相交的情况下 向量bc是在ab的顺时针方向,并且向量bd是在ab的逆时针方向.是不是有点柳暗花明的感觉了~?
别着急 .我们继续看.如果确实有以上结论了是否就能判断ab和cd一定相交了呢?
这里上个图:

图片转载声明:http://blog.csdn.net/lishuhuakai/article/details/8263160
对应理解一下 只有一组满足是不够的~~~~~
所以这里还需要再填上另外一组 :
w=(a.x-c.x)*(d.y-c.y)-(d.x-c.x)*(a.y-c.y);//a.d.c
    z=(b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);//b.d.c


所以如果有了
u*v<=0.00000001 && w*z<=0.00000001
我们就能判断出两线段是一定相交的了~

下边给上AC完整代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
struct dian
{
double x,y;
};

struct xian
{
dian a;dian b;
};
//判断两条线段是否相交 首先一定要通过快速排斥试验之后 再通过跨立试验之后就能判断了这两线段相交.
bool judge(dian a,dian b,dian c,dian d)
{
//快速排斥

if(!(min(a.x,b.x)<=max(c.x,d.x) && min(c.y,d.y)<=max(a.y,b.y)&& min(c.x,d.x)<=max(a.x,b.x) && min(a.y,b.y)<=max(c.y,d.y)))
//判断两条线段组成的矩形是否相交 如果不相交 那么这两条线是不会相交的.
//特别要注意一个矩形含于另一个矩形之内的情况
return false;
double u,v,w,z;
//定a定c.
//c.d在ab两端 a.b在cd两端.就能判断相交.
u=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);//c.b.a//u的正负表示bc在ab的顺时针方向还是逆时针方向. v=(d.x-a.x)*(b.y-a.y)-(b.x-a.x)*(d.y-a.y);//d.b.a//同理
w=(a.x-c.x)*(d.y-c.y)-(d.x-c.x)*(a.y-c.y);//a.d.c z=(b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y);//b.d.c
return (u*v<=0.00000001 && w*z<=0.00000001);

}

int main()
{
int n;
xian str[101];
while(cin>>n && n!=0)
{
int count=0;
for(int i=0;i<n;i++)
{
cin>>str[i].a.x>>str[i].a.y>>str[i].b.x>>str[i].b.y;
}
for(int i=0;i<n;i++)//遍历所有点什么的还是比较容易理解的~.
for(int j=i+1;j<n;j++)
if(judge(str[i].a,str[i].b,str[j].a,str[j].b)) count++;
cout<<count<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: