pathfind.cpp

Go to the documentation of this file.
00001 /* $Id: pathfind.cpp 12348 2008-03-07 00:47:42Z smatz $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "bridge_map.h"
00008 #include "station_map.h"
00009 #include "depot.h"
00010 #include "tile_cmd.h"
00011 #include "landscape.h"
00012 #include "pathfind.h"
00013 #include "rail_type.h"
00014 #include "debug.h"
00015 #include "tunnel_map.h"
00016 #include "settings_type.h"
00017 #include "depot.h"
00018 #include "tunnelbridge_map.h"
00019 #include "core/random_func.hpp"
00020 #include "tunnelbridge.h"
00021 
00022 /* remember which tiles we have already visited so we don't visit them again. */
00023 static bool TPFSetTileBit(TrackPathFinder *tpf, TileIndex tile, int dir)
00024 {
00025   uint hash, val, offs;
00026   TrackPathFinderLink *link, *new_link;
00027   uint bits = 1 << dir;
00028 
00029   if (tpf->disable_tile_hash)
00030     return true;
00031 
00032   hash = PATHFIND_HASH_TILE(tile);
00033 
00034   val = tpf->hash_head[hash];
00035 
00036   if (val == 0) {
00037     /* unused hash entry, set the appropriate bit in it and return true
00038      * to indicate that a bit was set. */
00039     tpf->hash_head[hash] = bits;
00040     tpf->hash_tile[hash] = tile;
00041     return true;
00042   } else if (!(val & 0x8000)) {
00043     /* single tile */
00044 
00045     if (tile == tpf->hash_tile[hash]) {
00046       /* found another bit for the same tile,
00047        * check if this bit is already set, if so, return false */
00048       if (val & bits)
00049         return false;
00050 
00051       /* otherwise set the bit and return true to indicate that the bit
00052        * was set */
00053       tpf->hash_head[hash] = val | bits;
00054       return true;
00055     } else {
00056       /* two tiles with the same hash, need to make a link */
00057 
00058       /* allocate a link. if out of links, handle this by returning
00059        * that a tile was already visisted. */
00060       if (tpf->num_links_left == 0) {
00061         return false;
00062       }
00063       tpf->num_links_left--;
00064       link = tpf->new_link++;
00065 
00066       /* move the data that was previously in the hash_??? variables
00067        * to the link struct, and let the hash variables point to the link */
00068       link->tile = tpf->hash_tile[hash];
00069       tpf->hash_tile[hash] = PATHFIND_GET_LINK_OFFS(tpf, link);
00070 
00071       link->flags = tpf->hash_head[hash];
00072       tpf->hash_head[hash] = 0xFFFF; // multi link
00073 
00074       link->next = 0xFFFF;
00075     }
00076   } else {
00077     /* a linked list of many tiles,
00078      * find the one corresponding to the tile, if it exists.
00079      * otherwise make a new link */
00080 
00081     offs = tpf->hash_tile[hash];
00082     do {
00083       link = PATHFIND_GET_LINK_PTR(tpf, offs);
00084       if (tile == link->tile) {
00085         /* found the tile in the link list,
00086          * check if the bit was alrady set, if so return false to indicate that the
00087          * bit was already set */
00088         if (link->flags & bits)
00089           return false;
00090         link->flags |= bits;
00091         return true;
00092       }
00093     } while ((offs=link->next) != 0xFFFF);
00094   }
00095 
00096   /* get here if we need to add a new link to link,
00097    * first, allocate a new link, in the same way as before */
00098   if (tpf->num_links_left == 0) {
00099       return false;
00100   }
00101   tpf->num_links_left--;
00102   new_link = tpf->new_link++;
00103 
00104   /* then fill the link with the new info, and establish a ptr from the old
00105    * link to the new one */
00106   new_link->tile = tile;
00107   new_link->flags = bits;
00108   new_link->next = 0xFFFF;
00109 
00110   link->next = PATHFIND_GET_LINK_OFFS(tpf, new_link);
00111   return true;
00112 }
00113 
00114 static const byte _bits_mask[4] = {
00115   0x19,
00116   0x16,
00117   0x25,
00118   0x2A,
00119 };
00120 
00121 static const DiagDirection _tpf_new_direction[14] = {
00122   DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE,
00123   INVALID_DIAGDIR, INVALID_DIAGDIR,
00124   DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE,
00125 };
00126 
00127 static const DiagDirection _tpf_prev_direction[14] = {
00128   DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW,
00129   INVALID_DIAGDIR, INVALID_DIAGDIR,
00130   DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, DIAGDIR_NW,
00131 };
00132 
00133 
00134 static const byte _otherdir_mask[4] = {
00135   0x10,
00136   0,
00137   0x5,
00138   0x2A,
00139 };
00140 
00141 static void TPFMode2(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
00142 {
00143   RememberData rd;
00144 
00145   assert(tpf->tracktype == TRANSPORT_WATER);
00146 
00147   /* This addition will sometimes overflow by a single tile.
00148    * The use of TILE_MASK here makes sure that we still point at a valid
00149    * tile, and then this tile will be in the sentinel row/col, so GetTileTrackStatus will fail. */
00150   tile = TILE_MASK(tile + TileOffsByDiagDir(direction));
00151 
00152   if (++tpf->rd.cur_length > 50)
00153     return;
00154 
00155   TrackStatus ts = GetTileTrackStatus(tile, tpf->tracktype, tpf->sub_type);
00156   TrackBits bits = (TrackBits)(TrackStatusToTrackBits(ts) & _bits_mask[direction]);
00157   if (bits == TRACK_BIT_NONE) return;
00158 
00159   assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
00160 
00161   bool only_one_track = true;
00162   do {
00163     Track track = RemoveFirstTrack(&bits);
00164     if (bits != TRACK_BIT_NONE) only_one_track = false;
00165     rd = tpf->rd;
00166 
00167     /* Change direction 4 times only */
00168     if (!only_one_track && track != tpf->rd.last_choosen_track) {
00169       if (++tpf->rd.depth > 4) {
00170         tpf->rd = rd;
00171         return;
00172       }
00173       tpf->rd.last_choosen_track = track;
00174     }
00175 
00176     tpf->the_dir = (Trackdir)(track + (HasBit(_otherdir_mask[direction], track) ? 8 : 0));
00177 
00178     if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length)) {
00179       TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
00180     }
00181 
00182     tpf->rd = rd;
00183   } while (bits != TRACK_BIT_NONE);
00184 
00185 }
00186 
00196 static inline bool CanAccessTileInDir(TileIndex tile, DiagDirection side, TransportType tracktype)
00197 {
00198   if (tracktype == TRANSPORT_RAIL) {
00199     /* depot from wrong side */
00200     if (IsTileDepotType(tile, TRANSPORT_RAIL) && GetRailDepotDirection(tile) != side) return false;
00201   } else if (tracktype == TRANSPORT_ROAD) {
00202     /* depot from wrong side */
00203     if (IsTileDepotType(tile, TRANSPORT_ROAD) && GetRoadDepotDirection(tile) != side) return false;
00204     /* non-driverthrough road station from wrong side */
00205     if (IsStandardRoadStopTile(tile) && GetRoadStopDir(tile) != side) return false;
00206   }
00207 
00208   return true;
00209 }
00210 
00211 static const uint16 _tpfmode1_and[4] = { 0x1009, 0x16, 0x520, 0x2A00 };
00212 
00213 static void TPFMode1(TrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
00214 {
00215   const TileIndex tile_org = tile;
00216 
00217   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00218     /* wrong track type */
00219     if (GetTunnelBridgeTransportType(tile) != tpf->tracktype) return;
00220 
00221     DiagDirection dir = GetTunnelBridgeDirection(tile);
00222     /* entering tunnel / bridge? */
00223     if (dir == direction) {
00224       TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
00225 
00226       tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1;
00227 
00228       TPFSetTileBit(tpf, tile, 14);
00229       TPFSetTileBit(tpf, endtile, 14);
00230 
00231       tile = endtile;
00232     } else {
00233       /* leaving tunnel / bridge? */
00234       if (ReverseDiagDir(dir) != direction) return;
00235     }
00236   } else {
00237     /* can we leave tile in this dir? */
00238     if (!CanAccessTileInDir(tile, direction, tpf->tracktype)) return;
00239   }
00240 
00241   tile += TileOffsByDiagDir(direction);
00242 
00243   /* can we enter tile in this dir? */
00244   if (!CanAccessTileInDir(tile, ReverseDiagDir(direction), tpf->tracktype)) return;
00245 
00246   /* Check if the new tile is a tunnel or bridge head and that the direction
00247    * and transport type match */
00248   if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00249     if (GetTunnelBridgeDirection(tile) != direction ||
00250         GetTunnelBridgeTransportType(tile) != tpf->tracktype) {
00251       return;
00252     }
00253   }
00254 
00255   uint32 bits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, tpf->tracktype, tpf->sub_type));
00256 
00257   /* Check in case of rail if the owner is the same */
00258   if (tpf->tracktype == TRANSPORT_RAIL) {
00259     if (bits != 0 && TrackStatusToTrackdirBits(GetTileTrackStatus(tile_org, TRANSPORT_RAIL, 0)) != TRACKDIR_BIT_NONE) {
00260       if (GetTileOwner(tile_org) != GetTileOwner(tile)) return;
00261     }
00262   }
00263 
00264   tpf->rd.cur_length++;
00265 
00266   if ((byte)bits != tpf->var2) {
00267     bits &= _tpfmode1_and[direction];
00268     bits |= bits >> 8;
00269   }
00270   bits &= 0xBF;
00271 
00272   if (bits != 0) {
00273     if (!tpf->disable_tile_hash || (tpf->rd.cur_length <= 64 && (KillFirstBit(bits) == 0 || ++tpf->rd.depth <= 7))) {
00274       do {
00275         int i = FIND_FIRST_BIT(bits);
00276         bits = KillFirstBit(bits);
00277 
00278         tpf->the_dir = (Trackdir)((_otherdir_mask[direction] & (byte)(1 << i)) ? (i + 8) : i);
00279         RememberData rd = tpf->rd;
00280 
00281         /* make sure we are not leaving from invalid side */
00282         if (TPFSetTileBit(tpf, tile, tpf->the_dir) && CanAccessTileInDir(tile, TrackdirToExitdir(tpf->the_dir), tpf->tracktype) &&
00283             !tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length) ) {
00284           TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
00285         }
00286         tpf->rd = rd;
00287       } while (bits != 0);
00288     }
00289   }
00290 }
00291 
00292 void FollowTrack(TileIndex tile, uint16 flags, uint sub_type, DiagDirection direction, TPFEnumProc *enum_proc, TPFAfterProc *after_proc, void *data)
00293 {
00294   TrackPathFinder tpf;
00295 
00296   assert(direction < 4);
00297 
00298   /* initialize path finder variables */
00299   tpf.userdata = data;
00300   tpf.enum_proc = enum_proc;
00301   tpf.new_link = tpf.links;
00302   tpf.num_links_left = lengthof(tpf.links);
00303 
00304   tpf.rd.cur_length = 0;
00305   tpf.rd.depth = 0;
00306   tpf.rd.last_choosen_track = INVALID_TRACK;
00307 
00308   tpf.var2 = HasBit(flags, 15) ? 0x43 : 0xFF; // 0x8000
00309 
00310   tpf.disable_tile_hash = HasBit(flags, 12);  // 0x1000
00311 
00312 
00313   tpf.tracktype = (TransportType)(flags & 0xFF);
00314   tpf.sub_type = sub_type;
00315 
00316   if (HasBit(flags, 11)) {
00317     tpf.enum_proc(tile, data, INVALID_TRACKDIR, 0);
00318     TPFMode2(&tpf, tile, direction);
00319   } else {
00320     /* clear the hash_heads */
00321     memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
00322     TPFMode1(&tpf, tile, direction);
00323   }
00324 
00325   if (after_proc != NULL)
00326     after_proc(&tpf);
00327 }
00328 
00329 struct StackedItem {
00330   TileIndex tile;
00331   uint16 cur_length; 
00332   uint16 priority;   
00333   TrackdirByte track;
00334   byte depth;
00335   byte state;
00336   byte first_track;
00337 };
00338 
00339 static const Trackdir _new_trackdir[6][4] = {
00340 {TRACKDIR_X_NE,    INVALID_TRACKDIR, TRACKDIR_X_SW,    INVALID_TRACKDIR,},
00341 {INVALID_TRACKDIR, TRACKDIR_Y_SE,    INVALID_TRACKDIR, TRACKDIR_Y_NW,},
00342 {INVALID_TRACKDIR, TRACKDIR_UPPER_E, TRACKDIR_UPPER_W, INVALID_TRACKDIR,},
00343 {TRACKDIR_LOWER_E, INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_LOWER_W,},
00344 {TRACKDIR_LEFT_N,  TRACKDIR_LEFT_S,  INVALID_TRACKDIR, INVALID_TRACKDIR,},
00345 {INVALID_TRACKDIR, INVALID_TRACKDIR, TRACKDIR_RIGHT_S, TRACKDIR_RIGHT_N,},
00346 };
00347 
00348 struct HashLink {
00349   TileIndex tile;
00350   uint16 typelength;
00351   uint16 next;
00352 };
00353 
00354 struct NewTrackPathFinder {
00355   NTPEnumProc *enum_proc;
00356   void *userdata;
00357   TileIndex dest;
00358 
00359   TransportType tracktype;
00360   RailTypes railtypes;
00361   uint maxlength;
00362 
00363   HashLink *new_link;
00364   uint num_links_left;
00365 
00366   uint nstack;
00367   StackedItem stack[256];     
00368 
00369   uint16 hash_head[0x400];    
00370   TileIndex hash_tile[0x400]; 
00371 
00372   HashLink links[0x400];      
00373 
00374 };
00375 #define NTP_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
00376 #define NTP_GET_LINK_PTR(tpf, link_offs) (HashLink*)((byte*)tpf->links + (link_offs))
00377 
00378 #define ARR(i) tpf->stack[(i)-1]
00379 
00382 static inline void HeapifyUp(NewTrackPathFinder *tpf)
00383 {
00384   StackedItem si;
00385   int i = ++tpf->nstack;
00386 
00387   while (i != 1 && ARR(i).priority < ARR(i>>1).priority) {
00388     /* the child element is larger than the parent item.
00389      * swap the child item and the parent item. */
00390     si = ARR(i); ARR(i) = ARR(i >> 1); ARR(i >> 1) = si;
00391     i >>= 1;
00392   }
00393 }
00394 
00396 static inline void HeapifyDown(NewTrackPathFinder *tpf)
00397 {
00398   StackedItem si;
00399   int i = 1, j;
00400   int n;
00401 
00402   assert(tpf->nstack > 0);
00403   n = --tpf->nstack;
00404 
00405   if (n == 0) return; // heap is empty so nothing to do?
00406 
00407   /* copy the last item to index 0. we use it as base for heapify. */
00408   ARR(1) = ARR(n + 1);
00409 
00410   while ((j = i * 2) <= n) {
00411     /* figure out which is smaller of the children. */
00412     if (j != n && ARR(j).priority > ARR(j + 1).priority)
00413       j++; // right item is smaller
00414 
00415     assert(i <= n && j <= n);
00416     if (ARR(i).priority <= ARR(j).priority)
00417       break; // base elem smaller than smallest, done!
00418 
00419     /* swap parent with the child */
00420     si = ARR(i); ARR(i) = ARR(j); ARR(j) = si;
00421     i = j;
00422   }
00423 }
00424 
00428 static bool NtpVisit(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection dir, uint length)
00429 {
00430   uint hash,head;
00431   HashLink *link, *new_link;
00432 
00433   assert(length < 16384-1);
00434 
00435   hash = PATHFIND_HASH_TILE(tile);
00436 
00437   /* never visited before? */
00438   if ((head=tpf->hash_head[hash]) == 0) {
00439     tpf->hash_tile[hash] = tile;
00440     tpf->hash_head[hash] = dir | (length << 2);
00441     return true;
00442   }
00443 
00444   if (head != 0xffff) {
00445     if (tile == tpf->hash_tile[hash] && (head & 0x3) == (uint)dir) {
00446 
00447       /* longer length */
00448       if (length >= (head >> 2)) return false;
00449 
00450       tpf->hash_head[hash] = dir | (length << 2);
00451       return true;
00452     }
00453     /* two tiles with the same hash, need to make a link
00454      * allocate a link. if out of links, handle this by returning
00455      * that a tile was already visisted. */
00456     if (tpf->num_links_left == 0) {
00457       DEBUG(ntp, 1, "No links left");
00458       return false;
00459     }
00460 
00461     tpf->num_links_left--;
00462     link = tpf->new_link++;
00463 
00464     /* move the data that was previously in the hash_??? variables
00465      * to the link struct, and let the hash variables point to the link */
00466     link->tile = tpf->hash_tile[hash];
00467     tpf->hash_tile[hash] = NTP_GET_LINK_OFFS(tpf, link);
00468 
00469     link->typelength = tpf->hash_head[hash];
00470     tpf->hash_head[hash] = 0xFFFF; // multi link
00471     link->next = 0xFFFF;
00472   } else {
00473     /* a linked list of many tiles,
00474      * find the one corresponding to the tile, if it exists.
00475      * otherwise make a new link */
00476 
00477     uint offs = tpf->hash_tile[hash];
00478     do {
00479       link = NTP_GET_LINK_PTR(tpf, offs);
00480       if (tile == link->tile && (link->typelength & 0x3U) == (uint)dir) {
00481         if (length >= (uint)(link->typelength >> 2)) return false;
00482         link->typelength = dir | (length << 2);
00483         return true;
00484       }
00485     } while ((offs = link->next) != 0xFFFF);
00486   }
00487 
00488   /* get here if we need to add a new link to link,
00489    * first, allocate a new link, in the same way as before */
00490   if (tpf->num_links_left == 0) {
00491     DEBUG(ntp, 1, "No links left");
00492     return false;
00493   }
00494   tpf->num_links_left--;
00495   new_link = tpf->new_link++;
00496 
00497   /* then fill the link with the new info, and establish a ptr from the old
00498    * link to the new one */
00499   new_link->tile = tile;
00500   new_link->typelength = dir | (length << 2);
00501   new_link->next = 0xFFFF;
00502 
00503   link->next = NTP_GET_LINK_OFFS(tpf, new_link);
00504   return true;
00505 }
00506 
00514 static bool NtpCheck(NewTrackPathFinder *tpf, TileIndex tile, uint dir, uint length)
00515 {
00516   uint hash,head,offs;
00517   HashLink *link;
00518 
00519   hash = PATHFIND_HASH_TILE(tile);
00520   head=tpf->hash_head[hash];
00521   assert(head);
00522 
00523   if (head != 0xffff) {
00524     assert( tpf->hash_tile[hash] == tile && (head & 3) == dir);
00525     assert( (head >> 2) <= length);
00526     return length == (head >> 2);
00527   }
00528 
00529   /* else it's a linked list of many tiles */
00530   offs = tpf->hash_tile[hash];
00531   for (;;) {
00532     link = NTP_GET_LINK_PTR(tpf, offs);
00533     if (tile == link->tile && (link->typelength & 0x3U) == dir) {
00534       assert((uint)(link->typelength >> 2) <= length);
00535       return length == (uint)(link->typelength >> 2);
00536     }
00537     offs = link->next;
00538     assert(offs != 0xffff);
00539   }
00540 }
00541 
00542 
00543 static uint DistanceMoo(TileIndex t0, TileIndex t1)
00544 {
00545   const uint dx = Delta(TileX(t0), TileX(t1));
00546   const uint dy = Delta(TileY(t0), TileY(t1));
00547 
00548   const uint straightTracks = 2 * min(dx, dy); // The number of straight (not full length) tracks
00549   /* OPTIMISATION:
00550    * Original: diagTracks = max(dx, dy) - min(dx,dy);
00551    * Proof:
00552    * (dx-dy) - straightTracks  == (min + max) - straightTracks = min + // max - 2 * min = max - min */
00553   const uint diagTracks = dx + dy - straightTracks; // The number of diagonal (full tile length) tracks.
00554 
00555   return diagTracks*DIAG_FACTOR + straightTracks*STR_FACTOR;
00556 }
00557 
00558 /* These has to be small cause the max length of a track
00559  * is currently limited to 16384 */
00560 
00561 static const byte _length_of_track[16] = {
00562   DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0,
00563   DIAG_FACTOR, DIAG_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, STR_FACTOR, 0, 0
00564 };
00565 
00566 /* new more optimized pathfinder for trains...
00567  * Tile is the tile the train is at.
00568  * direction is the tile the train is moving towards. */
00569 
00570 static void NTPEnum(NewTrackPathFinder* tpf, TileIndex tile, DiagDirection direction)
00571 {
00572   TrackBits bits, allbits;
00573   Trackdir track;
00574   TileIndex tile_org;
00575   StackedItem si;
00576   int estimation;
00577 
00578 
00579 
00580   /* Need to have a special case for the start.
00581    * We shouldn't call the callback for the current tile. */
00582   si.cur_length = 1; // Need to start at 1 cause 0 is a reserved value.
00583   si.depth = 0;
00584   si.state = 0;
00585   si.first_track = 0xFF;
00586   goto start_at;
00587 
00588   for (;;) {
00589     /* Get the next item to search from from the priority queue */
00590     do {
00591       if (tpf->nstack == 0)
00592         return; // nothing left? then we're done!
00593       si = tpf->stack[0];
00594       tile = si.tile;
00595 
00596       HeapifyDown(tpf);
00597       /* Make sure we havn't already visited this tile. */
00598     } while (!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length));
00599 
00600     /* Add the length of this track. */
00601     si.cur_length += _length_of_track[si.track];
00602 
00603 callback_and_continue:
00604     if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
00605       return;
00606 
00607     assert(si.track <= 13);
00608     direction = _tpf_new_direction[si.track];
00609 
00610 start_at:
00611     /* If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
00612      *   need to find the exit of the tunnel. */
00613     if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00614       if (GetTunnelBridgeDirection(tile) != ReverseDiagDir(direction)) {
00615         /* We are not just driving out of the tunnel/bridge */
00616         if (GetTunnelBridgeDirection(tile) != direction ||
00617             GetTunnelBridgeTransportType(tile) != tpf->tracktype) {
00618           /* We are not driving into the tunnel/bridge, or it is an invalid tunnel/bridge */
00619           continue;
00620         }
00621         if (!HasBit(tpf->railtypes, GetRailType(tile))) {
00622           bits = TRACK_BIT_NONE;
00623           break;
00624         }
00625 
00626         TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
00627         si.cur_length += DIAG_FACTOR * (GetTunnelBridgeLength(tile, endtile) + 1);
00628         tile = endtile;
00629         /* tile now points to the exit tile of the tunnel/bridge */
00630       }
00631     }
00632 
00633     /* This is a special loop used to go through
00634      * a rail net and find the first intersection */
00635     tile_org = tile;
00636     for (;;) {
00637       assert(direction <= 3);
00638       tile += TileOffsByDiagDir(direction);
00639 
00640       /* too long search length? bail out. */
00641       if (si.cur_length >= tpf->maxlength) {
00642         DEBUG(ntp, 1, "Cur_length too big");
00643         bits = TRACK_BIT_NONE;
00644         break;
00645       }
00646 
00647       /* Not a regular rail tile?
00648        * Then we can't use the code below, but revert to more general code. */
00649       if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
00650         /* We found a tile which is not a normal railway tile.
00651          * Determine which tracks that exist on this tile. */
00652         TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & _tpfmode1_and[direction];
00653         bits = TrackStatusToTrackBits(ts);
00654 
00655         /* Check that the tile contains exactly one track */
00656         if (bits == 0 || KillFirstBit(bits) != 0) break;
00657 
00658         if (!HasBit(tpf->railtypes, GetRailType(tile))) {
00659           bits = TRACK_BIT_NONE;
00660           break;
00661         }
00662 
00663         /*******************
00664          * If we reach here, the tile has exactly one track.
00665          *   tile - index to a tile that is not rail tile, but still straight (with optional signals)
00666          *   bits - bitmask of which track that exist on the tile (exactly one bit is set)
00667          *   direction - which direction are we moving in?
00668          *******************/
00669         si.track = _new_trackdir[FIND_FIRST_BIT(bits)][direction];
00670         si.cur_length += _length_of_track[si.track];
00671         goto callback_and_continue;
00672       }
00673 
00674       /* Regular rail tile, determine which tracks exist. */
00675       allbits = GetTrackBits(tile);
00676       /* Which tracks are reachable? */
00677       bits = allbits & DiagdirReachesTracks(direction);
00678 
00679       /* The tile has no reachable tracks => End of rail segment
00680        * or Intersection => End of rail segment. We check this agains all the
00681        * bits, not just reachable ones, to prevent infinite loops. */
00682       if (bits == TRACK_BIT_NONE || TracksOverlap(allbits)) break;
00683 
00684       if (!HasBit(tpf->railtypes, GetRailType(tile))) {
00685         bits = TRACK_BIT_NONE;
00686         break;
00687       }
00688 
00689       /* If we reach here, the tile has exactly one track, and this
00690        track is reachable = > Rail segment continues */
00691 
00692       track = _new_trackdir[FIND_FIRST_BIT(bits)][direction];
00693       assert(track != INVALID_TRACKDIR);
00694 
00695       si.cur_length += _length_of_track[track];
00696 
00697       /* Check if this rail is an upwards slope. If it is, then add a penalty. */
00698       if (IsDiagonalTrackdir(track) && IsUphillTrackdir(GetTileSlope(tile, NULL), track)) {
00699         // upwards slope. add some penalty.
00700         si.cur_length += 4 * DIAG_FACTOR;
00701       }
00702 
00703       /* railway tile with signals..? */
00704       if (HasSignals(tile)) {
00705         if (!HasSignalOnTrackdir(tile, track)) {
00706           /* if one way signal not pointing towards us, stop going in this direction => End of rail segment. */
00707           if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
00708             bits = TRACK_BIT_NONE;
00709             break;
00710           }
00711         } else if (GetSignalStateByTrackdir(tile, track) == SIGNAL_STATE_GREEN) {
00712           /* green signal in our direction. either one way or two way. */
00713           si.state |= 3;
00714         } else {
00715           /* reached a red signal. */
00716           if (HasSignalOnTrackdir(tile, ReverseTrackdir(track))) {
00717             /* two way red signal. unless we passed another green signal on the way,
00718              * stop going in this direction => End of rail segment.
00719              * this is to prevent us from going into a full platform. */
00720             if (!(si.state & 1)) {
00721               bits = TRACK_BIT_NONE;
00722               break;
00723             }
00724           }
00725           if (!(si.state & 2)) {
00726             /* Is this the first signal we see? And it's red... add penalty */
00727             si.cur_length += 10 * DIAG_FACTOR;
00728             si.state += 2; // remember that we added penalty.
00729             /* Because we added a penalty, we can't just continue as usual.
00730              * Need to get out and let A* do it's job with
00731              * possibly finding an even shorter path. */
00732             break;
00733           }
00734         }
00735 
00736         if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
00737           return; // Don't process this tile any further
00738       }
00739 
00740       /* continue with the next track */
00741       direction = _tpf_new_direction[track];
00742 
00743       /* safety check if we're running around chasing our tail... (infinite loop) */
00744       if (tile == tile_org) {
00745         bits = TRACK_BIT_NONE;
00746         break;
00747       }
00748     }
00749 
00750     /* There are no tracks to choose between.
00751      * Stop searching in this direction */
00752     if (bits == TRACK_BIT_NONE)
00753       continue;
00754 
00755     /****************
00756      * We got multiple tracks to choose between (intersection).
00757      * Branch the search space into several branches.
00758      ****************/
00759 
00760     /* Check if we've already visited this intersection.
00761      * If we've already visited it with a better length, then
00762      * there's no point in visiting it again. */
00763     if (!NtpVisit(tpf, tile, direction, si.cur_length))
00764       continue;
00765 
00766     /* Push all possible alternatives that we can reach from here
00767      * onto the priority heap.
00768      * 'bits' contains the tracks that we can choose between. */
00769 
00770     /* First compute the estimated distance to the target.
00771      * This is used to implement A* */
00772     estimation = 0;
00773     if (tpf->dest != 0)
00774       estimation = DistanceMoo(tile, tpf->dest);
00775 
00776     si.depth++;
00777     if (si.depth == 0)
00778       continue; // We overflowed our depth. No more searching in this direction.
00779     si.tile = tile;
00780     while (bits != TRACK_BIT_NONE) {
00781       Track track = RemoveFirstTrack(&bits);
00782       si.track = _new_trackdir[track][direction];
00783       assert(si.track != 0xFF);
00784       si.priority = si.cur_length + estimation;
00785 
00786       /* out of stack items, bail out? */
00787       if (tpf->nstack >= lengthof(tpf->stack)) {
00788         DEBUG(ntp, 1, "Out of stack");
00789         break;
00790       }
00791 
00792       tpf->stack[tpf->nstack] = si;
00793       HeapifyUp(tpf);
00794     };
00795 
00796     /* If this is the first intersection, we need to fill the first_track member.
00797      * so the code outside knows which path is better.
00798      * also randomize the order in which we search through them. */
00799     if (si.depth == 1) {
00800       assert(tpf->nstack == 1 || tpf->nstack == 2 || tpf->nstack == 3);
00801       if (tpf->nstack != 1) {
00802         uint32 r = Random();
00803         if (r & 1) Swap(tpf->stack[0].track, tpf->stack[1].track);
00804         if (tpf->nstack != 2) {
00805           TrackdirByte t = tpf->stack[2].track;
00806           if (r & 2) Swap(tpf->stack[0].track, t);
00807           if (r & 4) Swap(tpf->stack[1].track, t);
00808           tpf->stack[2].first_track = tpf->stack[2].track = t;
00809         }
00810         tpf->stack[0].first_track = tpf->stack[0].track;
00811         tpf->stack[1].first_track = tpf->stack[1].track;
00812       }
00813     }
00814 
00815     /* Continue with the next from the queue... */
00816   }
00817 }
00818 
00819 
00821 void NewTrainPathfind(TileIndex tile, TileIndex dest, RailTypes railtypes, DiagDirection direction, NTPEnumProc* enum_proc, void* data)
00822 {
00823   NewTrackPathFinder tpf;
00824 
00825   tpf.dest = dest;
00826   tpf.userdata = data;
00827   tpf.enum_proc = enum_proc;
00828   tpf.tracktype = TRANSPORT_RAIL;
00829   tpf.railtypes = railtypes;
00830   tpf.maxlength = min(_patches.pf_maxlength * 3, 10000);
00831   tpf.nstack = 0;
00832   tpf.new_link = tpf.links;
00833   tpf.num_links_left = lengthof(tpf.links);
00834   memset(tpf.hash_head, 0, sizeof(tpf.hash_head));
00835 
00836   NTPEnum(&tpf, tile, direction);
00837 }

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