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 default:
00087 break;
00088 }
00089 } else {
00090
00091 cost = YAPF_TILE_CORNER_LENGTH + Yapf().PfGetSettings().road_curve_penalty;
00092 }
00093 return cost;
00094 }
00095
00096 public:
00100 FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
00101 {
00102 int segment_cost = 0;
00103
00104 TileIndex tile = n.m_key.m_tile;
00105 Trackdir trackdir = n.m_key.m_td;
00106 while (true) {
00107
00108 segment_cost += Yapf().OneTileCost(tile, trackdir);
00109
00110 const RoadVehicle *v = Yapf().GetVehicle();
00111
00112 if (Yapf().PfDetectDestinationTile(tile, trackdir)) break;
00113
00114
00115 if (IsRoadDepotTile(tile) && trackdir == DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
00116
00117 break;
00118 }
00119
00120
00121 TrackFollower F(Yapf().GetVehicle());
00122 if (!F.Follow(tile, trackdir)) break;
00123
00124
00125 if (KillFirstBit(F.m_new_td_bits) != TRACKDIR_BIT_NONE) break;
00126
00127 Trackdir new_td = (Trackdir)FindFirstBit2x64(F.m_new_td_bits);
00128
00129
00130 if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td) return false;
00131
00132
00133 segment_cost += F.m_tiles_skipped * YAPF_TILE_LENGTH;
00134
00135
00136 segment_cost += Yapf().SlopeCost(tile, F.m_new_tile, trackdir);
00137
00138
00139 int min_speed = 0;
00140 int max_speed = F.GetSpeedLimit(&min_speed);
00141 if (max_speed < v->max_speed) segment_cost += 1 * (v->max_speed - max_speed);
00142 if (min_speed > v->max_speed) segment_cost += 10 * (min_speed - v->max_speed);
00143
00144
00145 tile = F.m_new_tile;
00146 trackdir = new_td;
00147 };
00148
00149
00150 n.m_segment_last_tile = tile;
00151 n.m_segment_last_td = trackdir;
00152
00153
00154 int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0;
00155 n.m_cost = parent_cost + segment_cost;
00156 return true;
00157 }
00158 };
00159
00160
00161 template <class Types>
00162 class CYapfDestinationAnyDepotRoadT
00163 {
00164 public:
00165 typedef typename Types::Tpf Tpf;
00166 typedef typename Types::TrackFollower TrackFollower;
00167 typedef typename Types::NodeList::Titem Node;
00168 typedef typename Node::Key Key;
00169
00171 Tpf& Yapf()
00172 {
00173 return *static_cast<Tpf*>(this);
00174 }
00175
00177 FORCEINLINE bool PfDetectDestination(Node& n)
00178 {
00179 bool bDest = IsRoadDepotTile(n.m_segment_last_tile);
00180 return bDest;
00181 }
00182
00183 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00184 {
00185 return IsRoadDepotTile(tile);
00186 }
00187
00190 FORCEINLINE bool PfCalcEstimate(Node& n)
00191 {
00192 n.m_estimate = n.m_cost;
00193 return true;
00194 }
00195 };
00196
00197
00198 template <class Types>
00199 class CYapfDestinationTileRoadT
00200 {
00201 public:
00202 typedef typename Types::Tpf Tpf;
00203 typedef typename Types::TrackFollower TrackFollower;
00204 typedef typename Types::NodeList::Titem Node;
00205 typedef typename Node::Key Key;
00206
00207 protected:
00208 TileIndex m_destTile;
00209 TrackdirBits m_destTrackdirs;
00210 StationID m_dest_station;
00211 bool m_bus;
00212 bool m_non_artic;
00213
00214 public:
00215 void SetDestination(const RoadVehicle *v)
00216 {
00217 if (v->current_order.IsType(OT_GOTO_STATION)) {
00218 m_dest_station = v->current_order.GetDestination();
00219 m_bus = v->IsBus();
00220 m_destTile = CalcClosestStationTile(m_dest_station, v->tile, m_bus ? STATION_BUS : STATION_TRUCK);
00221 m_non_artic = !v->HasArticulatedPart();
00222 m_destTrackdirs = INVALID_TRACKDIR_BIT;
00223 } else {
00224 m_dest_station = INVALID_STATION;
00225 m_destTile = v->dest_tile;
00226 m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, v->compatible_roadtypes));
00227 }
00228 }
00229
00230 protected:
00232 Tpf& Yapf()
00233 {
00234 return *static_cast<Tpf*>(this);
00235 }
00236
00237 public:
00239 FORCEINLINE bool PfDetectDestination(Node& n)
00240 {
00241 return PfDetectDestinationTile(n.m_segment_last_tile, n.m_segment_last_td);
00242 }
00243
00244 FORCEINLINE bool PfDetectDestinationTile(TileIndex tile, Trackdir trackdir)
00245 {
00246 if (m_dest_station != INVALID_STATION) {
00247 return IsTileType(tile, MP_STATION) &&
00248 GetStationIndex(tile) == m_dest_station &&
00249 (m_bus ? IsBusStop(tile) : IsTruckStop(tile)) &&
00250 (m_non_artic || IsDriveThroughStopTile(tile));
00251 }
00252
00253 return tile == m_destTile && ((m_destTrackdirs & TrackdirToTrackdirBits(trackdir)) != TRACKDIR_BIT_NONE);
00254 }
00255
00258 inline bool PfCalcEstimate(Node& n)
00259 {
00260 static const int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
00261 static const int dg_dir_to_y_offs[] = {0, 1, 0, -1};
00262 if (PfDetectDestination(n)) {
00263 n.m_estimate = n.m_cost;
00264 return true;
00265 }
00266
00267 TileIndex tile = n.m_segment_last_tile;
00268 DiagDirection exitdir = TrackdirToExitdir(n.m_segment_last_td);
00269 int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
00270 int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
00271 int x2 = 2 * TileX(m_destTile);
00272 int y2 = 2 * TileY(m_destTile);
00273 int dx = abs(x1 - x2);
00274 int dy = abs(y1 - y2);
00275 int dmin = min(dx, dy);
00276 int dxy = abs(dx - dy);
00277 int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
00278 n.m_estimate = n.m_cost + d;
00279 assert(n.m_estimate >= n.m_parent->m_estimate);
00280 return true;
00281 }
00282 };
00283
00284
00285
00286 template <class Types>
00287 class CYapfFollowRoadT
00288 {
00289 public:
00290 typedef typename Types::Tpf Tpf;
00291 typedef typename Types::TrackFollower TrackFollower;
00292 typedef typename Types::NodeList::Titem Node;
00293 typedef typename Node::Key Key;
00294
00295 protected:
00297 FORCEINLINE Tpf& Yapf()
00298 {
00299 return *static_cast<Tpf*>(this);
00300 }
00301
00302 public:
00303
00307 inline void PfFollowNode(Node& old_node)
00308 {
00309 TrackFollower F(Yapf().GetVehicle());
00310 if (F.Follow(old_node.m_segment_last_tile, old_node.m_segment_last_td)) {
00311 Yapf().AddMultipleNodes(&old_node, F);
00312 }
00313 }
00314
00316 FORCEINLINE char TransportTypeChar() const
00317 {
00318 return 'r';
00319 }
00320
00321 static Trackdir stChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir)
00322 {
00323 Tpf pf;
00324 return pf.ChooseRoadTrack(v, tile, enterdir);
00325 }
00326
00327 FORCEINLINE Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir)
00328 {
00329
00330
00331
00332
00333 if (tile == v->dest_tile && !v->current_order.IsType(OT_GOTO_STATION)) {
00334
00335 return DiagDirToDiagTrackdir(enterdir);
00336 }
00337
00338 TileIndex src_tile = tile;
00339
00340 TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes));
00341
00342 src_trackdirs &= DiagdirReachesTrackdirs(enterdir);
00343
00344
00345 Yapf().SetOrigin(src_tile, src_trackdirs);
00346 Yapf().SetDestination(v);
00347
00348
00349 Yapf().FindPath(v);
00350
00351
00352 Trackdir next_trackdir = INVALID_TRACKDIR;
00353 Node *pNode = Yapf().GetBestNode();
00354 if (pNode != NULL) {
00355
00356
00357 while (pNode->m_parent != NULL) {
00358 pNode = pNode->m_parent;
00359 }
00360
00361 Node& best_next_node = *pNode;
00362 assert(best_next_node.GetTile() == tile);
00363 next_trackdir = best_next_node.GetTrackdir();
00364 }
00365 return next_trackdir;
00366 }
00367
00368 static uint stDistanceToTile(const RoadVehicle *v, TileIndex tile)
00369 {
00370 Tpf pf;
00371 return pf.DistanceToTile(v, tile);
00372 }
00373
00374 FORCEINLINE uint DistanceToTile(const RoadVehicle *v, TileIndex dst_tile)
00375 {
00376
00377 if (dst_tile == v->tile) {
00378
00379 return 0;
00380 }
00381
00382 if (!SetOriginFromVehiclePos(v)) return UINT_MAX;
00383
00384
00385 Yapf().SetDestination(v);
00386
00387
00388 uint dist = UINT_MAX;
00389
00390
00391 if (!Yapf().FindPath(v)) return dist;
00392
00393 Node *pNode = Yapf().GetBestNode();
00394 if (pNode != NULL) {
00395
00396
00397 dist = pNode->GetCostEstimate();
00398 }
00399
00400 return dist;
00401 }
00402
00404 FORCEINLINE bool SetOriginFromVehiclePos(const RoadVehicle *v)
00405 {
00406
00407 TileIndex src_tile = v->tile;
00408 Trackdir src_td = v->GetVehicleTrackdir();
00409 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
00410
00411
00412 return false;
00413 }
00414 Yapf().SetOrigin(src_tile, TrackdirToTrackdirBits(src_td));
00415 return true;
00416 }
00417
00418 static bool stFindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile)
00419 {
00420 Tpf pf;
00421 return pf.FindNearestDepot(v, tile, td, max_distance, depot_tile);
00422 }
00423
00424 FORCEINLINE bool FindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile)
00425 {
00426
00427 Yapf().SetOrigin(tile, TrackdirToTrackdirBits(td));
00428
00429
00430 bool bFound = Yapf().FindPath(v);
00431 if (!bFound) return false;
00432
00433
00434
00435 Node *n = Yapf().GetBestNode();
00436
00437 if (max_distance > 0 && n->m_cost > max_distance * YAPF_TILE_LENGTH) return false;
00438
00439 *depot_tile = n->m_segment_last_tile;
00440 return true;
00441 }
00442 };
00443
00444 template <class Tpf_, class Tnode_list, template <class Types> class Tdestination>
00445 struct CYapfRoad_TypesT
00446 {
00447 typedef CYapfRoad_TypesT<Tpf_, Tnode_list, Tdestination> Types;
00448
00449 typedef Tpf_ Tpf;
00450 typedef CFollowTrackRoad TrackFollower;
00451 typedef Tnode_list NodeList;
00452 typedef RoadVehicle VehicleType;
00453 typedef CYapfBaseT<Types> PfBase;
00454 typedef CYapfFollowRoadT<Types> PfFollow;
00455 typedef CYapfOriginTileT<Types> PfOrigin;
00456 typedef Tdestination<Types> PfDestination;
00457 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00458 typedef CYapfCostRoadT<Types> PfCost;
00459 };
00460
00461 struct CYapfRoad1 : CYapfT<CYapfRoad_TypesT<CYapfRoad1 , CRoadNodeListTrackDir, CYapfDestinationTileRoadT > > {};
00462 struct CYapfRoad2 : CYapfT<CYapfRoad_TypesT<CYapfRoad2 , CRoadNodeListExitDir , CYapfDestinationTileRoadT > > {};
00463
00464 struct CYapfRoadAnyDepot1 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot1, CRoadNodeListTrackDir, CYapfDestinationAnyDepotRoadT> > {};
00465 struct CYapfRoadAnyDepot2 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot2, CRoadNodeListExitDir , CYapfDestinationAnyDepotRoadT> > {};
00466
00467
00468 Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs)
00469 {
00470
00471 typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection);
00472 PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack;
00473
00474
00475 if (_settings_game.pf.yapf.disable_node_optimization) {
00476 pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack;
00477 }
00478
00479 Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir);
00480 return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit2x64(trackdirs);
00481 }
00482
00483 FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance)
00484 {
00485 TileIndex tile = v->tile;
00486 Trackdir trackdir = v->GetVehicleTrackdir();
00487 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
00488 return FindDepotData();
00489 }
00490
00491
00492 typedef bool (*PfnFindNearestDepot)(const RoadVehicle*, TileIndex, Trackdir, int, TileIndex*);
00493 PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot;
00494
00495
00496 if (_settings_game.pf.yapf.disable_node_optimization) {
00497 pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot;
00498 }
00499
00500 FindDepotData fdd;
00501 bool ret = pfnFindNearestDepot(v, tile, trackdir, max_distance, &fdd.tile);
00502 fdd.best_length = ret ? max_distance / 2 : UINT_MAX;
00503 return fdd;
00504 }