gwnavruntime/navmesh/dynamictriangulation_int.h Source File

dynamictriangulation_int.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 
12 
13 namespace Kaim
14 {
15 
16 class DynTriHalfEdge;
17 class IndexedTriangleSoup2i;
18 class Triangle3i;
19 
20 typedef CoordPos AlignedCoordPos;
21 
22 enum DynamicVertexIntUserDataContent
23 {
24  DTI_UNKNOWN_VERTEX_USERDATA,
25  DTI_TRIANGLE_SOUP_VERTEX_TAG_DATA
26 };
27 // ----------------------------
28 // ----- DynamicVertex_Int --------
29 // ----------------------------
30 class DynTriVertex
31 {
32  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
33 public:
34  DynTriVertex() : m_idx(KyUInt32MAXVAL), m_coordPos(KyInt32MAXVAL, KyInt32MAXVAL), m_altitude(KyFloat32MAXVAL), m_userData(nullptr)
35  {
36  m_outGoingEdgeIdx.Reserve(12);
37  }
38 
39 
40  KY_INLINE void InsertInOutGoingEdges(KyUInt32 dynamicHalfEdgeIdx)
41  {
42  KY_ASSERT(m_outGoingEdgeIdx.DoesContain(dynamicHalfEdgeIdx) == false);
43  m_outGoingEdgeIdx.PushBack(dynamicHalfEdgeIdx);
44  KY_ASSERT(m_outGoingEdgeIdx.DoesContain(dynamicHalfEdgeIdx));
45  }
46 
47  KY_INLINE void RemoveFromOutGoingEdges(KyUInt32 dynamicHalfEdgeIdx)
48  {
49  KY_ASSERT(m_outGoingEdgeIdx.DoesContain(dynamicHalfEdgeIdx));
50  m_outGoingEdgeIdx.RemoveFirstOccurrence(dynamicHalfEdgeIdx);
51  KY_ASSERT(m_outGoingEdgeIdx.DoesContain(dynamicHalfEdgeIdx) == false);
52  }
53 
54 public:
55  KyUInt32 m_idx;
56  AlignedCoordPos m_coordPos;
57  KyFloat32 m_altitude;
58  Collection<KyUInt32> m_outGoingEdgeIdx;
59 
60  void* m_userData;
61 };
62 
63 // ------------------------------
64 // ----- DynamicTriangle_Int --------
65 // ------------------------------
66 class DynTriTriangle
67 {
68  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
69 public:
70  DynTriTriangle() : m_idx(KyUInt32MAXVAL), m_edgeIdx(KyUInt32MAXVAL), m_userData(nullptr) {}
71 
72  void GetLocalTriangle3i(KyUInt32 pixelSize, KyFloat32 rasterPrecision, Triangle3i& triangle3i) const;
73 public:
74  KyUInt32 m_idx;
75  KyUInt32 m_edgeIdx; // one edge around the face
76 
77  void* m_userData;
78 };
79 
80 // ---------------------------
81 // ----- DynamicHalfEdge_Int -----
82 // ---------------------------
83 class DynTriHalfEdge
84 {
85  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
86 public:
87  DynTriHalfEdge() : m_idx(KyUInt32MAXVAL), m_startVertexIdx(KyUInt32MAXVAL), m_triangleIdx(KyUInt32MAXVAL),
88  m_nextEdgeIdx(KyUInt32MAXVAL), m_pairEdgeIdx(KyUInt32MAXVAL), m_status(HalfEdgeStatus_NotOpen), m_userData(nullptr) {}
89 
90  enum HalfEdgeStatus
91  {
92  HalfEdgeStatus_Open = 0,
93  HalfEdgeStatus_NotOpen = 1,
94  HalfEdgeStatus_Locked = 2,
95 
96  HalfEdgeStatus_FORCE32 = 0xFFFFFFFF
97  };
98 
99  KY_INLINE bool IsABorder() const { return m_pairEdgeIdx == KyUInt32MAXVAL; }
100  KY_INLINE bool IsLocked() const { return m_status == HalfEdgeStatus_Locked; }
101 
102 public:
103  KyUInt32 m_idx;
104  KyUInt32 m_startVertexIdx;
105  KyUInt32 m_triangleIdx;
106  KyUInt32 m_nextEdgeIdx;
107  KyUInt32 m_pairEdgeIdx;
108  HalfEdgeStatus m_status;
109  void* m_userData;
110 };
111 
112 /* Instance of this class are returned by DynamicTriangulation_Int::InsertANewVertexInMeshAndUpdateTriangulation
113  if m_result == RESULT_NEW_VERTEX_CREATED => m_vertex refers to the new created vertex
114  if m_result == RESULT_CLOSE_TO_EXISTING_VERTEX => m_vertex refers to the vertex we are close to
115  if m_result == RESULT_CLOSE_TO_BORDER_EDGE => m_ halfEdge refers to the border HalfEdge we are close to
116  if m_result == RESULT_NOT_IN_TRIANGLE => no triangle contains input position. No usefull datan, m_vertex and m_halfEdge remains to nullptr
117  if m_result == RESULT_REFUSED => position refused becaus of floating precision issue (we don't want to create reverse face). No usefull data, m_vertex and m_halfEdge remains to nullptr
118 */
119 
120 class DynTriangulationInsertionResult
121 {
122  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
123 
124 public:
125 
126  DynTriangulationInsertionResult() : m_result(RESULT_FORCE32), m_vertexIdx(KyUInt32MAXVAL), m_halfEdgeIdx(KyUInt32MAXVAL) {}
127 
128  enum Result
129  {
130  RESULT_NEW_VERTEX_CREATED = 0,
131  RESULT_EXISTING_VERTEX = 1,
132  RESULT_ON_A_BORDER_EDGE = 2,
133  RESULT_NOT_IN_TRIANGLE = 3,
134  RESULT_REFUSED = 4,
135  RESULT_FORCE32 = 0xFFFFFFFF
136  };
137 
138  Result m_result;
139  KyUInt32 m_vertexIdx;
140  KyUInt32 m_halfEdgeIdx;
141 };
142 
143 
144 // --------------------------------
145 // ----- DynamicTriangulation_Int -----
146 // --------------------------------
147 class DynamicTriangulation
148 {
149  KY_DEFINE_NEW_DELETE_OPERATORS(Stat_Default_Mem)
150  KY_CLASS_WITHOUT_COPY(DynamicTriangulation)
151 public:
152  KY_INLINE DynamicTriangulation(MemoryHeap* heap) :
153  m_triangles(heap),
154  m_vertices(heap),
155  m_edges(heap),
156  m_edgeIdxToProcess(heap),
157  m_userDataContent(DTI_UNKNOWN_VERTEX_USERDATA)
158  {}
159 
160  ~DynamicTriangulation() { Clear(); }
161 
162  void Clear();
163 
164 
165  // mesh Creation
166  KyUInt32 AddVertex(const AlignedCoordPos& coordPos, KyFloat32 altitude = KyFloat32MAXVAL);
167  KyUInt32 AddTriangle(KyUInt32 v0Idx, KyUInt32 v1Idx, KyUInt32 v2Idx);
168 
169  // Use this after calling Resize with good value on m_vertices and m_edges
170  void AddVertex(KyUInt32 vertexIdx, const AlignedCoordPos& coordPos, KyFloat32 altitude = KyFloat32MAXVAL);
171  //KyUInt32 AddTriangle(KyUInt32 triangleIdx, KyUInt32 v0Idx, KyUInt32 v1Idx, KyUInt32 v2Idx);
172 
173 
174  KyResult BuildFromIndexedTriangleSoup(const IndexedTriangleSoup2i* triangulation);
175  KyResult BuildIndexedTriangleSoup(IndexedTriangleSoup2i* triangulation);
176 
177  // Process the triangulation to get a "Delaunay Like" triangulation
178  // This function should be called before inserting new vertices and Updating Triangulation
179  void GetABetterTriangulation();
180 
181  /*-------------- Functions used for better altitude approximation -------------- */
182 
183  // Add a new vertex in the Mesh and triangulate around him
184  // return KyUInt32MAXVAL if
185  // - the position isn't in any triangle
186  // - the position is too close to one of the three vertices of the triangle (according to m_squareMinDistFromExistingPoint, distances are in 2D)
187  // - the position is too close to a border edge (according to m_squareMinDistFromBorder, distances are in 2D)
188  // If the position is close to an edge (according to m_maxSquareDistToConsiderAPointOnAnEdge, distances are in 2D), the vertex is snapped on the edge
189  KyUInt32 InsertANewVertexInMesh(const CoordPos& position, DynTriangulationInsertionResult& result);
190 
191  // perform an InsertANewVertexInMesh and update the triangulation to get a "Delauney Like" triangulation
192  // if impactedTrianglesIndices is not null, fill it with the indices of modified triangles
193  DynTriangulationInsertionResult InsertANewVertexInMeshAndUpdateTriangulation(
194  const CoordPos& position, KyArrayDH_POD<KyUInt32>* impactedTrianglesIndices = nullptr);
195 
196  KY_INLINE void LockEdge(KyUInt32 halfEdgeIdx)
197  {
198  DynTriHalfEdge& edge = m_edges[halfEdgeIdx];
199 
200  if (edge.m_status != DynTriHalfEdge::HalfEdgeStatus_Locked)
201  {
202  KY_DEBUG_ASSERTN(edge.m_status == DynTriHalfEdge::HalfEdgeStatus_NotOpen ,("Don't change edge status during process"));
203  edge.m_status = DynTriHalfEdge::HalfEdgeStatus_Locked;
204  }
205 
206  if (edge.IsABorder() == false && m_edges[edge.m_pairEdgeIdx].m_status != DynTriHalfEdge::HalfEdgeStatus_Locked)
207  {
208  KY_DEBUG_ASSERTN(m_edges[edge.m_pairEdgeIdx].m_status == DynTriHalfEdge::HalfEdgeStatus_NotOpen ,("Don't change edge status during process"));
209  m_edges[edge.m_pairEdgeIdx].m_status = DynTriHalfEdge::HalfEdgeStatus_Locked;
210  }
211  }
212 
213 
214  void GetLocalTriangle3i(KyUInt32 triangleIdx, KyUInt32 pixelSize, KyFloat32 rasterPrecision, Triangle3i& triangle3i) const;
215 
216 public: // internal
217  KyResult FlipEdge(KyUInt32 halfEdgeIdx);
218 
219  void UpdateTriangulationAfterVertexInsertion(KyUInt32 newVertexIdx);
220 
221  bool IsEdgeLegal(KyUInt32 halfEdgeIdx);
222  bool IsEdgeLegalAfterPointInsertion(KyUInt32 halfEdgeIdx, KyUInt32 newVertexIdx);
223 
224  // dynamic mesh modification
225  KyUInt32 FindTriangleThatContainsAPosition(const CoordPos& position, DynTriangulationInsertionResult& result);
226 
227  void InsertANewVertexInsideATriangle(KyUInt32 newVertexIdx, KyUInt32 triangleIdx);
228  void InsertANewVertexInTheMiddleOfAnEdge(KyUInt32 newVertexIdx, KyUInt32 halfEdgeIdx);
229  void InsertANewVertexInTheMiddleOfABorderEdge(KyUInt32 newVertexIdx, KyUInt32 halfEdgeIdx);
230 
231  void AddToEdgeToProcessIfNotOpen(KyUInt32 halfEdgeIdx);
232  void AddToEdgeToProcessIfIllegalAndNotOpen(KyUInt32 halfEdgeIdx);
233 
234  static bool IsQuadrilateralConvex(const AlignedCoordPos& a, const AlignedCoordPos& b, const AlignedCoordPos& c, const AlignedCoordPos& d);
235 private:
236  KyUInt32 GetNewDynamicVertex();
237  KyUInt32 GetNewDynamicHalfEdge();
238  KyUInt32 GetNewDynamicTriangle();
239 
240 public:
241  KyArrayDH<DynTriTriangle> m_triangles;
242  KyArrayDH<DynTriVertex> m_vertices;
243  KyArrayDH<DynTriHalfEdge> m_edges;
244 
245  KyArrayDH_POD<KyUInt32> m_edgeIdxToProcess;
246 
247  DynamicVertexIntUserDataContent m_userDataContent;
248 };
249 
250 
251 KY_INLINE void DynamicTriangulation::AddVertex(KyUInt32 vertexIdx, const AlignedCoordPos& coordPos, KyFloat32 altitude)
252 {
253  KY_ASSERT(vertexIdx < m_vertices.GetCount());
254  KY_LOG_ERROR_IF(((coordPos.x & 0xFFFFFF00) != 0 || (coordPos.y & 0xFFFFFF00) != 0), ("Invalid coordinates : %d - %d", coordPos.x, coordPos.y));
255  DynTriVertex& vertex = m_vertices[vertexIdx];
256 
257  vertex.m_idx = vertexIdx;
258  vertex.m_coordPos = coordPos;
259  vertex.m_altitude = altitude;
260 }
261 }
262 
263 
264 
#define KyFloat32MAXVAL
KyFloat32 max value
Definition: types.h:71
std::uint32_t KyUInt32
uint32_t
Definition: types.h:29
#define KY_CLASS_WITHOUT_COPY(ClassName)
Define to forbid copy constructor and copy assignment.
Definition: types.h:196
#define KY_DEFINE_NEW_DELETE_OPERATORS(MemStat)
This macro defines new and delete operators.
Definition: memory.h:132
Vec2i CoordPos
A type that represents the position of a point within the 2D integer grid.
Definition: navmeshtypes.h:20
#define KyInt32MAXVAL
KyInt32 max value
Definition: types.h:60
Navigation return code class.
Definition: types.h:108
The Autodesk Navigation namespace.
Definition: gamekitcrowddispersion.cpp:17
#define KyUInt32MAXVAL
KyUInt32 max value
Definition: types.h:68
float KyFloat32
float
Definition: types.h:32