gwnavruntime/dynamicnavmesh/dynamicnavmeshquerytypes.h Source File

dynamicnavmeshquerytypes.h
Go to the documentation of this file.
1 /*
2 * Copyright 2016 Autodesk, Inc. All rights reserved.
3 * Use of this software is subject to the terms of the Autodesk license agreement and any attachments or Appendices thereto provided at the time of installation or download,
4 * or which otherwise accompanies this software in either electronic or hard copy form, or which is signed by you and accepted by Autodesk.
5 */
6 
7 #pragma once
8 
19 
20 namespace Kaim
21 {
22 
23 static const KyUInt32 SWEEPLINE_CLIPPING_EXTERIOR_POLYGON_BIT = 1 << 30;
24 static const KyUInt32 SWEEPLINE_CLIPPING_HOLE_POLYGON_BIT = 1 << 29;
25 
26 class EdgePoints
27 {
28  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
29 public:
30  EdgePoints() {}
31  EdgePoints(const Vec2i& start, const Vec2i& end) : m_start(start), m_end(end) {}
32 
33  bool operator==(const EdgePoints& rhs) const { return m_start == rhs.m_start && m_end == rhs.m_end; }
34  bool operator!=(const EdgePoints& rhs) const { return !operator==(rhs); }
35 
36  // return -1 if below(right), 0 if on, 1 if above(left)
37  KyInt32 ComputePointLocation(const Vec2i& P) const { return Side(P, m_start, m_end); }
38 
39  KY_INLINE bool IsAnExtremityWithThisXValue(KyInt32 x, KyInt32& out_y) const
40  {
41  if (m_start.x == x) { out_y = m_start.y; return true; }
42  if (m_end.x == x) { out_y = m_end.y; return true; }
43  return false;
44  }
45 
46  //idx = 0 or idx = 1
47  const Vec2i& operator[](KyUInt32 idx) const { KY_ASSERT(idx <= 1); return (&m_start)[idx]; }
48 
49 public:
50  Vec2i m_start;
51  Vec2i m_end;
52 };
53 
54 class InputEdgeProperty
55 {
56  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
57 public:
58 
59  enum EdgeOrigin
60  {
61  EDGE_FROM_CELLBOUNDARY_EAST = EDGETYPE_CELLBOUNDARY_EAST /*0*/,
62  EDGE_FROM_CELLBOUNDARY_NORTH = EDGETYPE_CELLBOUNDARY_NORTH /*1*/,
63  EDGE_FROM_CELLBOUNDARY_WEST = EDGETYPE_CELLBOUNDARY_WEST /*2*/,
64  EDGE_FROM_CELLBOUNDARY_SOUTH = EDGETYPE_CELLBOUNDARY_SOUTH /*3*/,
65  EDGE_FROM_FLOORBOUNDARY = EDGETYPE_FLOORBOUNDARY /*4*/,
66  EDGE_FROM_OBSTACLE = EDGETYPE_OBSTACLE /*5*/,
67  EDGE_FROM_CONNEXBOUNDARY = EDGETYPE_CONNEXBOUNDARY /*6*/,
68  EDGE_FROM_TAGVOLUME = 7,
69  EDGE_FROM_UNKNOWN_ORIGIN
70  };
71 
72 public:
73  KY_INLINE InputEdgeProperty() { SetDefault(); }
74  KY_INLINE void SetDefault()
75  {
76  m_edgeOrigin = EDGE_FROM_UNKNOWN_ORIGIN;
77  m_ownerIndex = KyUInt32MAXVAL;
78  m_stitch1To1EdgeIdx = KyUInt32MAXVAL;
79  m_navTagIndex = KyUInt32MAXVAL;
80  m_index = KyUInt32MAXVAL;
81  m_coordinatesFlipped = false;
82  }
83 
84  bool IsConnexBoundary() const { return (m_ownerIndex & SWEEPLINE_CLIPPING_EXTERIOR_POLYGON_BIT) != 0; }
85  bool IsHole() const { return (m_ownerIndex & SWEEPLINE_CLIPPING_HOLE_POLYGON_BIT) != 0; }
86 
87  bool operator <(const InputEdgeProperty& rhs) const { return m_ownerIndex < rhs.m_ownerIndex; }
88  bool operator ==(const InputEdgeProperty& rhs) const { return m_ownerIndex == rhs.m_ownerIndex; }
89 
90 public:
91  EdgeOrigin m_edgeOrigin; // EDGE_FROM_NAVFLOOR_XXX or EDGE_FROM_TAGVOLUME
92  KyUInt32 m_ownerIndex; // index of the contour it belong to in Navfloor or TagVolumeIndex
93  KyUInt32 m_stitch1To1EdgeIdx;
94  KyUInt32 m_navTagIndex; // info regarding the navtag associated to this edge : index in the array of dynamicNavTag
95  // internal state
96  KyUInt32 m_index; // index of the edge, unique among edges for a particular polygon
97  bool m_coordinatesFlipped;
98 };
99 
100 class InputEdge
101 {
102  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
103 public:
104  InputEdge() {}
105 
106  const Vec2i& A() const { return m_extremities.m_start; }
107  const Vec2i& B() const { return m_extremities.m_end; }
108 
109 public:
110  EdgePoints m_extremities;
111  InputEdgeProperty m_property;
112 };
113 
114 // simple "std::pair"-style comparator
115 struct BasicLessHalfEdge
116 {
117  KY_INLINE bool operator()(const InputEdge& edge1, const InputEdge& edge2) const
118  {
119  if (edge1.A() != edge2.A())
120  return edge1.A() < edge2.A();
121  else
122  return edge1.B() < edge2.B();
123  }
124 };
125 
126 class InputEdgePiece
127 {
128  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
129 public:
130  InputEdgePiece() : m_parentEdge(nullptr), m_count(0), m_index(0) {}
131  InputEdgePiece(const EdgePoints& subSegment, const InputEdge& parentEdge) : m_extremities(subSegment), m_parentEdge(&parentEdge), m_count(0), m_index(0) {}
132 
133  const InputEdgeProperty& ParentProperty() const { return m_parentEdge->m_property; }
134 
135  inline bool operator==(const InputEdgePiece& other) const
136  {
137  return A() == other.A() && B() == other.B() && GetCount() == other.GetCount();
138  }
139 
140  inline bool operator<(const InputEdgePiece& other) const
141  {
142  if (A().x != other.A().x)
143  return A().x < other.A().x;
144 
145  if (A().y != other.A().y)
146  return A().y < other.A().y;
147 
148  // both edges have the same start pos
149  return CrossProduct_15bits(AB(), other.AB()) > 0; // slope_this < slope_other
150  }
151 
152  bool operator!=(const InputEdgePiece& edge) const { return !((*this) == edge); }
153  bool operator>=(const InputEdgePiece& edge) const { return !((*this) < edge); }
154 
155  //KyFloat32 EvalAtX(KyInt32 x) const { return IntegerSegment::EvalAtXforY_float(x, A(), B()); }
156 
157  bool IsVertical() const { return A().x == B().x; }
158  KyInt32 GetCount() const { return m_count; }
159  const Vec2i& GetEdgeStart() const { return m_extremities.m_start; }
160  const Vec2i& GetEdgeEnd() const { return m_extremities.m_end; }
161 
162  const Vec2i& A() const { return m_extremities.m_start; }
163  const Vec2i& B() const { return m_extremities.m_end; }
164  Vec2i AB() const { return B() - A(); }
165 
166  const Vec2i& GetOriginalStart() const
167  {
168  // we know, by construction, that m_edgePiece.m_start.x <= m_edgePiece.m_end.x
169  // so m_edgePiece.m_start.x - m_edgePiece.m_end.x >= is the same as m_edgePiece.m_start.x == m_edgePiece.m_end.x
170  const KyInt32 swappedPropertyCount = Isel(m_extremities.m_start.x - m_extremities.m_end.x, -m_count , m_count);
171  const KyInt32 extremityIdx = Isel(swappedPropertyCount, 1, 0); // 0 for start, 1 for end
172  return m_extremities[extremityIdx];
173  }
174 
175  const Vec2i& GetOriginalEnd() const
176  {
177  // we know, by construction, that m_edgePiece.m_start.x <= m_edgePiece.m_end.x
178  // so m_edgePiece.m_start.x - m_edgePiece.m_end.x >= 0 is the same as m_edgePiece.m_start.x == m_edgePiece.m_end.x
179  const KyInt32 swappedPropertyCount = Isel(m_extremities.m_start.x - m_extremities.m_end.x, -m_count , m_count);
180  const KyInt32 extremityIdx = Isel(swappedPropertyCount, 0, 1); // 0 for start , 1 for end
181  return m_extremities[extremityIdx];
182  }
183 
184 public:
185  EdgePoints m_extremities;
186  const InputEdge* m_parentEdge;
187  // on construction in edge intersector:
188  // m_count == 1 means that m_edgePiece.m_start < m_edgePiece.end || (m_edgePiece is Vertical && m_edgePiece.m_start >= m_edgePiece.end)
189  // m_count == -1 means that m_edgePiece.m_start >= m_edgePiece.end || (m_edgePiece is Vertical && m_edgePiece.m_start < m_edgePiece.end)
190  KyInt32 m_count;
191  KyUInt32 m_index;
192 };
193 
194 class SweepLineOutputEdgePiece;
195 class MergedPolygon
196 {
197  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
198 public:
199  MergedPolygon() {}
200 public:
201  KyArrayPOD<Vec2i> m_points;
202  KyArrayPOD<const SweepLineOutputEdgePiece*> m_edges;
203 };
204 
205 class MergedPolygonWithHoles
206 {
207  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
208 public:
209  MergedPolygonWithHoles() {}
210 
211 public:
212  MergedPolygon m_exterior;
213  KyArray<MergedPolygon> m_holes;
214 };
215 
216 class TriangulatorOutput
217 {
218  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
219 
220 public:
221  KyUInt32 m_navTagIndex;
222  MergedPolygon m_referencePolygon;
223  KyArrayPOD<const SweepLineOutputEdgePiece*> m_inputEdgePiece; //GetCount == edgeCount
224  KyArrayPOD<KyUInt32> m_triangleEdgeIndices; // GetCount == edgeCount; for triangle I, indices 3i, 3i+1, 3i+2 are the edge ()
225  KyArrayPOD<KyUInt32> m_startVertexOfEdges; // GetCount == edgeCount; accesing from edgeIdx
226  KyArrayPOD<KyUInt32> m_pairEdgeIndices; // GetCount == edgeCount;
227 };
228 
229 
230 class IndexedPos
231 {
232 public:
233  IndexedPos() : m_index(KyUInt32MAXVAL) {}
234  IndexedPos(const Vec2i& pos, KyUInt32 index) : m_pos(pos), m_index(index) {}
235 public:
236  Vec2i m_pos;
237  KyUInt32 m_index;
238 };
239 
240 class IndexedPosSorter
241 {
242 public:
243  KY_INLINE bool operator() (const IndexedPos& hotPoint1, const IndexedPos& hotPoint2) const
244  {
245  return hotPoint1.m_pos < hotPoint2.m_pos;
246  }
247 };
248 
249 class EdgePointsComparatorAtX
250 {
251 public:
252  inline EdgePointsComparatorAtX() : m_x(0), m_justBefore(nullptr){}
253  inline EdgePointsComparatorAtX(KyInt32 x, KyInt32* justBefore = nullptr) : m_x(x), m_justBefore(justBefore){}
254 
255  inline bool operator()(const EdgePoints& edge1, const EdgePoints& edge2) const
256  {
257  KY_ASSERT(edge1.m_start != edge2.m_start || edge1.m_start.x == m_x);
258  KY_ASSERT(edge1.m_start.x <= m_x && edge1.m_end.x >= m_x); // We are sure that edge1 intersects the vertical axis x == m_x
259  KY_ASSERT(edge2.m_start.x <= m_x && edge2.m_end.x >= m_x); // We are sure that edge2 intersects the vertical axis x == m_x
260 
261  const KyInt32 edge1Miny = FastMin(edge1.m_start.y, edge1.m_end.y);
262  const KyInt32 edge1Maxy = FastMax(edge1.m_start.y, edge1.m_end.y);
263 
264  const KyInt32 edge2Miny = FastMin(edge2.m_start.y, edge2.m_end.y);
265  const KyInt32 edge2Maxy = FastMax(edge2.m_start.y, edge2.m_end.y);
266 
267  if (edge1Maxy < edge2Miny)
268  return true; // the edge1 interval on Y-axis is strictly "below" the edge2 interval on Y-axis.
269 
270  if (edge1Miny > edge2Maxy)
271  return false; // the edge1 interval on Y-axis is strictly "above" the edge2 interval on Y-axis.
272 
273  // here we know that there is an intersection between the edge1 and edge2 interval on Y-axis
274  // To know which edge is above the other on the m_x axis, we have to compute the y-value of both edges along this axis (edge1y and edge2y)
275 
276  //check if either x of elem1 is equal to x_
277  KyInt32 yValueOfPointAtXOnEdge1 = 0;
278  KyInt32 yValueOfPointAtXOnEdge2 = 0;
279 
280  bool edge1_at_x = edge1.IsAnExtremityWithThisXValue(m_x, yValueOfPointAtXOnEdge1);
281  bool edge2_at_x = edge2.IsAnExtremityWithThisXValue(m_x, yValueOfPointAtXOnEdge2);
282 
283  if (edge1_at_x == false || edge2_at_x == false)
284  {
285  KY_LOG_ERROR_IF(edge2.m_start == edge1.m_start, ("We know that should not happen when this function is called, except if both of them are on the m_x axis"));
286 
287  //at least one of the segments doesn't have an end point at the current x
288 
289  //return value of ComputePointLocationFromEdge is
290  // -1 below the edge ; 1 above the edge ; 0 on the edge
291  KyInt32 edge1StartPosFromEdge2 = edge2.ComputePointLocation(edge1.m_start);
292  KyInt32 edge1EndPosFromEdge2 = edge2.ComputePointLocation(edge1.m_end);
293  if (edge1StartPosFromEdge2 == edge1EndPosFromEdge2)
294  {
295  // the two extremity of edge1 are on the same side of edge2. if both of them are below, edge1<edge2 at this x
296  return edge1StartPosFromEdge2 == -1;
297  }
298 
299  // the two extremity of edge1 are not on the same side of edge2.
300  // we know by construction that the two edges cannot intersect except at their extremity.
301 
302  KyInt32 edge2StartPosFromEdge1 = edge1.ComputePointLocation(edge2.m_start);
303  // we know that edge2.m_start cannot be on the edge since if such an intersection exists, it can be only on one of the extremity
304  // edge2.m_start cannot be on the end point of edge1 because if it was, both of them should be
305  // on m_x axis (we checked if (edge1_at_x == false || edge2_at_x == false) )
306  // edge2.m_start cannot be on the start point of edge1 because we are sure of that when we call
307  // this function (this has to be checked). This only happen when edge1.m_start == edge2.m_start == m_x
308  KY_LOG_ERROR_IF(edge2StartPosFromEdge1 == 0, ("Error in comparator object"));
309 
310  return edge2StartPosFromEdge1 == 1; //edge1's point is above edge1
311  }
312 
313  // Here we know that the two edges have one of their extremity on the m_x axis
314 
315  if (yValueOfPointAtXOnEdge1 != yValueOfPointAtXOnEdge2)
316  return yValueOfPointAtXOnEdge1 < yValueOfPointAtXOnEdge2;
317 
318  if (edge1 == edge2) // the two edges are equals...
319  return false;
320 
321  bool edge1SlopeLessThanEdge2Slope = CrossProduct_15bits(edge1.m_end - edge1.m_start, edge2.m_end - edge2.m_start) > 0; // slope_edge1 < slope_edge2
322  return edge1SlopeLessThanEdge2Slope == (m_justBefore == nullptr || (*m_justBefore) == 0);
323  }
324 
325 private:
326  KyInt32 m_x; //x value at which to apply comparison
327  KyInt32* m_justBefore;
328 };
329 
330 class InputEdgePieceComp
331 {
332 public:
333  inline bool operator() (const InputEdgePiece& i1, const InputEdgePiece& i2) const
334  {
335  const EdgePoints& edge1 = i1.m_extremities;
336  const EdgePoints& edge2 = i2.m_extremities;
337 
338  if (edge1.m_start != edge2.m_start)
339  return edge1.m_start < edge2.m_start;
340 
341  EdgePointsComparatorAtX lhe(edge1.m_start.x);
342  return lhe(edge1, edge2);
343  }
344 };
345 
346 } // namespace Kaim
347 
348 
349 
std::uint32_t KyUInt32
uint32_t
Definition: types.h:29
KyInt32 Isel(KyInt32 a, KyInt32 x, KyInt32 y)
If a is greater than 0, returns x.
Definition: fastmath.h:26
Indicates that another NavHalfEdge in the same NavFloor but in different Connex lies adjacent to the ...
Definition: navmeshtypes.h:57
#define KY_DEFINE_NEW_DELETE_OPERATORS(MemStat)
This macro defines new and delete operators.
Definition: memory.h:132
Indicates that this NavHalfEdge lies on the border of its NavFloor and its NavCell.
Definition: navmeshtypes.h:54
Indicates that this NavHalfEdge lies on the border of its NavFloor and its NavCell.
Definition: navmeshtypes.h:51
KyInt32 Side(const Vec2i &P, const Vec2i &A, const Vec2i &B)
P relative to AB: left=1, on=0, right=-1.
Definition: vec2i.h:150
The Autodesk Navigation namespace.
Definition: gamekitcrowddispersion.cpp:17
Indicates that this NavHalfEdge lies on the border of its NavFloor.
Definition: navmeshtypes.h:55
Indicates that this NavHalfEdge lies on an external border of the NavMesh.
Definition: navmeshtypes.h:56
std::int32_t KyInt32
int32_t
Definition: types.h:24
Indicates that this NavHalfEdge lies on the border of its NavFloor and its NavCell.
Definition: navmeshtypes.h:52
Indicates that this NavHalfEdge lies on the border of its NavFloor and its NavCell.
Definition: navmeshtypes.h:53
#define KyUInt32MAXVAL
KyUInt32 max value
Definition: types.h:68