TubeShapeTest.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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 <AzTest/AzTest.h>
  9. #include <AZTestShared/Math/MathTestHelpers.h>
  10. #include <AzFramework/Components/TransformComponent.h>
  11. #include <AzCore/Component/ComponentApplication.h>
  12. #include <Shape/SplineComponent.h>
  13. #include <Shape/TubeShapeComponent.h>
  14. #include <AzCore/UnitTest/TestTypes.h>
  15. #include <ShapeThreadsafeTest.h>
  16. namespace UnitTest
  17. {
  18. class TubeShapeTest
  19. : public LeakDetectionFixture
  20. {
  21. AZStd::unique_ptr<AZ::SerializeContext> m_serializeContext;
  22. AZStd::unique_ptr<AZ::ComponentDescriptor> m_transformComponentDescriptor;
  23. AZStd::unique_ptr<AZ::ComponentDescriptor> m_splineComponentDescriptor;
  24. AZStd::unique_ptr<AZ::ComponentDescriptor> m_tubeShapeComponentDescriptor;
  25. public:
  26. void SetUp() override
  27. {
  28. LeakDetectionFixture::SetUp();
  29. m_serializeContext = AZStd::make_unique<AZ::SerializeContext>();
  30. m_transformComponentDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>(AzFramework::TransformComponent::CreateDescriptor());
  31. m_transformComponentDescriptor->Reflect(&(*m_serializeContext));
  32. m_tubeShapeComponentDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>(LmbrCentral::TubeShapeComponent::CreateDescriptor());
  33. m_tubeShapeComponentDescriptor->Reflect(&(*m_serializeContext));
  34. m_splineComponentDescriptor = AZStd::unique_ptr<AZ::ComponentDescriptor>(LmbrCentral::SplineComponent::CreateDescriptor());
  35. m_splineComponentDescriptor->Reflect(&(*m_serializeContext));
  36. }
  37. void TearDown() override
  38. {
  39. m_transformComponentDescriptor.reset();
  40. m_tubeShapeComponentDescriptor.reset();
  41. m_splineComponentDescriptor.reset();
  42. m_serializeContext.reset();
  43. LeakDetectionFixture::TearDown();
  44. }
  45. };
  46. void CreateTube(const AZ::Transform& transform, const float radius, AZ::Entity& entity)
  47. {
  48. entity.CreateComponent<AzFramework::TransformComponent>();
  49. entity.CreateComponent<LmbrCentral::SplineComponent>();
  50. entity.CreateComponent<LmbrCentral::TubeShapeComponent>();
  51. entity.Init();
  52. entity.Activate();
  53. AZ::TransformBus::Event(entity.GetId(), &AZ::TransformBus::Events::SetWorldTM, transform);
  54. LmbrCentral::SplineComponentRequestBus::Event(
  55. entity.GetId(), &LmbrCentral::SplineComponentRequests::SetVertices,
  56. AZStd::vector<AZ::Vector3>
  57. {
  58. AZ::Vector3(-3.0f, 0.0f, 0.0f), AZ::Vector3(-1.0f, 0.0f, 0.0f),
  59. AZ::Vector3(1.0f, 0.0f, 0.0f), AZ::Vector3(3.0f, 0.0f, 0.0f)
  60. }
  61. );
  62. LmbrCentral::TubeShapeComponentRequestsBus::Event(entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetRadius, radius);
  63. }
  64. TEST_F(TubeShapeTest, GetRayIntersectTubeSuccess1)
  65. {
  66. AZ::Entity entity;
  67. CreateTube(
  68. AZ::Transform::CreateIdentity(),
  69. 1.0f,
  70. entity);
  71. bool rayHit = false;
  72. float distance;
  73. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  74. rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay,
  75. AZ::Vector3(0.0f, -3.0f, 0.0f), AZ::Vector3(0.0f, 1.0f, 0.0f), distance);
  76. EXPECT_TRUE(rayHit);
  77. EXPECT_NEAR(distance, 2.0f, 1e-2f);
  78. }
  79. // firing at end of tube
  80. TEST_F(TubeShapeTest, GetRayIntersectTubeSuccess2)
  81. {
  82. AZ::Entity entity;
  83. CreateTube(
  84. AZ::Transform::CreateIdentity(),
  85. 1.0f,
  86. entity);
  87. bool rayHit = false;
  88. float distance;
  89. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  90. rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay,
  91. AZ::Vector3(6.0f, 0.0f, 0.0f), AZ::Vector3(-1.0f, 0.0f, 0.0f), distance);
  92. EXPECT_TRUE(rayHit);
  93. EXPECT_NEAR(distance, 2.0f, 1e-2f);
  94. }
  95. // firing at beginning of tube
  96. TEST_F(TubeShapeTest, GetRayIntersectTubeSuccess3)
  97. {
  98. AZ::Entity entity;
  99. CreateTube(
  100. AZ::Transform::CreateIdentity(),
  101. 1.0f,
  102. entity);
  103. bool rayHit = false;
  104. float distance;
  105. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  106. rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay,
  107. AZ::Vector3(-6.0f, 0.0f, 0.0f), AZ::Vector3(1.0f, 0.0f, 0.0f), distance);
  108. EXPECT_TRUE(rayHit);
  109. EXPECT_NEAR(distance, 2.0f, 1e-2f);
  110. }
  111. // transformed and scaled
  112. TEST_F(TubeShapeTest, GetRayIntersectTubeSuccess4)
  113. {
  114. AZ::Entity entity;
  115. CreateTube(
  116. AZ::Transform::CreateTranslation(AZ::Vector3(-40.0f, 6.0f, 1.0f)) *
  117. AZ::Transform::CreateUniformScale(2.5f),
  118. 1.0f,
  119. entity);
  120. // set variable radius
  121. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  122. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  123. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  124. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, 2.0f);
  125. bool rayHit = false;
  126. float distance;
  127. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  128. rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay,
  129. AZ::Vector3(-17.0f, 6.0f, 1.0f), AZ::Vector3(-1.0f, 0.0f, 0.0f), distance);
  130. EXPECT_TRUE(rayHit);
  131. EXPECT_NEAR(distance, 8.0f, 1e-2f);
  132. }
  133. // above tube
  134. TEST_F(TubeShapeTest, GetRayIntersectTubeFailure)
  135. {
  136. AZ::Entity entity;
  137. CreateTube(
  138. AZ::Transform::CreateIdentity(),
  139. 1.0f,
  140. entity);
  141. bool rayHit = false;
  142. float distance;
  143. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  144. rayHit, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IntersectRay,
  145. AZ::Vector3(0.0f, 2.0f, 2.0f), AZ::Vector3(0.0f, 1.0f, 0.0f), distance);
  146. EXPECT_FALSE(rayHit);
  147. }
  148. TEST_F(TubeShapeTest, GetAabb1)
  149. {
  150. AZ::Entity entity;
  151. CreateTube(AZ::Transform::CreateFromQuaternionAndTranslation(
  152. AZ::Quaternion::CreateIdentity(), AZ::Vector3(0.0f, -10.0f, 0.0f)),
  153. 1.0f, entity);
  154. AZ::Aabb aabb;
  155. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  156. aabb, entity.GetId(), &LmbrCentral::ShapeComponentRequests::GetEncompassingAabb);
  157. EXPECT_THAT(aabb.GetMin(), IsClose(AZ::Vector3(-4.0f, -11.0f, -1.0f)));
  158. EXPECT_THAT(aabb.GetMax(), IsClose(AZ::Vector3(4.0f, -9.0f, 1.0f)));
  159. }
  160. TEST_F(TubeShapeTest, GetAabb2)
  161. {
  162. AZ::Entity entity;
  163. CreateTube(AZ::Transform::CreateFromQuaternionAndTranslation(
  164. AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), AZ::Constants::QuarterPi) *
  165. AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisY(), AZ::Constants::QuarterPi), AZ::Vector3(-10.0f, -10.0f, 0.0f)),
  166. 2.0f, entity);
  167. AZ::Aabb aabb;
  168. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  169. aabb, entity.GetId(), &LmbrCentral::ShapeComponentRequests::GetEncompassingAabb);
  170. EXPECT_THAT(aabb.GetMin(), IsClose(AZ::Vector3(-14.1213f, -13.5f, -3.5f)));
  171. EXPECT_THAT(aabb.GetMax(), IsClose(AZ::Vector3(-5.8786f, -6.5f, 3.5f)));
  172. }
  173. TEST_F(TubeShapeTest, GetAabb3)
  174. {
  175. AZ::Entity entity;
  176. CreateTube(AZ::Transform::CreateFromQuaternionAndTranslation(
  177. AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisX(), AZ::Constants::QuarterPi) *
  178. AZ::Quaternion::CreateFromAxisAngle(AZ::Vector3::CreateAxisY(), AZ::Constants::QuarterPi), AZ::Vector3(-10.0f, -10.0f, 0.0f)),
  179. 2.0f, entity);
  180. // set variable radius
  181. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  182. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  183. AZ::Aabb aabb;
  184. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  185. aabb, entity.GetId(), &LmbrCentral::ShapeComponentRequests::GetEncompassingAabb);
  186. EXPECT_THAT(aabb.GetMin(), IsClose(AZ::Vector3(-15.1213f, -14.5f, -4.5f)));
  187. EXPECT_THAT(aabb.GetMax(), IsClose(AZ::Vector3(-4.87867f, -5.5f, 4.5f)));
  188. }
  189. // variable radius and scale
  190. TEST_F(TubeShapeTest, GetAabb4)
  191. {
  192. AZ::Entity entity;
  193. CreateTube(AZ::Transform::CreateUniformScale(2.0f), 1.0f, entity);
  194. // set variable radius
  195. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  196. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  197. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  198. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, 3.0f);
  199. AZ::Aabb aabb;
  200. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  201. aabb, entity.GetId(), &LmbrCentral::ShapeComponentRequests::GetEncompassingAabb);
  202. EXPECT_THAT(aabb.GetMin(), IsClose(AZ::Vector3(-14.0f, -8.0f, -8.0f)));
  203. EXPECT_THAT(aabb.GetMax(), IsClose(AZ::Vector3(14.0f, 8.0f, 8.0f)));
  204. }
  205. // variable radius and scale
  206. TEST_F(TubeShapeTest, IsPointInsideSuccess1)
  207. {
  208. AZ::Entity entity;
  209. CreateTube(
  210. AZ::Transform::CreateTranslation(AZ::Vector3(37.0f, 36.0f, 32.0f)) *
  211. AZ::Transform::CreateUniformScale(2.0f), 1.5f, entity);
  212. // set variable radius
  213. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  214. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  215. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  216. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, 3.0f);
  217. bool inside;
  218. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  219. inside, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IsPointInside, AZ::Vector3(43.6f, 35.8f, 37.86f));
  220. EXPECT_TRUE(inside);
  221. }
  222. // variable radius and scale
  223. TEST_F(TubeShapeTest, IsPointInsideSuccess2)
  224. {
  225. AZ::Entity entity;
  226. CreateTube(
  227. AZ::Transform::CreateTranslation(AZ::Vector3(37.0f, 36.0f, 32.0f)) *
  228. AZ::Transform::CreateRotationZ(AZ::Constants::QuarterPi) *
  229. AZ::Transform::CreateRotationY(AZ::Constants::QuarterPi) *
  230. AZ::Transform::CreateUniformScale(1.5f), 1.5f, entity);
  231. // set variable radius
  232. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  233. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  234. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  235. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 1, 0.2f);
  236. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  237. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 2, 0.5f);
  238. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  239. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, 2.0f);
  240. bool inside;
  241. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  242. inside, entity.GetId(), &LmbrCentral::ShapeComponentRequests::IsPointInside, AZ::Vector3(37.6f, 36.76f, 34.0f));
  243. EXPECT_TRUE(inside);
  244. }
  245. // distance scaled - along length
  246. TEST_F(TubeShapeTest, DistanceFromPoint1)
  247. {
  248. AZ::Entity entity;
  249. CreateTube(
  250. AZ::Transform::CreateTranslation(AZ::Vector3(37.0f, 36.0f, 39.0f)) *
  251. AZ::Transform::CreateUniformScale(2.0f), 1.5f, entity);
  252. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  253. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  254. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  255. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 1, 0.2f);
  256. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  257. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 2, 0.5f);
  258. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  259. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, 2.0f);
  260. float distance;
  261. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  262. distance, entity.GetId(), &LmbrCentral::ShapeComponentRequests::DistanceFromPoint, AZ::Vector3(53.0f, 36.0f, 39.0f));
  263. EXPECT_NEAR(distance, 3.0f, 1e-2f);
  264. }
  265. // distance scaled - along length
  266. TEST_F(TubeShapeTest, DistanceFromPoint2)
  267. {
  268. AZ::Entity entity;
  269. CreateTube(
  270. AZ::Transform::CreateTranslation(AZ::Vector3(37.0f, 36.0f, 39.0f)) *
  271. AZ::Transform::CreateUniformScale(2.0f), 1.5f, entity);
  272. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  273. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  274. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  275. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 1, 0.2f);
  276. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  277. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 2, 0.5f);
  278. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  279. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, 2.0f);
  280. float distance;
  281. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  282. distance, entity.GetId(), &LmbrCentral::ShapeComponentRequests::DistanceFromPoint, AZ::Vector3(39.0f, 41.0f, 39.0f));
  283. EXPECT_NEAR(distance, 1.0f, 1e-2f);
  284. }
  285. // distance scaled - along length
  286. TEST_F(TubeShapeTest, DistanceFromPointInsideTubeIsZero)
  287. {
  288. AZ::Entity entity;
  289. CreateTube(
  290. AZ::Transform::CreateTranslation(AZ::Vector3(37.0f, 36.0f, 39.0f)) *
  291. AZ::Transform::CreateUniformScale(2.0f), 1.5f, entity);
  292. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  293. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, 1.0f);
  294. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  295. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 1, 0.2f);
  296. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  297. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 2, 0.5f);
  298. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  299. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, 2.0f);
  300. // The 3rd vertex located at (43, 36, 39) has a radius of 2 * (1.5 + 2), so a point that's 5 up on the y axis should
  301. // still be located inside the tube and have a distance of 0.
  302. float distance;
  303. LmbrCentral::ShapeComponentRequestsBus::EventResult(
  304. distance, entity.GetId(), &LmbrCentral::ShapeComponentRequests::DistanceFromPoint, AZ::Vector3(43.0f, 41.0f, 39.0f));
  305. EXPECT_NEAR(distance, 0.0f, 1e-2f);
  306. }
  307. TEST_F(TubeShapeTest, RadiiCannotBeNegativeFromVariableChange)
  308. {
  309. AZ::Entity entity;
  310. const float baseRadius = 1.0f;
  311. CreateTube(
  312. AZ::Transform::CreateTranslation(AZ::Vector3::CreateZero()), baseRadius, entity);
  313. // setting variable radius
  314. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  315. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, -2.0f);
  316. float totalRadius = 0.0f;
  317. LmbrCentral::TubeShapeComponentRequestsBus::EventResult(
  318. totalRadius, entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::GetTotalRadius,
  319. AZ::SplineAddress());
  320. float variableRadius = 0.0f;
  321. LmbrCentral::TubeShapeComponentRequestsBus::EventResult(
  322. variableRadius, entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::GetVariableRadius,
  323. 0);
  324. using ::testing::FloatEq;
  325. EXPECT_THAT(totalRadius, FloatEq(0.0f));
  326. EXPECT_THAT(variableRadius, FloatEq(-1.0f));
  327. }
  328. TEST_F(TubeShapeTest, RadiiCannotBeNegativeFromBaseChange)
  329. {
  330. AZ::Entity entity;
  331. const float baseRadius = 5.0f;
  332. CreateTube(
  333. AZ::Transform::CreateTranslation(AZ::Vector3::CreateZero()), baseRadius, entity);
  334. // setting variable radii
  335. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  336. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, -2.0f);
  337. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  338. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 1, -3.0f);
  339. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  340. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 2, -4.0f);
  341. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  342. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, -0.5f);
  343. // set base radius
  344. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  345. entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetRadius, 1.0f);
  346. // expected (clamped) values
  347. AZStd::pair<float, float> totalAndVariableRadii[] = {
  348. { 0.0f, -1.0f }, { 0.0f, -1.0f }, { 0.0f, -1.0f }, { 0.5f, -0.5f } };
  349. using ::testing::FloatEq;
  350. // verify all expected values for each vertex
  351. for (size_t vertIndex = 0; vertIndex < 4; ++vertIndex)
  352. {
  353. const auto radiis = totalAndVariableRadii[vertIndex];
  354. float totalRadius = 0.0f;
  355. LmbrCentral::TubeShapeComponentRequestsBus::EventResult(
  356. totalRadius, entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::GetTotalRadius,
  357. AZ::SplineAddress(vertIndex));
  358. float variableRadius = 0.0f;
  359. LmbrCentral::TubeShapeComponentRequestsBus::EventResult(
  360. variableRadius, entity.GetId(), &LmbrCentral::TubeShapeComponentRequestsBus::Events::GetVariableRadius,
  361. static_cast<int>(vertIndex));
  362. EXPECT_THAT(totalRadius, FloatEq(radiis.first));
  363. EXPECT_THAT(variableRadius, FloatEq(radiis.second));
  364. }
  365. }
  366. TEST_F(TubeShapeTest, ShapeHasThreadsafeGetSetCalls)
  367. {
  368. // Verify that setting values from one thread and querying values from multiple other threads in parallel produces
  369. // correct, consistent results.
  370. // Create our sphere centered at 0 with half our height as the radius.
  371. AZ::Entity entity;
  372. CreateTube(AZ::Transform::CreateTranslation(AZ::Vector3::CreateZero()), ShapeThreadsafeTest::ShapeHeight / 2.0f, entity);
  373. // Define the function for setting unimportant dimensions on the shape while queries take place.
  374. auto setDimensionFn = [](AZ::EntityId shapeEntityId, float minDimension, uint32_t dimensionVariance, float height)
  375. {
  376. // Set the radius back to the same value. This should have no effect.
  377. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  378. shapeEntityId, &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetRadius, height / 2.0f);
  379. // Set the end radii to random values. As long as we don't set the middle radii that describe the portion of the tube
  380. // that intersects the origin, changing these should have no effect on our test point distance.
  381. float radius = minDimension + aznumeric_cast<float>(rand() % dimensionVariance);
  382. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  383. shapeEntityId, &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 0, radius);
  384. radius = minDimension + aznumeric_cast<float>(rand() % dimensionVariance);
  385. LmbrCentral::TubeShapeComponentRequestsBus::Event(
  386. shapeEntityId, &LmbrCentral::TubeShapeComponentRequestsBus::Events::SetVariableRadius, 3, radius);
  387. };
  388. // Run the test, which will run multiple queries in parallel with each other and with the dimension-setting function.
  389. // The number of iterations is arbitrary - it's set high enough to catch most failures, but low enough to keep the test
  390. // time to a minimum.
  391. const int numIterations = 30000;
  392. ShapeThreadsafeTest::TestShapeGetSetCallsAreThreadsafe(entity, numIterations, setDimensionFn);
  393. }
  394. } // namespace UnitTest