TDME2  1.9.200
FlowMap.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <map>
4 #include <string>
5 #include <tuple>
6 #include <unordered_map>
7 #include <variant>
8 #include <vector>
9 
10 #include <tdme/tdme.h>
11 #include <tdme/math/Math.h>
12 #include <tdme/math/Vector3.h>
13 #include <tdme/utilities/Console.h>
16 
17 using std::get;
18 using std::string;
19 using std::to_string;
20 using std::tuple;
21 using std::unordered_map;
22 using std::vector;
23 
24 using tdme::math::Math;
29 
30 /**
31  * Flow map
32  * @author Andreas Drewke
33  */
34 class tdme::utilities::FlowMap final: public Reference {
35 friend class PathFinding;
36 private:
38  std::size_t operator()(const tuple<int, int>& k) const {
39  std::hash<uint64_t> hashVal;
40  return hashVal(get<0>(k) ^ get<1>(k));
41  }
42  };
43 
44  bool complete;
45  float stepSize;
46  unordered_map<tuple<int, int>, FlowMapCell*, FlowMapCellId_Hash> cells;
47  vector<Vector3> endPositions;
48  vector<Vector3> path;
49 
50  /**
51  * Private destructor
52  */
53  inline ~FlowMap() {
54  for (const auto& [cellId, cell]: cells) delete cell;
55  }
56 
57  /**
58  * Set flow map complete flag
59  * @param complete complete
60  */
61  inline void setComplete(bool complete) {
62  this->complete = complete;
63  }
64 
65  /**
66  * Adds a cell to flow map
67  * @param id id
68  * @param position position
69  * @param walkable walkable
70  * @param direction direction
71  * @param pathIdx path index
72  */
73  inline void addCell(const tuple<int, int>& id, const Vector3& position, bool walkable, const Vector3& direction, int pathIdx) {
74  cells[id] = new FlowMapCell(position, walkable, direction, pathIdx);
75  }
76 
77  /**
78  * Checks if a cell exists in flow map
79  * @param id id
80  */
81  inline bool hasCell(const tuple<int, int>& id) const {
82  auto cellIt = cells.find(id);
83  return cellIt != cells.end();
84  }
85 
86 public:
87  /**
88  * Return string representation of given x,z for flow map cell id
89  * @param x x
90  * @param z z
91  * @return string representation
92  */
93  inline const tuple<int, int> toId(float x, float z) const {
94  return toId(x, z, stepSize);
95  }
96 
97  /**
98  * Return string representation of given x,z for flow map cell id
99  * @param x x
100  * @param z z
101  * @param stepSize step size
102  * @return string representation
103  */
104  inline static const tuple<int, int> toId(float x, float z, float stepSize) {
105  return tuple<int, int> { static_cast<int>(Math::ceil(x / stepSize)), static_cast<int>(Math::ceil(z / stepSize)) };
106  }
107 
108  /**
109  * Align position component
110  * @param value value which is usually a position vector 3 position component
111  * @param stepSize step size
112  */
113  inline static float alignPositionComponent(float value, float stepSize) {
114  return Math::floor(value / stepSize) * stepSize;
115  }
116 
117  /**
118  * Align position component
119  * @param value value which is usually a position vector 3 position component
120  */
121  inline float alignPositionComponent(float value) const {
122  return alignPositionComponent(value, stepSize);
123  }
124 
125  /**
126  * Returns integer position component
127  * @param value value
128  * @return integer position component
129  */
130  inline int getIntegerPositionComponent(float value) const {
131  return static_cast<int>(alignPositionComponent(value, stepSize) / stepSize);
132  }
133 
134  /**
135  * Returns integer position component
136  * @param value value
137  * @param stepSize step size
138  * @return integer position component
139  */
140  inline static int getIntegerPositionComponent(float value, float stepSize) {
141  return static_cast<int>(alignPositionComponent(value, stepSize) / stepSize);
142  }
143 
144  /**
145  * Return string representation of given x,z integer flow map position representation for flow map cell id
146  * @param x x
147  * @param z z
148  * @return string representation
149  */
150  inline static const tuple<int, int> toIdInt(int x, int z) {
151  return tuple<int, int> { x, z };
152  }
153 
154  // forbid class copy
156 
157  /**
158  * Constructor
159  * @param path path
160  * @param endPositions end positions
161  * @param stepSize step size
162  */
163  inline FlowMap(const vector<Vector3>& path, const vector<Vector3>& endPositions, float stepSize, bool complete = true): path(path), endPositions(endPositions), stepSize(stepSize), complete(complete) {
164  }
165 
166  /**
167  * @return if flow map is complete
168  */
169  inline bool isComplete() const {
170  return complete;
171  }
172 
173  /**
174  * @return step size
175  */
176  inline float getStepSize() const {
177  return stepSize;
178  }
179 
180  /**
181  * Returns end positions
182  * @return end positions
183  */
184  inline const vector<Vector3>& getEndPositions() const {
185  return endPositions;
186  }
187 
188  /**
189  * Returns path flow map is generated on
190  * @return path
191  */
192  inline const vector<Vector3>& getPath() const {
193  return path;
194  }
195 
196  /**
197  * Get cell by id
198  * @param id id
199  * @return cell
200  */
201  inline const FlowMapCell* getCell(const tuple<int, int>& id) const {
202  auto cellIt = cells.find(id);
203  if (cellIt == cells.end()) return nullptr;
204  return cellIt->second;
205  }
206 
207  /**
208  * Get cell by id
209  * @param id id
210  * @return cell
211  */
212  inline FlowMapCell* getCell(const tuple<int, int>& id) {
213  auto cellIt = cells.find(id);
214  if (cellIt == cells.end()) return nullptr;
215  return cellIt->second;
216  }
217 
218  /**
219  * Get cell by position
220  * @param x x
221  * @param z z
222  * @return cell
223  */
224  inline const FlowMapCell* getCell(float x, float z) const {
225  auto id = toId(
228  );
229  auto cellIt = cells.find(id);
230  if (cellIt == cells.end()) return nullptr;
231  return cellIt->second;
232  }
233 
234  /**
235  * Get cell by position
236  * @param x x
237  * @param z z
238  * @return cell
239  */
240  inline FlowMapCell* getCell(float x, float z) {
241  auto cellId = toId(
244  );
245  auto cellIt = cells.find(cellId);
246  if (cellIt == cells.end()) return nullptr;
247  return cellIt->second;
248  }
249 
250  /**
251  * Compute direction also taking neighbour cells into account
252  * @param x x
253  * @param y y
254  * @param direction direction
255  */
256  inline const Vector3 computeDirection(float x, float z) const {
257  // https://howtorts.github.io/2014/01/04/basic-flow-fields.html
258  auto cellCount = 0;
259  auto xInt = getIntegerPositionComponent(x);
260  auto zInt = getIntegerPositionComponent(z);
261  auto f00 = getCell(toIdInt(xInt, zInt));
262  if (f00 == nullptr) return Vector3();
263  auto f01 = getCell(toIdInt(xInt, zInt + 1));
264  auto f10 = getCell(toIdInt(xInt + 1, zInt));
265  auto f11 = getCell(toIdInt(xInt + 1, zInt + 1));
266  auto xWeight = x - xInt * stepSize;
267  auto top = f10 != nullptr?f00->getDirection().clone().scale(1.0f - xWeight).add(f10->getDirection().clone().scale(xWeight)):f00->getDirection();
268  auto bottom = f01 != nullptr && f11 != nullptr?f01->getDirection().clone().scale(1.0f - xWeight).add(f11->getDirection().clone().scale(xWeight)):top;
269  auto yWeight = z - zInt * stepSize;
270  auto direction = top.clone().scale(1.0f - yWeight).add(bottom.clone().scale(yWeight)).normalize();
271  return direction;
272  }
273 
274  /**
275  * Cell map getter
276  * @returns cell map
277  */
278  inline const unordered_map<tuple<int, int>, FlowMapCell*, FlowMapCellId_Hash>& getCellMap() const {
279  return cells;
280  }
281 
282  /**
283  * Remove cell by id
284  * @param id id
285  */
286  inline void removeCell(const tuple<int, int>& id) {
287  auto cellIt = cells.find(id);
288  if (cellIt == cells.end()) return;
289  cells.erase(cellIt);
290  }
291 
292  /**
293  * Merge given flow map into this flow map, please note that given flow map step size needs to match this flow maps step size
294  * This only applies to a series of flow maps created sequentially and in correct order along a path
295  * @param flowMap flow map
296  */
297  inline void merge(const FlowMap* flowMap) {
298  // complete
299  complete = flowMap->complete;
300  // add path
301  auto pathSize = path.size();
302  for (const auto& pathNode: flowMap->path) {
303  path.push_back(pathNode);
304  }
305  // add cells
306  // TODO: check again cell misssing neighbour cells
307  for (const auto& [cellId, cell]: flowMap->cells) {
308  auto clonedCell = cell->clone();
309  clonedCell->pathNodeIdx+= pathSize;
310  cells[cellId] = clonedCell;
311  }
312  // check if we have missing neighbour cells
313  for (const auto& [cellId, flowMapCell]: flowMap->cells) {
314  auto cell = getCell(cellId);
315  cell->setMissingNeighborCell(false);
316  auto cellX = getIntegerPositionComponent(cell->position.getX());
317  auto cellZ = getIntegerPositionComponent(cell->position.getZ());
318  auto hadMissingNeighborCell = false;
319  for (auto nZ = -1; nZ < 2 && hadMissingNeighborCell == false; nZ++) {
320  for (auto nX = -1; nX < 2 && hadMissingNeighborCell == false; nX++) {
321  if (nZ == 0 && nX == 0) continue;
322  auto neighbourCellId = FlowMap::toIdInt(
323  cellX + nX,
324  cellZ + nZ
325  );
326  auto neighbourCell = getCell(neighbourCellId);
327  if (neighbourCell == nullptr) {
328  cell->setMissingNeighborCell(true);
329  hadMissingNeighborCell = true;
330  break;
331  }
332  }
333  }
334  }
335  // end positions
336  endPositions = flowMap->endPositions;
337  }
338 
339  /**
340  * Find nearest cell, which can be used if outside of flow map to find back in
341  * @param x x
342  * @param z z
343  * @param steps steps
344  */
345  inline FlowMapCell* findNearestCell(float x, float z, int steps = 8) {
346  Vector3 position = Vector3(x, 0.0f, z);
347  auto cellX = getIntegerPositionComponent(x);
348  auto cellZ = getIntegerPositionComponent(z);
349  auto halfSteps = steps / 2;
350  FlowMapCell* cellBestFit = nullptr;
351  float cellBestFitDistanceSquared = Float::MAX_VALUE;
352  for (auto nZ = -halfSteps; nZ < halfSteps; nZ++) {
353  for (auto nX = -halfSteps; nX < halfSteps; nX++) {
354  auto cellId = FlowMap::toIdInt(
355  cellX + nX,
356  cellZ + nZ
357  );
358  auto cellCandidate = getCell(cellId);
359  if (cellCandidate == nullptr) continue;
360  auto cellCandidateDistanceSquared = cellCandidate->getPosition().clone().sub(position).computeLengthSquared();
361  if (cellBestFit == nullptr || cellCandidateDistanceSquared < cellBestFitDistanceSquared) {
362  cellBestFit = cellCandidate;
363  cellBestFitDistanceSquared = cellCandidateDistanceSquared;
364  }
365  }
366  }
367  return cellBestFit;
368  }
369 
370 };
Standard math functions.
Definition: Math.h:19
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
Console class.
Definition: Console.h:29
static constexpr float MAX_VALUE
Definition: Float.h:29
FlowMapCell * getCell(const tuple< int, int > &id)
Get cell by id.
Definition: FlowMap.h:212
const unordered_map< tuple< int, int >, FlowMapCell *, FlowMapCellId_Hash > & getCellMap() const
Cell map getter.
Definition: FlowMap.h:278
const tuple< int, int > toId(float x, float z) const
Return string representation of given x,z for flow map cell id.
Definition: FlowMap.h:93
const vector< Vector3 > & getPath() const
Returns path flow map is generated on.
Definition: FlowMap.h:192
const Vector3 computeDirection(float x, float z) const
Compute direction also taking neighbour cells into account.
Definition: FlowMap.h:256
bool isComplete() const
Definition: FlowMap.h:169
int getIntegerPositionComponent(float value) const
Returns integer position component.
Definition: FlowMap.h:130
FlowMapCell * getCell(float x, float z)
Get cell by position.
Definition: FlowMap.h:240
void addCell(const tuple< int, int > &id, const Vector3 &position, bool walkable, const Vector3 &direction, int pathIdx)
Adds a cell to flow map.
Definition: FlowMap.h:73
unordered_map< tuple< int, int >, FlowMapCell *, FlowMapCellId_Hash > cells
Definition: FlowMap.h:46
const FlowMapCell * getCell(float x, float z) const
Get cell by position.
Definition: FlowMap.h:224
void setComplete(bool complete)
Set flow map complete flag.
Definition: FlowMap.h:61
const FlowMapCell * getCell(const tuple< int, int > &id) const
Get cell by id.
Definition: FlowMap.h:201
FlowMapCell * findNearestCell(float x, float z, int steps=8)
Find nearest cell, which can be used if outside of flow map to find back in.
Definition: FlowMap.h:345
vector< Vector3 > endPositions
Definition: FlowMap.h:47
static int getIntegerPositionComponent(float value, float stepSize)
Returns integer position component.
Definition: FlowMap.h:140
const vector< Vector3 > & getEndPositions() const
Returns end positions.
Definition: FlowMap.h:184
void merge(const FlowMap *flowMap)
Merge given flow map into this flow map, please note that given flow map step size needs to match thi...
Definition: FlowMap.h:297
float getStepSize() const
Definition: FlowMap.h:176
bool hasCell(const tuple< int, int > &id) const
Checks if a cell exists in flow map.
Definition: FlowMap.h:81
vector< Vector3 > path
Definition: FlowMap.h:48
static const tuple< int, int > toId(float x, float z, float stepSize)
Return string representation of given x,z for flow map cell id.
Definition: FlowMap.h:104
float alignPositionComponent(float value) const
Align position component.
Definition: FlowMap.h:121
~FlowMap()
Private destructor.
Definition: FlowMap.h:53
void removeCell(const tuple< int, int > &id)
Remove cell by id.
Definition: FlowMap.h:286
static const tuple< int, int > toIdInt(int x, int z)
Return string representation of given x,z integer flow map position representation for flow map cell ...
Definition: FlowMap.h:150
static float alignPositionComponent(float value, float stepSize)
Align position component.
Definition: FlowMap.h:113
Path finding class.
Definition: PathFinding.h:51
Reference counter implementation to be used with inheritance.
Definition: Reference.h:13
std::size_t operator()(const tuple< int, int > &k) const
Definition: FlowMap.h:38
#define FORBID_CLASS_COPY(CLASS)
Definition: tdme.h:6