AabbTests.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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. #include <AzCore/std/containers/span.h>
  9. #include <AzCore/Math/Aabb.h>
  10. #include <AzCore/Math/Obb.h>
  11. #include <AzCore/Math/Vector3.h>
  12. #include <AzCore/Math/Transform.h>
  13. #include <AzCore/UnitTest/TestTypes.h>
  14. #include <AZTestShared/Math/MathTestHelpers.h>
  15. using namespace AZ;
  16. namespace UnitTest
  17. {
  18. TEST(MATH_Aabb, TestCreateNull)
  19. {
  20. Aabb aabb = Aabb::CreateNull();
  21. EXPECT_FALSE(aabb.IsValid());
  22. EXPECT_TRUE(aabb.GetMin().IsGreaterThan(aabb.GetMax()));
  23. }
  24. TEST(MATH_Aabb, TestCreateFromPoint)
  25. {
  26. Aabb aabb = Aabb::CreateFromPoint(Vector3(0.0f));
  27. EXPECT_TRUE(aabb.IsValid());
  28. EXPECT_TRUE(aabb.IsFinite());
  29. EXPECT_THAT(aabb.GetMin(), IsClose(aabb.GetMax()));
  30. }
  31. TEST(MATH_Aabb, TestCreateFromMinMax)
  32. {
  33. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f));
  34. EXPECT_TRUE(aabb.IsValid());
  35. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f)));
  36. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f)));
  37. }
  38. TEST(MATH_Aabb, TestCreateCenterHalfExtents)
  39. {
  40. Aabb aabb = Aabb::CreateCenterHalfExtents(Vector3(1.0f), Vector3(1.0f));
  41. EXPECT_TRUE(aabb.IsValid());
  42. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f)));
  43. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f)));
  44. EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(1.0f)));
  45. }
  46. TEST(MATH_Aabb, TestCreateCenterRadius)
  47. {
  48. Aabb aabb = Aabb::CreateCenterRadius(Vector3(4.0f), 2.0f);
  49. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(2.0f)));
  50. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(6.0f)));
  51. EXPECT_THAT(aabb.GetExtents(), IsClose(Vector3(4.0f)));
  52. }
  53. TEST(MATH_Aabb, TestCreatePoints)
  54. {
  55. const int numPoints = 3;
  56. Vector3 points[numPoints] =
  57. {
  58. Vector3(10.0f, 0.0f, -10.0f),
  59. Vector3(-10.0f, 10.0f, 0.0f),
  60. Vector3(0.0f, -10.0f, 10.0f)
  61. };
  62. Aabb aabb = Aabb::CreatePoints(points, numPoints);
  63. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-10.0f)));
  64. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f)));
  65. }
  66. TEST(MATH_Aabb, TestCreatePointsSlice)
  67. {
  68. Vector3 points[] =
  69. {
  70. Vector3(10.0f, 0.0f, -10.0f),
  71. Vector3(-10.0f, 10.0f, 0.0f),
  72. Vector3(0.0f, -10.0f, 10.0f)
  73. };
  74. Aabb aabb = Aabb::CreatePoints(points);
  75. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-10.0f)));
  76. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f)));
  77. }
  78. TEST(MATH_Aabb, TestCreatePointsEmpty)
  79. {
  80. Aabb aabb = Aabb::CreatePoints(nullptr, 0);
  81. EXPECT_FALSE(aabb.IsValid());
  82. }
  83. TEST(MATH_Aabb, TestCreatePointsEmptySlice)
  84. {
  85. AZStd::span<Vector3> points = {};
  86. Aabb aabb = Aabb::CreatePoints(points);
  87. EXPECT_FALSE(aabb.IsValid());
  88. }
  89. TEST(MATH_Aabb, TestCreateFromObb)
  90. {
  91. const Vector3 position(1.0f, 1.0f, 1.0f);
  92. const Quaternion rotation = Quaternion::CreateRotationZ(Constants::QuarterPi);
  93. const Vector3 halfLengths = Vector3::CreateOne();
  94. const Obb obb = Obb::CreateFromPositionRotationAndHalfLengths(position, rotation, halfLengths);
  95. Aabb aabb = Aabb::CreateFromObb(obb);
  96. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-0.414f, -0.414f, 0.0f)));
  97. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.414f, 2.414f, 2.0f)));
  98. EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(1.0f, 1.0f, 1.0f)));
  99. }
  100. TEST(MATH_Aabb, TestSetters)
  101. {
  102. Aabb aabb = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(4.0f));
  103. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f)));
  104. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(4.0f)));
  105. aabb.SetMin(Vector3(0.0f));
  106. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f)));
  107. EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(2.0f)));
  108. aabb.SetMax(Vector3(6.0f));
  109. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(6.0f)));
  110. EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(3.0f)));
  111. }
  112. TEST(MATH_Aabb, TestGetExtents)
  113. {
  114. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f, 2.0f, 3.0f));
  115. EXPECT_NEAR(aabb.GetXExtent(), 1.0f, AZ::Constants::Tolerance);
  116. EXPECT_NEAR(aabb.GetYExtent(), 2.0f, AZ::Constants::Tolerance);
  117. EXPECT_NEAR(aabb.GetZExtent(), 3.0f, AZ::Constants::Tolerance);
  118. }
  119. TEST(MATH_Aabb, TestSupport)
  120. {
  121. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f));
  122. EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774, 0.5774, 0.5774)), IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  123. EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774, 0.5774, -0.5774)), IsClose(Vector3(0.0f, 0.0f, 1.0f)));
  124. EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774, -0.5774, 0.5774)), IsClose(Vector3(0.0f, 1.0f, 0.0f)));
  125. EXPECT_THAT(aabb.GetSupport(Vector3( 0.5774, -0.5774, -0.5774)), IsClose(Vector3(0.0f, 1.0f, 1.0f)));
  126. EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774, 0.5774, 0.5774)), IsClose(Vector3(1.0f, 0.0f, 0.0f)));
  127. EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774, 0.5774, -0.5774)), IsClose(Vector3(1.0f, 0.0f, 1.0f)));
  128. EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774, -0.5774, 0.5774)), IsClose(Vector3(1.0f, 1.0f, 0.0f)));
  129. EXPECT_THAT(aabb.GetSupport(Vector3(-0.5774, -0.5774, -0.5774)), IsClose(Vector3(1.0f, 1.0f, 1.0f)));
  130. }
  131. TEST(MATH_Aabb, TestGetAsSphere)
  132. {
  133. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-2.0f, 0.0f, 0.0f), Vector3(2.0f, 0.0f, 0.0f));
  134. Vector3 center;
  135. float radius;
  136. aabb.GetAsSphere(center, radius);
  137. EXPECT_THAT(center, IsClose(Vector3(0.0f)));
  138. EXPECT_NEAR(radius, 2.0f, AZ::Constants::Tolerance);
  139. }
  140. TEST(MATH_Aabb, TestContains)
  141. {
  142. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(2.0f));
  143. Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(2.0f));
  144. //Contains(Vector3)
  145. EXPECT_TRUE(aabb.Contains(Vector3(1.0f)));
  146. //Contains(Aabb)
  147. EXPECT_TRUE(aabb.Contains(aabb2));
  148. EXPECT_FALSE(aabb2.Contains(aabb));
  149. }
  150. TEST(MATH_Aabb, TestOverlaps)
  151. {
  152. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f));
  153. Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(3.0f));
  154. EXPECT_TRUE(aabb.Overlaps(aabb2));
  155. aabb2.Set(Vector3(5.0f), Vector3(6.0f));
  156. EXPECT_FALSE(aabb.Overlaps(aabb2));
  157. }
  158. TEST(MATH_Aabb, TestDisjoint)
  159. {
  160. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(2.0f));
  161. Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(2.0f));
  162. Aabb aabb3 = Aabb::CreateFromMinMax(Vector3(3.0f), Vector3(4.0f));
  163. //Disjoint(Aabb)
  164. EXPECT_FALSE(aabb.Disjoint(aabb2));
  165. EXPECT_FALSE(aabb2.Disjoint(aabb));
  166. EXPECT_TRUE(aabb3.Disjoint(aabb));
  167. EXPECT_TRUE(aabb3.Disjoint(aabb2));
  168. EXPECT_TRUE(aabb.Disjoint(aabb3));
  169. EXPECT_TRUE(aabb2.Disjoint(aabb3));
  170. }
  171. TEST(MATH_Aabb, TestExpand)
  172. {
  173. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f));
  174. aabb.Expand(Vector3(1.0f));
  175. EXPECT_THAT(aabb.GetCenter(), IsClose(Vector3(1.0f)));
  176. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f)));
  177. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(3.0f)));
  178. }
  179. TEST(MATH_Aabb, TestGetExpanded)
  180. {
  181. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f));
  182. aabb = aabb.GetExpanded(Vector3(9.0f));
  183. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-10.0f)));
  184. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f)));
  185. }
  186. TEST(MATH_Aabb, TestAddPoint)
  187. {
  188. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f));
  189. aabb.AddPoint(Vector3(1.0f));
  190. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f)));
  191. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f)));
  192. aabb.AddPoint(Vector3(2.0f));
  193. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f)));
  194. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f)));
  195. }
  196. TEST(MATH_Aabb, TestAddAabb)
  197. {
  198. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f));
  199. Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(0.0f));
  200. aabb.AddAabb(aabb2);
  201. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-2.0f)));
  202. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f)));
  203. }
  204. TEST(MATH_Aabb, TestGetDistance)
  205. {
  206. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f));
  207. EXPECT_NEAR(aabb.GetDistance(Vector3(2.0f, 0.0f, 0.0f)), 1.0f, AZ::Constants::Tolerance);
  208. // make sure a point inside the box returns zero, even if that point isn't the center.
  209. EXPECT_NEAR(aabb.GetDistance(Vector3(0.5f, 0.0f, 0.0f)), 0.0f, AZ::Constants::Tolerance);
  210. }
  211. TEST(MATH_Aabb, TestGetDistanceSq)
  212. {
  213. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f));
  214. EXPECT_NEAR(aabb.GetDistanceSq(Vector3(0.0f, 3.0f, 0.0f)), 4.0f, AZ::Constants::Tolerance);
  215. // make sure a point inside the box returns zero, even if that point isn't the center.
  216. EXPECT_NEAR(aabb.GetDistanceSq(Vector3(0.0f, 0.5f, 0.0f)), 0.0f, AZ::Constants::Tolerance);
  217. }
  218. TEST(MATH_Aabb, TestGetMaxDistance)
  219. {
  220. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f));
  221. // The max distance for all of the following should be the square root of (4^2 + 3^2 + 2^2)
  222. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, 2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  223. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, 2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  224. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, -2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  225. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(3.0f, -2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  226. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, 2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  227. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, 2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  228. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, -2.0f, 1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  229. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-3.0f, -2.0f, -1.0f)), sqrtf(16.0f + 9.0f + 4.0f), AZ::Constants::Tolerance);
  230. // make sure points inside the box return a correct max distance as well - sqrt of (1.5^2 + 1.5^2 + 1.5^2)
  231. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, 0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  232. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, 0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  233. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, -0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  234. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.5f, -0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  235. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, 0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  236. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, 0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  237. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, -0.5f, 0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  238. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(-0.5f, -0.5f, -0.5f)), sqrtf(2.25f + 2.25f + 2.25f), AZ::Constants::Tolerance);
  239. // make sure the center returns our minimal max distance (1^2 + 1^2 + 1^2)
  240. EXPECT_NEAR(aabb.GetMaxDistance(Vector3(0.0f, 0.0f, 0.0f)), sqrtf(1.0f + 1.0f + 1.0f), AZ::Constants::Tolerance);
  241. }
  242. TEST(MATH_Aabb, TestGetMaxDistanceSq)
  243. {
  244. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f));
  245. // The max distance for all of the following should be (4^2 + 3^2 + 2^2)
  246. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, 2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  247. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, 2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  248. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, -2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  249. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(3.0f, -2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  250. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, 2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  251. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, 2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  252. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, -2.0f, 1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  253. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-3.0f, -2.0f, -1.0f)), 16.0f + 9.0f + 4.0f, AZ::Constants::Tolerance);
  254. // make sure points inside the box return a correct max distance as well: (1.5^2 + 1.5^2 + 1.5^2)
  255. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, 0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  256. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, 0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  257. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, -0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  258. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.5f, -0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  259. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, 0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  260. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, 0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  261. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, -0.5f, 0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  262. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(-0.5f, -0.5f, -0.5f)), 2.25f + 2.25f + 2.25f, AZ::Constants::Tolerance);
  263. // make sure the center returns our minimal max distance (1^2 + 1^2 + 1^2)
  264. EXPECT_NEAR(aabb.GetMaxDistanceSq(Vector3(0.0f, 0.0f, 0.0f)), 1.0f + 1.0f + 1.0f, AZ::Constants::Tolerance);
  265. }
  266. TEST(MATH_Aabb, TestGetClamped)
  267. {
  268. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f));
  269. Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(4.0f));
  270. aabb = aabb.GetClamped(aabb2);
  271. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f)));
  272. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(2.0f)));
  273. }
  274. TEST(MATH_Aabb, TestClamp)
  275. {
  276. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(2.0f));
  277. Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(-2.0f), Vector3(1.0f));
  278. aabb.Clamp(aabb2);
  279. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f)));
  280. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f)));
  281. }
  282. TEST(MATH_Aabb, TestSetNull)
  283. {
  284. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f));
  285. aabb.SetNull();
  286. EXPECT_FALSE(aabb.IsValid());
  287. }
  288. TEST(MATH_Aabb, TestTranslate)
  289. {
  290. Aabb aabb = Aabb::CreateFromMinMax(Vector3(-1.0f), Vector3(1.0f));
  291. aabb.Translate(Vector3(2.0f));
  292. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f)));
  293. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(3.0f)));
  294. }
  295. TEST(MATH_Aabb, TestGetTranslated)
  296. {
  297. Aabb aabb = Aabb::CreateFromMinMax(Vector3(1.0f), Vector3(3.0f));
  298. aabb = aabb.GetTranslated(Vector3(-2.0f));
  299. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.0f)));
  300. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(1.0f)));
  301. }
  302. TEST(MATH_Aabb, TestGetSurfaceArea)
  303. {
  304. Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f));
  305. EXPECT_NEAR(aabb.GetSurfaceArea(), 6.0f, 0.002f);
  306. }
  307. TEST(MATH_Aabb, TestIsClose)
  308. {
  309. const Aabb aabb1 = Aabb::CreateFromMinMax(Vector3(0.0f), Vector3(1.0f));
  310. const Aabb aabb2 = Aabb::CreateFromMinMax(Vector3(0.1f), Vector3(0.9f));
  311. const Aabb aabb3 = Aabb::CreateFromMinMax(Vector3(0.3f), Vector3(0.7f));
  312. EXPECT_TRUE(aabb1.IsClose(aabb2, 0.2f));
  313. EXPECT_FALSE(aabb1.IsClose(aabb3, 0.2f));
  314. EXPECT_TRUE(aabb2.IsClose(aabb3, 0.3f));
  315. }
  316. TEST(MATH_Aabb, TestIsFinite)
  317. {
  318. Aabb aabb = Aabb::CreateNull();
  319. const float infinity = std::numeric_limits<float>::infinity();
  320. const Vector3 infiniteV3 = Vector3(infinity);
  321. aabb.Set(Vector3(0), infiniteV3);
  322. // A bounding box is only invalid if the min is greater than the max.
  323. // A bounding box with an infinite min or max is valid as long as this is true.
  324. EXPECT_TRUE(aabb.IsValid());
  325. EXPECT_FALSE(aabb.IsFinite());
  326. }
  327. // Check if both aabb transform functions give the same result
  328. TEST(MATH_AabbTransform, CompareTest)
  329. {
  330. // create aabb
  331. Vector3 min(-100.0f, 50.0f, 0.0f);
  332. Vector3 max(120.0f, 300.0f, 50.0f);
  333. Aabb aabb = Aabb::CreateFromMinMax(min, max);
  334. // make the transformation matrix
  335. Transform tm = Transform::CreateRotationX(1.0f);
  336. tm.SetTranslation(100.0f, 0.0f, -50.0f);
  337. // transform
  338. Obb obb = aabb.GetTransformedObb(tm);
  339. Aabb transAabb = aabb.GetTransformedAabb(tm);
  340. Aabb transAabb2 = Aabb::CreateFromObb(obb);
  341. aabb.ApplyTransform(tm);
  342. // compare the transformations
  343. EXPECT_THAT(transAabb.GetMin(), IsClose(transAabb2.GetMin()));
  344. EXPECT_THAT(transAabb.GetMax(), IsClose(transAabb2.GetMax()));
  345. EXPECT_THAT(aabb.GetMin(), IsClose(transAabb.GetMin()));
  346. EXPECT_THAT(aabb.GetMax(), IsClose(transAabb.GetMax()));
  347. }
  348. TEST(MATH_AabbTransform, GetTransformedAabbCorrectResult)
  349. {
  350. // create aabb
  351. const Vector3 min(20.0f, 30.0f, 40.0f);
  352. const Vector3 max(50.0f, 80.0f, 60.0f);
  353. const Aabb aabb = Aabb::CreateFromMinMax(min, max);
  354. const Transform transform(Vector3(10.0f, 15.0f, 25.0f), Quaternion(0.08f, 0.44f, 0.16f, 0.88f), 0.5f);
  355. const Aabb transformedAabb = aabb.GetTransformedAabb(transform);
  356. EXPECT_THAT(transformedAabb.GetMin(), IsClose(Vector3(23.168f, 32.56f, 22.504f)));
  357. EXPECT_THAT(transformedAabb.GetMax(), IsClose(Vector3(44.872f, 61.24f, 46.776f)));
  358. }
  359. TEST(MATH_AabbTransform, GetTransformedObbMatrix3x4)
  360. {
  361. Vector3 min(-1.0f, -2.0f, -3.0f);
  362. Vector3 max(4.0f, 3.0f, 2.0f);
  363. Aabb aabb = Aabb::CreateFromMinMax(min, max);
  364. Quaternion rotation(0.46f, 0.26f, 0.58f, 0.62f);
  365. Vector3 translation(5.0f, 7.0f, 9.0f);
  366. Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation);
  367. matrix3x4.MultiplyByScale(Vector3(0.5f, 1.5f, 2.0f));
  368. Obb obb = aabb.GetTransformedObb(matrix3x4);
  369. EXPECT_THAT(obb.GetRotation(), IsClose(rotation));
  370. EXPECT_THAT(obb.GetHalfLengths(), IsClose(Vector3(1.25f, 3.75f, 5.0f)));
  371. EXPECT_THAT(obb.GetPosition(), IsClose(Vector3(3.928f, 7.9156f, 9.3708f)));
  372. }
  373. TEST(MATH_AabbTransform, GetTransformedAabbMatrix3x4)
  374. {
  375. Vector3 min(2.0f, 3.0f, 5.0f);
  376. Vector3 max(6.0f, 5.0f, 11.0f);
  377. Aabb aabb = Aabb::CreateFromMinMax(min, max);
  378. Quaternion rotation(0.34f, 0.46f, 0.58f, 0.58f);
  379. Vector3 translation(-3.0f, -4.0f, -5.0f);
  380. Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation);
  381. matrix3x4.MultiplyByScale(Vector3(1.2f, 0.8f, 2.0f));
  382. Aabb transformedAabb = aabb.GetTransformedAabb(matrix3x4);
  383. EXPECT_THAT(transformedAabb.GetMin(), IsClose(Vector3(4.1488f, -0.01216f, -0.31904f)));
  384. EXPECT_THAT(transformedAabb.GetMax(), IsClose(Vector3(16.3216f, 6.54272f, 5.98112f)));
  385. }
  386. TEST(MATH_AabbTransform, GetTransformedObbFitsInsideTransformedAabb)
  387. {
  388. Vector3 min(4.0f, 3.0f, 1.0f);
  389. Vector3 max(7.0f, 6.0f, 8.0f);
  390. Aabb aabb = Aabb::CreateFromMinMax(min, max);
  391. Quaternion rotation(0.40f, 0.40f, 0.64f, 0.52f);
  392. Vector3 translation(-2.0f, 4.0f, -3.0f);
  393. Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation);
  394. matrix3x4.MultiplyByScale(Vector3(2.2f, 0.6f, 1.4f));
  395. Aabb transformedAabb = aabb.GetTransformedAabb(matrix3x4);
  396. Obb transformedObb = aabb.GetTransformedObb(matrix3x4);
  397. Aabb aabbContainingTransformedObb = Aabb::CreateFromObb(transformedObb);
  398. EXPECT_THAT(transformedAabb.GetMin(), IsClose(aabbContainingTransformedObb.GetMin()));
  399. EXPECT_THAT(transformedAabb.GetMax(), IsClose(aabbContainingTransformedObb.GetMax()));
  400. }
  401. TEST(MATH_AabbTransform, GetTransformedAabbMatrix3x4EqualsGetTransformedAabbTransform)
  402. {
  403. Vector3 min(2.0f, 3.0f, 5.0f);
  404. Vector3 max(6.0f, 5.0f, 11.0f);
  405. Aabb aabb = Aabb::CreateFromMinMax(min, max);
  406. Quaternion rotation(0.34f, 0.46f, 0.58f, 0.58f);
  407. Vector3 translation(-3.0f, -4.0f, -5.0f);
  408. Transform transform = Transform::CreateFromQuaternionAndTranslation(rotation, translation);
  409. transform.MultiplyByUniformScale(1.5f);
  410. Aabb aabbFromTransform = aabb.GetTransformedAabb(transform);
  411. Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation);
  412. matrix3x4.MultiplyByScale(Vector3(1.5f));
  413. Aabb aabbFromMatrix = aabb.GetTransformedAabb(matrix3x4);
  414. EXPECT_THAT(aabbFromTransform.GetMin(), IsClose(aabbFromMatrix.GetMin()));
  415. EXPECT_THAT(aabbFromTransform.GetMax(), IsClose(aabbFromMatrix.GetMax()));
  416. }
  417. TEST(MATH_AabbTransform, GetTransformedAabbMatrix3x4WorksWithLargeBounds)
  418. {
  419. // Create an AABB with really large bounds on the Y axis.
  420. const Aabb aabb = Aabb::CreateFromMinMax(Vector3(0.0f, AZStd::numeric_limits<float>::lowest(), -10.0f),
  421. Vector3(100.0f, 100.0f, 10.0f));
  422. // Set up a 45 degree rotation around Z so that the X and Y bounds are rotated.
  423. const Quaternion rotation = Quaternion::CreateFromEulerDegreesXYZ(AZ::Vector3(0.0f, 0.0f, 45.0f));
  424. // Set up a translation with detectable numbers in X and Y.
  425. const Vector3 translation(1000.0f, 2000.0f, 0.0f);
  426. // Transform the AABB using the given rotation and translation
  427. const Matrix3x4 matrix3x4 = Matrix3x4::CreateFromQuaternionAndTranslation(rotation, translation);
  428. const Aabb aabbFromMatrix = aabb.GetTransformedAabb(matrix3x4);
  429. // The expected results on the X axis should go from < 1000 to a really large number,
  430. // on the Y axis should go from a negative really large number to > 2000,
  431. // and on the Z axis should remain -10 to 10.
  432. // If this isn't working, the min on the X axis will be 0, and the max on the Y axis will be 0, because the really large
  433. // numbers will destroy the precision needed to pick up the translation and the small X bounds.
  434. const Vector3 expectedMin(929.289307f, -2.40615924e+38f, -10.0f);
  435. const Vector3 expectedMax(2.40615965e+38f, 2141.42139f, 10.0f);
  436. EXPECT_NEAR(aabbFromMatrix.GetMin().GetX(), expectedMin.GetX(), AZ::Constants::Tolerance);
  437. EXPECT_TRUE(IsCloseMag(aabbFromMatrix.GetMin().GetY(), expectedMin.GetY(), AZ::Constants::Tolerance));
  438. EXPECT_NEAR(aabbFromMatrix.GetMin().GetZ(), expectedMin.GetZ(), AZ::Constants::Tolerance);
  439. EXPECT_TRUE(IsCloseMag(aabbFromMatrix.GetMax().GetX(), expectedMax.GetX(), AZ::Constants::Tolerance));
  440. EXPECT_NEAR(aabbFromMatrix.GetMax().GetY(), expectedMax.GetY(), AZ::Constants::Tolerance);
  441. EXPECT_NEAR(aabbFromMatrix.GetMax().GetZ(), expectedMax.GetZ(), AZ::Constants::Tolerance);
  442. }
  443. TEST(MATH_AabbTransform, GetTransformedAabbTransformWorksWithLargeBounds)
  444. {
  445. // Create an AABB with really large bounds on the Y axis.
  446. const Aabb aabb =
  447. Aabb::CreateFromMinMax(Vector3(0.0f, AZStd::numeric_limits<float>::lowest(), -10.0f), Vector3(100.0f, 100.0f, 10.0f));
  448. // Set up a 45 degree rotation around Z so that the X and Y bounds are rotated.
  449. const Quaternion rotation = Quaternion::CreateFromEulerDegreesXYZ(AZ::Vector3(0.0f, 0.0f, 45.0f));
  450. // Set up a translation with detectable numbers in X and Y.
  451. const Vector3 translation(1000.0f, 2000.0f, 0.0f);
  452. // Transform the AABB using the given rotation and translation
  453. const Transform transform = Transform::CreateFromQuaternionAndTranslation(rotation, translation);
  454. const Aabb aabbFromTransform = aabb.GetTransformedAabb(transform);
  455. // The expected results on the X axis should go from < 1000 to a really large number,
  456. // on the Y axis should go from a negative really large number to > 2000,
  457. // and on the Z axis should remain -10 to 10.
  458. // If this isn't working, the min on the X axis will be 0, and the max on the Y axis will be 0, because the really large
  459. // numbers will destroy the precision needed to pick up the translation and the small X bounds.
  460. const Vector3 expectedMin(929.289307f, -2.40615924e+38f, -10.0f);
  461. const Vector3 expectedMax(2.40615965e+38f, 2141.42139f, 10.0f);
  462. EXPECT_NEAR(aabbFromTransform.GetMin().GetX(), expectedMin.GetX(), AZ::Constants::Tolerance);
  463. EXPECT_TRUE(IsCloseMag(aabbFromTransform.GetMin().GetY(), expectedMin.GetY(), AZ::Constants::Tolerance));
  464. EXPECT_NEAR(aabbFromTransform.GetMin().GetZ(), expectedMin.GetZ(), AZ::Constants::Tolerance);
  465. EXPECT_TRUE(IsCloseMag(aabbFromTransform.GetMax().GetX(), expectedMax.GetX(), AZ::Constants::Tolerance));
  466. EXPECT_NEAR(aabbFromTransform.GetMax().GetY(), expectedMax.GetY(), AZ::Constants::Tolerance);
  467. EXPECT_NEAR(aabbFromTransform.GetMax().GetZ(), expectedMax.GetZ(), AZ::Constants::Tolerance);
  468. }
  469. TEST(MATH_AabbTransform, MultiplyByScale)
  470. {
  471. Vector3 min(2.0f, 6.0f, 8.0f);
  472. Vector3 max(6.0f, 9.0f, 10.0f);
  473. Aabb aabb = Aabb::CreateFromMinMax(min, max);
  474. Vector3 scale(0.5f, 2.0f, 1.5f);
  475. aabb.MultiplyByScale(scale);
  476. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(1.0f, 12.0f, 12.0f)));
  477. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(3.0f, 18.0f, 15.0f)));
  478. }
  479. }