凸包GiftWrapping GrahamScan 算法实现
开始
游戏内有需求做多边形碰撞功能,但是接入box2d相对游戏的需求来说太重度了。所以准备自己实现碰撞。
确定多边形,必然要用到凸包的算法。在github上也找到了一些lua实现,但是这里的算法没有考虑多点共线的问题。所以准备自己实现
准备
这里提到的所有凸包,都指的平面上的。
- 思路
凸包的具体定义,这里不赘述。一种通俗的说法,在木板上钉钉子,我们用一根麻绳绑住一个外面的钉子然后拉着麻绳绕所有钉子一圈这个麻绳围成的圈最后也构成了钉子组成的点集的凸包。
其实这种说法,和GiftWrapping算法的实现也有点异曲同工的感觉。 也就是先确定一个最边缘的点A,然后逆时针顺序寻找下一个与A构成的向量在逆时针方向上旋转角度最小的点。如果寻找到下一个点B,则继续用B点做基础点,寻找下一个点。直到寻找到的点为A,才会完成。
这里借用一下booble的图,画图好麻烦
了解更多GiftWrapping点这里,只不过这里的图示显示的是顺时针确定点的
- 寻找下一个逆时针方向旋转角度最小的点
虽然可以直接通过两点计算出构成的向量的角度,然后进行排序比较,但是性能太差了。这里主要是用到向量叉积,因为不需要知道确定的旋转角度,只要能比较大小就可以了
向量叉积的特性:向量A乘以向量B,如果结果为正,则A逆时针旋转向B,则A向量相对于B逆时针方向旋转角度更小;否则为B更小; 如果为0,则共线。这里必须保证的是A旋转到B的角度必须小于180,否则会出错。这也就是为什么一开始要选一个最边缘的点做基础点的原因。
- 共线的问题
如果两个向量叉积的结果为0,则两个向量共线了。因为这里只是确定凸多边形,而距离近的点必然是在基础点与较远点组成的边上,所以舍弃近距离点
实现
- 获取第一个基础点
这里获取最左点,即X最小的点。如果又多个,取这些点中,y最小的点
local function getLeftIndex(points)
local size = #points
local leftIndex = 1
for i=2,size do
if points[i].x < points[leftIndex].x
then
leftIndex = i
end
if points[i].x == points[leftIndex].x
and points[i].y < points[leftIndex].y
then
leftIndex = i
end
end
return leftIndex
end
- 比较一个哪个点与基础点形成的向量逆时针旋转更小
这里不多说,注释写的很明确了
--叉积
local function cross(p1,p2,p3)
return (p2.x - p1.x)*(p3.y - p1.y)
- (p2.y - p1.y)*(p3.x - p1.x)
end
--距离
local function longer(startP,endP1,endP2)
return ((endP2.x - startP.x)^2 + (endP2.y - startP.y)^2)
- ((endP1.x - startP.x)^2 + (endP1.y - startP.y)^2)
> Deviation
end
--判断(startP,midP)组成向量 a 是否顺时针旋转一个在 [0,180)区间的角度 β 后能与(startP,checkP)组成的向量 b 共线
--如果β 在(0,180)范围,则返回true
--如果β == 0 若,|b| > |a| 则,返回true 注意:如果midp 和 checkP是在误差范围内的相同点,返回的是false
local function isBetterVertice(startP,midP,checkP)
local crossResult = cross(startP,midP,checkP)
--crossResult0 则,逆时针
-- =0 则,共线
if crossResult < 0 then
return true
end
if crossResult < Deviation
and longer(startP,midP,checkP)
then
return true
end
return false
end
- 完成GiftWrapping算法
local function giftWrapping(points)
local pointCount = #points
if pointCount < 3 then return nil end
local leftIndex = getLeftIndex(points)
local preIndex = leftIndex
local hull = {}
repeat
table.insert(hull,#hull+1,points[preIndex])
local bestIndex = 1
for i=2,pointCount do
if bestIndex == preIndex
or isBetterVertice(points[preIndex],points[bestIndex],points[i])
then
bestIndex = i
end
end
preIndex = bestIndex
until (preIndex == leftIndex)
return hull
end
- 完整代码在这里
这个代码里顺带实现了GrahamScan,因为这个算法最麻烦的是确定一最左基础点后的剩余点按逆时针角度排序。但是排序要用的compare 方法,之前用到的isBetterVertice 完全可以胜任这个功能,就顺手写出来了。 GrahamScan相关
- 其他
如有错误多包涵,轻喷
之后开始记录一下碰撞的东西,主要是多边形碰撞以及圆与多边形碰撞
http://www.cnblogs.com/boliu/p/4109120.html
凸包GiftWrapping GrahamScan 算法实现的更多相关文章
- 计算几何 二维凸包问题 Andrew算法
凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把全部点排序.依照第一keywordx第二keywordy从小到大排序,删除反复 ...
- 二维凸包 Graham扫描算法
题目链接: http://poj.org/problem?id=1113 求下列点的凸包 求得凸包如下: Graham扫描算法: 找出最左下的点,设为一号点,将其它点对一号点连线,按照与x轴的夹角大小 ...
- 凸包Graham Scan算法实现
凸包算法实现点集合中搜索凸包顶点的功能,可以处理共线情况,可以输出共线点也可以不输出而只输出凸包顶点.经典的Graham Scan算法,点排序使用极角排序方式,并对共线情况做特殊处理.一般算法是将共线 ...
- 计算几何--求凸包模板--Graham算法--poj 1113
Wall Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28157 Accepted: 9401 Description ...
- poj 2187 凸包加旋转卡壳算法
题目链接:http://poj.org/problem?id=2187 旋转卡壳算法:http://www.cppblog.com/staryjy/archive/2009/11/19/101412. ...
- 《Algorithms算法》笔记:元素排序(4)——凸包问题
<Algorithms算法>笔记:元素排序(4)——凸包问题 Algorithms算法笔记元素排序4凸包问题 凸包问题 凸包问题的应用 凸包的几何性质 Graham 扫描算法 代码 凸包问 ...
- Andrew算法求二维凸包-学习笔记
凸包的概念 首先,引入凸包的概念: (有点窄的时候...图片右边可能会被吞,拉开图片看就可以了) 大概长这个样子: 那么,给定一些散点,如何快速地求出凸包呢(用在凸包上的点来表示凸包) Andrew算 ...
- POJ 1113 Wall 求凸包的两种方法
Wall Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 31199 Accepted: 10521 Descriptio ...
- POJ 1113 Wall(计算几何の凸包)
Description Once upon a time there was a greedy King who ordered his chief Architect to build a wall ...
随机推荐
- Jenkins 环境搭建
本文为jenkins入手教程,全文分为 jenkins安装.系统管理(配置全局安全.全局工具配置.管理插件).创建项目(同时创建证书),管理视图,jenkins 客户端,执行构建.查看任务历史 一.j ...
- 纹理混合遇到的问题 pre-multiplying OpenGL Android iOS
纹理混合遇到的问题 pre-multiplying OpenGL Android iOS Alpha-blending pre-multiplying of texture OpenGL Androi ...
- pdf.js跨域问题的分析
最近在做公司业务时,需要在线浏览pdf.在现代浏览器中, 均可直接浏览pdf文件,无兼容性问题.但公司的业务线需要支持到ie8. 经过自己的搜索调研, pdf.js比较适合.pdf.js兼容到ie9, ...
- Oracle日期查询:季度、月份、星期等时间信息
--oracle有关时间信息 Select to_char(sysdate,'Q') from dual;--指定日期的季度 Select to_char(sysdate,'MM') from dua ...
- 微信原图泄露的只能是 Exif ,你的隐私不在这!!!
版权声明: 本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有. 每周会统一更新到这里,如果喜欢,可关注公众号获取最新文章. 未经允许,不得转载. 序 最近很多公众号都推送了关 ...
- 又想起Solaris
想起曾几何时,学习的第一个UNIX-like操作系统.只可惜,从来都是在此操作系统上用C语言编程,而没有用过Sun公司的java. 又几何时,Sun公司慢慢不行了.再后来过了几年,Sun公司把Ultr ...
- 快速排序/快速查找(第k个, 前k个问题)
//快速排序:Partition分割函数,三数中值分割 bool g_bInvalidInput = false; int median3(int* data, int start, int end) ...
- JS自定义对象以及相关成绩系统完整案例演示
[自定义对象] 1.基本概念 ①对象是拥有一系列无无序属性和方法的集合 ②键值对:对象中的数据,用以键值对的形式存在,对象的每个属性和方法,都对应一个键值,以键取值 ③属性:描述对象特征的一系列变量称 ...
- 获取windows任务栏高度的方法
方法一: TRect rt; SystemParametersInfo(SPI_GETWORKAREA, , &rt, ); //任务栏在下面的高度 int y = ::GetSystemMe ...
- 转:【Java集合源码剖析】Java集合框架
转载轻注明出处:http://blog.csdn.net/ns_code/article/details/35564663 Java集合工具包位于Java.util包下,包含了很多常用的数据结构, ...