IntrRay3Ellipsoid3.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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/IntrIntervals.h>
  9. #include <Mathematics/IntrLine3Ellipsoid3.h>
  10. #include <Mathematics/Ray.h>
  11. #include <Mathematics/Matrix3x3.h>
  12. // The queries consider the ellipsoid to be a solid.
  13. namespace WwiseGTE
  14. {
  15. template <typename Real>
  16. class TIQuery<Real, Ray3<Real>, Ellipsoid3<Real>>
  17. {
  18. public:
  19. struct Result
  20. {
  21. bool intersect;
  22. };
  23. Result operator()(Ray3<Real> const& ray, Ellipsoid3<Real> const& ellipsoid)
  24. {
  25. // The ellipsoid is (X-K)^T*M*(X-K)-1 = 0 and the line is
  26. // X = P+t*D. Substitute the line equation into the ellipsoid
  27. // equation to obtain a quadratic equation
  28. // Q(t) = a2*t^2 + 2*a1*t + a0 = 0
  29. // where a2 = D^T*M*D, a1 = D^T*M*(P-K) and
  30. // a0 = (P-K)^T*M*(P-K)-1.
  31. Result result;
  32. Matrix3x3<Real> M;
  33. ellipsoid.GetM(M);
  34. Vector3<Real> diff = ray.origin - ellipsoid.center;
  35. Vector3<Real> matDir = M * ray.direction;
  36. Vector3<Real> matDiff = M * diff;
  37. Real a2 = Dot(ray.direction, matDir);
  38. Real a1 = Dot(ray.direction, matDiff);
  39. Real a0 = Dot(diff, matDiff) - (Real)1;
  40. Real discr = a1 * a1 - a0 * a2;
  41. if (discr >= (Real)0)
  42. {
  43. // Test whether ray origin is inside ellipsoid.
  44. if (a0 <= (Real)0)
  45. {
  46. result.intersect = true;
  47. }
  48. else
  49. {
  50. // At this point, Q(0) = a0 > 0 and Q(t) has real roots.
  51. // It is also the case that a2 > 0, since M is positive
  52. // definite, implying that D^T*M*D > 0 for any nonzero
  53. // vector D. Thus, an intersection occurs only when
  54. // Q'(0) < 0.
  55. result.intersect = (a1 < (Real)0);
  56. }
  57. }
  58. else
  59. {
  60. // No intersection if Q(t) has no real roots.
  61. result.intersect = false;
  62. }
  63. return result;
  64. }
  65. };
  66. template <typename Real>
  67. class FIQuery<Real, Ray3<Real>, Ellipsoid3<Real>>
  68. :
  69. public FIQuery<Real, Line3<Real>, Ellipsoid3<Real>>
  70. {
  71. public:
  72. struct Result
  73. :
  74. public FIQuery<Real, Line3<Real>, Ellipsoid3<Real>>::Result
  75. {
  76. // No additional information to compute.
  77. };
  78. Result operator()(Ray3<Real> const& ray, Ellipsoid3<Real> const& ellipsoid)
  79. {
  80. Result result;
  81. DoQuery(ray.origin, ray.direction, ellipsoid, result);
  82. for (int i = 0; i < result.numIntersections; ++i)
  83. {
  84. result.point[i] = ray.origin + result.parameter[i] * ray.direction;
  85. }
  86. return result;
  87. }
  88. protected:
  89. void DoQuery(Vector3<Real> const& rayOrigin,
  90. Vector3<Real> const& rayDirection, Ellipsoid3<Real> const& ellipsoid,
  91. Result& result)
  92. {
  93. FIQuery<Real, Line3<Real>, Ellipsoid3<Real>>::DoQuery(rayOrigin,
  94. rayDirection, ellipsoid, result);
  95. if (result.intersect)
  96. {
  97. // The line containing the ray intersects the ellipsoid; the
  98. // t-interval is [t0,t1]. The ray intersects the capsule as
  99. // long as [t0,t1] overlaps the ray t-interval [0,+infinity).
  100. std::array<Real, 2> rayInterval = { (Real)0, std::numeric_limits<Real>::max() };
  101. FIQuery<Real, std::array<Real, 2>, std::array<Real, 2>> iiQuery;
  102. auto iiResult = iiQuery(result.parameter, rayInterval);
  103. if (iiResult.intersect)
  104. {
  105. result.numIntersections = iiResult.numIntersections;
  106. result.parameter = iiResult.overlap;
  107. }
  108. else
  109. {
  110. result.intersect = false;
  111. result.numIntersections = 0;
  112. }
  113. }
  114. }
  115. };
  116. }