Pyrogenesis HEAD
Pyrogenesis, a RTS Engine
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 */
38struct 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
58private:
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{
68public:
69 enum {
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; }
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
88private:
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
92public:
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{
131};
132
135
136class 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
160class LongOverlay;
161
163
165{
166public:
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
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;
242
243private:
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
static enum @29 state
PriorityQueueHeap< TileID, PathCost, PathCost > PriorityQueue
Definition: LongPathfinder.h:133
SparseGrid< PathfindTile > PathfindTileGrid
Definition: LongPathfinder.h:134
u16 pass_class_t
Definition: Pathfinding.h:29
A simple fixed-point number class.
Definition: Fixed.h:120
u16 m_H
Definition: Grid.h:249
u16 m_W
Definition: Grid.h:249
Definition: HierarchicalPathfinder.h:61
Jump point cache.
Definition: LongPathfinder.cpp:65
Terrain overlay for pathfinder debugging.
Definition: LongPathfinder.cpp:1058
Definition: LongPathfinder.h:165
int HasJumpedVert(int i, int j, int dj, PathfinderState &state, bool detectGoal) const
Definition: LongPathfinder.cpp:624
void GetDebugDataJPS(u32 &steps, double &time, Grid< u8 > &grid) const
Definition: LongPathfinder.cpp:974
LongPathfinder()
Definition: LongPathfinder.cpp:381
Grid< NavcellData > * m_Grid
Definition: LongPathfinder.h:224
void SetDebugOverlay(bool enabled)
Definition: LongPathfinder.cpp:1143
void ComputePath(const HierarchicalPathfinder &hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal &origGoal, pass_class_t passClass, WaypointPath &path) const
Compute a tile-based path from the given point to the goal, and return the set of waypoints.
Definition: LongPathfinder.cpp:1000
~LongPathfinder()
Definition: LongPathfinder.cpp:1151
int HasJumpedHoriz(int i, int j, int di, PathfinderState &state, bool detectGoal) const
Definition: LongPathfinder.cpp:546
bool m_UseJPSCache
Definition: LongPathfinder.h:280
void AddJumpedVert(int i, int j, int dj, PathCost g, PathfinderState &state, bool detectGoal) const
Definition: LongPathfinder.cpp:582
void AddJumpedDiag(int i, int j, int di, int dj, PathCost g, PathfinderState &state) const
Definition: LongPathfinder.cpp:664
void Update(Grid< NavcellData > *passabilityGrid)
Definition: LongPathfinder.h:193
u16 m_GridSize
Definition: LongPathfinder.h:225
void ComputeJPSPath(const HierarchicalPathfinder &hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal &origGoal, pass_class_t passClass, WaypointPath &path) const
See LongPathfinder.cpp for implementation details TODO: cleanup documentation.
Definition: LongPathfinder.cpp:715
PathCost CalculateHeuristic(int i, int j, int iGoal, int jGoal) const
Definition: LongPathfinder.cpp:391
void GenerateSpecialMap(pass_class_t passClass, std::vector< CircularRegion > excludedRegions)
Generate a passability map, stored in the 16th bit of navcells, based on passClass,...
Definition: LongPathfinder.cpp:1026
void ProcessNeighbour(int pi, int pj, int i, int j, PathCost pg, PathfinderState &state) const
Definition: LongPathfinder.cpp:400
std::map< pass_class_t, std::shared_ptr< JumpPointCache > > m_JumpPointCache
Definition: LongPathfinder.h:285
void GetDebugData(u32 &steps, double &time, Grid< u8 > &grid) const
Definition: LongPathfinder.h:219
void ImprovePathWaypoints(WaypointPath &path, pass_class_t passClass, entity_pos_t maxDist, entity_pos_t x0, entity_pos_t z0) const
Given a path with an arbitrary collection of waypoints, updates the waypoints to be nicer.
Definition: LongPathfinder.cpp:922
void AddJumpedHoriz(int i, int j, int di, PathCost g, PathfinderState &state, bool detectGoal) const
JPS algorithm helper functions.
Definition: LongPathfinder.cpp:504
void SetDebugPath(const HierarchicalPathfinder &hierPath, entity_pos_t x0, entity_pos_t z0, const PathGoal &goal, pass_class_t passClass)
Definition: LongPathfinder.h:172
void Reload(Grid< NavcellData > *passabilityGrid)
Definition: LongPathfinder.h:184
struct LongPathfinder::Debug m_Debug
Pathfinder goal.
Definition: PathGoal.h:33
Definition: path.h:80
Similar to Grid, except optimised for sparse usage (the grid is subdivided into buckets whose content...
Definition: Grid.h:311
#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
#define ASSERT(expr)
same as ENSURE in debug mode, does nothing in release mode.
Definition: debug.h:305
Definition: LongPathfinder.h:128
CircularRegion(entity_pos_t x, entity_pos_t z, entity_pos_t r)
Definition: LongPathfinder.h:129
entity_pos_t z
Definition: LongPathfinder.h:130
entity_pos_t x
Definition: LongPathfinder.h:130
entity_pos_t r
Definition: LongPathfinder.h:130
Definition: LongPathfinder.h:229
double Time
Definition: LongPathfinder.h:236
WaypointPath * Path
Definition: LongPathfinder.h:239
PathGoal Goal
Definition: LongPathfinder.h:237
u32 Steps
Definition: LongPathfinder.h:235
PathfindTileGrid * Grid
Definition: LongPathfinder.h:234
std::atomic< LongOverlay * > Overlay
Definition: LongPathfinder.h:231
pass_class_t PassClass
Definition: LongPathfinder.h:240
Represents the cost of a path consisting of horizontal/vertical and diagonal movements over a uniform...
Definition: Pathfinding.h:77
Tile data for A* computation.
Definition: LongPathfinder.h:67
u8 GetStatus() const
Definition: LongPathfinder.h:93
@ STATUS_OPEN
Definition: LongPathfinder.h:71
@ STATUS_CLOSED
Definition: LongPathfinder.h:72
@ STATUS_UNEXPLORED
Definition: LongPathfinder.h:70
bool IsOpen() const
Definition: LongPathfinder.h:76
int GetPredI(int i) const
Definition: LongPathfinder.h:82
int GetPredJ(int j) const
Definition: LongPathfinder.h:83
PathCost g
Definition: LongPathfinder.h:89
u32 data
Definition: LongPathfinder.h:90
void SetStatus(u8 s)
Definition: LongPathfinder.h:98
int GetPredDI() const
Definition: LongPathfinder.h:105
void SetCost(PathCost cost)
Definition: LongPathfinder.h:86
void SetPred(int pi, int pj, int i, int j)
Definition: LongPathfinder.h:116
bool IsClosed() const
Definition: LongPathfinder.h:77
int GetPredDJ() const
Definition: LongPathfinder.h:110
void SetStatusClosed()
Definition: LongPathfinder.h:79
void SetStatusOpen()
Definition: LongPathfinder.h:78
PathCost GetCost() const
Definition: LongPathfinder.h:85
bool IsUnexplored() const
Definition: LongPathfinder.h:75
Definition: LongPathfinder.h:139
PathCost hBest
Definition: LongPathfinder.h:154
u16 iGoal
Definition: LongPathfinder.h:144
const JumpPointCache * jpc
Definition: LongPathfinder.h:157
u16 iBest
Definition: LongPathfinder.h:155
Grid< NavcellData > * terrain
Definition: LongPathfinder.h:152
PriorityQueue open
Definition: LongPathfinder.h:148
u32 steps
Definition: LongPathfinder.h:140
PathfindTileGrid * tiles
Definition: LongPathfinder.h:151
pass_class_t passClass
Definition: LongPathfinder.h:146
u16 jGoal
Definition: LongPathfinder.h:144
u16 jBest
Definition: LongPathfinder.h:155
PathGoal goal
Definition: LongPathfinder.h:142
Represents the 2D coordinates of a tile.
Definition: LongPathfinder.h:39
TileID()
Definition: LongPathfinder.h:40
u16 i() const
Definition: LongPathfinder.h:55
TileID(u16 i, u16 j)
Definition: LongPathfinder.h:42
u16 j() const
Definition: LongPathfinder.h:56
bool operator<(const TileID &b) const
Returns lexicographic order over (i,j)
Definition: LongPathfinder.h:50
bool operator==(const TileID &b) const
Definition: LongPathfinder.h:44
u32 data
Definition: LongPathfinder.h:59
Returned path.
Definition: Pathfinding.h:67
int32_t i32
Definition: types.h:34
uint8_t u8
Definition: types.h:37
uint16_t u16
Definition: types.h:38
uint32_t u32
Definition: types.h:39