DistPoint3ConvexPolyhedron3.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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/DCPQuery.h>
  9. #include <Mathematics/LCPSolver.h>
  10. #include <Mathematics/ConvexPolyhedron3.h>
  11. #include <memory>
  12. // Compute the distance between a point and a convex polyhedron in 3D. The
  13. // algorithm is based on using an LCP solver for the convex quadratic
  14. // programming problem. For details, see
  15. // https://www.geometrictools.com/Documentation/ConvexQuadraticProgramming.pdf
  16. namespace WwiseGTE
  17. {
  18. template <typename Real>
  19. class DCPQuery<Real, Vector3<Real>, ConvexPolyhedron3<Real>>
  20. {
  21. public:
  22. // Construction. If you have no knowledge of the number of faces
  23. // for the convex polyhedra you plan on applying the query to, pass
  24. // 'numTriangles' of zero. This is a request to the operator()
  25. // function to create the LCP solver for each query, and this
  26. // requires memory allocation and deallocation per query. If you
  27. // plan on applying the query multiple/ times to a single polyhedron,
  28. // even if the vertices of the polyhedron are modified for each query,
  29. // then pass 'numTriangles' to be the number of triangle faces for
  30. // that polyhedron. This lets the operator() function know to create
  31. // the LCP solver once at construction time, thus avoiding the memory
  32. // management costs during the query.
  33. DCPQuery(int numTriangles = 0)
  34. {
  35. if (numTriangles > 0)
  36. {
  37. int const n = numTriangles + 3;
  38. mLCP = std::make_unique<LCPSolver<Real>>(n);
  39. mMaxLCPIterations = mLCP->GetMaxIterations();
  40. }
  41. else
  42. {
  43. mMaxLCPIterations = 0;
  44. }
  45. }
  46. struct Result
  47. {
  48. bool queryIsSuccessful;
  49. // These members are valid only when queryIsSuccessful is true;
  50. // otherwise, they are all set to zero.
  51. Real distance, sqrDistance;
  52. Vector3<Real> closestPoint[2];
  53. // The number of iterations used by LCPSolver regardless of
  54. // whether the query is successful.
  55. int numLCPIterations;
  56. };
  57. // Default maximum iterations is 144 (n = 12, maxIterations = n*n).
  58. // If the solver fails to converge, try increasing the maximum number
  59. // of iterations.
  60. void SetMaxLCPIterations(int maxLCPIterations)
  61. {
  62. mMaxLCPIterations = maxLCPIterations;
  63. if (mLCP)
  64. {
  65. mLCP->SetMaxIterations(mMaxLCPIterations);
  66. }
  67. }
  68. Result operator()(Vector3<Real> const& point, ConvexPolyhedron3<Real> const& polyhedron)
  69. {
  70. Result result;
  71. int const numTriangles = static_cast<int>(polyhedron.planes.size());
  72. if (numTriangles == 0)
  73. {
  74. // The polyhedron planes and aligned box need to be created.
  75. result.queryIsSuccessful = false;
  76. for (int i = 0; i < 3; ++i)
  77. {
  78. result.closestPoint[0][i] = (Real)0;
  79. result.closestPoint[1][i] = (Real)0;
  80. }
  81. result.distance = (Real)0;
  82. result.sqrDistance = (Real)0;
  83. result.numLCPIterations = 0;
  84. return result;
  85. }
  86. int const n = numTriangles + 3;
  87. // Translate the point and convex polyhedron so that the
  88. // polyhedron is in the first octant. The translation is not
  89. // explicit; rather, the q and M for the LCP are initialized using
  90. // the translation information.
  91. Vector4<Real> hmin = HLift(polyhedron.alignedBox.min, (Real)1);
  92. std::vector<Real> q(n);
  93. for (int r = 0; r < 3; ++r)
  94. {
  95. q[r] = polyhedron.alignedBox.min[r] - point[r];
  96. }
  97. for (int r = 3, t = 0; r < n; ++r, ++t)
  98. {
  99. q[r] = -Dot(polyhedron.planes[t], hmin);
  100. }
  101. std::vector<Real> M(n * n);
  102. M[0] = (Real)1; M[1] = (Real)0; M[2] = (Real)0;
  103. M[n] = (Real)0; M[n + 1] = (Real)1; M[n + 2] = (Real)0;
  104. M[2 * n] = (Real)0; M[2 * n + 1] = (Real)0; M[2 * n + 2] = (Real)1;
  105. for (int t = 0, c = 3; t < numTriangles; ++t, ++c)
  106. {
  107. Vector3<Real> normal = HProject(polyhedron.planes[t]);
  108. for (int r = 0; r < 3; ++r)
  109. {
  110. M[c + n * r] = normal[r];
  111. M[r + n * c] = -normal[r];
  112. }
  113. }
  114. for (int r = 3; r < n; ++r)
  115. {
  116. for (int c = 3; c < n; ++c)
  117. {
  118. M[c + n * r] = (Real)0;
  119. }
  120. }
  121. bool needsLCP = (mLCP == nullptr);
  122. if (needsLCP)
  123. {
  124. mLCP = std::make_unique<LCPSolver<Real>>(n);
  125. if (mMaxLCPIterations > 0)
  126. {
  127. mLCP->SetMaxIterations(mMaxLCPIterations);
  128. }
  129. }
  130. std::vector<Real> w(n), z(n);
  131. if (mLCP->Solve(q, M, w, z))
  132. {
  133. result.queryIsSuccessful = true;
  134. result.closestPoint[0] = point;
  135. for (int i = 0; i < 3; ++i)
  136. {
  137. result.closestPoint[1][i] = z[i] + polyhedron.alignedBox.min[i];
  138. }
  139. Vector3<Real> diff = result.closestPoint[1] - result.closestPoint[0];
  140. result.sqrDistance = Dot(diff, diff);
  141. result.distance = std::sqrt(result.sqrDistance);
  142. }
  143. else
  144. {
  145. // If you reach this case, the maximum number of iterations
  146. // was not specified to be large enough or there is a problem
  147. // due to floating-point rounding errors. If you believe the
  148. // latter is true, file a bug report.
  149. result.queryIsSuccessful = false;
  150. }
  151. result.numLCPIterations = mLCP->GetNumIterations();
  152. if (needsLCP)
  153. {
  154. mLCP = nullptr;
  155. }
  156. return result;
  157. }
  158. private:
  159. int mMaxLCPIterations;
  160. std::unique_ptr<LCPSolver<Real>> mLCP;
  161. };
  162. }