DistPoint3Cylinder3.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  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/Cylinder3.h>
  10. #include <Mathematics/Vector3.h>
  11. // The queries consider the cylinder to be a solid.
  12. namespace WwiseGTE
  13. {
  14. template <typename Real>
  15. class DCPQuery<Real, Vector3<Real>, Cylinder3<Real>>
  16. {
  17. public:
  18. struct Result
  19. {
  20. Real distance;
  21. Vector3<Real> cylinderClosest;
  22. };
  23. Result operator()(Vector3<Real> const& point, Cylinder3<Real> const& cylinder)
  24. {
  25. Result result;
  26. // Convert the point to the cylinder coordinate system. In this
  27. // system, the point believes (0,0,0) is the cylinder axis origin
  28. // and (0,0,1) is the cylinder axis direction.
  29. Vector3<Real> basis[3];
  30. basis[0] = cylinder.axis.direction;
  31. ComputeOrthogonalComplement(1, basis);
  32. Vector3<Real> delta = point - cylinder.axis.origin;
  33. Vector3<Real> P
  34. {
  35. Dot(basis[1], delta),
  36. Dot(basis[2], delta),
  37. Dot(basis[0], delta)
  38. };
  39. if (cylinder.height == std::numeric_limits<Real>::max())
  40. {
  41. DoQueryInfiniteCylinder(P, cylinder.radius, result);
  42. }
  43. else
  44. {
  45. DoQueryFiniteCylinder(P, cylinder.radius, cylinder.height, result);
  46. }
  47. // Convert the closest point from the cylinder coordinate system
  48. // to the original coordinate system.
  49. result.cylinderClosest = cylinder.axis.origin +
  50. result.cylinderClosest[0] * basis[1] +
  51. result.cylinderClosest[1] * basis[2] +
  52. result.cylinderClosest[2] * basis[0];
  53. return result;
  54. }
  55. private:
  56. void DoQueryInfiniteCylinder(Vector3<Real> const& P, Real radius,
  57. Result& result)
  58. {
  59. Real sqrRadius = radius * radius;
  60. Real sqrDistance = P[0] * P[0] + P[1] * P[1];
  61. if (sqrDistance >= sqrRadius)
  62. {
  63. // The point is outside the cylinder or on the cylinder wall.
  64. Real distance = std::sqrt(sqrDistance);
  65. result.distance = distance - radius;
  66. Real temp = radius / distance;
  67. result.cylinderClosest[0] = P[0] * temp;
  68. result.cylinderClosest[1] = P[1] * temp;
  69. result.cylinderClosest[2] = P[2];
  70. }
  71. else
  72. {
  73. // The point is inside the cylinder.
  74. result.distance = (Real)0;
  75. result.cylinderClosest = P;
  76. }
  77. }
  78. void DoQueryFiniteCylinder(Vector3<Real> const& P, Real radius,
  79. Real height, Result& result)
  80. {
  81. DoQueryInfiniteCylinder(P, radius, result);
  82. // Clamp the infinite cylinder's closest point to the finite
  83. // cylinder.
  84. if (result.cylinderClosest[2] > height)
  85. {
  86. result.cylinderClosest[2] = height;
  87. result.distance = Length(result.cylinderClosest - P);
  88. }
  89. else if (result.cylinderClosest[2] < -height)
  90. {
  91. result.cylinderClosest[2] = -height;
  92. result.distance = Length(result.cylinderClosest - P);
  93. }
  94. }
  95. };
  96. }