Cry_GeoDistance.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. // Description : Common distance-computations
  9. #pragma once
  10. #include <Cry_Geo.h>
  11. #include <AzCore/Math/Vector3.h>
  12. #ifdef max
  13. #undef max
  14. #endif
  15. namespace Distance {
  16. //----------------------------------------------------------------------------------
  17. /// Returns squared distance from a point to a line segment and also the "t value" (from 0 to 1) of the
  18. /// closest point on the line segment
  19. //----------------------------------------------------------------------------------
  20. template<typename F>
  21. ILINE F Point_LinesegSq(const Vec3_tpl<F>& p, const Lineseg& lineseg, F& fT)
  22. {
  23. Vec3_tpl<F> diff = p - lineseg.start;
  24. Vec3_tpl<F> dir = lineseg.end - lineseg.start;
  25. fT = diff.Dot(dir);
  26. if (fT <= 0.0f)
  27. {
  28. fT = 0.0f;
  29. }
  30. else
  31. {
  32. F fSqrLen = dir.GetLengthSquared();
  33. if (fT >= fSqrLen)
  34. {
  35. fT = 1.0f;
  36. diff -= dir;
  37. }
  38. else
  39. {
  40. fT /= fSqrLen;
  41. diff -= fT * dir;
  42. }
  43. }
  44. return diff.GetLengthSquared();
  45. }
  46. /// Returns distance from a point to a line segment and also the "t value" (from 0 to 1) of the
  47. /// closest point on the line segment
  48. template<typename F>
  49. ILINE F Point_Lineseg(const Vec3_tpl<F>& p, const Lineseg& lineseg, F& fT)
  50. {
  51. return sqrt_tpl(Point_LinesegSq(p, lineseg, fT));
  52. }
  53. //! \brief Get the distance squared from a Point to a Cylinder.
  54. //! \param point AZ::Vector3 The point to test distance against the cylinder
  55. //! \param cylinderAxisEndA AZ::Vector3 One end of the cylinder axis (centered in the circle)
  56. //! \param cylinderAxisEndB AZ::Vector3 Other end of the cylinder axis (centered in the circle)
  57. //! \param radius float Radius of the cylinder
  58. //! \return float Closest distance squared from the point to the cylinder.
  59. AZ_INLINE float Point_CylinderSq(
  60. const AZ::Vector3& point,
  61. const AZ::Vector3& cylinderAxisEndA,
  62. const AZ::Vector3& cylinderAxisEndB,
  63. float radius
  64. )
  65. {
  66. // Use the cylinder axis' center point to determine distance by
  67. // splitting into Voronoi regions and using symmetry.
  68. // The regions are:
  69. // - Inside
  70. // - Beyond cylinder radius but between two disc ends.
  71. // - Within cylinder radius but beyond two disc ends.
  72. // - Beyond cylinder radius and beyond two disc ends.
  73. const AZ::Vector3 cylinderAxis = cylinderAxisEndB - cylinderAxisEndA;
  74. float halfLength = cylinderAxis.GetLength() * 0.5f;
  75. const AZ::Vector3 cylinderAxisUnit = cylinderAxis.GetNormalized();
  76. // get the center of the axis and the vector from center to the test point
  77. const AZ::Vector3 centerPoint = (cylinderAxis * 0.5) + cylinderAxisEndA;
  78. const AZ::Vector3 pointToCenter = point - centerPoint;
  79. // distance point is from center (projected onto axis)
  80. // the abs here takes advantage of symmetry.
  81. float x = fabsf(pointToCenter.Dot(cylinderAxisUnit));
  82. // squared distance from point to center (hypotenuse)
  83. float n2 = pointToCenter.GetLengthSq();
  84. // squared distance from point to center perpendicular to axis (pythagorean)
  85. float y2 = n2 - sqr(x);
  86. float distanceSquared = 0.f;
  87. if (x < halfLength) // point is between the two ends
  88. {
  89. if (y2 > sqr(radius)) // point is outside of radius
  90. {
  91. distanceSquared = sqr(sqrtf(y2) - radius);
  92. }
  93. // else point is inside cylinder, distance is zero.
  94. }
  95. else if (y2 < sqr(radius))
  96. {
  97. // point is within radius
  98. // point projects into a disc at either end, grab the "parallel" distance only
  99. distanceSquared = sqr(x - halfLength);
  100. }
  101. else
  102. {
  103. // point is outside of radius
  104. // point projects onto the edge of the disc, grab distance in two directions,
  105. // combine "parallel" and "perpendicular" distances.
  106. distanceSquared = sqr(sqrtf(y2) - radius) + sqr(x - halfLength);
  107. }
  108. return distanceSquared;
  109. }
  110. } //namespace Distance