ETNonmanifoldMesh.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <Mathematics/WeakPtrCompare.h>
  10. #include <Mathematics/EdgeKey.h>
  11. #include <Mathematics/TriangleKey.h>
  12. #include <map>
  13. #include <vector>
  14. namespace WwiseGTE
  15. {
  16. class ETNonmanifoldMesh
  17. {
  18. public:
  19. // Edge data types.
  20. class Edge;
  21. typedef std::shared_ptr<Edge>(*ECreator)(int, int);
  22. typedef std::map<EdgeKey<false>, std::shared_ptr<Edge>> EMap;
  23. // Triangle data types.
  24. class Triangle;
  25. typedef std::shared_ptr<Triangle>(*TCreator)(int, int, int);
  26. typedef std::map<TriangleKey<true>, std::shared_ptr<Triangle>> TMap;
  27. // Edge object.
  28. class Edge
  29. {
  30. public:
  31. virtual ~Edge() = default;
  32. Edge(int v0, int v1)
  33. :
  34. V{ v0, v1 }
  35. {
  36. }
  37. bool operator<(Edge const& other) const
  38. {
  39. return EdgeKey<false>(V[0], V[1]) < EdgeKey<false>(other.V[0], other.V[1]);
  40. }
  41. // Vertices of the edge.
  42. std::array<int, 2> V;
  43. // Triangles sharing the edge.
  44. std::set<std::weak_ptr<Triangle>, WeakPtrLT<Triangle>> T;
  45. };
  46. // Triangle object.
  47. class Triangle
  48. {
  49. public:
  50. virtual ~Triangle() = default;
  51. Triangle(int v0, int v1, int v2)
  52. :
  53. V{ v0, v1, v2 }
  54. {
  55. }
  56. bool operator<(Triangle const& other) const
  57. {
  58. return TriangleKey<true>(V[0], V[1], V[2]) < TriangleKey<true>(other.V[0], other.V[1], other.V[2]);
  59. }
  60. // Vertices listed in counterclockwise order (V[0],V[1],V[2]).
  61. std::array<int, 3> V;
  62. // Adjacent edges. E[i] points to edge (V[i],V[(i+1)%3]).
  63. std::array<std::weak_ptr<Edge>, 3> E;
  64. };
  65. // Construction and destruction.
  66. virtual ~ETNonmanifoldMesh() = default;
  67. ETNonmanifoldMesh(ECreator eCreator = nullptr, TCreator tCreator = nullptr)
  68. :
  69. mECreator(eCreator ? eCreator : CreateEdge),
  70. mTCreator(tCreator ? tCreator : CreateTriangle)
  71. {
  72. }
  73. // Support for a deep copy of the mesh. The mEMap and mTMap objects
  74. // have dynamically allocated memory for edges and triangles. A
  75. // shallow copy of the pointers to this memory is problematic.
  76. // Allowing sharing, say, via std::shared_ptr, is an option but not
  77. // really the intent of copying the mesh graph.
  78. ETNonmanifoldMesh(ETNonmanifoldMesh const& mesh)
  79. {
  80. *this = mesh;
  81. }
  82. ETNonmanifoldMesh& operator=(ETNonmanifoldMesh const& mesh)
  83. {
  84. Clear();
  85. mECreator = mesh.mECreator;
  86. mTCreator = mesh.mTCreator;
  87. for (auto const& element : mesh.mTMap)
  88. {
  89. Insert(element.first.V[0], element.first.V[1], element.first.V[2]);
  90. }
  91. return *this;
  92. }
  93. // Member access.
  94. inline EMap const& GetEdges() const
  95. {
  96. return mEMap;
  97. }
  98. inline TMap const& GetTriangles() const
  99. {
  100. return mTMap;
  101. }
  102. // If <v0,v1,v2> is not in the mesh, a Triangle object is created and
  103. // returned; otherwise, <v0,v1,v2> is in the mesh and nullptr is
  104. // returned.
  105. virtual std::shared_ptr<Triangle> Insert(int v0, int v1, int v2)
  106. {
  107. TriangleKey<true> tkey(v0, v1, v2);
  108. if (mTMap.find(tkey) != mTMap.end())
  109. {
  110. // The triangle already exists. Return a null pointer as a
  111. // signal to the caller that the insertion failed.
  112. return nullptr;
  113. }
  114. // Create the new triangle. It will be added to mTMap at the end
  115. // of the function so that if an assertion is triggered and the
  116. // function returns early, the (bad) triangle will not be part of
  117. // the mesh.
  118. std::shared_ptr<Triangle> tri = mTCreator(v0, v1, v2);
  119. // Add the edges to the mesh if they do not already exist.
  120. for (int i0 = 2, i1 = 0; i1 < 3; i0 = i1++)
  121. {
  122. EdgeKey<false> ekey(tri->V[i0], tri->V[i1]);
  123. std::shared_ptr<Edge> edge;
  124. auto eiter = mEMap.find(ekey);
  125. if (eiter == mEMap.end())
  126. {
  127. // This is the first time the edge is encountered.
  128. edge = mECreator(tri->V[i0], tri->V[i1]);
  129. mEMap[ekey] = edge;
  130. }
  131. else
  132. {
  133. // The edge was previously encountered and created.
  134. edge = eiter->second;
  135. LogAssert(edge != nullptr, "Unexpected condition.");
  136. }
  137. // Associate the edge with the triangle.
  138. tri->E[i0] = edge;
  139. // Update the adjacent set of triangles for the edge.
  140. edge->T.insert(tri);
  141. }
  142. mTMap[tkey] = tri;
  143. return tri;
  144. }
  145. // If <v0,v1,v2> is in the mesh, it is removed and 'true' is returned;
  146. // otherwise, <v0,v1,v2> is not in the mesh and 'false' is returned.
  147. virtual bool Remove(int v0, int v1, int v2)
  148. {
  149. TriangleKey<true> tkey(v0, v1, v2);
  150. auto titer = mTMap.find(tkey);
  151. if (titer == mTMap.end())
  152. {
  153. // The triangle does not exist.
  154. return false;
  155. }
  156. // Get the triangle.
  157. std::shared_ptr<Triangle> tri = titer->second;
  158. // Remove the edges and update adjacent triangles if necessary.
  159. for (int i = 0; i < 3; ++i)
  160. {
  161. // Inform the edges the triangle is being deleted.
  162. auto edge = tri->E[i].lock();
  163. LogAssert(edge != nullptr, "Unexpected condition.");
  164. // Remove the triangle from the edge's set of adjacent
  165. // triangles.
  166. size_t numRemoved = edge->T.erase(tri);
  167. LogAssert(numRemoved > 0, "Unexpected condition.");
  168. // Remove the edge if you have the last reference to it.
  169. if (edge->T.size() == 0)
  170. {
  171. EdgeKey<false> ekey(edge->V[0], edge->V[1]);
  172. mEMap.erase(ekey);
  173. }
  174. }
  175. // Remove the triangle from the graph.
  176. mTMap.erase(tkey);
  177. return true;
  178. }
  179. // Destroy the edges and triangles to obtain an empty mesh.
  180. virtual void Clear()
  181. {
  182. mEMap.clear();
  183. mTMap.clear();
  184. }
  185. // A manifold mesh has the property that an edge is shared by at most
  186. // two triangles sharing.
  187. bool IsManifold() const
  188. {
  189. for (auto const& element : mEMap)
  190. {
  191. if (element.second->T.size() > 2)
  192. {
  193. return false;
  194. }
  195. }
  196. return true;
  197. }
  198. // A manifold mesh is closed if each edge is shared twice. A closed
  199. // mesh is not necessarily oriented. For example, you could have a
  200. // mesh with spherical topology. The upper hemisphere has outer-facing
  201. // normals and the lower hemisphere has inner-facing normals. The
  202. // discontinuity in orientation occurs on the circle shared by the
  203. // hemispheres.
  204. bool IsClosed() const
  205. {
  206. for (auto const& element : mEMap)
  207. {
  208. if (element.second->T.size() != 2)
  209. {
  210. return false;
  211. }
  212. }
  213. return true;
  214. }
  215. // Compute the connected components of the edge-triangle graph that
  216. // the mesh represents. The first function returns pointers into
  217. // 'this' object's containers, so you must consume the components
  218. // before clearing or destroying 'this'. The second function returns
  219. // triangle keys, which requires three times as much storage as the
  220. // pointers but allows you to clear or destroy 'this' before consuming
  221. // the components.
  222. void GetComponents(std::vector<std::vector<std::shared_ptr<Triangle>>>& components) const
  223. {
  224. // visited: 0 (unvisited), 1 (discovered), 2 (finished)
  225. std::map<std::shared_ptr<Triangle>, int> visited;
  226. for (auto const& element : mTMap)
  227. {
  228. visited.insert(std::make_pair(element.second, 0));
  229. }
  230. for (auto& element : mTMap)
  231. {
  232. auto tri = element.second;
  233. if (visited[tri] == 0)
  234. {
  235. std::vector<std::shared_ptr<Triangle>> component;
  236. DepthFirstSearch(tri, visited, component);
  237. components.push_back(component);
  238. }
  239. }
  240. }
  241. void GetComponents(std::vector<std::vector<TriangleKey<true>>>& components) const
  242. {
  243. // visited: 0 (unvisited), 1 (discovered), 2 (finished)
  244. std::map<std::shared_ptr<Triangle>, int> visited;
  245. for (auto const& element : mTMap)
  246. {
  247. visited.insert(std::make_pair(element.second, 0));
  248. }
  249. for (auto& element : mTMap)
  250. {
  251. std::shared_ptr<Triangle> tri = element.second;
  252. if (visited[tri] == 0)
  253. {
  254. std::vector<std::shared_ptr<Triangle>> component;
  255. DepthFirstSearch(tri, visited, component);
  256. std::vector<TriangleKey<true>> keyComponent;
  257. keyComponent.reserve(component.size());
  258. for (auto const& t : component)
  259. {
  260. keyComponent.push_back(TriangleKey<true>(t->V[0], t->V[1], t->V[2]));
  261. }
  262. components.push_back(keyComponent);
  263. }
  264. }
  265. }
  266. protected:
  267. // The edge data and default edge creation.
  268. static std::shared_ptr<Edge> CreateEdge(int v0, int v1)
  269. {
  270. return std::make_shared<Edge>(v0, v1);
  271. }
  272. ECreator mECreator;
  273. EMap mEMap;
  274. // The triangle data and default triangle creation.
  275. static std::shared_ptr<Triangle> CreateTriangle(int v0, int v1, int v2)
  276. {
  277. return std::make_shared<Triangle>(v0, v1, v2);
  278. }
  279. TCreator mTCreator;
  280. TMap mTMap;
  281. // Support for computing connected components. This is a
  282. // straightforward depth-first search of the graph but uses a
  283. // preallocated stack rather than a recursive function that could
  284. // possibly overflow the call stack.
  285. void DepthFirstSearch(std::shared_ptr<Triangle> const& tInitial,
  286. std::map<std::shared_ptr<Triangle>, int>& visited,
  287. std::vector<std::shared_ptr<Triangle>>& component) const
  288. {
  289. // Allocate the maximum-size stack that can occur in the
  290. // depth-first search. The stack is empty when the index top
  291. // is -1.
  292. std::vector<std::shared_ptr<Triangle>> tStack(mTMap.size());
  293. int top = -1;
  294. tStack[++top] = tInitial;
  295. while (top >= 0)
  296. {
  297. std::shared_ptr<Triangle> tri = tStack[top];
  298. visited[tri] = 1;
  299. int i;
  300. for (i = 0; i < 3; ++i)
  301. {
  302. auto edge = tri->E[i].lock();
  303. LogAssert(edge != nullptr, "Unexpected condition.");
  304. bool foundUnvisited = false;
  305. for (auto const& adjw : edge->T)
  306. {
  307. auto adj = adjw.lock();
  308. LogAssert(adj != nullptr, "Unexpected condition.");
  309. if (visited[adj] == 0)
  310. {
  311. tStack[++top] = adj;
  312. foundUnvisited = true;
  313. break;
  314. }
  315. }
  316. if (foundUnvisited)
  317. {
  318. break;
  319. }
  320. }
  321. if (i == 3)
  322. {
  323. visited[tri] = 2;
  324. component.push_back(tri);
  325. --top;
  326. }
  327. }
  328. }
  329. };
  330. }