碰撞检测:判断线段相交

2024-02-04 10:48

本文主要是介绍碰撞检测:判断线段相交,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文乃Siliphen原创,转载请注明出处:http://blog.csdn.net/stevenkylelee

文本demo演示:

在这里插入图片描述

本文介绍的判断线段相交的算法用到2D向量叉乘,
所以先来了解一下:2D向量的叉乘(叉积)

2D叉乘

3D 叉乘:
3D 叉乘的结果是一个 3D 向量,这个向量垂直于参与运算的2个向量的法向量。
3D 叉乘计算公式:( a.y * b.z - b.y * a.z , a.z * b.x - b.z * a.x , a.x * b.y - b.x * a.y )

2D叉乘:
2D 叉乘的结果是一个标量。
2D 叉乘就是把 2D 点看作 3D 的点( z 轴的值为 0 ),套进 3D 叉乘公式进行计算。
例如:有2个2D向量 a , b ,计算叉乘就是:
( a.y * b.z - b.y * 0 , 0 * b.x - b.z * a.x , a.x * b.y - b.x * a.y )= ( 0 , 0 , a.x * b.y - b.x * a.y )
套进3D叉乘公式计算的2D叉乘的结果的 x , y 分量均为 0 ,只有 z 有意义。
所以,标量 z 是 2D 叉乘的结果。

2D 叉乘公式:
设两个 2D 向量 a , b,叉乘公式:a.x * b.y - b.x * a.y

向量 a 叉乘 向量 b 结果的意义:

  • a ,b 向量构成的平行四边形的面积。
  • 方位:以 a 为参考轴,b 相对于 a 的方位。
    结果 > 0 正数 :b 在 a 的左边,a 的逆时针旋转方向。a 逆时针旋转到 b 的角度小于180°。
    结果 < 0 负数 :b 在 a 的右边,a 的顺时针旋转方向。a 顺时针旋转到 b 的角度小于180°。
    结果 = 0 :a 和 b 向量是平行的。

在这里插入图片描述

如上图所示:
向量 a 把空间分为2部分:

  • 左边的空间:逆时针旋转180°范围内的空间。
  • 右边的空间:顺时针旋转180°范围内的空间。

a 叉乘 b 的结果是 > 0 的正数,b 在 a 的左边。
a 叉乘 c , d 的结果是 < 0 的负数,c , d 在 a 的右边。
a 叉乘 a 的结果是0。因为 a 和它自己是平行的。

2D向量叉乘demo演示:在这里插入图片描述

判断线段是否相交:基于2D叉乘

基本思想:

一个线段会把空间分为2部分,以这个线段为分界线,判断是否另一个线段2个端点分别在这个线段分割的2个空间中。
如果2个线段的2个端点都分别在另一个线段分割的2个空间中,那么就认为是相交。

如下图,有线段 a 和 b
在这里插入图片描述

线段 a 把空间分为2部分,浅蓝和浅绿2部分。
b 的2个端点 bp1、bp2 分别在 a 划分出来的2个空间中。
在这里插入图片描述

同样的,线段 b 把空间分为2部分,浅蓝和浅绿2部分。
a 的 2个端点 ap1 , ap2 分别在 b 划分出来的2个空间中。
在这里插入图片描述

如上图所示,
2个线段的2个端点都在另一个线段分割出来的2个空间中,这2个线段相交。

算法描述:

设有2个线段 a , b 。线段 a 的2个端点为:ap1 , ap2 , 线段 b 的 2个端点为:bp1 , bp2 。
条件1:是否 向量 ap1->bp1 、ap1->bp2 分别位于向量 ap1->ap2 的左右2端。
条件2:是否 向量 bp1->ap1 、bp1->ap2 分别位于向量 bp1->bp2 的左右2端。
当条件1和条件2同时满足时,线段 a , b 相交。

判断一个向量之于另一个向量的方位,可以用2D叉乘。

下图演示如何判断 线段 a 的2个端点分别在线段 b 分割出来的2个空间中。
在这里插入图片描述

以 bp2 为起点,拉出3条向量。分别是 v = bp2->bp1 ,v1 = bp2->ap1 , v2 = bp2->ap2
计算:
c1 = v 叉乘 v1
c2 = v 叉乘 v2
如果 c1 , c2 有一个为负数另一个为正数或者为0,那么说明线段a的2端分别在线段b分割的2个空间中。
c1 和 c2 的值相乘,结果为负数说明互为相反符号的数,否者是相同符号。
条件1计算完毕。

