简介:

首先给出我的Github页面:ConcaveIntersection
这个开源库基于Unity开发,主要实现了凹多边形之间的相交判断,当然也可以应用于顶点与凹凸包、线段与凹凸包、凸包与凸包之间的相交判断,也就是说,这个方案基本可以解决前面两则文章中的所有多边形判断,效率也非常高,复杂度几乎接近O(n),下面解释原理。

一、扫线法概念

扫线法其实是一种常用的平面空间算法思路,在很多算法中均有应用,例如我的文章Voronoi图和扫线法中就是应用扫线法来实现Voroni图的计算,从而实现三角剖分。扫线法的典型作用是降维,将原本的二维空间数据,转化为一位空间数据,这样可以大大提升计算效率。

如上图,假设存在多边形ABCDEFG,我们在执行运算时,依照从左至右,从下到上的规则,好像有一条扫描线推遍整个相关平面区域,这样的计算方法,就称为扫线法。
所谓的从左到右不难理解,图中的每个顶点都被从左至右排序,而通过这些顶点的垂线将平面划分成了若干区域,这些被划分的区域我们可以称为不同的扫描阶段,因此以上共有A、G、B、F、D、C、E七个阶段。
那么,从下到上代表什么意思?先看下图:

在每一个扫描阶段,我们都会使用一个区域栈来存储当前阶段范围的空间区域划分情况,如上图中的A阶段,此阶段所能代表的空间区域位于经过A点的垂线与经过G点的垂线之间,此部分空间区域被划分又为三块,AB以下的①号区域,AG与AB之间的②号区域,AG以上的③号区域,我们在执行判断时,一般跟从从下到上的规则进行判断,这里就是依次扫过①、②、③号区域。

二、提出目标问题

首先,给出一个问题,如何判断顶点是否包含于简单的凹多边形中?
这里也可以使用前文所述的射线法来解决,不过我们这里介绍扫线法的使用,因为这在后续的凹包相交判断计算中更有价值。
思考:如上所述,我们可以使用扫线的形式划分整个多边形空间,那只要判断顶点在其中的某个空间内,即可认为包含于凹多边形中。
接下来,我们只须完成两件事:
1、分阶段扫线,构建空间划分的区域栈
2、在区域栈中判断是否遭遇了目标顶点

三、基本结构定义

在深入了解扫描规则之前,我们首先需要一些前置条件:

1、我们需要定义Point结构,以及Region结构
2、我们需要按照逆时针顺序存储凹多边形中的顶点,称为顶点列表(point list)
3、我们需要在每个顶点结构保存邻接顶点的引用,构成双向链表
4、由于表示的区域有内外之分,因此定义enum Inout
5、需要一个有序列表(SortedList),用于水平方向排序被扫描顶点,称为扫描列表(sweep list)
6、需要一个区域栈(RegionList),虽然类似栈结构,但是不需要应用先进后出的规则,只需用List存储即可
大概主要结构单元如下:

public class Point2
{public float x;public float y;public Point2 m_left;public Point2 m_right;
}
public enum InOut
{In,Out,
}
public class SlopeRegion
{public Point2 m_start;    //起点public Point2 m_end;      //终点public float m_slope;     //斜率public float m_swY;       //扫描线Y坐标public InOut m_inOut;     //区域内外
}

四、事件定义与扫描规则

为了更方便执行扫描过程中的处理,我们可以参考Voronoi图和扫线法中的做法,将遭遇的不同类型的扫描结果使用不同的事件来表示,这里我们可以使用三种类型的事件:
1、OpenRegion(开启区域)
在扫描到某个顶点时,发现类似A、D点情况,即它的左右邻接点都位于当前点右侧,则说明遭遇一块界定区域的开启。
2、CloseRegion(关闭区域)
当遭遇类似C、E点的情况,即它的左右邻接点均位于当前点左侧,则说明遭遇了一块界定区域的关闭。
3、TurnRegion(转换区域)
当遭遇类似G、F、B的情况,即它的左右邻接点一左一右分布于当前点两侧,则说明遭遇了一块界定区域的转换。

