4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file yapf_road.cpp The road pathfinding. */
12 #include "../../stdafx.h"
14 #include "yapf_node_road.hpp"
15 #include "../../roadstop_base.h"
17 #include "../../safeguards.h"
20 template <class Types
>
24 typedef typename
Types::Tpf Tpf
; ///< pathfinder (derived from THIS class)
25 typedef typename
Types::TrackFollower TrackFollower
; ///< track follower helper
26 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
27 typedef typename
Node::Key Key
; ///< key to hash tables
30 /** to access inherited path finder */
33 return *static_cast<Tpf
*>(this);
36 int SlopeCost(TileIndex tile
, TileIndex next_tile
, Trackdir trackdir
)
38 /* height of the center of the current tile */
39 int x1
= TileX(tile
) * TILE_SIZE
;
40 int y1
= TileY(tile
) * TILE_SIZE
;
41 int z1
= GetSlopePixelZ(x1
+ TILE_SIZE
/ 2, y1
+ TILE_SIZE
/ 2);
43 /* height of the center of the next tile */
44 int x2
= TileX(next_tile
) * TILE_SIZE
;
45 int y2
= TileY(next_tile
) * TILE_SIZE
;
46 int z2
= GetSlopePixelZ(x2
+ TILE_SIZE
/ 2, y2
+ TILE_SIZE
/ 2);
50 return Yapf().PfGetSettings().road_slope_penalty
;
55 /** return one tile cost */
56 inline int OneTileCost(TileIndex tile
, Trackdir trackdir
)
60 if (IsDiagonalTrackdir(trackdir
)) {
61 cost
+= YAPF_TILE_LENGTH
;
62 switch (GetTileType(tile
)) {
64 /* Increase the cost for level crossings */
65 if (IsLevelCrossing(tile
)) {
66 cost
+= Yapf().PfGetSettings().road_crossing_penalty
;
71 const RoadStop
*rs
= RoadStop::GetByTile(tile
, GetRoadStopType(tile
));
72 if (IsDriveThroughStopTile(tile
)) {
73 /* Increase the cost for drive-through road stops */
74 cost
+= Yapf().PfGetSettings().road_stop_penalty
;
75 DiagDirection dir
= TrackdirToExitdir(trackdir
);
76 if (!RoadStop::IsDriveThroughRoadStopContinuation(tile
, tile
- TileOffsByDiagDir(dir
))) {
77 /* When we're the first road stop in a 'queue' of them we increase
78 * cost based on the fill percentage of the whole queue. */
79 const RoadStop::Entry
*entry
= rs
->GetEntry(dir
);
80 cost
+= entry
->GetOccupied() * Yapf().PfGetSettings().road_stop_occupied_penalty
/ entry
->GetLength();
83 /* Increase cost for filled road stops */
84 cost
+= Yapf().PfGetSettings().road_stop_bay_occupied_penalty
* (!rs
->IsFreeBay(0) + !rs
->IsFreeBay(1)) / 2;
93 /* non-diagonal trackdir */
94 cost
= YAPF_TILE_CORNER_LENGTH
+ Yapf().PfGetSettings().road_curve_penalty
;
101 * Called by YAPF to calculate the cost from the origin to the given node.
102 * Calculates only the cost of given node, adds it to the parent node cost
103 * and stores the result into Node::m_cost member
105 inline bool PfCalcCost(Node
&n
, const TrackFollower
*tf
)
107 int segment_cost
= 0;
109 /* start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment */
110 TileIndex tile
= n
.m_key
.m_tile
;
111 Trackdir trackdir
= n
.m_key
.m_td
;
113 /* base tile cost depending on distance between edges */
114 segment_cost
+= Yapf().OneTileCost(tile
, trackdir
);
116 const RoadVehicle
*v
= Yapf().GetVehicle();
117 /* we have reached the vehicle's destination - segment should end here to avoid target skipping */
118 if (Yapf().PfDetectDestinationTile(tile
, trackdir
)) break;
120 /* stop if we have just entered the depot */
121 if (IsRoadDepotTile(tile
) && trackdir
== DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile
)))) {
122 /* next time we will reverse and leave the depot */
126 /* if there are no reachable trackdirs on new tile, we have end of road */
127 TrackFollower
F(Yapf().GetVehicle());
128 if (!F
.Follow(tile
, trackdir
)) break;
130 /* if there are more trackdirs available & reachable, we are at the end of segment */
131 if (KillFirstBit(F
.m_new_td_bits
) != TRACKDIR_BIT_NONE
) break;
133 Trackdir new_td
= (Trackdir
)FindFirstBit2x64(F
.m_new_td_bits
);
135 /* stop if RV is on simple loop with no junctions */
136 if (F
.m_new_tile
== n
.m_key
.m_tile
&& new_td
== n
.m_key
.m_td
) return false;
138 /* if we skipped some tunnel tiles, add their cost */
139 segment_cost
+= F
.m_tiles_skipped
* YAPF_TILE_LENGTH
;
140 tiles
+= F
.m_tiles_skipped
+ 1;
142 /* add hilly terrain penalty */
143 segment_cost
+= Yapf().SlopeCost(tile
, F
.m_new_tile
, trackdir
);
145 /* add min/max speed penalties */
147 int max_veh_speed
= v
->GetDisplayMaxSpeed();
148 int max_speed
= F
.GetSpeedLimit(&min_speed
);
149 if (max_speed
< max_veh_speed
) segment_cost
+= 1 * (max_veh_speed
- max_speed
);
150 if (min_speed
> max_veh_speed
) segment_cost
+= 10 * (min_speed
- max_veh_speed
);
152 /* move to the next tile */
155 if (tiles
> MAX_MAP_SIZE
) break;
158 /* save end of segment back to the node */
159 n
.m_segment_last_tile
= tile
;
160 n
.m_segment_last_td
= trackdir
;
162 /* save also tile cost */
163 int parent_cost
= (n
.m_parent
!= NULL
) ? n
.m_parent
->m_cost
: 0;
164 n
.m_cost
= parent_cost
+ segment_cost
;
170 template <class Types
>
171 class CYapfDestinationAnyDepotRoadT
174 typedef typename
Types::Tpf Tpf
; ///< the pathfinder class (derived from THIS class)
175 typedef typename
Types::TrackFollower TrackFollower
;
176 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
177 typedef typename
Node::Key Key
; ///< key to hash tables
179 /** to access inherited path finder */
182 return *static_cast<Tpf
*>(this);
185 /** Called by YAPF to detect if node ends in the desired destination */
186 inline bool PfDetectDestination(Node
&n
)
188 bool bDest
= IsRoadDepotTile(n
.m_segment_last_tile
);
192 inline bool PfDetectDestinationTile(TileIndex tile
, Trackdir trackdir
)
194 return IsRoadDepotTile(tile
);
198 * Called by YAPF to calculate cost estimate. Calculates distance to the destination
199 * adds it to the actual cost from origin and stores the sum to the Node::m_estimate
201 inline bool PfCalcEstimate(Node
&n
)
203 n
.m_estimate
= n
.m_cost
;
209 template <class Types
>
210 class CYapfDestinationTileRoadT
213 typedef typename
Types::Tpf Tpf
; ///< the pathfinder class (derived from THIS class)
214 typedef typename
Types::TrackFollower TrackFollower
;
215 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
216 typedef typename
Node::Key Key
; ///< key to hash tables
219 TileIndex m_destTile
;
220 TrackdirBits m_destTrackdirs
;
221 StationID m_dest_station
;
226 void SetDestination(const RoadVehicle
*v
)
228 if (v
->current_order
.IsType(OT_GOTO_STATION
)) {
229 m_dest_station
= v
->current_order
.GetDestination();
231 m_destTile
= CalcClosestStationTile(m_dest_station
, v
->tile
, m_bus
? STATION_BUS
: STATION_TRUCK
);
232 m_non_artic
= !v
->HasArticulatedPart();
233 m_destTrackdirs
= INVALID_TRACKDIR_BIT
;
235 m_dest_station
= INVALID_STATION
;
236 m_destTile
= v
->dest_tile
;
237 m_destTrackdirs
= TrackStatusToTrackdirBits(GetTileTrackStatus(v
->dest_tile
, TRANSPORT_ROAD
, v
->compatible_roadtypes
));
242 /** to access inherited path finder */
245 return *static_cast<Tpf
*>(this);
249 /** Called by YAPF to detect if node ends in the desired destination */
250 inline bool PfDetectDestination(Node
&n
)
252 return PfDetectDestinationTile(n
.m_segment_last_tile
, n
.m_segment_last_td
);
255 inline bool PfDetectDestinationTile(TileIndex tile
, Trackdir trackdir
)
257 if (m_dest_station
!= INVALID_STATION
) {
258 return IsTileType(tile
, MP_STATION
) &&
259 GetStationIndex(tile
) == m_dest_station
&&
260 (m_bus
? IsBusStop(tile
) : IsTruckStop(tile
)) &&
261 (m_non_artic
|| IsDriveThroughStopTile(tile
));
264 return tile
== m_destTile
&& ((m_destTrackdirs
& TrackdirToTrackdirBits(trackdir
)) != TRACKDIR_BIT_NONE
);
268 * Called by YAPF to calculate cost estimate. Calculates distance to the destination
269 * adds it to the actual cost from origin and stores the sum to the Node::m_estimate
271 inline bool PfCalcEstimate(Node
&n
)
273 static const int dg_dir_to_x_offs
[] = {-1, 0, 1, 0};
274 static const int dg_dir_to_y_offs
[] = {0, 1, 0, -1};
275 if (PfDetectDestination(n
)) {
276 n
.m_estimate
= n
.m_cost
;
280 TileIndex tile
= n
.m_segment_last_tile
;
281 DiagDirection exitdir
= TrackdirToExitdir(n
.m_segment_last_td
);
282 int x1
= 2 * TileX(tile
) + dg_dir_to_x_offs
[(int)exitdir
];
283 int y1
= 2 * TileY(tile
) + dg_dir_to_y_offs
[(int)exitdir
];
284 int x2
= 2 * TileX(m_destTile
);
285 int y2
= 2 * TileY(m_destTile
);
286 int dx
= abs(x1
- x2
);
287 int dy
= abs(y1
- y2
);
288 int dmin
= min(dx
, dy
);
289 int dxy
= abs(dx
- dy
);
290 int d
= dmin
* YAPF_TILE_CORNER_LENGTH
+ (dxy
- 1) * (YAPF_TILE_LENGTH
/ 2);
291 n
.m_estimate
= n
.m_cost
+ d
;
292 assert(n
.m_estimate
>= n
.m_parent
->m_estimate
);
299 template <class Types
>
300 class CYapfFollowRoadT
303 typedef typename
Types::Tpf Tpf
; ///< the pathfinder class (derived from THIS class)
304 typedef typename
Types::TrackFollower TrackFollower
;
305 typedef typename
Types::NodeList::Titem Node
; ///< this will be our node type
306 typedef typename
Node::Key Key
; ///< key to hash tables
309 /** to access inherited path finder */
312 return *static_cast<Tpf
*>(this);
318 * Called by YAPF to move from the given node to the next tile. For each
319 * reachable trackdir on the new tile creates new node, initializes it
320 * and adds it to the open list by calling Yapf().AddNewNode(n)
322 inline void PfFollowNode(Node
&old_node
)
324 TrackFollower
F(Yapf().GetVehicle());
325 if (F
.Follow(old_node
.m_segment_last_tile
, old_node
.m_segment_last_td
)) {
326 Yapf().AddMultipleNodes(&old_node
, F
);
330 /** return debug report character to identify the transportation type */
331 inline char TransportTypeChar() const
336 static Trackdir
stChooseRoadTrack(const RoadVehicle
*v
, TileIndex tile
, DiagDirection enterdir
, bool &path_found
)
339 return pf
.ChooseRoadTrack(v
, tile
, enterdir
, path_found
);
342 inline Trackdir
ChooseRoadTrack(const RoadVehicle
*v
, TileIndex tile
, DiagDirection enterdir
, bool &path_found
)
344 /* Handle special case - when next tile is destination tile.
345 * However, when going to a station the (initial) destination
346 * tile might not be a station, but a junction, in which case
347 * this method forces the vehicle to jump in circles. */
348 if (tile
== v
->dest_tile
&& !v
->current_order
.IsType(OT_GOTO_STATION
)) {
349 /* choose diagonal trackdir reachable from enterdir */
350 return DiagDirToDiagTrackdir(enterdir
);
352 /* our source tile will be the next vehicle tile (should be the given one) */
353 TileIndex src_tile
= tile
;
354 /* get available trackdirs on the start tile */
355 TrackdirBits src_trackdirs
= TrackStatusToTrackdirBits(GetTileTrackStatus(tile
, TRANSPORT_ROAD
, v
->compatible_roadtypes
));
356 /* select reachable trackdirs only */
357 src_trackdirs
&= DiagdirReachesTrackdirs(enterdir
);
359 /* set origin and destination nodes */
360 Yapf().SetOrigin(src_tile
, src_trackdirs
);
361 Yapf().SetDestination(v
);
363 /* find the best path */
364 path_found
= Yapf().FindPath(v
);
366 /* if path not found - return INVALID_TRACKDIR */
367 Trackdir next_trackdir
= INVALID_TRACKDIR
;
368 Node
*pNode
= Yapf().GetBestNode();
370 /* path was found or at least suggested
371 * walk through the path back to its origin */
372 while (pNode
->m_parent
!= NULL
) {
373 pNode
= pNode
->m_parent
;
375 /* return trackdir from the best origin node (one of start nodes) */
376 Node
&best_next_node
= *pNode
;
377 assert(best_next_node
.GetTile() == tile
);
378 next_trackdir
= best_next_node
.GetTrackdir();
380 return next_trackdir
;
383 static uint
stDistanceToTile(const RoadVehicle
*v
, TileIndex tile
)
386 return pf
.DistanceToTile(v
, tile
);
389 inline uint
DistanceToTile(const RoadVehicle
*v
, TileIndex dst_tile
)
391 /* handle special case - when current tile is the destination tile */
392 if (dst_tile
== v
->tile
) {
393 /* distance is zero in this case */
397 if (!SetOriginFromVehiclePos(v
)) return UINT_MAX
;
399 /* get available trackdirs on the destination tile */
400 Yapf().SetDestination(v
);
402 /* if path not found - return distance = UINT_MAX */
403 uint dist
= UINT_MAX
;
405 /* find the best path */
406 if (!Yapf().FindPath(v
)) return dist
;
408 Node
*pNode
= Yapf().GetBestNode();
411 * get the path cost estimate */
412 dist
= pNode
->GetCostEstimate();
418 /** Return true if the valid origin (tile/trackdir) was set from the current vehicle position. */
419 inline bool SetOriginFromVehiclePos(const RoadVehicle
*v
)
421 /* set origin (tile, trackdir) */
422 TileIndex src_tile
= v
->tile
;
423 Trackdir src_td
= v
->GetVehicleTrackdir();
424 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile
, TRANSPORT_ROAD
, v
->compatible_roadtypes
)) & TrackdirToTrackdirBits(src_td
)) == 0) {
425 /* sometimes the roadveh is not on the road (it resides on non-existing track)
426 * how should we handle that situation? */
429 Yapf().SetOrigin(src_tile
, TrackdirToTrackdirBits(src_td
));
433 static FindDepotData
stFindNearestDepot(const RoadVehicle
*v
, TileIndex tile
, Trackdir td
, int max_distance
)
436 return pf
.FindNearestDepot(v
, tile
, td
, max_distance
);
440 * Find the best depot for a road vehicle.
442 * @param tile Tile of the vehicle.
443 * @param td Trackdir of the vehicle.
444 * @param max_distance max length (penalty) for paths.
445 * @todo max_distance not used by YAPF for road vehicles.
446 * It can be removed or copy the SetMaxCost() strategy
447 * applied in YAPF for rail. The best depot can be at
448 * a distance greater than max_distance.
450 inline FindDepotData
FindNearestDepot(const RoadVehicle
*v
, TileIndex tile
, Trackdir td
, int max_distance
)
453 Yapf().SetOrigin(tile
, TrackdirToTrackdirBits(td
));
455 /* Find the best path and return if no depot is found. */
456 if (!Yapf().FindPath(v
)) return FindDepotData();
458 /* Return the cost of the best path and its depot. */
459 Node
*n
= Yapf().GetBestNode();
460 return FindDepotData(n
->m_segment_last_tile
, n
->m_cost
);
464 template <class Tpf_
, class Tnode_list
, template <class Types
> class Tdestination
>
465 struct CYapfRoad_TypesT
467 typedef CYapfRoad_TypesT
<Tpf_
, Tnode_list
, Tdestination
> Types
;
470 typedef CFollowTrackRoad TrackFollower
;
471 typedef Tnode_list NodeList
;
472 typedef RoadVehicle VehicleType
;
473 typedef CYapfBaseT
<Types
> PfBase
;
474 typedef CYapfFollowRoadT
<Types
> PfFollow
;
475 typedef CYapfOriginTileT
<Types
> PfOrigin
;
476 typedef Tdestination
<Types
> PfDestination
;
477 typedef CYapfSegmentCostCacheNoneT
<Types
> PfCache
;
478 typedef CYapfCostRoadT
<Types
> PfCost
;
481 struct CYapfRoad1
: CYapfT
<CYapfRoad_TypesT
<CYapfRoad1
, CRoadNodeListTrackDir
, CYapfDestinationTileRoadT
> > {};
482 struct CYapfRoad2
: CYapfT
<CYapfRoad_TypesT
<CYapfRoad2
, CRoadNodeListExitDir
, CYapfDestinationTileRoadT
> > {};
484 struct CYapfRoadAnyDepot1
: CYapfT
<CYapfRoad_TypesT
<CYapfRoadAnyDepot1
, CRoadNodeListTrackDir
, CYapfDestinationAnyDepotRoadT
> > {};
485 struct CYapfRoadAnyDepot2
: CYapfT
<CYapfRoad_TypesT
<CYapfRoadAnyDepot2
, CRoadNodeListExitDir
, CYapfDestinationAnyDepotRoadT
> > {};
488 Trackdir
YapfRoadVehicleChooseTrack(const RoadVehicle
*v
, TileIndex tile
, DiagDirection enterdir
, TrackdirBits trackdirs
, bool &path_found
)
490 /* default is YAPF type 2 */
491 typedef Trackdir (*PfnChooseRoadTrack
)(const RoadVehicle
*, TileIndex
, DiagDirection
, bool &path_found
);
492 PfnChooseRoadTrack pfnChooseRoadTrack
= &CYapfRoad2::stChooseRoadTrack
; // default: ExitDir, allow 90-deg
494 /* check if non-default YAPF type should be used */
495 if (_settings_game
.pf
.yapf
.disable_node_optimization
) {
496 pfnChooseRoadTrack
= &CYapfRoad1::stChooseRoadTrack
; // Trackdir, allow 90-deg
499 Trackdir td_ret
= pfnChooseRoadTrack(v
, tile
, enterdir
, path_found
);
500 return (td_ret
!= INVALID_TRACKDIR
) ? td_ret
: (Trackdir
)FindFirstBit2x64(trackdirs
);
503 FindDepotData
YapfRoadVehicleFindNearestDepot(const RoadVehicle
*v
, int max_distance
)
505 TileIndex tile
= v
->tile
;
506 Trackdir trackdir
= v
->GetVehicleTrackdir();
507 if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile
, TRANSPORT_ROAD
, v
->compatible_roadtypes
)) & TrackdirToTrackdirBits(trackdir
)) == 0) {
508 return FindDepotData();
511 /* default is YAPF type 2 */
512 typedef FindDepotData (*PfnFindNearestDepot
)(const RoadVehicle
*, TileIndex
, Trackdir
, int);
513 PfnFindNearestDepot pfnFindNearestDepot
= &CYapfRoadAnyDepot2::stFindNearestDepot
;
515 /* check if non-default YAPF type should be used */
516 if (_settings_game
.pf
.yapf
.disable_node_optimization
) {
517 pfnFindNearestDepot
= &CYapfRoadAnyDepot1::stFindNearestDepot
; // Trackdir, allow 90-deg
520 return pfnFindNearestDepot(v
, tile
, trackdir
, max_distance
);