00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef YAPF_COSTRAIL_HPP
00013 #define YAPF_COSTRAIL_HPP
00014
00015 #include "../../pbs.h"
00016
00017 template <class Types>
00018 class CYapfCostRailT
00019 : public CYapfCostBase
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 typedef typename Node::CachedData CachedData;
00027
00028 protected:
00029
00030
00031 struct TILE {
00032 TileIndex tile;
00033 Trackdir td;
00034 TileType tile_type;
00035 RailType rail_type;
00036
00037 TILE()
00038 {
00039 tile = INVALID_TILE;
00040 td = INVALID_TRACKDIR;
00041 tile_type = MP_VOID;
00042 rail_type = INVALID_RAILTYPE;
00043 }
00044
00045 TILE(TileIndex tile, Trackdir td)
00046 {
00047 this->tile = tile;
00048 this->td = td;
00049 this->tile_type = GetTileType(tile);
00050 this->rail_type = GetTileRailType(tile);
00051 }
00052
00053 TILE(const TILE &src)
00054 {
00055 tile = src.tile;
00056 td = src.td;
00057 tile_type = src.tile_type;
00058 rail_type = src.rail_type;
00059 }
00060 };
00061
00062 protected:
00067 int m_max_cost;
00068 CBlobT<int> m_sig_look_ahead_costs;
00069 bool m_disable_cache;
00070
00071 public:
00072 bool m_stopped_on_first_two_way_signal;
00073 protected:
00074
00075 static const int s_max_segment_cost = 10000;
00076
00077 CYapfCostRailT()
00078 : m_max_cost(0)
00079 , m_disable_cache(false)
00080 , m_stopped_on_first_two_way_signal(false)
00081 {
00082
00083 int p0 = Yapf().PfGetSettings().rail_look_ahead_signal_p0;
00084 int p1 = Yapf().PfGetSettings().rail_look_ahead_signal_p1;
00085 int p2 = Yapf().PfGetSettings().rail_look_ahead_signal_p2;
00086 int *pen = m_sig_look_ahead_costs.GrowSizeNC(Yapf().PfGetSettings().rail_look_ahead_max_signals);
00087 for (uint i = 0; i < Yapf().PfGetSettings().rail_look_ahead_max_signals; i++) {
00088 pen[i] = p0 + i * (p1 + i * p2);
00089 }
00090 }
00091
00093 Tpf& Yapf()
00094 {
00095 return *static_cast<Tpf*>(this);
00096 }
00097
00098 public:
00099 FORCEINLINE int SlopeCost(TileIndex tile, Trackdir td)
00100 {
00101 CPerfStart perf_cost(Yapf().m_perf_slope_cost);
00102 if (!stSlopeCost(tile, td)) return 0;
00103 return Yapf().PfGetSettings().rail_slope_penalty;
00104 }
00105
00106 FORCEINLINE int CurveCost(Trackdir td1, Trackdir td2)
00107 {
00108 assert(IsValidTrackdir(td1));
00109 assert(IsValidTrackdir(td2));
00110 int cost = 0;
00111 if (TrackFollower::Allow90degTurns()
00112 && ((TrackdirToTrackdirBits(td2) & (TrackdirBits)TrackdirCrossesTrackdirs(td1)) != 0)) {
00113
00114 cost += Yapf().PfGetSettings().rail_curve90_penalty;
00115 } else if (td2 != NextTrackdir(td1)) {
00116
00117 cost += Yapf().PfGetSettings().rail_curve45_penalty;
00118 }
00119 return cost;
00120 }
00121
00122 FORCEINLINE int SwitchCost(TileIndex tile1, TileIndex tile2, DiagDirection exitdir)
00123 {
00124 if (IsPlainRailTile(tile1) && IsPlainRailTile(tile2)) {
00125 bool t1 = KillFirstBit(GetTrackBits(tile1) & DiagdirReachesTracks(ReverseDiagDir(exitdir))) != TRACK_BIT_NONE;
00126 bool t2 = KillFirstBit(GetTrackBits(tile2) & DiagdirReachesTracks(exitdir)) != TRACK_BIT_NONE;
00127 if (t1 && t2) return Yapf().PfGetSettings().rail_doubleslip_penalty;
00128 }
00129 return 0;
00130 }
00131
00133 FORCEINLINE int OneTileCost(TileIndex& tile, Trackdir trackdir)
00134 {
00135 int cost = 0;
00136
00137 if (IsDiagonalTrackdir(trackdir)) {
00138 cost += YAPF_TILE_LENGTH;
00139 switch (GetTileType(tile)) {
00140 case MP_ROAD:
00141
00142 if (IsLevelCrossing(tile)) {
00143 cost += Yapf().PfGetSettings().rail_crossing_penalty;
00144 }
00145 break;
00146
00147 default:
00148 break;
00149 }
00150 } else {
00151
00152 cost = YAPF_TILE_CORNER_LENGTH;
00153 }
00154 return cost;
00155 }
00156
00158 FORCEINLINE bool IsAnyStationTileReserved(TileIndex tile, Trackdir trackdir, int skipped)
00159 {
00160 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(trackdir)));
00161 for (; skipped >= 0; skipped--, tile += diff) {
00162 if (HasStationReservation(tile)) return true;
00163 }
00164 return false;
00165 }
00166
00168 FORCEINLINE int ReservationCost(Node& n, TileIndex tile, Trackdir trackdir, int skipped)
00169 {
00170 if (n.m_num_signals_passed >= m_sig_look_ahead_costs.Size() / 2) return 0;
00171 if (!IsPbsSignal(n.m_last_signal_type)) return 0;
00172
00173 if (IsRailStationTile(tile) && IsAnyStationTileReserved(tile, trackdir, skipped)) {
00174 return Yapf().PfGetSettings().rail_pbs_station_penalty * (skipped + 1);
00175 } else if (TrackOverlapsTracks(GetReservedTrackbits(tile), TrackdirToTrack(trackdir))) {
00176 int cost = Yapf().PfGetSettings().rail_pbs_cross_penalty;
00177 if (!IsDiagonalTrackdir(trackdir)) cost = (cost * YAPF_TILE_CORNER_LENGTH) / YAPF_TILE_LENGTH;
00178 return cost * (skipped + 1);
00179 }
00180 return 0;
00181 }
00182
00183 int SignalCost(Node& n, TileIndex tile, Trackdir trackdir)
00184 {
00185 int cost = 0;
00186
00187 CPerfStart perf_cost(Yapf().m_perf_other_cost);
00188 if (IsTileType(tile, MP_RAILWAY)) {
00189 bool has_signal_against = HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir));
00190 bool has_signal_along = HasSignalOnTrackdir(tile, trackdir);
00191 if (has_signal_against && !has_signal_along && IsOnewaySignal(tile, TrackdirToTrack(trackdir))) {
00192
00193 n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
00194 } else {
00195 if (has_signal_along) {
00196 SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir);
00197 SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir));
00198
00199 n.m_last_signal_type = sig_type;
00200
00201
00202 int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) ? m_sig_look_ahead_costs.Data()[n.m_num_signals_passed] : 0;
00203 if (sig_state != SIGNAL_STATE_RED) {
00204
00205 n.flags_u.flags_s.m_last_signal_was_red = false;
00206
00207 if (look_ahead_cost < 0) {
00208
00209 cost -= look_ahead_cost;
00210 }
00211 } else {
00212
00213
00214 if (!IsPbsSignal(sig_type) && Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) {
00215
00216 n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
00217 Yapf().m_stopped_on_first_two_way_signal = true;
00218 return -1;
00219 }
00220 n.m_last_red_signal_type = sig_type;
00221 n.flags_u.flags_s.m_last_signal_was_red = true;
00222
00223
00224 if (!IsPbsSignal(sig_type) && look_ahead_cost > 0) {
00225
00226 cost += look_ahead_cost;
00227 }
00228
00229
00230 if (n.m_num_signals_passed == 0) {
00231 switch (sig_type) {
00232 case SIGTYPE_COMBO:
00233 case SIGTYPE_EXIT: cost += Yapf().PfGetSettings().rail_firstred_exit_penalty; break;
00234 case SIGTYPE_NORMAL:
00235 case SIGTYPE_ENTRY: cost += Yapf().PfGetSettings().rail_firstred_penalty; break;
00236 default: break;
00237 }
00238 }
00239 }
00240
00241 n.m_num_signals_passed++;
00242 n.m_segment->m_last_signal_tile = tile;
00243 n.m_segment->m_last_signal_td = trackdir;
00244 }
00245
00246 if (has_signal_against && IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) {
00247 cost += n.m_num_signals_passed < Yapf().PfGetSettings().rail_look_ahead_max_signals ? Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
00248 }
00249 }
00250 }
00251 return cost;
00252 }
00253
00254 FORCEINLINE int PlatformLengthPenalty(int platform_length)
00255 {
00256 int cost = 0;
00257 const Train *v = Yapf().GetVehicle();
00258 assert(v != NULL);
00259 assert(v->type == VEH_TRAIN);
00260 assert(v->gcache.cached_total_length != 0);
00261 int missing_platform_length = CeilDiv(v->gcache.cached_total_length, TILE_SIZE) - platform_length;
00262 if (missing_platform_length < 0) {
00263
00264 cost += Yapf().PfGetSettings().rail_longer_platform_penalty + Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length;
00265 } else if (missing_platform_length > 0) {
00266
00267 cost += Yapf().PfGetSettings().rail_shorter_platform_penalty + Yapf().PfGetSettings().rail_shorter_platform_per_tile_penalty * missing_platform_length;
00268 }
00269 return cost;
00270 }
00271
00272 public:
00273 FORCEINLINE void SetMaxCost(int max_cost)
00274 {
00275 m_max_cost = max_cost;
00276 }
00277
00283 FORCEINLINE bool PfCalcCost(Node &n, const TrackFollower *tf)
00284 {
00285 assert(!n.flags_u.flags_s.m_targed_seen);
00286 assert(tf->m_new_tile == n.m_key.m_tile);
00287 assert((TrackdirToTrackdirBits(n.m_key.m_td) & tf->m_new_td_bits) != TRACKDIR_BIT_NONE);
00288
00289 CPerfStart perf_cost(Yapf().m_perf_cost);
00290
00291
00292 bool has_parent = (n.m_parent != NULL);
00293
00294
00295 CachedData &segment = *n.m_segment;
00296 bool is_cached_segment = (segment.m_cost >= 0);
00297
00298 int parent_cost = has_parent ? n.m_parent->m_cost : 0;
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319 int transition_cost = 0;
00320 int extra_cost = 0;
00321
00322
00323
00324
00325
00326
00327 int segment_entry_cost = 0;
00328 int segment_cost = 0;
00329
00330 const Train *v = Yapf().GetVehicle();
00331
00332
00333 TILE cur(n.m_key.m_tile, n.m_key.m_td);
00334
00335
00336 TILE prev = !has_parent ? TILE() : TILE(n.m_parent->GetLastTile(), n.m_parent->GetLastTrackdir());
00337
00338 EndSegmentReasonBits end_segment_reason = ESRB_NONE;
00339
00340 TrackFollower tf_local(v, Yapf().GetCompatibleRailTypes(), &Yapf().m_perf_ts_cost);
00341
00342 if (!has_parent) {
00343
00344 assert(!is_cached_segment);
00345
00346 goto no_entry_cost;
00347 }
00348
00349 for (;;) {
00350
00351 transition_cost = Yapf().CurveCost(prev.td, cur.td);
00352 transition_cost += Yapf().SwitchCost(prev.tile, cur.tile, TrackdirToExitdir(prev.td));
00353
00354
00355
00356 if (segment_cost == 0) {
00357
00358 segment_entry_cost = transition_cost;
00359 transition_cost = 0;
00360
00361
00362 if (is_cached_segment) {
00363
00364 segment_cost = segment.m_cost;
00365
00366 end_segment_reason = segment.m_end_segment_reason;
00367
00368 if (segment.m_last_signal_tile != INVALID_TILE) {
00369 assert(HasSignalOnTrackdir(segment.m_last_signal_tile, segment.m_last_signal_td));
00370 SignalState sig_state = GetSignalStateByTrackdir(segment.m_last_signal_tile, segment.m_last_signal_td);
00371 bool is_red = (sig_state == SIGNAL_STATE_RED);
00372 n.flags_u.flags_s.m_last_signal_was_red = is_red;
00373 if (is_red) {
00374 n.m_last_red_signal_type = GetSignalType(segment.m_last_signal_tile, TrackdirToTrack(segment.m_last_signal_td));
00375 }
00376 }
00377
00378 cur = TILE(n.GetLastTile(), n.GetLastTrackdir());
00379 break;
00380 }
00381 } else {
00382
00383 segment_cost += transition_cost;
00384 }
00385
00386 no_entry_cost:
00387
00388
00389 segment_cost += Yapf().OneTileCost(cur.tile, cur.td);
00390
00391
00392 segment_cost += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
00393
00394
00395 segment_cost += Yapf().SlopeCost(cur.tile, cur.td);
00396
00397
00398 segment_cost += Yapf().SignalCost(n, cur.tile, cur.td);
00399
00400
00401 segment_cost += Yapf().ReservationCost(n, cur.tile, cur.td, tf->m_tiles_skipped);
00402
00403 end_segment_reason = segment.m_end_segment_reason;
00404
00405
00406 if (cur.tile == prev.tile) {
00407
00408 assert(IsRailDepot(cur.tile));
00409 segment_cost += Yapf().PfGetSettings().rail_depot_reverse_penalty;
00410
00411 end_segment_reason |= ESRB_DEPOT;
00412
00413 } else if (cur.tile_type == MP_STATION && IsRailWaypoint(cur.tile)) {
00414 if (v->current_order.IsType(OT_GOTO_WAYPOINT) &&
00415 GetStationIndex(cur.tile) == v->current_order.GetDestination() &&
00416 !Waypoint::Get(v->current_order.GetDestination())->IsSingleTile()) {
00417
00418
00419
00420 CFollowTrackRail ft(v);
00421 TileIndex t = cur.tile;
00422 Trackdir td = cur.td;
00423 while (ft.Follow(t, td)) {
00424 assert(t != ft.m_new_tile);
00425 t = ft.m_new_tile;
00426 if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
00427
00428
00429
00430 td = INVALID_TRACKDIR;
00431 break;
00432 }
00433 td = RemoveFirstTrackdir(&ft.m_new_td_bits);
00434
00435 if (IsSafeWaitingPosition(v, t, td, true, _settings_game.pf.forbid_90_deg)) break;
00436 }
00437
00438
00439
00440
00441 if (td == INVALID_TRACKDIR ||
00442 !IsSafeWaitingPosition(v, t, td, true, _settings_game.pf.forbid_90_deg) ||
00443 !IsWaitingPositionFree(v, t, td, _settings_game.pf.forbid_90_deg)) {
00444 extra_cost += Yapf().PfGetSettings().rail_lastred_penalty;
00445 }
00446 }
00447
00448 end_segment_reason |= ESRB_WAYPOINT;
00449
00450 } else if (tf->m_is_station) {
00451
00452 uint platform_length = tf->m_tiles_skipped + 1;
00453
00454
00455 segment_cost += Yapf().PfGetSettings().rail_station_penalty * platform_length;
00456
00457 end_segment_reason |= ESRB_STATION;
00458
00459 } else if (TrackFollower::DoTrackMasking() && cur.tile_type == MP_RAILWAY) {
00460
00461 if (HasSignalOnTrackdir(cur.tile, cur.td) && !IsPbsSignal(GetSignalType(cur.tile, TrackdirToTrack(cur.td)))) {
00462 end_segment_reason |= ESRB_SAFE_TILE;
00463 }
00464 }
00465
00466
00467
00468 if (n.m_num_signals_passed < m_sig_look_ahead_costs.Size())
00469 {
00470 int min_speed = 0;
00471 int max_speed = tf->GetSpeedLimit(&min_speed);
00472 int max_veh_speed = v->GetDisplayMaxSpeed();
00473 if (max_speed < max_veh_speed) {
00474 extra_cost += YAPF_TILE_LENGTH * (max_veh_speed - max_speed) * (4 + tf->m_tiles_skipped) / max_veh_speed;
00475 }
00476 if (min_speed > max_veh_speed) {
00477 extra_cost += YAPF_TILE_LENGTH * (min_speed - max_veh_speed);
00478 }
00479 }
00480
00481
00482
00483 if (m_max_cost > 0 && (parent_cost + segment_entry_cost + segment_cost) > m_max_cost) {
00484 end_segment_reason |= ESRB_PATH_TOO_LONG;
00485 }
00486
00487
00488 tf = &tf_local;
00489 tf_local.Init(v, Yapf().GetCompatibleRailTypes(), &Yapf().m_perf_ts_cost);
00490
00491 if (!tf_local.Follow(cur.tile, cur.td)) {
00492 assert(tf_local.m_err != TrackFollower::EC_NONE);
00493
00494 if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) {
00495 end_segment_reason |= ESRB_RAIL_TYPE;
00496 } else {
00497 end_segment_reason |= ESRB_DEAD_END;
00498 }
00499
00500 if (TrackFollower::DoTrackMasking() && !HasOnewaySignalBlockingTrackdir(cur.tile, cur.td)) {
00501 end_segment_reason |= ESRB_SAFE_TILE;
00502 }
00503 break;
00504 }
00505
00506
00507 if (KillFirstBit(tf_local.m_new_td_bits) != TRACKDIR_BIT_NONE) {
00508
00509 end_segment_reason |= ESRB_CHOICE_FOLLOWS;
00510 break;
00511 }
00512
00513
00514 TILE next(tf_local.m_new_tile, (Trackdir)FindFirstBit2x64(tf_local.m_new_td_bits));
00515
00516 if (TrackFollower::DoTrackMasking() && IsTileType(next.tile, MP_RAILWAY)) {
00517 if (HasSignalOnTrackdir(next.tile, next.td) && IsPbsSignal(GetSignalType(next.tile, TrackdirToTrack(next.td)))) {
00518
00519 end_segment_reason |= ESRB_SAFE_TILE;
00520 } else if (HasSignalOnTrackdir(next.tile, ReverseTrackdir(next.td)) && GetSignalType(next.tile, TrackdirToTrack(next.td)) == SIGTYPE_PBS_ONEWAY) {
00521
00522 end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END;
00523 extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty;
00524 }
00525 }
00526
00527
00528 if (next.rail_type != cur.rail_type) {
00529
00530 end_segment_reason |= ESRB_RAIL_TYPE;
00531 break;
00532 }
00533
00534
00535 if (next.tile == n.m_key.m_tile && next.td == n.m_key.m_td) {
00536 end_segment_reason |= ESRB_INFINITE_LOOP;
00537 break;
00538 }
00539
00540 if (segment_cost > s_max_segment_cost) {
00541
00542
00543 if (IsTileType(tf->m_new_tile, MP_RAILWAY)) {
00544 end_segment_reason |= ESRB_SEGMENT_TOO_LONG;
00545 break;
00546 }
00547 }
00548
00549
00550 if (end_segment_reason != ESRB_NONE) {
00551 break;
00552 }
00553
00554
00555 prev = cur;
00556 cur = next;
00557
00558 }
00559
00560 bool target_seen = false;
00561 if ((end_segment_reason & ESRB_POSSIBLE_TARGET) != ESRB_NONE) {
00562
00563 if (Yapf().PfDetectDestination(cur.tile, cur.td)) {
00564
00565 target_seen = true;
00566 }
00567 }
00568
00569
00570 if (!is_cached_segment) {
00571
00572 segment.m_cost = segment_cost;
00573 segment.m_end_segment_reason = end_segment_reason & ESRB_CACHED_MASK;
00574
00575 n.SetLastTileTrackdir(cur.tile, cur.td);
00576 }
00577
00578
00579 if (!target_seen && (end_segment_reason & ESRB_ABORT_PF_MASK) != ESRB_NONE) {
00580
00581 return false;
00582 }
00583
00584
00585 if (target_seen) {
00586 n.flags_u.flags_s.m_targed_seen = true;
00587
00588 if (n.flags_u.flags_s.m_last_signal_was_red) {
00589 if (n.m_last_red_signal_type == SIGTYPE_EXIT) {
00590
00591 extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty;
00592 } else if (!IsPbsSignal(n.m_last_red_signal_type)) {
00593
00594 extra_cost += Yapf().PfGetSettings().rail_lastred_penalty;
00595 }
00596 }
00597
00598
00599 if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) {
00600 const BaseStation *st = BaseStation::GetByTile(n.GetLastTile());
00601 assert(st != NULL);
00602 uint platform_length = st->GetPlatformLength(n.GetLastTile(), ReverseDiagDir(TrackdirToExitdir(n.GetLastTrackdir())));
00603
00604 extra_cost -= Yapf().PfGetSettings().rail_station_penalty * platform_length;
00605
00606 extra_cost += PlatformLengthPenalty(platform_length);
00607 }
00608 }
00609
00610
00611 n.m_cost = parent_cost + segment_entry_cost + segment_cost + extra_cost;
00612
00613 return true;
00614 }
00615
00616 FORCEINLINE bool CanUseGlobalCache(Node& n) const
00617 {
00618 return !m_disable_cache
00619 && (n.m_parent != NULL)
00620 && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.Size());
00621 }
00622
00623 FORCEINLINE void ConnectNodeToCachedData(Node& n, CachedData& ci)
00624 {
00625 n.m_segment = &ci;
00626 if (n.m_segment->m_cost < 0) {
00627 n.m_segment->m_last_tile = n.m_key.m_tile;
00628 n.m_segment->m_last_td = n.m_key.m_td;
00629 }
00630 }
00631
00632 void DisableCache(bool disable)
00633 {
00634 m_disable_cache = disable;
00635 }
00636 };
00637
00638 #endif