热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【C++笔记】如何判断2个线段相交

判断2个线段相交有很多方法,最直接的方法就是直接计算两条直线的交点,然后看看交点是否分别在这两条线段上。这样的方法很容易理解,但是代码实现

判断 2 个线段相交有很多方法,最直接的方法就是直接计算两条直线的交点,然后看看交点是否分别在这两条线段上。这样的方法很容易理解,但是代码实现比较麻烦。

还有一种常用的方法是通过向量叉积来判断的,这种方法不需要算出直线方程,在代码实现上比较简便。 
用这种方法判别线段是否相交一般分为两步: 
1. 快速排斥实验 
2. 跨立实验

快速排斥实验

我们首先判断两条线段在 x 以及 y 坐标的投影是否有重合。 
也就是判断下一个线段中 x 较大的端点是否小于另一个线段中 x 较小的段点,若是,则说明两个线段必然没有交点,同理判断下 y。

这里写图片描述 
如上图所示,代码表示如下:

max(C.x,D.x).x,B.x) || max(C.y,D.y).y,B.y) ||
max(A.x,B.x).x,D.x) || max(A.y,B.y).y,C.y)

如果上面的四条判断有一个为真,则代表两线段必不可交,否则应该进行第二步判断。 
显然,上图通不过快速排斥实验。

跨立实验


矢量叉积

计算矢量叉积是与直线和线段相关算法的核心部分。 
设矢量 P = (x1, y1),Q = ( x2, y2 ),则矢量叉积定义为:P × Q = x1*y2 - x2*y1,其结果是一个矢量,与为 P Q 向量所在平面的法向量。显然有性质 P × Q = - ( Q × P ) 和 P × ( - Q ) = - ( P × Q )。 
叉积的一个非常重要性质是可以通过它的符号判断两矢量相互之间的顺逆时针关系: 
  若 P × Q > 0 , 则 P 在 Q 的顺时针方向。 
  若 P × Q <0 , 则 P 在 Q 的逆时针方向。 
  若 P × Q &#61; 0 , 则 P 与 Q 共线&#xff0c;但可能同向也可能反向。

通过叉积来判断线段相交

这里写图片描述 
如果两线段相交那么就意味着它们互相跨立&#xff0c;即如上图点 A 和 B 分别在线段 CD 两侧&#xff0c;点 C 和 D 分别在线 AB 两侧。 
判断 A 点与 B 点是否在线段 DC 的两侧&#xff0c;即向量 A-D 与向量 B-D 分别在向量 C-D 的两端&#xff0c;也就是其叉积是异号的&#xff0c;即 (AD)×(CD)(BD)×(CD)<0(A−D)×(C−D)∗(B−D)×(C−D)<0。 
同时也要证明 C 点与 D 点在线段 AB 的两端&#xff0c;两个同时满足&#xff0c;则表示线段相交。

然后我们来看看临界情况&#xff0c;也就是上式恰好等于 0 的情况下&#xff1a;

这里写图片描述

当出现如上图所示的情况的时候&#xff0c;(AD)×(CD)(BD)×(CD)&#61;0(A−D)×(C−D)∗(B−D)×(C−D)&#61;0&#xff0c;显然&#xff0c;这种情况是相交的。只要将等号直接补上即可。

再接得想一想&#xff0c;如果没有第一步的快速排斥实验&#xff0c;仅判断第二步&#xff0c;会出现什么问题&#xff1f;

这里写图片描述

当出现如上所示的情况的时候&#xff0c;叉积都为 0, 可以通过跨立实验&#xff0c;但是两个线段并没有交点。不过还好&#xff0c;这种情况在第一步快速排斥已经被排除了。

代码

struct Line {double x1;double y1;double x2;double y2;
};bool intersection(const Line &l1, const Line &l2)
{//快速排斥实验if ((l1.x1 > l1.x2 ? l1.x1 : l1.x2) <(l2.x1 l1.y2 ? l1.y1 : l1.y2) <(l2.y1 l2.x2 ? l2.x1 : l2.x2) <(l1.x1 l2.y2 ? l2.y1 : l2.y2) <(l1.y1 0 ||(((l2.x1 - l1.x1)*(l1.y2 - l1.y1) - (l2.y1 - l1.y1)*(l1.x2 - l1.x1))*((l2.x2 - l1.x1)*(l1.y2 - l1.y1) - (l2.y2 - l1.y1)*(l1.x2 - l1.x1))) > 0){return false;}return true;
}



推荐阅读
  • 本题探讨了在大数据结构背景下,如何通过整体二分和CDQ分治等高级算法优化处理复杂的时间序列问题。题目设定包括节点数量、查询次数和权重限制,并详细分析了解决方案中的关键步骤。 ... [详细]
  • 在进行QT交叉编译时,可能会遇到与目标架构不匹配的宏定义问题。例如,当为ARM或MIPS架构编译时,需要确保使用正确的宏(如QT_ARCH_ARM或QT_ARCH_MIPS),而不是默认的QT_ARCH_I386。本文将详细介绍如何正确配置编译环境以避免此类错误。 ... [详细]
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 本文介绍如何利用栈数据结构在C++中判断字符串中的括号是否匹配。通过顺序栈和链栈两种方式实现,并详细解释了算法的核心思想和具体实现步骤。 ... [详细]
  • 本文介绍了如何在 C# 和 XNA 框架中实现一个自定义的 3x3 矩阵类(MMatrix33),旨在深入理解矩阵运算及其应用场景。该类参考了 AS3 Starling 和其他相关资源,以确保算法的准确性和高效性。 ... [详细]
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • 目录一、salt-job管理#job存放数据目录#缓存时间设置#Others二、returns模块配置job数据入库#配置returns返回值信息#mysql安全设置#创建模块相关 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 主板IO用W83627THG,用VC如何取得CPU温度,系统温度,CPU风扇转速,VBat的电压. ... [详细]
  • 本文探讨了如何在 F# Interactive (FSI) 中通过 AddPrinter 和 AddPrintTransformer 方法自定义类型(尤其是集合类型)的输出格式,提供了详细的指南和示例代码。 ... [详细]
  • Linux环境下C语言实现定时向文件写入当前时间
    本文介绍如何在Linux系统中使用C语言编程,实现在每秒钟向指定文件中写入当前时间戳。通过此示例,读者可以了解基本的文件操作、时间处理以及循环控制。 ... [详细]
  • 本文详细解释了为什么在成功执行移动赋值操作后,对象的析构函数会被调用,并提供了代码示例和详细的分析。 ... [详细]
  • 由二叉树到贪心算法
    二叉树很重要树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。单就面试而言,在 ... [详细]
  • Linux环境下进程间通信:深入解析信号机制
    本文详细探讨了Linux系统中信号的生命周期,从信号生成到处理函数执行完毕的全过程,并介绍了信号编程中的注意事项和常见应用实例。通过分析信号在进程中的注册、注销及处理过程,帮助读者理解如何高效利用信号进行进程间通信。 ... [详细]
author-avatar
910621rh_270
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有