拉绳算法(漏斗算法)平滑路径
文章以Recast-Detour(JAVA版本)中的String Pulling作为学习研究的基本源码
JAVA版本中的方法名称为:findStraightPath() 方法
目录
算法概述
上图为三角形导航网格,S为寻路起点,End为寻路终点。
该图为基础A星算法寻路后的多边形路径,其中A星算法是以三角形边中点作为距离运算的迭代点的。
该图为漏斗算法优化后的路径点,最终为S,D,G,End。可以明显的看出基础A星在非规整导航网格中的路径结果是不平滑的,有种左右摇摆的感觉,而漏斗算法就是解决路径平滑问题的。
算法详解
所谓漏斗,就是设定两个边界包围向量,然后去迭代路径多边形,如果迭代的过程中,这两个边界包围向量可以不断缩小,证明这些路径多边形是可以直线联通的,这就是所谓的拉绳。而一旦出现了边界向量的交叉,则证明出现了拐角点。
- S为起始点,序号①到⑨为A星寻路的结果多边形路径。End为终点。
- 初始多边形为①,下一个路径为②,①②之间的连接边是CB。
- 初始两个空间范围向量,图中的SB,SC。为了方便,下面称SB为“范围右边界”,SC为“范围左边界”。
- ②和③的临边是CE,根据CE端点构造新的“范围左右边界”SC、SE。后续的算法就是不断的迭代对比,新边界和旧边界的关系。
“范围左右边界”并不是随意定义的,是需要遵循规则的。在DETOUR中,一个多边形的边采用的逆时针存储方式,例如多边形①,三点的存储方式为,CBA,这是严格控制的。而两个边界向量,在区分左右边界的时候,是根据两个相邻多边形公共边的方向顺序来定的。
- 确定左右边界的时候,是根据公共边在“初始多边形”中的边端点顺序来的。
- 从①到②,①就是“起始多边形”,DETOUR中称为“From”,②就是“目的多边形”,DETOUR中称为“To”。
- 例如,①②的公共边为CB,CB在①中的定义顺序,按照逆时针来,C就是左边界点,B就是右边界点。同理,③④的公共边为DE,DE在③中的逆时针顺序为,D就是左边界点,E就是右边界点。
- 上图是处理多边形④到⑤的漏斗情况。
- 根据之前的规则,公共边为FE,且F为左边界点,E为右边界点。
- 在经过③到④后,此时的左边界为SD,右边界为SE。(漏斗算法介绍完就明白,这里③到④的结果为什么是这个了)
- 所以此时漏斗算法,就是去比较SE,SF和旧边界SD,SE的位置关系。
此时产生两条规则:
- SE和SE是重合的,不需要任何修改,这个很容易理解。
- SF在SD的右侧(可以理解为外侧),同时D,F是左边界点,此时不需要更新。
- 此时是⑤到⑥的漏斗处理:公共边为FG,且F为左边界点,G为右边界点。
- 此时对比SE和SG,发现SG在SE的右侧,且已经越过了左边界SD的范围,那么说明在A星结果路径的约束下,S到G之间是不能直线联通的,此时就产生了拐角点D。
当找到拐角点之后,将拐角点加入到结果路径点集中,且以当前拐角点为起始点,重复上述过程,直到找到终点。总结规则如下:
- 已经确定好的左右边界向量,称为“已确定左右边界向量”。
- 算法迭代过程中,需要新对比的左右边界点所形成的向量,称为“对比左右边界”。
- 当“对比左右边界”在“已确定左右边界”包围范围内的时候,更新“确定左右边界”为“对比左右边界”。
- 当“对比左边界”在“已确定左边界”的右侧(外侧)。或者,“对比右边界”在“已确定右边界”的左侧(外侧)时,无需更新。
- 当“对比左边界”在“已确定右边界”的左侧(外侧)。或者,“对比右边界”在“已确定左边界”的右侧(外侧)时,此时,产生拐角点。
终点又是一种特殊情况:
- 图中END为终点,在多边形⑤内。
- 在经历多边形④到⑤的漏斗计算后,此时的“确定左右边界”为SD,SE。
- 如图,最终结果,D肯定是一个拐角点,因为不存在S到End之间有联通直线路径。
- 但是,上图说明从④到⑤漏斗计算后,上下边界仍旧是SE和SD。
- 此时,算法在多边形⑤中找到End终点的时候,会同时设定End点为新的“对边左边界点”和“对比右边界点”。即SEnd向量同时为“对比左右边界向量”
- 按照漏斗算法流程,SEnd作为“对比右边界”时,其在“确定右边界”SE的右侧,且在“确定左边界”SD的右侧(外侧),所以D被解析为拐角点。
算法详细步骤
- 依赖上层寻路的多边形结果集合。例如例子中的多边形①到⑨。
- 进而得到得到①②的公共边,“左右边界点”。以当前起点为向量起点,“左右边界点”为向量终点,构造出两个“左右边界向量”。
- 继续向下迭代,得到②③的公共边,进而得到新的“左右边界点”,仍旧以起点作为向量起点,构建两个新的“对比左右边界向量”。
- 对比最新的两个“对比左右边界向量”和之前的两个“左右边界向量”,去更新迭代到当前多边形后确定最新的漏斗的两个边界向量。同时可能会产生拐角点。
- 一旦出现拐角点,则将当前拐角点加入到结果路径点集中,同时以当前拐角点作为新的迭代路径起点,重复上述的过程。
- 所有细节规则参考上述的算法详解。
算法思考
从算法的角度思考,漏斗平滑路径是完全基于上层寻路算法的,且依赖于上层寻路算法的多边形寻路结果。如下图所示:
- 假设局部导航网格中三角形CDF也是可以直接通过的。
- 但是上层寻路算法从S到End的寻路路径仍然是①到⑨。
- 寻路之后的“漏斗算法”平滑依然是:SD,DG,GEnd。
- 但是,可以直观的看出,从S到G是完全可以直线通过,而不需要拐角点D的。
造成上述问题的原因,并不是“漏斗算法”本身有问题,而正是证明了“漏斗”平滑是完全依赖于上层寻路结果的。多边形CDF可以通过,但是上层寻路的结果集中没有该多边形,所以“漏斗”也不可能去主动搜索上层寻路中没有出现的多边形。由此可见,“漏斗”平滑在广义上是有局限性的。