SplineTests.cpp 97 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188
  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/Math/Spline.h>
  9. #include <AzCore/Math/Aabb.h>
  10. #include <AzCore/Math/Matrix3x3.h>
  11. #include <AzCore/Math/Vector3.h>
  12. #include <AzCore/UnitTest/TestTypes.h>
  13. #include <AZTestShared/Math/MathTestHelpers.h>
  14. using namespace AZ;
  15. namespace UnitTest
  16. {
  17. class MATH_SplineTest
  18. : public LeakDetectionFixture
  19. {
  20. public:
  21. void Linear_NearestAddressFromPosition()
  22. {
  23. {
  24. LinearSpline linearSpline;
  25. // backward C shaped spline (xy plane)
  26. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  27. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  28. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  29. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  30. {
  31. PositionSplineQueryResult posSplineQueryResult = linearSpline.GetNearestAddressPosition(Vector3(7.5f, 2.5f, 0.0f));
  32. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  33. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  34. }
  35. {
  36. PositionSplineQueryResult posSplineQueryResult = linearSpline.GetNearestAddressPosition(Vector3(-1.0f, -1.0f, 0.0f));
  37. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 0);
  38. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  39. }
  40. {
  41. PositionSplineQueryResult posSplineQueryResult = linearSpline.GetNearestAddressPosition(Vector3(-1.0f, 6.0f, 0.0f));
  42. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 2);
  43. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  44. }
  45. {
  46. PositionSplineQueryResult posSplineQueryResult = linearSpline.GetNearestAddressPosition(Vector3(2.5f, 6.0f, 0.0f));
  47. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 2);
  48. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  49. }
  50. }
  51. {
  52. LinearSpline linearSpline;
  53. linearSpline.SetClosed(true);
  54. // backward C shaped spline (xy plane)
  55. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  56. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  57. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  58. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  59. {
  60. PositionSplineQueryResult posSplineQueryResult = linearSpline.GetNearestAddressPosition(Vector3(-2.0f, 2.5f, 0.0f));
  61. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  62. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  63. }
  64. {
  65. PositionSplineQueryResult posSplineQueryResult = linearSpline.GetNearestAddressPosition(Vector3(-2.0f, 4.0f, 0.0f));
  66. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  67. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.2f, AZ::Constants::Tolerance);
  68. }
  69. }
  70. }
  71. void Linear_NearestAddressFromDirection()
  72. {
  73. {
  74. LinearSpline linearSpline;
  75. // backward C shaped spline (xy plane)
  76. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  77. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  78. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  79. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  80. {
  81. RaySplineQueryResult raySplineQueryResult = linearSpline.GetNearestAddressRay(Vector3(2.5f, -2.5f, 1.0f), Vector3(0.0f, 1.0f, 0.0f));
  82. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 0);
  83. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  84. }
  85. {
  86. RaySplineQueryResult raySplineQueryResult = linearSpline.GetNearestAddressRay(Vector3(2.5f, -10.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f));
  87. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 0);
  88. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  89. }
  90. {
  91. RaySplineQueryResult raySplineQueryResult = linearSpline.GetNearestAddressRay(Vector3(7.5f, 2.5f, 0.0f), Vector3(-1.0f, 1.0f, 0.0f));
  92. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  93. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  94. }
  95. {
  96. RaySplineQueryResult raySplineQueryResult = linearSpline.GetNearestAddressRay(Vector3(-2.5f, 2.5f, -1.0f), Vector3(1.0f, 1.0f, 0.0f));
  97. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 2);
  98. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  99. }
  100. }
  101. {
  102. LinearSpline linearSpline;
  103. linearSpline.SetClosed(true);
  104. // backward C shaped spline (xy plane)
  105. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  106. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  107. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  108. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  109. {
  110. RaySplineQueryResult raySplineQueryResult = linearSpline.GetNearestAddressRay(Vector3(-2.5f, 2.5f, 0.0f), Vector3(0.0f, 0.0f, -1.0f));
  111. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  112. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  113. }
  114. {
  115. RaySplineQueryResult raySplineQueryResult = linearSpline.GetNearestAddressRay(Vector3(-2.5f, 2.5f, 0.0f), Vector3(1.0f, 0.0f, 0.0f));
  116. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  117. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  118. }
  119. }
  120. }
  121. void Linear_AddressByDistance()
  122. {
  123. {
  124. LinearSpline linearSpline;
  125. // backward C shaped spline (xy plane)
  126. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  127. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  128. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  129. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  130. {
  131. SplineAddress splineAddress = linearSpline.GetAddressByDistance(7.5f);
  132. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  133. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  134. }
  135. {
  136. SplineAddress splineAddress = linearSpline.GetAddressByDistance(15.0f);
  137. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  138. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  139. }
  140. {
  141. SplineAddress splineAddress = linearSpline.GetAddressByDistance(0.0f);
  142. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  143. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  144. }
  145. {
  146. SplineAddress splineAddress = linearSpline.GetAddressByDistance(11.0f);
  147. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  148. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.2f, AZ::Constants::Tolerance);
  149. }
  150. {
  151. SplineAddress splineAddress = linearSpline.GetAddressByDistance(3.0f);
  152. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  153. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.6f, AZ::Constants::Tolerance);
  154. }
  155. {
  156. SplineAddress splineAddress = linearSpline.GetAddressByDistance(20.0f);
  157. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  158. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  159. }
  160. {
  161. SplineAddress splineAddress = linearSpline.GetAddressByDistance(-5.0f);
  162. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  163. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  164. }
  165. }
  166. {
  167. LinearSpline linearSpline;
  168. linearSpline.SetClosed(true);
  169. // backward C shaped spline (xy plane)
  170. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  171. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  172. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  173. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  174. {
  175. SplineAddress splineAddress = linearSpline.GetAddressByDistance(17.5f);
  176. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  177. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  178. }
  179. {
  180. SplineAddress splineAddress = linearSpline.GetAddressByDistance(20.0f);
  181. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  182. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  183. }
  184. }
  185. }
  186. void Linear_AddressByFraction()
  187. {
  188. {
  189. LinearSpline linearSpline;
  190. // backward C shaped spline (xy plane)
  191. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  192. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  193. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  194. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  195. {
  196. SplineAddress splineAddress = linearSpline.GetAddressByFraction(0.5f);
  197. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  198. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  199. }
  200. {
  201. SplineAddress splineAddress = linearSpline.GetAddressByFraction(1.0f);
  202. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  203. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  204. }
  205. {
  206. SplineAddress splineAddress = linearSpline.GetAddressByFraction(0.0f);
  207. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  208. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  209. }
  210. {
  211. SplineAddress splineAddress = linearSpline.GetAddressByFraction(0.6f);
  212. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  213. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.8f, AZ::Constants::Tolerance);
  214. }
  215. {
  216. SplineAddress splineAddress = linearSpline.GetAddressByFraction(0.2f);
  217. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  218. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.6f, AZ::Constants::Tolerance);
  219. }
  220. {
  221. SplineAddress splineAddress = linearSpline.GetAddressByFraction(1.5f);
  222. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  223. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  224. }
  225. {
  226. SplineAddress splineAddress = linearSpline.GetAddressByFraction(-0.5f);
  227. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  228. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  229. }
  230. }
  231. {
  232. LinearSpline linearSpline;
  233. linearSpline.SetClosed(true);
  234. // backward C shaped spline (xy plane)
  235. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  236. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  237. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  238. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  239. {
  240. SplineAddress splineAddress = linearSpline.GetAddressByFraction(0.5f);
  241. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  242. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  243. }
  244. {
  245. SplineAddress splineAddress = linearSpline.GetAddressByFraction(1.0f);
  246. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  247. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  248. }
  249. {
  250. SplineAddress splineAddress = linearSpline.GetAddressByFraction(0.8f);
  251. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  252. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.2f, AZ::Constants::Tolerance);
  253. }
  254. }
  255. }
  256. void Linear_GetPosition()
  257. {
  258. {
  259. LinearSpline linearSpline;
  260. // backward C shaped spline (xy plane)
  261. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  262. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  263. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  264. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  265. {
  266. Vector3 position = linearSpline.GetPosition(linearSpline.GetAddressByFraction(0.5f));
  267. EXPECT_THAT(position, IsClose(Vector3(5.0f, 2.5f, 0.0f)));
  268. }
  269. {
  270. Vector3 position = linearSpline.GetPosition(SplineAddress());
  271. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  272. }
  273. {
  274. Vector3 position = linearSpline.GetPosition(SplineAddress(linearSpline.GetSegmentCount() - 1, 1.0f));
  275. EXPECT_THAT(position, IsClose(Vector3(0.0f, 5.0f, 0.0f)));
  276. }
  277. {
  278. Vector3 position = linearSpline.GetPosition(linearSpline.GetAddressByDistance(4.0f));
  279. EXPECT_THAT(position, IsClose(Vector3(4.0f, 0.0f, 0.0f)));
  280. }
  281. {
  282. Vector3 position = linearSpline.GetPosition(SplineAddress(3, 0.0f));
  283. EXPECT_THAT(position, IsClose(Vector3(0.0f, 5.0f, 0.0f)));
  284. }
  285. {
  286. // out of bounds access (return position of last vertex - clamped)
  287. Vector3 position = linearSpline.GetPosition(SplineAddress(5, 0.0f));
  288. EXPECT_THAT(position, IsClose(Vector3(0.0f, 5.0f, 0.0f)));
  289. }
  290. }
  291. {
  292. LinearSpline linearSpline;
  293. linearSpline.SetClosed(true);
  294. // backward C shaped spline (xy plane)
  295. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  296. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  297. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  298. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  299. {
  300. Vector3 position = linearSpline.GetPosition(linearSpline.GetAddressByFraction(0.5f));
  301. EXPECT_THAT(position, IsClose(Vector3(5.0f, 5.0f, 0.0f)));
  302. }
  303. {
  304. Vector3 position = linearSpline.GetPosition(linearSpline.GetAddressByDistance(20.0f));
  305. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  306. }
  307. {
  308. Vector3 position = linearSpline.GetPosition(linearSpline.GetAddressByDistance(18.0f));
  309. EXPECT_THAT(position, IsClose(Vector3(0.0f, 2.0f, 0.0f)));
  310. }
  311. {
  312. // out of bounds access (return position of last/first vertex - clamped)
  313. Vector3 position = linearSpline.GetPosition(SplineAddress(5, 0.0f));
  314. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  315. }
  316. }
  317. }
  318. void Linear_GetNormal()
  319. {
  320. {
  321. LinearSpline linearSpline;
  322. // n shaped spline (xy plane)
  323. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  324. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  325. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  326. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  327. {
  328. Vector3 normal = linearSpline.GetNormal(linearSpline.GetAddressByFraction(0.5f));
  329. EXPECT_THAT(normal, IsClose(Vector3(0.0f, 1.0f, 0.0f)));
  330. }
  331. {
  332. Vector3 normal = linearSpline.GetNormal(SplineAddress());
  333. EXPECT_THAT(normal, IsClose(Vector3(-1.0f, 0.0f, 0.0f)));
  334. }
  335. {
  336. Vector3 normal = linearSpline.GetNormal(SplineAddress(linearSpline.GetSegmentCount() - 1, 1.0f));
  337. EXPECT_THAT(normal, IsClose(Vector3(1.0f, 0.0f, 0.0f)));
  338. }
  339. {
  340. Vector3 normal = linearSpline.GetNormal(linearSpline.GetAddressByDistance(4.0f));
  341. EXPECT_THAT(normal, IsClose(Vector3(-1.0f, 0.0f, 0.0f)));
  342. }
  343. {
  344. // out of bounds access (return normal of last vertex - clamped)
  345. Vector3 normal = linearSpline.GetNormal(SplineAddress(5, 0.0f));
  346. EXPECT_THAT(normal, IsClose(Vector3(1.0f, 0.0f, 0.0f)));
  347. }
  348. }
  349. {
  350. LinearSpline linearSpline;
  351. // n shape spline (yz plane)
  352. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  353. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 5.0f));
  354. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 5.0f));
  355. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  356. Vector3 normal = linearSpline.GetNormal(linearSpline.GetAddressByDistance(4.0f));
  357. EXPECT_THAT(normal, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  358. }
  359. {
  360. LinearSpline linearSpline;
  361. linearSpline.SetClosed(true);
  362. // n shaped spline (xy plane)
  363. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  364. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  365. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  366. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  367. {
  368. Vector3 normal = linearSpline.GetNormal(linearSpline.GetAddressByDistance(20.0f));
  369. EXPECT_THAT(normal, IsClose(Vector3(0.0f, -1.0f, 0.0f)));
  370. }
  371. {
  372. Vector3 normal = linearSpline.GetNormal(linearSpline.GetAddressByFraction(0.8f));
  373. EXPECT_THAT(normal, IsClose(Vector3(0.0f, -1.0f, 0.0f)));
  374. }
  375. }
  376. }
  377. void Linear_GetTangent()
  378. {
  379. {
  380. LinearSpline linearSpline;
  381. // backward C shaped spline (xy plane)
  382. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  383. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  384. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  385. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  386. {
  387. Vector3 tangent = linearSpline.GetTangent(linearSpline.GetAddressByFraction(0.5f));
  388. EXPECT_THAT(tangent, IsClose(Vector3(0.0f, 1.0f, 0.0f)));
  389. }
  390. {
  391. Vector3 tangent = linearSpline.GetTangent(SplineAddress());
  392. EXPECT_THAT(tangent, IsClose(Vector3(1.0f, 0.0f, 0.0f)));
  393. }
  394. {
  395. Vector3 tangent = linearSpline.GetTangent(SplineAddress(linearSpline.GetSegmentCount() - 1, 1.0f));
  396. EXPECT_THAT(tangent, IsClose(Vector3(-1.0f, 0.0f, 0.0f)));
  397. }
  398. {
  399. Vector3 tangent = linearSpline.GetTangent(linearSpline.GetAddressByDistance(4.0f));
  400. EXPECT_THAT(tangent, IsClose(Vector3(1.0f, 0.0f, 0.0f)));
  401. }
  402. }
  403. {
  404. LinearSpline linearSpline;
  405. linearSpline.SetClosed(true);
  406. // backward C shaped spline (xy plane)
  407. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  408. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  409. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  410. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  411. {
  412. Vector3 tangent = linearSpline.GetTangent(SplineAddress(linearSpline.GetSegmentCount() - 1, 1.0f));
  413. EXPECT_THAT(tangent, IsClose(Vector3(0.0f, -1.0f, 0.0f)));
  414. }
  415. {
  416. Vector3 tangent = linearSpline.GetTangent(linearSpline.GetAddressByDistance(16.0f));
  417. EXPECT_THAT(tangent, IsClose(Vector3(0.0f, -1.0f, 0.0f)));
  418. }
  419. }
  420. }
  421. void Linear_Length()
  422. {
  423. {
  424. LinearSpline linearSpline;
  425. // backward C shaped spline (xy plane)
  426. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  427. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  428. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  429. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  430. {
  431. float splineLength = linearSpline.GetSplineLength();
  432. EXPECT_NEAR(splineLength, 15.0f, AZ::Constants::Tolerance);
  433. }
  434. {
  435. float segmentLength = linearSpline.GetSegmentLength(0);
  436. EXPECT_NEAR(segmentLength, 5.0f, AZ::Constants::Tolerance);
  437. }
  438. {
  439. float segmentLength = linearSpline.GetSegmentLength(2);
  440. EXPECT_NEAR(segmentLength, 5.0f, AZ::Constants::Tolerance);
  441. }
  442. {
  443. float segmentLength = linearSpline.GetSegmentLength(4);
  444. EXPECT_NEAR(segmentLength, 0.0f, AZ::Constants::Tolerance);
  445. }
  446. }
  447. {
  448. LinearSpline linearSpline;
  449. // backward C shaped spline (xy plane)
  450. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  451. linearSpline.m_vertexContainer.AddVertex(Vector3(2.0f, 0.0f, 0.0f));
  452. linearSpline.m_vertexContainer.AddVertex(Vector3(2.0f, 3.0f, 0.0f));
  453. linearSpline.m_vertexContainer.AddVertex(Vector3(4.0f, 3.0f, 0.0f));
  454. linearSpline.m_vertexContainer.AddVertex(Vector3(4.0f, 10.0f, 0.0f));
  455. {
  456. float splineLength = linearSpline.GetSplineLength();
  457. EXPECT_NEAR(splineLength, 14.0f, AZ::Constants::Tolerance);
  458. }
  459. {
  460. float segmentLength = linearSpline.GetSegmentLength(0);
  461. EXPECT_NEAR(segmentLength, 2.0f, AZ::Constants::Tolerance);
  462. }
  463. {
  464. float segmentLength = linearSpline.GetSegmentLength(3);
  465. EXPECT_NEAR(segmentLength, 7.0f, AZ::Constants::Tolerance);
  466. }
  467. }
  468. {
  469. LinearSpline linearSpline;
  470. linearSpline.SetClosed(true);
  471. // backward C shaped spline (xy plane)
  472. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  473. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  474. linearSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  475. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  476. {
  477. float splineLength = linearSpline.GetSplineLength();
  478. EXPECT_NEAR(splineLength, 20.0f, AZ::Constants::Tolerance);
  479. }
  480. {
  481. float segmentLength = linearSpline.GetSegmentLength(3);
  482. EXPECT_NEAR(segmentLength, 5.0f, AZ::Constants::Tolerance);
  483. }
  484. }
  485. {
  486. LinearSpline linearSpline;
  487. linearSpline.SetClosed(true);
  488. // single line (y axis)
  489. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  490. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  491. {
  492. float splineLength = linearSpline.GetSplineLength();
  493. EXPECT_NEAR(splineLength, 20.0f, AZ::Constants::Tolerance);
  494. }
  495. {
  496. float segmentLength = linearSpline.GetSegmentLength(1);
  497. EXPECT_NEAR(segmentLength, 10.0f, AZ::Constants::Tolerance);
  498. }
  499. }
  500. }
  501. void Linear_Aabb()
  502. {
  503. {
  504. LinearSpline linearSpline;
  505. // slight n curve spline (xy plane)
  506. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  507. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  508. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  509. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  510. AZ::Aabb aabb;
  511. linearSpline.GetAabb(aabb);
  512. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  513. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f, 10.0f, 0.0f)));
  514. }
  515. {
  516. LinearSpline linearSpline;
  517. linearSpline.SetClosed(true);
  518. // slight n curve spline (xy plane)
  519. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  520. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  521. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  522. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  523. AZ::Aabb aabb;
  524. linearSpline.GetAabb(aabb);
  525. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  526. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f, 10.0f, 0.0f)));
  527. }
  528. {
  529. LinearSpline linearSpline;
  530. AZ::Transform translation = AZ::Transform::CreateFromMatrix3x3AndTranslation(Matrix3x3::CreateIdentity(), Vector3(25.0f, 25.0f, 0.0f));
  531. // slight n curve spline (xy plane)
  532. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  533. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  534. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  535. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  536. AZ::Aabb aabb;
  537. linearSpline.GetAabb(aabb, translation);
  538. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(25.0f, 25.0f, 0.0f)));
  539. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(35.0f, 35.0f, 0.0f)));
  540. }
  541. }
  542. void Linear_GetLength()
  543. {
  544. {
  545. LinearSpline spline;
  546. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  547. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  548. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 20.0f, 0.0f));
  549. auto distance = spline.GetLength(AZ::SplineAddress(1, 0.5f));
  550. EXPECT_NEAR(distance, 15.0f, 1e-4);
  551. distance = spline.GetLength(AZ::SplineAddress(0, 0.0f));
  552. EXPECT_NEAR(distance, 0.0f, 1e-4);
  553. distance = spline.GetLength(AZ::SplineAddress(1, 1.0f));
  554. EXPECT_NEAR(distance, 20.0f, 1e-4);
  555. distance = spline.GetLength(AZ::SplineAddress(5, 1.0f));
  556. EXPECT_NEAR(distance, spline.GetSplineLength(), 1e-4);
  557. }
  558. {
  559. LinearSpline spline;
  560. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  561. spline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  562. spline.m_vertexContainer.AddVertex(Vector3(20.0f, 20.0f, 10.0f));
  563. spline.m_vertexContainer.AddVertex(Vector3(10.0f, 15.0f, -10.0f));
  564. float length = spline.GetSplineLength();
  565. for (float t = 0.0f; t <= length; t += 0.5f)
  566. {
  567. auto result = spline.GetLength(spline.GetAddressByDistance(t));
  568. EXPECT_NEAR(result, t, 1e-4);
  569. }
  570. }
  571. {
  572. LinearSpline spline;
  573. auto result = spline.GetLength(AZ::SplineAddress(0, 0.0f));
  574. EXPECT_NEAR(result, 0.0f, 1e-4);
  575. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  576. result = spline.GetLength(AZ::SplineAddress(0, 0.0f));
  577. EXPECT_NEAR(result, 0.0f, 1e-4);
  578. }
  579. }
  580. void CatmullRom_NearestAddressFromPosition()
  581. {
  582. {
  583. CatmullRomSpline catmullRomSpline;
  584. // slight backward C curve spline (xy plane)
  585. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  586. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  587. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  588. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  589. {
  590. PositionSplineQueryResult posSplineQueryResult = catmullRomSpline.GetNearestAddressPosition(Vector3(7.5f, 2.5f, 0.0f));
  591. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  592. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  593. }
  594. {
  595. PositionSplineQueryResult posSplineQueryResult = catmullRomSpline.GetNearestAddressPosition(Vector3(-1.0f, -1.0f, 0.0f));
  596. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  597. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  598. }
  599. {
  600. PositionSplineQueryResult posSplineQueryResult = catmullRomSpline.GetNearestAddressPosition(Vector3(-1.0f, 6.0f, 0.0f));
  601. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  602. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  603. }
  604. {
  605. PositionSplineQueryResult posSplineQueryResult = catmullRomSpline.GetNearestAddressPosition(Vector3(2.5f, 6.0f, 0.0f));
  606. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  607. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  608. }
  609. }
  610. {
  611. CatmullRomSpline catmullRomSpline;
  612. catmullRomSpline.SetClosed(true);
  613. // slight n curve spline (xy plane)
  614. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  615. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  616. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  617. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  618. {
  619. PositionSplineQueryResult posSplineQueryResult = catmullRomSpline.GetNearestAddressPosition(Vector3(5.0f, -2.5f, 0.0f));
  620. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  621. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  622. }
  623. }
  624. }
  625. void CatmullRom_NearestAddressFromDirection()
  626. {
  627. {
  628. CatmullRomSpline catmullRomSpline;
  629. // slight backward C curve spline (xy plane)
  630. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  631. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  632. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  633. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  634. {
  635. RaySplineQueryResult raySplineQueryResult = catmullRomSpline.GetNearestAddressRay(Vector3(2.5f, -2.5f, 1.0f), Vector3(0.0f, 1.0f, 0.0f));
  636. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  637. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  638. }
  639. {
  640. RaySplineQueryResult raySplineQueryResult = catmullRomSpline.GetNearestAddressRay(Vector3(2.5f, -10.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f));
  641. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  642. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  643. }
  644. {
  645. RaySplineQueryResult raySplineQueryResult = catmullRomSpline.GetNearestAddressRay(Vector3(7.5f, 2.5f, 0.0f), Vector3(-1.0f, 0.0f, 0.0f));
  646. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  647. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  648. }
  649. {
  650. RaySplineQueryResult raySplineQueryResult = catmullRomSpline.GetNearestAddressRay(Vector3(-2.5f, 7.5f, -1.0f), Vector3(1.0f, 0.0f, 0.0f));
  651. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  652. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  653. }
  654. }
  655. {
  656. CatmullRomSpline catmullRomSpline;
  657. catmullRomSpline.SetClosed(true);
  658. // slight backward C curve spline (xy plane)
  659. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  660. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 0.0f, 0.0f));
  661. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  662. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 5.0f, 0.0f));
  663. {
  664. RaySplineQueryResult raySplineQueryResult = catmullRomSpline.GetNearestAddressRay(Vector3(-2.5f, 2.5f, 0.0f), Vector3(0.0f, 1.0f, 0.0f));
  665. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  666. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  667. }
  668. }
  669. }
  670. /*
  671. Catmull-Rom Sample Points - (0.0f, 0.0f, 0.0f), (0.0f, 10.0f, 0.0f), (10.0f, 10.0f, 0.0f), (10.0f, 0.0f, 0.0f)
  672. (calculated using https://www.desmos.com/calculator/552cpvzfxw)
  673. t = 0 pos = (0.0f, 10.0f, 0.0f)
  674. t = 0.125 pos = (0.83984375.0f, 10.546875.0f, 0.0f)
  675. t = 0.25 pos = (2.03125.0f, 10.9375.0f, 0.0f)
  676. t = 0.375 pos = (3.45703125.0f, 11.171875.0f, 0.0f)
  677. t = 0.5 pos = (5.0.0f, 11.25.0f, 0.0f)
  678. t = 0.625 pos = (6.54296875.0f, 11.171875.0f, 0.0f)
  679. t = 0.75 pos = (7.96875.0f, 10.9375.0f, 0.0f)
  680. t = 0.875 pos = (9.16015625.0f, 10.546875.0f, 0.0f)
  681. t = 1 pos = (10.0f, 10.0f)
  682. delta = (0.83984375.0f, 0.546875.0f, 0.0f) length = 1.00220
  683. delta = (1.19140625.0f, 0.390625.0f, 0.0f) length = 1.25381
  684. delta = (1.42578125.0f, 0.234375.0f, 0.0f) length = 1.44492
  685. delta = (1.54296875.0f, 0.078125.0f, 0.0f) length = 1.54495
  686. delta = (1.54296875.0f, -0.078125.0f, 0.0f) length = 1.54495
  687. delta = (1.42578125.0f, -0.234375.0f, 0.0f) length = 1.44492
  688. delta = (1.19140625.0f, -0.390625.0f, 0.0f) length = 1.25381
  689. delta = (0.83984375.0f, -0.546875.0f, 0.0f) length = 1.00220
  690. total = 10.49176
  691. */
  692. void CatmullRom_AddressByDistance()
  693. {
  694. {
  695. CatmullRomSpline catmullRomSpline;
  696. // slight n curve spline (xy plane)
  697. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  698. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  699. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  700. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  701. {
  702. SplineAddress splineAddress = catmullRomSpline.GetAddressByDistance(20.0f);
  703. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  704. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  705. }
  706. {
  707. SplineAddress splineAddress = catmullRomSpline.GetAddressByDistance(0.0f);
  708. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  709. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  710. }
  711. {
  712. // note: spline length is approx 10.49176
  713. SplineAddress splineAddress = catmullRomSpline.GetAddressByDistance(5.24588f);
  714. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  715. EXPECT_NEAR(0.5f, splineAddress.m_segmentFraction, 0.0001f);
  716. }
  717. {
  718. SplineAddress splineAddress = catmullRomSpline.GetAddressByDistance(-10.0f);
  719. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  720. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  721. }
  722. }
  723. {
  724. CatmullRomSpline catmullRomSpline;
  725. catmullRomSpline.SetClosed(true);
  726. // slight n curve spline (xy plane)
  727. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  728. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  729. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  730. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  731. {
  732. SplineAddress splineAddress = catmullRomSpline.GetAddressByDistance(50.0f);
  733. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  734. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  735. }
  736. {
  737. SplineAddress splineAddress = catmullRomSpline.GetAddressByDistance(0.0f);
  738. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  739. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  740. }
  741. }
  742. }
  743. void CatmullRom_AddressByFraction()
  744. {
  745. {
  746. CatmullRomSpline catmullRomSpline;
  747. // slight n curve spline (xy plane)
  748. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  749. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  750. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  751. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  752. {
  753. SplineAddress splineAddress = catmullRomSpline.GetAddressByFraction(0.0f);
  754. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  755. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  756. }
  757. {
  758. SplineAddress splineAddress = catmullRomSpline.GetAddressByFraction(1.0f);
  759. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  760. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  761. }
  762. {
  763. SplineAddress splineAddress = catmullRomSpline.GetAddressByFraction(0.5f);
  764. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  765. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  766. }
  767. {
  768. SplineAddress splineAddress = catmullRomSpline.GetAddressByFraction(0.75f);
  769. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  770. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.75f, AZ::Constants::Tolerance);
  771. }
  772. }
  773. {
  774. CatmullRomSpline catmullRomSpline;
  775. catmullRomSpline.SetClosed(true);
  776. // slight n curve spline (xy plane)
  777. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  778. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  779. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  780. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  781. {
  782. SplineAddress splineAddress = catmullRomSpline.GetAddressByFraction(0.0f);
  783. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  784. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  785. }
  786. {
  787. SplineAddress splineAddress = catmullRomSpline.GetAddressByFraction(1.0f);
  788. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  789. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  790. }
  791. {
  792. SplineAddress splineAddress = catmullRomSpline.GetAddressByFraction(0.5f);
  793. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  794. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  795. }
  796. }
  797. }
  798. void CatmullRom_GetPosition()
  799. {
  800. {
  801. CatmullRomSpline catmullRomSpline;
  802. // slight n curve spline (xy plane)
  803. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  804. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  805. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  806. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  807. {
  808. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(1, 0.125f));
  809. EXPECT_THAT(position, IsClose(Vector3(0.83984375f, 10.546875f, 0.0f)));
  810. }
  811. {
  812. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(1, 0.625f));
  813. EXPECT_THAT(position, IsClose(Vector3(6.54296875f, 11.171875f, 0.0f)));
  814. }
  815. {
  816. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(3, 0.5f));
  817. EXPECT_THAT(position, IsClose(Vector3(10.0f, 10.0f, 0.0f)));
  818. }
  819. {
  820. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(0, 0.0f));
  821. EXPECT_THAT(position, IsClose(Vector3(0.0f, 10.0f, 0.0f)));
  822. }
  823. {
  824. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(1, 0.0f));
  825. EXPECT_THAT(position, IsClose(Vector3(0.0f, 10.0f, 0.0f)));
  826. }
  827. {
  828. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(2, 0.0f));
  829. EXPECT_THAT(position, IsClose(Vector3(10.0f, 10.0f, 0.0f)));
  830. }
  831. {
  832. // out of bounds access (return position of last vertex that is not a control point - clamped)
  833. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(5, 0.0f));
  834. EXPECT_THAT(position, IsClose(Vector3(10.0f, 10.0f, 0.0f)));
  835. }
  836. }
  837. {
  838. CatmullRomSpline catmullRomSpline;
  839. catmullRomSpline.SetClosed(true);
  840. // slight n curve spline (xy plane)
  841. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  842. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  843. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  844. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  845. {
  846. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(1, 0.125f));
  847. EXPECT_THAT(position, IsClose(Vector3(0.83984375f, 10.546875f, 0.0f)));
  848. }
  849. {
  850. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(1, 0.625f));
  851. EXPECT_THAT(position, IsClose(Vector3(6.54296875f, 11.171875f, 0.0f)));
  852. }
  853. {
  854. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(0, 0.0f));
  855. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  856. }
  857. {
  858. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(3, 1.0f));
  859. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  860. }
  861. {
  862. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(0, 0.5f));
  863. EXPECT_THAT(position, IsClose(Vector3(-1.25f, 5.0f, 0.0f)));
  864. }
  865. {
  866. // out of bounds access (return position of first/last vertex - clamped)
  867. Vector3 position = catmullRomSpline.GetPosition(SplineAddress(5, 0.0f));
  868. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  869. }
  870. }
  871. }
  872. void CatmullRom_GetNormal()
  873. {
  874. {
  875. CatmullRomSpline catmullRomSpline;
  876. // slight n curve spline (xy plane)
  877. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  878. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  879. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  880. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  881. {
  882. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress());
  883. EXPECT_THAT(normal, IsClose(Vector3(-5.0f, 5.0f, 0.0f).GetNormalized()));
  884. }
  885. {
  886. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(1, 0.0f));
  887. EXPECT_THAT(normal, IsClose(Vector3(-5.0f, 5.0f, 0.0f).GetNormalized()));
  888. }
  889. {
  890. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(1, 1.0f));
  891. EXPECT_THAT(normal, IsClose(Vector3(5.0f, 5.0f, 0.0f).GetNormalized()));
  892. }
  893. {
  894. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(1, 0.5f));
  895. EXPECT_THAT(normal, IsClose(Vector3(0.0f, 12.5f, 0.0f).GetNormalized()));
  896. }
  897. {
  898. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(2, 0.0f));
  899. EXPECT_THAT(normal, IsClose(Vector3(5.0f, 5.0f, 0.0f).GetNormalized()));
  900. }
  901. {
  902. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(3, 0.5f));
  903. EXPECT_THAT(normal, IsClose(Vector3(5.0f, 5.0f, 0.0f).GetNormalized()));
  904. }
  905. {
  906. // out of bounds access (return normal of last vertex that is not a control point - clamped)
  907. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(5, 0.0f));
  908. EXPECT_THAT(normal, IsClose(Vector3(5.0f, 5.0f, 0.0f).GetNormalized()));
  909. }
  910. }
  911. {
  912. CatmullRomSpline catmullRomSpline;
  913. catmullRomSpline.SetClosed(true);
  914. // slight n curve spline (xy plane)
  915. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  916. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  917. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  918. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  919. {
  920. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress());
  921. EXPECT_THAT(normal, IsClose(Vector3(-5.0f, -5.0f, 0.0f).GetNormalized()));
  922. }
  923. {
  924. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(1, 0.5f));
  925. EXPECT_THAT(normal, IsClose(Vector3(0.0f, 1.0f, 0.0f)));
  926. }
  927. {
  928. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(3, 0.5f));
  929. EXPECT_THAT(normal, IsClose(Vector3(0.0f, -1.0f, 0.0f)));
  930. }
  931. {
  932. // out of bounds access (return normal of last vertex that is not a control point - clamped)
  933. Vector3 normal = catmullRomSpline.GetNormal(SplineAddress(5, 0.0f));
  934. EXPECT_THAT(normal, IsClose(Vector3(-5.0f, -5.0f, 0.0f).GetNormalized()));
  935. }
  936. }
  937. }
  938. void CatmullRom_GetTangent()
  939. {
  940. {
  941. CatmullRomSpline catmullRomSpline;
  942. // slight n curve spline (xy plane)
  943. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  944. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  945. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  946. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  947. {
  948. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(1, 0.0f));
  949. EXPECT_THAT(tangent, IsClose(Vector3(5.0f, 5.0f, 0.0f).GetNormalized()));
  950. }
  951. {
  952. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(1, 1.0f));
  953. EXPECT_THAT(tangent, IsClose(Vector3(5.0f, -5.0f, 0.0f).GetNormalized()));
  954. }
  955. {
  956. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(1, 0.5f));
  957. EXPECT_THAT(tangent, IsClose(Vector3(12.5f, 0.0f, 0.0f).GetNormalized()));
  958. }
  959. {
  960. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(2, 0.0f));
  961. EXPECT_THAT(tangent, IsClose(Vector3(5.0f, -5.0f, 0.0f).GetNormalized()));
  962. }
  963. {
  964. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(3, 0.5f));
  965. EXPECT_THAT(tangent, IsClose(Vector3(5.0f, -5.0f, 0.0f).GetNormalized()));
  966. }
  967. }
  968. {
  969. CatmullRomSpline catmullRomSpline;
  970. catmullRomSpline.SetClosed(true);
  971. // slight n curve spline (xy plane)
  972. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  973. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  974. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  975. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  976. {
  977. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(3, 0.5f));
  978. EXPECT_THAT(tangent, IsClose(Vector3(-1.0f, 0.0f, 0.0f)));
  979. }
  980. {
  981. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(1, 0.5f));
  982. EXPECT_THAT(tangent, IsClose(Vector3(1.0f, 0.0f, 0.0f)));
  983. }
  984. {
  985. Vector3 tangent = catmullRomSpline.GetTangent(SplineAddress(3, 1.0f));
  986. EXPECT_THAT(tangent, IsClose(Vector3(-5.0f, 5.0f, 0.0f).GetNormalized()));
  987. }
  988. }
  989. }
  990. void CatmullRom_Length()
  991. {
  992. {
  993. CatmullRomSpline catmullRomSpline;
  994. // slight n curve spline (xy plane)
  995. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  996. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  997. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  998. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  999. {
  1000. float length = catmullRomSpline.GetSplineLength();
  1001. EXPECT_NEAR(10.49176f, length, 0.0001f);
  1002. }
  1003. {
  1004. float length = catmullRomSpline.GetSegmentLength(0);
  1005. EXPECT_NEAR(length, 0.0f, AZ::Constants::Tolerance);
  1006. }
  1007. {
  1008. float length = catmullRomSpline.GetSegmentLength(1);
  1009. EXPECT_NEAR(10.49176f, length, 0.0001f);
  1010. }
  1011. {
  1012. float length = catmullRomSpline.GetSegmentLength((size_t)-1);
  1013. EXPECT_NEAR(length, 0.0f, AZ::Constants::Tolerance);
  1014. }
  1015. {
  1016. float length = catmullRomSpline.GetSegmentLength(10);
  1017. EXPECT_NEAR(length, 0.0f, AZ::Constants::Tolerance);
  1018. }
  1019. }
  1020. {
  1021. CatmullRomSpline catmullRomSpline;
  1022. catmullRomSpline.SetClosed(true);
  1023. // slight n curve spline (xy plane)
  1024. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1025. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1026. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1027. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1028. {
  1029. float length = catmullRomSpline.GetSplineLength();
  1030. EXPECT_NEAR(41.96704, length, 0.0001f);
  1031. }
  1032. {
  1033. float length = catmullRomSpline.GetSegmentLength(3);
  1034. EXPECT_NEAR(10.49176f, length, 0.0001f);
  1035. }
  1036. }
  1037. }
  1038. void CatmullRom_Aabb()
  1039. {
  1040. {
  1041. CatmullRomSpline catmullRomSpline;
  1042. // slight n curve spline (xy plane)
  1043. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1044. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1045. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1046. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1047. AZ::Aabb aabb;
  1048. catmullRomSpline.GetAabb(aabb);
  1049. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(0.0f, 10.0f, 0.0f)));
  1050. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(10.0f, 11.25f, 0.0f)));
  1051. }
  1052. {
  1053. CatmullRomSpline catmullRomSpline;
  1054. catmullRomSpline.SetClosed(true);
  1055. // slight n curve spline (xy plane)
  1056. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1057. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1058. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1059. catmullRomSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1060. AZ::Aabb aabb;
  1061. catmullRomSpline.GetAabb(aabb);
  1062. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.25f, -1.25f, 0.0f)));
  1063. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(11.25f, 11.25f, 0.0f)));
  1064. }
  1065. }
  1066. void CatmullRom_GetLength()
  1067. {
  1068. {
  1069. CatmullRomSpline spline;
  1070. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1071. spline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1072. spline.m_vertexContainer.AddVertex(Vector3(20.0f, 20.0f, 10.0f));
  1073. spline.m_vertexContainer.AddVertex(Vector3(10.0f, 15.0f, -10.0f));
  1074. float length = spline.GetSplineLength();
  1075. for (float t = 0.0f; t <= length; t += 0.5f)
  1076. {
  1077. auto result = spline.GetLength(spline.GetAddressByDistance(t));
  1078. EXPECT_NEAR(result, t, 1e-4);
  1079. }
  1080. auto distance = spline.GetLength(AZ::SplineAddress(3, 0.5f));
  1081. EXPECT_NEAR(distance, spline.GetSplineLength(), 1e-4);
  1082. distance = spline.GetLength(AZ::SplineAddress(4, 1.0f));
  1083. EXPECT_NEAR(distance, spline.GetSplineLength(), 1e-4);
  1084. distance = spline.GetLength(AZ::SplineAddress(5, 1.0f));
  1085. EXPECT_NEAR(distance, spline.GetSplineLength(), 1e-4);
  1086. }
  1087. {
  1088. CatmullRomSpline spline;
  1089. auto result = spline.GetLength(AZ::SplineAddress(0, 0.0f));
  1090. EXPECT_NEAR(result, 0.0f, 1e-4);
  1091. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1092. result = spline.GetLength(AZ::SplineAddress(0, 0.0f));
  1093. EXPECT_NEAR(result, 0.0f, 1e-4);
  1094. }
  1095. {
  1096. CatmullRomSpline spline;
  1097. spline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1098. spline.m_vertexContainer.AddVertex(Vector3(5.0f, 5.0f, 0.0f));
  1099. auto result = spline.GetLength(AZ::SplineAddress(0, 0.0f));
  1100. EXPECT_NEAR(result, 0.0f, 1e-4);
  1101. }
  1102. }
  1103. void Bezier_NearestAddressFromPosition()
  1104. {
  1105. {
  1106. BezierSpline bezierSpline;
  1107. // n shape (xy plane)
  1108. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1109. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1110. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1111. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1112. {
  1113. PositionSplineQueryResult posSplineQueryResult = bezierSpline.GetNearestAddressPosition(Vector3(-1.0f, -1.0f, 0.0f));
  1114. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 0);
  1115. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  1116. }
  1117. {
  1118. PositionSplineQueryResult posSplineQueryResult = bezierSpline.GetNearestAddressPosition(Vector3(5.0f, 12.0f, 0.0f));
  1119. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  1120. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  1121. }
  1122. {
  1123. PositionSplineQueryResult posSplineQueryResult = bezierSpline.GetNearestAddressPosition(Vector3(12.0f, -1.0f, 0.0f));
  1124. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 2);
  1125. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  1126. }
  1127. }
  1128. {
  1129. BezierSpline bezierSpline;
  1130. bezierSpline.SetClosed(true);
  1131. // n shape (xy plane)
  1132. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1133. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1134. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1135. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1136. {
  1137. PositionSplineQueryResult posSplineQueryResult = bezierSpline.GetNearestAddressPosition(Vector3(5.0f, -12.0f, 0.0f));
  1138. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  1139. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  1140. }
  1141. {
  1142. PositionSplineQueryResult posSplineQueryResult = bezierSpline.GetNearestAddressPosition(Vector3(12.0f, 12.0f, 0.0f));
  1143. EXPECT_EQ(posSplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  1144. EXPECT_NEAR(posSplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  1145. }
  1146. }
  1147. }
  1148. void Bezier_NearestAddressFromDirection()
  1149. {
  1150. {
  1151. BezierSpline bezierSpline;
  1152. // n shape (xy plane)
  1153. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1154. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1155. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1156. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1157. {
  1158. RaySplineQueryResult raySplineQueryResult = bezierSpline.GetNearestAddressRay(Vector3(-1.0f, -1.0f, 0.0f), Vector3(-1.0f, 1.0f, 0.0f));
  1159. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 0);
  1160. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  1161. }
  1162. {
  1163. RaySplineQueryResult raySplineQueryResult = bezierSpline.GetNearestAddressRay(Vector3(5.0f, 12.0f, 0.0f), Vector3(0.0f, -1.0f, 0.0f));
  1164. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 1);
  1165. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  1166. }
  1167. {
  1168. RaySplineQueryResult raySplineQueryResult = bezierSpline.GetNearestAddressRay(Vector3(12.0f, -1.0f, 0.0f), Vector3(1.0f, 1.0f, 0.0f));
  1169. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 2);
  1170. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  1171. }
  1172. }
  1173. {
  1174. BezierSpline bezierSpline;
  1175. bezierSpline.SetClosed(true);
  1176. // n shape (xy plane)
  1177. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1178. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1179. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1180. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1181. {
  1182. RaySplineQueryResult raySplineQueryResult = bezierSpline.GetNearestAddressRay(Vector3(-10.0f, -10.0f, 0.0f), Vector3(1.0f, 0.0f, 0.0f));
  1183. EXPECT_EQ(raySplineQueryResult.m_splineAddress.m_segmentIndex, 3);
  1184. EXPECT_NEAR(raySplineQueryResult.m_splineAddress.m_segmentFraction, 0.5f, AZ::Constants::Tolerance);
  1185. }
  1186. }
  1187. }
  1188. void Bezier_AddressByDistance()
  1189. {
  1190. {
  1191. BezierSpline bezierSpline;
  1192. // n shape (xy plane)
  1193. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1194. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1195. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1196. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1197. {
  1198. SplineAddress splineAddress = bezierSpline.GetAddressByDistance(0.0f);
  1199. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  1200. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  1201. }
  1202. {
  1203. SplineAddress splineAddress = bezierSpline.GetAddressByDistance(-5.0f);
  1204. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  1205. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  1206. }
  1207. {
  1208. SplineAddress splineAddress = bezierSpline.GetAddressByDistance(100.0f);
  1209. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  1210. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  1211. }
  1212. }
  1213. {
  1214. BezierSpline bezierSpline;
  1215. bezierSpline.SetClosed(true);
  1216. // n shape (xy plane)
  1217. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1218. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1219. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1220. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1221. {
  1222. SplineAddress splineAddress = bezierSpline.GetAddressByDistance(100.0f);
  1223. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  1224. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  1225. }
  1226. }
  1227. }
  1228. void Bezier_AddressByFraction()
  1229. {
  1230. {
  1231. BezierSpline bezierSpline;
  1232. // n shape (xy plane)
  1233. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1234. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1235. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1236. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1237. {
  1238. SplineAddress splineAddress = bezierSpline.GetAddressByFraction(0.0f);
  1239. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  1240. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  1241. }
  1242. {
  1243. SplineAddress splineAddress = bezierSpline.GetAddressByFraction(-0.5f);
  1244. EXPECT_EQ(splineAddress.m_segmentIndex, 0);
  1245. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.0f, AZ::Constants::Tolerance);
  1246. }
  1247. {
  1248. SplineAddress splineAddress = bezierSpline.GetAddressByFraction(2.0f);
  1249. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  1250. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  1251. }
  1252. {
  1253. SplineAddress splineAddress = bezierSpline.GetAddressByFraction(1.0f);
  1254. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  1255. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, AZ::Constants::Tolerance);
  1256. }
  1257. {
  1258. SplineAddress splineAddress = bezierSpline.GetAddressByFraction(0.5f);
  1259. EXPECT_EQ(splineAddress.m_segmentIndex, 1);
  1260. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.5f, Constants::Tolerance);
  1261. }
  1262. }
  1263. {
  1264. BezierSpline bezierSpline;
  1265. bezierSpline.SetClosed(true);
  1266. // n shape (xy plane)
  1267. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1268. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1269. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1270. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1271. {
  1272. SplineAddress splineAddress = bezierSpline.GetAddressByFraction(1.0f);
  1273. EXPECT_EQ(splineAddress.m_segmentIndex, 3);
  1274. EXPECT_NEAR(splineAddress.m_segmentFraction, 1.0f, Constants::Tolerance);
  1275. }
  1276. {
  1277. // testing a fraction far away from a boundary between segments as points right on
  1278. // a boundary could fall into either segment depending on floating point differences
  1279. SplineAddress splineAddress = bezierSpline.GetAddressByFraction(0.6f);
  1280. EXPECT_EQ(splineAddress.m_segmentIndex, 2);
  1281. EXPECT_NEAR(splineAddress.m_segmentFraction, 0.4f, Constants::Tolerance);
  1282. }
  1283. }
  1284. }
  1285. void Bezier_GetPosition()
  1286. {
  1287. {
  1288. BezierSpline bezierSpline;
  1289. // n shape (xy plane)
  1290. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1291. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1292. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1293. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1294. {
  1295. Vector3 position = bezierSpline.GetPosition(bezierSpline.GetAddressByFraction(1.0f));
  1296. EXPECT_THAT(position, IsClose(Vector3(10.0f, 0.0f, 0.0f)));
  1297. }
  1298. {
  1299. Vector3 position = bezierSpline.GetPosition(SplineAddress());
  1300. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  1301. }
  1302. {
  1303. Vector3 position = bezierSpline.GetPosition(SplineAddress(bezierSpline.GetSegmentCount() - 1, 1.0f));
  1304. EXPECT_THAT(position, IsClose(Vector3(10.0f, 0.0f, 0.0f)));
  1305. }
  1306. {
  1307. // out of bounds access (return position of last vertex - clamped)
  1308. Vector3 position = bezierSpline.GetPosition(SplineAddress(5, 0.5f));
  1309. EXPECT_THAT(position, IsClose(Vector3(10.0f, 0.0f, 0.0f)));
  1310. }
  1311. }
  1312. {
  1313. BezierSpline bezierSpline;
  1314. bezierSpline.SetClosed(true);
  1315. // n shape (xy plane)
  1316. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1317. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1318. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1319. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1320. {
  1321. Vector3 position = bezierSpline.GetPosition(SplineAddress());
  1322. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  1323. }
  1324. {
  1325. Vector3 position = bezierSpline.GetPosition(SplineAddress(bezierSpline.GetSegmentCount() - 1, 1.0f));
  1326. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  1327. }
  1328. {
  1329. // out of bounds access (return position of last/first vertex - clamped)
  1330. Vector3 position = bezierSpline.GetPosition(SplineAddress(5, 0.5f));
  1331. EXPECT_THAT(position, IsClose(Vector3(0.0f, 0.0f, 0.0f)));
  1332. }
  1333. }
  1334. }
  1335. void Bezier_GetNormal()
  1336. {
  1337. {
  1338. BezierSpline bezierSpline;
  1339. // n shape (xy plane)
  1340. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1341. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1342. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1343. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1344. {
  1345. Vector3 normal = bezierSpline.GetNormal(SplineAddress(1, 0.5f));
  1346. EXPECT_THAT(normal, IsClose(Vector3(0.0f, 1.0f, 0.0f)));
  1347. }
  1348. {
  1349. Vector3 normal = bezierSpline.GetNormal(SplineAddress(0, 0.0f));
  1350. EXPECT_THAT(normal, IsCloseTolerance(Vector3(-0.955f, -0.294f, 0.0f), 1e-3f));
  1351. }
  1352. {
  1353. Vector3 normal = bezierSpline.GetNormal(SplineAddress(3, 0.0f));
  1354. EXPECT_THAT(normal, IsCloseTolerance(Vector3(0.955f, -0.294f, 0.0f), 1e-3f));
  1355. }
  1356. {
  1357. // out of bounds access (return normal of last vertex - clamped)
  1358. Vector3 normal = bezierSpline.GetNormal(SplineAddress(5, 0.5f));
  1359. EXPECT_THAT(normal, IsCloseTolerance(Vector3(0.955f, -0.294f, 0.0f), 1e-3f));
  1360. }
  1361. }
  1362. {
  1363. BezierSpline bezierSpline;
  1364. bezierSpline.SetClosed(true);
  1365. // n shape (xy plane)
  1366. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1367. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1368. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1369. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1370. {
  1371. Vector3 normal = bezierSpline.GetNormal(SplineAddress(3, 0.5f));
  1372. EXPECT_THAT(normal, IsClose(Vector3(0.0f, -1.0f, 0.0f)));
  1373. }
  1374. {
  1375. Vector3 normal = bezierSpline.GetNormal(SplineAddress(0, 0.0f));
  1376. EXPECT_THAT(normal, IsClose(Vector3(-0.7071f, -0.7071f, 0.0f)));
  1377. }
  1378. {
  1379. Vector3 normal = bezierSpline.GetNormal(SplineAddress(3, 0.0f));
  1380. EXPECT_THAT(normal, IsClose(Vector3(0.7071f, -0.7071f, 0.0f)));
  1381. }
  1382. {
  1383. Vector3 normal = bezierSpline.GetNormal(SplineAddress(3, 1.0f));
  1384. EXPECT_THAT(normal, IsClose(Vector3(-0.7071f, -0.7071f, 0.0f)));
  1385. }
  1386. {
  1387. // out of bounds access (return normal of last vertex - clamped)
  1388. Vector3 normal = bezierSpline.GetNormal(SplineAddress(5, 0.5f));
  1389. EXPECT_THAT(normal, IsClose(Vector3(-0.7071f, -0.7071f, 0.0f)));
  1390. }
  1391. }
  1392. }
  1393. void Bezier_GetTangent()
  1394. {
  1395. {
  1396. BezierSpline bezierSpline;
  1397. // n shape (xy plane)
  1398. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1399. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1400. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1401. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1402. {
  1403. Vector3 tangent = bezierSpline.GetTangent(SplineAddress(1, 0.5f));
  1404. EXPECT_THAT(tangent, IsClose(Vector3(1.0f, 0.0f, 0.0f)));
  1405. }
  1406. }
  1407. {
  1408. BezierSpline bezierSpline;
  1409. bezierSpline.SetClosed(true);
  1410. // n shape (xy plane)
  1411. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1412. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1413. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1414. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1415. {
  1416. Vector3 tangent = bezierSpline.GetTangent(SplineAddress(3, 0.5f));
  1417. EXPECT_THAT(tangent, IsClose(Vector3(-1.0f, 0.0f, 0.0f)));
  1418. }
  1419. {
  1420. Vector3 tangent = bezierSpline.GetTangent(SplineAddress(2, 0.5f));
  1421. EXPECT_THAT(tangent, IsClose(Vector3(0.0f, -1.0f, 0.0f)));
  1422. }
  1423. }
  1424. }
  1425. void Bezier_Length()
  1426. {
  1427. {
  1428. BezierSpline bezierSpline;
  1429. // n shape (xy plane)
  1430. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1431. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1432. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1433. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1434. {
  1435. float splineLength = bezierSpline.GetSplineLength();
  1436. EXPECT_NEAR(splineLength, 31.8014f, 0.0001f);
  1437. }
  1438. // lengths should be exact as shape is symmetrical
  1439. {
  1440. float segment0Length = bezierSpline.GetSegmentLength(0);
  1441. float segment2Length = bezierSpline.GetSegmentLength(2);
  1442. EXPECT_NEAR(segment0Length, segment2Length, Constants::Tolerance);
  1443. }
  1444. }
  1445. {
  1446. BezierSpline bezierSpline;
  1447. bezierSpline.SetClosed(true);
  1448. // n shape (xy plane)
  1449. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1450. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1451. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1452. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1453. {
  1454. float splineLength = bezierSpline.GetSplineLength();
  1455. EXPECT_NEAR(splineLength, 43.40867f, Constants::Tolerance);
  1456. }
  1457. {
  1458. float segment0Length = bezierSpline.GetSegmentLength(0);
  1459. float segment2Length = bezierSpline.GetSegmentLength(3);
  1460. EXPECT_NEAR(segment0Length, segment2Length, Constants::Tolerance);
  1461. }
  1462. }
  1463. {
  1464. BezierSpline bezierSpline;
  1465. bezierSpline.SetClosed(true);
  1466. // single line (y axis)
  1467. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1468. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1469. {
  1470. float splineLength = bezierSpline.GetSplineLength();
  1471. EXPECT_NEAR(splineLength, 20.0f, AZ::Constants::Tolerance);
  1472. }
  1473. {
  1474. float segmentLength = bezierSpline.GetSegmentLength(1);
  1475. EXPECT_NEAR(segmentLength, 10.0f, AZ::Constants::Tolerance);
  1476. }
  1477. }
  1478. }
  1479. void Bezier_GetLength()
  1480. {
  1481. {
  1482. BezierSpline bezierSpline;
  1483. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1484. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1485. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 20.0f, 0.0f));
  1486. auto distance = bezierSpline.GetLength(AZ::SplineAddress(1, 0.5f));
  1487. EXPECT_NEAR(distance, 15.0f, 1e-4);
  1488. distance = bezierSpline.GetLength(AZ::SplineAddress(0, 0.0f));
  1489. EXPECT_NEAR(distance, 0.0f, 1e-4);
  1490. distance = bezierSpline.GetLength(AZ::SplineAddress(1, 1.0f));
  1491. EXPECT_NEAR(distance, 20.0f, 1e-4);
  1492. distance = bezierSpline.GetLength(AZ::SplineAddress(5, 1.0f));
  1493. EXPECT_NEAR(distance, bezierSpline.GetSplineLength(), 1e-4);
  1494. }
  1495. {
  1496. BezierSpline bezierSpline;
  1497. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1498. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1499. bezierSpline.m_vertexContainer.AddVertex(Vector3(20.0f, 20.0f, 10.0f));
  1500. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 15.0f, -10.0f));
  1501. float length = bezierSpline.GetSplineLength();
  1502. for (float t = 0.0f; t <= length; t += 0.5f)
  1503. {
  1504. auto result = bezierSpline.GetLength(bezierSpline.GetAddressByDistance(t));
  1505. EXPECT_NEAR(result, t, 1e-4);
  1506. }
  1507. }
  1508. {
  1509. BezierSpline bezierSpline;
  1510. auto result = bezierSpline.GetLength(AZ::SplineAddress(0, 0.0f));
  1511. EXPECT_NEAR(result, 0.0f, 1e-4);
  1512. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1513. result = bezierSpline.GetLength(AZ::SplineAddress(0, 0.0f));
  1514. EXPECT_NEAR(result, 0.0f, 1e-4);
  1515. }
  1516. }
  1517. void Bezier_Aabb()
  1518. {
  1519. {
  1520. BezierSpline bezierSpline;
  1521. // slight n curve spline (xy plane)
  1522. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1523. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1524. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1525. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1526. AZ::Aabb aabb;
  1527. bezierSpline.GetAabb(aabb);
  1528. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.2948f, 0.0f, 0.0f)));
  1529. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(11.2948f, 11.7677f, 0.0f)));
  1530. }
  1531. {
  1532. BezierSpline bezierSpline;
  1533. bezierSpline.SetClosed(true);
  1534. // slight n curve spline (xy plane)
  1535. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1536. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1537. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1538. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1539. AZ::Aabb aabb;
  1540. bezierSpline.GetAabb(aabb);
  1541. EXPECT_THAT(aabb.GetMin(), IsClose(Vector3(-1.7677f, -1.7677f, 0.0f)));
  1542. EXPECT_THAT(aabb.GetMax(), IsClose(Vector3(11.7677f, 11.7677f, 0.0f)));
  1543. }
  1544. }
  1545. void Spline_Invalid()
  1546. {
  1547. {
  1548. LinearSpline linearSpline;
  1549. PositionSplineQueryResult posSplineQuery = linearSpline.GetNearestAddressPosition(Vector3::CreateZero());
  1550. EXPECT_EQ(posSplineQuery.m_splineAddress, SplineAddress());
  1551. EXPECT_NEAR(posSplineQuery.m_distanceSq, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1552. RaySplineQueryResult raySplineQuery = linearSpline.GetNearestAddressRay(Vector3::CreateZero(), Vector3::CreateZero());
  1553. EXPECT_EQ(raySplineQuery.m_splineAddress, SplineAddress());
  1554. EXPECT_NEAR(raySplineQuery.m_distanceSq, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1555. EXPECT_NEAR(raySplineQuery.m_rayDistance, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1556. SplineAddress linearAddressDistance = linearSpline.GetAddressByDistance(2.0f);
  1557. EXPECT_EQ(linearAddressDistance, SplineAddress());
  1558. SplineAddress linearAddressFraction = linearSpline.GetAddressByFraction(0.0f);
  1559. EXPECT_EQ(linearAddressFraction, SplineAddress());
  1560. Vector3 linearPosition = linearSpline.GetPosition(SplineAddress(0, 0.5f));
  1561. EXPECT_THAT(linearPosition, IsClose(Vector3::CreateZero()));
  1562. Vector3 linearNormal = linearSpline.GetNormal(SplineAddress(1, 0.5f));
  1563. EXPECT_THAT(linearNormal, IsClose(Vector3::CreateAxisX()));
  1564. Vector3 linearTangent = linearSpline.GetTangent(SplineAddress(2, 0.5f));
  1565. EXPECT_THAT(linearTangent, IsClose(Vector3::CreateAxisX()));
  1566. float linearSegmentLength = linearSpline.GetSegmentLength(2);
  1567. EXPECT_NEAR(linearSegmentLength, 0.0f, AZ::Constants::Tolerance);
  1568. float linearSplineLength = linearSpline.GetSplineLength();
  1569. EXPECT_NEAR(linearSplineLength, 0.0f, AZ::Constants::Tolerance);
  1570. }
  1571. {
  1572. CatmullRomSpline catmullRomSpline;
  1573. PositionSplineQueryResult posSplineQuery = catmullRomSpline.GetNearestAddressPosition(Vector3::CreateZero());
  1574. EXPECT_EQ(posSplineQuery.m_splineAddress, SplineAddress());
  1575. EXPECT_NEAR(posSplineQuery.m_distanceSq, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1576. RaySplineQueryResult raySplineQuery = catmullRomSpline.GetNearestAddressRay(Vector3::CreateZero(), Vector3::CreateZero());
  1577. EXPECT_EQ(raySplineQuery.m_splineAddress, SplineAddress());
  1578. EXPECT_NEAR(raySplineQuery.m_distanceSq, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1579. EXPECT_NEAR(raySplineQuery.m_rayDistance, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1580. SplineAddress catmullRomAddressDistance = catmullRomSpline.GetAddressByDistance(2.0f);
  1581. EXPECT_EQ(catmullRomAddressDistance, SplineAddress());
  1582. SplineAddress catmullRomAddressFraction = catmullRomSpline.GetAddressByFraction(0.0f);
  1583. EXPECT_EQ(catmullRomAddressFraction, SplineAddress());
  1584. Vector3 catmullRomPosition = catmullRomSpline.GetPosition(SplineAddress(0, 0.5f));
  1585. EXPECT_THAT(catmullRomPosition, IsClose(Vector3::CreateZero()));
  1586. Vector3 catmullRomNormal = catmullRomSpline.GetNormal(SplineAddress(1, 0.5f));
  1587. EXPECT_THAT(catmullRomNormal, IsClose(Vector3::CreateAxisX()));
  1588. Vector3 catmullRomTangent = catmullRomSpline.GetTangent(SplineAddress(2, 0.5f));
  1589. EXPECT_THAT(catmullRomTangent, IsClose(Vector3::CreateAxisX()));
  1590. float catmullRomSegmentLength = catmullRomSpline.GetSegmentLength(2);
  1591. EXPECT_NEAR(catmullRomSegmentLength, 0.0f, AZ::Constants::Tolerance);
  1592. float catmullRomSplineLength = catmullRomSpline.GetSplineLength();
  1593. EXPECT_NEAR(catmullRomSplineLength, 0.0f, AZ::Constants::Tolerance);
  1594. }
  1595. {
  1596. BezierSpline bezierSpline;
  1597. PositionSplineQueryResult posSplineQuery = bezierSpline.GetNearestAddressPosition(Vector3::CreateZero());
  1598. EXPECT_EQ(posSplineQuery.m_splineAddress, SplineAddress());
  1599. EXPECT_NEAR(posSplineQuery.m_distanceSq, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1600. RaySplineQueryResult raySplineQuery = bezierSpline.GetNearestAddressRay(Vector3::CreateZero(), Vector3::CreateZero());
  1601. EXPECT_EQ(raySplineQuery.m_splineAddress, SplineAddress());
  1602. EXPECT_NEAR(raySplineQuery.m_distanceSq, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1603. EXPECT_NEAR(raySplineQuery.m_rayDistance, std::numeric_limits<float>::max(), AZ::Constants::Tolerance);
  1604. SplineAddress bezierAddressDistance = bezierSpline.GetAddressByDistance(2.0f);
  1605. EXPECT_EQ(bezierAddressDistance, SplineAddress());
  1606. SplineAddress bezierAddressFraction = bezierSpline.GetAddressByFraction(0.0f);
  1607. EXPECT_EQ(bezierAddressFraction, SplineAddress());
  1608. Vector3 bezierPosition = bezierSpline.GetPosition(SplineAddress(0, 0.5f));
  1609. EXPECT_THAT(bezierPosition, IsClose(Vector3::CreateZero()));
  1610. Vector3 bezierNormal = bezierSpline.GetNormal(SplineAddress(1, 0.5f));
  1611. EXPECT_THAT(bezierNormal, IsClose(Vector3::CreateAxisX()));
  1612. Vector3 bezierTangent = bezierSpline.GetTangent(SplineAddress(2, 0.5f));
  1613. EXPECT_THAT(bezierTangent, IsClose(Vector3::CreateAxisX()));
  1614. float bezierSegmentLength = bezierSpline.GetSegmentLength(2);
  1615. EXPECT_NEAR(bezierSegmentLength, 0.0f, AZ::Constants::Tolerance);
  1616. float bezierSplineLength = bezierSpline.GetSplineLength();
  1617. EXPECT_NEAR(bezierSplineLength, 0.0f, AZ::Constants::Tolerance);
  1618. }
  1619. }
  1620. void Spline_Set()
  1621. {
  1622. LinearSpline linearSpline;
  1623. // slight n curve spline (xy plane)
  1624. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1625. linearSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1626. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1627. linearSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1628. AZStd::vector<Vector3> vertices{
  1629. Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 10.0f, 0.0f), Vector3(10.0f, 10.0f, 0.0f), Vector3(10.0f, 0.0f, 0.0f)
  1630. };
  1631. LinearSpline linearSplineSetLValue;
  1632. linearSplineSetLValue.m_vertexContainer.SetVertices(vertices);
  1633. LinearSpline linearSplineSetRValue;
  1634. linearSplineSetRValue.m_vertexContainer.SetVertices(AZStd::vector<Vector3>{ Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 10.0f, 0.0f), Vector3(10.0f, 10.0f, 0.0f), Vector3(10.0f, 0.0f, 0.0f) });
  1635. LinearSpline linearSplineSetLValueCopy;
  1636. linearSplineSetLValueCopy.m_vertexContainer.SetVertices(linearSplineSetLValue.GetVertices());
  1637. EXPECT_EQ(linearSpline.GetVertexCount(), linearSplineSetLValue.GetVertexCount());
  1638. EXPECT_EQ(linearSpline.GetVertexCount(), linearSplineSetRValue.GetVertexCount());
  1639. EXPECT_EQ(linearSplineSetLValue.GetVertexCount(), linearSplineSetRValue.GetVertexCount());
  1640. EXPECT_EQ(linearSplineSetLValueCopy.GetVertexCount(), vertices.size());
  1641. BezierSpline bezierSpline;
  1642. // slight n curve spline (xy plane)
  1643. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 0.0f, 0.0f));
  1644. bezierSpline.m_vertexContainer.AddVertex(Vector3(0.0f, 10.0f, 0.0f));
  1645. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 10.0f, 0.0f));
  1646. bezierSpline.m_vertexContainer.AddVertex(Vector3(10.0f, 0.0f, 0.0f));
  1647. BezierSpline bezierSplineSetLValue;
  1648. bezierSplineSetLValue.m_vertexContainer.SetVertices(vertices);
  1649. BezierSpline bezierSplineSetRValue;
  1650. bezierSplineSetRValue.m_vertexContainer.SetVertices(AZStd::vector<Vector3>{ Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 10.0f, 0.0f), Vector3(10.0f, 10.0f, 0.0f), Vector3(10.0f, 0.0f, 0.0f) });
  1651. BezierSpline bezierSplineSetLValueCopy;
  1652. bezierSplineSetLValueCopy.m_vertexContainer.SetVertices(bezierSplineSetLValue.GetVertices());
  1653. EXPECT_EQ(bezierSpline.GetBezierData().size(), bezierSplineSetLValue.GetBezierData().size());
  1654. EXPECT_EQ(bezierSplineSetLValue.GetBezierData().size(), 4);
  1655. EXPECT_EQ(bezierSplineSetLValue.GetBezierData().size(), bezierSplineSetRValue.GetBezierData().size());
  1656. EXPECT_EQ(bezierSplineSetLValueCopy.GetBezierData().size(), 4);
  1657. EXPECT_EQ(bezierSplineSetLValueCopy.GetVertexCount(), vertices.size());
  1658. }
  1659. };
  1660. TEST_F(MATH_SplineTest, Linear_NearestAddressFromPosition)
  1661. {
  1662. Linear_NearestAddressFromPosition();
  1663. }
  1664. TEST_F(MATH_SplineTest, Linear_NearestAddressFromDirection)
  1665. {
  1666. Linear_NearestAddressFromDirection();
  1667. }
  1668. TEST_F(MATH_SplineTest, Linear_AddressByDistance)
  1669. {
  1670. Linear_AddressByDistance();
  1671. }
  1672. TEST_F(MATH_SplineTest, Linear_AddressByFraction)
  1673. {
  1674. Linear_AddressByFraction();
  1675. }
  1676. TEST_F(MATH_SplineTest, Linear_GetPosition)
  1677. {
  1678. Linear_GetPosition();
  1679. }
  1680. TEST_F(MATH_SplineTest, Linear_GetNormal)
  1681. {
  1682. Linear_GetNormal();
  1683. }
  1684. TEST_F(MATH_SplineTest, Linear_GetTangent)
  1685. {
  1686. Linear_GetTangent();
  1687. }
  1688. TEST_F(MATH_SplineTest, Linear_Length)
  1689. {
  1690. Linear_Length();
  1691. }
  1692. TEST_F(MATH_SplineTest, Linear_Aabb)
  1693. {
  1694. Linear_Aabb();
  1695. }
  1696. TEST_F(MATH_SplineTest, Linear_GetLength)
  1697. {
  1698. Linear_GetLength();
  1699. }
  1700. TEST_F(MATH_SplineTest, CatmullRom_Length)
  1701. {
  1702. CatmullRom_Length();
  1703. }
  1704. TEST_F(MATH_SplineTest, CatmullRom_NearestAddressFromPosition)
  1705. {
  1706. CatmullRom_NearestAddressFromPosition();
  1707. }
  1708. TEST_F(MATH_SplineTest, CatmullRom_NearestAddressFromDirection)
  1709. {
  1710. CatmullRom_NearestAddressFromDirection();
  1711. }
  1712. TEST_F(MATH_SplineTest, CatmullRom_AddressByDistance)
  1713. {
  1714. CatmullRom_AddressByDistance();
  1715. }
  1716. TEST_F(MATH_SplineTest, CatmullRom_AddressByFraction)
  1717. {
  1718. CatmullRom_AddressByFraction();
  1719. }
  1720. TEST_F(MATH_SplineTest, CatmullRom_GetPosition)
  1721. {
  1722. CatmullRom_GetPosition();
  1723. }
  1724. TEST_F(MATH_SplineTest, CatmullRom_GetNormal)
  1725. {
  1726. CatmullRom_GetNormal();
  1727. }
  1728. TEST_F(MATH_SplineTest, CatmullRom_GetTangent)
  1729. {
  1730. CatmullRom_GetTangent();
  1731. }
  1732. TEST_F(MATH_SplineTest, CatmullRom_Aabb)
  1733. {
  1734. CatmullRom_Aabb();
  1735. }
  1736. TEST_F(MATH_SplineTest, CatmullRom_GetLength)
  1737. {
  1738. CatmullRom_GetLength();
  1739. }
  1740. TEST_F(MATH_SplineTest, Bezier_NearestAddressFromPosition)
  1741. {
  1742. Bezier_NearestAddressFromPosition();
  1743. }
  1744. TEST_F(MATH_SplineTest, Bezier_NearestAddressFromDirection)
  1745. {
  1746. Bezier_NearestAddressFromDirection();
  1747. }
  1748. TEST_F(MATH_SplineTest, Bezier_AddressByDistance)
  1749. {
  1750. Bezier_AddressByDistance();
  1751. }
  1752. TEST_F(MATH_SplineTest, Bezier_AddressByFraction)
  1753. {
  1754. Bezier_AddressByFraction();
  1755. }
  1756. TEST_F(MATH_SplineTest, Bezier_GetPosition)
  1757. {
  1758. Bezier_GetPosition();
  1759. }
  1760. TEST_F(MATH_SplineTest, Bezier_GetNormal)
  1761. {
  1762. Bezier_GetNormal();
  1763. }
  1764. TEST_F(MATH_SplineTest, Bezier_GetTangent)
  1765. {
  1766. Bezier_GetTangent();
  1767. }
  1768. TEST_F(MATH_SplineTest, Bezier_Length)
  1769. {
  1770. Bezier_Length();
  1771. }
  1772. TEST_F(MATH_SplineTest, Bezier_Aabb)
  1773. {
  1774. Bezier_Aabb();
  1775. }
  1776. TEST_F(MATH_SplineTest, Bezier_GetLength)
  1777. {
  1778. Bezier_GetLength();
  1779. }
  1780. TEST_F(MATH_SplineTest, Spline_Invalid)
  1781. {
  1782. Spline_Invalid();
  1783. }
  1784. TEST_F(MATH_SplineTest, Spline_Set)
  1785. {
  1786. Spline_Set();
  1787. }
  1788. }