00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../../stdafx.h"
00013 #include "yapf.hpp"
00014 #include "yapf_node_road.hpp"
00015 #include "../../roadstop_base.h"
00016
00017
00018 template <class Types>
00019 class CYapfCostRoadT
00020 {
00021 public:
00022 typedef typename Types::Tpf Tpf;
00023 typedef typename Types::TrackFollower TrackFollower;
00024 typedef typename Types::NodeList::Titem Node;
00025 typedef typename Node::Key Key;
00026
00027 protected:
00029 Tpf& Yapf()
00030 {
00031 return *static_cast<Tpf*>(this);
00032 }
00033
00034 int SlopeCost(TileIndex tile, TileIndex next_tile, Trackdir trackdir)
00035 {
00036
00037 int x1 = TileX(tile) * TILE_SIZE;
00038 int y1 = TileY(tile) * TILE_SIZE;
00039 int z1 = GetSlopeZ(x1 + TILE_SIZE / 2, y1 + TILE_SIZE / 2);
00040
00041
00042 int x2 = TileX(next_tile) * TILE_SIZE;
00043 int y2 = TileY(next_tile) * TILE_SIZE;
00044 int z2 = GetSlopeZ(x2 + TILE_SIZE / 2, y2 + TILE_SIZE / 2);
00045
00046 if (z2 - z1 > 1) {
00047
00048 return Yapf().PfGetSettings().road_slope_penalty;
00049 }
00050 return 0;
00051 }
00052
00054 FORCEINLINE int OneTileCost(TileIndex tile, Trackdir trackdir)
00055 {
00056 int cost = 0;
00057
00058 if (IsDiagonalTrackdir(trackdir)) {
00059 cost += YAPF_TILE_LENGTH;
00060 switch (GetTileType(tile)) {
00061 case MP_ROAD:
00062
00063 if (IsLevelCrossing(tile)) {
00064 cost += Yapf().PfGetSettings().road_crossing_penalty;
00065 }
00066 break;
00067
00068 case MP_STATION: {
00069 const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
00070 if (IsDriveThroughStopTile(tile)) {
00071
00072 cost += Yapf().PfGetSettings().road_stop_penalty;
00073 DiagDirection dir = TrackdirToExitdir(trackdir);
00074 if (!RoadStop::IsDriveThroughRoadStopContinuation(tile, tile - TileOffsByDiagDir(dir))) {
00075
00076
00077 const RoadStop::Entry *entry = rs->GetEntry(dir);
00078 cost += entry->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty / entry->GetLength();
00079 }
00080 } else {
00081
00082 cost += Yapf().PfGetSettings().road_stop_bay_occupied_penalty * (!rs->IsFreeBay(0) + !rs->IsFreeBay(1)) / 2;
00083 }
00084 break;
00085 }
00086
00087 default:
00088 break;
00089 }
00090 } else {
00091
00092 cost = YAPF_TILE_CORNER_LENGTH + Yapf().PfGetSettings().road_curve_penalty;
00093 }
00094 return cost;
00095 }
00096
00097 public:
00103 FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
00104 {
00105 int segment_cost = 0;
00106
00107 TileIndex tile = n.m_key.m_tile;
00108 Trackdir trackdir = n.m_key.m_td;
00109 while (true) {
00110
00111 segment_cost += Yapf().OneTileCost(tile, trackdir);
00112
00113 const RoadVehicle *v = Yapf().GetVehicle();
00114
00115 if (Yapf().PfDetectDestinationTile(tile, trackdir)) break;
00116
00117
00118 if (IsRoadDepotTile(tile) && trackdir == DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
00119
00120 break;
00121 }
00122
00123
00124 TrackFollower F(Yapf().GetVehicle());
00125 if (!F.Follow(tile, trackdir)) break;
00126
00127
00128 if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break;
00129
00130 Trackdir new_td = (Trackdir)FindFirstBit2x64(F.m_new_td_bits);
00131
00132
00133 if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false;
00134
00135
00136 segment_cost += F.m_tiles_skipped * YAPF_TILE_LENGTH;
00137
00138
00139 segment_cost += Yapf().SlopeCost(tile, F.m_new_tile, trackdir);
00140
00141
00142 int min_speed = 0;
00143 int max_veh_speed = v->GetDisplayMaxSpeed();
00144 int max_speed = F.GetSpeedLimit(&min_speed);
00145 if (max_speed < max_veh_speed) segment_cost += 1 * (max_veh_speed - max_speed);
00146 if (min_speed > max_veh_speed) segment_cost += 10 * (min_speed - max_veh_speed);
00147
00148
00149 tile = F.m_new_tile;
00150 trackdir = new_td;
00151 };
00152
00153
00154 n.m_segment_last_tile = tile;
00155 n.m_segment_last_td = trackdir;
00156
00157
00158 int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0;
00159 n.m_cost = parent_cost + segment_cost;
00160 return true;
00161 }
00162 };
00163
00164
00165 template <class Types>
00166 class CYapfDestinationAnyDepotRoadT
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
00175 Tpf& Yapf()
00176 {
00177 return *static_cast<Tpf*>(this);
00178 }
00179
00181 FORCEINLINE bool PfDetectDestination(Node& n)
00182 {
00183 bool bDest = IsRoadDepotTile(n.m_segment_last_tile);
00184 return bDest;
00185 }
00186
00187 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00188 {
00189 return IsRoadDepotTile(tile);
00190 }
00191
00196 FORCEINLINE bool PfCalcEstimate(Node& n)
00197 {
00198 n.m_estimate = n.m_cost;
00199 return true;
00200 }
00201 };
00202
00203
00204 template <class Types>
00205 class CYapfDestinationTileRoadT
00206 {
00207 public:
00208 typedef typename Types::Tpf Tpf;
00209 typedef typename Types::TrackFollower TrackFollower;
00210 typedef typename Types::NodeList::Titem Node;
00211 typedef typename Node::Key Key;
00212
00213 protected:
00214 TileIndex m_destTile;
00215 TrackdirBits m_destTrackdirs;
00216 StationID m_dest_station;
00217 bool m_bus;
00218 bool m_non_artic;
00219
00220 public:
00221 void SetDestination(const RoadVehicle *v)
00222 {
00223 if (v->current_order.IsType(OT_GOTO_STATION)) {
00224 m_dest_station = v->current_order.GetDestination();
00225 m_bus = v->IsBus();
00226 m_destTile = CalcClosestStationTile(m_dest_station, v->tile, m_bus ? STATION_BUS : STATION_TRUCK);
00227 m_non_artic = !v->HasArticulatedPart();
00228 m_destTrackdirs = INVALID_TRACKDIR_BIT;
00229 } else {
00230 m_dest_station = INVALID_STATION;
00231 m_destTile = v->dest_tile;
00232 m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, v->compatible_roadtypes));
00233 }
00234 }
00235
00236 protected:
00238 Tpf& Yapf()
00239 {
00240 return *static_cast<Tpf*>(this);
00241 }
00242
00243 public:
00245 FORCEINLINE bool PfDetectDestination(Node& n)
00246 {
00247 return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td);
00248 }
00249
00250 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00251 {
00252 if (m_dest_station != INVALID_STATION) {
00253 return IsTileType(tile, MP_STATION) &&
00254 GetStationIndex(tile) == m_dest_station &&
00255 (m_bus ? IsBusStop(tile) : IsTruckStop(tile)) &&
00256 (m_non_artic || IsDriveThroughStopTile(tile));
00257 }
00258
00259 return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
00260 }
00261
00266 inline bool PfCalcEstimate(Node& n)
00267 {
00268 static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
00269 static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
00270 if (PfDetectDestination(n)) {
00271 n.m_estimate = n.m_cost;
00272 return true;
00273 }
00274
00275 TileIndex tile = n.m_segment_last_tile;
00276 DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
00277 int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
00278 int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
00279 int x2 = 2 * TileX(m_destTile);
00280 int y2 = 2 * TileY(m_destTile);
00281 int dx = abs(x1 - x2);
00282 int dy = abs(y1 - y2);
00283 int dmin = min(dx, dy);
00284 int dxy = abs(dx - dy);
00285 int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
00286 n.m_estimate = n.m_cost + d;
00287 assert(n.m_estimate >= n.m_parent->m_estimate);
00288 return true;
00289 }
00290 };
00291
00292
00293
00294 template <class Types>
00295 class CYapfFollowRoadT
00296 {
00297 public:
00298 typedef typename Types::Tpf Tpf;
00299 typedef typename Types::TrackFollower TrackFollower;
00300 typedef typename Types::NodeList::Titem Node;
00301 typedef typename Node::Key Key;
00302
00303 protected:
00305 FORCEINLINE Tpf& Yapf()
00306 {
00307 return *static_cast<Tpf*>(this);
00308 }
00309
00310 public:
00311
00317 inline void PfFollowNode(Node& old_node)
00318 {
00319 TrackFollower F(Yapf().GetVehicle());
00320 if (F.Follow(old_node.m_segment_last_tile, old_node.m_segment_last_td)) {
00321 Yapf().AddMultipleNodes(&old_node, F);
00322 }
00323 }
00324
00326 FORCEINLINE char TransportTypeChar() const
00327 {
00328 return 'r';
00329 }
00330
00331 static Trackdir stChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found)
00332 {
00333 Tpf pf;
00334 return pf.ChooseRoadTrack(v, tile, enterdir, path_found);
00335 }
00336
00337 FORCEINLINE Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found)
00338 {
00339
00340
00341
00342
00343 if (tile == v->dest_tile && !v->current_order.IsType(OT_GOTO_STATION)) {
00344
00345 return DiagDirToDiagTrackdir(enterdir);
00346 }
00347
00348 TileIndex src_tile = tile;
00349
00350 TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes));
00351
00352 src_trackdirs &= DiagdirReachesTrackdirs(enterdir);
00353
00354
00355 Yapf().SetOrigin(src_tile, src_trackdirs);
00356 Yapf().SetDestination(v);
00357
00358
00359 path_found = Yapf().FindPath(v);
00360
00361
00362 Trackdir next_trackdir = INVALID_TRACKDIR;
00363 Node *pNode = Yapf().GetBestNode();
00364 if (pNode != NULL) {
00365
00366
00367 while (pNode->m_parent != NULL) {
00368 pNode = pNode->m_parent;
00369 }
00370
00371 Node& best_next_node = *pNode;
00372 assert(best_next_node.GetTile() == tile);
00373 next_trackdir = best_next_node.GetTrackdir();
00374 }
00375 return next_trackdir;
00376 }
00377
00378 static uint stDistanceToTile(const RoadVehicle *v, TileIndex tile)
00379 {
00380 Tpf pf;
00381 return pf.DistanceToTile(v, tile);
00382 }
00383
00384 FORCEINLINE uint DistanceToTile(const RoadVehicle *v, TileIndex dst_tile)
00385 {
00386
00387 if (dst_tile == v->tile) {
00388
00389 return 0;
00390 }
00391
00392 if (!SetOriginFromVehiclePos(v)) return UINT_MAX;
00393
00394
00395 Yapf().SetDestination(v);
00396
00397
00398 uint dist = UINT_MAX;
00399
00400
00401 if (!Yapf().FindPath(v)) return dist;
00402
00403 Node *pNode = Yapf().GetBestNode();
00404 if (pNode != NULL) {
00405
00406
00407 dist = pNode->GetCostEstimate();
00408 }
00409
00410 return dist;
00411 }
00412
00414 FORCEINLINE bool SetOriginFromVehiclePos(const RoadVehicle *v)
00415 {
00416
00417 TileIndex src_tile = v->tile;
00418 Trackdir src_td = v->GetVehicleTrackdir();
00419 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
00420
00421
00422 return false;
00423 }
00424 Yapf().SetOrigin(src_tile, TrackdirToTrackdirBits(src_td));
00425 return true;
00426 }
00427
00428 static bool stFindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile)
00429 {
00430 Tpf pf;
00431 return pf.FindNearestDepot(v, tile, td, max_distance, depot_tile);
00432 }
00433
00434 FORCEINLINE bool FindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile)
00435 {
00436
00437 Yapf().SetOrigin(tile, TrackdirToTrackdirBits(td));
00438
00439
00440 bool bFound = Yapf().FindPath(v);
00441 if (!bFound) return false;
00442
00443
00444
00445 Node *n = Yapf().GetBestNode();
00446
00447 if (max_distance > 0 && n->m_cost > max_distance * YAPF_TILE_LENGTH) return false;
00448
00449 *depot_tile = n->m_segment_last_tile;
00450 return true;
00451 }
00452 };
00453
00454 template <class Tpf_, class Tnode_list, template <class Types> class Tdestination>
00455 struct CYapfRoad_TypesT
00456 {
00457 typedef CYapfRoad_TypesT<Tpf_, Tnode_list, Tdestination> Types;
00458
00459 typedef Tpf_ Tpf;
00460 typedef CFollowTrackRoad TrackFollower;
00461 typedef Tnode_list NodeList;
00462 typedef RoadVehicle VehicleType;
00463 typedef CYapfBaseT<Types> PfBase;
00464 typedef CYapfFollowRoadT<Types> PfFollow;
00465 typedef CYapfOriginTileT<Types> PfOrigin;
00466 typedef Tdestination<Types> PfDestination;
00467 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00468 typedef CYapfCostRoadT<Types> PfCost;
00469 };
00470
00471 struct CYapfRoad1 : CYapfT<CYapfRoad_TypesT<CYapfRoad1 , CRoadNodeListTrackDir, CYapfDestinationTileRoadT > > {};
00472 struct CYapfRoad2 : CYapfT<CYapfRoad_TypesT<CYapfRoad2 , CRoadNodeListExitDir , CYapfDestinationTileRoadT > > {};
00473
00474 struct CYapfRoadAnyDepot1 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot1, CRoadNodeListTrackDir, CYapfDestinationAnyDepotRoadT> > {};
00475 struct CYapfRoadAnyDepot2 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot2, CRoadNodeListExitDir , CYapfDestinationAnyDepotRoadT> > {};
00476
00477
00478 Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs, bool &path_found)
00479 {
00480
00481 typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection, bool &path_found);
00482 PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack;
00483
00484
00485 if (_settings_game.pf.yapf.disable_node_optimization) {
00486 pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack;
00487 }
00488
00489 Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir, path_found);
00490 return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit2x64(trackdirs);
00491 }
00492
00493 FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance)
00494 {
00495 TileIndex tile = v->tile;
00496 Trackdir trackdir = v->GetVehicleTrackdir();
00497 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
00498 return FindDepotData();
00499 }
00500
00501
00502 typedef bool (*PfnFindNearestDepot)(const RoadVehicle*, TileIndex, Trackdir, int, TileIndex*);
00503 PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot;
00504
00505
00506 if (_settings_game.pf.yapf.disable_node_optimization) {
00507 pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot;
00508 }
00509
00510 FindDepotData fdd;
00511 bool ret = pfnFindNearestDepot(v, tile, trackdir, max_distance, &fdd.tile);
00512 fdd.best_length = ret ? max_distance / 2 : UINT_MAX;
00513 return fdd;
00514 }