本篇是在 【C++笔记】如何判断2个线段相交 的基础上加上自己的理解和实践总结出的判断两线段是否相交的方法。

判断两条线段是否相交

先附上判断函数

bool judge(int Ax1,int Ay1,int Ax2,int Ay2,int Bx1,int By1,int Bx2,int By2)
{if(( max(Ax1,Ax2)>=min(Bx1,Bx2)&&min(Ax1,Ax2)<=max(Bx1,Bx2) )&&  //判断x轴投影( max(Ay1,Ay2)>=min(By1,By2)&&min(Ay1,Ay2)<=max(By1,By2) )    //判断y轴投影){if(( (Bx1-Ax1)*(Ay2-Ay1)-(By1-Ay1)*(Ax2-Ax1) ) *          //判断B是否跨过A( (Bx2-Ax1)*(Ay2-Ay1)-(By2-Ay1)*(Ax2-Ax1) ) <=0 &&( (Ax1-Bx1)*(By2-By1)-(Ay1-By1)*(Bx2-Bx1) ) *          //判断A是否跨过B( (Ax2-Bx1)*(By2-By1)-(Ay2-By1)*(Bx2-Bx1) ) <=0){return 1;}elsereturn 0;}elsereturn 0;
}

判断一共分为两步,即code中的第一个if和第二个if
第一步:判断两线段在x轴和y轴的投影是否有交,有任何一条轴没有交点就不可能相交。(快速排斥实验)
第二步:判断两条直线是否相互跨过,用跨立来判断,具体用到的知识是向量积。(跨立实验)

第一步:快速排斥实验

很好理解吧,如果两线段在x,y的投影都不重合,是不可能会相交的
求解的方法也有很多种,这里我就介绍我理解的这个方法。
拿x轴举例,y轴可类比

投影要有重合(哪怕只是一个点也算),那么两线段中任意一条线段的两端点中x较大的那一个端点的x值一定要大于另一条线段的两端点中x较小的那一个端点的x值,不然这两线段一定是相离的,在x轴投影没有重合。

前面是先A线段对B线段,后面是B线段对A线段

max(Ax1,Ax2)>=min(Bx1,Bx2)&&min(Ax1,Ax2)<=max(Bx1,Bx2)//判断x
max(Ay1,Ay2)>=min(By1,By2)&&min(Ay1,Ay2)<=max(By1,By2)//判断y

我还有一种非正式但很好理解的说法
我们把投影到x轴上的投影线段看作两个队伍,这两个队伍要各派一个队员进行比赛,投影线段上的每一个点就是一个队员,点对应的值就是这个队员的能力,两投影线段有重合说明两个队伍都有获胜或平手的可能,怎么样才会出现两个队伍都有获胜或平手可能呢?那就是两个队伍中任意一个队伍能力最强的选手能力要>=另一个队伍中能力最弱的选手,即max(A)>=min(B)&&max(B)>=min(A)。这样,只要A派出最强的,B派出最弱的,A就会获胜或平手;B派出最强的,A派出最弱的,B就会获胜或平手。

第二步:跨立实验

两个坐标A(x1,y1),B(x2,y2),那么AxB的向量积就是x1y2-y1x2。
我们假定一个向量积R,R=x1y2-y1x2。
R<0 说明A在B的逆时针方向
R=0 说明A与B共线,可能正向也可能反向
R>0 说明A在B的顺时针方向

我们证明两线段的跨立就需要证明A跨立B且B跨立A
如何证明跨立?
我们以B跨立A举例
B跨立A的意思就是B线段与A所在的直线有交点。
我们在A的两端点中任意选一个端点,将它与B的两个端点相连得到L1,L2

若此时A线段向量在L1,L2的中间或L1,L2的边上,就能说明B跨立A
即L1,L2在A的不同的顺逆时针方向,我们就可以分别求出两个L的向量积,再将他们相乘,如果结果<=0,即向量积异号或有0。

if(( (Bx1-Ax1)*(Ay2-Ay1)-(By1-Ay1)*(Ax2-Ax1) ) *          //判断B是否跨过A( (Bx2-Ax1)*(Ay2-Ay1)-(By2-Ay1)*(Ax2-Ax1) ) <=0 &&( (Ax1-Bx1)*(By2-By1)-(Ay1-By1)*(Bx2-Bx1) ) *          //判断A是否跨过B( (Ax2-Bx1)*(By2-By1)-(Ay2-By1)*(Bx2-Bx1) ) <=0)

完整代码

#include <bits/stdc++.h>
using namespace std;
bool judge(int Ax1,int Ay1,int Ax2,int Ay2,int Bx1,int By1,int Bx2,int By2);
int main()
{int Ax1,Ay1,Ax2,Ay2;int Bx1,By1,Bx2,By2;while(cin >> Ax1 >> Ay1 >> Ax2 >> Ay2 >> Bx1 >> By1 >> Bx2 >> By2){if(judge(Ax1,Ay1,Ax2,Ay2,Bx1,By1,Bx2,By2))cout << "YES!" << endl ;elsecout << "NO" << endl ;}return 0;
}
bool judge(int Ax1,int Ay1,int Ax2,int Ay2,int Bx1,int By1,int Bx2,int By2)
{if(( max(Ax1,Ax2)>=min(Bx1,Bx2)&&min(Ax1,Ax2)<=max(Bx1,Bx2) )&&  //判断x轴投影( max(Ay1,Ay2)>=min(By1,By2)&&min(Ay1,Ay2)<=max(By1,By2) )    //判断y轴投影){if(( (Bx1-Ax1)*(Ay2-Ay1)-(By1-Ay1)*(Ax2-Ax1) ) *          //判断B是否跨过A( (Bx2-Ax1)*(Ay2-Ay1)-(By2-Ay1)*(Ax2-Ax1) ) <=0 &&( (Ax1-Bx1)*(By2-By1)-(Ay1-By1)*(Bx2-Bx1) ) *          //判断A是否跨过B( (Ax2-Bx1)*(By2-By1)-(Ay2-By1)*(Bx2-Bx1) ) <=0){return 1;}elsereturn 0;}elsereturn 0;
}

关于代码优化

在 【C++笔记】如何判断2个线段相交 中已经有谈到,如果不要第一步,可能会出现两条共线但不相交的线段判断的错误,因为共线后向量积都为0,这种情况可以在第一步中被排除掉。

如果将第二个if的<=0改为<0呢,不就排除了共线不相交了吗?但这样的话我们把刚好相交(一点相交)和共线相交的情况也都排除了。

那我们允许向量积最多一个为0行不行呢,同样,这样我们把共线相交的情况和两线段共用一个端点的情况也排除了

暂时还没有想出更优的代码

相关题目

P922

#include <bits/stdc++.h>
using namespace std;
bool judge(int Ax1,int Ay1,int Ax2,int Ay2,int Bx1,int By1,int Bx2,int By2);
int main()
{int Ax1,Ay1,Ax2,Ay2;int Bx1,By1,Bx2,By2;int n;while(cin >> n && n){while(n--){cin >> Ax1 >> Ay1 >> Ax2 >> Ay2 >> Bx1 >> By1 >> Bx2 >> By2;if(judge(Ax1,Ay1,Ax2,Ay2,Bx1,By1,Bx2,By2))cout << "YES" << endl ;elsecout << "no" << endl ;}}return 0;
}
bool judge(int Ax1,int Ay1,int Ax2,int Ay2,int Bx1,int By1,int Bx2,int By2)
{if(( max(Ax1,Ax2)>=min(Bx1,Bx2)&&min(Ax1,Ax2)<=max(Bx1,Bx2) )&&  //判断x轴投影( max(Ay1,Ay2)>=min(By1,By2)&&min(Ay1,Ay2)<=max(By1,By2) )    //判断y轴投影){if(( (Bx1-Ax1)*(Ay2-Ay1)-(By1-Ay1)*(Ax2-Ax1) ) *          //判断B是否跨过A( (Bx2-Ax1)*(Ay2-Ay1)-(By2-Ay1)*(Ax2-Ax1) ) <=0 &&( (Ax1-Bx1)*(By2-By1)-(Ay1-By1)*(Bx2-Bx1) ) *          //判断A是否跨过B( (Ax2-Bx1)*(By2-By1)-(Ay2-By1)*(Bx2-Bx1) ) <=0){return 1;}elsereturn 0;}elsereturn 0;
}

如何判断两条线段是否相交相关推荐

  1. 计算几何-判断两条线段是否相交

    原理:如果两条线段相交,那么必须跨立,就是以一条线段为标准,另一条线段的两端点一定在这条线段的两段 也就是说a b两点在线段cd的两端,c d两点在线段ab的两端 struct point() {do ...

  2. 【数学计算】判断两条线段是否相交+计算两条线段的交点和夹角

    序言 还是那句话,学习是为了应用.书到用时方恨"用得少" 1. 计算两条直线的交点 直线一般式方程 A x + B y + C = 0 Ax+By+C = 0 Ax+By+C=0 ...

  3. 判断两条线段是否相交

    如上图,判断线段AB和线段CD相交. 分析:如果线段AB和线段CD相交,只能是图中的两种相交情况.可以用向量叉乘来判断.如果(向量AB叉乘向量AC)*(向量AB叉乘向量AD)<= 0 并且(向量 ...

  4. 判断两条线段是否相交 java_判断两个线段是否相交02

    写在前面 在其他博客中看到这方面的知识,很多都是重复,并且说的总是云里雾里的,所以这里我就自己总结一下这种问题如何求解,判断两个线段是否相交在前面我们提到了会用到叉积的一点知识,那么这里就来详细说一下 ...

  5. 二维空间内,如何判断两条线段是否相交,相离,平行,重合,并求交点

    首先,假设有两条线段p,q,求这两条线段的空间关系. 我们把两条线段的四个顶点看为向量,用坐标表示:p1(p1x,p1y), p2(p2x,p2y), q1(q1x,q1y), q2(q2x, q2y ...

  6. 判断两条线段/直线相交,并求交点

      一.矢量基本知识     因为后面的计算需要一些矢量的基本知识,这里只是简单的列举如下,如果需要更加详细的信息,可以自行搜索wikipedia或google. 1.矢量的概念:如果一条线段的端点是 ...

  7. 【转载】判断两条线段是否相交——(向量叉乘)

    原文:https://www.cnblogs.com/tuyang1129/p/9390376.html 实现:https://blog.csdn.net/yegshun/article/detail ...

  8. Unity3D C#数学系列之判断两条线段是否相交并求交点

    1 引言 问题:已知三维空间中四点A.B.C.D,如何判断线段AB与CD是否相交,若相交则求出交点. 分析: AB.CD要相交,则AB.CD必须要在同一平面内 快速排斥和跨立实验判断是否相交 几何法分 ...

  9. 判断两条直线是否相交c语言,计算几何-两条线段是否相交(三种算法)

    原标题:计算几何-两条线段是否相交(三种算法) 计算几何中,判断线段是否相交是最基本的题目. 所谓几何, 最基本的当然就是坐标, 从坐标中我们可以知道位置和方向,比如:一个点就是一个位置,两点确定一条 ...

最新文章

  1. 安卓设置菊花动画_Android Progressbar自定义菊花效果
  2. 比特币现金的一年回顾
  3. linux下 LVM的应用
  4. 进程的退出方式以及僵尸进程和孤儿进程
  5. 【写作技巧】计算机应用技术毕业论文范文
  6. 百度地图json_R: 民政部官网市级行政地图的绘制
  7. 惠普HP Deskjet D1530 打印机驱动
  8. 怎么设计一种雷达成像系统代码_光纤阵列成像激光雷达系统的设计
  9. 一个抄底指标(52周新低的股票占比)
  10. 正版Windows7 OEM初级版升级到各版本(Lenovo/ThinkPad/ThinkCentre品牌)的密钥
  11. CURL命令测试网站打开速度
  12. 【opencv】selective_search函数
  13. C#winform下获取主机ip及hostname
  14. 苹果CMS根据有无播放组输出不同的内容
  15. 微信小程序image组件频闪问题
  16. 信息系统项目管理师 - 项目集管理
  17. win10 mysql 1030_Win10系统打开按键精灵提示#1030:启动脚本执行(图)
  18. 外网访问云服务器上的网站
  19. [NOI 2005]聪聪和可可
  20. 数据可视化—初识Gitee

热门文章

  1. opencv | cv2|OpenCV3.3安装Make sure that you use the correct version of ‘pip‘ installed for your Pytho
  2. windows防火墙
  3. windows 防火墙开启导致ping不通
  4. php.ini 验证码,PHP-验证码
  5. Python笔记:query查询
  6. speedoffice被隐藏的工作表如何取消隐藏
  7. HDWiki/插件开发指南
  8. java rsa 文件加密解密_RSA 加密、解密(自己生成加密解密文件)
  9. 虚拟实验工场大学计算机报告,模拟工厂实习报告
  10. 日语发音:日语汉字音变规则