AABox.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Geometry/Triangle.h>
  5. #include <Geometry/IndexedTriangle.h>
  6. #include <Geometry/Plane.h>
  7. #include <Math/Mat44.h>
  8. namespace JPH {
  9. /// Axis aligned box
  10. class [[nodiscard]] AABox
  11. {
  12. public:
  13. /// Constructor
  14. AABox() : mMin(Vec3::sReplicate(FLT_MAX)), mMax(Vec3::sReplicate(-FLT_MAX)) { }
  15. AABox(Vec3Arg inMin, Vec3Arg inMax) : mMin(inMin), mMax(inMax) { }
  16. AABox(Vec3Arg inCenter, float inRadius) : mMin(inCenter - Vec3::sReplicate(inRadius)), mMax(inCenter + Vec3::sReplicate(inRadius)) { }
  17. /// Create box from 2 points
  18. static AABox sFromTwoPoints(Vec3Arg inP1, Vec3Arg inP2) { return AABox(Vec3::sMin(inP1, inP2), Vec3::sMax(inP1, inP2)); }
  19. /// Get bounding box of size 2 * FLT_MAX
  20. static AABox sBiggest()
  21. {
  22. return AABox(Vec3::sReplicate(-FLT_MAX), Vec3::sReplicate(FLT_MAX));
  23. }
  24. /// Comparison operators
  25. bool operator == (const AABox &inRHS) const { return mMin == inRHS.mMin && mMax == inRHS.mMax; }
  26. bool operator != (const AABox &inRHS) const { return mMin != inRHS.mMin || mMax != inRHS.mMax; }
  27. /// Reset the bounding box to an empty bounding box
  28. void SetEmpty()
  29. {
  30. mMin = Vec3::sReplicate(FLT_MAX);
  31. mMax = Vec3::sReplicate(-FLT_MAX);
  32. }
  33. /// Check if the bounding box is valid (max >= min)
  34. bool IsValid() const
  35. {
  36. return mMin.GetX() <= mMax.GetX() && mMin.GetY() <= mMax.GetY() && mMin.GetZ() <= mMax.GetZ();
  37. }
  38. /// Encapsulate point in bounding box
  39. void Encapsulate(Vec3Arg inPos)
  40. {
  41. mMin = Vec3::sMin(mMin, inPos);
  42. mMax = Vec3::sMax(mMax, inPos);
  43. }
  44. /// Encapsulate bounding box in bounding box
  45. void Encapsulate(const AABox &inRHS)
  46. {
  47. mMin = Vec3::sMin(mMin, inRHS.mMin);
  48. mMax = Vec3::sMax(mMax, inRHS.mMax);
  49. }
  50. /// Encapsulate triangle in bounding box
  51. void Encapsulate(const Triangle &inRHS)
  52. {
  53. Vec3 v = Vec3::sLoadFloat3Unsafe(inRHS.mV[0]);
  54. Encapsulate(v);
  55. v = Vec3::sLoadFloat3Unsafe(inRHS.mV[1]);
  56. Encapsulate(v);
  57. v = Vec3::sLoadFloat3Unsafe(inRHS.mV[2]);
  58. Encapsulate(v);
  59. }
  60. /// Encapsulate triangle in bounding box
  61. void Encapsulate(const VertexList &inVertices, const IndexedTriangle &inTriangle)
  62. {
  63. for (uint32 idx : inTriangle.mIdx)
  64. Encapsulate(Vec3(inVertices[idx]));
  65. }
  66. /// Intersect this bounding box with inOther, returns the intersection
  67. const AABox Intersect(const AABox &inOther) const
  68. {
  69. return AABox(Vec3::sMax(mMin, inOther.mMin), Vec3::sMin(mMax, inOther.mMax));
  70. }
  71. /// Make sure that each edge of the bounding box has a minimal length
  72. void EnsureMinimalEdgeLength(float inMinEdgeLength)
  73. {
  74. Vec3 min_length = Vec3::sReplicate(inMinEdgeLength);
  75. mMax = Vec3::sSelect(mMax, mMin + min_length, Vec3::sLess(mMax - mMin, min_length));
  76. }
  77. /// Widen the box on both sides by inVector
  78. void ExpandBy(Vec3Arg inVector)
  79. {
  80. mMin -= inVector;
  81. mMax += inVector;
  82. }
  83. /// Get center of bounding box
  84. const Vec3 GetCenter() const
  85. {
  86. return 0.5f * (mMin + mMax);
  87. }
  88. /// Get extent of bounding box (half of the size)
  89. const Vec3 GetExtent() const
  90. {
  91. return 0.5f * (mMax - mMin);
  92. }
  93. /// Get size of bounding box
  94. const Vec3 GetSize() const
  95. {
  96. return mMax - mMin;
  97. }
  98. /// Get surface area of bounding box
  99. float GetSurfaceArea() const
  100. {
  101. Vec3 extent = mMax - mMin;
  102. return 2.0f * (extent.GetX() * extent.GetY() + extent.GetX() * extent.GetZ() + extent.GetY() * extent.GetZ());
  103. }
  104. /// Get volume of bounding box
  105. float GetVolume() const
  106. {
  107. Vec3 extent = mMax - mMin;
  108. return extent.GetX() * extent.GetY() * extent.GetZ();
  109. }
  110. /// Check if this box contains another box
  111. bool Contains(const AABox &inOther) const
  112. {
  113. return UVec4::sAnd(Vec3::sLessOrEqual(mMin, inOther.mMin), Vec3::sGreaterOrEqual(mMax, inOther.mMax)).TestAllXYZTrue();
  114. }
  115. /// Check if this box contains a point
  116. bool Contains(Vec3Arg inOther) const
  117. {
  118. return UVec4::sAnd(Vec3::sLessOrEqual(mMin, inOther), Vec3::sGreaterOrEqual(mMax, inOther)).TestAllXYZTrue();
  119. }
  120. /// Check if this box overlaps with another box
  121. bool Overlaps(const AABox &inOther) const
  122. {
  123. return !UVec4::sOr(Vec3::sGreater(mMin, inOther.mMax), Vec3::sLess(mMax, inOther.mMin)).TestAnyXYZTrue();
  124. }
  125. /// Check if this box overlaps with a plane
  126. bool Overlaps(const Plane &inPlane) const
  127. {
  128. Vec3 normal = inPlane.GetNormal();
  129. float dist_normal = inPlane.SignedDistance(GetSupport(normal));
  130. float dist_min_normal = inPlane.SignedDistance(GetSupport(-normal));
  131. return dist_normal * dist_min_normal <= 0.0f; // If both support points are on the same side of the plane we don't overlap
  132. }
  133. /// Translate bounding box
  134. void Translate(Vec3Arg inTranslation)
  135. {
  136. mMin += inTranslation;
  137. mMax += inTranslation;
  138. }
  139. /// Transform bounding box
  140. AABox Transformed(Mat44Arg inMatrix) const
  141. {
  142. // Start with the translation of the matrix
  143. Vec3 new_min, new_max;
  144. new_min = new_max = inMatrix.GetTranslation();
  145. // Now find the extreme points by considering the product of the min and max with each column of inMatrix
  146. for (int c = 0; c < 3; ++c)
  147. {
  148. Vec3 col = inMatrix.GetColumn3(c);
  149. Vec3 a = col * mMin[c];
  150. Vec3 b = col * mMax[c];
  151. new_min += Vec3::sMin(a, b);
  152. new_max += Vec3::sMax(a, b);
  153. }
  154. // Return the new bounding box
  155. return AABox(new_min, new_max);
  156. }
  157. /// Scale this bounding box, can handle non-uniform and negative scaling
  158. AABox Scaled(Vec3Arg inScale) const
  159. {
  160. return AABox::sFromTwoPoints(mMin * inScale, mMax * inScale);
  161. }
  162. /// Calculate the support vector for this convex shape.
  163. const Vec3 GetSupport(Vec3Arg inDirection) const
  164. {
  165. return Vec3::sSelect(mMax, mMin, Vec3::sLess(inDirection, Vec3::sZero()));
  166. }
  167. /// Get the vertices of the face that faces inDirection the most
  168. template <class VERTEX_ARRAY>
  169. void GetSupportingFace(Vec3Arg inDirection, VERTEX_ARRAY &outVertices) const
  170. {
  171. outVertices.resize(4);
  172. int axis = inDirection.Abs().GetHighestComponentIndex();
  173. if (inDirection[axis] < 0.0f)
  174. {
  175. switch (axis)
  176. {
  177. case 0:
  178. outVertices[0] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
  179. outVertices[1] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
  180. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
  181. outVertices[3] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
  182. break;
  183. case 1:
  184. outVertices[0] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
  185. outVertices[1] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
  186. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
  187. outVertices[3] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
  188. break;
  189. case 2:
  190. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
  191. outVertices[1] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
  192. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMax.GetZ());
  193. outVertices[3] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
  194. break;
  195. }
  196. }
  197. else
  198. {
  199. switch (axis)
  200. {
  201. case 0:
  202. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
  203. outVertices[1] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
  204. outVertices[2] = Vec3(mMin.GetX(), mMax.GetY(), mMax.GetZ());
  205. outVertices[3] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
  206. break;
  207. case 1:
  208. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
  209. outVertices[1] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
  210. outVertices[2] = Vec3(mMax.GetX(), mMin.GetY(), mMax.GetZ());
  211. outVertices[3] = Vec3(mMin.GetX(), mMin.GetY(), mMax.GetZ());
  212. break;
  213. case 2:
  214. outVertices[0] = Vec3(mMin.GetX(), mMin.GetY(), mMin.GetZ());
  215. outVertices[1] = Vec3(mMin.GetX(), mMax.GetY(), mMin.GetZ());
  216. outVertices[2] = Vec3(mMax.GetX(), mMax.GetY(), mMin.GetZ());
  217. outVertices[3] = Vec3(mMax.GetX(), mMin.GetY(), mMin.GetZ());
  218. break;
  219. }
  220. }
  221. }
  222. /// Get the closest point on or in this box to inPoint
  223. inline Vec3 GetClosestPoint(Vec3Arg inPoint) const
  224. {
  225. return Vec3::sMin(Vec3::sMax(inPoint, mMin), mMax);
  226. }
  227. /// Get the squared distance between inPoint and this box (will be 0 if in Point is inside the box)
  228. inline float GetSqDistanceTo(Vec3Arg inPoint) const
  229. {
  230. return (GetClosestPoint(inPoint) - inPoint).LengthSq();
  231. }
  232. /// Bounding box min and max
  233. Vec3 mMin;
  234. Vec3 mMax;
  235. };
  236. } // JPH