IntrDisk2Sector2.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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/TIQuery.h>
  9. #include <Mathematics/Hypersphere.h>
  10. #include <Mathematics/Sector2.h>
  11. // The Circle2 object is considered to be a disk whose points X satisfy the
  12. // constraint |X-C| <= R, where C is the disk center and R is the disk
  13. // radius. The Sector2 object is also considered to be a solid. Also,
  14. // the Sector2 object is required to be convex, so the sector angle must
  15. // be in (0,pi/2], even though the Sector2 definition allows for angles
  16. // larger than pi/2 (leading to nonconvex sectors). The sector vertex is
  17. // V, the radius is L, the axis direction is D, and the angle is A. Sector
  18. // points X satisfy |X-V| <= L and Dot(D,X-V) >= cos(A)|X-V| >= 0.
  19. //
  20. // A subproblem for the test-intersection query is to determine whether
  21. // the disk intersects the cone of the sector. Although the query is in
  22. // 2D, it is analogous to the 3D problem of determining whether a sphere
  23. // and cone overlap. That algorithm is described in
  24. // https://www.geometrictools.com/Documentation/IntersectionSphereCone.pdf
  25. // The algorithm leads to coordinate-free pseudocode that applies to 2D
  26. // as well as 3D. That function is the first SphereIntersectsCone on
  27. // page 4 of the PDF.
  28. //
  29. // If the disk is outside the cone, there is no intersection. If the disk
  30. // overlaps the cone, we then need to test whether the disk overlaps the
  31. // disk of the sector.
  32. namespace WwiseGTE
  33. {
  34. template <typename Real>
  35. class TIQuery<Real, Circle2<Real>, Sector2<Real>>
  36. {
  37. public:
  38. struct Result
  39. {
  40. bool intersect;
  41. };
  42. Result operator()(Circle2<Real> const& disk, Sector2<Real> const& sector)
  43. {
  44. Result result;
  45. // Test whether the disk and the disk of the sector overlap.
  46. Vector2<Real> CmV = disk.center - sector.vertex;
  47. Real sqrLengthCmV = Dot(CmV, CmV);
  48. Real lengthCmV = std::sqrt(sqrLengthCmV);
  49. if (lengthCmV > disk.radius + sector.radius)
  50. {
  51. // The disk is outside the disk of the sector.
  52. result.intersect = false;
  53. return result;
  54. }
  55. // Test whether the disk and cone of the sector overlap. The
  56. // comments about K, K', and K" refer to the PDF mentioned
  57. // previously.
  58. Vector2<Real> U = sector.vertex - (disk.radius / sector.sinAngle) * sector.direction;
  59. Vector2<Real> CmU = disk.center - U;
  60. Real lengthCmU = Length(CmU);
  61. if (Dot(sector.direction, CmU) < lengthCmU * sector.cosAngle)
  62. {
  63. // The disk center is outside K" (in the white or gray
  64. // regions).
  65. result.intersect = false;
  66. return result;
  67. }
  68. // The disk center is inside K" (in the red, orange, blue, or
  69. // green regions).
  70. Real dotDirCmV = Dot(sector.direction, CmV);
  71. if (-dotDirCmV >= lengthCmV * sector.sinAngle)
  72. {
  73. // The disk center is inside K" and inside K' (in the blue
  74. // or green regions).
  75. if (lengthCmV <= disk.radius)
  76. {
  77. // The disk center is in the blue region, in which case
  78. // the disk contains the sector's vertex.
  79. result.intersect = true;
  80. }
  81. else
  82. {
  83. // The disk center is in the green region.
  84. result.intersect = false;
  85. }
  86. return result;
  87. }
  88. // To reach here, we know that the disk overlaps the sector's disk
  89. // and the sector's cone. The disk center is in the orange region
  90. // or in the red region (not including the segments that separate
  91. // the red and blue regions).
  92. // Test whether the ray of the right boundary of the sector
  93. // overlaps the disk. The ray direction U0 is a clockwise
  94. // rotation of the cone axis by the cone angle.
  95. Vector2<Real> U0
  96. {
  97. +sector.cosAngle * sector.direction[0] + sector.sinAngle * sector.direction[1],
  98. -sector.sinAngle * sector.direction[0] + sector.cosAngle * sector.direction[1]
  99. };
  100. Real dp0 = Dot(U0, CmV);
  101. Real discr0 = disk.radius * disk.radius + dp0 * dp0 - sqrLengthCmV;
  102. if (discr0 >= (Real)0)
  103. {
  104. // The ray intersects the disk. Now test whether the sector
  105. // boundary segment contained by the ray overlaps the disk.
  106. // The quadratic root tmin generates the ray-disk point of
  107. // intersection closest to the sector vertex.
  108. Real tmin = dp0 - std::sqrt(discr0);
  109. if (sector.radius >= tmin)
  110. {
  111. // The segment overlaps the disk.
  112. result.intersect = true;
  113. return result;
  114. }
  115. else
  116. {
  117. // The segment does not overlap the disk. We know the
  118. // disks overlap, so if the disk center is outside the
  119. // sector cone or on the right-boundary ray, the overlap
  120. // occurs outside the cone, which implies the disk and
  121. // sector do not intersect.
  122. if (dotDirCmV <= lengthCmV * sector.cosAngle)
  123. {
  124. // The disk center is not inside the sector cone.
  125. result.intersect = false;
  126. return result;
  127. }
  128. }
  129. }
  130. // Test whether the ray of the left boundary of the sector
  131. // overlaps the disk. The ray direction U1 is a counterclockwise
  132. // rotation of the cone axis by the cone angle.
  133. Vector2<Real> U1
  134. {
  135. +sector.cosAngle * sector.direction[0] - sector.sinAngle * sector.direction[1],
  136. +sector.sinAngle * sector.direction[0] + sector.cosAngle * sector.direction[1]
  137. };
  138. Real dp1 = Dot(U1, CmV);
  139. Real discr1 = disk.radius * disk.radius + dp1 * dp1 - sqrLengthCmV;
  140. if (discr1 >= (Real)0)
  141. {
  142. // The ray intersects the disk. Now test whether the sector
  143. // boundary segment contained by the ray overlaps the disk.
  144. // The quadratic root tmin generates the ray-disk point of
  145. // intersection closest to the sector vertex.
  146. Real tmin = dp1 - std::sqrt(discr1);
  147. if (sector.radius >= tmin)
  148. {
  149. result.intersect = true;
  150. return result;
  151. }
  152. else
  153. {
  154. // The segment does not overlap the disk. We know the
  155. // disks overlap, so if the disk center is outside the
  156. // sector cone or on the right-boundary ray, the overlap
  157. // occurs outside the cone, which implies the disk and
  158. // sector do not intersect.
  159. if (dotDirCmV <= lengthCmV * sector.cosAngle)
  160. {
  161. // The disk center is not inside the sector cone.
  162. result.intersect = false;
  163. return result;
  164. }
  165. }
  166. }
  167. // To reach here, a strict subset of the sector's arc boundary
  168. // must intersect the disk.
  169. result.intersect = true;
  170. return result;
  171. }
  172. };
  173. }