AABox.h 9.2 KB

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