IntrPlane3Circle3.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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/IntrPlane3Plane3.h>
  9. #include <Mathematics/Circle3.h>
  10. namespace WwiseGTE
  11. {
  12. template <typename Real>
  13. class TIQuery<Real, Plane3<Real>, Circle3<Real>>
  14. {
  15. public:
  16. struct Result
  17. {
  18. bool intersect;
  19. };
  20. Result operator()(Plane3<Real> const& plane, Circle3<Real> const& circle)
  21. {
  22. Result result;
  23. // Construct the plane of the circle.
  24. Plane3<Real> cPlane(circle.normal, circle.center);
  25. // Compute the intersection of this plane with the input plane.
  26. FIQuery<Real, Plane3<Real>, Plane3<Real>> ppQuery;
  27. auto ppResult = ppQuery(plane, cPlane);
  28. if (!ppResult.intersect)
  29. {
  30. // Planes are parallel and nonintersecting.
  31. result.intersect = false;
  32. return result;
  33. }
  34. if (!ppResult.isLine)
  35. {
  36. // Planes are the same, the circle is the common intersection
  37. // set.
  38. result.intersect = true;
  39. return result;
  40. }
  41. // The planes intersect in a line. Locate one or two points that
  42. // are on the circle and line. If the line is t*D+P, the circle
  43. // center is C, and the circle radius is r, then
  44. // r^2 = |t*D+P-C|^2 = |D|^2*t^2 + 2*Dot(D,P-C)*t + |P-C|^2
  45. // This is a quadratic equation of the form
  46. // a2*t^2 + 2*a1*t + a0 = 0.
  47. Vector3<Real> diff = ppResult.line.origin - circle.center;
  48. Real a2 = Dot(ppResult.line.direction, ppResult.line.direction);
  49. Real a1 = Dot(diff, ppResult.line.direction);
  50. Real a0 = Dot(diff, diff) - circle.radius * circle.radius;
  51. // Real-valued roots imply an intersection.
  52. Real discr = a1 * a1 - a0 * a2;
  53. result.intersect = (discr >= (Real)0);
  54. return result;
  55. }
  56. };
  57. template <typename Real>
  58. class FIQuery<Real, Plane3<Real>, Circle3<Real>>
  59. {
  60. public:
  61. struct Result
  62. {
  63. bool intersect;
  64. // If 'intersect' is true, the intersection is either 1 or 2 points
  65. // or the entire circle. When points, 'numIntersections' and
  66. // 'point' are valid. When a circle, 'circle' is set to the incoming
  67. // circle.
  68. bool isPoints;
  69. int numIntersections;
  70. Vector3<Real> point[2];
  71. Circle3<Real> circle;
  72. };
  73. Result operator()(Plane3<Real> const& plane, Circle3<Real> const& circle)
  74. {
  75. Result result;
  76. // Construct the plane of the circle.
  77. Plane3<Real> cPlane(circle.normal, circle.center);
  78. // Compute the intersection of this plane with the input plane.
  79. FIQuery<Real, Plane3<Real>, Plane3<Real>> ppQuery;
  80. auto ppResult = ppQuery(plane, cPlane);
  81. if (!ppResult.intersect)
  82. {
  83. // Planes are parallel and nonintersecting.
  84. result.intersect = false;
  85. return result;
  86. }
  87. if (!ppResult.isLine)
  88. {
  89. // Planes are the same, the circle is the common intersection
  90. // set.
  91. result.intersect = true;
  92. result.isPoints = false;
  93. result.circle = circle;
  94. return result;
  95. }
  96. // The planes intersect in a line. Locate one or two points that
  97. // are on the circle and line. If the line is t*D+P, the circle
  98. // center is C, and the circle radius is r, then
  99. // r^2 = |t*D+P-C|^2 = |D|^2*t^2 + 2*Dot(D,P-C)*t + |P-C|^2
  100. // This is a quadratic equation of the form
  101. // a2*t^2 + 2*a1*t + a0 = 0.
  102. Vector3<Real> diff = ppResult.line.origin - circle.center;
  103. Real a2 = Dot(ppResult.line.direction, ppResult.line.direction);
  104. Real a1 = Dot(diff, ppResult.line.direction);
  105. Real a0 = Dot(diff, diff) - circle.radius * circle.radius;
  106. Real discr = a1 * a1 - a0 * a2;
  107. if (discr < (Real)0)
  108. {
  109. // No real roots, the circle does not intersect the plane.
  110. result.intersect = false;
  111. return result;
  112. }
  113. result.isPoints = true;
  114. Real inv = ((Real)1) / a2;
  115. if (discr == (Real)0)
  116. {
  117. // One repeated root, the circle just touches the plane.
  118. result.numIntersections = 1;
  119. result.point[0] = ppResult.line.origin - (a1 * inv) * ppResult.line.direction;
  120. return result;
  121. }
  122. // Two distinct, real-valued roots, the circle intersects the
  123. // plane in two points.
  124. Real root = std::sqrt(discr);
  125. result.numIntersections = 2;
  126. result.point[0] = ppResult.line.origin - ((a1 + root) * inv) * ppResult.line.direction;
  127. result.point[1] = ppResult.line.origin - ((a1 - root) * inv) * ppResult.line.direction;
  128. return result;
  129. }
  130. };
  131. }