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

2023-11-06

本篇是在 【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;
        }
        else
            return 0;
    }
    else
        return 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 ;
        else
            cout << "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;
        }
        else
            return 0;
    }
    else
        return 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 ;
            else
                cout << "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;
        }
        else
            return 0;
    }
    else
        return 0;
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何判断两条线段是否相交 的相关文章

  • 属性对象什么时候创建?

    由于属性实际上只是附加到程序集的元数据 这是否意味着属性对象仅根据请求创建 例如当您调用 GetCustomAttributes 时 或者它们是在创建对象时创建的 或者 前两个的组合 在由于 CLR 的属性扫描而创建对象时创建 从 CLR
  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • FFMPEG Seeking 带来音频伪影

    我正在使用 ffmpeg 实现音频解码器 在读取音频甚至搜索已经可以工作时 我无法找到一种在搜索后清除缓冲区的方法 因此当应用程序在搜索后立即开始读取音频时 我没有任何工件 avcodec flush buffers似乎对内部缓冲区没有任何
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J
  • A* 之间的差异 pA = 新 A;和 A* pA = 新 A();

    在 C 中 以下两个动态对象创建之间的确切区别是什么 A pA new A A pA new A 我做了一些测试 但似乎在这两种情况下 都调用了默认构造函数 并且仅调用了它 我正在寻找性能方面的任何差异 Thanks If A是 POD 类
  • 编译的表达式树会泄漏吗?

    根据我的理解 JIT 代码在程序运行时永远不会从内存中释放 这是否意味着重复调用 Compile 表达式树上会泄漏内存吗 这意味着仅在静态构造函数中编译表达式树或以其他方式缓存它们 这可能不那么简单 正确的 他们可能是GCed Lambda
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 如何构建印度尼西亚电话号码正则表达式

    这些是一些印度尼西亚的电话号码 08xxxxxxxxx 至少包含 11 个字符长度 08xxxxxxxxxxx 始终以 08 开头 我发现这个很有用 Regex regex new Regex 08 0 9 0 9 0 9 0 9 0 9
  • GDK3/GTK3窗口更新的精确定时

    我有一个使用 GTK 用 C 语言编写的应用程序 尽管该语言对于这个问题可能并不重要 这个应用程序有全屏gtk window与单个gtk drawing area 对于绘图区域 我已经通过注册了一个刻度回调gtk widget add ti
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 将 viewbag 从操作控制器传递到部分视图

    我有一个带有部分视图的 mvc 视图 控制器中有一个 ActionResult 方法 它将返回 PartialView 因此 我需要将 ViewBag 数据从 ActionResult 方法传递到 Partial View 这是我的控制器
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐

  • 半导体制程发展史

    半导体制程发展史 大杀器级别文献 摘要 半导体制造的工艺节点 涉及到多方面的问题 如制造工艺和设备 晶体管的架构 材料等 分析半导体制造的工艺节点发展历程 其实就是在回顾半导体大咖的统治史 首先 技术节点 诸如台积电16nm工艺的Nvidi
  • 函数式编程-Stream流学习第二节-中间操作

    1 Stream流概述 java8使用的是函数式编程模式 如同它的名字一样 它可以用来对集合或者数组进行链状流式操作 让我们更方便的对集合或者数组进行操作 2 案例准备工作 我们首先创建2个类一个作家类 一个图书类 package com
  • STL(标准模板库)专题

    STL 标准模板库 专题 STL主要分为分为三类 容器 STL主要分为分为三类 algorithm 算法 对数据进行处理 解决问题 步骤的有限集合 container 容器 用来管理一组数据元素 Iterator 迭代器 可遍历STL容器内
  • 【C++】实现一个日期计算器

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 日期计算器的功能 二 获取每个月的天数 三 Date类
  • python答题系统的代码_答题辅助python代码实现

    本文实例为大家分享了答题辅助python具体代码 供大家参考 具体内容如下 from screenshot import pull screenshot import time urllib request try import Image
  • EasyPoi 导出表格并设置表头

    EasyPoi 导出表格 EasyPoiUtil 工具类 设置表头 NewExcelExportStylerDefaultImpl 工具类 VO实体类 对应的是表的列名 Controller 1 未设置表头版本 Controller 2 设
  • hp服务器能不能装win7系统,惠普 HPC0Q07PA可不可以装windows7系统_惠普 HPC0Q07PA怎么安装win7系统-win7之家...

    刚买了一台惠普 HPC0Q07PA笔记本电脑 想安装windows7系统 但不知道能不能安装 也不知道装完win7系统之后系统运行的流畅不流畅 小编特意查了下惠普 HPC0Q07PA笔记本的相关信息 跟大家分析下这个能不能安装win7系统
  • 点云的关键点检测-传统方法总结

    三维点云的关键点检测可以通过以下步骤实现 1 寻找局部区域 从点云中选择一个局部区域 2 估计曲率和法线 对局部区域进行曲率估计 并计算法向量 3 计算关键点 使用曲率和法线信息来计算点云的关键点 这可以通过计算曲率极值点 曲率变化最大点或
  • Vue里使用Element UI的Tabs時el-tab-pane的隱藏和顯示

    1 效果圖 隱藏相關項后
  • tensorflow与tflearn的安装时numpy无法更新问题

    对于老司机来说 这都不是事 但对于初学者来说 在安装看到python里import tflearn 在安装tensorflow还真遇到了问题 电脑 mac python版本2 7 直接运行 sudo pip install tensorfl
  • Linux系统中如何查看TCP连接数

    这篇文章主要为大家展示了 Linux系统中如何查看TCP连接数 内容简而易懂 条理清晰 希望能够帮助大家解决疑惑 下面让小编带领大家一起研究并学习一下 Linux系统中如何查看TCP连接数 这篇文章吧 一 查看哪些IP连接本机 netsta
  • raid配置ssd为缓存_群晖SSD缓存有什么用?

    作用 SSD 缓存功能 使用户可以通过添加 SSD 提高 Synology NAS 上的随机访问性能 功能模式 只读缓存 使用此类型的 SSD 缓存时 只会将经常访问的数据存储在 SSD 缓存中以提高随机读取速度 因为 SSD 不涉及任何数
  • stm32 IAP APP 相互跳转实验 (keil4 jlink STM32F407ZE)

    1 实验目标 STM32 IAP学习时 希望有一个快捷的方式去实验IAP与APP之间的相互跳转 1 验证IAP跳转至APP 2 验证APP通过软件reset跳转至IAP 避免再一开始就实验完整的IAP过程 编写BootLoader 编写 A
  • flutter 高德地图 amap_flutter_location 隐私合规校验失败

    flutter 高德地图 amap flutter location 隐私合规校验失败 提醒 ios版本他的最新库是没有办法使用的 如果你的项目需要使用到iOS版本 请使用下面的路径 https github com yangsiyi41
  • 微信开发(js-sdk)中遇见的各种问题

    微信开发的准备工作 不熟 不是我来搞的 copy一下别人和官方的 1 绑定域名 先登录微信公众平台进入 公众号设置 的 功能设置 里填写 JS接口安全域名 备注 登录后可在 开发者中心 查看对应的接口权限 2 引入js文件 在需要调用JS接
  • 动态路由协议RIP配置实战

    1 RIP简介 RIP是一种基于距离矢量 Distance Vector 算法的协议 它使用跳数 Hop Count 作为度量值来衡量到达目的地址的距离 在RIP网络中 RIP协议要求网络中每一台路由器都要维护从自身到每一个目的网络的路由信
  • Kettle-动态数据链接,使JOB得以复用

    动态数据连接 使JOB得以复用 背景 移动执法系统在目前的主要的部署策略为1 N的方式 即总队部署一套 地市各部署一套 且基本都在环保专网 各地市的业务数据需要推送到总队系统 以便总队系统做整体的监督 决策 在整个数据对接过程中 基于Ket
  • Matlab导入txt文件

    有三种常见的方式 1 A importdata filename txt 则A就是n m的矩阵了 2 load filename txt 这样也是载入n m的矩阵 3 在MATLAB的work文件夹下 选择想要导入的数据 用右键import
  • 前端系列-1 HTML+JS+CSS基础

    背景 前端系列会收集碎片化的前端知识点 作为自己工作和学习时的字典 欢迎读者收藏和使用 笔者是后端开发 前端涉猎不深 因此文章重在广度和实用 对原理和性能不会过多深究 1 html 1 1 html5网页结构
  • 如何判断两条线段是否相交

    本篇是在 C 笔记 如何判断2个线段相交 的基础上加上自己的理解和实践总结出的判断两线段是否相交的方法 判断两条线段是否相交 先附上判断函数 bool judge int Ax1 int Ay1 int Ax2 int Ay2 int Bx