KUDr@3900: /* $Id$ */ KUDr@3900: celestar@6447: /** @file yapf_common.hpp */ celestar@6447: KUDr@3900: #ifndef YAPF_COMMON_HPP KUDr@3900: #define YAPF_COMMON_HPP KUDr@3900: KUDr@3914: /** YAPF origin provider base class - used when origin is one tile / multiple trackdirs */ KUDr@3900: template KUDr@3900: class CYapfOriginTileT KUDr@3900: { KUDr@3900: public: KUDr@3914: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) KUDr@3900: typedef typename Types::NodeList::Titem Node; ///< this will be our node type KUDr@3914: typedef typename Node::Key Key; ///< key to hash tables KUDr@3900: KUDr@3900: protected: KUDr@3914: TileIndex m_orgTile; ///< origin tile KUDr@3914: TrackdirBits m_orgTrackdirs; ///< origin trackdir mask KUDr@3900: KUDr@3914: /// to access inherited path finder KUDr@3900: FORCEINLINE Tpf& Yapf() {return *static_cast(this);} KUDr@3900: KUDr@3900: public: KUDr@3914: /// Set origin tile / trackdir mask KUDr@3900: void SetOrigin(TileIndex tile, TrackdirBits trackdirs) KUDr@3900: { KUDr@3900: m_orgTile = tile; KUDr@3900: m_orgTrackdirs = trackdirs; KUDr@3900: } KUDr@3900: KUDr@3914: /// Called when YAPF needs to place origin nodes into open list KUDr@3900: void PfSetStartupNodes() KUDr@3900: { KUDr@3978: bool is_choice = (KillFirstBit2x64(m_orgTrackdirs) != 0); KUDr@3900: for (TrackdirBits tdb = m_orgTrackdirs; tdb != TRACKDIR_BIT_NONE; tdb = (TrackdirBits)KillFirstBit2x64(tdb)) { KUDr@3900: Trackdir td = (Trackdir)FindFirstBit2x64(tdb); KUDr@3900: Node& n1 = Yapf().CreateNewNode(); KUDr@3978: n1.Set(NULL, m_orgTile, td, is_choice); KUDr@3900: Yapf().AddStartupNode(n1); KUDr@3900: } KUDr@3900: } KUDr@3900: }; KUDr@3900: KUDr@3914: /** YAPF origin provider base class - used when there are two tile/trackdir origins */ KUDr@3900: template KUDr@3900: class CYapfOriginTileTwoWayT KUDr@3900: { KUDr@3900: public: KUDr@3914: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) KUDr@3900: typedef typename Types::NodeList::Titem Node; ///< this will be our node type KUDr@3914: typedef typename Node::Key Key; ///< key to hash tables KUDr@3900: KUDr@3900: protected: KUDr@3914: TileIndex m_orgTile; ///< first origin tile KUDr@3914: Trackdir m_orgTd; ///< first origin trackdir KUDr@3914: TileIndex m_revTile; ///< second (reversed) origin tile KUDr@3914: Trackdir m_revTd; ///< second (reversed) origin trackdir KUDr@3914: int m_reverse_penalty; ///< penalty to be added for using the reversed origin KUDr@3914: bool m_treat_first_red_two_way_signal_as_eol; ///< in some cases (leaving station) we need to handle first two-way signal differently KUDr@3900: KUDr@3914: /// to access inherited path finder KUDr@3900: FORCEINLINE Tpf& Yapf() {return *static_cast(this);} KUDr@3900: KUDr@3900: public: KUDr@3914: /// set origin (tiles, trackdirs, etc.) KUDr@3900: void SetOrigin(TileIndex tile, Trackdir td, TileIndex tiler = INVALID_TILE, Trackdir tdr = INVALID_TRACKDIR, int reverse_penalty = 0, bool treat_first_red_two_way_signal_as_eol = true) KUDr@3900: { KUDr@3900: m_orgTile = tile; KUDr@3900: m_orgTd = td; KUDr@3900: m_revTile = tiler; KUDr@3900: m_revTd = tdr; KUDr@3900: m_reverse_penalty = reverse_penalty; KUDr@3900: m_treat_first_red_two_way_signal_as_eol = treat_first_red_two_way_signal_as_eol; KUDr@3900: } KUDr@3900: KUDr@3914: /// Called when YAPF needs to place origin nodes into open list KUDr@3900: void PfSetStartupNodes() KUDr@3900: { KUDr@3900: if (m_orgTile != INVALID_TILE && m_orgTd != INVALID_TRACKDIR) { KUDr@3900: Node& n1 = Yapf().CreateNewNode(); KUDr@3978: n1.Set(NULL, m_orgTile, m_orgTd, false); KUDr@3900: Yapf().AddStartupNode(n1); KUDr@3900: } KUDr@3900: if (m_revTile != INVALID_TILE && m_revTd != INVALID_TRACKDIR) { KUDr@3900: Node& n2 = Yapf().CreateNewNode(); KUDr@3978: n2.Set(NULL, m_revTile, m_revTd, false); KUDr@3900: n2.m_cost = m_reverse_penalty; KUDr@3900: Yapf().AddStartupNode(n2); KUDr@3900: } KUDr@3900: } KUDr@3900: KUDr@3914: /// return true if first two-way signal should be treated as dead end KUDr@3900: FORCEINLINE bool TreatFirstRedTwoWaySignalAsEOL() KUDr@3900: { KUDr@3900: return Yapf().PfGetSettings().rail_firstred_twoway_eol && m_treat_first_red_two_way_signal_as_eol; KUDr@3900: } KUDr@3900: }; KUDr@3900: KUDr@3914: /** YAPF destination provider base class - used when destination is single tile / multiple trackdirs */ KUDr@3900: template KUDr@3900: class CYapfDestinationTileT KUDr@3900: { KUDr@3900: public: KUDr@3914: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) KUDr@3900: typedef typename Types::NodeList::Titem Node; ///< this will be our node type KUDr@3914: typedef typename Node::Key Key; ///< key to hash tables KUDr@3900: KUDr@3900: protected: KUDr@3914: TileIndex m_destTile; ///< destination tile KUDr@3914: TrackdirBits m_destTrackdirs; ///< destination trackdir mask KUDr@3900: KUDr@3900: public: KUDr@3914: /// set the destination tile / more trackdirs KUDr@3900: void SetDestination(TileIndex tile, TrackdirBits trackdirs) KUDr@3900: { KUDr@3900: m_destTile = tile; KUDr@3900: m_destTrackdirs = trackdirs; KUDr@3900: } KUDr@3900: KUDr@3900: protected: KUDr@3914: /// to access inherited path finder KUDr@3900: Tpf& Yapf() {return *static_cast(this);} KUDr@3900: KUDr@3900: public: KUDr@3914: /// Called by YAPF to detect if node ends in the desired destination KUDr@3900: FORCEINLINE bool PfDetectDestination(Node& n) KUDr@3900: { KUDr@3900: bool bDest = (n.m_key.m_tile == m_destTile) && ((m_destTrackdirs & TrackdirToTrackdirBits(n.GetTrackdir())) != TRACKDIR_BIT_NONE); KUDr@3900: return bDest; KUDr@3900: } KUDr@3900: KUDr@3914: /** Called by YAPF to calculate cost estimate. Calculates distance to the destination rubidium@4549: * adds it to the actual cost from origin and stores the sum to the Node::m_estimate */ KUDr@3900: inline bool PfCalcEstimate(Node& n) KUDr@3900: { rubidium@9686: static int dg_dir_to_x_offs[] = {-1, 0, 1, 0}; rubidium@9686: static int dg_dir_to_y_offs[] = {0, 1, 0, -1}; rubidium@9686: if (PfDetectDestination(n)) { rubidium@9686: n.m_estimate = n.m_cost; rubidium@9686: return true; rubidium@9686: } rubidium@9686: rubidium@9686: TileIndex tile = n.GetTile(); rubidium@9686: DiagDirection exitdir = TrackdirToExitdir(n.GetTrackdir()); rubidium@9686: int x1 = 2 * TileX(tile) + dg_dir_to_x_offs[(int)exitdir]; rubidium@9686: int y1 = 2 * TileY(tile) + dg_dir_to_y_offs[(int)exitdir]; rubidium@9686: int x2 = 2 * TileX(m_destTile); rubidium@9686: int y2 = 2 * TileY(m_destTile); rubidium@9686: int dx = abs(x1 - x2); rubidium@9686: int dy = abs(y1 - y2); rubidium@9686: int dmin = min(dx, dy); KUDr@3900: int dxy = abs(dx - dy); rubidium@9686: int d = dmin * 7 + (dxy - 1) * (10 / 2); rubidium@9686: n.m_estimate = n.m_cost + d; rubidium@9686: assert(n.m_estimate >= n.m_parent->m_estimate); KUDr@3900: return true; KUDr@3900: } KUDr@3900: }; KUDr@3900: KUDr@3914: /** YAPF template that uses Ttypes template argument to determine all YAPF rubidium@4549: * components (base classes) from which the actual YAPF is composed. rubidium@4549: * For example classes consult: CYapfRail_TypesT template and its instantiations: rubidium@4549: * CYapfRail1, CYapfRail2, CYapfRail3, CYapfAnyDepotRail1, CYapfAnyDepotRail2, CYapfAnyDepotRail3 */ KUDr@3900: template KUDr@3900: class CYapfT KUDr@3914: : public Ttypes::PfBase ///< Instance of CYapfBaseT - main YAPF loop and support base class KUDr@3914: , public Ttypes::PfCost ///< Cost calculation provider base class KUDr@3914: , public Ttypes::PfCache ///< Segment cost cache provider KUDr@3914: , public Ttypes::PfOrigin ///< Origin (tile or two-tile origin) KUDr@3914: , public Ttypes::PfDestination ///< Destination detector and distance (estimate) calculation provider KUDr@3914: , public Ttypes::PfFollow ///< Node follower (stepping provider) KUDr@3900: { KUDr@3900: }; KUDr@3900: KUDr@3900: KUDr@3900: KUDr@3900: #endif /* YAPF_COMMON_HPP */