Changeset - r3930:aff4ee55c4ef
[Not reviewed]
master
0 2 0
KUDr - 18 years ago 2006-06-01 21:00:59
kudr@openttd.org
(svn r5065) -CodeChange: [YAPF] Added PfDetectDestination(tile, trackdir) for trains (to be used by platform selection feature)
2 files changed with 21 insertions and 8 deletions:
0 comments (0 inline, 0 general)
yapf/yapf_costrail.hpp
Show inline comments
 
@@ -72,264 +72,265 @@ public:
 
						cost += Yapf().PfGetSettings().rail_crossing_penalty;
 
					break;
 

	
 
				case MP_STATION:
 
					// penalty for passing station tiles
 
					cost += Yapf().PfGetSettings().rail_station_penalty;
 
					break;
 

	
 
				default:
 
					break;
 
			}
 
		} else {
 
			// non-diagonal trackdir
 
			cost = YAPF_TILE_CORNER_LENGTH;
 
		}
 
		return cost;
 
	}
 

	
 
	int SignalCost(Node& n, TileIndex tile, Trackdir trackdir)
 
	{
 
		int cost = 0;
 
		// if there is one-way signal in the opposite direction, then it is not our way
 
		CPerfStart perf_cost(Yapf().m_perf_other_cost);
 
		if (IsTileType(tile, MP_RAILWAY)) {
 
			bool has_signal_against = HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir));
 
			bool has_signal_along = HasSignalOnTrackdir(tile, trackdir);
 
			if (has_signal_against && !has_signal_along) {
 
				// one-way signal in opposite direction
 
				n.m_segment->flags_u.flags_s.m_end_of_line = true;
 
			} else if (has_signal_along) {
 
				SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir);
 
				if (sig_state != SIGNAL_STATE_RED) {
 
					// green signal
 
					n.flags_u.flags_s.m_last_signal_was_red = false;
 
				} else {
 
					// we have a red signal in our direction
 
					// was it first signal which is two-way?
 
					if (Yapf().TreatFirstRedTwoWaySignalAsEOL() && has_signal_against && n.m_num_signals_passed == 0) {
 
						// yes, the first signal is two-way red signal => DEAD END
 
						n.m_segment->flags_u.flags_s.m_end_of_line = true;
 
						return -1;
 
					}
 
					SignalType sig_type = GetSignalType(tile);
 
					n.m_last_red_signal_type = sig_type;
 
					n.flags_u.flags_s.m_last_signal_was_red = true;
 

	
 
					// look-ahead signal penalty
 
					if (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) {
 
						cost += m_sig_look_ahead_costs.Data()[n.m_num_signals_passed];
 
					}
 

	
 
					// special signal penalties
 
					if (n.m_num_signals_passed == 0) {
 
						switch (sig_type) {
 
							case SIGTYPE_COMBO:
 
							case SIGTYPE_EXIT:   cost += Yapf().PfGetSettings().rail_firstred_exit_penalty; break; // first signal is red pre-signal-exit
 
							case SIGTYPE_NORMAL:
 
							case SIGTYPE_ENTRY:  cost += Yapf().PfGetSettings().rail_firstred_penalty; break;
 
						};
 
					}
 
				}
 
				n.m_num_signals_passed++;
 
				n.m_segment->m_last_signal_tile = tile;
 
				n.m_segment->m_last_signal_td = trackdir;
 
			}
 
		}
 
		return cost;
 
	}
 

	
 
