CG2017 PA2-1 Shortest Path in The Room (房间中的最短路径)
1. 前置知识
- 计算几何算法:Triangulation,详见教材 3 多边形三角剖分:画廊看守(3 Polygon Triangulation: Guarding an Art Gallery)
- DCEL
这里给到必要观看的视频课程章节,这些内容对理解和实现 Triangulation 算法至关重要,标记有绿色√为必看章节:
2. 思路分析
关于这道题的思路分析,笔者在小破站上面发布了系列讲解视频,相关内容视频都有涉及,大家可以观看相关视频,这里就不再赘述:
3. 伪代码
※ 这部分的伪代码是笔者自己翻译的,所以和中文教材上面有些许不同
3.1 单调多边形拆分
// 单调多边形拆分主算法
Algorithm MAKEMONOTONE(P)
算法 MAKEMONOTONE(P)
Input. A simple polygon P stored in a doubly-connected edge list D.
输入:用双向边链表D表示的简单多边形
Output. A partitioning of P into monotone subpolygons, stored in D.
输出:拆分后的多个单调多边形,用D表示
1. Construct a priority queue Q on the vertices of P, using their y-coordinates as priority. If two points have the same y-coordinate, the one with smaller x-coordinate has higher priority.
创建一个优先列队Q,以Y值大的为更高优先级,把所有顶点存储到Q中。如果两个顶点的Y相同,则X越小的优先级越高。
2. Initialize an empty binary search tree T.
初始化一个空的二叉搜索树T。
3. while Q is not empty
只要Q不为空:
4. do Remove the vertex vi with the highest priority from Q.
从Q中移除优先级最高的顶点vi。
5. Call the appropriate procedure to handle the vertex, depending on its type
根据顶点的类型,调用相应的处理函数对该顶点进行处理。
// 各个顶点处理算法
// 处理起始顶点(start vertex)
HANDLESTARTVERTEX(vi)
算法 HANDLESTARTVERTEX(vi)
1. Insert ei in T and set helper(ei) to vi.
将边ei插入到T中,并设置ei的helper为vi。
// 处理终止顶点(end vertex)
HANDLEENDVERTEX(vi)
算法 HANDLEENDVERTEX(vi)
1. if helper(ei-1) is a merge vertex
如果边ei-1的helper是merge vertex
2. then Insert the diagonal connecting vi to helper(ei-1) in D.
在D插入连接vi和helper(ei-1)的内对角线
3. Delete ei-1 from T.
从T中删除边ei-1
// 处理分裂顶点(split vertex)
HANDLESPLITVERTEX(vi)
算法 HANDLESPLITVERTEX(vi)
1. Search in T to find the edge e j directly left of vi.
在T搜索位于vi左边的第一条边ej
2. Insert the diagonal connecting vi to helper(ej) in D.
在D插入连接vi和helper(ej)的内对角线
3. helper(ej)<-vi
设置ej的helper为vi
4. Insert ei in T and set helper(ei) to vi.
将边ei插入到T中,并设置ei的helper为vi。
// 处理普通顶点(regular vertex)
HANDLEMERGEVERTEX(vi)
算法 HANDLEMERGEVERTEX(vi)
// similar to HANDLEENDVERTEX()
1. if helper(ei-1) is a merge vertex
如果边ei-1的helper是merge vertex
2. then Insert the diagonal connecting vi to helper(ei-1) in D.
在D插入连接vi和helper(ei-1)的内对角线
3. Delete ei-1 from T.
从T中删除边ei-1
// similar to HANDLESPLITVERTEX()
4. Search in T to find the edge ej directly left of vi.
在T搜索位于vi左边的第一条边ej
5. if helper(ej) is a merge vertex
如果边ej的helper是merge vertex
6. then Insert the diagonal connecting vi to helper(e j) in D.
在D插入连接vi和helper(ej)的内对角线
7. helper(ej)<-vi
设置ej的helper为vi
HANDLEREGULARVERTEX(vi)
算法 HANDLEREGULARVERTEX(vi)
// left regular vertex
// similar to HANDLEENDVERTEX()
1. if the interior of P lies to the right of vi
如果多边形的内部落在vi的右侧
2. then if helper(ei-1) is a merge vertex
如果边ei-1的helper是merge vertex
3. then Insert the diagonal connecting vi to helper(ei-1) in D.
在D插入连接vi和helper(ei-1)的内对角线
4. Delete ei-1 from T.
从T中删除边ei-1
// similar to HANDLESTARTVERTEX()
5. Insert ei in T and set helper(ei) to vi.
将边ei插入到T中,并设置ei的helper为vi。
// right regular vertex
// similar to the last part of HANDLEMVERTEX()
6. else Search in T to find the edge e j directly left of vi.
反之在T搜索位于vi左边的第一条边ej
7. if helper(ej) is a merge vertex
如果边ej的helper是merge vertex
8. then Insert the diagonal connecting vi to helper(e-j) in D.
在D插入连接vi和helper(ej)的内对角线
9. helper(ej)<-vi
设置ej的helper为vi
3.2 三角拆分
// 对单调多边形进行三角拆分
Algorithm TRIANGULATEMONOTONEPOLYGON(P)
算法 TRIANGULATEMONOTONEPOLYGON(P)
Input. A strictly y-monotone polygon P stored in a doubly-connected edge ist D.
输入:严格相对Y轴得单调多边形P,用DCEL表示
Output. A triangulation of P stored in the doubly-connected edge list D.
输出:三角拆分后得若干个三角形,用DCEL存储
1. Merge the vertices on the left chain and the vertices on the right chain of P into one sequence, sorted on decreasing y-coordinate. If two vertices have the same y-coordinate, then the leftmost one comes first. Let u1, . . . ,un denote the sorted sequence.
将左链和右链上的顶点存储在一个数组中,并序排序。如果两个顶点的Y值相同,则左边(X值小的靠前)。我们用u_1 ...., u_表示这个排序的顶点数组元素。
2. Initialize an empty stack S, and push u1 and u2 onto it.
初始化一个空stack S,把u_1和u_2入栈。
3. for j←3 to n−1
遍历u_到u_n-1:
4. do if uj and the vertex on top of S are on different chains
如果u_j和栈顶的顶点属于不同的链:
5. then Pop all vertices from S.
弹出S中所有的顶点
6. Insert into D a diagonal from uj to each popped vertex, except the last one.
往D中添加连接u_j和每个弹出顶点的内对角线,除了栈底的那个顶点
7. Push uj−1 and uj onto S.
将u_j-1和u_j入栈
8. else Pop one vertex from S.
否则从S中弹出一个顶点
9. Pop the other vertices from S as long as the diagonals from uj to them are inside P. Insert thesediagonals into D. Push the last vertex that has been popped back onto S.
持续从S中弹出顶点,直到u_j和弹出顶点的连线不为内对角线则停止弹出。把这些内对角线放入D中,把最后弹出的顶点放回S中
10. Push uj onto S.
将u_j入栈
11. Add diagonals from un to all stack vertices except the first and the last one.
连接u_n和所有S中的顶点,形成内对角线,但不包括栈顶和栈底的顶点。
4. 可视化结果示例
这里展示一个相对复杂的案例,输入多边形为正交多边形( Orthogonal Polygon ),且为迷宫多边形,用这个案例大家可以体会到整个算法项目可以应用到很多领域,比如机器人寻路,自动驾驶寻路,游戏AI寻路等等,当然这里的算法只是基础算法,想要进行落地还是有不少差距的。
首先,我们给到原始输入多边形,和单调多边形拆分:
其次,进行三角拆分,然后根据拆分得到的三角形进行Dual Graph计算:
最后,在Dual Graph中运用BFS,找到最短路径需要经过的三角形,最后应用Funnel Algorithm计算得到实际的最短路径:
5. 项目代码
个人作业项目代码:Algorithm
1.1.4 Triangulation
Description | Entry method\File |
---|---|
Partionting monotone polygons | List<Face> makeMonotone( List<Vertex> vertices ) |
Triangulation | List<Face> triangulate( List<Face> monotonePolygons ) |
BFS in a dual graph | void BFS( int sizeOfGraph, DualVertex start, DualVertex end ) |
Funnel algorithm | List<Vector> Funnel( DualVertex startTriangle, Vector startPoint, Vector endPoint ) |
Program ( including visualization ) | CG2017 PA2-1 Shortest Path in The Room |
Pedagogical Aid Webpage | Pedagogical Aid of Triangulation |
6. 拓展(Follow-ups)
- 复杂多边形的三角拆分,根据教材上面的描述,本题涉及的算法是可以正确处理任意Subdivision的三角拆分,不仅仅对简单多边形有效;
- 复杂多边形的最短路径问题,既本题允许输入多边形为复杂多边形,同样给到两点,求解两点在多边形内部的最短路径问题;
上一节:CG2017 PA2-2 Find Dancing Partners (寻找舞伴)
下一节:CG2017 PA5-2 FruitNinja(水果忍者)
系列汇总:清华计算几何大作业思路分析和代码实现
7. 参考资料
- Computational Geometry: Algorithms and Applications
- 计算几何 ⎯⎯ 算法与应用, 邓俊辉译,清华大学出版社
- 计算几何 | Computational Geometry
8. 免责声明
※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~
※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;