Main Page | Class Hierarchy | Class List | Directories | File List | Class Members | Related Pages

pathfinder.cpp

00001 /***************************************************************************
00002                         pathfinder.cpp  -  description
00003                             -------------------
00004     begin                : may 17th, 2004
00005     copyright            : (C) 2004-2006 by Duong-Khang NGUYEN
00006     email                : neoneurone @ users sourceforge net
00007     
00008     $Id: pathfinder.cpp 6 2006-06-19 21:43:20Z neoneurone $
00009  ***************************************************************************/
00010 
00011 /***************************************************************************
00012  *                                                                         *
00013  *   This program is free software; you can redistribute it and/or modify  *
00014  *   it under the terms of the GNU General Public License as published by  *
00015  *   the Free Software Foundation; either version 2 of the License, or     *
00016  *   any later version.                                                    *
00017  *                                                                         *
00018  ***************************************************************************/
00019 
00020 #include "buildinglayer.h"
00021 #include "destination.h"
00022 #include "pathstructure.h"
00023 #include "map.h"
00024 
00025 #include "pathfinder.h"
00026 
00027 #define OC_PATHFINDER_MAX_LENGTH    0xFFFF0000
00028 #define OC_PATHFINDER_A_STAR        1       // use Dijkstra + A* algorithm
00029 
00030 
00033 struct PathFinderNode {
00034     int iOwnLinear;             
00035     int iFatherLinear;          
00036     uint uiEvaluation;          
00037     PathStructure* ppath;       
00038 };
00039 
00040 
00041    //========================================================================
00044 static bool
00045 pathfinderCompareTraffic(
00046     const PathFinderNode & rcA,
00047     const PathFinderNode & rcB )
00048 {
00049     uint uiA = rcA.ppath->GetLength();
00050     uint uiB = rcB.ppath->GetLength();
00051 
00052    // same length
00053     if ( uiA == uiB ) {
00054 #ifdef OC_PATHFINDER_A_STAR
00055         if ( rcA.uiEvaluation < rcB.uiEvaluation) {
00056             return false;
00057         }
00058         else {
00059             return true;
00060         }
00061 #else
00062         return true;
00063 #endif
00064        // this is not necessary since the
00065        // contained structures are not marked
00066        /*
00067         if (rcA.ppath->IsSet( OC_STRUCTURE_MARK ) == false) {
00068             return false;
00069         }
00070         else {
00071             return true;
00072         }
00073        */
00074     } else
00075     if ( uiA < uiB) {
00076         return false;
00077     }
00078     else {
00079    // greater length, then put it at the beginning
00080         return true;
00081     }
00082 
00083    //impossible here
00084     assert( 0 );
00085 }
00086 
00087 
00088    //========================================================================
00091 static bool
00092 pathfinderCompareDistance(
00093     const PathFinderNode & rcA,
00094     const PathFinderNode & rcB )
00095 {
00096 #ifdef OC_PATHFINDER_A_STAR
00097     uint uiA = rcA.ppath->GetLength();
00098     uint uiB = rcB.ppath->GetLength();
00099 #endif
00100 
00101    // same length
00102     if ( rcA.uiEvaluation == rcB.uiEvaluation ) {
00103 #ifdef OC_PATHFINDER_A_STAR
00104         if ( uiA < uiB ) {
00105             return false;
00106         }
00107         else {
00108             return true;
00109         }
00110 #else
00111         return true;
00112 #endif
00113     } else
00114     if ( rcA.uiEvaluation < rcB.uiEvaluation ) {
00115         return false;
00116     }
00117     else {
00118    // greater length, then put it at the beginning
00119         return true;
00120     }
00121 
00122    //impossible here
00123     assert( 0 );
00124 }
00125 
00126 
00127    //========================================================================
00131 inline const uint
00132 pathfinderEvaluate(
00133     const uint & rcuiW1,
00134     const uint & rcuiH1,
00135     const uint & rcuiW2,
00136     const uint & rcuiH2)
00137 {
00138     return ((rcuiW2-rcuiW1)*(rcuiW2-rcuiW1) + (rcuiH2-rcuiH1)*(rcuiH2-rcuiH1));
00139 }
00140 
00141 
00142    /*=====================================================================*/
00143 PathFinder::PathFinder(
00144     SDL_mutex* const mutex,
00145     BuildingLayer* const pblayer,
00146     Map* const map,
00147     const uint & rcuiCityWidth,
00148     const uint & rcuiCityHeight ):
00149 pmutex( mutex ),
00150 pbuildlayer( pblayer ),
00151 pmap( map ),
00152 uiWidth( rcuiCityWidth ),
00153 uiHeight( rcuiCityHeight )
00154 {
00155     OPENCITY_DEBUG( "ctor" );
00156 
00157 // some assert for programming errors checking
00158     assert( mutex != NULL );
00159     assert( pblayer != NULL );
00160     assert( map != NULL );
00161 }
00162 
00163 
00164    /*=====================================================================*/
00165 PathFinder::~PathFinder()
00166 {
00167     OPENCITY_DEBUG( "dtor" );
00168 }
00169 
00170    //========================================================================
00208 const bool
00209 PathFinder::findShortestPath(
00210     const uint & rcuiW1,
00211     const uint & rcuiH1,
00212     const uint & rcuiW2,
00213     const uint & rcuiH2,
00214     std::vector<Destination> & rvdest,
00215     const PATH_TYPE & enumType,
00216     uint uiMaxLength )
00217 {
00218     uint uiLinear;
00219     uint uiW, uiH;
00220     uint uiWN, uiHN;        // N as Neighbour
00221     uint uiLength;
00222     uint uiMaxLinear = this->pbuildlayer->GetMaxLinear();
00223     Structure* pstruct;
00224     PathStructure * ppathstruct;
00225 
00226     PathFinderNode node;
00227     PathFinderNode nodeDone;
00228     std::vector<PathFinderNode> vProcessing;
00229     std::vector<PathFinderNode> vDone;
00230     bool boolFound;
00231 
00232 // Dynamic compare functor
00233     bool (*pFunctor)(const PathFinderNode&, const PathFinderNode&);
00234 
00235 // Variables used to rebuild the "destination vector" from start to stop
00236     int iFatherLinear;
00237     Destination destLast, destTemp;
00238 
00239 // WARNING the Start point is a PathStructure
00240 // do we need dynamic casting for automatic checking ?
00241     ppathstruct = dynamic_cast<PathStructure*>
00242         (pbuildlayer->GetStructure( rcuiW1, rcuiH1 ));
00243     if ( ppathstruct == NULL ) {
00244         OPENCITY_DEBUG("WARNING: Starting point NULL");
00245         return false;
00246     }
00247 
00248    // initialize the functor
00249     switch (enumType) {
00250         case OC_DISTANCE:
00251             pFunctor = pathfinderCompareDistance;
00252             break;
00253         case OC_TRAFFIC:
00254             pFunctor = pathfinderCompareTraffic;
00255             break;
00256     }
00257 
00258    // block all the other threads
00259    // while we play with the structures
00260     SDL_LockMutex( this->pmutex );
00261 
00262    // for each OC_ROAD structure
00263     for ( uiLinear = 0; uiLinear <= uiMaxLinear; uiLinear++ ) {
00264         pstruct = pbuildlayer->GetLinearStructure( uiLinear );
00265         if ((pstruct != NULL)
00266         &&  (pstruct->GetCode() == OC_STRUCTURE_ROAD )) {
00267            // clear the "mark"
00268             pstruct->Unset( OC_STRUCTURE_MARK );
00269            // set the maximum "length"
00270             ((PathStructure*)pstruct)->SetLength(
00271                 OC_PATHFINDER_MAX_LENGTH );
00272         }
00273     }
00274 
00275    // The length value of the starting point is 0 (minimum)
00276     ppathstruct->SetLength( 0 );
00277 
00278    // insert the starting point to the processing vector
00279     node.iOwnLinear = this->uiWidth * rcuiH1 + rcuiW1;
00280     node.iFatherLinear = -1;        // there's no precedent node
00281     node.uiEvaluation = pathfinderEvaluate(rcuiW1, rcuiH1, rcuiW2, rcuiH2);
00282     node.ppath = ppathstruct;
00283     vProcessing.push_back( node );
00284 
00285 // Loop until we finish or we found the arrival point
00286     boolFound = false;
00287 
00288     while ((!vProcessing.empty())
00289         and (boolFound == false)
00290         and (vDone.size() < uiMaxLength)) {
00291 
00292 //debug: display the "vProcessing" list
00293 /*
00294 cout << "Processing list BEFORE sorted" << endl;
00295 for (unsigned int i = 0; i < vProcessing.size(); i++) {
00296     node = vProcessing[i];
00297 // convert Linear <-> WH
00298     uiH = node.iOwnLinear / uiWidth;
00299     uiW = node.iOwnLinear % uiWidth;
00300     cout << "W / H: " << uiW << " / " << uiH;
00301     cout << " Length: " << node.ppath->GetLength();
00302     cout << " Traffic: " << (int)node.ppath->GetTraffic();
00303     cout << endl;
00304 }
00305 cout << "Processing list end" << endl << endl;
00306 */
00307 
00308     // sort the list so that the node with minimum "length" value
00309     // and not "marked" is placed at the bottom (back)
00310         std::sort( vProcessing.begin(), vProcessing.end(), pFunctor );
00311 
00312 //debug
00313 /*
00314 cout << "Processing list AFTER sorted" << endl;
00315 for (unsigned int i = 0; i < vProcessing.size(); i++) {
00316     node = vProcessing[i];
00317 // convert Linear <-> WH
00318     uiH = node.iOwnLinear / uiWidth;
00319     uiW = node.iOwnLinear % uiWidth;
00320     cout << "W / H: " << uiW << " / " << uiH;
00321     cout << " Length: " << node.ppath->GetLength();
00322     cout << " Traffic: " << (int)node.ppath->GetTraffic();
00323     cout << endl;
00324 }
00325 cout << "Processing list end" << endl << endl;
00326 */
00327 
00328     // get the sorted node with minimum length, and not marked
00329     // NOTE: everything contained in the vProcessing is not marked !
00330         node = vProcessing.back();
00331         vProcessing.pop_back();
00332 
00333        // convert Linear <-> WH
00334         uiH = node.iOwnLinear / uiWidth;
00335         uiW = node.iOwnLinear % uiWidth;
00336 
00337 //debug: display the current working node
00338 /*
00339 cout << "Processing W / H: " << uiW << " / " << uiH;
00340 cout << " Length: " << node.ppath->GetLength();
00341 cout << " Traffic: " << (int)node.ppath->GetTraffic();
00342 cout << endl;
00343 */
00344 
00345        // have we found the arrival point ?
00346         if ((uiW == rcuiW2) && (uiH == rcuiH2)) {
00347             boolFound = true;
00348             vDone.push_back( node );
00349             break;
00350         }
00351 
00352        //---------------------- WARNING: repeated procedure begin ---------------------
00353     // Get the neighbour in the NORTH
00354         if ((this->pmap->GetNeighbourWH(uiW, uiH, uiWN, uiHN, OC_DIR_N ) == true)
00355           &&((pstruct = pbuildlayer->GetStructure( uiWN, uiHN )) != NULL)
00356           && (pstruct->GetCode() == OC_STRUCTURE_ROAD)
00357           && (pstruct->IsSet(OC_STRUCTURE_MARK) == false)) {
00358 //debug cout << "NORTH " << endl;
00359             ppathstruct = (PathStructure*)pstruct;
00360             uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00361         // Is the new path shorter ?
00362             if (ppathstruct->GetLength() > uiLength) {
00363                 ppathstruct->SetLength( uiLength );
00364             // Now push the neighbour to the processing list
00365                 nodeDone.iOwnLinear = uiHN * uiWidth + uiWN;
00366                 nodeDone.iFatherLinear = node.iOwnLinear;
00367                 nodeDone.uiEvaluation = pathfinderEvaluate(uiWN, uiHN, rcuiW2, rcuiH2);
00368                 nodeDone.ppath = ppathstruct;
00369                 vProcessing.push_back( nodeDone );
00370             }
00371         }
00372 
00373     // Get the neighbour in the EAST
00374         if ((this->pmap->GetNeighbourWH(uiW, uiH, uiWN, uiHN, OC_DIR_E ) == true)
00375           &&((pstruct = pbuildlayer->GetStructure( uiWN, uiHN )) != NULL)
00376           && (pstruct->GetCode() == OC_STRUCTURE_ROAD)
00377           && (pstruct->IsSet(OC_STRUCTURE_MARK) == false)) {
00378 //debug cout << "EAST " << endl;
00379             ppathstruct = (PathStructure*)pstruct;
00380             uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00381         // Is the new path shorter ?
00382             if (ppathstruct->GetLength() > uiLength) {
00383                 ppathstruct->SetLength( uiLength );
00384                // now push the neighbour to the processing list
00385                 nodeDone.iOwnLinear = uiHN * uiWidth + uiWN;
00386                 nodeDone.iFatherLinear = node.iOwnLinear;
00387                 nodeDone.uiEvaluation = pathfinderEvaluate(uiWN, uiHN, rcuiW2, rcuiH2);
00388                 nodeDone.ppath = ppathstruct;
00389                 vProcessing.push_back( nodeDone );
00390             }
00391         }
00392 
00393     // Get the neighbour in the SOUTH
00394         if ((this->pmap->GetNeighbourWH(uiW, uiH, uiWN, uiHN, OC_DIR_S ) == true)
00395           &&((pstruct = pbuildlayer->GetStructure( uiWN, uiHN )) != NULL)
00396           && (pstruct->GetCode() == OC_STRUCTURE_ROAD)
00397           && (pstruct->IsSet(OC_STRUCTURE_MARK) == false)) {
00398 //debug cout << "SOUTH " << endl;
00399             ppathstruct = (PathStructure*)pstruct;
00400             uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00401         // Is the new path shorter ?
00402             if (ppathstruct->GetLength() > uiLength) {
00403                 ppathstruct->SetLength( uiLength );
00404                // now push the neighbour to the processing list
00405                 nodeDone.iOwnLinear = uiHN * uiWidth + uiWN;
00406                 nodeDone.iFatherLinear = node.iOwnLinear;
00407                 nodeDone.uiEvaluation = pathfinderEvaluate(uiWN, uiHN, rcuiW2, rcuiH2);
00408                 nodeDone.ppath = ppathstruct;
00409                 vProcessing.push_back( nodeDone );
00410             }
00411         }
00412 
00413     // Get the neighbour in the WEST
00414         if ((this->pmap->GetNeighbourWH(uiW, uiH, uiWN, uiHN, OC_DIR_W ) == true)
00415           &&((pstruct = pbuildlayer->GetStructure( uiWN, uiHN )) != NULL)
00416           && (pstruct->GetCode() == OC_STRUCTURE_ROAD)
00417           && (pstruct->IsSet(OC_STRUCTURE_MARK) == false)) {
00418 //debug cout << "WEST " << endl;
00419             ppathstruct = (PathStructure*)pstruct;
00420             uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00421         // Is the new path shorter ?
00422             if (ppathstruct->GetLength() > uiLength) {
00423                 ppathstruct->SetLength( uiLength );
00424                // now push the neighbour to the processing list
00425                 nodeDone.iOwnLinear = uiHN * uiWidth + uiWN;
00426                 nodeDone.iFatherLinear = node.iOwnLinear;
00427                 nodeDone.uiEvaluation = pathfinderEvaluate(uiWN, uiHN, rcuiW2, rcuiH2);
00428                 nodeDone.ppath = ppathstruct;
00429                 vProcessing.push_back( nodeDone );
00430             }
00431         }
00432        //---------------------- repeated procedure end ---------------------
00433 
00434     // mark this node as "done"
00435         node.ppath->Set( OC_STRUCTURE_MARK );
00436 
00437     // then insert it into the "done" list
00438         vDone.push_back( node );
00439     }
00440 
00441 
00442 // Build the destination vector from start to stop
00443     if ((boolFound == true) or (vDone.size() >= uiMaxLength)) {
00444     // Put the last node to the list
00445         int i = vDone.size()-1;
00446         node = vDone[ i ];
00447         iFatherLinear = node.iFatherLinear;
00448         destLast._uiW = node.iOwnLinear % uiWidth;
00449         destLast._uiL = node.iOwnLinear / uiWidth;
00450         destLast._iHMin = pmap->GetSquareMinHeight( destLast._uiW, destLast._uiL );
00451         destLast._iHMax = pmap->GetSquareMaxHeight( destLast._uiW, destLast._uiL );
00452         destLast._uiTime = 1;
00453         destLast._ubTraffic =
00454             ((PathStructure*)pbuildlayer->
00455             GetLinearStructure( node.iOwnLinear ))->GetTraffic();
00456 
00457         rvdest.push_back( destLast );
00458 
00459         while (--i >= 0) {
00460             node = vDone[i];
00461         // Is this node is the father of the precedent node ?
00462             if (node.iOwnLinear == iFatherLinear) {
00463                 iFatherLinear = node.iFatherLinear;
00464                 destTemp._uiW = node.iOwnLinear % uiWidth;
00465                 destTemp._uiL = node.iOwnLinear / uiWidth;
00466                 destTemp._iHMin = pmap->GetSquareMinHeight( destTemp._uiW, destTemp._uiL );
00467                 destTemp._iHMax = pmap->GetSquareMaxHeight( destTemp._uiW, destTemp._uiL );
00468                 destTemp._uiTime = 1;
00469                 destTemp._ubTraffic =
00470                     ((PathStructure*)pbuildlayer->
00471                     GetLinearStructure( node.iOwnLinear ))->GetTraffic();
00472             // NOTE: we're going from the back to the front
00473                 destTemp._eDir = Destination::GetDir( destTemp, destLast );
00474 
00475                 rvdest.push_back( destTemp );
00476                 destLast = destTemp;
00477             }
00478         }
00479 
00480 /* old code, for reference, june 18th, 06
00481     // Initialize the "iFatherLinear" variable as the stop point's linear index
00482         node = vDone[ vDone.size()-1 ];
00483         iFatherLinear = node.iOwnLinear;
00484         for (int i = vDone.size()-1; i > -1; i--) {
00485             node = vDone[i];
00486         // Is this node is the father of the precedent node ?
00487             if (node.iOwnLinear == iFatherLinear) {
00488                 iFatherLinear = node.iFatherLinear;
00489                 destTemp.uiW = node.iOwnLinear % uiWidth;
00490                 destTemp.uiH = node.iOwnLinear / uiWidth;
00491                 destTemp.uiTime = 1;
00492             // Save the local traffic
00493                 destTemp.ubTraffic =
00494                     ((PathStructure*)pbuildlayer->
00495                     GetLinearStructure( node.iOwnLinear ))->
00496                     GetTraffic();
00497                 rvdest.push_back( destTemp );
00498             // FIXME: this one is not specified
00499                 //destTemp.enumDirection;
00500             }
00501         }
00502 */
00503 
00504     // Reverse the destination vector so that the starting point is at the beginning
00505         reverse( rvdest.begin(), rvdest.end() );
00506     } // if boolFound
00507 
00508 #ifndef PATHFINDER_NDEBUG
00509 //debug, print out the found path
00510     if ((boolFound == true) or (vDone.size() >= uiMaxLength)) {
00511         PATHFINDER_DEBUG( "Shortest path found, number of nodes: " << rvdest.size() );
00512        // initialize the "iFatherLinear" variable
00513        // as the stop point's linear index
00514         iFatherLinear = vDone[ vDone.size()-1 ].iOwnLinear;
00515         for (int i = vDone.size()-1; i > -1; i--) {
00516             node = vDone[i];
00517            // is this node is the father of the precedent node ?
00518             if (node.iOwnLinear == iFatherLinear) {
00519                // convert Linear <-> WH
00520                 uiH = node.iOwnLinear / uiWidth;
00521                 uiW = node.iOwnLinear % uiWidth;
00522                 cout << "W / H: " << uiW << " / " << uiH;
00523                 cout << " Length: " << node.ppath->GetLength();
00524                 cout << " Traffic: " << (int)node.ppath->GetTraffic();
00525                 cout << endl;
00526                 iFatherLinear = node.iFatherLinear;
00527             }
00528         }
00529 //debug: print out all the processed WH
00530         PATHFINDER_DEBUG( "All processed nodes, number of nodes : " << vDone.size() );
00531         for (unsigned int i = 0; i < vDone.size(); i++) {
00532             node = vDone[i];
00533            // convert Linear <-> WH
00534             uiH = node.iOwnLinear / uiWidth;
00535             uiW = node.iOwnLinear % uiWidth;
00536             cout << "W / H: " << uiW << " / " << uiH;
00537             cout << " Length: " << node.ppath->GetLength();
00538             cout << " Traffic: " << (int)node.ppath->GetTraffic();
00539             cout << " Evaluation: " << node.uiEvaluation;
00540             cout << endl;
00541         }
00542     }
00543 #endif
00544 
00545    // let the other threads run now
00546     SDL_UnlockMutex( this->pmutex );
00547 
00548     return boolFound;
00549 }
00550 
00551 
00552 
00553 
00554 
00555 
00556 
00557 
00558 
00559 
00560 
00561 
00562 
00563 
00564 
00565 
00566 
00567 
00568 
00569 
00570 
00571 
00572 
00573 
00574 
00575 
00576 
00577 
00578 
00579 
00580 
00581 
00582 
00583 

Generated on Sat Nov 11 10:21:10 2006 for OpenCity by  doxygen 1.4.2