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