00001
00002
00005 #include "../stdafx.h"
00006 #include "../depot_base.h"
00007
00008 #include "yapf.hpp"
00009 #include "yapf_node_road.hpp"
00010
00011
00012 template <class Types>
00013 class CYapfCostRoadT
00014 {
00015 public:
00016 typedef typename Types::Tpf Tpf;
00017 typedef typename Types::TrackFollower TrackFollower;
00018 typedef typename Types::NodeList::Titem Node;
00019 typedef typename Node::Key Key;
00020
00021 protected:
00023 Tpf& Yapf() {return *static_cast<Tpf*>(this);}
00024
00025 int SlopeCost(TileIndex tile, TileIndex next_tile, Trackdir trackdir)
00026 {
00027
00028 int x1 = TileX(tile) * TILE_SIZE;
00029 int y1 = TileY(tile) * TILE_SIZE;
00030 int z1 = GetSlopeZ(x1 + TILE_SIZE / 2, y1 + TILE_SIZE / 2);
00031
00032
00033 int x2 = TileX(next_tile) * TILE_SIZE;
00034 int y2 = TileY(next_tile) * TILE_SIZE;
00035 int z2 = GetSlopeZ(x2 + TILE_SIZE / 2, y2 + TILE_SIZE / 2);
00036
00037 if (z2 - z1 > 1) {
00038
00039 return Yapf().PfGetSettings().road_slope_penalty;
00040 }
00041 return 0;
00042 }
00043
00045 FORCEINLINE int OneTileCost(TileIndex tile, Trackdir trackdir)
00046 {
00047 int cost = 0;
00048
00049 if (IsDiagonalTrackdir(trackdir)) {
00050 cost += YAPF_TILE_LENGTH;
00051 switch (GetTileType(tile)) {
00052 case MP_ROAD:
00053
00054 if (IsLevelCrossing(tile))
00055 cost += Yapf().PfGetSettings().road_crossing_penalty;
00056 break;
00057 case MP_STATION:
00058 if (IsDriveThroughStopTile(tile))
00059 cost += Yapf().PfGetSettings().road_stop_penalty;
00060 break;
00061
00062 default:
00063 break;
00064 }
00065 } else {
00066
00067 cost = YAPF_TILE_CORNER_LENGTH + Yapf().PfGetSettings().road_curve_penalty;
00068 }
00069 return cost;
00070 }
00071
00072 public:
00076 FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
00077 {
00078 int segment_cost = 0;
00079
00080 TileIndex tile = n.m_key.m_tile;
00081 Trackdir trackdir = n.m_key.m_td;
00082 while (true) {
00083
00084 segment_cost += Yapf().OneTileCost(tile, trackdir);
00085
00086 const Vehicle *v = Yapf().GetVehicle();
00087
00088 if (Yapf().PfDetectDestinationTile(tile, trackdir)) break;
00089
00090
00091 if (IsRoadDepotTile(tile) && trackdir == DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
00092
00093 break;
00094 }
00095
00096
00097 TrackFollower F(Yapf().GetVehicle());
00098 if (!F.Follow(tile, trackdir)) break;
00099
00100
00101 if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break;
00102
00103 Trackdir new_td = (Trackdir)FindFirstBit2x64(F.m_new_td_bits);
00104
00105
00106 if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false;
00107
00108
00109 segment_cost += F.m_tiles_skipped * YAPF_TILE_LENGTH;
00110
00111
00112 segment_cost += Yapf().SlopeCost(tile, F.m_new_tile, trackdir);
00113
00114
00115 int min_speed = 0;
00116 int max_speed = F.GetSpeedLimit(&min_speed);
00117 if (max_speed < v->max_speed) segment_cost += 1 * (v->max_speed - max_speed);
00118 if (min_speed > v->max_speed) segment_cost += 10 * (min_speed - v->max_speed);
00119
00120
00121 tile = F.m_new_tile;
00122 trackdir = new_td;
00123 };
00124
00125
00126 n.m_segment_last_tile = tile;
00127 n.m_segment_last_td = trackdir;
00128
00129
00130 int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0;
00131 n.m_cost = parent_cost + segment_cost;
00132 return true;
00133 }
00134 };
00135
00136
00137 template <class Types>
00138 class CYapfDestinationAnyDepotRoadT
00139 {
00140 public:
00141 typedef typename Types::Tpf Tpf;
00142 typedef typename Types::TrackFollower TrackFollower;
00143 typedef typename Types::NodeList::Titem Node;
00144 typedef typename Node::Key Key;
00145
00147 Tpf& Yapf() {return *static_cast<Tpf*>(this);}
00148
00150 FORCEINLINE bool PfDetectDestination(Node& n)
00151 {
00152 bool bDest = IsRoadDepotTile(n.m_segment_last_tile);
00153 return bDest;
00154 }
00155
00156 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00157 {
00158 return IsRoadDepotTile(tile);
00159 }
00160
00163 FORCEINLINE bool PfCalcEstimate(Node& n)
00164 {
00165 n.m_estimate = n.m_cost;
00166 return true;
00167 }
00168 };
00169
00170
00171 template <class Types>
00172 class CYapfDestinationTileRoadT
00173 {
00174 public:
00175 typedef typename Types::Tpf Tpf;
00176 typedef typename Types::TrackFollower TrackFollower;
00177 typedef typename Types::NodeList::Titem Node;
00178 typedef typename Node::Key Key;
00179
00180 protected:
00181 TileIndex m_destTile;
00182 TrackdirBits m_destTrackdirs;
00183
00184 public:
00185 void SetDestination(TileIndex tile, TrackdirBits trackdirs)
00186 {
00187 m_destTile = tile;
00188 m_destTrackdirs = trackdirs;
00189 }
00190
00191 protected:
00193 Tpf& Yapf() {return *static_cast<Tpf*>(this);}
00194
00195 public:
00197 FORCEINLINE bool PfDetectDestination(Node& n)
00198 {
00199 bool bDest = (n.m_segment_last_tile == m_destTile) && ((m_destTrackdirs & TrackdirToTrackdirBits(n.m_segment_last_td)) != TRACKDIR_BIT_NONE);
00200 return bDest;
00201 }
00202
00203 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00204 {
00205 return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
00206 }
00207
00210 inline bool PfCalcEstimate(Node& n)
00211 {
00212 static int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
00213 static int dg_dir_to_y_offs[] = {0, 1, 0, -1};
00214 if (PfDetectDestination(n)) {
00215 n.m_estimate = n.m_cost;
00216 return true;
00217 }
00218
00219 TileIndex tile = n.m_segment_last_tile;
00220 DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
00221 int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
00222 int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
00223 int x2 = 2 * TileX(m_destTile);
00224 int y2 = 2 * TileY(m_destTile);
00225 int dx = abs(x1 - x2);
00226 int dy = abs(y1 - y2);
00227 int dmin = min(dx, dy);
00228 int dxy = abs(dx - dy);
00229 int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
00230 n.m_estimate = n.m_cost + d;
00231 assert(n.m_estimate >= n.m_parent->m_estimate);
00232 return true;
00233 }
00234 };
00235
00236
00237
00238 template <class Types>
00239 class CYapfFollowRoadT
00240 {
00241 public:
00242 typedef typename Types::Tpf Tpf;
00243 typedef typename Types::TrackFollower TrackFollower;
00244 typedef typename Types::NodeList::Titem Node;
00245 typedef typename Node::Key Key;
00246
00247 protected:
00249 FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
00250
00251 public:
00252
00256 inline void PfFollowNode(Node& old_node)
00257 {
00258 TrackFollower F(Yapf().GetVehicle());
00259 if (F.Follow(old_node.m_segment_last_tile, old_node.m_segment_last_td))
00260 Yapf().AddMultipleNodes(&old_node, F);
00261 }
00262
00264 FORCEINLINE char TransportTypeChar() const {return 'r';}
00265
00266 static Trackdir stChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir)
00267 {
00268 Tpf pf;
00269 return pf.ChooseRoadTrack(v, tile, enterdir);
00270 }
00271
00272 FORCEINLINE Trackdir ChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir)
00273 {
00274
00275 if (tile == v->dest_tile) {
00276
00277 return DiagDirToDiagTrackdir(enterdir);
00278 }
00279
00280 TileIndex src_tile = tile;
00281
00282 TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
00283
00284 src_trackdirs &= DiagdirReachesTrackdirs(enterdir);
00285
00286
00287 TileIndex dest_tile = v->dest_tile;
00288 TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(dest_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
00289
00290
00291 Yapf().SetOrigin(src_tile, src_trackdirs);
00292 Yapf().SetDestination(dest_tile, dest_trackdirs);
00293
00294
00295 Yapf().FindPath(v);
00296
00297
00298 Trackdir next_trackdir = INVALID_TRACKDIR;
00299 Node *pNode = Yapf().GetBestNode();
00300 if (pNode != NULL) {
00301
00302
00303 while (pNode->m_parent != NULL) {
00304 pNode = pNode->m_parent;
00305 }
00306
00307 Node& best_next_node = *pNode;
00308 assert(best_next_node.GetTile() == tile);
00309 next_trackdir = best_next_node.GetTrackdir();
00310 }
00311 return next_trackdir;
00312 }
00313
00314 static uint stDistanceToTile(const Vehicle *v, TileIndex tile)
00315 {
00316 Tpf pf;
00317 return pf.DistanceToTile(v, tile);
00318 }
00319
00320 FORCEINLINE uint DistanceToTile(const Vehicle *v, TileIndex dst_tile)
00321 {
00322
00323 if (dst_tile == v->tile) {
00324
00325 return 0;
00326 }
00327
00328 if (!SetOriginFromVehiclePos(v)) return UINT_MAX;
00329
00330
00331
00332 TrackdirBits dst_td_bits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes));
00333 Yapf().SetDestination(dst_tile, dst_td_bits);
00334
00335
00336 uint dist = UINT_MAX;
00337
00338
00339 if (!Yapf().FindPath(v)) return dist;
00340
00341 Node *pNode = Yapf().GetBestNode();
00342 if (pNode != NULL) {
00343
00344
00345 dist = pNode->GetCostEstimate();
00346 }
00347
00348 return dist;
00349 }
00350
00352 FORCEINLINE bool SetOriginFromVehiclePos(const Vehicle *v)
00353 {
00354
00355 TileIndex src_tile = v->tile;
00356 Trackdir src_td = GetVehicleTrackdir(v);
00357 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
00358
00359
00360 return false;
00361 }
00362 Yapf().SetOrigin(src_tile, TrackdirToTrackdirBits(src_td));
00363 return true;
00364 }
00365
00366 static Depot *stFindNearestDepot(const Vehicle *v, TileIndex tile, Trackdir td)
00367 {
00368 Tpf pf;
00369 return pf.FindNearestDepot(v, tile, td);
00370 }
00371
00372 FORCEINLINE Depot *FindNearestDepot(const Vehicle *v, TileIndex tile, Trackdir td)
00373 {
00374
00375 Yapf().SetOrigin(tile, TrackdirToTrackdirBits(td));
00376
00377
00378 bool bFound = Yapf().FindPath(v);
00379 if (!bFound) return false;
00380
00381
00382
00383 Node *n = Yapf().GetBestNode();
00384 TileIndex depot_tile = n->m_segment_last_tile;
00385 assert(IsRoadDepotTile(depot_tile));
00386 Depot *ret = GetDepotByTile(depot_tile);
00387 return ret;
00388 }
00389 };
00390
00391 template <class Tpf_, class Tnode_list, template <class Types> class Tdestination>
00392 struct CYapfRoad_TypesT
00393 {
00394 typedef CYapfRoad_TypesT<Tpf_, Tnode_list, Tdestination> Types;
00395
00396 typedef Tpf_ Tpf;
00397 typedef CFollowTrackRoad TrackFollower;
00398 typedef Tnode_list NodeList;
00399 typedef CYapfBaseT<Types> PfBase;
00400 typedef CYapfFollowRoadT<Types> PfFollow;
00401 typedef CYapfOriginTileT<Types> PfOrigin;
00402 typedef Tdestination<Types> PfDestination;
00403 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00404 typedef CYapfCostRoadT<Types> PfCost;
00405 };
00406
00407 struct CYapfRoad1 : CYapfT<CYapfRoad_TypesT<CYapfRoad1 , CRoadNodeListTrackDir, CYapfDestinationTileRoadT > > {};
00408 struct CYapfRoad2 : CYapfT<CYapfRoad_TypesT<CYapfRoad2 , CRoadNodeListExitDir , CYapfDestinationTileRoadT > > {};
00409
00410 struct CYapfRoadAnyDepot1 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot1, CRoadNodeListTrackDir, CYapfDestinationAnyDepotRoadT> > {};
00411 struct CYapfRoadAnyDepot2 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot2, CRoadNodeListExitDir , CYapfDestinationAnyDepotRoadT> > {};
00412
00413
00414 Trackdir YapfChooseRoadTrack(const Vehicle *v, TileIndex tile, DiagDirection enterdir)
00415 {
00416
00417 typedef Trackdir (*PfnChooseRoadTrack)(const Vehicle*, TileIndex, DiagDirection);
00418 PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack;
00419
00420
00421 if (_settings_game.pf.yapf.disable_node_optimization) {
00422 pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack;
00423 }
00424
00425 Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir);
00426 return td_ret;
00427 }
00428
00429 uint YapfRoadVehDistanceToTile(const Vehicle *v, TileIndex tile)
00430 {
00431
00432 typedef uint (*PfnDistanceToTile)(const Vehicle*, TileIndex);
00433 PfnDistanceToTile pfnDistanceToTile = &CYapfRoad2::stDistanceToTile;
00434
00435
00436 if (_settings_game.pf.yapf.disable_node_optimization)
00437 pfnDistanceToTile = &CYapfRoad1::stDistanceToTile;
00438
00439
00440 uint dist = pfnDistanceToTile(v, tile);
00441
00442 if (dist != UINT_MAX)
00443 dist = (dist + YAPF_TILE_LENGTH - 1) / YAPF_TILE_LENGTH;
00444 return dist;
00445 }
00446
00447 Depot *YapfFindNearestRoadDepot(const Vehicle *v)
00448 {
00449 TileIndex tile = v->tile;
00450 Trackdir trackdir = GetVehicleTrackdir(v);
00451 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0)
00452 return NULL;
00453
00454
00455 if (IsRoadDepotTile(tile)) {
00456
00457 return GetDepotByTile(tile);
00458 }
00459
00460
00461 typedef Depot *(*PfnFindNearestDepot)(const Vehicle*, TileIndex, Trackdir);
00462 PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot;
00463
00464
00465 if (_settings_game.pf.yapf.disable_node_optimization)
00466 pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot;
00467
00468 Depot *ret = pfnFindNearestDepot(v, tile, trackdir);
00469 return ret;
00470 }