public:
 
	FORCEINLINE void SetMaxCost(int max_cost) {m_max_cost = max_cost;}
 

	
 
	/** Called by YAPF to calculate the cost from the origin to the given node.
 
	*   Calculates only the cost of given node, adds it to the parent node cost
 
	*   and stores the result into Node::m_cost member */
 
	FORCEINLINE bool PfCalcCost(Node& n)
 
	{
 
		assert(!n.flags_u.flags_s.m_targed_seen);
 
		CPerfStart perf_cost(Yapf().m_perf_cost);
 
		int parent_cost = (n.m_parent != NULL) ? n.m_parent->m_cost : 0;
 
		int first_tile_cost = 0;
 
		int segment_cost = 0;
 
		int extra_cost = 0;
 
		const Vehicle* v = Yapf().GetVehicle();
 

	
 
		// start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment
 
		TileIndex prev_tile      = (n.m_parent != NULL) ? n.m_parent->GetLastTile() : INVALID_TILE;
 
		Trackdir  prev_trackdir  = (n.m_parent != NULL) ? n.m_parent->GetLastTrackdir() : INVALID_TRACKDIR;
 
		TileType  prev_tile_type = (n.m_parent != NULL) ? GetTileType(n.m_parent->GetLastTile()) : MP_VOID;
 

	
 
		TileIndex tile = n.m_key.m_tile;
 
		Trackdir trackdir = n.m_key.m_td;
 
		TileType tile_type = GetTileType(tile);
 

	
 
		RailType rail_type = GetTileRailType(tile, trackdir);
 

	
 
		bool target_seen = false;
 
		bool target_seen = Yapf().PfDetectDestination(tile, trackdir);
 

	
 
		while (true) {
 
			segment_cost += Yapf().OneTileCost(tile, trackdir);
 
			segment_cost += Yapf().CurveCost(prev_trackdir, trackdir);
 
			segment_cost += Yapf().SlopeCost(tile, trackdir);
 
			segment_cost += Yapf().SignalCost(n, tile, trackdir);
 
			if (n.m_segment->flags_u.flags_s.m_end_of_line) {
 
				break;
 
			}
 

	
 
			// finish if we have reached the destination
 
			target_seen = Yapf().PfDetectDestination(n);
 
			if (target_seen) {
 
				break;
 
			}
 

	
 
			// finish on first station tile - segment should end here to avoid target skipping
 
			// when cached segments are used
 
			if (tile_type == MP_STATION && prev_tile_type != MP_STATION) {
 
				break;
 
			}
 

	
 
			// finish also on waypoint - same workaround as for first station tile
 
			if (tile_type == MP_RAILWAY && IsRailWaypoint(tile)) {
 
				break;
 
			}
 

	
 
			// if there are no reachable trackdirs on the next tile, we have end of road
 
			TrackFollower F(v, &Yapf().m_perf_ts_cost);
 
			if (!F.Follow(tile, trackdir)) {
 
				// we can't continue?
 
				// n.m_segment->flags_u.flags_s.m_end_of_line = true;
 
				break;
 
			}
 

	
 
			// if there are more trackdirs available & reachable, we are at the end of segment
 
			if (KillFirstBit2x64(F.m_new_td_bits) != 0) {
 
				break;
 
			}
 

	
 
			Trackdir new_td = (Trackdir)FindFirstBit2x64(F.m_new_td_bits);
 

	
 
			{
 
				// end segment if train is about to enter simple loop with no junctions
 
				// so next time it should stop on the next if
 
				if (segment_cost > s_max_segment_cost && IsTileType(F.m_new_tile, MP_RAILWAY))
 
					break;
 

	
 
				// stop if train is on simple loop with no junctions
 
				if (F.m_new_tile == n.m_key.m_tile && new_td == n.m_key.m_td)
 
					return false;
 
			}
 

	
 
			// if tail type changes, finish segment (cached segment can't contain more rail types)
 
			{
 
				RailType new_rail_type = GetTileRailType(F.m_new_tile, (Trackdir)FindFirstBit2x64(F.m_new_td_bits));
 
				if (new_rail_type != rail_type) {
 
					break;
 
				}
 
				rail_type = new_rail_type;
 
			}
 

	
 
			// move to the next tile
 
			prev_tile = tile;
 
			prev_trackdir = trackdir;
 
			prev_tile_type = tile_type;
 

	
 
			tile = F.m_new_tile;
 
			trackdir = new_td;
 
			tile_type = GetTileType(tile);
 

	
 
			target_seen = Yapf().PfDetectDestination(tile, trackdir);
 

	
 
			// reversing in depot penalty
 
			if (tile == prev_tile) {
 
				segment_cost += Yapf().PfGetSettings().rail_depot_reverse_penalty;
 
				break;
 
			}
 

	
 
			// if we skipped some tunnel tiles, add their cost
 
			segment_cost += YAPF_TILE_LENGTH * F.m_tunnel_tiles_skipped;
 

	
 
			// add min/max speed penalties
 
			int min_speed = 0;
 
			int max_speed = F.GetSpeedLimit(&min_speed);
 
			if (max_speed < v->max_speed)
 
				segment_cost += YAPF_TILE_LENGTH * (v->max_speed - max_speed) / v->max_speed;
 
			if (min_speed > v->max_speed)
 
				segment_cost += YAPF_TILE_LENGTH * (min_speed - v->max_speed);
 

	
 
			// finish if we already exceeded the maximum cost
 
			if (m_max_cost > 0 && (parent_cost + first_tile_cost + segment_cost) > m_max_cost) {
 
				return false;
 
			}
 

	
 
			if (first_tile_cost == 0) {
 
				// we just have done first tile
 
				first_tile_cost = segment_cost;
 
				segment_cost = 0;
 

	
 
				// look if we can reuse existing (cached) segment cost
 
				if (n.m_segment->m_cost >= 0) {
 
					// reuse the cached segment cost
 
					break;
 
				}
 
			}
 
			// segment cost was not filled yes, we have not cached it yet
 
			n.SetLastTileTrackdir(tile, trackdir);
 

	
 
		} // while (true)
 

	
 
		if (first_tile_cost == 0) {
 
			// we have just finished first tile
 
			first_tile_cost = segment_cost;
 
			segment_cost = 0;
 
		}
 

	
 
		// do we have cached segment cost?
 
		if (n.m_segment->m_cost >= 0) {
 
			// reuse the cached segment cost
 
			segment_cost = n.m_segment->m_cost;
 
		} else {
 
			// save segment cost
 
			n.m_segment->m_cost = segment_cost;
 

	
 
			// save end of segment back to the node
 
			n.SetLastTileTrackdir(tile, trackdir);
 
		}
 

	
 
		// special costs for the case we have reached our target
 
		if (target_seen) {
 
			n.flags_u.flags_s.m_targed_seen = true;
 
			if (n.flags_u.flags_s.m_last_signal_was_red) {
 
				if (n.m_last_red_signal_type == SIGTYPE_EXIT) {
 
					// last signal was red pre-signal-exit
 
					extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty;
 
				} else {
 
					// last signal was red, but not exit
 
					extra_cost += Yapf().PfGetSettings().rail_lastred_penalty;
 
				}
 
			}
 
		}
 

	
 
		// total node cost
 
		n.m_cost = parent_cost + first_tile_cost + segment_cost + extra_cost;
 

	
 
		return !n.m_segment->flags_u.flags_s.m_end_of_line;
 
	}
 

	
 
	FORCEINLINE bool CanUseGlobalCache(Node& n) const
 
	{
 
		return (n.m_parent != NULL)
 
			&& (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.Size());
 
	}
 

	
 
	FORCEINLINE void ConnectNodeToCachedData(Node& n, CachedData& ci)
 
	{
 
		n.m_segment = &ci;
 
		if (n.m_segment->m_cost < 0) {
 
			n.m_segment->m_last_tile = n.m_key.m_tile;
 
			n.m_segment->m_last_td = n.m_key.m_td;
 
		}
 
	}
 

	
 
};
 

	
 

	
 

	
 
