planners/prm/PL_PRM.cpp

Go to the documentation of this file.
00001 //=========================================================================
00002 //
00003 //  File:  PL_PRM.cpp
00004 //
00005 //  Created by Ian Gipson, Modified by Shane Schneider.
00006 //
00007 //              Full and Lazy PRM planner.  Uses PL_GraphBase as parent class
00008 //              the basic graph structure and access functions.  This planner
00009 //              will modify the graph and implement the PRM planners.
00010 
00011 // PL_PRM
00012 #include "synchronization/semaphore.h"
00013 #include "PL_PRM.h"
00014 #include "smoothers\SmootherBase.h"
00015 // LEDA Include Files
00016 #include <LEDA/node_map.h> 
00017 #include <LEDA/node_pq.h>
00018 #include "math/math2.h"
00019 #include <iosfwd>
00020 #include <iostream>
00021 
00022 
00023 // fix gl path...
00024 // #include <gl/glos.h>
00025 #include "opengl/glos.h"
00026 #include <gl/gl.h>
00027 
00028 using std::endl;
00029 using std::istrstream;
00030 
00031 //--------------------- Constants ---------------
00032 static const double DEFAULT_TOL = 0.1;          // 10% of CSpaceRange.
00033 static const int DEFAULT_INIT_QUANT = 100; // Minimal Number of nodes to maintain in a roadmap
00034 static const int DEFAULT_ENHANCE_QUANT = 50;  // Number of nodes to add during enhancement.
00035 static const double DEFAULT_SEED_RATIO = 0.5;   // Default ratio between seeded nodes and uniform nodes.
00036 static const int DEFAULTBASECONNECTID = 0;              // Default baseConnect ID for tree graphs.
00037 // File Constants
00038 static const char FILEEXT[] = ".prm";           // File extension for a base graph planner
00039 static const char FILEHEADER[] = "PL_PRM";
00040 
00041 
00042 // Class PL_PRM 
00043 
00044 PL_PRM::PL_PRM()
00045 {
00046         // Assign the file header and extension for this type
00047         strcpy( fileext, FILEEXT );
00048         strcpy( fileheader, FILEHEADER );
00049 
00050 
00051         // Initialize the node and edge checked maps to the correct graph.
00052         edgeChecked.init(G,FALSE);
00053         nodeChecked.init(G,FALSE);
00054 
00055         // Assume node are to be added uniformly.
00056         uniformlyAdded.init(G,TRUE);
00057 
00058         // Assign the open ptr
00059         openp = NULL;
00060 
00061         // Assign the tree connected component ID
00062         baseConnectID = DEFAULTBASECONNECTID;
00063         connectIDp = NULL;
00064 
00065         // Default Parameter Settings
00066         SetRadiusTol( DEFAULT_TOL );
00067         lazyMode = TRUE;
00068         validNodesOnly = FALSE;
00069         validEdgesOnly = FALSE;
00070         useMidPts = FALSE;
00071 
00072         initQuant    = DEFAULT_INIT_QUANT;
00073         enhanceQuant = DEFAULT_ENHANCE_QUANT;
00074         seedRatio        = DEFAULT_SEED_RATIO;
00075 
00076         // Start with a blank list of config seeds.
00077         config_seeds.clear();
00078 
00079 
00080         // Set DOF and initialize the diagonal Length.
00081         diagonal_squared = 0;
00082 
00083         // Since we are starting a new planner. We want to start a new planning session.
00084         lastPlanningState = PRM_START;
00085 }
00086 
00087 
00088 PL_PRM::~PL_PRM()
00089 {
00090         // Delete the open list pointer
00091         if ( openp != NULL )
00092         {
00093                 delete openp;
00094                 openp = NULL;
00095         }
00096 
00097         // Delete the connection ID node map if it exists.
00098         if ( connectIDp != NULL )
00099         {
00100                 delete connectIDp;
00101                 connectIDp = NULL;
00102         }
00103 }
00104 
00105 
00106 //=============================================================================
00107 // DrawExplicit
00108 //
00109 // Purpose: Draws the planner data to the planner window when called
00110 //                      This draw is a modified version from the GraphBase drawer since
00111 //                      we want to use different colours to inidacate which edges and nodes 
00112 //          have been checked.
00113 //=============================================================================
00114 bool PL_PRM::DrawExplicit () const
00115 {
00116         // IMPROVE:  Add Open GL code to inser the graph here.
00117         double Xcor, Ycor, Zcor;        // temp coordinate variables
00118         node   n1;                                      // index for the various nodes during iterations
00119         edge   e1;                                      // index for iteration of edges
00120         
00121         // Lock Graph for Drawing
00122         Semaphore semaphore( this->guid );
00123         semaphore.Lock();
00124 
00125         // Setup GL Environment
00126         glClearColor( 0.0f, 0.0f, 0.2f, 1.0f );
00127         glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00128         BOOL lightingState = glIsEnabled( GL_LIGHTING );
00129         glDisable( GL_LIGHTING );
00130 
00131         // Create Shading Effects that will allow edges to have two end colours.
00132         //  IMPROVE:  Does this change the shading for others.  If so, is there a way
00133         //                    to check for current shading mode and save it.
00134         glShadeModel( GL_SMOOTH );
00135 
00136         // The depth function is set to its default of GL_LESS.  This means that any object closer to the viewport
00137         // will have its colour displayed for that pixel.  This means closer objects will be drawn on top of further
00138         // objects.  Any objects that are in the same plane, will have the colour of the object drawn first.
00139 
00140         // Draw Child Planner Specific Information
00141         DrawSpecific();
00142 
00143 
00144         // Draw all NODES first, as these are to be seen on top of any edges.
00145         glPointSize(5.0f);      // Set size of points associated with the nodes.
00146 
00147         // Draw the Start and Goal nodes as these want to be predominately seen.
00148         glBegin(GL_POINTS);
00149                 // Draw the Startnode, if valid.
00150                 if ( startNode != nil )
00151                 {
00152                         glColor3f(1.0f,1.0f,0.0f);              // set colour to yellow
00153                         GetCoords( startNode, Xcor, Ycor, Zcor );
00154                         glVertex3f( (float)Xcor, (float)Ycor, (float)Zcor );
00155                 }
00156 
00157                 // Draw the Goalnode, if valid.
00158                 if ( goalNode != nil )
00159                 {
00160                         glColor3f(0.0f,1.0f,1.0f);              // set colour to cyan
00161                         GetCoords( goalNode, Xcor, Ycor, Zcor );
00162                         glVertex3f( (float)Xcor, (float)Ycor, (float)Zcor );
00163                 }
00164         glEnd();
00165 
00166         // Draw all remainning nodes.
00167         glBegin(GL_POINTS);
00168                 // Search all nodes of the graph and draw them unless they are start and goal.
00169                 forall_nodes( n1, G )
00170                 {
00171                         if ( ( n1 != startNode ) && ( n1 != goalNode ) )
00172                         {
00173                                 if ( nodeChecked[n1] )
00174                                 {
00175                                         if ( uniformlyAdded[n1] )
00176                                         {
00177                                                 // uniformly collision checked node
00178                                                 glColor3f(1.0f,0.0f,0.0f);              // set colour to red
00179                                         }
00180                                         else
00181                                         {
00182                                                 // seeded collision checked node
00183                                                 glColor3f(0.0f,1.0f,0.0f);              // set colour to green
00184                                         }
00185                                 }
00186                                 else if ( uniformlyAdded[n1] )
00187                                 {
00188                                         // uniformly non-checked node
00189                                         glColor3f(0.75f,0.4f,0.0f);             // set colour to dark orange
00190                                 }
00191                                 else
00192                                 {
00193                                         // all others (seeded non-checked nodes)
00194                                         glColor3f(0.0f,0.5f,0.0f);              // set colour to dark green
00195                                 }
00196 
00197                                 GetCoords( n1, Xcor, Ycor, Zcor );      // Get Coordinates of the current node
00198                                 glVertex3f( (float)Xcor, (float)Ycor, (float)Zcor );
00199                         }
00200                 }
00201         glEnd();
00202 
00203 
00204         // Draw EDGES joining the nodes
00205         // Draw the tentative path through the nodes, if it exists, by drawing edges connects the nodes of 
00206         // the path.
00207         if ( !graphPath.empty() ) 
00208         {
00209                 glLineWidth( 3.0f );
00210                 glBegin(GL_LINES);
00211                         node n1 = graphPath.tail();
00212         
00213                         // Search through the nodes of the graphPath, starting with
00214                         // the goalNode (last node listed in path) and ending on startNode (first node)
00215                         node firstNode = graphPath.head();
00216                         while ( n1 != firstNode )
00217                         {
00218                                 // get the source node coordinates
00219                                 GetCoords( n1, Xcor, Ycor, Zcor );
00220                                 glColor3f(1.0f,0.5f,0.0f);      // set colour to orange
00221                                 glVertex3f( (float)Xcor, (float)Ycor, (float)Zcor );    // add source vertex for edge line
00222 
00223                                 // advance to prev node (target vertex of edge)
00224                                 n1 = graphPath.pred(n1);
00225 
00226                                 // get the target node coordinates
00227                                 GetCoords( n1, Xcor, Ycor, Zcor );
00228                                 glColor3f(1.0f,1.0f,0.0f);      // set colour to yellow
00229                                 glVertex3f( (float)Xcor, (float)Ycor, (float)Zcor );    // add target vertex for edge line
00230 
00231                                 // for next iteration, want to use the current node and node index as the source for the next node.  
00232                                 // Will automatically fall out when the end of the list is reached and the last node serves as the target 
00233                                 // for the last edge only.
00234                         } 
00235                         
00236                 glEnd();
00237         }
00238 
00239 
00240         // Draw all Edges joining the nodes of the graph.
00241         glLineWidth( 1.0f );
00242         glBegin(GL_LINES);
00243                 // Draw all connecting edges
00244                 forall_edges(e1,G)
00245                 {       
00246                         GetCoords( G.source(e1), Xcor, Ycor, Zcor );    // get coordinates of source node;
00247                         if (edgeChecked[e1])
00248                         {
00249                                 glColor3f(0.0f,0.0f,1.0f);      // set colour to blue
00250                         }
00251                         else
00252                         {
00253                                 glColor3f(0.0f,0.3f,0.5f);      // set colour to dark blue
00254                         }
00255                         glVertex3f( (float)Xcor, (float)Ycor, (float)Zcor );    // add source vertex for edge line.
00256 
00257                         GetCoords( G.target(e1), Xcor, Ycor, Zcor );    // get coordinates of target node;
00258                         if (edgeChecked[e1])
00259                         {
00260                                 glColor3f(1.0f,1.0f,1.0f);      // set colour to white
00261                         }
00262                         else
00263                         {
00264                                 glColor3f(0.5f,0.5f,0.5f);      // set colour to grey
00265                         }
00266                         glVertex3f( (float)Xcor, (float)Ycor, (float)Zcor );    // add target vertex for edge line.
00267                 }
00268         glEnd();
00269 
00270         // Clean up Environment
00271         if( lightingState != FALSE )
00272         {
00273                 glEnable( GL_LIGHTING );
00274         }
00275 
00276         // Unlock Semaphore
00277         semaphore.Unlock();
00278         Sleep( 15 );
00279 
00280         return true;
00281 }
00282 
00283 
00284 //=============================================================================
00285 // LoadContents
00286 //
00287 // Purpose: Loads the graph and other related base planner parameters to the the
00288 //                  given ifstream.
00289 //      
00290 //                      Returns success of load.
00291 //=============================================================================
00292 bool PL_PRM::LoadContents( std::ifstream& infile )
00293 {
00294         // Load the Graph and other base parameters
00295         bool success = PL_GraphBase::LoadContents( infile );
00296         if ( !success )
00297         {
00298                 return false;
00299         }
00300         
00301         // Load the PRM Parameters
00302         infile >> radiusTol;
00303         infile >> initQuant >> enhanceQuant >> seedRatio;
00304         infile >> lazyMode >> validNodesOnly >> validEdgesOnly >> useMidPts;
00305 
00306         // The graph mode will depend on the PRM mode type (lazy or full).  Since
00307         // the graph has just been loaded, DO NOT call SetGraphMode to initialize the graph
00308         // mode as this may clear the just loaded graph.  Instead, use the lazyMode switch
00309         // to determine if the connectID list should be initialized and loaded.
00310         if ( !lazyMode )
00311         {
00312                 // Will be using a tree graph.  Initialize the list and set the base counter.
00313                 infile >> baseConnectID;  // this number will only be saved in a tree graph because of backwards
00314                                                                   // compatibility.
00315                 if ( connectIDp != NULL )
00316                 {
00317                         delete connectIDp;
00318                 }
00319                 connectIDp = new node_map<int>(G);
00320         }
00321         else
00322         {
00323                 // using a fully connected graph.  Delete any current connectionID list.
00324                 baseConnectID = DEFAULTBASECONNECTID;
00325                 if ( connectIDp != NULL )
00326                 {
00327                         delete connectIDp;
00328                         connectIDp = NULL;
00329                 }
00330         }
00331 
00332 
00333         // Load the Node Information
00334         node n0;
00335         forall_nodes( n0, G )
00336         {
00337                 int nodeID;
00338                 infile >> nodeID;
00339                 infile >> nodeChecked[n0] >> uniformlyAdded[n0];
00340 
00341                 if ( !lazyMode )
00342                 {
00343                         // this item is only saved in a tree graph.
00344                         infile >> (*connectIDp)[n0];
00345                 }
00346         }
00347 
00348         // Error checking.  The next entry in file should be the nil id
00349         int id;
00350         infile >> id;
00351         if ( id != NIL_ID )
00352         {
00353                 // Error has occurred.
00354                 MessageBox( NULL, "Node and Edge information do not align with current Graph.", "ERROR", MB_OK );
00355                 return false;
00356         }
00357 
00358         // Load the Edge information.
00359         edge e1;
00360         forall_edges( e1, G )
00361         {
00362                 int edgeID;
00363                 infile >> edgeID;
00364                 infile >> edgeChecked[e1];
00365         }
00366 
00367         // Since we have loaded a new graph, inform the planner we want to start a new graph search.
00368         lastPlanningState = PRM_START;
00369 
00370         return true;
00371         
00372 }
00373 
00374 //=============================================================================
00375 // SaveContents
00376 //
00377 // Purpose: Saves the graph and other related base planner parameters to the the
00378 //                  given ofstream.
00379 //      
00380 //                      Returns success of save.
00381 //=============================================================================
00382 bool PL_PRM::SaveContents ( std::ofstream& outfile ) const
00383 {
00384         // Save the Graph and parent parameters
00385         bool success = PL_GraphBase::SaveContents( outfile );
00386         if ( !success )
00387         {
00388                 return false;
00389         }
00390 
00391         // Save the PRM parameters
00392         outfile << radiusTol << endl;
00393         outfile << initQuant << " " << enhanceQuant << " " << seedRatio << endl;
00394         outfile << lazyMode << " " << validNodesOnly << " " << validEdgesOnly << " " << useMidPts << endl;
00395 
00396         // Save the baseconnectID only if a tree graph has been saved.
00397         // In a fully connected graph, this number will not be saved, thus ensuring backwards compatibilty with previous
00398         // saved PRM files.
00399         if ( !lazyMode )
00400         {
00401                 outfile << baseConnectID << endl;
00402         }
00403 
00404         // Save Node Information
00405         node n1;
00406         forall_nodes( n1, G )
00407         {
00408                 outfile << n1->id() << " " << nodeChecked[n1] << " " << uniformlyAdded[n1];
00409 
00410                 // Save the connectionID if a tree graph
00411                 if ( !lazyMode )
00412                 { 
00413                         outfile << " " << (*connectIDp)[n1];
00414                 }
00415 
00416                 // append the end of line character.
00417                 outfile << endl;
00418 
00419         }
00420 
00421         // Add error checking to file, seperate node info from edge info by adding nil
00422         outfile << NIL_ID << endl;
00423 
00424         // Save the Edge Information
00425         edge e1;
00426         forall_edges( e1, G )
00427         {
00428                 outfile << e1->id() << " " << edgeChecked[e1] << endl;
00429         }
00430 
00431         // Last Planning state will be refreshed in the load.
00432         
00433         return true;
00434 }
00435 
00436 //=============================================================================
00437 // Does Planning
00438 //
00439 // Purpose: performs the planning task
00440 //
00441 //                      This function uses a state machine to determine what is the next
00442 //                      step in the planning algorithm.  See the functions associated
00443 //                      with each state for explanation of how it works.
00444 //=============================================================================
00445 bool PL_PRM::Plan ()
00446 {
00447         srand( (unsigned)time( NULL ) );
00448 
00449         PRM_StateMachineType currentState = lastPlanningState;
00450 
00451         // Nodes may have been added since last plan.  Allow planner to check roadmap again
00452         // IMPROVE:  Is this still needed?
00453         if ( lastPlanningState == PRM_FAILURE )
00454         {
00455                 currentState = PRM_START;
00456         }
00457 
00458         // Start the timer
00459         StartTimer();
00460 
00461         // Establish the semaphore
00462         Semaphore semaphore( guid );
00463         if( this->m_UseSemaphores == true )
00464         {
00465                 semaphore.Lock();
00466         }
00467         
00468 
00469         // Some quick checks to determine if we really need to plan
00470         if ( (currentState != PRM_DONE ) && (currentState != PRM_FAILURE) ) 
00471         {
00472                 if ( startNode == goalNode )
00473                 {
00474                         // start and goal are the same.  Do not plan.
00475                         currentState = PRM_DONE;
00476 
00477                         // Assign a small path.
00478                         path.Clear();
00479                         path.AppendPoint( GetStartConfig() );
00480                 }
00481                 else if ( (IsInterfering(startNode)) || (IsInterfering(goalNode)) )
00482                 {
00483                         // either the start or goal are already interfering.  Plan will
00484                         // automatically fail.
00485                         currentState = PRM_FAILURE;
00486                 }
00487         }
00488         if( this->m_UseSemaphores == true )
00489         {
00490                 semaphore.Unlock();
00491         }
00492 
00493         // Ensure the diagonal length is correct
00494         diagonal_squared = GetCspaceRange();
00495         
00496         // State Machine
00497         while (( currentState != PRM_DONE ) && ( currentState != PRM_FAILURE )) 
00498                 // NOTE:  The PRM_FAILURE state should eventually be removed!
00499         {
00500                 SuccessResultType success;
00501 
00502                 if( this->m_UseSemaphores == true )
00503                 {
00504                         semaphore.Lock();
00505                 }
00506                 // Determine the State function to call for this iteration
00507                 switch ( currentState )
00508                 {
00509                         case PRM_BUILD_INIT_ROADMAP :
00510                                 success = BuildInitRoadMap();
00511                                 break;
00512                         case PRM_FIND_PATH :
00513                                 success = FindPath();
00514                                 break;
00515                         case PRM_VERIFY_PATH :
00516                                 success = VerifyPath();
00517                                 break;
00518                         case PRM_TRANSLATE_PATH :
00519                                 success = TranslatePath();
00520                                 break;
00521                         case PRM_ENHANCE_ROADMAP :
00522                                 success = EnhanceRoadMap();
00523                                 break;
00524                         default :
00525                                 // No state functions are associated with this state.
00526                                 // Do nothing except prepare for next iteration.
00527                                 success = PASS;
00528                 }  // end SWITCH
00529 
00530 
00531                 // Check if timer has expired and one of the state functions had returned early.
00532                 if ( success == TIMER_EXPIRED )
00533                 {
00534                         // Escape the state machine.
00535                         break;
00536                 }
00537 
00538                 // Determine the State Function to call for the next iteration
00539                 switch ( currentState )
00540                 {
00541                         case PRM_START :
00542                                 // Start by building the initial roadmap.
00543                                 currentState = PRM_BUILD_INIT_ROADMAP;  
00544                                 break;
00545                         case PRM_BUILD_INIT_ROADMAP :
00546                                 // Search current road map for a short path.
00547                                 currentState = PRM_FIND_PATH;                   
00548                                 break;
00549                         case PRM_FIND_PATH :
00550                                 if ( success == PASS )
00551                                 {
00552                                         // A path has been found, verify it has no collision.
00553                                         currentState = PRM_VERIFY_PATH;
00554                                 }
00555                                 else
00556                                 {
00557                                         // No path was found.  Enhance some of the trouble areas.
00558                                         currentState = PRM_ENHANCE_ROADMAP;
00559                                         //currentState = PRM_FAILURE;           // NOTE:  Once EnhanceRoadmap is working,
00560                                                                                                         //                the PRM_FAILURE state should be removed.
00561                                 }
00562                                 break;
00563                         case PRM_VERIFY_PATH :
00564                                 if ( success == PASS )
00565                                 {
00566                                         // Path represented by valid nodes is successful. Translate it so the
00567                                         // main program can implement it.
00568                                         currentState = PRM_TRANSLATE_PATH;
00569                                 }
00570                                 else
00571                                 {
00572                                         // Path was not collision free.  Need to find a new path now that the troublesome
00573                                         // nodes/edges have been removed.
00574                                         currentState = PRM_FIND_PATH;
00575                                 }
00576                                 break;
00577                         case PRM_TRANSLATE_PATH :
00578                                 // We are done.  Escape state machine and report success.
00579                                 currentState = PRM_DONE;
00580                                 break;
00581                         case PRM_ENHANCE_ROADMAP :
00582                                 // Try finding a path again with the new nodes and edges added.
00583                                 currentState = PRM_FIND_PATH;
00584                                 break;
00585                         default :
00586                                 // an unexpected or invalid state has occurred.  Crash the program!
00587                                 ASSERT( FALSE );
00588                 } // end SWITCH.
00589 
00590                 // Release semaphore temporary.
00591                 if( this->m_UseSemaphores == true )
00592                 {
00593                         semaphore.Unlock();
00594                 }
00595         }  // END State Machine
00596 
00597 
00598         // save the current state of the machine for the next time the planner is called.
00599         lastPlanningState = currentState;
00600 
00601         // Report the success of the planner.
00602         if ( currentState == PRM_DONE )
00603         {
00604                 // planner has completed.  A path has been found and saved.
00605                         
00606                 // Release semaphore permanetly.
00607                 if( this->m_UseSemaphores == true )
00608                 {
00609                         semaphore.Unlock();
00610                 }
00611 
00612                 //smooth the path
00613                 if( m_Smoother != NULL )
00614                 {
00615                         this->m_Smoother->SetPath( &this->path );
00616                         this->m_Smoother->SetCollisionDetector( this->collisionDetector );
00617                         m_Smoother->Smooth();
00618                         this->path = m_Smoother->GetPath();
00619                         m_Smoother->SetPath( NULL );
00620                 }
00621 
00622                 return true;
00623         }
00624         else
00625         {
00626                 // planner has not completed and has terminated early
00627                 graphPath.clear();
00628 
00629                 // Assign a small path.
00630                 path.Clear();
00631                 path.AppendPoint( GetStartConfig() );
00632 
00633                 // Release semaphore permanetly.
00634                 if( this->m_UseSemaphores == true )
00635                 {
00636                         semaphore.Unlock();
00637                 }
00638 
00639                 return false;
00640         }
00641 
00642 }  // END Plan
00643 
00644 //=============================================================================
00645 // SetRadiusTol
00646 //
00647 // Purpose: Sets the maxRadius for connecting to close neighbours by a given tol.
00648 //                      Setting by Tol allows the user not to worry about the size and range
00649 //                      of the Cspace customized by the weight function.
00650 //=============================================================================
00651 void PL_PRM::SetRadiusTol( double tol )
00652 {
00653         // Store the given tolerence
00654         radiusTol = tol;
00655         
00656 }
00657 
00658 //=============================================================================
00659 // GetRadiusTol
00660 //
00661 // Purpose: Determines what the tol was in order to set the maxRadius.
00662 //                      Used for updating the Dialog Window
00663 //=============================================================================
00664 double PL_PRM::GetRadiusTol()
00665 {
00666         // Return the tol
00667         return radiusTol;
00668 }
00669 
00670 //=============================================================================
00671 // SetPRMMode
00672 //
00673 // Purpose: Sets the mode dependent switches for the different variations of PRM
00674 //=============================================================================
00675 void PL_PRM::SetPRMMode ( BOOL& isLazy, BOOL& validNodes, BOOL& validEdges )
00676 {
00677         // Mode Switches:  Lazy OFF => have to use validNodes and validEdges
00678         //                                 if either validNodes or validEdges are off, then will be
00679         //                                 running some form of lazy, therefore lazy is turned ON.
00680 
00681         // Figure out which of the modes a change has been requested.
00682         if ( lazyMode != isLazy )
00683         {
00684                 // Update the dependent mode requests for non-lazy mode.
00685                 if ( !isLazy )
00686                 {
00687                         // have to use valid Nodes and valid Edges
00688                         validNodes = TRUE;
00689                         validEdges = TRUE;
00690                 }
00691         }
00692         else 
00693         {
00694                 // update the requirement for a form of lazy if valid nodes or edges have not been requested
00695                 if ( (!validNodes) || (!validEdges) )
00696                 {
00697                         isLazy = TRUE;
00698                 }
00699         }
00700 
00701         // Check if lazy mode has been changed, thus requiring the graph mode to be changed
00702         if ( lazyMode != isLazy )
00703         {
00704                 // Tree graph is required if lazy is turned off, and a fully connected graph is turned on.
00705                 SetGraphMode( !isLazy );
00706         }
00707 
00708         // Update the switches with any mode changes
00709         lazyMode = isLazy;
00710         validNodesOnly = validNodes;
00711         validEdgesOnly = validEdges;
00712         
00713 }
00714 
00715 
00716 //=============================================================================
00717 // GetPRMMode
00718 //
00719 // Purpose: Gets the mode dependent switches for the different variations of PRM
00720 //=============================================================================
00721 void PL_PRM::GetPRMMode ( BOOL& isLazy, BOOL& validNodes, BOOL& validEdges ) const
00722 {
00723         // Return the current mode settings
00724         isLazy = lazyMode;
00725         validNodes = validNodesOnly;
00726         validEdges = validEdgesOnly;
00727 
00728 }
00729 
00730 //=============================================================================
00731 // SetCollisionDetector
00732 //
00733 // Purpose: Assigns the collision detector and then updates PRM specific parameters
00734 //                  based on the collision detector.
00735 //=============================================================================
00736 void PL_PRM::SetCollisionDetector (CD_BasicStyle* collisionDetector)
00737 {
00738         // Call Parent's Collision Detector and assign the collision detector
00739         PL_GraphBase::SetCollisionDetector( collisionDetector );
00740 
00741         // Calculate the diagonal length now that we have some DOF
00742         diagonal_squared = GetCspaceRange();
00743 
00744 
00745 }
00746 
00747 //=============================================================================
00748 // SetStartConfig
00749 //
00750 // Purpose: Sets the start config and connects the node associated with it to 
00751 //                      the current graph.
00752 //=============================================================================
00753 void PL_PRM::SetStartConfig( const Configuration& config )
00754 {
00755         // Check if the configuration has changed.
00756         if (( GetStartConfig() == config ) && ( startNode != nil ) )
00757         {
00758                 // no change in configuration.  Can exit early.
00759                 return;
00760         }
00761 
00762         // Set the startConfig, add it to the graph, and assign the startNode to it by
00763         // calling the parent's SetStartConfig.
00764         PL_GraphBase::SetStartConfig( config );
00765 
00766         // Verify the startNode was initiated.
00767         ASSERT( startNode != nil );
00768 
00769         // Check if the startNode is already graph connected and connect it if it isn't.
00770         // StartNode could possible not be graph connected because it was just added.
00771         if ( G.degree( startNode ) < 1 )
00772         {
00773                 // node is not connected.  Do so now.
00774                 ConnectNode( startNode );
00775         }
00776 
00777         // Since we have added a new configuration, we want to start a fresh planning session,
00778         // so indicate we want to start a new session.
00779         lastPlanningState = PRM_START;
00780 
00781 }
00782 
00783 //=============================================================================
00784 // SetGoalConfig
00785 //
00786 // Purpose: Sets the goal config and connects the node associated with it to 
00787 //                      the current graph.
00788 //=============================================================================
00789 void PL_PRM::SetGoalConfig( const Configuration& config )
00790 {
00791         // Check if the configuration has changed.
00792         if (( GetGoalConfig() == config ) && ( goalNode != nil ))
00793         {
00794                 // no change in configuration.  Can exit early.
00795                 return;
00796         }
00797 
00798         // Set the goalConfig, add it to the graph, and assign the goalNode to it by
00799         // calling the parent's SetGoalConfig.
00800         PL_GraphBase::SetGoalConfig( config );
00801 
00802         // Verify the goalNode was initiated.
00803         ASSERT( goalNode != nil );
00804 
00805         // Check if the goalNode is already graph connected and connect it if it isn't.
00806         // GoalNode could possible not be graph connected because it was just added.
00807         if ( G.degree( goalNode ) < 1 )
00808         {
00809                 // node is not connected.  Do so now.
00810                 ConnectNode( goalNode );
00811         }
00812 
00813         // Since we have added a new configuration, we want to start a fresh planning session,
00814         // so indicate we want to start a new session.
00815         lastPlanningState = PRM_START;
00816 
00817 }
00818 
00819 
00820 //=============================================================================
00821 // SetGraphMode
00822 //
00823 // Purpose:  Sets the graph mode for either connect tree or fully connected graph.
00824 //                       If set for tree mode, the current graph is cleared and the connection ID lists
00825 //                       are intialized.  
00826 //                       If set for fully connected graph, then the existing graph is kept, but the
00827 //                       connection ID lists are deleted.  To switch back to tree graph, the graph
00828 //                       will be cleared.
00829 //=============================================================================
00830 void PL_PRM::SetGraphMode ( const bool& treeGraph )
00831 {
00832         if ( treeGraph )
00833         // Update Graph for a tree graph
00834         {
00835                 // Clear the existing graph.
00836                 ClearGraph();
00837 
00838                 // Initialize the connection ID pointer and base counter
00839                 baseConnectID = DEFAULTBASECONNECTID;
00840                 if ( connectIDp != NULL )
00841                 {
00842                         delete connectIDp;
00843                 }
00844                 connectIDp = new node_map<int>(G,0);
00845         }
00846         // Update the graph for a fully connected graph
00847         else {
00848                 // Delete the connectionID list.  
00849                 if ( connectIDp != NULL )
00850                 {
00851                         delete connectIDp;
00852                         connectIDp = NULL;
00853                 }
00854 
00855                 baseConnectID = DEFAULTBASECONNECTID;
00856         }
00857 
00858 
00859 }
00860 
00861 //=============================================================================
00862 // NodeInConnectionList
00863 //
00864 // Purpose: Checks if the given node has a connectionID that matches the given
00865 //                      connection ID list.  Returns FALSE if connectIDp is not valid.
00866 //=============================================================================
00867 bool PL_PRM::NodeInConnectionList( const node& n1, const list<int>& connectIDs)
00868 {
00869         if ( connectIDp == NULL )
00870         {
00871                 return false;
00872         }
00873 
00874         int id;
00875 
00876         forall( id, connectIDs )
00877         {
00878                 if ( (*connectIDp)[n1] == id )
00879                 {
00880                         return true;
00881                 }
00882         }
00883 
00884         // if still in function, node is not in given connectID list.
00885         return false;
00886 
00887 }
00888 
00889 
00890 //=============================================================================
00891 // AddNode
00892 //
00893 // Purpose: Adds a uniformly distributed random configuration into the graph.
00894 //                      Returns TRUE if the node was successfully added.
00895 //=============================================================================
00896 BOOL PL_PRM::AddNode()
00897 {
00898         Configuration newConfig;
00899 
00900         bool validConfig = FALSE;
00901         while ( !validConfig )
00902         {
00903                 newConfig = GenerateRandomConfig();
00904 
00905                 if ( validNodesOnly )
00906                 // Check if collision detection is requried
00907                 {
00908                         // check if config is valid
00909                         if ( IsInterfering( newConfig ) )
00910                         {
00911                                 validConfig = FALSE;
00912 
00913                                 // add this config as a seed 
00914                                 config_seeds.append( newConfig );
00915                         }
00916                         else
00917                         {
00918                                 validConfig = TRUE;
00919                         }
00920                 }
00921                 else
00922                 {
00923                         // since we do not care if invalid nodes are added, all configs are considered valid
00924                         validConfig = TRUE;
00925                 }
00926 
00927                 if ( HasTimeLimitExpired() )
00928                 {
00929                         return FALSE;
00930                 }
00931         }  // end while
00932 
00933 
00934         node newNode = G.new_node( newConfig );
00935 
00936         if (newNode != nil)
00937         {
00938                 // Report if node has been checked for collisions by its addition type.
00939             nodeChecked[newNode] = validNodesOnly;
00940 
00941                 // Node has been added uniformly
00942                 uniformlyAdded[newNode] = TRUE;
00943 
00944                 // Connect the new node
00945                 ConnectNode( newNode );
00946 
00947                 return TRUE;    // node was successfully added
00948         }
00949         else
00950         {
00951                 return FALSE;   // node was not successfullt added.
00952         }
00953 }
00954 
00955 //=============================================================================
00956 // ConnectNode
00957 //
00958 // Purpose: Connects the given node with edges to neighbours within the tolerance
00959 //                  radius, calculated from the radiusTol and the diagonal length.
00960 //                      
00961 //                      This function calls the appropriate connect edges style function depending
00962 //                      on the PRM implemenation selected.
00963 //=============================================================================
00964 void PL_PRM::ConnectNode( const node& newnode )
00965 {
00966         if ( lazyMode )
00967         {
00968                 // Lazy PRM selected
00969                 //    radiusTol are squared since we are dealing with squared distances, therefore the fraction
00970                 //        also needs to be squared:  (frac*dist)^2 = frac^2*dist^2 = frac^2*(dist_squared);
00971                 ConnectEdgesLazy( newnode, radiusTol*radiusTol*diagonal_squared );
00972         }
00973         else
00974         {
00975                 // Full PRM selected
00976                 ConnectEdgesFull( newnode, radiusTol*radiusTol*diagonal_squared );
00977         }
00978 
00979 }
00980 
00981 
00982 //=============================================================================
00983 // ConnectEdgesLazy
00984 //
00985 // Purpose: Connects the node to the graph Lazy PRM Style:  connects to all nodes 
00986 //              within given sqauared radius.  Does not perform any type of collision 
00987 //                      detecting when connecting edges.
00988 //=============================================================================
00989 void PL_PRM::ConnectEdgesLazy( const node& newnode, const double& radius_squared )
00990 {
00991         // Save calculation time by determining configuration of the node once intstead of in each iteration
00992         Configuration nodeconfig = G.inf(newnode);
00993 
00994         //  Search all nodes in graph, selecting those within radius and add an edge to join them with new node
00995         node testnode;
00996         forall_nodes( testnode, G )
00997         {
00998                 if ( newnode != testnode)
00999                 {
01000                         double edgelength_squared = Distance( nodeconfig, G.inf(testnode) );  // returns the squared distance
01001                         // Check if the two nodes are within radius
01002                         if (  edgelength_squared <= radius_squared )  // can compare squares since a^2<b^2 if |a|<|b|
01003                         {
01004                                 bool addedge = TRUE;
01005 
01006                                 // connect edge based on its addition type
01007                                 if ( validEdgesOnly )
01008                                 {
01009                                         if ( IsInterfering( nodeconfig, G.inf(testnode) ) )
01010                                         {
01011                                                 addedge = FALSE;
01012 
01013                                                 // Add the midpoint of this potential edge as a seed, if requested
01014                                                 if ( useMidPts )
01015                                                 {
01016                                                         Configuration midpt = GetMidPoint( nodeconfig, G.inf(testnode) );
01017                                                         config_seeds.append( midpt );
01018                                                 }
01019                                         }
01020                                 } // end if ValidEdges
01021 
01022                                 if ( addedge )
01023                                 {
01024                                         // connect the two nodes with an edge and store the actual distance (sqrt) as the cost of the length
01025                                         double edgelength = sqrt( edgelength_squared );
01026                                         edge newedge = G.new_edge ( newnode, testnode, edgelength ); 
01027 
01028                                         // new edge has been collision if a validEdge was requested.
01029                                         edgeChecked[newedge] = validEdgesOnly;
01030                                 }  // end if addedge
01031                         }  // end if within neighbourhood
01032                 }  // end if not testnode
01033         }  // end for loop
01034 } // end ConnectEdgesLazy
01035 
01036 
01037 //=============================================================================
01038 // ConnectEdgesFull
01039 //
01040 // Purpose: Connects the node to the graph Full PRM Style:  tree graph connect to 
01041 //          closest nodes only; any other nodes that are within the given squared radius, 
01042 //          but are already graph connected will not be connected again.
01043 //
01044 //                      This function will perform collision detection for each potential edge,
01045 //                      only connecting those that do not contain a collision.
01046 //=============================================================================
01047 void PL_PRM::ConnectEdgesFull(const node& newnode, const double& radius_squared)
01048 {
01049         // verify connectIDp is valid.
01050         ASSERT( connectIDp != NULL );
01051 
01052         // Save calculation time by determining configuration of the node once intstead of in each iteration
01053         Configuration nodeconfig = G.inf(newnode);
01054 
01055         node n1;
01056 
01057         // create a list of neighbour nodes to connect to within the given radius.
01058         node_pq<double> neighbours(G);
01059         forall_nodes( n1, G)
01060         {
01061                 if ( newnode != n1)
01062                 {
01063                         double edgelength_squared = Distance( nodeconfig, G.inf(n1) );  // returns the squared distance
01064                         // Check if the two nodes are within radius
01065                         if (  edgelength_squared <= radius_squared )  // can compare squares since a^2<b^2 if |a|<|b|
01066                         {
01067                                 // node is within radius, add it as a neighbour with its distance as its priority.
01068                                 neighbours.insert( n1, edgelength_squared );
01069                         }
01070                 }
01071         }
01072 
01073         // New node is currently not connected to anyone, assign it the NIL_ID.
01074         (*connectIDp)[newnode] = NIL_ID;
01075 
01076         // Create a running list of graph connected components new node is attached to.
01077         list<int> connectIDs;
01078 
01079         // While the list of neighbour is not empty, connect the node to the closests nodes, not already graph
01080         // connected to.
01081         while ( !neighbours.empty() )
01082         {
01083                 // get closest neighbour and remove it from the list
01084                 node neighbour = neighbours.find_min();
01085                 double dist_sq = neighbours.inf( neighbour );
01086                 neighbours.del( neighbour );
01087 
01088                 // connect the neighbour to the new node if it is not already graph connected.
01089                 // A node is graph connected if its current connectID is in the running list of
01090                 // connected graph components or has the same connectID as the new node.
01091                 if ( ((*connectIDp)[neighbour] == NIL_ID) ||
01092                          ( ((*connectIDp)[neighbour] != (*connectIDp)[newnode]) &&
01093                            ( !NodeInConnectionList(neighbour, connectIDs) ) )
01094                    )
01095                 {
01096                         // nodes are not aleady connected.  Connect them now if there is a collision free path.
01097                         if ( !IsInterfering( nodeconfig, G.inf(neighbour) ) )
01098                         {
01099                                 double edgelength = sqrt( dist_sq );
01100                                 edge newedge = G.new_edge( newnode, neighbour, edgelength );
01101                                 edgeChecked[newedge] = TRUE;
01102 
01103                                 // update the connectionIDs to show these two nodes are now graph connected.
01104                                 if ( (*connectIDp)[neighbour] != NIL_ID )
01105                                 // neighbour node has been previously connected to a graph component.
01106                                 {
01107                                         if ( (*connectIDp)[newnode] == NIL_ID )
01108                                         {
01109                                                 // node has not been previously connected, assign it the connect ID of its new neighbour.
01110                                                 (*connectIDp)[newnode] = (*connectIDp)[neighbour];
01111                                         }
01112                                         else if ( (*connectIDp)[neighbour] < (*connectIDp)[newnode] )
01113                                         {
01114                                                 // the neighbour node has the smaller ID.  Select this as the new ID for the two
01115                                                 // newly connected graph components (one from the new neighbour, one from the new node).
01116 
01117                                                 // save the old connectionID into the running list to be updated later.
01118                                                 connectIDs.push( (*connectIDp)[newnode] );
01119 
01120                                                 // assign the lower connection ID to the new node.
01121                                                 (*connectIDp)[newnode] = (*connectIDp)[neighbour];
01122                                         }
01123                                         else
01124                                         {
01125                                                 // the new node has the smaller ID.  Select this as the new ID for the two components.
01126 
01127                                                 // save the old connectionID into the running list to be updated later.
01128                                                 connectIDs.push( (*connectIDp)[neighbour] );
01129 
01130                                                 // assign the lower connection ID to the neighbour.
01131                                                 (*connectIDp)[neighbour] = (*connectIDp)[newnode];
01132                                         }
01133                                 }  // end if neighbour != NIL_ID
01134                                 else
01135                                 // neighbour has not been previously connected.
01136                                 {
01137                                         if ( (*connectIDp)[newnode] != NIL_ID )
01138                                         {
01139                                                 // new node has been previously connected, assign the neighbour its ID.
01140                                                 (*connectIDp)[neighbour] = (*connectIDp)[newnode];
01141                                         }
01142                                         else
01143                                         {
01144                                                 // both nodes have not been previously connected.  Create a new graph connected
01145                                                 // component by assigning these two nodes the baseConnectID.
01146                                                 (*connectIDp)[newnode] = baseConnectID;
01147                                                 (*connectIDp)[neighbour] = baseConnectID;
01148 
01149                                                 // Update the base connect ID to ensure a new unique ID is available for next new node.
01150                                                 baseConnectID++;
01151                                         }
01152                                 }  // end update connectIDs.
01153 
01154                         } // end if interfering
01155                         else
01156                         {
01157                                 // nodes have a collision path.  Use the midpoint between these two nodes as a seed for enhancing.
01158                                 // Add the midpoint of this potential edge as a seed, if requested
01159                                 if ( useMidPts )
01160                                 {
01161                                         Configuration midpt = GetMidPoint( nodeconfig, G.inf(neighbour) );
01162                                         config_seeds.append( midpt );
01163                                 }
01164                         }  // end if interfering else.
01165 
01166                 }       // end if not already graph connected.
01167 
01168         } // end while !neighbours.empty().
01169 
01170         // Search the entire graph, if required, updating connectIDs to reflect how new node has graph connected
01171         // different components of the graph.
01172         if ( ((*connectIDp)[newnode] != NIL_ID) && ( !connectIDs.empty() ) )
01173         {
01174                 // new node is connected to more than one graph connected component.  Update the connect IDs of
01175                 // affected nodes.
01176                 int newID = (*connectIDp)[newnode];
01177 
01178                 forall_nodes( n1, G )
01179                 {
01180                         if ( ((*connectIDp)[n1] != newID ) && (NodeInConnectionList( n1, connectIDs )) )
01181                         {
01182                                 (*connectIDp)[n1] = newID;
01183                         }
01184                 }
01185         }  // end update connectIDs of entire graph
01186 
01187                 
01188         return;
01189 }       // end ConnectEdgesFull
01190 
01191 
01192 //=============================================================================
01193 // BuildInitRoadMap
01194 //
01195 // Purpose: Adds nodes according to specified PRM implemenation until the
01196 //                  mininium amount of nodes have been added.
01197 //
01198 //                      Function will exit early if the timer has expired.
01199 //=============================================================================
01200 SuccessResultType PL_PRM::BuildInitRoadMap()
01201 {
01202         // Keep adding additional nodes and connect them until initQuant is acheived.
01203         for (int i = NodeCount(); i < initQuant; i++ )
01204         {
01205                 // Add the nodes
01206                 AddNode();
01207 
01208                 // Check if Time has expired
01209                 if ( HasTimeLimitExpired() )
01210                 {
01211                         return TIMER_EXPIRED;
01212                 }
01213 
01214         }  // end For Loop
01215 
01216         return PASS;
01217 }
01218 
01219 //=============================================================================
01220 // FindPath
01221 //
01222 // Purpose: Performs the A* search on the current roadmap (graph) to determine
01223 //                      a [shortest] path between start and goal nodes.  If no path is found,
01224 //                      the function will return failure.
01225 //
01226 //                      Function will exit early if the timer has expired.
01227 //=============================================================================
01228 SuccessResultType PL_PRM::FindPath()
01229 {
01230 
01231         // Going to emulate the A* Algorithm.
01232         node n1;                    //stores the current node
01233 
01234         // All storage structures are stored as private members or pointers of this class.
01235         
01236         graphPath.clear();      // Clears any previous preposal path.
01237                                         
01238 
01239         // Check if we are continuing from a previously expired search, and if not, initialize a fresh search.
01240         if ( lastPlanningState != PRM_FIND_PATH )
01241         // We are starting fresh.  Initialize the search.
01242         {
01243                 // Initialize search lists.
01244                 pred.init(G,nil);       // Associates pred edge pointers to current graph and initializes them to nil.
01245                 dist.init(G,0);         // Associates the current cost of each of the nodes with the current graph.
01246                 
01247                 // Assign the cost of the first node
01248                 dist[startNode] = 0;
01249 
01250                 // Create the a new priority queue of open nodes.
01251                 if ( openp != NULL )
01252                 {
01253                         delete openp;
01254                 }
01255                 openp = new node_pq<double>(G);
01256                 openp->clear();
01257 
01258                 // Start Open queue
01259                 openp->insert(startNode,0);     // priority set with 0 to ensure it is the first to be selected
01260         }
01261         else
01262         // We are using an exisiting search.  Leave all parameters as before.
01263         {
01264                 // Indicate we have entered this loop because the previous search expired and ensure
01265                 // we re-enter this state function fresh on the next iteration.
01266                 lastPlanningState = PRM_TIMER_EXPIRED;
01267 
01268         }
01269 
01270 
01271         // While OPEN is not empty
01272         while ( !openp->empty() )
01273         {
01274                 // Check to make sure timer has not expired.
01275                 if ( HasTimeLimitExpired() )
01276                 {
01277                         // Timer has expired.
01278 
01279                         // current state variables are saved, include the open priority queue which is not deleted.
01280 
01281                         // Report the timer has expired.
01282                         return TIMER_EXPIRED;
01283                 }
01284 
01285                 //Remove the lowest cost node from open queue
01286                 n1 = openp->del_min();
01287 
01288                 // check if goal has been found
01289                 if ( n1 == goalNode )
01290                 // found goal.
01291                 {
01292                         // Store the current path.
01293                         graphPath.clear();
01294                         graphPath.push( n1 );
01295 
01296                         // Starting with the goal, go up through path, adding each of the prev nodes
01297                         // to the path as they are found.
01298                         while ( n1 != startNode )
01299                         {
01300                                 node n0 = pred[n1];             // get the prev node
01301                                 
01302                                 // Add prev node to front of the path.
01303                                 graphPath.push( n0 );
01304 
01305                                 // Prepare for next iteration: the prev node will be the current node.
01306                                 n1 = n0;
01307                         }
01308 
01309                         // No longer need the open priority queue list.  Delete it.
01310                         delete openp;
01311                         openp = NULL;
01312 
01313                         // A path has been successfully found.
01314                         return PASS;
01315                                         
01316                 }
01317                 else
01318                 {
01319                         // Expand all successor nodes (all nodes that graph connected to current node)
01320                         // NOTE:  TO find the successor nodes, we search all nodes connected by edges (bi-diretional) to
01321                         //                the current node.  Eventually the prev node in the path will be selected, however, it will
01322                         //                never be updated as one of the potential successor nodes since the current cost of getting
01323                         //                to the current node, includes going through the previous node.  This means a newcost of the
01324                         //                actual cost to the current node plus the cost of travelling back from the current node
01325                         //                to the prev node will be higher than the cost of getting to the prev node by not passing through
01326                         //                the current node.  Cost:  cost[A] < cost[A] + cost(A to B) + cost(B back to A)!
01327 
01328                         node n2;        // successor node.  n1 = curr node.
01329                         edge e1;        // scanning edge.
01330 
01331                         
01332                         forall_inout_edges(e1, n1)
01333                         {
01334                                 // find the successor node.   (since edges are in both directions, will have to examine
01335                                 // both the target and source node of the edge.  If either is the current node, then the
01336                                 // opposite node is the correct successor node. 
01337 
01338                                 n2 = G.source(e1);
01339                                 if ( n2 == n1)
01340                                 {
01341                                         // edge was pointing from current node, so select the target node as the successor
01342                                         n2 = G.target(e1);
01343                                 }
01344 
01345                                 // check if new node is uninitialized
01346                                 if ( ( pred[n2] == nil ) && ( n2 != startNode ) )
01347                                 {
01348                                         // record current node as the prev node for the successor
01349                                         pred[n2] = n1;
01350                                         
01351                                         // Assign a cost (dist) to successor node
01352                                         dist[n2] = dist[n1] + G.inf(e1);  // length of path upto current node point plus cost of using edge to this node
01353                                                 
01354                                         //Add this node to open priority queue based on its estimated cost for the entire path
01355                                         openp->insert( n2, Astar_f(n2, dist[n2]) );
01356                                 }
01357                                 else
01358                                 {
01359                                         // check if path to this node is cheaper than the existing path
01360                                         double currcost = dist[n2];
01361                                         double newcost  = dist[n1] + G.inf(e1);
01362 
01363                                         // if new path is cheaper, update the parameters
01364                                         if ( newcost < currcost )
01365                                         {
01366                                                 // record current node as the prev node for the successor
01367                                                 pred[n2] = n1;
01368                                         
01369                                                 // Assign new cost to this node
01370                                                 dist[n2] = newcost;
01371 
01372                                                 // Find priority for new node:  cost upto this node + estimated distance to goal. 
01373                                                 double priority = Astar_f(n2, dist[n2]);
01374 
01375                                                 // check if this node is in the priority queue
01376                                                 if ( openp->member(n2) )
01377                                                 {
01378                                                         // already in queue, decrease its priority
01379                                                         openp->decrease_p( n2, priority );
01380                                                 }
01381                                                 else
01382                                                 {
01383                                                         // not in queue, add it
01384                                                         openp->insert( n2, priority );
01385                                                 }
01386                                         } // end if newcost < currcost
01387                                 } // end if uninitialized
01388                         } // end forall_inout_edges
01389 
01390                 } // end if not goal
01391 
01392                                 
01393         }  // end while
01394 
01395         // No longer need the open queue, delete it.
01396         delete openp;
01397         openp = NULL;
01398 
01399         // Fall through the While Loop => no path between start and goal has been found.
01400         return FAIL;
01401 }
01402 
01403 //=============================================================================
01404 // VerifyPath
01405 //
01406 // Purpose: Checks the proposed path to ensure all nodes and edges are collision
01407 //                      free.  Will delete the first node or edge it finds that contains a 
01408 //                      collision and report failure.  If the entire path is collision free,
01409 //                      will report success.
01410 //
01411 //                      Function will exit early if the timer has expired.
01412 //=============================================================================
01413 SuccessResultType PL_PRM::VerifyPath()
01414 {
01415         // Starting from opposite ends of the path and working towards
01416         // the centre, check for collisions.
01417 
01418         if ( graphPath.empty() )
01419         {
01420                 // There is no path to verify
01421                 return FAIL;
01422         }
01423 
01424         // Check each of the nodes of the path
01425         node n0 = graphPath.head();
01426         node n1 = graphPath.tail();
01427 
01428         // Starting from the ends and working towards the centre, check each node for collisions
01429         while ( TRUE )
01430         {
01431                 // Check the Timer
01432                 if ( HasTimeLimitExpired() )
01433                 {
01434                         return TIMER_EXPIRED;
01435                 }
01436 
01437                 if (!nodeChecked[n0])
01438                 {
01439                         // Check for collision
01440                         if ( IsInterfering( n0 ) )
01441                         {
01442                                 // Use the midpoint between the last valid node and this node as a seed if the
01443                                 // colliding node was uniformly added.
01444                                 if ( uniformlyAdded[n0] )
01445                                 {
01446                                         Configuration midpoint = GetMidPoint( G.inf(n0), G.inf( graphPath.cyclic_pred( n0 ) ) );
01447                                         config_seeds.append( midpoint );
01448                                 }
01449 
01450                                 // Node interfers...delete it.
01451                                 G.del_node( n0 );
01452 
01453                                 // A node in this path collides.  Therefore path is not valid.
01454                                 return FAIL;
01455                         }
01456                         else
01457                         {
01458                                 // Node has just been checked OK!
01459                                 nodeChecked[n0] = TRUE;
01460                         }
01461 
01462                 }
01463 
01464                 // Check if we sitting the middle node, which we just checked.
01465                 if ( n0 == n1 )
01466                 {
01467                         break;
01468                 }
01469 
01470                 if (!nodeChecked[n1])
01471                 {
01472                         // Check for collision
01473                         if ( IsInterfering( n1 ) )
01474                         {
01475 
01476                                 // Use the midpoint between the last valid node and this node as a seed is the problem node was uniformly added.
01477                                 if ( uniformlyAdded[n1] )
01478                                 {
01479                                         Configuration midpoint = GetMidPoint( G.inf(n1), G.inf( graphPath.cyclic_succ( n1 ) ) );
01480                                         config_seeds.append( midpoint );
01481                                 }
01482 
01483                                 // Node interfers...delete it.
01484                                 G.del_node( n1 );
01485 
01486                                 // A node in this path collides.  Therefore path is not valid.
01487                                 return FAIL;
01488                         }
01489                         else
01490                         {
01491                                 // Node has just been checked OK!
01492                                 nodeChecked[n1] = TRUE;
01493                         }
01494                 }
01495 
01496                 // Move nodes towards centre
01497                 n0 = graphPath.succ( n0 );
01498 
01499                 // Check if we are about to cross the middle
01500                 if ( n0 == n1 )
01501                 {
01502                         break;
01503                 }
01504 
01505                 n1 = graphPath.pred( n1 );
01506 
01507         } // End While loop.
01508 
01509         // IF still in this function, then all nodes of path have been verifed.  Now
01510         // check the edges.
01511         // Again, starting from the ends and working towards the centre, check edge for
01512         // collision.
01513 
01514         // the two nodes marking the edge to check at the front of the path.
01515         node front0 = graphPath.head();
01516         node front1 = graphPath.succ( front0 );
01517 
01518         // the two nodes marking the edge to check at the back of the path.
01519         node back1 = graphPath.tail();
01520         node back0 = graphPath.pred( back1 );
01521 
01522         while ( TRUE )
01523         {
01524                 // Check the Timer
01525                 if ( HasTimeLimitExpired() )
01526                 {
01527                         return TIMER_EXPIRED;
01528                 }
01529 
01530                 // Get edge at the front of the path
01531                 edge e0 = FindEdge( front0, front1 );
01532                 if ( e0 == nil )
01533                 {
01534                         // no edge found joining the two nodes. Report failure.
01535                         return FAIL;
01536                 }
01537                 
01538                 // Check edge for collision if it has not already been done so.
01539                 if ( !edgeChecked[e0] )
01540                 {
01541                         // Check for collision
01542                         if ( IsInterfering( e0 ) )
01543                         {
01544                                 // Obtain the midpoint along this colliding edge and use it as a seed during enhancing if
01545                                 // the end node was uniformly added and edge midpoints are requested.
01546                                 if ( (useMidPts) && ( uniformlyAdded[front1] ) )
01547                                 { 
01548                                         Configuration midpt = GetMidPoint( G.inf(front0), G.inf(front1) );
01549                                         config_seeds.append( midpt );
01550                                 }
01551 
01552                                 // Edge has collision...delete it.
01553                                 G.del_edge( e0 );
01554 
01555                                 // An edge in this path collides.  Therefore path is not valid.
01556                                 return FAIL;
01557                         }
01558                         else
01559                         {
01560                                 // Edge has just been checked OK!
01561                                 edgeChecked[e0] = TRUE;
01562                         }
01563                 }
01564 
01565                 // Check if we are on the middle edge of the path. (both sets of nodes surrounding same edge)
01566                 if ( front1 == back1 )
01567                 {
01568                         // on middle edge.  Check complete.
01569                         break;
01570                 }
01571 
01572                 // Get edge at back of the path
01573                 e0 = FindEdge( back0, back1 );
01574                 if ( e0 == nil )
01575                 {
01576                         // no edge found joining the two nodes. Report failure.
01577                         return FAIL;
01578                 }
01579                 
01580                 // Check edge for collision if it has not already been done so.
01581                 if ( !edgeChecked[e0] )
01582                 {
01583                         // Check for collision
01584                         if ( IsInterfering( e0 ) )
01585                         {
01586                                 // Obtain the midpoint along this colliding edge and use it as a seed during enhancing if
01587                                 // the end node was uniformly added and edge midpoints are requested
01588                                 if ( (useMidPts) && ( uniformlyAdded[back0] ) )
01589                                 {
01590                                         Configuration midpt = GetMidPoint( G.inf(back1), G.inf(back0) );
01591                                         config_seeds.append( midpt );
01592                                 }
01593 
01594                                 // Edge has collision...delete it.
01595                                 G.del_edge( e0 );
01596 
01597                                 // An edge in this path collides.  Therefore path is not valid.
01598                                 return FAIL;
01599                         }
01600                         else
01601                         {
01602                                 // Edge has just been checked OK!
01603                                 edgeChecked[e0] = TRUE;
01604                         }
01605                 }
01606 
01607                 // Move the nodes
01608                 front0 = front1;
01609                 front1 = graphPath.succ( front1 );
01610 
01611                 // Check if we are on an edge that was just checked by the back set, indicating
01612                 // we are in the middle of the path.
01613                 if ( front1 == back1 )
01614                 {
01615                         // Middle edge, check complete.
01616                         break;
01617                 }
01618 
01619                 back1 = back0;
01620                 back0 = graphPath.pred( back0 );
01621         
01622         }  // End While
01623 
01624         // If we are still in the function, then path has been completely verified.  
01625         // Report success.
01626         return PASS;
01627 }
01628 
01629 
01630 //=============================================================================
01631 // EnhanceRoadmap
01632 //
01633 // Purpose: Determine the troublesome areas of the roadmap (graph) and add more
01634 //                      nodes and edges in these areas.  The next time the findpath routine is
01635 //                      called, hopefully the new nodes and edges generated will allow for a
01636 //                      successful path.
01637 //
01638 //                      Function will exit early if the timer has expired.
01639 //=============================================================================
01640 SuccessResultType PL_PRM::EnhanceRoadMap()
01641 {
01642         // Add the requested number of enhanced nodes to roadmap.
01643 
01644         // Enhancing is done in two steps:  nodes added using seeds based on previosly deleted nodes and edges
01645         //                                                                      then additional nodes distributed uniformly across C-space.
01646 
01647         int uniformQuant = enhanceQuant;
01648 
01649         if ( !config_seeds.empty() )
01650         {
01651                 // Half the new nodes will be based on seeds.  The remainder will be uniformly distributed.
01652                 int seedQuant = double(enhanceQuant * seedRatio);
01653                 uniformQuant = enhanceQuant - seedQuant;
01654 
01655                 // Want to distribute an even number of enhance nodes for each seed, so continue to cyclic search
01656                 // through the list until enhance quant has been met.  Then clear the seeds so we do not use them again.
01657                 list_item seedindex = config_seeds.first();
01658                 //list_item firstindex = seedindex;
01659                 //bool gone_through_all = FALSE;
01660 
01661                 double std_dev = 0.5 * radiusTol * sqrt( diagonal_squared );
01662 
01663                 for ( int i = 0; i < seedQuant; i++ )
01664                 {
01665                         // Get a configuration normally distributed about the seed.
01666                         Configuration newConfig;
01667                         
01668                         bool validConfig = FALSE;
01669                         while (!validConfig)
01670                         {
01671                                 newConfig = GenerateRandomConfig( config_seeds.inf( seedindex ), std_dev );
01672 
01673                                 // NOTE:  order of argurments in if statment is vital; interference checking will only be done if validNodesOnly.
01674                                 if ( (validNodesOnly) && (IsInterfering( newConfig )) ) 
01675                                                                 
01676                                 {
01677                                         validConfig = FALSE;
01678                                 }
01679                                 else
01680                                 {
01681                                         validConfig = TRUE;
01682                                 }
01683                         }
01684 
01685                         node newNode = G.new_node( newConfig );
01686 
01687                         ASSERT ( newNode != nil );
01688 
01689                         // Node has been checked for collisions if validNodesOnly.
01690                         nodeChecked[newNode] = validNodesOnly;
01691 
01692                         // Node was added as part of a seed and not uniformly
01693                         uniformlyAdded[newNode] = FALSE;
01694 
01695                         // Connect the new node
01696                         ConnectNode( newNode );
01697 
01698                         // Check if Time has expired
01699                         if ( HasTimeLimitExpired() )
01700                         {
01701                                 return TIMER_EXPIRED;
01702                         }
01703 
01704                         // Advance to next seed
01705                         seedindex = config_seeds.cyclic_succ( seedindex );
01706                         /*if ( seedindex == firstindex )
01707                         {
01708                                 // gone through all the seeds at least once.
01709                                 gone_through_all = TRUE;
01710                         }*/
01711 
01712                 }       // end for loop.
01713 
01714                 // Finished adding nodes about these seeds.  Clear list for next time.
01715                 config_seeds.clear();           // start with a fresh seed list.
01716                 /*if ( gone_through_all )
01717                 {
01718                         // all seeds have been used.  Clear list
01719                         config_seeds.clear();
01720                 }
01721                 else
01722                 {
01723                         // save any seeds that weren't used by removing those that were.
01724                         while ( firstindex != seedindex )
01725                         {
01726                                 config_seeds.erase( firstindex );
01727                                 firstindex = config_seeds.first();
01728                         }
01729 
01730                 } */
01731 
01732         }  // end if-then
01733 
01734 
01735         // Add the remaining number of enhanceQuant nodes uniformly
01736         for (int i = 0; i < uniformQuant; i++ )
01737         {
01738                 // Add the nodes
01739                 AddNode();
01740 
01741                 // Check if Time has expired
01742                 if ( HasTimeLimitExpired() )
01743                 {
01744                         return TIMER_EXPIRED;
01745                 }
01746 
01747         }  // end For Loop
01748 
01749                         
01750         // Return Success.
01751         return PASS;
01752 }
01753 
01754 
01755 //=============================================================================
01756 // Astar_f
01757 //
01758 // Purpose: Estimates the cost of the path based on the given node.
01759 //                      Returns the cost of the path upto the current node (given as a parameter)
01760 //                      and estimates the cost from current node to the goal.
01761 //=============================================================================
01762 double PL_PRM::Astar_f( const node& n, const double& currcost ) const
01763 {
01764         return currcost + sqrt(Distance( n, goalNode ));  
01765 }
01766 
01767 //=============================================================================
01768 // CopySettings
01769 //
01770 // Purpose: copies the settings from a different planner
01771 //=============================================================================
01772 void PL_PRM::CopySettings( PlannerBase* original )
01773 {
01774         PL_GraphBase::CopySettings( original );
01775         PL_PRM* originalPrm = dynamic_cast< PL_PRM* >( original );
01776         if( originalPrm == NULL )
01777         {
01778                 return;
01779         }
01780         this->validEdgesOnly = originalPrm->validEdgesOnly;
01781         this->validNodesOnly = originalPrm->validNodesOnly;
01782         this->seedRatio = originalPrm->seedRatio;
01783         this->radiusTol = originalPrm->radiusTol;
01784         this->useMidPts = originalPrm->useMidPts;
01785         this->initQuant = originalPrm->initQuant;
01786         this->enhanceQuant = originalPrm->enhanceQuant;
01787         this->lazyMode = originalPrm->lazyMode;
01788 
01789         // Set the graph mode based on lazyMode.
01790         SetGraphMode( !lazyMode );
01791 }
01792 
01793 
01794 void *PL_PRM::GetParameters()
01795 {
01796         PL_GraphBase::GetParameters();
01797         //if (paramBuffer)
01798         //      return paramBuffer;
01799 
01800         char szLine[255];
01801 
01802         //Test size first;
01803         int bufferLen = 0;
01804         sprintf(szLine, "Validate Edges Only: %d\n", validEdgesOnly);
01805         bufferLen += strlen(szLine);
01806         sprintf(szLine, "Validate Nodes Only: %d\n", validNodesOnly);
01807         bufferLen += strlen(szLine);
01808         sprintf(szLine, "Use Middle Points: %d\n", useMidPts);
01809         bufferLen += strlen(szLine);
01810         sprintf(szLine, "Use Lazy Mode: %d\n", lazyMode);
01811         bufferLen += strlen(szLine);
01812         sprintf(szLine, "Initial Quantity: %d\n", initQuant);
01813         bufferLen += strlen(szLine);
01814         sprintf(szLine, "Enhance Quantity: %d\n", enhanceQuant);
01815         bufferLen += strlen(szLine);
01816         sprintf(szLine, "Seed Ratio: %f\n", seedRatio);
01817         bufferLen += strlen(szLine);
01818         sprintf(szLine, "Radius Tolerance: %f\n", radiusTol);
01819         bufferLen += strlen(szLine);
01820 
01821         //In case the buffer is too small, reallocate one.
01822         bufferLen += 100;
01823         if (paramBuffer != NULL)
01824                 bufferLen += strlen(paramBuffer);
01825         if (bufferLen > sizeOfParameterBuffer)
01826         {
01827                 char *pNewBuffer = (char *)malloc(bufferLen);
01828                 if (pNewBuffer)
01829                 {
01830                         memset(pNewBuffer, 0, bufferLen);
01831                         if (paramBuffer)
01832                         {
01833                                 strcpy(pNewBuffer, paramBuffer);
01834                                 delete paramBuffer;
01835                         }
01836                         paramBuffer = pNewBuffer;
01837                         sizeOfParameterBuffer = bufferLen;
01838                 }
01839                 else
01840                 {
01841                         return paramBuffer;
01842                 }
01843         }
01844 
01845         //This time really put them into buffer
01846         sprintf(szLine, "Validate Edges Only: %d\n", validEdgesOnly);
01847         strcat(paramBuffer, szLine);
01848         sprintf(szLine, "Validate Nodes Only: %d\n", validNodesOnly);
01849         strcat(paramBuffer, szLine);
01850         sprintf(szLine, "Use Middle Points: %d\n", useMidPts);
01851         strcat(paramBuffer, szLine);
01852         sprintf(szLine, "Use Lazy Mode: %d\n", lazyMode);
01853         strcat(paramBuffer, szLine);
01854         sprintf(szLine, "Initial Quantity: %d\n", initQuant);
01855         strcat(paramBuffer, szLine);
01856         sprintf(szLine, "Enhance Quantity: %d\n", enhanceQuant);
01857         strcat(paramBuffer, szLine);
01858         sprintf(szLine, "Seed Ratio: %f\n", seedRatio);
01859         strcat(paramBuffer, szLine);
01860         sprintf(szLine, "Radius Tolerance: %f\n", radiusTol);
01861         strcat(paramBuffer, szLine);
01862 
01863         return paramBuffer;
01864 }
01865 
01866 bool PL_PRM::SetParameters(const void *param)
01867 {
01868         if (PL_GraphBase::SetParameters(param)==false)
01869                 return false;
01870 
01871         istrstream paramStream(paramBuffer);
01872         char szLine[255];
01873         while (!paramStream.eof())
01874         {
01875                 paramStream.getline(szLine, 255);
01876                 _strlwr(szLine);
01877                 char *pValue = strchr(szLine, ':');
01878                 if (pValue == NULL)
01879                 {
01880                         pValue = szLine;
01881                         //Trimleft of szLine
01882                         while(*pValue==' ')
01883                                 pValue++;
01884                         //IF szLine is non-empty, there is some mistake, 
01885                         //ELSE it just end of the stream.
01886                         if (strlen(pValue) != 0)
01887                                 return false;
01888                         else
01889                                 break;
01890                 }
01891                 else
01892                 {
01893                         pValue += 1;
01894                 }
01895 
01896                 if (strstr(szLine, "validate edges only"))
01897                 {
01898                         validEdgesOnly = atoi(pValue);
01899                 }
01900                 else if (strstr(szLine, "validate nodes only"))
01901                 {
01902                         validNodesOnly = atoi(pValue);
01903                 }
01904                 else if (strstr(szLine, "use middle points"))
01905                 {
01906                         useMidPts = atoi(pValue);
01907                 }
01908                 else if (strstr(szLine, "use lazy mode"))
01909                 {
01910                         lazyMode = atoi(pValue);
01911                 }
01912                 else if (strstr(szLine, "initial quantity"))
01913                 {
01914                         initQuant = atoi(pValue);
01915                 }
01916                 else if (strstr(szLine, "enhance quantity"))
01917                 {
01918                         enhanceQuant = atoi(pValue);
01919                 }
01920                 else if (strstr(szLine, "seed ratio"))
01921                 {
01922                         seedRatio = atof(pValue);
01923                 }
01924                 else if (strstr(szLine, "radius tolerance"))
01925                 {
01926                         radiusTol = atof(pValue);
01927                 }
01928         }
01929         return true;
01930 }
01931 
01932 bool PL_PRM::ValidateParameters()
01933 {
01934         return true;
01935 }
01936 

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