接下来,我们描述上图的每个扫线阶段时,我们预期的区域栈的变化。
A阶段:为了达成前述的①、②、③号区域划分,因此在区域栈中,我们应该预期依次出现[AB、AG]单元结构,两个区域条目可以将垂直空间划分为三部分。相当于在遭遇开启区域时,需要向栈中插入两个区域单元,各自对应左右邻接点。邻接点靠上的区域单元存放在上方。
G阶段:看图中,形成了三个区域,应该预期出现[GF、AB]结构,也就是说,在遭遇转换区域时,需要删除X方向上靠左的邻接点对应的栈单元AG,再加入靠右的邻接点与当前点构成的栈单元。
B阶段:与G阶段类似,删除AB,插入BC,此时栈结构变成[GF、BC]
F阶段:与G阶段类似,删除GF,插入FE,此时栈结构变成[FE、BC]
D阶段:与A阶段类似,插入DE、DC,此时栈结构变成[FE、DE、DC、BC]
C阶段:此时遭遇关闭区域,代表DC、BC所能界定的区域的终结,因此删除DC、BC单元,栈结构变成[FE、DE]
E阶段:与C阶段类似,删除终结区域FE、DE,栈结构清除,扫描完毕

总结一下扫线过程中遭遇三种类型的事件处理:
1、OpenRegion(开启区域)
向栈中插入两个区域单元,各自对应左右邻接点。邻接点靠上的区域单元存放在上方。
2、CloseRegion(关闭区域)
删除以左右两个邻接点开始的栈单元,也即以当前顶点结束的栈单元。
3、TurnRegion(转换区域)
在遭遇转换区域时,需要删除X方向上靠左的邻接点对应的栈单元,再加入靠右的邻接点与当前点构成的栈单元。

五、顶点与凹多边形相交判定规则

至此,我们可以通过每个扫描阶段,完成空间区域的分割,为了达成最终的判定,我们还需要附加2条附加规则。
1、InOut规则:
如果我们遭遇线段时,是以逆时针顺序分别遭遇两个顶点,那么所界定的区域表示外部区域,反则反之。
如A阶段遭遇了AB,即是逆时针遭遇,所以AB以下的区域代表多边形的外部区域,而同时遭遇的AG,由于是顺时针遭遇,其所代表的区域是内部区域。
2、底部优先规则:
判断一个顶点是否在区域内时,依照从下到上的顺序进行判断,只要被包含在某个区域内部,就表示属于当前区域,比对当前区域的InOut参数表示即可完成判断。如果不属于任意一个区域,则默认属于外部。
至此,我们已经可以完成顶点与凹多边形相交关系的判断。需要额外说明的是,在开始的排序过程中,我们可以将目标顶点与凹包顶点一起纳入扫描列表执行排序,而在每次扫描时先行判断是否是目标顶点,不是,则持续维护扫线堆栈,是则使用当前区域堆栈执行区域判断,完成算法过程。

六、凹多边形之间相交判断

在可以扫线判断顶点的情况下,已经非常接近最后的结果,针对凹多边形之间的处理,我们稍微改变一下规则,即:
1、在开始的排序过程中,我们将凹包C1与凹包C2的顶点一起纳入扫描列表执行排序
2、在每个扫线阶段,如果遭遇的是C1中的顶点,则会将其与C2当前的扫线栈执行区域判断,如果在其中,则完成算法退出,如果不在,则将顶点用作C1堆栈的维护,如果遭遇C2的顶点,则会将其与C1当前的扫线栈执行区域判断,如果在其中,则完成算法退出,如果不在,则将顶点用作C2堆栈的维护。