#endif /* YAPF_COSTRAIL_HPP */
yapf/yapf_destrail.hpp
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef  YAPF_DESTRAIL_HPP
 
#define  YAPF_DESTRAIL_HPP
 

	
 
class CYapfDestinationRailBase
 
{
 
protected:
 
	RailTypeMask m_compatible_railtypes;
 

	
 
public:
 
	void SetDestination(Vehicle* v)
 
	{
 
		m_compatible_railtypes = v->u.rail.compatible_railtypes;
 
	}
 

	
 
	bool IsCompatibleRailType(RailType rt)
 
	{
 
		return HASBIT(m_compatible_railtypes, rt);
 
	}
 
};
 

	
 
template <class Types>
 
class CYapfDestinationAnyDepotRailT
 
	: public CYapfDestinationRailBase
 
{
 
public:
 
	typedef typename Types::Tpf Tpf;              ///< the pathfinder class (derived from THIS class)
 
	typedef typename Types::NodeList::Titem Node; ///< this will be our node type
 
	typedef typename Node::Key Key;               ///< key to hash tables
 

	
 
	/// to access inherited path finder
 
	Tpf& Yapf() {return *static_cast<Tpf*>(this);}
 

	
 
	/// Called by YAPF to detect if node ends in the desired destination
 
	FORCEINLINE bool PfDetectDestination(Node& n)
 
	{
 
		bool bDest = IsTileDepotType(n.GetLastTile(), TRANSPORT_RAIL);
 
		return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir());
 
	}
 

	
 
	/// Called by YAPF to detect if node ends in the desired destination
 
	FORCEINLINE bool PfDetectDestination(TileIndex tile, Trackdir td)
 
	{
 
		bool bDest = IsTileDepotType(tile, TRANSPORT_RAIL);
 
		return bDest;
 
	}
 

	
 
	/** Called by YAPF to calculate cost estimate. Calculates distance to the destination
 
	*   adds it to the actual cost from origin and stores the sum to the Node::m_estimate */
 
	FORCEINLINE bool PfCalcEstimate(Node& n)
 
	{
 
		n.m_estimate = n.m_cost;
 
		return true;
 
	}
 
};
 

	
 
template <class Types>
 
class CYapfDestinationTileOrStationRailT
 
	: public CYapfDestinationRailBase
 
