热门标签 | 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;
}



推荐阅读
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 题目Link题目学习link1题目学习link2题目学习link3%%%受益匪浅!-----&# ... [详细]
  • 本实验主要探讨了二叉排序树(BST)的基本操作,包括创建、查找和删除节点。通过具体实例和代码实现,详细介绍了如何使用递归和非递归方法进行关键字查找,并展示了删除特定节点后的树结构变化。 ... [详细]
  • 本文详细探讨了VxWorks操作系统中双向链表和环形缓冲区的实现原理及使用方法,通过具体示例代码加深理解。 ... [详细]
  • Codeforces Round #566 (Div. 2) A~F个人题解
    Dashboard-CodeforcesRound#566(Div.2)-CodeforcesA.FillingShapes题意:给你一个的表格,你 ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • ImmutableX Poised to Pioneer Web3 Gaming Revolution
    ImmutableX is set to spearhead the evolution of Web3 gaming, with its innovative technologies and strategic partnerships driving significant advancements in the industry. ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 本题涉及一棵由N个节点组成的树(共有N-1条边),初始时所有节点均为白色。题目要求处理两种操作:一是改变某个节点的颜色(从白变黑或从黑变白);二是查询从根节点到指定节点路径上的第一个黑色节点,若无则输出-1。 ... [详细]
  • Linux设备驱动程序:异步时间操作与调度机制
    本文介绍了Linux内核中的几种异步延迟操作方法,包括内核定时器、tasklet机制和工作队列。这些机制允许在未来的某个时间点执行任务,而无需阻塞当前线程,从而提高系统的响应性和效率。 ... [详细]
  • 本题通过将每个矩形视为一个节点,根据其相对位置构建拓扑图,并利用深度优先搜索(DFS)或状态压缩动态规划(DP)求解最小涂色次数。本文详细解析了该问题的建模思路与算法实现。 ... [详细]
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社区 版权所有