黑马程序员技术交流社区
标题:
A* 算法计算导航路径(最短路径)
[打印本页]
作者:
aisini
时间:
2014-7-29 19:50
标题:
A* 算法计算导航路径(最短路径)
导航路径的计算,一般用 Dijkstra 算法和 A* 算法。
Dijkstra 算法是全局遍历,确保运算结果一定是最短路径。
A* 算法是策略寻路,不保证一定是最短路径。
Dijkstra 需要载入全部数据,遍历搜索。(也可以分层计算,分层载入)
A* 算法可以根据需要,分部分块载入地图数据。
本代码是基于 A* 算法搜索最短路径的一个演示程序。
附件源码中的道路属性类参考了高德导航地图的数据结构。
/// <summary>
/// 搜索最短路径
/// </summary>
/// <param name="starts">起始节点描述序列</param>
/// <param name="endPt">终止点坐标值</param>
/// <param name="endsID">终止节点ID序列</param>
/// <param name="avoidsID">避开节点ID序列</param>
/// <returns></returns>
public int[] CreateShortPath(ExtendLine startELine, ExtendLine endELine, int[] avoids)
{
ExtendLine sl = startELine;
ExtendLine el = endELine;
// 检测入口参数的合法性
// ...
// 检查起始节点内是否包含终止节点,如果包含,直接返回此点
Debug.Assert( sl.IsOut == false && el.IsOut == true );
if (( sl.FLine != null && el.FLine != null && el.FLine.TNodeID == el.FLine.FNodeID ) ||
( sl.FLine != null && el.TLine != null && sl.FLine.TNodeID == el.TLine.FNodeID ))
return new int[] { sl.FLine.TNodeID };
if (( sl.TLine != null && el.FLine != null && sl.TLine.TNodeID == el.FLine.FNodeID ) ||
( sl.TLine != null && el.TLine != null && sl.TLine.TNodeID == el.TLine.FNodeID ))
return new int[] { sl.TLine.TNodeID };
// 初始化搜索队列
AStarQueue queue = this.InitSearchQueue( sl, el, avoids );
// 搜索最短路径
int pos = this.ShortSearch( queue, el.VLine.Points[1] );
// 返回路径信息
return this.TracePath( queue, pos );
}
/// <summary>
/// 初始化搜索队列
/// </summary>
private AStarQueue InitSearchQueue(ExtendLine sl, ExtendLine el, int[] avoidsID)
{
// 创建队列
AStarQueue queue = new AStarQueue( _gTab );
// 起始点加入开放列表
Debug.Assert( sl.FLine != null || sl.TLine != null );
if ( sl.FLine != null )
{
Debug.Assert( sl.FLine.TNodeID > 0 );
GraphNode gn = GraphNode.SearchByID( _gTab, sl.FLine.TNodeID );
float h = GeoMath.Distance( gn.Point, el.VLine.Points[1] );
queue.SetOpen( gn.NodePos, -1, sl.FLine.Length, h );
}
if ( sl.TLine != null )
{
Debug.Assert( sl.TLine.TNodeID > 0 );
GraphNode gn = GraphNode.SearchByID( _gTab, sl.TLine.TNodeID );
float h = GeoMath.Distance( gn.Point, el.VLine.Points[1] );
queue.SetOpen( gn.NodePos, -1, sl.TLine.Length, h );
}
// 终止点加入终止列表
if ( el.FLine != null )
{
Debug.Assert( el.FLine.FNodeID > 0 );
GraphNode gn = GraphNode.SearchByID( _gTab, el.FLine.FNodeID );
Debug.Assert( ! queue.IsOpen( gn.NodePos ) ); // 起始点不能与终止点重合
queue.SetEnd( gn.NodePos );
}
if ( el.TLine != null )
{
Debug.Assert( el.TLine.FNodeID > 0 );
GraphNode gn = GraphNode.SearchByID( _gTab, el.TLine.FNodeID );
Debug.Assert( ! queue.IsOpen( gn.NodePos ) );
queue.SetEnd( gn.NodePos );
}
// 避开点加入封闭列表
if ( avoidsID != null )
{
foreach ( int nid in avoidsID )
{
GraphNode gn = GraphNode.SearchByID( _gTab, nid );
if ( queue.IsOpen( gn.NodePos ) )
continue;
else if ( queue.IsEnd( gn.NodePos ) )
continue;
else
queue.SetClose( gn.NodePos );
}
}
// 返回队列
return queue;
}
/// <summary>
/// 在设置好的队列内搜索最短路径
/// </summary>
/// <param name="queue">已设置好起止节点的队列</param>
/// <param name="endPoint">终止点坐标</param>
/// <returns>终止节点的位置(Pos)</returns>
private int ShortSearch(AStarQueue queue, FPoint endPt)
{
// 开始搜索
while ( queue.Min >= 0 )
{
// 当前点加入封闭列表
int curPos = queue.Min;
queue.SetClose( curPos );
GraphNode gnCur = this._gTab[curPos] as GraphNode;
foreach ( GraphLink glnk in gnCur.Links )
{
// 获取连接点
int nextPos = glnk.NodePos;
GraphNode gnNext = this._gTab[nextPos] as GraphNode;
float g = queue.GValue( curPos ) + glnk.Length;
float h = GeoMath.Distance( gnNext.Point, endPt );
if ( ! queue.IsEnd( gnNext.NodePos ) ) // 未达终点
{
// 不在封闭列表
if ( ! queue.IsClose( nextPos ) )
{
// 开放列表内
if ( queue.IsOpen( nextPos ) )
{
if ( g < queue.GValue( nextPos ) )
{
queue.SetOpen( nextPos, curPos, g, h );
}
}
else
{
queue.SetOpen( nextPos, curPos, g, h );
}
}
}
else // 抵达终点
{
queue.SetOpen( nextPos, curPos, g, h );
queue.SetClose( nextPos );
return nextPos;
}
}
}
return -1; // 不可到达
}
/// <summary>
/// 获取路径数据
/// </summary>
/// <param name="queue">已搜出路径的队列</param>
/// <param name="pos">回溯操作的起始点</param>
/// <returns>NodeID, RoadID, NodeID, RoadID, ... , NodeID</returns>
private int[] TracePath(AStarQueue queue, int endPos)
{
// 获取路径
ArrayList idls = new ArrayList();
for ( int pos = endPos; pos >= 0; pos = queue[pos].ParentPos )
{
GraphNode gn = _gTab[pos] as GraphNode;
idls.Add( gn.NodeID );
int parentPos = queue[pos].ParentPos;
if ( parentPos >= 0 )
{
GraphNode pn = _gTab[parentPos] as GraphNode;
foreach ( GraphLink glnk in pn.Links )
{
if ( glnk.NodePos == pos )
{
idls.Add( glnk.RoadID );
break;
}
}
}
}
idls.Reverse();
int[] ids = new int[idls.Count];
idls.CopyTo( ids );
Debug.Assert( this.ValidResult( ids ) );
return ids;
}
复制代码
作者:
rende1991
时间:
2014-7-30 00:39
学习了 努力再努力
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2