00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 } else
00075 if ( uiA < uiB) {
00076 return false;
00077 }
00078 else {
00079
00080 return true;
00081 }
00082
00083
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
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
00119 return true;
00120 }
00121
00122
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
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;
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
00233 bool (*pFunctor)(const PathFinderNode&, const PathFinderNode&);
00234
00235
00236 int iFatherLinear;
00237 Destination destLast, destTemp;
00238
00239
00240
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
00249 switch (enumType) {
00250 case OC_DISTANCE:
00251 pFunctor = pathfinderCompareDistance;
00252 break;
00253 case OC_TRAFFIC:
00254 pFunctor = pathfinderCompareTraffic;
00255 break;
00256 }
00257
00258
00259
00260 SDL_LockMutex( this->pmutex );
00261
00262
00263 for ( uiLinear = 0; uiLinear <= uiMaxLinear; uiLinear++ ) {
00264 pstruct = pbuildlayer->GetLinearStructure( uiLinear );
00265 if ((pstruct != NULL)
00266 && (pstruct->GetCode() == OC_STRUCTURE_ROAD )) {
00267
00268 pstruct->Unset( OC_STRUCTURE_MARK );
00269
00270 ((PathStructure*)pstruct)->SetLength(
00271 OC_PATHFINDER_MAX_LENGTH );
00272 }
00273 }
00274
00275
00276 ppathstruct->SetLength( 0 );
00277
00278
00279 node.iOwnLinear = this->uiWidth * rcuiH1 + rcuiW1;
00280 node.iFatherLinear = -1;
00281 node.uiEvaluation = pathfinderEvaluate(rcuiW1, rcuiH1, rcuiW2, rcuiH2);
00282 node.ppath = ppathstruct;
00283 vProcessing.push_back( node );
00284
00285
00286 boolFound = false;
00287
00288 while ((!vProcessing.empty())
00289 and (boolFound == false)
00290 and (vDone.size() < uiMaxLength)) {
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 std::sort( vProcessing.begin(), vProcessing.end(), pFunctor );
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 node = vProcessing.back();
00331 vProcessing.pop_back();
00332
00333
00334 uiH = node.iOwnLinear / uiWidth;
00335 uiW = node.iOwnLinear % uiWidth;
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346 if ((uiW == rcuiW2) && (uiH == rcuiH2)) {
00347 boolFound = true;
00348 vDone.push_back( node );
00349 break;
00350 }
00351
00352
00353
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
00359 ppathstruct = (PathStructure*)pstruct;
00360 uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00361
00362 if (ppathstruct->GetLength() > uiLength) {
00363 ppathstruct->SetLength( uiLength );
00364
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
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
00379 ppathstruct = (PathStructure*)pstruct;
00380 uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00381
00382 if (ppathstruct->GetLength() > uiLength) {
00383 ppathstruct->SetLength( uiLength );
00384
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
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
00399 ppathstruct = (PathStructure*)pstruct;
00400 uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00401
00402 if (ppathstruct->GetLength() > uiLength) {
00403 ppathstruct->SetLength( uiLength );
00404
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
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
00419 ppathstruct = (PathStructure*)pstruct;
00420 uiLength = node.ppath->GetLength() + (uint)ppathstruct->GetTraffic();
00421
00422 if (ppathstruct->GetLength() > uiLength) {
00423 ppathstruct->SetLength( uiLength );
00424
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
00433
00434
00435 node.ppath->Set( OC_STRUCTURE_MARK );
00436
00437
00438 vDone.push_back( node );
00439 }
00440
00441
00442
00443 if ((boolFound == true) or (vDone.size() >= uiMaxLength)) {
00444
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
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
00473 destTemp._eDir = Destination::GetDir( destTemp, destLast );
00474
00475 rvdest.push_back( destTemp );
00476 destLast = destTemp;
00477 }
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 reverse( rvdest.begin(), rvdest.end() );
00506 }
00507
00508 #ifndef PATHFINDER_NDEBUG
00509
00510 if ((boolFound == true) or (vDone.size() >= uiMaxLength)) {
00511 PATHFINDER_DEBUG( "Shortest path found, number of nodes: " << rvdest.size() );
00512
00513
00514 iFatherLinear = vDone[ vDone.size()-1 ].iOwnLinear;
00515 for (int i = vDone.size()-1; i > -1; i--) {
00516 node = vDone[i];
00517
00518 if (node.iOwnLinear == iFatherLinear) {
00519
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
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
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
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