PathFinder.cpp
Go to the documentation of this file.00001 //*** PathFinder.cpp *** 00002 00003 #include "PathFinder.h" 00004 #include "MemoryPool.h" 00005 #include "PriorityQueueIterator.h" 00006 #include "HashTableIterator.h" 00007 00008 bool PathFinder::PriorityCompareFunction(PathFinder::PathFinderNode* const &a, PathFinder::PathFinderNode* const &b) 00009 { 00010 if (a->nodeScore < b->nodeScore) 00011 { 00012 return true; 00013 } 00014 00015 return false; 00016 } 00017 00018 00019 //*** Constructor *** 00020 00021 PathFinder::PathFinder(): 00022 memoryPool_(1024), 00023 openNodes_(PriorityCompareFunction,1024), 00024 nodes_(1024) 00025 { 00026 00027 } 00028 00029 00030 //*** GetNodeFromCell *** 00031 00032 PathFinder::PathFinderNode* PathFinder::GetNodeFromCell(const PathFinderCell* cell) 00033 { 00034 // See if a node already exists for this cell 00035 HashTableIterator<HashTableKey_Pointer,PathFinderNode*> it(nodes_); 00036 if (it.Find(cell)) 00037 { 00038 // Yes, it exists, so return it 00039 return it.GetCurrent(); 00040 } 00041 00043 PathFinderNode* newnode = memoryPool_.Allocate(); 00044 newnode->costFromStart=0; 00045 newnode->estimatedCostToGoal=0; 00046 newnode->nodeScore=0; 00047 newnode->parent=0; 00048 newnode->cell=cell; 00049 newnode->closed=false; 00050 nodes_.Insert(HashTableKey_Pointer(cell),newnode); 00051 return newnode; 00052 } 00053 00054 00055 00056 //*** BuildPath *** 00057 00058 void PathFinder::BuildPath(PathFinderNode* node, Array<const PathFinderCell*>& path) 00059 { 00060 // Clear any existing path that might be stored 00061 path.Clear(); 00062 00063 // Walk backwards through the nodes, adding each cell to the resulting path 00064 while (node) 00065 { 00066 path.Add(node->cell); 00067 node=node->parent; 00068 } 00069 00070 // Clear the internal lists of nodes 00071 ClearLists(); 00072 } 00073 00074 00075 //*** FindPath *** 00076 00077 bool PathFinder::FindPath(const PathFinderAgent* agent, const PathFinderCell* start, const PathFinderCell* end, Array<const PathFinderCell*>& path, int iterationSafetyLimit) 00078 { 00079 Assert(start,"Invalid start node"); 00080 Assert(end,"Invalid end node"); 00081 if (!start || !end) 00082 { 00083 return false; 00084 } 00085 00086 // Prepare start node 00087 PathFinderNode* startnode=GetNodeFromCell(start); 00088 startnode->costFromStart=0; 00089 startnode->estimatedCostToGoal=start->EstimateCost(agent,end); 00090 startnode->nodeScore=startnode->costFromStart+startnode->estimatedCostToGoal; 00091 openNodes_.Add(startnode); 00092 00093 // Store the best node so far 00094 PathFinderNode* bestNode=startnode; 00095 00096 // Try all nodes on the "open" list 00097 int iterationCount=iterationSafetyLimit; 00098 while (openNodes_.GetItemCount() && (iterationSafetyLimit==0 || iterationCount>0)) 00099 { 00100 // Get top node of priority queue 00101 PathFinderNode* n=openNodes_.Remove(); 00102 Assert(n,"Invalid node!"); 00103 if (!n) 00104 { 00105 return false; 00106 } 00107 00108 // Mark node as being on the closed list 00109 n->closed=true; 00110 00111 // Reevaluate best node so far 00112 if (n->estimatedCostToGoal < bestNode->estimatedCostToGoal) 00113 { 00114 bestNode = n; 00115 } 00116 00117 // Check if this is the target node 00118 if (n->cell==end) 00119 { 00120 // If so, build the path from this node back to the start 00121 BuildPath(n,path); 00122 00123 // Return success 00124 return true; 00125 } 00126 00127 // Go through all the neighbours 00128 for (int i=0; i <n->cell->GetNeighbourCount(agent); i++) 00129 { 00130 const PathFinderCell* ncell=n->cell->GetNeighbour(agent, i); 00131 00132 // Skip if node data is not valid (means no neighbour) 00133 if (!ncell) 00134 { 00135 continue; 00136 } 00137 00138 // Examine the neighbour node 00139 PathFinderNode* nn = GetNodeFromCell(ncell); // The node itself 00140 00141 00142 // If node is on closed list, then skip it 00143 if (nn->closed) 00144 { 00145 continue; 00146 } 00147 00148 float nnCost = n->cell->CalculateCost(agent,nn->cell); // Cost to get from current node to neighbour 00149 float nnTotalCost = n->costFromStart + nnCost; // Total cost from start to get to this node 00150 00151 PriorityQueueIterator<PathFinderNode*> it(openNodes_); 00152 int nnIndex=-1; 00153 if (it.Find(nn)) 00154 { 00155 nnIndex=it.GetCurrentIndex(); 00156 } 00157 00158 00159 // If node is already on open list with a lower cost, then skip it 00160 if ((nnIndex>=0) && nn->costFromStart <= nnTotalCost) 00161 { 00162 continue; 00163 } 00164 00165 // Set node values 00166 nn->parent=n; 00167 nn->costFromStart=nnTotalCost; 00168 nn->estimatedCostToGoal=nn->cell->EstimateCost(agent,end); 00169 nn->nodeScore = nn->costFromStart + nn->estimatedCostToGoal; 00170 00171 00172 // Add to open list 00173 if (nnIndex<0) 00174 { 00175 openNodes_.Add(nn); 00176 } 00177 else 00178 { 00179 openNodes_.Update(nnIndex); 00180 } 00181 00182 } 00183 00184 00185 if (iterationSafetyLimit>0) 00186 { 00187 iterationCount--; 00188 } 00189 } 00190 00191 Assert(iterationSafetyLimit==0 || iterationCount>0,"Iterator safety limit exceeded"); 00192 00193 // We didn't find a path, but we can build one to the closest cell we have 00194 BuildPath(bestNode,path); 00195 00196 return false; 00197 } 00198 00199 00200 00201 //*** ClearLists *** 00202 00203 void PathFinder::ClearLists() 00204 { 00205 // Loop through the main node list and return all elements to the memory pool 00206 HashTableIterator<HashTableKey_Pointer,PathFinderNode*> it(nodes_); 00207 while (it.IsValid()) 00208 { 00209 memoryPool_.Free(it.GetCurrent()); 00210 it.MoveNext(); 00211 } 00212 00213 // Clear each of the lists 00214 nodes_.Clear(false); 00215 openNodes_.Clear(false); 00216 } 00217 00218 00219
Reproduction/republishing of any material on this site without permission is strictly prohibited.
