IntrPlane3Cylinder3.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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/Logger.h>
  9. #include <Mathematics/FIQuery.h>
  10. #include <Mathematics/TIQuery.h>
  11. #include <Mathematics/DistPoint3Plane3.h>
  12. #include <Mathematics/Circle3.h>
  13. #include <Mathematics/Cylinder3.h>
  14. #include <Mathematics/Ellipse3.h>
  15. #include <Mathematics/Line.h>
  16. namespace WwiseGTE
  17. {
  18. template <typename Real>
  19. class TIQuery<Real, Plane3<Real>, Cylinder3<Real>>
  20. {
  21. public:
  22. struct Result
  23. {
  24. bool intersect;
  25. };
  26. // The cylinder must have finite height.
  27. Result operator()(Plane3<Real> const& plane, Cylinder3<Real> const& cylinder)
  28. {
  29. LogAssert(cylinder.height != std::numeric_limits<Real>::max(),
  30. "Cylinder height must be finite.");
  31. Result result;
  32. // Compute extremes of signed distance Dot(N,X)-d for points on
  33. // the cylinder. These are
  34. // min = (Dot(N,C)-d) - r*sqrt(1-Dot(N,W)^2) - (h/2)*|Dot(N,W)|
  35. // max = (Dot(N,C)-d) + r*sqrt(1-Dot(N,W)^2) + (h/2)*|Dot(N,W)|
  36. DCPQuery<Real, Vector3<Real>, Plane3<Real>> vpQuery;
  37. Real distance = vpQuery(cylinder.axis.origin, plane).distance;
  38. Real absNdW = std::fabs(Dot(plane.normal, cylinder.axis.direction));
  39. Real root = std::sqrt(std::max((Real)1 - absNdW * absNdW, (Real)0));
  40. Real term = cylinder.radius * root + (Real)0.5 * cylinder.height * absNdW;
  41. // Intersection occurs if and only if 0 is in the interval
  42. // [min,max].
  43. result.intersect = (distance <= term);
  44. return result;
  45. }
  46. };
  47. template <typename Real>
  48. class FIQuery<Real, Plane3<Real>, Cylinder3<Real>>
  49. {
  50. public:
  51. struct Result
  52. {
  53. bool intersect;
  54. // The type of intersection.
  55. // 0: none
  56. // 1: single line (cylinder is tangent to plane), line[0] valid
  57. // 2: two parallel lines (plane cuts cylinder in two lines)
  58. // 3: circle (cylinder axis perpendicular to plane)
  59. // 4: ellipse (cylinder axis neither parallel nor perpendicular)
  60. int type;
  61. Line3<Real> line[2];
  62. Circle3<Real> circle;
  63. Ellipse3<Real> ellipse;
  64. };
  65. // The cylinder must have infinite height.
  66. Result operator()(Plane3<Real> const& plane, Cylinder3<Real> const& cylinder)
  67. {
  68. LogAssert(cylinder.height != std::numeric_limits<Real>::max(),
  69. "Cylinder height must be finite.");
  70. Result result;
  71. DCPQuery<Real, Vector3<Real>, Plane3<Real>> vpQuery;
  72. Real sdistance = vpQuery(cylinder.axis.origin, plane).signedDistance;
  73. Vector3<Real> center = cylinder.axis.origin - sdistance * plane.normal;
  74. Real cosTheta = Dot(cylinder.axis.direction, plane.normal);
  75. Real absCosTheta = std::fabs(cosTheta);
  76. if (absCosTheta > (Real)0)
  77. {
  78. // The cylinder axis intersects the plane in a unique point.
  79. result.intersect = true;
  80. if (absCosTheta < (Real)1)
  81. {
  82. result.type = 4;
  83. result.ellipse.normal = plane.normal;
  84. result.ellipse.center = cylinder.axis.origin -
  85. (sdistance / cosTheta) * cylinder.axis.direction;
  86. result.ellipse.axis[0] = cylinder.axis.direction -
  87. cosTheta * plane.normal;
  88. Normalize(result.ellipse.axis[0]);
  89. result.ellipse.axis[1] = UnitCross(plane.normal,
  90. result.ellipse.axis[0]);
  91. result.ellipse.extent[0] = cylinder.radius / absCosTheta;
  92. result.ellipse.extent[1] = cylinder.radius;
  93. }
  94. else
  95. {
  96. result.type = 3;
  97. result.circle.normal = plane.normal;
  98. result.circle.center = center;
  99. result.circle.radius = cylinder.radius;
  100. }
  101. }
  102. else
  103. {
  104. // The cylinder is parallel to the plane.
  105. Real distance = std::fabs(sdistance);
  106. if (distance < cylinder.radius)
  107. {
  108. result.intersect = true;
  109. result.type = 2;
  110. Vector3<Real> offset = Cross(cylinder.axis.direction, plane.normal);
  111. Real extent = std::sqrt(cylinder.radius * cylinder.radius - sdistance * sdistance);
  112. result.line[0].origin = center - extent * offset;
  113. result.line[0].direction = cylinder.axis.direction;
  114. result.line[1].origin = center + extent * offset;
  115. result.line[1].direction = cylinder.axis.direction;
  116. }
  117. else if (distance == cylinder.radius)
  118. {
  119. result.intersect = true;
  120. result.type = 1;
  121. result.line[0].origin = center;
  122. result.line[0].direction = cylinder.axis.direction;
  123. }
  124. else
  125. {
  126. result.intersect = false;
  127. result.type = 0;
  128. }
  129. }
  130. return result;
  131. }
  132. };
  133. }