DistOrientedBox3OrientedBox3.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  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/OrientedBox.h>
  11. #include <Mathematics/Vector3.h>
  12. // Compute the distance between oriented boxes in 3D. The algorithm is based
  13. // on using an LCP solver for the convex quadratic programming problem. For
  14. // details, see
  15. // https://www.geometrictools.com/Documentation/ConvexQuadraticProgramming.pdf
  16. namespace WwiseGTE
  17. {
  18. template <typename Real>
  19. class DCPQuery<Real, OrientedBox3<Real>, OrientedBox3<Real>>
  20. {
  21. public:
  22. struct Result
  23. {
  24. bool queryIsSuccessful;
  25. // These members are valid only when queryIsSuccessful is true;
  26. // otherwise, they are all set to zero.
  27. Real distance, sqrDistance;
  28. std::array<Real, 3> box0Parameter, box1Parameter;
  29. Vector3<Real> closestPoint[2];
  30. // The number of iterations used by LCPSolver regardless of
  31. // whether the query is successful.
  32. int numLCPIterations;
  33. };
  34. // Default maximum iterations is 144 (n = 12, maxIterations = n*n).
  35. // If the solver fails to converge, try increasing the maximum number
  36. // of iterations.
  37. void SetMaxLCPIterations(int maxLCPIterations)
  38. {
  39. mLCP.SetMaxIterations(maxLCPIterations);
  40. }
  41. Result operator()(OrientedBox3<Real> const& box0, OrientedBox3<Real> const& box1)
  42. {
  43. Result result;
  44. // Translate the center of box0 to the origin. Modify the
  45. // oriented box coefficients to be nonnegative.
  46. Vector3<Real> delta = box1.center - box0.center;
  47. for (int i = 0; i < 3; ++i)
  48. {
  49. delta += box0.extent[i] * box0.axis[i];
  50. delta -= box1.extent[i] * box1.axis[i];
  51. }
  52. Vector3<Real> R0Delta, R1Delta;
  53. for (int i = 0; i < 3; ++i)
  54. {
  55. R0Delta[i] = Dot(box0.axis[i], delta);
  56. R1Delta[i] = Dot(box1.axis[i], delta);
  57. }
  58. std::array<std::array<Real, 3>, 3> R0TR1;
  59. for (int r = 0; r < 3; ++r)
  60. {
  61. for (int c = 0; c < 3; ++c)
  62. {
  63. R0TR1[r][c] = Dot(box0.axis[r], box1.axis[c]);
  64. }
  65. }
  66. Vector3<Real> twoExtent0 = box0.extent * (Real)2;
  67. Vector3<Real> twoExtent1 = box1.extent * (Real)2;
  68. // The LCP has 6 variables and 6 (nontrivial) inequality
  69. // constraints.
  70. std::array<Real, 12> q =
  71. {
  72. -R0Delta[0], -R0Delta[1], -R0Delta[2], R1Delta[0], R1Delta[1], R1Delta[2],
  73. twoExtent0[0], twoExtent0[1], twoExtent0[2], twoExtent1[0], twoExtent1[1], twoExtent1[2]
  74. };
  75. std::array<std::array<Real, 12>, 12> M;
  76. {
  77. Real const z = (Real)0;
  78. Real const p = (Real)1;
  79. Real const m = (Real)-1;
  80. M[0] = { p, z, z, -R0TR1[0][0], -R0TR1[0][1], -R0TR1[0][2], p, z, z, z, z, z };
  81. M[1] = { z, p, z, -R0TR1[1][0], -R0TR1[1][1], -R0TR1[1][2], z, p, z, z, z, z };
  82. M[2] = { z, z, p, -R0TR1[2][0], -R0TR1[2][1], -R0TR1[2][2], z, z, p, z, z, z };
  83. M[3] = { -R0TR1[0][0], -R0TR1[1][0], -R0TR1[2][0], p, z, z, z, z, z, p, z, z };
  84. M[4] = { -R0TR1[0][1], -R0TR1[1][1], -R0TR1[2][1], z, p, z, z, z, z, z, p, z };
  85. M[5] = { -R0TR1[0][2], -R0TR1[1][2], -R0TR1[2][2], z, z, p, z, z, z, z, z, p };
  86. M[6] = { m, z, z, z, z, z, z, z, z, z, z, z };
  87. M[7] = { z, m, z, z, z, z, z, z, z, z, z, z };
  88. M[8] = { z, z, m, z, z, z, z, z, z, z, z, z };
  89. M[9] = { z, z, z, m, z, z, z, z, z, z, z, z };
  90. M[10] = { z, z, z, z, m, z, z, z, z, z, z, z };
  91. M[11] = { z, z, z, z, z, m, z, z, z, z, z, z };
  92. }
  93. std::array<Real, 12> w, z;
  94. if (mLCP.Solve(q, M, w, z))
  95. {
  96. result.queryIsSuccessful = true;
  97. result.closestPoint[0] = box0.center;
  98. for (int i = 0; i < 3; ++i)
  99. {
  100. result.box0Parameter[i] = z[i] - box0.extent[i];
  101. result.closestPoint[0] += result.box0Parameter[i] * box0.axis[i];
  102. }
  103. result.closestPoint[1] = box1.center;
  104. for (int i = 0, j = 3; i < 3; ++i, ++j)
  105. {
  106. result.box1Parameter[i] = z[j] - box1.extent[i];
  107. result.closestPoint[1] += result.box1Parameter[i] * box1.axis[i];
  108. }
  109. Vector3<Real> diff = result.closestPoint[1] - result.closestPoint[0];
  110. result.sqrDistance = Dot(diff, diff);
  111. result.distance = std::sqrt(result.sqrDistance);
  112. }
  113. else
  114. {
  115. // If you reach this case, the maximum number of iterations
  116. // was not specified to be large enough or there is a problem
  117. // due to floating-point rounding errors. If you believe the
  118. // latter is true, file a bug report.
  119. result.queryIsSuccessful = false;
  120. for (int i = 0; i < 3; ++i)
  121. {
  122. result.box0Parameter[i] = (Real)0;
  123. result.box1Parameter[i] = (Real)0;
  124. result.closestPoint[0][i] = (Real)0;
  125. result.closestPoint[1][i] = (Real)0;
  126. }
  127. result.distance = (Real)0;
  128. result.sqrDistance = (Real)0;
  129. }
  130. result.numLCPIterations = mLCP.GetNumIterations();
  131. return result;
  132. }
  133. private:
  134. LCPSolver<Real, 12> mLCP;
  135. };
  136. }