# yapf_rail.cpp

Go to the documentation of this file.

    00001 /* $Id: yapf_rail.cpp 12056 2008-02-04 15:26:35Z frosch $ */
    00002
    00005 #include "../stdafx.h"
    00006
    00007 #include "yapf.hpp"
    00008 #include "yapf_node_rail.hpp"
    00009 #include "yapf_costrail.hpp"
    00010 #include "yapf_destrail.hpp"
    00011 #include "../vehicle_func.h"
    00012
    00013 #define DEBUG_YAPF_CACHE 0
    00014
    00015 int _total_pf_time_us = 0;
    00016
    00017
    00018
    00019
    00020
    00021 template <class Types>
    00022 class CYapfFollowAnyDepotRailT
    00023 {
    00024 public:
    00025   typedef typename Types::Tpf Tpf;
    00026   typedef typename Types::TrackFollower TrackFollower;
    00027   typedef typename Types::NodeList::Titem Node;
    00028   typedef typename Node::Key Key;
    00029
    00030 protected:
    00032   FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
    00033
    00034 public:
    00038   inline void PfFollowNode(Node& old_node)
    00039   {
    00040     TrackFollower F(Yapf().GetVehicle());
    00041     if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()))
    00042       Yapf().AddMultipleNodes(&old_node, F);
    00043   }
    00044
    00046   FORCEINLINE char TransportTypeChar() const {return 't';}
    00047
    00048   static bool stFindNearestDepotTwoWay(Vehicle *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed)
    00049   {
    00050     Tpf pf1;
    00051     bool result1 = pf1.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_distance, reverse_penalty, depot_tile, reversed);
    00052
    00053 #if DEBUG_YAPF_CACHE
    00054     Tpf pf2;
    00055     TileIndex depot_tile2 = INVALID_TILE;
    00056     bool reversed2 = false;
    00057     pf2.DisableCache(true);
    00058     bool result2 = pf2.FindNearestDepotTwoWay(v, t1, td1, t2, td2, max_distance, reverse_penalty, &depot_tile2, &reversed2);
    00059     if (result1 != result2 || (result1 && (*depot_tile != depot_tile2 || *reversed != reversed2))) {
    00060       DEBUG(yapf, 0, "CACHE ERROR: FindNearestDepotTwoWay() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
    00061     }
    00062 #endif
    00063
    00064     return result1;
    00065   }
    00066
    00067   FORCEINLINE bool FindNearestDepotTwoWay(Vehicle *v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed)
    00068   {
    00069     // set origin and destination nodes
    00070     Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty, true);
    00071     Yapf().SetDestination(v);
    00072     Yapf().SetMaxCost(YAPF_TILE_LENGTH * max_distance);
    00073
    00074     // find the best path
    00075     bool bFound = Yapf().FindPath(v);
    00076     if (!bFound) return false;
    00077
    00078     // some path found
    00079     // get found depot tile
    00080     Node *n = Yapf().GetBestNode();
    00081     *depot_tile = n->GetLastTile();
    00082
    00083     // walk through the path back to the origin
    00084     Node *pNode = n;
    00085     while (pNode->m_parent != NULL) {
    00086       pNode = pNode->m_parent;
    00087     }
    00088
    00089     // if the origin node is our front vehicle tile/Trackdir then we didn't reverse
    00090     // but we can also look at the cost (== 0 -> not reversed, == reverse_penalty -> reversed)
    00091     *reversed = (pNode->m_cost != 0);
    00092
    00093     return true;
    00094   }
    00095 };
    00096
    00097 template <class Types>
    00098 class CYapfFollowRailT
    00099 {
    00100 public:
    00101   typedef typename Types::Tpf Tpf;
    00102   typedef typename Types::TrackFollower TrackFollower;
    00103   typedef typename Types::NodeList::Titem Node;
    00104   typedef typename Node::Key Key;
    00105
    00106 protected:
    00108   FORCEINLINE Tpf& Yapf() {return *static_cast<Tpf*>(this);}
    00109
    00110 public:
    00114   inline void PfFollowNode(Node& old_node)
    00115   {
    00116     TrackFollower F(Yapf().GetVehicle());
    00117     if (F.Follow(old_node.GetLastTile(), old_node.GetLastTrackdir()))
    00118       Yapf().AddMultipleNodes(&old_node, F);
    00119   }
    00120
    00122   FORCEINLINE char TransportTypeChar() const {return 't';}
    00123
    00124   static Trackdir stChooseRailTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found)
    00125   {
    00126     // create pathfinder instance
    00127     Tpf pf1;
    00128     Trackdir result1 = pf1.ChooseRailTrack(v, tile, enterdir, tracks, path_not_found);
    00129
    00130 #if DEBUG_YAPF_CACHE
    00131     Tpf pf2;
    00132     pf2.DisableCache(true);
    00133     Trackdir result2 = pf2.ChooseRailTrack(v, tile, enterdir, tracks, path_not_found);
    00134     if (result1 != result2) {
    00135       DEBUG(yapf, 0, "CACHE ERROR: ChooseRailTrack() = [%d, %d]", result1, result2);
    00136       DumpTarget dmp1, dmp2;
    00137       pf1.DumpBase(dmp1);
    00138       pf2.DumpBase(dmp2);
    00139       FILE *f1 = fopen("C:\\yapf1.txt", "wt");
    00140       FILE *f2 = fopen("C:\\yapf2.txt", "wt");
    00141       fwrite(dmp1.m_out.Data(), 1, dmp1.m_out.Size(), f1);
    00142       fwrite(dmp2.m_out.Data(), 1, dmp2.m_out.Size(), f2);
    00143       fclose(f1);
    00144       fclose(f2);
    00145     }
    00146 #endif
    00147
    00148     return result1;
    00149   }
    00150
    00151   FORCEINLINE Trackdir ChooseRailTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found)
    00152   {
    00153     // set origin and destination nodes
    00154     Yapf().SetOrigin(v->tile, GetVehicleTrackdir(v), INVALID_TILE, INVALID_TRACKDIR, 1, true);
    00155     Yapf().SetDestination(v);
    00156
    00157     // find the best path
    00158     bool path_found = Yapf().FindPath(v);
    00159     if (path_not_found != NULL) {
    00160       // tell controller that the path was only 'guessed'
    00161       // treat the path as found if stopped on the first two way signal(s)
    00162       *path_not_found = !(path_found || Yapf().m_stopped_on_first_two_way_signal);
    00163     }
    00164
    00165     // if path not found - return INVALID_TRACKDIR
    00166     Trackdir next_trackdir = INVALID_TRACKDIR;
    00167     Node *pNode = Yapf().GetBestNode();
    00168     if (pNode != NULL) {
    00169       // path was found or at least suggested
    00170       // walk through the path back to the origin
    00171       Node* pPrev = NULL;
    00172       while (pNode->m_parent != NULL) {
    00173         pPrev = pNode;
    00174         pNode = pNode->m_parent;
    00175       }
    00176       // return trackdir from the best origin node (one of start nodes)
    00177       Node& best_next_node = *pPrev;
    00178       assert(best_next_node.GetTile() == tile);
    00179       next_trackdir = best_next_node.GetTrackdir();
    00180     }
    00181     return next_trackdir;
    00182   }
    00183
    00184   static bool stCheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
    00185   {
    00186     Tpf pf1;
    00187     bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
    00188
    00189 #if DEBUG_YAPF_CACHE
    00190     Tpf pf2;
    00191     pf2.DisableCache(true);
    00192     bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty);
    00193     if (result1 != result2) {
    00194       DEBUG(yapf, 0, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F");
    00195     }
    00196 #endif
    00197
    00198     return result1;
    00199   }
    00200
    00201   FORCEINLINE bool CheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty)
    00202   {
    00203     // create pathfinder instance
    00204     // set origin and destination nodes
    00205     Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty, false);
    00206     Yapf().SetDestination(v);
    00207
    00208     // find the best path
    00209     bool bFound = Yapf().FindPath(v);
    00210
    00211     if (!bFound) return false;
    00212
    00213     // path was found
    00214     // walk through the path back to the origin
    00215     Node *pNode = Yapf().GetBestNode();
    00216     while (pNode->m_parent != NULL) {
    00217       pNode = pNode->m_parent;
    00218     }
    00219
    00220     // check if it was reversed origin
    00221     Node& best_org_node = *pNode;
    00222     bool reversed = (best_org_node.m_cost != 0);
    00223     return reversed;
    00224   }
    00225 };
    00226
    00227 template <class Tpf_, class Ttrack_follower, class Tnode_list, template <class Types> class TdestinationT, template <class Types> class TfollowT>
    00228 struct CYapfRail_TypesT
    00229 {
    00230   typedef CYapfRail_TypesT<Tpf_, Ttrack_follower, Tnode_list, TdestinationT, TfollowT>  Types;
    00231
    00232   typedef Tpf_                                Tpf;
    00233   typedef Ttrack_follower                     TrackFollower;
    00234   typedef Tnode_list                          NodeList;
    00235   typedef CYapfBaseT<Types>                   PfBase;
    00236   typedef TfollowT<Types>                     PfFollow;
    00237   typedef CYapfOriginTileTwoWayT<Types>       PfOrigin;
    00238   typedef TdestinationT<Types>                PfDestination;
    00239   typedef CYapfSegmentCostCacheGlobalT<Types> PfCache;
    00240   typedef CYapfCostRailT<Types>               PfCost;
    00241 };
    00242
    00243 struct CYapfRail1         : CYapfT<CYapfRail_TypesT<CYapfRail1        , CFollowTrackRail    , CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
    00244 struct CYapfRail2         : CYapfT<CYapfRail_TypesT<CYapfRail2        , CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationTileOrStationRailT, CYapfFollowRailT> > {};
    00245
    00246 struct CYapfAnyDepotRail1 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail1, CFollowTrackRail    , CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT     , CYapfFollowAnyDepotRailT> > {};
    00247 struct CYapfAnyDepotRail2 : CYapfT<CYapfRail_TypesT<CYapfAnyDepotRail2, CFollowTrackRailNo90, CRailNodeListTrackDir, CYapfDestinationAnyDepotRailT     , CYapfFollowAnyDepotRailT> > {};
    00248
    00249
    00250 Trackdir YapfChooseRailTrack(Vehicle *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool *path_not_found)
    00251 {
    00252   // default is YAPF type 2
    00253   typedef Trackdir (*PfnChooseRailTrack)(Vehicle*, TileIndex, DiagDirection, TrackBits, bool*);
    00254   PfnChooseRailTrack pfnChooseRailTrack = &CYapfRail1::stChooseRailTrack;
    00255
    00256   // check if non-default YAPF type needed
    00257   if (_patches.forbid_90_deg) {
    00258     pfnChooseRailTrack = &CYapfRail2::stChooseRailTrack; // Trackdir, forbid 90-deg
    00259   }
    00260
    00261   Trackdir td_ret = pfnChooseRailTrack(v, tile, enterdir, tracks, path_not_found);
    00262
    00263   return td_ret;
    00264 }
    00265
    00266 bool YapfCheckReverseTrain(Vehicle* v)
    00267 {
    00268   /* last wagon */
    00269   Vehicle* last_veh = GetLastVehicleInChain(v);
    00270
    00271   // get trackdirs of both ends
    00272   Trackdir td = GetVehicleTrackdir(v);
    00273   Trackdir td_rev = ReverseTrackdir(GetVehicleTrackdir(last_veh));
    00274
    00275   /* tiles where front and back are */
    00276   TileIndex tile = v->tile;
    00277   TileIndex tile_rev = last_veh->tile;
    00278
    00279   int reverse_penalty = 0;
    00280
    00281   if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
    00282     /* front in tunnel / on bridge */
    00283     DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
    00284
    00285     if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile);
    00286     /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */
    00287
    00288     /* Current position of the train in the wormhole */
    00289     TileIndex cur_tile = TileVirtXY(v->x_pos, v->y_pos);
    00290
    00291     /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path
    00292      * Note: Negative penalties are ok for the start tile. */
    00293     reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
    00294   }
    00295
    00296   if (last_veh->u.rail.track == TRACK_BIT_WORMHOLE) {
    00297     /* back in tunnel / on bridge */
    00298     DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
    00299
    00300     if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev);
    00301     /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */
    00302
    00303     /* Current position of the last wagon in the wormhole */
    00304     TileIndex cur_tile = TileVirtXY(last_veh->x_pos, last_veh->y_pos);
    00305
    00306     /* Add distance to drive in the wormhole as penalty for the revere path. */
    00307     reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH;
    00308   }
    00309
    00310   typedef bool (*PfnCheckReverseTrain)(Vehicle*, TileIndex, Trackdir, TileIndex, Trackdir, int);
    00311   PfnCheckReverseTrain pfnCheckReverseTrain = CYapfRail1::stCheckReverseTrain;
    00312
    00313   // check if non-default YAPF type needed
    00314   if (_patches.forbid_90_deg) {
    00315     pfnCheckReverseTrain = &CYapfRail2::stCheckReverseTrain; // Trackdir, forbid 90-deg
    00316   }
    00317
    00318   /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */
    00319   if (reverse_penalty == 0) reverse_penalty = 1;
    00320
    00321   bool reverse = pfnCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty);
    00322
    00323   return reverse;
    00324 }
    00325
    00326 bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed)
    00327 {
    00328   *depot_tile = INVALID_TILE;
    00329   *reversed = false;
    00330
    00331   Vehicle* last_veh = GetLastVehicleInChain(v);
    00332
    00333   TileIndex tile = v->tile;
    00334   TileIndex last_tile = last_veh->tile;
    00335
    00336   // their trackdirs
    00337   Trackdir td = GetVehicleTrackdir(v);
    00338   Trackdir td_rev = ReverseTrackdir(GetVehicleTrackdir(last_veh));
    00339
    00340   typedef bool (*PfnFindNearestDepotTwoWay)(Vehicle*, TileIndex, Trackdir, TileIndex, Trackdir, int, int, TileIndex*, bool*);
    00341   PfnFindNearestDepotTwoWay pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail1::stFindNearestDepotTwoWay;
    00342
    00343   // check if non-default YAPF type needed
    00344   if (_patches.forbid_90_deg) {
    00345     pfnFindNearestDepotTwoWay = &CYapfAnyDepotRail2::stFindNearestDepotTwoWay; // Trackdir, forbid 90-deg
    00346   }
    00347
    00348   bool ret = pfnFindNearestDepotTwoWay(v, tile, td, last_tile, td_rev, max_distance, reverse_penalty, depot_tile, reversed);
    00349   return ret;
    00350 }
    00351
    00353 int CSegmentCostCacheBase::s_rail_change_counter = 0;
    00354
    00355 void YapfNotifyTrackLayoutChange(TileIndex tile, Track track) {CSegmentCostCacheBase::NotifyTrackLayoutChange(tile, track);}