上回说到我们已经得到了以轮廓线顶点集表示d的可行走区域
但是对于不规则的轮廓线,我们并不能直接在上面寻路,我们希望得到的是一个一个的凸多边形,因为凸多边形内部的任意两点一定是直线可达的,但凹多边形则不满足这一点
现在我们要做的就是把由轮廓线表示的区域分割成多个相邻的凸多变形集合(即最后的多边形网格)
Step 6. Build polygons mesh from contours.
多边形网格的生成大概分这样几个步骤:
a.将初始轮廓线图形进行三角化
b.将上一步得到的三角形进行合并(合并成凸多边形集合)
c.计算凸多边形的邻接关系
其实这一部分做的内容基本上都是纯计算几何算法的应用
首先是三角化,项目中用了耳裁剪(EarClipping)的算法
先说下几个定义:
多边形的对角线:设多边形连续的三个顶点为v1,v2,v3,则v1v3的连线为多边形的对角线
多边形的耳朵:可以理解为不包含其他顶点的一个外凸三角形,对应的v2称为耳尖
如图下中
ABC是一个耳朵
FAB内部包含点D,不是耳朵
CDE不是外凸三角形,不是耳朵
三角化的具体算法流程是:
找到当前多边形的所有耳朵,选择其中对角线最短的耳朵,将对应的耳尖顶点删除,这样N边形就变为了N-1边形
重复这个过程N-3次
具体的代码在这个函数中实现:
static int triangulate(int n, const int* verts, int* indices, int* tris)
三角化之后,其实已经得到了凸多边形集合,但是这样的三角形网格太细碎了,如果直接上a*搜索会导致搜索节点非常多,所以可以将三角形再合并成凸多边形
项目中处理的方式是:
每次枚举所有的多边形对,判断是否可以合成,取其中公共边最长的一对进行合并
重复这个过程直到无法再合并得到新的凸多边形
最后我们再计算出凸多边形之间的邻接关系
具体的做法是:
先得到所有多边形的边,用链式前向星的方式存起来(每个点记录以它为起始点的边)
然后遍历所有边,对每条边设置以它为公共边的多边形的邻接信息
邻接信息是跟多边形的顶点信息存在一起的,在rcPolyMesh这个结构体里
每个区域轮廓对应一个rcPolyMesh,内部包含了这个轮廓内的所有凸多边形
struct rcPolyMesh
{
unsigned short* verts; ///所有多边形的顶点,注意这里顶点的坐标不是实际坐标,而是网格坐标
unsigned short* polys; ///所有凸多边形的信息
///polys数组长度为 多边形数量maxpolys*多边形最大顶点数nvp
///对于每个多边形,前nvp个数存顶点id,后nvp个数存与它相邻的多边形id(n个顶点最多与n个多边形相邻)
};