DistLine3Rectangle3.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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/DistLineSegment.h>
  9. #include <Mathematics/Rectangle.h>
  10. #include <Mathematics/Vector3.h>
  11. namespace WwiseGTE
  12. {
  13. template <typename Real>
  14. class DCPQuery<Real, Line3<Real>, Rectangle3<Real>>
  15. {
  16. public:
  17. struct Result
  18. {
  19. Real distance, sqrDistance;
  20. Real lineParameter, rectangleParameter[2];
  21. Vector3<Real> closestPoint[2];
  22. };
  23. Result operator()(Line3<Real> const& line, Rectangle3<Real> const& rectangle)
  24. {
  25. Result result;
  26. // Test if line intersects rectangle. If so, the squared distance
  27. // is zero.
  28. Vector3<Real> N = Cross(rectangle.axis[0], rectangle.axis[1]);
  29. Real NdD = Dot(N, line.direction);
  30. if (std::fabs(NdD) > (Real)0)
  31. {
  32. // The line and rectangle are not parallel, so the line
  33. // intersects the plane of the rectangle.
  34. Vector3<Real> diff = line.origin - rectangle.center;
  35. Vector3<Real> basis[3]; // {D, U, V}
  36. basis[0] = line.direction;
  37. ComputeOrthogonalComplement<Real>(1, basis);
  38. Real UdD0 = Dot(basis[1], rectangle.axis[0]);
  39. Real UdD1 = Dot(basis[1], rectangle.axis[1]);
  40. Real UdPmC = Dot(basis[1], diff);
  41. Real VdD0 = Dot(basis[2], rectangle.axis[0]);
  42. Real VdD1 = Dot(basis[2], rectangle.axis[1]);
  43. Real VdPmC = Dot(basis[2], diff);
  44. Real invDet = ((Real)1) / (UdD0 * VdD1 - UdD1 * VdD0);
  45. // Rectangle coordinates for the point of intersection.
  46. Real s0 = (VdD1 * UdPmC - UdD1 * VdPmC) * invDet;
  47. Real s1 = (UdD0 * VdPmC - VdD0 * UdPmC) * invDet;
  48. if (std::fabs(s0) <= rectangle.extent[0] && std::fabs(s1) <= rectangle.extent[1])
  49. {
  50. // Line parameter for the point of intersection.
  51. Real DdD0 = Dot(line.direction, rectangle.axis[0]);
  52. Real DdD1 = Dot(line.direction, rectangle.axis[1]);
  53. Real DdDiff = Dot(line.direction, diff);
  54. result.lineParameter = s0 * DdD0 + s1 * DdD1 - DdDiff;
  55. // Rectangle coordinates for the point of intersection.
  56. result.rectangleParameter[0] = s0;
  57. result.rectangleParameter[1] = s1;
  58. // The intersection point is inside or on the rectangle.
  59. result.closestPoint[0] =
  60. line.origin + result.lineParameter * line.direction;
  61. result.closestPoint[1] =
  62. rectangle.center + s0 * rectangle.axis[0] + s1 * rectangle.axis[1];
  63. result.distance = (Real)0;
  64. result.sqrDistance = (Real)0;
  65. return result;
  66. }
  67. }
  68. // Either (1) the line is not parallel to the rectangle and the
  69. // point of intersection of the line and the plane of the
  70. // rectangle is outside the rectangle or (2) the line and
  71. // rectangle are parallel. Regardless, the closest point on
  72. // the rectangle is on an edge of the rectangle. Compare the
  73. // line to all four edges of the rectangle.
  74. result.distance = std::numeric_limits<Real>::max();
  75. result.sqrDistance = std::numeric_limits<Real>::max();
  76. Vector3<Real> scaledDir[2] =
  77. {
  78. rectangle.extent[0] * rectangle.axis[0],
  79. rectangle.extent[1] * rectangle.axis[1]
  80. };
  81. for (int i1 = 0, omi1 = 1; i1 <= 1; ++i1, --omi1)
  82. {
  83. for (int i0 = -1; i0 <= 1; i0 += 2)
  84. {
  85. Vector3<Real> segCenter = rectangle.center + scaledDir[i1] * (Real)i0;
  86. Vector3<Real> segDirection = rectangle.axis[omi1];
  87. Real segExtent = rectangle.extent[omi1];
  88. Segment3<Real> segment(segCenter, segDirection, segExtent);
  89. DCPQuery<Real, Line3<Real>, Segment3<Real>> query;
  90. auto lsResult = query(line, segment);
  91. if (lsResult.sqrDistance < result.sqrDistance)
  92. {
  93. result.sqrDistance = lsResult.sqrDistance;
  94. result.distance = lsResult.distance;
  95. result.lineParameter = lsResult.parameter[0];
  96. // ratio is in [-1,1]
  97. Real ratio = lsResult.parameter[1] / segExtent;
  98. result.rectangleParameter[0] =
  99. rectangle.extent[0] * (omi1 * i0 + i1 * ratio);
  100. result.rectangleParameter[1] =
  101. rectangle.extent[1] * (i1 * i0 + omi1 * ratio);
  102. result.closestPoint[0] = lsResult.closestPoint[0];
  103. result.closestPoint[1] = lsResult.closestPoint[1];
  104. }
  105. }
  106. }
  107. return result;
  108. }
  109. };
  110. // Template alias for convenience.
  111. template <typename Real>
  112. using DCPLine3Rectangle3 = DCPQuery<Real, Line3<Real>, Rectangle3<Real>>;
  113. }