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);}

Generated on Mon Sep 22 20:34:20 2008 for openttd by  doxygen 1.5.6