00001
00002
00005 #include "../stdafx.h"
00006 #include "../depot_base.h"
00007 #include "../station_base.h"
00008 #include "../roadveh.h"
00009 #include "../cargotype.h"
00010 #include "../newgrf_cargo.h"
00011
00012 #include "yapf.hpp"
00013 #include "yapf_node_road.hpp"
00014
00015
00016 template <class Types>
00017 class CYapfCostRoadT
00018 {
00019 public:
00020 typedef typename Types::Tpf Tpf;
00021 typedef typename Types::TrackFollower TrackFollower;
00022 typedef typename Types::NodeList::Titem Node;
00023 typedef typename Node::Key Key;
00024
00025 protected:
00027 Tpf& Yapf()
00028 {
00029 return *static_cast<Tpf*>(this);
00030 }
00031
00032 int SlopeCost(TileIndex tile, TileIndex next_tile, Trackdir trackdir)
00033 {
00034
00035 int x1 = TileX(tile) * TILE_SIZE;
00036 int y1 = TileY(tile) * TILE_SIZE;
00037 int z1 = GetSlopeZ(x1 + TILE_SIZE / 2, y1 + TILE_SIZE / 2);
00038
00039
00040 int x2 = TileX(next_tile) * TILE_SIZE;
00041 int y2 = TileY(next_tile) * TILE_SIZE;
00042 int z2 = GetSlopeZ(x2 + TILE_SIZE / 2, y2 + TILE_SIZE / 2);
00043
00044 if (z2 - z1 > 1) {
00045
00046 return Yapf().PfGetSettings().road_slope_penalty;
00047 }
00048 return 0;
00049 }
00050
00052 FORCEINLINE int OneTileCost(TileIndex tile, Trackdir trackdir)
00053 {
00054 int cost = 0;
00055
00056 if (IsDiagonalTrackdir(trackdir)) {
00057 cost += YAPF_TILE_LENGTH;
00058 switch (GetTileType(tile)) {
00059 case MP_ROAD:
00060
00061 if (IsLevelCrossing(tile)) {
00062 cost += Yapf().PfGetSettings().road_crossing_penalty;
00063 }
00064 break;
00065
00066 case MP_STATION:
00067 if (IsDriveThroughStopTile(tile)) {
00068 cost += Yapf().PfGetSettings().road_stop_penalty;
00069 }
00070 break;
00071
00072 default:
00073 break;
00074 }
00075 } else {
00076
00077 cost = YAPF_TILE_CORNER_LENGTH + Yapf().PfGetSettings().road_curve_penalty;
00078 }
00079 return cost;
00080 }
00081
00082 public:
00086 FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
00087 {
00088 int segment_cost = 0;
00089
00090 TileIndex tile = n.m_key.m_tile;
00091 Trackdir trackdir = n.m_key.m_td;
00092 while (true) {
00093
00094 segment_cost += Yapf().OneTileCost(tile, trackdir);
00095
00096 const Vehicle *v = Yapf().GetVehicle();
00097
00098 if (Yapf().PfDetectDestinationTile(tile, trackdir)) break;
00099
00100
00101 if (IsRoadDepotTile(tile) && trackdir == DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
00102
00103 break;
00104 }
00105
00106
00107 TrackFollower F(Yapf().GetVehicle());
00108 if (!F.Follow(tile, trackdir)) break;
00109
00110
00111 if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break;
00112
00113 Trackdir new_td = (Trackdir)FindFirstBit2x64(F.m_new_td_bits);
00114
00115
00116 if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false;
00117
00118
00119 segment_cost += F.m_tiles_skipped * YAPF_TILE_LENGTH;
00120
00121
00122 segment_cost += Yapf().SlopeCost(tile, F.m_new_tile, trackdir);
00123
00124
00125 int min_speed = 0;
00126 int max_speed = F.GetSpeedLimit(&min_speed);
00127 if (max_speed < v->max_speed) segment_cost += 1 * (v->max_speed - max_speed);
00128 if (min_speed > v->max_speed) segment_cost += 10 * (min_speed - v->max_speed);
00129
00130
00131 tile = F.m_new_tile;
00132 trackdir = new_td;
00133 };
00134
00135
00136 n.m_segment_last_tile = tile;
00137 n.m_segment_last_td = trackdir;
00138
00139
00140 int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0;
00141 n.m_cost = parent_cost + segment_cost;
00142 return true;
00143 }
00144 };
00145
00146
00147 template <class Types>
00148 class CYapfDestinationAnyDepotRoadT
00149 {
00150 public:
00151 typedef typename Types::Tpf Tpf;
00152 typedef typename Types::TrackFollower TrackFollower;
00153 typedef typename Types::NodeList::Titem Node;
00154 typedef typename Node::Key Key;
00155
00157 Tpf& Yapf()
00158 {
00159 return *static_cast<Tpf*>(this);
00160 }
00161
00163 FORCEINLINE bool PfDetectDestination(Node& n)
00164 {
00165 bool bDest = IsRoadDepotTile(n.m_segment_last_tile);
00166 return bDest;
00167 }
00168
00169 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00170 {
00171 return IsRoadDepotTile(tile);
00172 }
00173
00176 FORCEINLINE bool PfCalcEstimate(Node& n)
00177 {
00178 n.m_estimate = n.m_cost;
00179 return true;
00180 }
00181 };
00182
00183
00184 template <class Types>
00185 class CYapfDestinationAnyRoadVehicleCompatibleStopOfGivenStationT
00186 {
00187 public:
00188 typedef typename Types::Tpf Tpf;
00189 typedef typename Types::TrackFollower TrackFollower;
00190 typedef typename Types::NodeList::Titem Node;
00191 typedef typename Node::Key Key;
00192
00193 TileIndex m_destTile;
00194 StationID m_dest_station;
00195 bool m_bus;
00196 bool m_non_artic;
00197
00199 Tpf& Yapf()
00200 {
00201 return *static_cast<Tpf*>(this);
00202 }
00203
00204 void SetDestination(const Vehicle *v, StationID sid, TileIndex destTile)
00205 {
00206 m_dest_station = sid;
00207 m_destTile = destTile;
00208 m_bus = IsCargoInClass(v->cargo_type, CC_PASSENGERS);
00209 m_non_artic = !RoadVehHasArticPart(v);
00210 }
00211
00213 FORCEINLINE bool PfDetectDestination(Node& n)
00214 {
00215 return PfDetectDestinationTile(n.m_segment_last_tile, INVALID_TRACKDIR);
00216 }
00217
00218 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00219 {
00220 return
00221 IsTileType(tile, MP_STATION) &&
00222 GetStationIndex(tile) == m_dest_station &&
00223 (m_bus ? IsBusStop(tile) : IsTruckStop(tile)) &&
00224 (m_non_artic || IsDriveThroughStopTile(tile));
00225 }
00226
00229 FORCEINLINE bool PfCalcEstimate(Node& n)
00230 {
00231 static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
00232 static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
00233 if (PfDetectDestination(n)) {
00234 n.m_estimate = n.m_cost;
00235 return true;
00236 }
00237
00238 TileIndex tile = n.m_segment_last_tile;
00239 DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
00240 int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
00241 int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
00242 int x2 = 2 * TileX(m_destTile);
00243 int y2 = 2 * TileY(m_destTile);
00244 int dx = abs(x1 - x2);
00245 int dy = abs(y1 - y2);
00246 int dmin = min(dx, dy);
00247 int dxy = abs(dx - dy);
00248 int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
00249 n.m_estimate = n.m_cost + d;
00250 assert(n.m_estimate >= n.m_parent->m_estimate);
00251 return true;
00252 }
00253 };
00254
00255
00256 template <class Types>
00257 class CYapfDestinationTileRoadT
00258 {
00259 public:
00260 typedef typename Types::Tpf Tpf;
00261 typedef typename Types::TrackFollower TrackFollower;
00262 typedef typename Types::NodeList::Titem Node;
00263 typedef typename Node::Key Key;
00264
00265 protected:
00266 TileIndex m_destTile;
00267 TrackdirBits m_destTrackdirs;
00268
00269 public:
00270 void SetDestination(TileIndex tile, TrackdirBits trackdirs)
00271 {
00272 m_destTile = tile;
00273 m_destTrackdirs = trackdirs;
00274 }
00275
00276 protected:
00278 Tpf& Yapf()
00279 {
00280 return *static_cast<Tpf*>(this);
00281 }
00282
00283 public:
00285 FORCEINLINE bool PfDetectDestination(Node& n)
00286 {
00287 bool bDest = (n.m_segment_last_tile == m_destTile) && ((m_destTrackdirs & TrackdirToTrackdirBits(n.m_segment_last_td)) != TRACKDIR_BIT_NONE);
00288 return bDest;
00289 }
00290
00291 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00292 {
00293 return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
00294 }
00295
00298 inline bool PfCalcEstimate(Node& n)
00299 {
00300 static int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
00301 static int dg_dir_to_y_offs[] = {0, 1, 0, -1};
00302 if (PfDetectDestination(n)) {
00303 n.m_estimate = n.m_cost;
00304 return true;
00305 }
00306
00307 TileIndex tile = n.m_segment_last_tile;
00308 DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
00309 int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
00310 int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
00311 int x2 = 2 * TileX(m_destTile);
00312 int y2 = 2 * TileY(m_destTile);
00313 int dx = abs(x1 - x2);
00314 int dy = abs(y1 - y2);
00315 int dmin = min(dx, dy);
00316 int dxy = abs(dx - dy);
00317 int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
00318 n.m_estimate = n.m_cost + d;
00319 assert(n.m_estimate >= n.m_parent->m_estimate);
00320 return true;
00321 }
00322 };
00323
00324
00325
00326 template <class Types>
00327 class CYapfFollowRoadT
00328 {
00329 public:
00330 typedef typename Types::Tpf Tpf;
00331 typedef typename Types::TrackFollower TrackFollower;
00332 typedef typename Types::NodeList::Titem Node;
00333 typedef typename Node::Key Key;
00334
00335 protected:
00337 FORCEINLINE Tpf& Yapf()
00338 {
00339 return *static_cast<Tpf*>(this);
00340 }
00341
00342 public:
00343
00347 inline void PfFollowNode(Node& old_node)
00348 {
00349 TrackFollower F(Yapf().GetVehicle());
00350 if (F.Follow(old_node.m_segment_last_tile, old_node.m_segment_last_td)) {
00351 Yapf().AddMultipleNodes(&old_node, F);
00352 }
00353 }
00354
00356 FORCEINLINE char TransportTypeChar() const
00357 {
00358 return 'r';
00359 }
00360
00361 static Trackdir stChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir)
00362 {
00363 Tpf pf;
00364 return pf.ChooseRoadTrack(v, tile, enterdir);
00365 }
00366
00367 FORCEINLINE Trackdir ChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir)
00368 {
00369
00370 if (tile == v->dest_tile) {
00371
00372 return DiagDirToDiagTrackdir(enterdir);
00373 }
00374
00375 TileIndex src_tile = tile;
00376
00377 TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
00378
00379 src_trackdirs &= DiagdirReachesTrackdirs(enterdir);
00380
00381
00382 TileIndex dest_tile = v->dest_tile;
00383 TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(dest_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
00384
00385
00386 Yapf().SetOrigin(src_tile, src_trackdirs);
00387 Yapf().SetDestination(dest_tile, dest_trackdirs);
00388
00389
00390 Yapf().FindPath(v);
00391
00392
00393 Trackdir next_trackdir = INVALID_TRACKDIR;
00394 Node *pNode = Yapf().GetBestNode();
00395 if (pNode != NULL) {
00396
00397
00398 while (pNode->m_parent != NULL) {
00399 pNode = pNode->m_parent;
00400 }
00401
00402 Node& best_next_node = *pNode;
00403 assert(best_next_node.GetTile() == tile);
00404 next_trackdir = best_next_node.GetTrackdir();
00405 }
00406 return next_trackdir;
00407 }
00408
00409 static uint stDistanceToTile(const Vehicle *v, TileIndex tile)
00410 {
00411 Tpf pf;
00412 return pf.DistanceToTile(v, tile);
00413 }
00414
00415 FORCEINLINE uint DistanceToTile(const Vehicle *v, TileIndex dst_tile)
00416 {
00417
00418 if (dst_tile == v->tile) {
00419
00420 return 0;
00421 }
00422
00423 if (!SetOriginFromVehiclePos(v)) return UINT_MAX;
00424
00425
00426
00427 TrackdirBits dst_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
00428 Yapf().SetDestination(dst_tile, dst_td_bits);
00429
00430
00431 uint dist = UINT_MAX;
00432
00433
00434 if (!Yapf().FindPath(v)) return dist;
00435
00436 Node *pNode = Yapf().GetBestNode();
00437 if (pNode != NULL) {
00438
00439
00440 dist = pNode->GetCostEstimate();
00441 }
00442
00443 return dist;
00444 }
00445
00447 FORCEINLINE bool SetOriginFromVehiclePos(const Vehicle *v)
00448 {
00449
00450 TileIndex src_tile = v->tile;
00451 Trackdir src_td = GetVehicleTrackdir(v);
00452 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
00453
00454
00455 return false;
00456 }
00457 Yapf().SetOrigin(src_tile, TrackdirToTrackdirBits(src_td));
00458 return true;
00459 }
00460
00461 static Depot *stFindNearestDepot(const Vehicle *v, TileIndex tile, Trackdir td)
00462 {
00463 Tpf pf;
00464 return pf.FindNearestDepot(v, tile, td);
00465 }
00466
00467 FORCEINLINE Depot *FindNearestDepot(const Vehicle *v, TileIndex tile, Trackdir td)
00468 {
00469
00470 Yapf().SetOrigin(tile, TrackdirToTrackdirBits(td));
00471
00472
00473 bool bFound = Yapf().FindPath(v);
00474 if (!bFound) return false;
00475
00476
00477
00478 Node *n = Yapf().GetBestNode();
00479 TileIndex depot_tile = n->m_segment_last_tile;
00480 assert(IsRoadDepotTile(depot_tile));
00481 Depot *ret = GetDepotByTile(depot_tile);
00482 return ret;
00483 }
00484
00485 static bool stFindNearestRoadVehicleCompatibleStop(const Vehicle *v, TileIndex tile, TileIndex destTile, Trackdir td, StationID sid, TileIndex *stop_tile)
00486 {
00487 Tpf pf;
00488 return pf.FindNearestRoadVehicleCompatibleStop(v, tile, destTile, td, sid, stop_tile);
00489 }
00490
00491 FORCEINLINE bool FindNearestRoadVehicleCompatibleStop(const Vehicle *v, TileIndex tile, TileIndex destTile, Trackdir td, StationID sid, TileIndex *stop_tile)
00492 {
00493
00494 Yapf().SetOrigin(tile, TrackdirToTrackdirBits(td));
00495 Yapf().SetDestination(v, sid, destTile);
00496
00497
00498 bool bFound = Yapf().FindPath(v);
00499 if (!bFound) return false;
00500
00501
00502
00503 const Node *n = Yapf().GetBestNode();
00504
00505 *stop_tile = n->m_segment_last_tile;
00506 return true;
00507 }
00508 };
00509
00510 template <class Tpf_, class Tnode_list, template <class Types> class Tdestination>
00511 struct CYapfRoad_TypesT
00512 {
00513 typedef CYapfRoad_TypesT<Tpf_, Tnode_list, Tdestination> Types;
00514
00515 typedef Tpf_ Tpf;
00516 typedef CFollowTrackRoad TrackFollower;
00517 typedef Tnode_list NodeList;
00518 typedef CYapfBaseT<Types> PfBase;
00519 typedef CYapfFollowRoadT<Types> PfFollow;
00520 typedef CYapfOriginTileT<Types> PfOrigin;
00521 typedef Tdestination<Types> PfDestination;
00522 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00523 typedef CYapfCostRoadT<Types> PfCost;
00524 };
00525
00526 struct CYapfRoad1 : CYapfT<CYapfRoad_TypesT<CYapfRoad1 , CRoadNodeListTrackDir, CYapfDestinationTileRoadT > > {};
00527 struct CYapfRoad2 : CYapfT<CYapfRoad_TypesT<CYapfRoad2 , CRoadNodeListExitDir , CYapfDestinationTileRoadT > > {};
00528
00529 struct CYapfRoadAnyDepot1 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot1, CRoadNodeListTrackDir, CYapfDestinationAnyDepotRoadT> > {};
00530 struct CYapfRoadAnyDepot2 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot2, CRoadNodeListExitDir , CYapfDestinationAnyDepotRoadT> > {};
00531
00532 struct CYapfRoadAnyRoadVehicleCompatibleStopOfGivenStation1 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyRoadVehicleCompatibleStopOfGivenStation1, CRoadNodeListTrackDir, CYapfDestinationAnyRoadVehicleCompatibleStopOfGivenStationT> > {};
00533 struct CYapfRoadAnyRoadVehicleCompatibleStopOfGivenStation2 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyRoadVehicleCompatibleStopOfGivenStation2, CRoadNodeListExitDir , CYapfDestinationAnyRoadVehicleCompatibleStopOfGivenStationT> > {};
00534
00535
00536 Trackdir YapfChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir)
00537 {
00538
00539 typedef Trackdir (*PfnChooseRoadTrack)(const Vehicle*, TileIndex, DiagDirection);
00540 PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack;
00541
00542
00543 if (_settings_game.pf.yapf.disable_node_optimization) {
00544 pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack;
00545 }
00546
00547 Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir);
00548 return td_ret;
00549 }
00550
00551 uint YapfRoadVehDistanceToTile(const Vehicle *v, TileIndex tile)
00552 {
00553
00554 typedef uint (*PfnDistanceToTile)(const Vehicle*, TileIndex);
00555 PfnDistanceToTile pfnDistanceToTile = &CYapfRoad2::stDistanceToTile;
00556
00557
00558 if (_settings_game.pf.yapf.disable_node_optimization) {
00559 pfnDistanceToTile = &CYapfRoad1::stDistanceToTile;
00560 }
00561
00562
00563 uint dist = pfnDistanceToTile(v, tile);
00564
00565 if (dist != UINT_MAX) {
00566 dist = (dist + YAPF_TILE_LENGTH - 1) / YAPF_TILE_LENGTH;
00567 }
00568
00569 return dist;
00570 }
00571
00572 Depot *YapfFindNearestRoadDepot(const Vehicle *v)
00573 {
00574 TileIndex tile = v->tile;
00575 Trackdir trackdir = GetVehicleTrackdir(v);
00576 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
00577 return NULL;
00578 }
00579
00580
00581 if (IsRoadDepotTile(tile)) {
00582
00583 return GetDepotByTile(tile);
00584 }
00585
00586
00587 typedef Depot *(*PfnFindNearestDepot)(const Vehicle*, TileIndex, Trackdir);
00588 PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot;
00589
00590
00591 if (_settings_game.pf.yapf.disable_node_optimization) {
00592 pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot;
00593 }
00594
00595 Depot *ret = pfnFindNearestDepot(v, tile, trackdir);
00596 return ret;
00597 }
00598
00599 bool YapfFindNearestRoadVehicleCompatibleStop(const Vehicle *v, StationID station, TileIndex *stop_tile)
00600 {
00601 *stop_tile = INVALID_TILE;
00602
00603 const RoadStop *rs = GetStation(station)->GetPrimaryRoadStop(v);
00604 if (rs == NULL) return false;
00605
00606 TileIndex tile = v->tile;
00607 Trackdir trackdir = GetVehicleTrackdir(v);
00608 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
00609 return false;
00610 }
00611
00612
00613 typedef bool (*PfnFindNearestRoadVehicleCompatibleStop)(const Vehicle*, TileIndex, TileIndex, Trackdir, StationID, TileIndex*);
00614 PfnFindNearestRoadVehicleCompatibleStop pfnFindNearestRoadVehicleCompatibleStop = &CYapfRoadAnyRoadVehicleCompatibleStopOfGivenStation2::stFindNearestRoadVehicleCompatibleStop;
00615
00616
00617 if (_settings_game.pf.yapf.disable_node_optimization) {
00618 pfnFindNearestRoadVehicleCompatibleStop = &CYapfRoadAnyRoadVehicleCompatibleStopOfGivenStation1::stFindNearestRoadVehicleCompatibleStop;
00619 }
00620
00621 bool ret = pfnFindNearestRoadVehicleCompatibleStop(v, tile, rs->xy, trackdir, station, stop_tile);
00622 return ret;
00623 }