条件2的计算示意图如下,计算过程如法炮制条件1。
在这里插入图片描述

本文demo工程下载:

demo 工程是 cocos creator 2.0.8 写的。
可执行文件是一个网页,直接运行 index.htm 即可。

下载地址:
https://download.csdn.net/download/stevenkylelee/10977144

这篇关于碰撞检测:判断线段相交的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/677234

相关文章

Java面试八股之怎么通过Java程序判断JVM是32位还是64位

怎么通过Java程序判断JVM是32位还是64位 可以通过Java程序内部检查系统属性来判断当前运行的JVM是32位还是64位。以下是一个简单的方法: public class JvmBitCheck {public static void main(String[] args) {String arch = System.getProperty("os.arch");String dataM

改变背景颜色+碰撞检测

1.让类继承CCLayerColor比如 class HelloWorld:public cocos2d::CCLayerColor{ public : 在.cpp文件中 bool HelloWorld::init(){ if(!CCLayerColor::initWithColor(ccc4(255,255,255,25

【Python如何输入升高和体重判断你是偏胖还是偏瘦】

1、求体质指数得Python代码如下: # BMI(Body Mass Index)指数:简称体质指数,# 是国际上常用的衡量人体胖瘦程度以及是否健康的一个标准。# 常用指标:BMI<18.5 偏瘦 18.5<=MBI<=24 正常 MBI>24 偏胖# 计算公式:BMI=体重kg/身高的平方ma = eval(input("请输入你的体重(kg):")) # 输入体重b = e

算法11—判断一个树是不是二叉查询树

问题: 给定一个二叉树,判断它是否是二叉查询树。 思路: 要判断是否是二叉查询树,标准就是看每一个节点是否满足:1、左节点及以下节点的值比它小;2、右节点及以下节点的值比它大。当然,前提是子节点都存在的情况。所以,我们需要从根节点不断向下递归,只要所有节点都满足,那么就是BST,否则,就不是。 代码: [java]  view plain copy pri

算法7— 判断一个单链表是否有环,如果有,找出环的起始位置

第一种方法是从单链表head开始,每遍历一个,就把那个node放在hashset里,走到下一个的时候,把该node放在hashset里查找,如果有相同的,就表示有环,如果走到单链表最后一个node,在hashset里都没有重复的node,就表示没有环。 这种方法需要O(n)的空间和时间。 第二种方法是设置两个指针指向单链表的head, 然后开始遍历,第一个指针走一步,第二个指针走两步,如果没

算法6— 判断两个链表是否相交

问题: 给出两个单向链表的头指针,比如h1、h2,判断链表是否相交,如果不相交返回NULL;如果相交,返回指向第一个相交节点的指针。时间复杂度控制在O(n)。 分析: 如果两单向链表相交的话,一定是Y型相交,不可能出现X型,弄清楚这点后接下来的工作就是: (1)先找到h1,h2的最后一个节点L1和L2,同时记录节点数量a,b;(这里假设 a > b) (2)判断最后一个节点是否相同

如何判断和处理.DS_Store文件

在Mac上经常会遇到.DS_Store文件,.DS_Store是Mac OS保存文件夹的自定义属性的隐藏文件,如文件的图标位置或背景色,相当于Windows的desktop.ini.那么在使用os.listdir(path)等函数对文件进行操作的时候就会出现invalid literal for int() with base 10 错误。这是因为.DS_Store文件也会包含进去

JS奇偶数判断例子

JS奇偶数判断例子

判断字符串是否为Python标识符

import keyword,stringdef Identifier(s):#内置关键字kw = keyword.kwlist # Bifsbifs = dir(__builtins__) s_list = list(s)# 关键字判断if (s in kw) | (s in bifs):return 'keyWord'# 数字、字母、下划线以及开头判断 elif not s_list[0

java编程:命令行输入的三个整数判断是否构成三角形,不能就抛异常。

写一个方法void sanjiao(int a,int b,int c),判断三个参数是否能构成一个三角形,如果不能则抛出 异常IllegalArgumentException,显示异常信息“a,b,c不能构成三角形”, 如果可以构成则显示三角形三个边长,在主方法中得到命令行输入的三个整数,调用此方法,并捕获异常。 附源代码: package 异常;public class Sa