IntrCircle2Circle2.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  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/FIQuery.h>
  9. #include <Mathematics/TIQuery.h>
  10. #include <Mathematics/Hypersphere.h>
  11. #include <Mathematics/Vector2.h>
  12. namespace WwiseGTE
  13. {
  14. template <typename Real>
  15. class TIQuery<Real, Circle2<Real>, Circle2<Real>>
  16. {
  17. public:
  18. struct Result
  19. {
  20. bool intersect;
  21. };
  22. Result operator()(Circle2<Real> const& circle0, Circle2<Real> const& circle1)
  23. {
  24. Result result;
  25. Vector2<Real> diff = circle0.center - circle1.center;
  26. result.intersect = (Length(diff) <= circle0.radius + circle1.radius);
  27. return result;
  28. }
  29. };
  30. template <typename Real>
  31. class FIQuery<Real, Circle2<Real>, Circle2<Real>>
  32. {
  33. public:
  34. struct Result
  35. {
  36. bool intersect;
  37. // The number of intersections is 0, 1, 2 or maxInt =
  38. // std::numeric_limits<int>::max(). When 1, the circles are
  39. // tangent and intersect in a single point. When 2, circles have
  40. // two transverse intersection points. When maxInt, the circles
  41. // are the same.
  42. int numIntersections;
  43. // Valid only when numIntersections = 1 or 2.
  44. Vector2<Real> point[2];
  45. // Valid only when numIntersections = maxInt.
  46. Circle2<Real> circle;
  47. };
  48. Result operator()(Circle2<Real> const& circle0, Circle2<Real> const& circle1)
  49. {
  50. // The two circles are |X-C0| = R0 and |X-C1| = R1. Define
  51. // U = C1 - C0 and V = Perp(U) where Perp(x,y) = (y,-x). Note
  52. // that Dot(U,V) = 0 and |V|^2 = |U|^2. The intersection points X
  53. // can be written in the form X = C0+s*U+t*V and
  54. // X = C1+(s-1)*U+t*V. Squaring the circle equations and
  55. // substituting these formulas into them yields
  56. // R0^2 = (s^2 + t^2)*|U|^2
  57. // R1^2 = ((s-1)^2 + t^2)*|U|^2.
  58. // Subtracting and solving for s yields
  59. // s = ((R0^2-R1^2)/|U|^2 + 1)/2
  60. // Then replace in the first equation and solve for t^2
  61. // t^2 = (R0^2/|U|^2) - s^2.
  62. // In order for there to be solutions, the right-hand side must be
  63. // nonnegative. Some algebra leads to the condition for existence
  64. // of solutions,
  65. // (|U|^2 - (R0+R1)^2)*(|U|^2 - (R0-R1)^2) <= 0.
  66. // This reduces to
  67. // |R0-R1| <= |U| <= |R0+R1|.
  68. // If |U| = |R0-R1|, then the circles are side-by-side and just
  69. // tangent. If |U| = |R0+R1|, then the circles are nested and
  70. // just tangent. If |R0-R1| < |U| < |R0+R1|, then the two circles
  71. // to intersect in two points.
  72. Result result;
  73. Vector2<Real> U = circle1.center - circle0.center;
  74. Real USqrLen = Dot(U, U);
  75. Real R0 = circle0.radius, R1 = circle1.radius;
  76. Real R0mR1 = R0 - R1;
  77. if (USqrLen == (Real)0 && R0mR1 == (Real)0)
  78. {
  79. // Circles are the same.
  80. result.intersect = true;
  81. result.numIntersections = std::numeric_limits<int>::max();
  82. result.circle = circle0;
  83. return result;
  84. }
  85. Real R0mR1Sqr = R0mR1 * R0mR1;
  86. if (USqrLen < R0mR1Sqr)
  87. {
  88. // The circles do not intersect.
  89. result.intersect = false;
  90. result.numIntersections = 0;
  91. return result;
  92. }
  93. Real R0pR1 = R0 + R1;
  94. Real R0pR1Sqr = R0pR1 * R0pR1;
  95. if (USqrLen > R0pR1Sqr)
  96. {
  97. // The circles do not intersect.
  98. result.intersect = false;
  99. result.numIntersections = 0;
  100. return result;
  101. }
  102. if (USqrLen < R0pR1Sqr)
  103. {
  104. if (R0mR1Sqr < USqrLen)
  105. {
  106. Real invUSqrLen = (Real)1 / USqrLen;
  107. Real s = (Real)0.5 * ((R0 * R0 - R1 * R1) * invUSqrLen + (Real)1);
  108. Vector2<Real> tmp = circle0.center + s * U;
  109. // In theory, discr is nonnegative. However, numerical round-off
  110. // errors can make it slightly negative. Clamp it to zero.
  111. Real discr = R0 * R0 * invUSqrLen - s * s;
  112. if (discr < (Real)0)
  113. {
  114. discr = (Real)0;
  115. }
  116. Real t = std::sqrt(discr);
  117. Vector2<Real> V{ U[1], -U[0] };
  118. result.point[0] = tmp - t * V;
  119. result.point[1] = tmp + t * V;
  120. result.numIntersections = (t > (Real)0 ? 2 : 1);
  121. }
  122. else
  123. {
  124. // |U| = |R0-R1|, circles are tangent.
  125. result.numIntersections = 1;
  126. result.point[0] = circle0.center + (R0 / R0mR1) * U;
  127. }
  128. }
  129. else
  130. {
  131. // |U| = |R0+R1|, circles are tangent.
  132. result.numIntersections = 1;
  133. result.point[0] = circle0.center + (R0 / R0pR1) * U;
  134. }
  135. // The circles intersect in 1 or 2 points.
  136. result.intersect = true;
  137. return result;
  138. }
  139. };
  140. }