planners/astar/PL_Astar.cpp

Go to the documentation of this file.
00001 //=========================================================================
00002 //
00003 //  File:  PL_Astar.h
00004 //
00005 //  Created by Shane Schneider
00006 //
00007 //              Base A* Planner. 
00008 //
00009 
00010 // PL_Astar
00011 #include "synchronization/semaphore.h"
00012 #include "PL_Astar.h"
00013 
00014 // LEDA Include Files
00015 #include <LEDA/node_map.h> 
00016 #include <LEDA/node_pq.h>
00017 
00018 #include "math/math2.h"
00019 #include <iosfwd>
00020 #include <iostream>
00021 
00022 using std::endl;
00023 
00024 
00025 //--------------------- Constants ---------------
00026 const int DEFAULTNUMSTEPS = 40;
00027 const double DEFAULTWEIGHT = 0.9;
00028 const double COMPTOL = 1e-8;
00029 // File Constants
00030 static const char FILEEXT[] = ".a8";            // File extension for a base graph planner
00031 static const char FILEHEADER[] = "PL_ASTAR";
00032 
00033 
00034 // Class PL_Astar 
00035 
00036 PL_Astar::PL_Astar()
00037 {
00038         // Assign the file header and extension for this type
00039         strcpy( fileext, FILEEXT );
00040         strcpy( fileheader, FILEHEADER );
00041 
00042         // assign the open list pointer
00043         openp = NULL;
00044         
00045         // Clear the graph and initialize the node maps and open list
00046         ClearGraph();
00047                 
00048         // Default Parameter Settings
00049         weight = DEFAULTWEIGHT;
00050 
00051         // Initialize the Step Settings
00052         SetDefaultStepSize();
00053 
00054         TRACE("PL_Astar Default Constructor completed.\n");
00055 
00056 }
00057 
00058 
00059 PL_Astar::~PL_Astar()
00060 {
00061         // Delete the open list pointer
00062         if ( openp != NULL )
00063         {
00064                 delete openp;
00065         }
00066 
00067 }
00068 
00069 //=============================================================================
00070 // Clearing Functions
00071 //
00072 // Purpose: Clears the graph and start and goal nodes, initializes the node maps
00073 //                  and initializes the open node list.
00074 //                  
00075 //=============================================================================
00076 void PL_Astar::ClearGraph()
00077 {
00078         // Call Parent's ClearGraph
00079         PL_GraphBase::ClearGraph();
00080 
00081         // Initialize the node maps to the correct graph.
00082         nodeExpanded.init(G,FALSE);
00083         
00084         InitNewSearch();        
00085 }
00086 
00087 //=============================================================================
00088 // InitNewSearch 
00089 //
00090 // Purpose: Initializes the graph parameters for a new search
00091 //                  
00092 //=============================================================================
00093 void PL_Astar::InitNewSearch()
00094 {
00095         // Clear the existing path
00096         ClearGraphPath();
00097 
00098         // Initialize node maps for searching the graph
00099         pred.init(G,nil);
00100         dist.init(G,0);
00101 
00102         // Initilize a new open list
00103         if ( openp == NULL )
00104         {
00105                 openp = new node_pq<double>(G); 
00106         }
00107         openp->clear();
00108         
00109         // Start the search from the current start node (if it exists)
00110         if ( startNode != nil )
00111         {
00112                 openp->insert( startNode, 0 );  // Use 0 Priority to ensure it is the first node selected.
00113                 dist[startNode] = 0;
00114                 pred[startNode] = nil;
00115         }
00116 
00117         // Trick the planner into starting a new search.
00118         plan_success = TIMER_EXPIRED;
00119 }
00120 
00121 
00122 //=============================================================================
00123 // LoadContents
00124 //
00125 // Purpose: Loads the graph and other related base planner parameters to the the
00126 //                  given ifstream.
00127 //      
00128 //                      Returns success of load.
00129 //=============================================================================
00130 bool PL_Astar::LoadContents( std::ifstream& infile )
00131 {
00132         // Load the Graph and other base parameters
00133         bool success = PL_GraphBase::LoadContents( infile );
00134         if ( !success )
00135         {
00136                 return false;
00137         }
00138         
00139         // Load the A* Parameters
00140         infile >> stepsize;
00141         infile >> goalOnGrid >> weight;
00142 
00143         InvertStepSize();
00144 
00145         // Load the Node Information
00146         node n0;
00147         forall_nodes( n0, G )
00148         {
00149                 int nodeID;
00150                 infile >> nodeID;
00151                 infile >> nodeExpanded[n0];
00152         }
00153 
00154         // Get Planner to use new graph
00155         InitNewSearch();
00156 
00157         return true;
00158         
00159 }
00160 
00161 //=============================================================================
00162 // SaveContents
00163 //
00164 // Purpose: Saves the graph and other related base planner parameters to the the
00165 //                  given ofstream.
00166 //      
00167 //                      Returns success of save.
00168 //=============================================================================
00169 bool PL_Astar::SaveContents ( std::ofstream& outfile ) const
00170 {
00171         // Save the Graph and parent parameters
00172         bool success = PL_GraphBase::SaveContents( outfile );
00173         if ( !success )
00174         {
00175                 return false;
00176         }
00177 
00178         // Save the A* parameters
00179         outfile << stepsize << endl;
00180         outfile << goalOnGrid << " " << weight << endl;
00181 
00182         // Save Node Information
00183         node n1;
00184         forall_nodes( n1, G )
00185         {
00186                 outfile << n1->id() << " " << nodeExpanded[n1] << endl;
00187         }
00188         
00189         // Planning success will be refreshed in the load.
00190         
00191         return true;
00192 }
00193 
00194 //=============================================================================
00195 // Does Planning
00196 //
00197 // Purpose: performs the planning task
00198 //
00199 //=============================================================================
00200 bool PL_Astar::Plan ()
00201 {
00202         // If both start and goal are the same configuration
00203         if ( startNode == goalNode )
00204         {
00205                 graphPath.clear();
00206                 TranslatePath();
00207                 plan_success = PASS;
00208         }
00209 
00210         // Perform early checks
00211         if ( plan_success == PASS )
00212         {
00213                 return true;
00214         }
00215         else if ( plan_success == FAIL )
00216         {
00217                 return false;
00218         }
00219 
00220 
00221         // Start the timer
00222         StartTimer();
00223 
00224         // Establish the semaphore
00225         Semaphore semaphore( guid );
00226         semaphore.Lock();
00227 
00228         // Assume path will not be found.
00229         plan_success = FAIL;
00230 
00231         // Perform A* Search by continuing searching graph until the list of open nodes is exhausting, timer has expired, 
00232         // or solution has been found.
00233 
00234         // While OPEN is not empty
00235         while ( !openp->empty() )
00236         {
00237                 // Check to make sure timer has not expired.
00238                 if ( HasTimeLimitExpired() )
00239                 {
00240                         // Timer has expired.
00241 
00242                         // current state variables are saved, include the open priority queue which is not deleted.
00243 
00244                         // Report the timer has expired.
00245                         plan_success = TIMER_EXPIRED;
00246                         break;
00247                 }
00248 
00249                 //Remove the lowest cost node from open queue
00250                 node n1 = openp->del_min();
00251 
00252                 // check if goal has been found
00253                 if ( n1 == goalNode )
00254                 // found goal.
00255                 {
00256                         // Store the current path.
00257                         graphPath.clear();
00258                         graphPath.push( n1 );
00259 
00260                         // Starting with the goal, go up through path, adding each of the prev nodes
00261                         // to the path as they are found.
00262                         while ( n1 != startNode )
00263                         {
00264                                 node n0 = pred[n1];             // find the prev node in the path.
00265                                 
00266                                 // Add prev node to front of the path.
00267                                 graphPath.push( n0 );
00268 
00269                                 // Prepare for next iteration: the prev node will be the current node.
00270                                 n1 = n0;
00271                         }
00272 
00273                         // No longer need the open priority queue list.  Delete it.
00274                         delete openp;
00275                         openp = NULL;
00276 
00277                         // A path has been successfully found.
00278                         plan_success = PASS;
00279                         break;
00280                                         
00281                 }
00282                 else
00283                 {
00284                         // Expand all successor nodes
00285                         // NOTE:  TO find the successor nodes, we search all nodes connected by edges (bi-diretional) to
00286                         //                the current node.  Eventually the prev node in the path will be selected, however, it will
00287                         //                never be updated as one of the potential successor nodes since the current cost of getting
00288                         //                to the current node, includes going through the previous node.  This means a newcost of the
00289                         //                actual cost to the current node plus the cost of travelling back from the current node
00290                         //                to the prev node will be higher than the cost of getting to the prev node by not passing through
00291                         //                the current node.  Cost:  cost[A] < cost[A] + cost(A to B) + cost(B back to A)!
00292 
00293                         // Add all nodes within the stepsize of the current node to the graph.
00294                         ExpandNode( n1 );       
00295 
00296                         node n2;        // successor node.  n1 = curr node.
00297                         edge e1;        // scanning edge.
00298 
00299                         // Search all the successor nodes.              
00300                         forall_inout_edges(e1, n1)
00301                         {
00302                                 // find the successor node.   (since edges are in both directions, will have to examine
00303                                 // both the target and source node of the edge.  If either is the current node, then the
00304                                 // opposite node is the correct successor node. 
00305 
00306                                 n2 = G.source(e1);
00307                                 if ( n2 == n1)
00308                                 {
00309                                         // edge was pointing from current node, so select the target node as the successor
00310                                         n2 = G.target(e1);
00311                                 }
00312 
00313                                 // check if new node is uninitialized
00314                                 if ( ( pred[n2] == nil ) && ( n2 != startNode ) )
00315                                 {
00316                                         // record the prev node
00317                                         pred[n2] = n1;
00318                                         
00319                                         // Assign a cost (dist) to successor node
00320                                         dist[n2] = dist[n1] + G.inf(e1);  // length of path upto current node point plus cost of using edge to this node
00321                                                 
00322                                         //Add this node to open priority queue based on its estimated cost for the entire path
00323                                         openp->insert( n2, Astar_f(n2, dist[n2]) );
00324                                 }
00325                                 else
00326                                 {
00327                                         // check if path to this node is cheaper than the existing path
00328                                         double currcost = dist[n2];
00329                                         double newcost  = dist[n1] + G.inf(e1);
00330 
00331                                         // if new path is cheaper, update the parameters
00332                                         if ( newcost < currcost )
00333                                         {
00334                                                 // record the prev node.
00335                                                 pred[n2] = n1;
00336 
00337                                                 // Assign new cost to this node
00338                                                 dist[n2] = newcost;
00339 
00340                                                 // Find priority for new node:  cost upto this node + estimated distance to goal. 
00341                                                 double priority = Astar_f(n2, dist[n2]);
00342 
00343                                                 // check if this node is in the priority queue
00344                                                 if ( openp->member(n2) )
00345                                                 {
00346                                                         // already in queue, decrease its priority
00347                                                         openp->decrease_p( n2, priority );
00348                                                 }
00349                                                 else
00350                                                 {
00351                                                         // not in queue, add it
00352                                                         openp->insert( n2, priority );
00353                                                 }
00354                                         } // end if newcost < currcost
00355                                 } // end if uninitialized
00356                         } // end forall_inout_edges
00357 
00358                 } // end if not goal
00359 
00360                 // Allow for Multithreaded Draws, by releasing the semaphore tempoary
00361                 semaphore.Unlock();
00362                 semaphore.Lock();
00363                                 
00364         }  // end while open list is not empty.
00365 
00366 
00367 
00368         
00369         // Get the Path
00370         SuccessResultType success = TranslatePath();
00371 
00372         // Release semaphore permanetly.
00373         semaphore.Unlock();
00374 
00375         // Report the success of the planner.
00376         if ( success == PASS )
00377         {
00378                 // planner has completed and a path has been found and saved.
00379                 return true;
00380         }
00381         else
00382         {
00383                 // planner has not completed and has terminated early or no valid path was found.
00384                 return false;
00385         }
00386 
00387 
00388 }  // END Plan
00389 
00390 //=============================================================================
00391 // SetStartConfig
00392 //
00393 // Purpose: Prepares for a new A* search by clearing the current graph and associated
00394 //                  parameters, assigning the start configuration and it as a node into a 
00395 //                      new graph.
00396 //=============================================================================
00397 void PL_Astar::SetStartConfig( const Configuration& config )
00398 {
00399         // Check if the configuration has changed.
00400         if (( startNode != nil ) && ( GetStartConfig() == config ))
00401         {
00402                 // no change in configuration.  Can exit early.
00403                 return;
00404         }
00405 
00406         // A new configuration has been requested.  Need to clear the current graph and search parameters
00407         ClearGraph();
00408 
00409         // Set the startConfig, add it to the graph, and assign the startNode to it by
00410         // calling the parent's SetStartConfig.
00411         PL_GraphBase::SetStartConfig( config );
00412 
00413         // Verify the startNode was initiated.
00414         ASSERT( startNode != nil );
00415 
00416         // Make sure the start node is valid
00417         if ( IsInterfering( GetStartConfig() ) )
00418         {
00419                 // Remove invalid start from graph.
00420                 G.del_node( startNode );
00421                 startNode = nil;
00422 
00423                 // Start Interfers, there will be no valid path possible.
00424                 plan_success = FAIL;
00425                 return;
00426         }
00427 
00428         // Assume the current goal config is correct, but still need to add it to new graph 
00429         // and assign the goal node.
00430         PL_GraphBase::SetGoalConfig( GetGoalConfig() );
00431 
00432         // Verify the goalNode was initiated.
00433         ASSERT( goalNode != nil );
00434 
00435     int gSize = GetGoalConfig().Size();
00436     int cSize = config.Size();
00437         if( ( gSize != cSize ) || ( IsInterfering( GetGoalConfig() ) ) )
00438         {
00439                 // Remove the invalid goal from graph
00440                 G.del_node( goalNode );
00441                 goalNode = nil;
00442 
00443                 // Goal Interfers, there will be no valid path possible.
00444                 plan_success = FAIL;
00445                 return;
00446         }
00447 
00448         // Only allow the goal node to be expanded if it is on the grid.
00449         if ( GetGoalConfig().Compare( AlignConfig( GetGoalConfig() ) , COMPTOL ) )
00450         {
00451                 goalOnGrid = TRUE;
00452                 nodeExpanded[ goalNode ] = FALSE;       // making this switch false, this node will be allowed to be expanded later.
00453         }
00454         else
00455         {
00456                 goalOnGrid = FALSE;
00457                 nodeExpanded[ goalNode ] = TRUE;        // Do not allow node to be expanded, by forcing it to report expanded.
00458         }
00459 
00460         // Initialize for a new search
00461         InitNewSearch();
00462 
00463         // This is a fresh graph, so need to ensure the start node can be expanded
00464         nodeExpanded[ startNode ] = FALSE;
00465         
00466 }
00467 
00468 //=============================================================================
00469 // SetGoalConfig
00470 //
00471 // Purpose: Prepares for a new A* search by moving the goal node and performing
00472 //                      updates in graph parameters to request a new search.
00473 //=============================================================================
00474 void PL_Astar::SetGoalConfig( const Configuration& config )
00475 {
00476         // Check if the configuration has changed.
00477         if (( goalNode != nil ) && ( GetGoalConfig() == config ))
00478         {
00479                 // no change in configuration.  Can exit early.
00480                 return;
00481         }
00482 
00483         // Remove old goal from graph if it was not on the grid
00484         if ( !goalOnGrid )
00485         {
00486                 G.del_node( goalNode );
00487                 goalNode = nil;
00488         }
00489 
00490         // Set the goalConfig, add it to the graph, and assign the goalNode to it by
00491         // calling the parent's SetGoalConfig.
00492         int oldNumNodes = NodeCount();
00493         PL_GraphBase::SetGoalConfig( config );
00494 
00495 
00496         // Verify the goalNode was initiated.
00497         ASSERT( goalNode != nil );
00498 
00499         // Ensure the new goal is valid
00500         if ( IsInterfering( GetGoalConfig() ) )
00501         {
00502                 G.del_node( goalNode );
00503                 goalNode = nil;
00504 
00505                 // Goal interferes.  There is no point in performing a search.  Exit early
00506                 plan_success = FAIL;
00507                 return;
00508         }
00509 
00510         // Determine if new goal is on grid and is allowed to be expanded.
00511         if ( GetGoalConfig().Compare( AlignConfig( GetGoalConfig() ) , COMPTOL ) )
00512         {
00513                 goalOnGrid = TRUE;
00514                 
00515                 if ( oldNumNodes == NodeCount() )
00516                 {
00517                         // Do not change status of node being expanded, since goal is one of the existing nodes in graph
00518                 }
00519                 else
00520                 {
00521                         nodeExpanded[ goalNode ] = FALSE;       // This is a new node.  It has not been expanded.
00522                 }
00523         }
00524         else
00525         {
00526                 goalOnGrid = FALSE;
00527                 nodeExpanded[ goalNode ] = TRUE;        // Do not allow node to be expanded, by forcing it to report expanded.
00528 
00529                 // Since goal is not allowed to be expanded, have to check if it is already among expanded nodes and
00530                 // connect goal to neighbours
00531                 node n;
00532                 forall_nodes( n, G )
00533                 {
00534                         if ( n != goalNode )
00535                         {
00536                                 // Connect edge if node is within 1 grid box of goal and does not cause a collision
00537                                 Configuration testConfig = G.inf(n);
00538                                 if ( (Distance( testConfig, GetGoalConfig(), invStepSize ) < 1) && (!IsInterfering( testConfig, GetGoalConfig() )) )
00539                                 {
00540                                         double dist = sqrt( Distance( testConfig, GetGoalConfig() ) );
00541                                         edge e1 = G.new_edge( goalNode, n, dist );
00542                                 } // end if within 1 grid box
00543                         } // end if not goalNode
00544                 } // end for all nodes
00545         }  // end if not on grid.
00546 
00547 
00548         // Initialize for a new search
00549         InitNewSearch();
00550 
00551 }
00552 
00553 //=============================================================================
00554 // SetCollisionDetector
00555 //
00556 // Purpose: Assigns the CollisionDetector and extracts the DOF from it to allow
00557 //                  other graph specific parameters to be defined.
00558 //=============================================================================
00559 void PL_Astar::SetCollisionDetector (CD_BasicStyle* collisionDetector)
00560 {
00561         // Call the parent's SetCollisionDetector to ensure proper assignment.
00562         PL_GraphBase::SetCollisionDetector( collisionDetector );
00563 
00564 
00565         // Initialize to the default step size if the step size has not already been initialized.
00566         if ( stepsize.Length() != collisionDetector->DOF() )
00567         {
00568                 SetDefaultStepSize();
00569         }
00570 
00571 }
00572 
00573 //=============================================================================
00574 // Astar_f
00575 //
00576 // Purpose: Estimates the cost of the path based on the given node.
00577 //                      Returns the cost of the path upto the current node (given as a parameter)
00578 //                      and estimates the cost from current node to the goal.
00579 //=============================================================================
00580 double PL_Astar::Astar_f( const node& n, const double& currcost ) const
00581 {
00582         return (1-weight)*currcost + weight*sqrt(Distance( n, goalNode ));  
00583 }
00584 
00585 
00586 //=============================================================================
00587 // InvertStepSize
00588 //
00589 // Purpose: Inverts the current step size for each of the joints and assigns
00590 //                      it to invStepSize.
00591 //=============================================================================
00592 void PL_Astar::InvertStepSize()
00593 {
00594         // Equate the size of the vector.
00595         int length = stepsize.Length();
00596         invStepSize.SetLength( length );
00597 
00598         // Get inverse of each of the steps.
00599         for (int i = 0; i < length; i++ )
00600         {
00601                 invStepSize[i] = double( 1 / stepsize[i] );
00602         }
00603 
00604 }
00605 
00606 //=============================================================================
00607 // SetStepSize
00608 //
00609 // Purpose: Assigns the step size for each joint based on the given parameter
00610 //                      If the new step size has changed, the graph is cleared.
00611 //=============================================================================
00612 void PL_Astar::SetStepSize( const VectorN& newstepsize )
00613 {
00614         if ( stepsize == newstepsize )
00615         {
00616                 return; // step size is the same.  Exit early.
00617         }
00618 
00619         // Assign new stepsize.
00620         stepsize = newstepsize;
00621 
00622         // Store the inverse of each step
00623         InvertStepSize();
00624 
00625         // Clear the Graph
00626         ClearGraph();
00627 
00628 }
00629 
00630 //=============================================================================
00631 // SetDefaultStepSize
00632 //
00633 // Purpose: Assigns the default step size for each joint based on the joint limits
00634 //=============================================================================
00635 void PL_Astar::SetDefaultStepSize()
00636 {
00637         int dof = 0;
00638 
00639         if ( collisionDetector != NULL )
00640         {
00641                 dof = collisionDetector->DOF();
00642         }
00643         
00644         stepsize.SetLength( dof );
00645 
00646         for ( int i = 0; i < dof; i++)
00647         {
00648                 stepsize[i] = double( (collisionDetector->JointMax(i) - collisionDetector->JointMin(i)) / DEFAULTNUMSTEPS );
00649         }
00650 
00651         // Store the inverse of each step.
00652         InvertStepSize();
00653 
00654 }
00655 
00656 //=============================================================================
00657 // AlignJoint
00658 //
00659 // Purpose: Returns an alligned joint value on a grid that is created from
00660 //                      the step size and start configuration, closest to the given joint value
00661 //=============================================================================
00662 double PL_Astar::AlignJoint( const int& jointNum, const double& jointValue ) const
00663 {
00664         double start = GetStartConfig()[jointNum];
00665         double step  = stepsize[jointNum];
00666 
00667         double diff = jointValue - start;
00668 
00669         int numofsteps = diff / step;   // number will truncate towards zero.
00670 
00671         double align = start + numofsteps*step;
00672 
00673         // check if we are within 1/2 a step of proposed joint value
00674         if ( fabs( jointValue - align ) < ( 0.5 * step ) )
00675         {
00676                 return align;
00677         }
00678         else if ( diff > 0 )            // truncate towards zero, so make sure we step in the right direction to get closest grid allignment
00679         {
00680                 double align2 = align + step;
00681                 if ( align2 > collisionDetector->JointMax( jointNum ) )  // ensure we do not go over the limits
00682                 {
00683                         return align;
00684                 }
00685                 else
00686                 {
00687                         return align2;
00688                 }
00689         }
00690         else
00691         {
00692                 double align2 = align - step;
00693                 if ( align2 < collisionDetector->JointMin( jointNum ) )  // ensure we do not go over the limits
00694                 {
00695                         return align;
00696                 }
00697                 else
00698                 {
00699                         return align2;
00700                 }
00701         }
00702 
00703 }
00704 
00705 //=============================================================================
00706 // AlignConfig
00707 //
00708 // Purpose: Returns an alligned configuration on a grid that is created from
00709 //                      the step size and start configuration, closest to the given config
00710 //=============================================================================
00711 Configuration PL_Astar::AlignConfig( const Configuration& config ) const
00712 {
00713         int dof = config.DOF();
00714 
00715         Configuration returnMe;
00716         returnMe.SetNumDOF( dof );
00717 
00718         for ( int i = 0; i < dof; i++ )
00719         {
00720                 returnMe[i] = AlignJoint( i, config[i] );
00721         }
00722 
00723         return returnMe;
00724 
00725 }
00726 
00727 //=============================================================================
00728 // ExpandNode
00729 //
00730 // Purpose: Expands the node by finding all valid configurations within specified
00731 //                  stepsize and connects to them with valid edges.
00732 //
00733 //                      Only expands nodes that were not previously expanded.
00734 //=============================================================================
00735 void PL_Astar::ExpandNode( const node& n )
00736 {
00737         // Check if node has already been expanded and return early if TRUE.
00738         if ( nodeExpanded[n] )
00739         {
00740                 return;
00741         }
00742 
00743         int dof = collisionDetector->DOF();
00744 
00745         // Create list of nodes already connected to current node
00746         node_list neighbours;
00747         edge e1;
00748         forall_inout_edges( e1, n)
00749         {
00750                 node n1 = G.source(e1);
00751                 if ( n1 == n )
00752                 {
00753                         n1 = G.target(e1);
00754                 }
00755 
00756                 neighbours.append(n1);
00757         }
00758 
00759         // Search all configurations within stepsize of current node.
00760         Configuration currentconfig = G.inf(n);
00761         for( int i = 0; i < dof; i++)
00762         {
00763                 BOOL jointWraps = collisionDetector->JointWraps( i );
00764                 double jmax = collisionDetector->JointMax( i );
00765                 double jmin = collisionDetector->JointMin( i );
00766 
00767                 for( int j = -1; j < 2; j+=2 )  // perform check for both forward and backward step.
00768                 {
00769                         Configuration newconfig = currentconfig;
00770                         double newjoint = currentconfig[i] + (j*stepsize[i]);
00771                         
00772 
00773                         // With wrapping joints, need to be able to wrap around the limits but ensure the resulting wrap 
00774                         // remains alligned to the grid.  Need to check first if the joint wraps, and then if it
00775                         // exceeds any of the limits, realign it to the grid using the corresponding joint limit.
00776                         
00777                         if ( jointWraps )
00778                         {
00779                                 // Joint Wraps, check limits first and then align.
00780                                 if ( newjoint > jmax )
00781                                 {
00782                                         // Want to have joint at smallest grid alligned value.
00783                                         newjoint = AlignJoint( i, jmin );
00784                                 }
00785                                 else if ( newjoint < jmin )
00786                                 {
00787                                         // Want to have joint at largest grid alligned value.
00788                                         newjoint = AlignJoint( i, jmax );
00789                                 }
00790                         }
00791                         else
00792                         {       
00793                                 // joint does not wrap.  Hence, if the new joint value exceeds the joint limits, it
00794                                 // is invalid and the resulting configuration should not be added to graph.
00795                                 if ( ( newjoint > jmax ) || ( newjoint < jmin ) )
00796                                 {
00797                                         // joint exceeds limit
00798                                         continue;
00799                                 }
00800                                 
00801                         }
00802 
00803                         // With realigning the joint, there is a chance the new config is now the same as the current config.
00804                         // To ensure we do not add a duplicate config to the graph a second time with a 0 distance edge, check if the
00805                         // new joint is the same as the current joint and escape if ture.
00806                         if ( newjoint == currentconfig[i] )
00807                         {
00808                                 continue;       
00809                         }
00810 
00811 
00812                         // Update new config with new joint value
00813                         newconfig[i] = newjoint;
00814 
00815                         // Verify new configuration is valid
00816                         if ( IsInterfering( newconfig ) )
00817                         {
00818                                 continue;       // configuration causes collision.  Don't preform further checks, but start next iteration
00819                         }
00820 
00821                         // Check if new config is already graph connected to node by checking its neighbours
00822                         node n1;
00823                         bool configFound = FALSE;
00824                         forall( n1, neighbours )
00825                         {
00826                                 // use the compare function using a tolerance to prevent floating point math errors.
00827                                 if ( newconfig.Compare( G.inf(n1) , COMPTOL ) )
00828                                 {
00829                                         configFound = TRUE;
00830                                         break;  // break out check of neighbours.
00831                                 }
00832                         }
00833                         if ( configFound )
00834                         {
00835                                 continue;  // this config already exists.  Search next iteration.
00836                         }
00837 
00838                         // Search for config in existing graph, and add it if it is not found.
00839                         n1 = FindConfig( newconfig );  // uses the compare function using a tolerance to prevent floating point math errors.
00840                         if ( n1 == nil )
00841                         {
00842                                 // Add the node
00843                                 n1 = G.new_node( newconfig );
00844                                 nodeExpanded[ n1 ] = FALSE;                     // new node has not been expanded.
00845                                 pred[ n1 ] = nil;                                       // node has just been initialized.
00846                                 dist[ n1 ] = 0;
00847 
00848                         }
00849 
00850                         // Connect configuration to current node if a collision free edge exists
00851                         if ( !IsInterfering( newconfig, currentconfig ) )
00852                         {
00853                                 double dist = sqrt( Distance( newconfig, currentconfig ) );
00854                                 edge e1 = G.new_edge( n1, n, dist );            // edge points to current node.
00855                         }
00856 
00857                 }  // end for j
00858         }  // end for i
00859 
00860 
00861         // If the goal is not on the grid, check to if it is within 1 grid box of current node and connect if valid.
00862         if ( ( !goalOnGrid ) && 
00863                  ( Distance( currentconfig, GetGoalConfig(), invStepSize ) < 1 ) && 
00864                  ( !IsInterfering( currentconfig, GetGoalConfig() ) )  )
00865         {
00866                 double dist = sqrt( Distance( GetGoalConfig(), currentconfig ) );
00867                 edge e1 = G.new_edge( goalNode, n, dist );              // edge points from goal to current node
00868         }
00869 
00870         // Current node has just been fully expanded.
00871         nodeExpanded[ n ] = TRUE;
00872 
00873 }
00874 
00875 //=============================================================================
00876 // CopySettings
00877 //
00878 // Purpose: copies the settings from a different planner
00879 //=============================================================================
00880 void PL_Astar::CopySettings( PlannerBase* original )
00881 {
00882         PL_GraphBase::CopySettings( original );
00883 
00884         PL_Astar* originalAstar = dynamic_cast< PL_Astar* >( original );
00885         if( originalAstar == NULL )
00886         {
00887                 return;
00888         }
00889         this->stepsize = originalAstar->stepsize;
00890         this->invStepSize = originalAstar->invStepSize;
00891         this->weight = originalAstar->weight;
00892 
00893 }

Generated on Sat Apr 1 21:30:40 2006 for Motion Planning Kernel by  doxygen 1.4.6-NO