扫线法快速判断凹多边形相交相关推荐

  1. EXCEL表格-矩阵法快速判断异常数据

    ❤关注我,不迷路❤ 点击进入EXCEL综合应用场景专栏 工作中会有时会遇到如下场景:EXCEL中有大量的数字需要校验是否存在错误,有些可能是多打了一个字母,有些可能是多输入了一位小数点,肉眼很难发现问 ...

  2. 【C++】快速判断质数(6的倍数法)、快速获取n以下的质数(欧拉筛)板子

    快速判断质数(6的倍数法)板子 bool judge(int num) {if (num == 2 || num == 3) {return true;}//如果num不在6的倍数附近,则不是素数if ...

  3. 教您快速学会用制表描点连线法画双曲线

    制表.描点.连线法绘制函数是初步认识函数图像的基础,现在教学都是多媒体教学,所以数学老师要掌握几何画板的使用,下面将以绘制[-7,7]闭区间内,y=8/x图像为例介绍制表.描点和连线画双曲线的过程. ...

  4. 入门必看,快速判断mos管封装引脚的三个极和它的好坏

    MOS管,即在集成电路中绝缘性场效应管.MOS英文全称为Metal-Oxide-Semiconductor,即金属-氧化物-半导体,描述了集成电路中的结构,即:在一定结构的半导体器件上,加上二氧化硅和 ...

  5. 计算机主板桥烧坏了怎么办,经验:快速判断主板南、北桥是否损坏

    快速判断南桥已经损坏 下面几个条件一般可以判断为南桥已经击穿和损坏: 1)SB3.3V或5V对地短路或阻值小于80欧姆 2)USB数据线对地短路或对地阻值小于80 3)CMOS跳线中间脚对地短路 4) ...

  6. 第十七届CH32V307多车组头尾双车摄像头传统扫线循迹

    一.传统的扫线循迹,网上的资料繁杂,开源资料或者博客破碎化 1.我于2021年10份正式接触摄像头,在到最终比赛期间,遇到了不少困难和迷惑的地方,接下来我会阐述摄像头小车整个从图像处理到实现循迹的大概 ...

  7. 智能车学习笔记(摄像头组)——基础扫线

    今年第一次搞智能车,刚刚上大一,一切都是摸索着来,趁着放假了就把自己学会的东西梳理一下.第一次写的比较乱,欢迎各位一起学习(我亲爱的队友要加倍努力哈,这几天嗓子疼,不能腾讯会议给你讲了,专门给你写的) ...

  8. 快速判断IC芯片好坏的方法

    快速判断IC芯片好坏的方法 在日常电路维修工作中如何准确判断电路中电源IC芯片的好坏,是修理电视.音响.录像设备的一个重要工作内容,如果判断不准确,不但花费了大量的精力,重点是集成电路中的故障依然存在 ...

  9. 【BZOJ-30391057】玉蟾宫棋盘制作 悬线法

    3039: 玉蟾宫 Time Limit: 2 Sec  Memory Limit: 128 MB Submit: 753  Solved: 444 [Submit][Status][Discuss] ...

  10. 【BZOJ-1127】KUP 悬线法 + 贪心

    1127: [POI2008]KUP Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge Submit: 317  Solved: 1 ...

最新文章

  1. 2021年大数据ELK(十八):Beats 简单介绍和FileBeat工作原理
  2. 条件变量 pthread_cond_wait
  3. C# 系统应用之清除Cookies、IE临时文件、历史记录 转载
  4. ad域帐号登录提示无法处理请求_微软Windows Server之AD域控制器迁移测试方案
  5. 续上篇随笔:陈勇提示做分批载入需要用到的数据
  6. android studio 导入一个已有的android studio project作为lib使用
  7. 道java_请问这道java里的这几个语句是什么意思
  8. 精心整理吐血推荐的AUTOSAR科普介绍材料
  9. 【启智树NOIP模拟】奇偶【卢卡斯定理】【背包】【bitset】
  10. jQ效果:简单的手风琴效果
  11. 跟我学《JavaScript高程3》第一讲,视频课程,课程笔记
  12. JavaScript从入门到放弃 -(三)ES5新增方法及商品查询案例
  13. Maven学习总结(37)——利用GitHub或阿里云OSS对象存储、又拍云、七牛云存储等搭建个人Maven仓库
  14. 金山云服务器e1型,金山云-文档中心-重装系统
  15. 除硬件外 计算机系统不可缺少的,计算机应用基础选择精选100题.doc
  16. 循环、推导式、多重循环
  17. 图像分割之基于阙值的分割方法
  18. 霍格沃兹测试开发学社技术学习笔记之——Python基础笔记
  19. 解决png图片在IE6下的透明问题
  20. Latex论文表格画法及相关技巧

热门文章

  1. 对称密钥和非对称密钥有什么区别,区别在哪里
  2. PHP168整站数据库结构说明,PHP168
  3. [963]Android app代理软件
  4. COPRA算法学习笔记
  5. Ubuntu18.04下部署Honeyd蜜罐(完整过程)
  6. java运行环境(jre)_什么是JRE? Java运行时环境简介
  7. 电力拖动自动控制系统_教授为你解读“电气工程及其自动化”专业类
  8. 心理测量学信度计算机试题,心理测量学试题及答案
  9. 华夏互联十年网站开发经验-只为更专业
  10. 电工与电子技术基础【2】