{
 
public:
 
	typedef typename Types::Tpf Tpf;              ///< the pathfinder class (derived from THIS class)
 
	typedef typename Types::NodeList::Titem Node; ///< this will be our node type
 
	typedef typename Node::Key Key;               ///< key to hash tables
 

	
 
protected:
 
	TileIndex    m_destTile;
 
	TrackdirBits m_destTrackdirs;
 
	StationID    m_dest_station_id;
 

	
 
	/// to access inherited path finder
 
	Tpf& Yapf() {return *static_cast<Tpf*>(this);}
 

	
 
	static TileIndex CalcStationCenterTile(StationID station)
 
	{
 
		const Station* st = GetStation(station);
 

	
 
		uint x = TileX(st->train_tile) + st->trainst_w / 2;
 
		uint y = TileY(st->train_tile) + st->trainst_h / 2;
 
		// return the tile of our target coordinates
 
		return TileXY(x, y);
 
	}
 

	
 
public:
 
	void SetDestination(Vehicle* v)
 
	{
 
		if (v->current_order.type == OT_GOTO_STATION) {
 
			m_destTile = CalcStationCenterTile(v->current_order.station);
 
			m_dest_station_id = v->current_order.station;
 
			m_destTrackdirs = INVALID_TRACKDIR_BIT;
 
		} else {
 
			m_destTile = v->dest_tile;
 
			m_dest_station_id = INVALID_STATION;
 
			m_destTrackdirs = (TrackdirBits)(GetTileTrackStatus(v->dest_tile, TRANSPORT_RAIL) & TRACKDIR_BIT_MASK);
 
		}
 
		CYapfDestinationRailBase::SetDestination(v);
 
	}
 

	
 
	/// Called by YAPF to detect if node ends in the desired destination
 
	FORCEINLINE bool PfDetectDestination(Node& n)
 
	{
 
		return PfDetectDestination(n.GetLastTile(), n.GetLastTrackdir());
 
	}
 

	
 
	/// Called by YAPF to detect if node ends in the desired destination
 
	FORCEINLINE bool PfDetectDestination(TileIndex tile, Trackdir td)
 
	{
 
		bool bDest;
 
		if (m_dest_station_id != INVALID_STATION) {
 
			bDest = IsRailwayStationTile(n.GetLastTile())
 
				&& (GetStationIndex(n.GetLastTile()) == m_dest_station_id)
 
				&& (GetRailStationTrack(n.GetLastTile()) == TrackdirToTrack(n.GetLastTrackdir()));
 
			bDest = IsRailwayStationTile(tile)
 
				&& (GetStationIndex(tile) == m_dest_station_id)
 
				&& (GetRailStationTrack(tile) == TrackdirToTrack(td));
 
		} else {
 
			bDest = (n.GetLastTile() == m_destTile)
 
				&& ((m_destTrackdirs & TrackdirToTrackdirBits(n.GetLastTrackdir())) != TRACKDIR_BIT_NONE);
 
			bDest = (tile == m_destTile)
 
				&& ((m_destTrackdirs & TrackdirToTrackdirBits(td)) != TRACKDIR_BIT_NONE);
 
		}
 
		return bDest;
 
	}
 

	
 
	/** Called by YAPF to calculate cost estimate. Calculates distance to the destination
 
	*   adds it to the actual cost from origin and stores the sum to the Node::m_estimate */
 
	FORCEINLINE bool PfCalcEstimate(Node& n)
 
	{
 
		static int dg_dir_to_x_offs[] = {-1, 0, 1, 0};
 
		static int dg_dir_to_y_offs[] = {0, 1, 0, -1};
 
		if (PfDetectDestination(n)) {
 
			n.m_estimate = n.m_cost;
 
			return true;
 
		}
 

	
 
		TileIndex tile = n.GetLastTile();
 
		DiagDirection exitdir = TrackdirToExitdir(n.GetLastTrackdir());
 
		int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir];
 
		int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir];
 
		int x2 = 2 * TileX(m_destTile);
 
		int y2 = 2 * TileY(m_destTile);
 
		int dx = abs(x1 - x2);
 
		int dy = abs(y1 - y2);
 
		int dmin = min(dx, dy);
 
		int dxy = abs(dx - dy);
 
		int d = dmin * YAPF_TILE_CORNER_LENGTH + (dxy - 1) * (YAPF_TILE_LENGTH / 2);
 
		n.m_estimate = n.m_cost + d;
 
		assert(n.m_estimate >= n.m_parent->m_estimate);
 
		return true;
 
	}
 
};
 

	
 

	
 
#endif /* YAPF_DESTRAIL_HPP */
0 comments (0 inline, 0 general)