GJK算法求凸多边形之间的距离
2014-04-18 10:05
597 查看
GJK算法最初用来求三维空间中凸多面体的距离(即最近距离),也因此经常用来做碰撞检测(距离是否为0)。后被推广到n维空间中求凸包之间的距离,此处用来求二维平面上2个凸多边形的距离。
GJK算法首先要解决计算Minkowski和的问题。所谓Minkowski和,指A、B两个集合,令A+B={x+y,其中x属于A,y属于B}即二者的Minkowski和。类似的可以定义负集与Minkowski差。
若A、B为凸多边形,顶点个数分别是n、m,则他们的Minkowski和一定是凸多边形且至多有n+m个顶点。
左上为多边形A、B,假设黑点为原点,三个图分别表示-B、A+B与A-B。A、B之间的点对距离即||x - y||,其中x属于A,y属于B;而A、B之间的距离就是||x-y||的最小值。因此,A、B之间的距离就是其Minkowski差A-B中的最小元素,这个最小指的是模最小,实际上就是距离原点的距离。因此,2个凸多边形的距离转化为点到凸多边形的距离,点指的是原点,凸多边形指的是原题中的2个凸包的Minkowski差。
Minkowski和的算法如下,将A、B的边按逆时针方向拆成向量(顺时针实际上也可以),如上图可以得到6个向量。将这些向量按极角排序,然后依次首尾相连即可得到凸包。该算法找自英文维基,感谢谷歌。
上述算法只是得到了和的形状与相对位置(因为首尾相连时出发的基点是原点),实际上该凸包还需做一个平移才能得到正确的坐标。如果排序时极角是取0~360度范围(NOTE:不必显示的求出极角,用先象限后叉积的方法排序),则求出A、B各自的最下最左点,将其坐标相加作为出发的基点即可。代码实现上这一点其实非常容易完成。
求出Minkowski差之后(求差与求和本质是一样的),剩下的就是求点到凸多边形的距离,这个问题又转化为求点到边的距离。一个凸多边形有n条边,点到这n条边的距离的最小值就是点到凸多边形的距离。而且,点到边的距离是具有确定单调性的,因此运气好的话不需要求出所有边的距离,只需扫描到极小值即可。点到边的距离也就是点到线段的距离,利用叉积计算、点积进行判断,很容易求得。
上述算法其实不是GJK算法,因为所求为凸多边形,而GJK算法可以用来求曲线凸包之间的距离(此情况下是一个数值逼近过程)。简单描述一下GJK的迭代过程,除了初始情况下,每一步迭代时均已求得凸包边缘上的3个点构成一个三角形Tk,然后求指定点p距离Tk最近的点,记作q,再将凸包投影到pq。qp方向上最远的投影点所对应的凸包上的点记作w,最后将Tk的3个点舍去1个,然后加上w形成新的Tk+1。最开始的3个点哪里来的?似乎可以随便选边缘上的3个点,最后应该可能也许大概一定可以迭代到结果,只是影响迭代次数而已。
上述GJK算法来自《计算机图形学几何工具算法详解》中译本,此书的某些算法有问题,可能是翻译的问题。
用GJK算法的Minkowski和可以解决POJ3608。凸多边形的距离也可以使用旋转卡壳法解决,但GJK算法应该更容易实现一些。
GJK算法首先要解决计算Minkowski和的问题。所谓Minkowski和,指A、B两个集合,令A+B={x+y,其中x属于A,y属于B}即二者的Minkowski和。类似的可以定义负集与Minkowski差。
若A、B为凸多边形,顶点个数分别是n、m,则他们的Minkowski和一定是凸多边形且至多有n+m个顶点。
左上为多边形A、B,假设黑点为原点,三个图分别表示-B、A+B与A-B。A、B之间的点对距离即||x - y||,其中x属于A,y属于B;而A、B之间的距离就是||x-y||的最小值。因此,A、B之间的距离就是其Minkowski差A-B中的最小元素,这个最小指的是模最小,实际上就是距离原点的距离。因此,2个凸多边形的距离转化为点到凸多边形的距离,点指的是原点,凸多边形指的是原题中的2个凸包的Minkowski差。
Minkowski和的算法如下,将A、B的边按逆时针方向拆成向量(顺时针实际上也可以),如上图可以得到6个向量。将这些向量按极角排序,然后依次首尾相连即可得到凸包。该算法找自英文维基,感谢谷歌。
上述算法只是得到了和的形状与相对位置(因为首尾相连时出发的基点是原点),实际上该凸包还需做一个平移才能得到正确的坐标。如果排序时极角是取0~360度范围(NOTE:不必显示的求出极角,用先象限后叉积的方法排序),则求出A、B各自的最下最左点,将其坐标相加作为出发的基点即可。代码实现上这一点其实非常容易完成。
求出Minkowski差之后(求差与求和本质是一样的),剩下的就是求点到凸多边形的距离,这个问题又转化为求点到边的距离。一个凸多边形有n条边,点到这n条边的距离的最小值就是点到凸多边形的距离。而且,点到边的距离是具有确定单调性的,因此运气好的话不需要求出所有边的距离,只需扫描到极小值即可。点到边的距离也就是点到线段的距离,利用叉积计算、点积进行判断,很容易求得。
上述算法其实不是GJK算法,因为所求为凸多边形,而GJK算法可以用来求曲线凸包之间的距离(此情况下是一个数值逼近过程)。简单描述一下GJK的迭代过程,除了初始情况下,每一步迭代时均已求得凸包边缘上的3个点构成一个三角形Tk,然后求指定点p距离Tk最近的点,记作q,再将凸包投影到pq。qp方向上最远的投影点所对应的凸包上的点记作w,最后将Tk的3个点舍去1个,然后加上w形成新的Tk+1。最开始的3个点哪里来的?似乎可以随便选边缘上的3个点,最后应该可能也许大概一定可以迭代到结果,只是影响迭代次数而已。
上述GJK算法来自《计算机图形学几何工具算法详解》中译本,此书的某些算法有问题,可能是翻译的问题。
用GJK算法的Minkowski和可以解决POJ3608。凸多边形的距离也可以使用旋转卡壳法解决,但GJK算法应该更容易实现一些。
相关文章推荐
- 推荐算法之向量之间的距离
- java通过经纬度计算两个点的之间的距离的算法
- 游戏开发中的数学和物理算法(3):点之间的距离
- 算法竞赛入门经典: 第四章 函数与递归 4.1求两点之间距离
- java通过经纬度计算两个点的之间的距离的算法 (单位:米)
- 游戏开发中的数学和物理算法(3):点之间的距离
- 游戏开发中的数学和物理算法(3):点之间的距离
- 微软算法100题11 求二叉树中两节点之间的最大距离
- [python]My Unique JsonDiff算法——如何计算2个json串之间的差距并Diff出来(一):编辑距离(Levenshtein)算法
- 武汉科技大学ACM :1006: 零起点学算法25——求两点之间的距离
- 趣味算法-城市之间最短总距离
- 用于评估实体之间距离的聚会算法
- 城市之间的最短总距离(最小生成树算法)
- 获取两经纬度之间距离;经纬度移动多少米移动的的度数算法;
- java通过经纬度计算两个点的之间的距离的算法
- 两个面之间的最短距离算法(记录)
- 计算两个经纬度之间的距离(python算法)
- [Game] 游戏开发中的数学和物理算法:点之间的距离
- java通过经纬度计算两个点的之间的距离的算法
- Javascript 地图经度纬度之间的距离的算法(轉)