IntrSegment3Sphere3.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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/IntrLine3Sphere3.h>
  10. #include <Mathematics/Segment.h>
  11. namespace WwiseGTE
  12. {
  13. template <typename Real>
  14. class TIQuery<Real, Segment3<Real>, Sphere3<Real>>
  15. {
  16. public:
  17. struct Result
  18. {
  19. bool intersect;
  20. };
  21. Result operator()(Segment3<Real> const& segment, Sphere3<Real> const& sphere)
  22. {
  23. // The sphere is (X-C)^T*(X-C)-1 = 0 and the line is X = P+t*D.
  24. // Substitute the line equation into the sphere equation to
  25. // obtain a quadratic equation Q(t) = t^2 + 2*a1*t + a0 = 0, where
  26. // a1 = D^T*(P-C) and a0 = (P-C)^T*(P-C)-1.
  27. Result result;
  28. Vector3<Real> segOrigin, segDirection;
  29. Real segExtent;
  30. segment.GetCenteredForm(segOrigin, segDirection, segExtent);
  31. Vector3<Real> diff = segOrigin - sphere.center;
  32. Real a0 = Dot(diff, diff) - sphere.radius * sphere.radius;
  33. Real a1 = Dot(segDirection, diff);
  34. Real discr = a1 * a1 - a0;
  35. if (discr < (Real)0)
  36. {
  37. result.intersect = false;
  38. return result;
  39. }
  40. Real tmp0 = segExtent * segExtent + a0;
  41. Real tmp1 = ((Real)2) * a1 * segExtent;
  42. Real qm = tmp0 - tmp1;
  43. Real qp = tmp0 + tmp1;
  44. if (qm * qp <= (Real)0)
  45. {
  46. result.intersect = true;
  47. return result;
  48. }
  49. result.intersect = (qm > (Real)0 && std::fabs(a1) < segExtent);
  50. return result;
  51. }
  52. };
  53. template <typename Real>
  54. class FIQuery<Real, Segment3<Real>, Sphere3<Real>>
  55. :
  56. public FIQuery<Real, Line3<Real>, Sphere3<Real>>
  57. {
  58. public:
  59. struct Result
  60. :
  61. public FIQuery<Real, Line3<Real>, Sphere3<Real>>::Result
  62. {
  63. // No additional information to compute.
  64. };
  65. Result operator()(Segment3<Real> const& segment, Sphere3<Real> const& sphere)
  66. {
  67. Vector3<Real> segOrigin, segDirection;
  68. Real segExtent;
  69. segment.GetCenteredForm(segOrigin, segDirection, segExtent);
  70. Result result;
  71. DoQuery(segOrigin, segDirection, segExtent, sphere, result);
  72. for (int i = 0; i < result.numIntersections; ++i)
  73. {
  74. result.point[i] = segOrigin + result.parameter[i] * segDirection;
  75. }
  76. return result;
  77. }
  78. protected:
  79. void DoQuery(Vector3<Real> const& segOrigin,
  80. Vector3<Real> const& segDirection, Real segExtent,
  81. Sphere3<Real> const& sphere, Result& result)
  82. {
  83. FIQuery<Real, Line3<Real>, Sphere3<Real>>::DoQuery(segOrigin,
  84. segDirection, sphere, result);
  85. if (result.intersect)
  86. {
  87. // The line containing the segment intersects the sphere; the
  88. // t-interval is [t0,t1]. The segment intersects the sphere
  89. // as long as [t0,t1] overlaps the segment t-interval
  90. // [-segExtent,+segExtent].
  91. std::array<Real, 2> segInterval = { -segExtent, segExtent };
  92. FIQuery<Real, std::array<Real, 2>, std::array<Real, 2>> iiQuery;
  93. auto iiResult = iiQuery(result.parameter, segInterval);
  94. if (iiResult.intersect)
  95. {
  96. result.numIntersections = iiResult.numIntersections;
  97. result.parameter = iiResult.overlap;
  98. }
  99. else
  100. {
  101. result.intersect = false;
  102. result.numIntersections = 0;
  103. }
  104. }
  105. }
  106. };
  107. }