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 if (tile == v->dest_tile) {
00331
00332 return DiagDirToDiagTrackdir(enterdir);
00333 }
00334
00335 TileIndex src_tile = tile;
00336
00337 TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes));
00338
00339 src_trackdirs &= DiagdirReachesTrackdirs(enterdir);
00340
00341
00342 Yapf().SetOrigin(src_tile, src_trackdirs);
00343 Yapf().SetDestination(v);
00344
00345
00346 Yapf().FindPath(v);
00347
00348
00349 Trackdir next_trackdir = INVALID_TRACKDIR;
00350 Node *pNode = Yapf().GetBestNode();
00351 if (pNode != NULL) {
00352
00353
00354 while (pNode->m_parent != NULL) {
00355 pNode = pNode->m_parent;
00356 }
00357
00358 Node& best_next_node = *pNode;
00359 assert(best_next_node.GetTile() == tile);
00360 next_trackdir = best_next_node.GetTrackdir();
00361 }
00362 return next_trackdir;
00363 }
00364
00365 static uint stDistanceToTile(const RoadVehicle *v, TileIndex tile)
00366 {
00367 Tpf pf;
00368 return pf.DistanceToTile(v, tile);
00369 }
00370
00371 FORCEINLINE uint DistanceToTile(const RoadVehicle *v, TileIndex dst_tile)
00372 {
00373
00374 if (dst_tile == v->tile) {
00375
00376 return 0;
00377 }
00378
00379 if (!SetOriginFromVehiclePos(v)) return UINT_MAX;
00380
00381
00382 Yapf().SetDestination(v);
00383
00384
00385 uint dist = UINT_MAX;
00386
00387
00388 if (!Yapf().FindPath(v)) return dist;
00389
00390 Node *pNode = Yapf().GetBestNode();
00391 if (pNode != NULL) {
00392
00393
00394 dist = pNode->GetCostEstimate();
00395 }
00396
00397 return dist;
00398 }
00399
00401 FORCEINLINE bool SetOriginFromVehiclePos(const RoadVehicle *v)
00402 {
00403
00404 TileIndex src_tile = v->tile;
00405 Trackdir src_td = v->GetVehicleTrackdir();
00406 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
00407
00408
00409 return false;
00410 }
00411 Yapf().SetOrigin(src_tile, TrackdirToTrackdirBits(src_td));
00412 return true;
00413 }
00414
00415 static bool stFindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile)
00416 {
00417 Tpf pf;
00418 return pf.FindNearestDepot(v, tile, td, max_distance, depot_tile);
00419 }
00420
00421 FORCEINLINE bool FindNearestDepot(const RoadVehicle *v, TileIndex tile, Trackdir td, int max_distance, TileIndex *depot_tile)
00422 {
00423
00424 Yapf().SetOrigin(tile, TrackdirToTrackdirBits(td));
00425
00426
00427 bool bFound = Yapf().FindPath(v);
00428 if (!bFound) return false;
00429
00430
00431
00432 Node *n = Yapf().GetBestNode();
00433
00434 if (max_distance > 0 && n->m_cost > max_distance * YAPF_TILE_LENGTH) return false;
00435
00436 *depot_tile = n->m_segment_last_tile;
00437 return true;
00438 }
00439 };
00440
00441 template <class Tpf_, class Tnode_list, template <class Types> class Tdestination>
00442 struct CYapfRoad_TypesT
00443 {
00444 typedef CYapfRoad_TypesT<Tpf_, Tnode_list, Tdestination> Types;
00445
00446 typedef Tpf_ Tpf;
00447 typedef CFollowTrackRoad TrackFollower;
00448 typedef Tnode_list NodeList;
00449 typedef RoadVehicle VehicleType;
00450 typedef CYapfBaseT<Types> PfBase;
00451 typedef CYapfFollowRoadT<Types> PfFollow;
00452 typedef CYapfOriginTileT<Types> PfOrigin;
00453 typedef Tdestination<Types> PfDestination;
00454 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00455 typedef CYapfCostRoadT<Types> PfCost;
00456 };
00457
00458 struct CYapfRoad1 : CYapfT<CYapfRoad_TypesT<CYapfRoad1 , CRoadNodeListTrackDir, CYapfDestinationTileRoadT > > {};
00459 struct CYapfRoad2 : CYapfT<CYapfRoad_TypesT<CYapfRoad2 , CRoadNodeListExitDir , CYapfDestinationTileRoadT > > {};
00460
00461 struct CYapfRoadAnyDepot1 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot1, CRoadNodeListTrackDir, CYapfDestinationAnyDepotRoadT> > {};
00462 struct CYapfRoadAnyDepot2 : CYapfT<CYapfRoad_TypesT<CYapfRoadAnyDepot2, CRoadNodeListExitDir , CYapfDestinationAnyDepotRoadT> > {};
00463
00464
00465 Trackdir YapfRoadVehicleChooseTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, TrackdirBits trackdirs)
00466 {
00467
00468 typedef Trackdir (*PfnChooseRoadTrack)(const RoadVehicle*, TileIndex, DiagDirection);
00469 PfnChooseRoadTrack pfnChooseRoadTrack = &CYapfRoad2::stChooseRoadTrack;
00470
00471
00472 if (_settings_game.pf.yapf.disable_node_optimization) {
00473 pfnChooseRoadTrack = &CYapfRoad1::stChooseRoadTrack;
00474 }
00475
00476 Trackdir td_ret = pfnChooseRoadTrack(v, tile, enterdir);
00477 return (td_ret != INVALID_TRACKDIR) ? td_ret : (Trackdir)FindFirstBit2x64(trackdirs);
00478 }
00479
00480 FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance)
00481 {
00482 TileIndex tile = v->tile;
00483 Trackdir trackdir = v->GetVehicleTrackdir();
00484 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
00485 return FindDepotData();
00486 }
00487
00488
00489 typedef bool (*PfnFindNearestDepot)(const RoadVehicle*, TileIndex, Trackdir, int, TileIndex*);
00490 PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot;
00491
00492
00493 if (_settings_game.pf.yapf.disable_node_optimization) {
00494 pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot;
00495 }
00496
00497 FindDepotData fdd;
00498 bool ret = pfnFindNearestDepot(v, tile, trackdir, max_distance, &fdd.tile);
00499 fdd.best_length = ret ? max_distance / 2 : UINT_MAX;
00500 return fdd;
00501 }