Pyrogenesis  trunk
LongPathfinder.h
Go to the documentation of this file.
1 /* Copyright (C) 2021 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_LONGPATHFINDER
19 #define INCLUDED_LONGPATHFINDER
20 
21 #include "Pathfinding.h"
22 
23 #include "graphics/Overlay.h"
24 #include "renderer/Scene.h"
28 
29 #include <map>
30 
31 /**
32  * Represents the 2D coordinates of a tile.
33  * The i/j components are packed into a single u32, since we usually use these
34  * objects for equality comparisons and the VC2010 optimizer doesn't seem to automatically
35  * compare two u16s in a single operation.
36  * TODO: maybe VC2012 will?
37  */
38 struct TileID
39 {
40  TileID() { }
41 
42  TileID(u16 i, u16 j) : data((i << 16) | j) { }
43 
44  bool operator==(const TileID& b) const
45  {
46  return data == b.data;
47  }
48 
49  /// Returns lexicographic order over (i,j)
50  bool operator<(const TileID& b) const
51  {
52  return data < b.data;
53  }
54 
55  u16 i() const { return data >> 16; }
56  u16 j() const { return data & 0xFFFF; }
57 
58 private:
60 };
61 
62 /**
63  * Tile data for A* computation.
64  * (We store an array of one of these per terrain tile, so it ought to be optimised for size)
65  */
67 {
68 public:
69  enum {
70  STATUS_UNEXPLORED = 0,
71  STATUS_OPEN = 1,
72  STATUS_CLOSED = 2
73  };
74 
75  bool IsUnexplored() const { return GetStatus() == STATUS_UNEXPLORED; }
76  bool IsOpen() const { return GetStatus() == STATUS_OPEN; }
77  bool IsClosed() const { return GetStatus() == STATUS_CLOSED; }
78  void SetStatusOpen() { SetStatus(STATUS_OPEN); }
79  void SetStatusClosed() { SetStatus(STATUS_CLOSED); }
80 
81  // Get pi,pj coords of predecessor to this tile on best path, given i,j coords of this tile
82  inline int GetPredI(int i) const { return i + GetPredDI(); }
83  inline int GetPredJ(int j) const { return j + GetPredDJ(); }
84 
85  inline PathCost GetCost() const { return g; }
86  inline void SetCost(PathCost cost) { g = cost; }
87 
88 private:
89  PathCost g; // cost to reach this tile
90  u32 data; // 2-bit status; 15-bit PredI; 15-bit PredJ; packed for storage efficiency
91 
92 public:
93  inline u8 GetStatus() const
94  {
95  return data & 3;
96  }
97 
98  inline void SetStatus(u8 s)
99  {
100  ASSERT(s < 4);
101  data &= ~3;
102  data |= (s & 3);
103  }
104 
105  int GetPredDI() const
106  {
107  return (i32)data >> 17;
108  }
109 
110  int GetPredDJ() const
111  {
112  return ((i32)data << 15) >> 17;
113  }
114 
115  // Set the pi,pj coords of predecessor, given i,j coords of this tile
116  inline void SetPred(int pi, int pj, int i, int j)
117  {
118  int di = pi - i;
119  int dj = pj - j;
120  ASSERT(-16384 <= di && di < 16384);
121  ASSERT(-16384 <= dj && dj < 16384);
122  data &= 3;
123  data |= (((u32)di & 0x7FFF) << 17) | (((u32)dj & 0x7FFF) << 2);
124  }
125 };
126 
128 {
129  CircularRegion(entity_pos_t x, entity_pos_t z, entity_pos_t r) : x(x), z(z), r(r) {}
131 };
132 
135 
136 class JumpPointCache;
137 
139 {
140  u32 steps; // number of algorithm iterations
141 
143 
144  u16 iGoal, jGoal; // goal tile
145 
147 
149  // (there's no explicit closed list; it's encoded in PathfindTile)
150 
153 
154  PathCost hBest; // heuristic of closest discovered tile to goal
155  u16 iBest, jBest; // closest tile
156 
158 };
159 
160 class LongOverlay;
161 
163 
165 {
166 public:
167  LongPathfinder();
168  ~LongPathfinder();
169 
170  void SetDebugOverlay(bool enabled);
171 
172  void SetDebugPath(const HierarchicalPathfinder& hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal& goal, pass_class_t passClass)
173  {
174  if (!m_Debug.Overlay)
175  return;
176 
177  SAFE_DELETE(m_Debug.Grid);
178  delete m_Debug.Path;
179  m_Debug.Path = new WaypointPath();
180  ComputePath(hierPath, x0, z0, goal, passClass, *m_Debug.Path);
181  m_Debug.PassClass = passClass;
182  }
183 
184  void Reload(Grid<NavcellData>* passabilityGrid)
185  {
186  m_Grid = passabilityGrid;
187  ASSERT(passabilityGrid->m_H == passabilityGrid->m_W);
188  m_GridSize = passabilityGrid->m_W;
189 
190  m_JumpPointCache.clear();
191  }
192 
193  void Update(Grid<NavcellData>* passabilityGrid)
194  {
195  m_Grid = passabilityGrid;
196  ASSERT(passabilityGrid->m_H == passabilityGrid->m_W);
197  ASSERT(m_GridSize == passabilityGrid->m_H);
198 
199  m_JumpPointCache.clear();
200  }
201 
202  /**
203  * Compute a tile-based path from the given point to the goal, and return the set of waypoints.
204  * The waypoints correspond to the centers of horizontally/vertically adjacent tiles
205  * along the path.
206  */
207  void ComputePath(const HierarchicalPathfinder& hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal& origGoal,
208  pass_class_t passClass, WaypointPath& path) const;
209 
210  /**
211  * Compute a tile-based path from the given point to the goal, excluding the regions
212  * specified in excludedRegions (which are treated as impassable) and return the set of waypoints.
213  * The waypoints correspond to the centers of horizontally/vertically adjacent tiles
214  * along the path.
215  */
216  void ComputePath(const HierarchicalPathfinder& hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal& origGoal,
217  pass_class_t passClass, std::vector<CircularRegion> excludedRegions, WaypointPath& path);
218 
219  void GetDebugData(u32& steps, double& time, Grid<u8>& grid) const
220  {
221  GetDebugDataJPS(steps, time, grid);
222  }
223 
226 
227  // Debugging - output from last pathfind operation.
228  struct Debug
229  {
230  // Atomic - used to toggle debugging.
231  std::atomic<LongOverlay*> Overlay = nullptr;
232  // Mutable - set by ComputeJPSPath (thus possibly from different threads).
233  // Synchronized via mutex if necessary.
234  mutable PathfindTileGrid* Grid = nullptr;
235  mutable u32 Steps;
236  mutable double Time;
237  mutable PathGoal Goal;
238 
239  WaypointPath* Path = nullptr;
241  } m_Debug;
242 
243 private:
244  PathCost CalculateHeuristic(int i, int j, int iGoal, int jGoal) const;
245  void ProcessNeighbour(int pi, int pj, int i, int j, PathCost pg, PathfinderState& state) const;
246 
247  /**
248  * JPS algorithm helper functions
249  * @param detectGoal is not used if m_UseJPSCache is true
250  */
251  void AddJumpedHoriz(int i, int j, int di, PathCost g, PathfinderState& state, bool detectGoal) const;
252  int HasJumpedHoriz(int i, int j, int di, PathfinderState& state, bool detectGoal) const;
253  void AddJumpedVert(int i, int j, int dj, PathCost g, PathfinderState& state, bool detectGoal) const;
254  int HasJumpedVert(int i, int j, int dj, PathfinderState& state, bool detectGoal) const;
255  void AddJumpedDiag(int i, int j, int di, int dj, PathCost g, PathfinderState& state) const;
256 
257  /**
258  * See LongPathfinder.cpp for implementation details
259  * TODO: cleanup documentation
260  */
261  void ComputeJPSPath(const HierarchicalPathfinder& hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal& origGoal, pass_class_t passClass, WaypointPath& path) const;
262  void GetDebugDataJPS(u32& steps, double& time, Grid<u8>& grid) const;
263 
264  // Helper functions for ComputePath
265 
266  /**
267  * Given a path with an arbitrary collection of waypoints, updates the
268  * waypoints to be nicer.
269  * If @param maxDist is non-zero, path waypoints will be espaced by at most @param maxDist.
270  * In that case the distance between (x0, z0) and the first waypoint will also be made less than maxDist.
271  */
272  void ImprovePathWaypoints(WaypointPath& path, pass_class_t passClass, entity_pos_t maxDist, entity_pos_t x0, entity_pos_t z0) const;
273 
274  /**
275  * Generate a passability map, stored in the 16th bit of navcells, based on passClass,
276  * but with a set of impassable circular regions.
277  */
278  void GenerateSpecialMap(pass_class_t passClass, std::vector<CircularRegion> excludedRegions);
279 
281  // Mutable may be used here as caching does not change the external const-ness of the Long Range pathfinder.
282  // This is thread-safe as it is order independent (no change in the output of the function for a given set of params).
283  // Obviously, this means that the cache should actually be a cache and not return different results
284  // from what would happen if things hadn't been cached.
285  mutable std::map<pass_class_t, std::shared_ptr<JumpPointCache>> m_JumpPointCache;
286 };
287 
288 #endif // INCLUDED_LONGPATHFINDER
Represents the 2D coordinates of a tile.
Definition: LongPathfinder.h:38
A simple fixed-point number class.
Definition: Fixed.h:119
CircularRegion(entity_pos_t x, entity_pos_t z, entity_pos_t r)
Definition: LongPathfinder.h:129
PathGoal Goal
Definition: LongPathfinder.h:237
Similar to Grid, except optimised for sparse usage (the grid is subdivided into buckets whose content...
Definition: Grid.h:310
u16 pass_class_t
Definition: Pathfinding.h:27
bool m_UseJPSCache
Definition: LongPathfinder.h:280
double Time
Definition: LongPathfinder.h:236
Returned path.
Definition: Pathfinding.h:66
u32 data
Definition: LongPathfinder.h:90
uint16_t u16
Definition: types.h:38
static enum @32 state
u32 data
Definition: LongPathfinder.h:59
u16 j() const
Definition: LongPathfinder.h:56
bool IsUnexplored() const
Definition: LongPathfinder.h:75
u16 m_H
Definition: Grid.h:249
u16 jBest
Definition: LongPathfinder.h:155
PathCost hBest
Definition: LongPathfinder.h:154
int GetPredDJ() const
Definition: LongPathfinder.h:110
Pathfinder goal.
Definition: PathGoal.h:32
#define ASSERT(expr)
same as ENSURE in debug mode, does nothing in release mode.
Definition: debug.h:318
int GetPredI(int i) const
Definition: LongPathfinder.h:82
uint8_t u8
Definition: types.h:37
u32 steps
Definition: LongPathfinder.h:140
void SetDebugPath(const HierarchicalPathfinder &hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal &goal, pass_class_t passClass)
Definition: LongPathfinder.h:172
Jump point cache.
Definition: LongPathfinder.cpp:64
Definition: LongPathfinder.h:164
int GetPredDI() const
Definition: LongPathfinder.h:105
void Update(Grid< NavcellData > *passabilityGrid)
Definition: LongPathfinder.h:193
uint32_t u32
Definition: types.h:39
u16 i() const
Definition: LongPathfinder.h:55
bool operator<(const TileID &b) const
Returns lexicographic order over (i,j)
Definition: LongPathfinder.h:50
Definition: HierarchicalPathfinder.h:60
void SetStatusOpen()
Definition: LongPathfinder.h:78
PathCost g
Definition: LongPathfinder.h:89
Definition: path.h:79
int GetPredJ(int j) const
Definition: LongPathfinder.h:83
Definition: LongPathfinder.h:138
TileID()
Definition: LongPathfinder.h:40
void SetStatus(u8 s)
Definition: LongPathfinder.h:98
TileID(u16 i, u16 j)
Definition: LongPathfinder.h:42
#define SAFE_DELETE(p)
delete memory ensuing from new and set the pointer to zero (thus making double-frees safe / a no-op) ...
Definition: code_generation.h:111
pass_class_t passClass
Definition: LongPathfinder.h:146
Tile data for A* computation.
Definition: LongPathfinder.h:66
bool IsClosed() const
Definition: LongPathfinder.h:77
void Reload(Grid< NavcellData > *passabilityGrid)
Definition: LongPathfinder.h:184
Terrain overlay for pathfinder debugging.
Definition: LongPathfinder.cpp:1057
int32_t i32
Definition: types.h:34
void GetDebugData(u32 &steps, double &time, Grid< u8 > &grid) const
Definition: LongPathfinder.h:219
u16 m_GridSize
Definition: LongPathfinder.h:225
SparseGrid< PathfindTile > PathfindTileGrid
Definition: LongPathfinder.h:134
u32 Steps
Definition: LongPathfinder.h:235
PathfindTileGrid * tiles
Definition: LongPathfinder.h:151
Definition: LongPathfinder.h:228
PathGoal goal
Definition: LongPathfinder.h:142
void SetStatusClosed()
Definition: LongPathfinder.h:79
Grid< NavcellData > * m_Grid
Definition: LongPathfinder.h:224
const JumpPointCache * jpc
Definition: LongPathfinder.h:157
PathCost GetCost() const
Definition: LongPathfinder.h:85
Definition: LongPathfinder.h:127
PriorityQueue open
Definition: LongPathfinder.h:148
u8 GetStatus() const
Definition: LongPathfinder.h:93
pass_class_t PassClass
Definition: LongPathfinder.h:240
u16 m_W
Definition: Grid.h:249
void SetCost(PathCost cost)
Definition: LongPathfinder.h:86
Represents the cost of a path consisting of horizontal/vertical and diagonal movements over a uniform...
Definition: Pathfinding.h:76
Grid< NavcellData > * terrain
Definition: LongPathfinder.h:152
bool operator==(const TileID &b) const
Definition: LongPathfinder.h:44
u16 jGoal
Definition: LongPathfinder.h:144
void SetPred(int pi, int pj, int i, int j)
Definition: LongPathfinder.h:116
std::map< pass_class_t, std::shared_ptr< JumpPointCache > > m_JumpPointCache
Definition: LongPathfinder.h:285
bool IsOpen() const
Definition: LongPathfinder.h:76
entity_pos_t z
Definition: LongPathfinder.h:130
PriorityQueueHeap< TileID, PathCost, PathCost > PriorityQueue
Definition: LongPathfinder.h:133