ExtremalQuery3BSP.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  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/ExtremalQuery3.h>
  9. #include <Mathematics/RangeIteration.h>
  10. #include <Mathematics/VETManifoldMesh.h>
  11. #include <stack>
  12. #include <queue>
  13. namespace WwiseGTE
  14. {
  15. template <typename Real>
  16. class ExtremalQuery3BSP : public ExtremalQuery3<Real>
  17. {
  18. public:
  19. // Construction.
  20. ExtremalQuery3BSP(Polyhedron3<Real> const& polytope)
  21. :
  22. ExtremalQuery3<Real>(polytope)
  23. {
  24. // Create the adjacency information for the polytope.
  25. VETManifoldMesh mesh;
  26. auto const& indices = this->mPolytope.GetIndices();
  27. int const numTriangles = static_cast<int>(indices.size() / 3);
  28. for (int t = 0; t < numTriangles; ++t)
  29. {
  30. int V[3];
  31. for (int j = 0; j < 3; ++j)
  32. {
  33. V[j] = indices[3 * t + j];
  34. }
  35. auto triangle = mesh.Insert(V[0], V[1], V[2]);
  36. mTriToNormal.insert(std::make_pair(triangle, t));
  37. }
  38. // Create the set of unique arcs which are used to create the BSP
  39. // tree.
  40. std::multiset<SphericalArc> arcs;
  41. CreateSphericalArcs(mesh, arcs);
  42. // Create the BSP tree to be used in the extremal query.
  43. CreateBSPTree(arcs);
  44. }
  45. // Disallow copying and assignment.
  46. ExtremalQuery3BSP(ExtremalQuery3BSP const&) = delete;
  47. ExtremalQuery3BSP& operator=(ExtremalQuery3BSP const&) = delete;
  48. // Compute the extreme vertices in the specified direction and return
  49. // the indices of the vertices in the polyhedron vertex array.
  50. virtual void GetExtremeVertices(Vector3<Real> const& direction,
  51. int& positiveDirection, int& negativeDirection) override
  52. {
  53. // Do a nonrecursive depth-first search of the BSP tree to
  54. // determine spherical polygon contains the incoming direction D.
  55. // Index 0 is the root of the BSP tree.
  56. int current = 0;
  57. while (current >= 0)
  58. {
  59. SphericalArc& node = mNodes[current];
  60. int sign = WwiseGTE::isign(Dot(direction, node.normal));
  61. if (sign >= 0)
  62. {
  63. current = node.posChild;
  64. if (current == -1)
  65. {
  66. // At a leaf node.
  67. positiveDirection = node.posVertex;
  68. }
  69. }
  70. else
  71. {
  72. current = node.negChild;
  73. if (current == -1)
  74. {
  75. // At a leaf node.
  76. positiveDirection = node.negVertex;
  77. }
  78. }
  79. }
  80. // Do a nonrecursive depth-first search of the BSP tree to
  81. // determine spherical polygon contains the reverse incoming
  82. // direction -D.
  83. current = 0; // the root of the BSP tree
  84. while (current >= 0)
  85. {
  86. SphericalArc& node = mNodes[current];
  87. int sign = WwiseGTE::isign(Dot(direction, node.normal));
  88. if (sign <= 0)
  89. {
  90. current = node.posChild;
  91. if (current == -1)
  92. {
  93. // At a leaf node.
  94. negativeDirection = node.posVertex;
  95. }
  96. }
  97. else
  98. {
  99. current = node.negChild;
  100. if (current == -1)
  101. {
  102. // At a leaf node.
  103. negativeDirection = node.negVertex;
  104. }
  105. }
  106. }
  107. }
  108. // Tree statistics.
  109. inline int GetNumNodes() const
  110. {
  111. return static_cast<int>(mNodes.size());
  112. }
  113. inline int GetTreeDepth() const
  114. {
  115. return mTreeDepth;
  116. }
  117. private:
  118. class SphericalArc
  119. {
  120. public:
  121. // Construction.
  122. SphericalArc()
  123. :
  124. nIndex{ -1, -1 },
  125. separation(0),
  126. posVertex(-1),
  127. negVertex(-1),
  128. posChild(-1),
  129. negChild(-1)
  130. {
  131. }
  132. // The arcs are stored in a multiset ordered by increasing
  133. // separation. The multiset will be traversed in reverse order.
  134. // This heuristic is designed to create BSP trees whose top-most
  135. // nodes can eliminate as many arcs as possible during an extremal
  136. // query.
  137. bool operator<(SphericalArc const& arc) const
  138. {
  139. return separation < arc.separation;
  140. }
  141. // Indices N[] into the face normal array for the endpoints of the
  142. // arc.
  143. std::array<int, 2> nIndex;
  144. // The number of arcs in the path from normal N[0] to normal N[1].
  145. // For spherical polygon edges, the number is 1. The number is 2
  146. // or larger for bisector arcs of the spherical polygon.
  147. int separation;
  148. // The normal is Cross(FaceNormal[N[0]],FaceNormal[N[1]]).
  149. Vector3<Real> normal;
  150. // Indices into the vertex array for the extremal points for the
  151. // two regions sharing the arc. As the arc is traversed from
  152. // normal N[0] to normal N[1], PosVertex is the index for the
  153. // extreme vertex to the left of the arc and NegVertex is the
  154. // index for the extreme vertex to the right of the arc.
  155. int posVertex, negVertex;
  156. // Support for BSP trees stored as contiguous nodes in an array.
  157. int posChild, negChild;
  158. };
  159. typedef VETManifoldMesh::Triangle Triangle;
  160. void SortAdjacentTriangles(int vIndex,
  161. std::set<std::shared_ptr<Triangle>> const& tAdj,
  162. std::vector<std::shared_ptr<Triangle>>& tAdjSorted)
  163. {
  164. // Copy the set of adjacent triangles into a vector container.
  165. int const numTriangles = static_cast<int>(tAdj.size());
  166. tAdjSorted.resize(tAdj.size());
  167. // Traverse the triangles adjacent to vertex V using edge-triangle
  168. // adjacency information to produce a sorted array of adjacent
  169. // triangles.
  170. auto tri = *tAdj.begin();
  171. for (int i = 0; i < numTriangles; ++i)
  172. {
  173. for (int prev = 2, curr = 0; curr < 3; prev = curr++)
  174. {
  175. if (tri->V[curr] == vIndex)
  176. {
  177. tAdjSorted[i] = tri;
  178. tri = tri->T[prev].lock();
  179. break;
  180. }
  181. }
  182. }
  183. }
  184. void CreateSphericalArcs(VETManifoldMesh& mesh, std::multiset<SphericalArc>& arcs)
  185. {
  186. int const prev[3] = { 2, 0, 1 };
  187. int const next[3] = { 1, 2, 0 };
  188. for (auto const& element : mesh.GetEdges())
  189. {
  190. auto edge = element.second;
  191. SphericalArc arc;
  192. arc.nIndex[0] = mTriToNormal[edge->T[0].lock()];
  193. arc.nIndex[1] = mTriToNormal[edge->T[1].lock()];
  194. arc.separation = 1;
  195. arc.normal = Cross(this->mFaceNormals[arc.nIndex[0]], this->mFaceNormals[arc.nIndex[1]]);
  196. auto adj = edge->T[0].lock();
  197. int j;
  198. for (j = 0; j < 3; ++j)
  199. {
  200. if (adj->V[j] != edge->V[0] && adj->V[j] != edge->V[1])
  201. {
  202. arc.posVertex = adj->V[prev[j]];
  203. arc.negVertex = adj->V[next[j]];
  204. break;
  205. }
  206. }
  207. LogAssert(j < 3, "Unexpected condition.");
  208. arcs.insert(arc);
  209. }
  210. CreateSphericalBisectors(mesh, arcs);
  211. }
  212. void CreateSphericalBisectors(VETManifoldMesh& mesh, std::multiset<SphericalArc>& arcs)
  213. {
  214. std::queue<std::pair<int, int>> queue;
  215. for (auto const& element : mesh.GetVertices())
  216. {
  217. // Sort the normals into a counterclockwise spherical polygon
  218. // when viewed from outside the sphere.
  219. auto vertex = element.second;
  220. int const vIndex = vertex->V;
  221. std::vector<std::shared_ptr<Triangle>> tAdjSorted;
  222. SortAdjacentTriangles(vIndex, vertex->TAdjacent, tAdjSorted);
  223. int const numTriangles = static_cast<int>(vertex->TAdjacent.size());
  224. queue.push(std::make_pair(0, numTriangles));
  225. while (!queue.empty())
  226. {
  227. std::pair<int, int> item = queue.front();
  228. queue.pop();
  229. int i0 = item.first, i1 = item.second;
  230. int separation = i1 - i0;
  231. if (separation > 1 && separation != numTriangles - 1)
  232. {
  233. if (i1 < numTriangles)
  234. {
  235. SphericalArc arc;
  236. arc.nIndex[0] = mTriToNormal[tAdjSorted[i0]];
  237. arc.nIndex[1] = mTriToNormal[tAdjSorted[i1]];
  238. arc.separation = separation;
  239. arc.normal = Cross(this->mFaceNormals[arc.nIndex[0]],
  240. this->mFaceNormals[arc.nIndex[1]]);
  241. arc.posVertex = vIndex;
  242. arc.negVertex = vIndex;
  243. arcs.insert(arc);
  244. }
  245. int imid = (i0 + i1 + 1) / 2;
  246. if (imid != i1)
  247. {
  248. queue.push(std::make_pair(i0, imid));
  249. queue.push(std::make_pair(imid, i1));
  250. }
  251. }
  252. }
  253. }
  254. }
  255. void CreateBSPTree(std::multiset<SphericalArc>& arcs)
  256. {
  257. // The tree has at least a root.
  258. mTreeDepth = 1;
  259. for (auto const& arc : WwiseGTE::reverse(arcs))
  260. {
  261. InsertArc(arc);
  262. }
  263. // The leaf nodes are not counted in the traversal of InsertArc.
  264. // The depth must be incremented to account for leaves.
  265. ++mTreeDepth;
  266. }
  267. void InsertArc(SphericalArc const& arc)
  268. {
  269. // The incoming arc is stored at the end of the nodes array.
  270. if (mNodes.size() > 0)
  271. {
  272. // Do a nonrecursive depth-first search of the current BSP
  273. // tree to place the incoming arc. Index 0 is the root of the
  274. // BSP tree.
  275. std::stack<int> candidates;
  276. candidates.push(0);
  277. while (!candidates.empty())
  278. {
  279. int current = candidates.top();
  280. candidates.pop();
  281. SphericalArc* node = &mNodes[current];
  282. int sign0;
  283. if (arc.nIndex[0] == node->nIndex[0] || arc.nIndex[0] == node->nIndex[1])
  284. {
  285. sign0 = 0;
  286. }
  287. else
  288. {
  289. Real dot = Dot(this->mFaceNormals[arc.nIndex[0]], node->normal);
  290. sign0 = WwiseGTE::isign(dot);
  291. }
  292. int sign1;
  293. if (arc.nIndex[1] == node->nIndex[0] || arc.nIndex[1] == node->nIndex[1])
  294. {
  295. sign1 = 0;
  296. }
  297. else
  298. {
  299. Real dot = Dot(this->mFaceNormals[arc.nIndex[1]], node->normal);
  300. sign1 = WwiseGTE::isign(dot);
  301. }
  302. int doTest = 0;
  303. if (sign0 * sign1 < 0)
  304. {
  305. // The new arc straddles the current arc, so propagate
  306. // it to both child nodes.
  307. doTest = 3;
  308. }
  309. else if (sign0 > 0 || sign1 > 0)
  310. {
  311. // The new arc is on the positive side of the current
  312. // arc.
  313. doTest = 1;
  314. }
  315. else if (sign0 < 0 || sign1 < 0)
  316. {
  317. // The new arc is on the negative side of the current
  318. // arc.
  319. doTest = 2;
  320. }
  321. // else: sign0 = sign1 = 0, in which case no propagation
  322. // is needed because the current BSP node will handle the
  323. // correct partitioning of the arcs during extremal
  324. // queries.
  325. int depth;
  326. if (doTest & 1)
  327. {
  328. if (node->posChild != -1)
  329. {
  330. candidates.push(node->posChild);
  331. depth = static_cast<int>(candidates.size());
  332. if (depth > mTreeDepth)
  333. {
  334. mTreeDepth = depth;
  335. }
  336. }
  337. else
  338. {
  339. node->posChild = static_cast<int>(mNodes.size());
  340. mNodes.push_back(arc);
  341. // The push_back can cause a reallocation, so the
  342. // current pointer must be refreshed.
  343. node = &mNodes[current];
  344. }
  345. }
  346. if (doTest & 2)
  347. {
  348. if (node->negChild != -1)
  349. {
  350. candidates.push(node->negChild);
  351. depth = static_cast<int>(candidates.size());
  352. if (depth > mTreeDepth)
  353. {
  354. mTreeDepth = depth;
  355. }
  356. }
  357. else
  358. {
  359. node->negChild = static_cast<int>(mNodes.size());
  360. mNodes.push_back(arc);
  361. }
  362. }
  363. }
  364. }
  365. else
  366. {
  367. // root node
  368. mNodes.push_back(arc);
  369. }
  370. }
  371. // Lookup table for indexing into mFaceNormals.
  372. std::map<std::shared_ptr<Triangle>, int> mTriToNormal;
  373. // Fixed-size storage for the BSP nodes.
  374. std::vector<SphericalArc> mNodes;
  375. int mTreeDepth;
  376. };
  377. }