Basis.cs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186
  1. using System;
  2. using System.Runtime.InteropServices;
  3. namespace Godot
  4. {
  5. /// <summary>
  6. /// 3×3 matrix used for 3D rotation and scale.
  7. /// Almost always used as an orthogonal basis for a Transform.
  8. ///
  9. /// Contains 3 vector fields X, Y and Z as its columns, which are typically
  10. /// interpreted as the local basis vectors of a 3D transformation. For such use,
  11. /// it is composed of a scaling and a rotation matrix, in that order (M = R.S).
  12. ///
  13. /// Can also be accessed as array of 3D vectors. These vectors are normally
  14. /// orthogonal to each other, but are not necessarily normalized (due to scaling).
  15. ///
  16. /// For more information, read this documentation article:
  17. /// https://docs.godotengine.org/en/latest/tutorials/math/matrices_and_transforms.html
  18. /// </summary>
  19. [Serializable]
  20. [StructLayout(LayoutKind.Sequential)]
  21. public struct Basis : IEquatable<Basis>
  22. {
  23. // NOTE: x, y and z are public-only. Use Column0, Column1 and Column2 internally.
  24. /// <summary>
  25. /// The basis matrix's X vector (column 0).
  26. /// </summary>
  27. /// <value>Equivalent to <see cref="Column0"/> and array index <c>[0]</c>.</value>
  28. public Vector3 x
  29. {
  30. readonly get => Column0;
  31. set => Column0 = value;
  32. }
  33. /// <summary>
  34. /// The basis matrix's Y vector (column 1).
  35. /// </summary>
  36. /// <value>Equivalent to <see cref="Column1"/> and array index <c>[1]</c>.</value>
  37. public Vector3 y
  38. {
  39. readonly get => Column1;
  40. set => Column1 = value;
  41. }
  42. /// <summary>
  43. /// The basis matrix's Z vector (column 2).
  44. /// </summary>
  45. /// <value>Equivalent to <see cref="Column2"/> and array index <c>[2]</c>.</value>
  46. public Vector3 z
  47. {
  48. readonly get => Column2;
  49. set => Column2 = value;
  50. }
  51. /// <summary>
  52. /// Row 0 of the basis matrix. Shows which vectors contribute
  53. /// to the X direction. Rows are not very useful for user code,
  54. /// but are more efficient for some internal calculations.
  55. /// </summary>
  56. public Vector3 Row0;
  57. /// <summary>
  58. /// Row 1 of the basis matrix. Shows which vectors contribute
  59. /// to the Y direction. Rows are not very useful for user code,
  60. /// but are more efficient for some internal calculations.
  61. /// </summary>
  62. public Vector3 Row1;
  63. /// <summary>
  64. /// Row 2 of the basis matrix. Shows which vectors contribute
  65. /// to the Z direction. Rows are not very useful for user code,
  66. /// but are more efficient for some internal calculations.
  67. /// </summary>
  68. public Vector3 Row2;
  69. /// <summary>
  70. /// Column 0 of the basis matrix (the X vector).
  71. /// </summary>
  72. /// <value>Equivalent to <see cref="x"/> and array index <c>[0]</c>.</value>
  73. public Vector3 Column0
  74. {
  75. readonly get => new Vector3(Row0.x, Row1.x, Row2.x);
  76. set
  77. {
  78. Row0.x = value.x;
  79. Row1.x = value.y;
  80. Row2.x = value.z;
  81. }
  82. }
  83. /// <summary>
  84. /// Column 1 of the basis matrix (the Y vector).
  85. /// </summary>
  86. /// <value>Equivalent to <see cref="y"/> and array index <c>[1]</c>.</value>
  87. public Vector3 Column1
  88. {
  89. readonly get => new Vector3(Row0.y, Row1.y, Row2.y);
  90. set
  91. {
  92. Row0.y = value.x;
  93. Row1.y = value.y;
  94. Row2.y = value.z;
  95. }
  96. }
  97. /// <summary>
  98. /// Column 2 of the basis matrix (the Z vector).
  99. /// </summary>
  100. /// <value>Equivalent to <see cref="z"/> and array index <c>[2]</c>.</value>
  101. public Vector3 Column2
  102. {
  103. readonly get => new Vector3(Row0.z, Row1.z, Row2.z);
  104. set
  105. {
  106. Row0.z = value.x;
  107. Row1.z = value.y;
  108. Row2.z = value.z;
  109. }
  110. }
  111. /// <summary>
  112. /// The scale of this basis.
  113. /// </summary>
  114. /// <value>Equivalent to the lengths of each column vector, but negative if the determinant is negative.</value>
  115. public Vector3 Scale
  116. {
  117. readonly get
  118. {
  119. real_t detSign = Mathf.Sign(Determinant());
  120. return detSign * new Vector3
  121. (
  122. Column0.Length(),
  123. Column1.Length(),
  124. Column2.Length()
  125. );
  126. }
  127. set
  128. {
  129. value /= Scale; // Value becomes what's called "delta_scale" in core.
  130. Column0 *= value.x;
  131. Column1 *= value.y;
  132. Column2 *= value.z;
  133. }
  134. }
  135. /// <summary>
  136. /// Access whole columns in the form of <see cref="Vector3"/>.
  137. /// </summary>
  138. /// <param name="column">Which column vector.</param>
  139. /// <exception cref="ArgumentOutOfRangeException">
  140. /// <paramref name="column"/> is not 0, 1, 2 or 3.
  141. /// </exception>
  142. /// <value>The basis column.</value>
  143. public Vector3 this[int column]
  144. {
  145. readonly get
  146. {
  147. switch (column)
  148. {
  149. case 0:
  150. return Column0;
  151. case 1:
  152. return Column1;
  153. case 2:
  154. return Column2;
  155. default:
  156. throw new ArgumentOutOfRangeException(nameof(column));
  157. }
  158. }
  159. set
  160. {
  161. switch (column)
  162. {
  163. case 0:
  164. Column0 = value;
  165. return;
  166. case 1:
  167. Column1 = value;
  168. return;
  169. case 2:
  170. Column2 = value;
  171. return;
  172. default:
  173. throw new ArgumentOutOfRangeException(nameof(column));
  174. }
  175. }
  176. }
  177. /// <summary>
  178. /// Access matrix elements in column-major order.
  179. /// </summary>
  180. /// <param name="column">Which column, the matrix horizontal position.</param>
  181. /// <param name="row">Which row, the matrix vertical position.</param>
  182. /// <value>The matrix element.</value>
  183. public real_t this[int column, int row]
  184. {
  185. readonly get
  186. {
  187. return this[column][row];
  188. }
  189. set
  190. {
  191. Vector3 columnVector = this[column];
  192. columnVector[row] = value;
  193. this[column] = columnVector;
  194. }
  195. }
  196. internal void SetQuaternionScale(Quaternion quaternion, Vector3 scale)
  197. {
  198. SetDiagonal(scale);
  199. Rotate(quaternion);
  200. }
  201. private void Rotate(Quaternion quaternion)
  202. {
  203. this *= new Basis(quaternion);
  204. }
  205. private void SetDiagonal(Vector3 diagonal)
  206. {
  207. Row0 = new Vector3(diagonal.x, 0, 0);
  208. Row1 = new Vector3(0, diagonal.y, 0);
  209. Row2 = new Vector3(0, 0, diagonal.z);
  210. }
  211. /// <summary>
  212. /// Returns the determinant of the basis matrix. If the basis is
  213. /// uniformly scaled, its determinant is the square of the scale.
  214. ///
  215. /// A negative determinant means the basis has a negative scale.
  216. /// A zero determinant means the basis isn't invertible,
  217. /// and is usually considered invalid.
  218. /// </summary>
  219. /// <returns>The determinant of the basis matrix.</returns>
  220. public readonly real_t Determinant()
  221. {
  222. real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
  223. real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
  224. real_t cofac20 = Row1[0] * Row2[1] - Row1[1] * Row2[0];
  225. return Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
  226. }
  227. /// <summary>
  228. /// Returns the basis's rotation in the form of Euler angles.
  229. /// The Euler order depends on the [param order] parameter,
  230. /// by default it uses the YXZ convention: when decomposing,
  231. /// first Z, then X, and Y last. The returned vector contains
  232. /// the rotation angles in the format (X angle, Y angle, Z angle).
  233. ///
  234. /// Consider using the <see cref="GetRotationQuaternion"/> method instead, which
  235. /// returns a <see cref="Quaternion"/> quaternion instead of Euler angles.
  236. /// </summary>
  237. /// <param name="order">The Euler order to use. By default, use YXZ order (most common).</param>
  238. /// <returns>A <see cref="Vector3"/> representing the basis rotation in Euler angles.</returns>
  239. public readonly Vector3 GetEuler(EulerOrder order = EulerOrder.Yxz)
  240. {
  241. switch (order)
  242. {
  243. case EulerOrder.Xyz:
  244. {
  245. // Euler angles in XYZ convention.
  246. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
  247. //
  248. // rot = cy*cz -cy*sz sy
  249. // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
  250. // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
  251. Vector3 euler;
  252. real_t sy = Row0[2];
  253. if (sy < (1.0f - Mathf.Epsilon))
  254. {
  255. if (sy > -(1.0f - Mathf.Epsilon))
  256. {
  257. // is this a pure Y rotation?
  258. if (Row1[0] == 0 && Row0[1] == 0 && Row1[2] == 0 && Row2[1] == 0 && Row1[1] == 1)
  259. {
  260. // return the simplest form (human friendlier in editor and scripts)
  261. euler.x = 0;
  262. euler.y = Mathf.Atan2(Row0[2], Row0[0]);
  263. euler.z = 0;
  264. }
  265. else
  266. {
  267. euler.x = Mathf.Atan2(-Row1[2], Row2[2]);
  268. euler.y = Mathf.Asin(sy);
  269. euler.z = Mathf.Atan2(-Row0[1], Row0[0]);
  270. }
  271. }
  272. else
  273. {
  274. euler.x = Mathf.Atan2(Row2[1], Row1[1]);
  275. euler.y = -Mathf.Tau / 4.0f;
  276. euler.z = 0.0f;
  277. }
  278. }
  279. else
  280. {
  281. euler.x = Mathf.Atan2(Row2[1], Row1[1]);
  282. euler.y = Mathf.Tau / 4.0f;
  283. euler.z = 0.0f;
  284. }
  285. return euler;
  286. }
  287. case EulerOrder.Xzy:
  288. {
  289. // Euler angles in XZY convention.
  290. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
  291. //
  292. // rot = cz*cy -sz cz*sy
  293. // sx*sy+cx*cy*sz cx*cz cx*sz*sy-cy*sx
  294. // cy*sx*sz cz*sx cx*cy+sx*sz*sy
  295. Vector3 euler;
  296. real_t sz = Row0[1];
  297. if (sz < (1.0f - Mathf.Epsilon))
  298. {
  299. if (sz > -(1.0f - Mathf.Epsilon))
  300. {
  301. euler.x = Mathf.Atan2(Row2[1], Row1[1]);
  302. euler.y = Mathf.Atan2(Row0[2], Row0[0]);
  303. euler.z = Mathf.Asin(-sz);
  304. }
  305. else
  306. {
  307. // It's -1
  308. euler.x = -Mathf.Atan2(Row1[2], Row2[2]);
  309. euler.y = 0.0f;
  310. euler.z = Mathf.Tau / 4.0f;
  311. }
  312. }
  313. else
  314. {
  315. // It's 1
  316. euler.x = -Mathf.Atan2(Row1[2], Row2[2]);
  317. euler.y = 0.0f;
  318. euler.z = -Mathf.Tau / 4.0f;
  319. }
  320. return euler;
  321. }
  322. case EulerOrder.Yxz:
  323. {
  324. // Euler angles in YXZ convention.
  325. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
  326. //
  327. // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy
  328. // cx*sz cx*cz -sx
  329. // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx
  330. Vector3 euler;
  331. real_t m12 = Row1[2];
  332. if (m12 < (1 - Mathf.Epsilon))
  333. {
  334. if (m12 > -(1 - Mathf.Epsilon))
  335. {
  336. // is this a pure X rotation?
  337. if (Row1[0] == 0 && Row0[1] == 0 && Row0[2] == 0 && Row2[0] == 0 && Row0[0] == 1)
  338. {
  339. // return the simplest form (human friendlier in editor and scripts)
  340. euler.x = Mathf.Atan2(-m12, Row1[1]);
  341. euler.y = 0;
  342. euler.z = 0;
  343. }
  344. else
  345. {
  346. euler.x = Mathf.Asin(-m12);
  347. euler.y = Mathf.Atan2(Row0[2], Row2[2]);
  348. euler.z = Mathf.Atan2(Row1[0], Row1[1]);
  349. }
  350. }
  351. else
  352. { // m12 == -1
  353. euler.x = Mathf.Tau / 4.0f;
  354. euler.y = Mathf.Atan2(Row0[1], Row0[0]);
  355. euler.z = 0;
  356. }
  357. }
  358. else
  359. { // m12 == 1
  360. euler.x = -Mathf.Tau / 4.0f;
  361. euler.y = -Mathf.Atan2(Row0[1], Row0[0]);
  362. euler.z = 0;
  363. }
  364. return euler;
  365. }
  366. case EulerOrder.Yzx:
  367. {
  368. // Euler angles in YZX convention.
  369. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
  370. //
  371. // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx
  372. // sz cz*cx -cz*sx
  373. // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx
  374. Vector3 euler;
  375. real_t sz = Row1[0];
  376. if (sz < (1.0f - Mathf.Epsilon))
  377. {
  378. if (sz > -(1.0f - Mathf.Epsilon))
  379. {
  380. euler.x = Mathf.Atan2(-Row1[2], Row1[1]);
  381. euler.y = Mathf.Atan2(-Row2[0], Row0[0]);
  382. euler.z = Mathf.Asin(sz);
  383. }
  384. else
  385. {
  386. // It's -1
  387. euler.x = Mathf.Atan2(Row2[1], Row2[2]);
  388. euler.y = 0.0f;
  389. euler.z = -Mathf.Tau / 4.0f;
  390. }
  391. }
  392. else
  393. {
  394. // It's 1
  395. euler.x = Mathf.Atan2(Row2[1], Row2[2]);
  396. euler.y = 0.0f;
  397. euler.z = Mathf.Tau / 4.0f;
  398. }
  399. return euler;
  400. }
  401. case EulerOrder.Zxy:
  402. {
  403. // Euler angles in ZXY convention.
  404. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
  405. //
  406. // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx
  407. // cy*sz+cz*sx*sy cz*cx sz*sy-cz*cy*sx
  408. // -cx*sy sx cx*cy
  409. Vector3 euler;
  410. real_t sx = Row2[1];
  411. if (sx < (1.0f - Mathf.Epsilon))
  412. {
  413. if (sx > -(1.0f - Mathf.Epsilon))
  414. {
  415. euler.x = Mathf.Asin(sx);
  416. euler.y = Mathf.Atan2(-Row2[0], Row2[2]);
  417. euler.z = Mathf.Atan2(-Row0[1], Row1[1]);
  418. }
  419. else
  420. {
  421. // It's -1
  422. euler.x = -Mathf.Tau / 4.0f;
  423. euler.y = Mathf.Atan2(Row0[2], Row0[0]);
  424. euler.z = 0;
  425. }
  426. }
  427. else
  428. {
  429. // It's 1
  430. euler.x = Mathf.Tau / 4.0f;
  431. euler.y = Mathf.Atan2(Row0[2], Row0[0]);
  432. euler.z = 0;
  433. }
  434. return euler;
  435. }
  436. case EulerOrder.Zyx:
  437. {
  438. // Euler angles in ZYX convention.
  439. // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
  440. //
  441. // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*cy
  442. // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx
  443. // -sy cy*sx cy*cx
  444. Vector3 euler;
  445. real_t sy = Row2[0];
  446. if (sy < (1.0f - Mathf.Epsilon))
  447. {
  448. if (sy > -(1.0f - Mathf.Epsilon))
  449. {
  450. euler.x = Mathf.Atan2(Row2[1], Row2[2]);
  451. euler.y = Mathf.Asin(-sy);
  452. euler.z = Mathf.Atan2(Row1[0], Row0[0]);
  453. }
  454. else
  455. {
  456. // It's -1
  457. euler.x = 0;
  458. euler.y = Mathf.Tau / 4.0f;
  459. euler.z = -Mathf.Atan2(Row0[1], Row1[1]);
  460. }
  461. }
  462. else
  463. {
  464. // It's 1
  465. euler.x = 0;
  466. euler.y = -Mathf.Tau / 4.0f;
  467. euler.z = -Mathf.Atan2(Row0[1], Row1[1]);
  468. }
  469. return euler;
  470. }
  471. default:
  472. throw new ArgumentOutOfRangeException(nameof(order));
  473. }
  474. }
  475. /// <summary>
  476. /// Returns the basis's rotation in the form of a quaternion.
  477. /// See <see cref="GetEuler"/> if you need Euler angles, but keep in
  478. /// mind that quaternions should generally be preferred to Euler angles.
  479. /// </summary>
  480. /// <returns>A <see cref="Quaternion"/> representing the basis's rotation.</returns>
  481. internal readonly Quaternion GetQuaternion()
  482. {
  483. real_t trace = Row0[0] + Row1[1] + Row2[2];
  484. if (trace > 0.0f)
  485. {
  486. real_t s = Mathf.Sqrt(trace + 1.0f) * 2f;
  487. real_t inv_s = 1f / s;
  488. return new Quaternion(
  489. (Row2[1] - Row1[2]) * inv_s,
  490. (Row0[2] - Row2[0]) * inv_s,
  491. (Row1[0] - Row0[1]) * inv_s,
  492. s * 0.25f
  493. );
  494. }
  495. if (Row0[0] > Row1[1] && Row0[0] > Row2[2])
  496. {
  497. real_t s = Mathf.Sqrt(Row0[0] - Row1[1] - Row2[2] + 1.0f) * 2f;
  498. real_t inv_s = 1f / s;
  499. return new Quaternion(
  500. s * 0.25f,
  501. (Row0[1] + Row1[0]) * inv_s,
  502. (Row0[2] + Row2[0]) * inv_s,
  503. (Row2[1] - Row1[2]) * inv_s
  504. );
  505. }
  506. if (Row1[1] > Row2[2])
  507. {
  508. real_t s = Mathf.Sqrt(-Row0[0] + Row1[1] - Row2[2] + 1.0f) * 2f;
  509. real_t inv_s = 1f / s;
  510. return new Quaternion(
  511. (Row0[1] + Row1[0]) * inv_s,
  512. s * 0.25f,
  513. (Row1[2] + Row2[1]) * inv_s,
  514. (Row0[2] - Row2[0]) * inv_s
  515. );
  516. }
  517. else
  518. {
  519. real_t s = Mathf.Sqrt(-Row0[0] - Row1[1] + Row2[2] + 1.0f) * 2f;
  520. real_t inv_s = 1f / s;
  521. return new Quaternion(
  522. (Row0[2] + Row2[0]) * inv_s,
  523. (Row1[2] + Row2[1]) * inv_s,
  524. s * 0.25f,
  525. (Row1[0] - Row0[1]) * inv_s
  526. );
  527. }
  528. }
  529. /// <summary>
  530. /// Returns the <see cref="Basis"/>'s rotation in the form of a
  531. /// <see cref="Quaternion"/>. See <see cref="GetEuler"/> if you
  532. /// need Euler angles, but keep in mind quaternions should generally
  533. /// be preferred to Euler angles.
  534. /// </summary>
  535. /// <returns>The basis rotation.</returns>
  536. public readonly Quaternion GetRotationQuaternion()
  537. {
  538. Basis orthonormalizedBasis = Orthonormalized();
  539. real_t det = orthonormalizedBasis.Determinant();
  540. if (det < 0)
  541. {
  542. // Ensure that the determinant is 1, such that result is a proper
  543. // rotation matrix which can be represented by Euler angles.
  544. orthonormalizedBasis = orthonormalizedBasis.Scaled(-Vector3.One);
  545. }
  546. return orthonormalizedBasis.GetQuaternion();
  547. }
  548. /// <summary>
  549. /// Get rows by index. Rows are not very useful for user code,
  550. /// but are more efficient for some internal calculations.
  551. /// </summary>
  552. /// <param name="index">Which row.</param>
  553. /// <exception cref="ArgumentOutOfRangeException">
  554. /// <paramref name="index"/> is not 0, 1 or 2.
  555. /// </exception>
  556. /// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns>
  557. public readonly Vector3 GetRow(int index)
  558. {
  559. switch (index)
  560. {
  561. case 0:
  562. return Row0;
  563. case 1:
  564. return Row1;
  565. case 2:
  566. return Row2;
  567. default:
  568. throw new ArgumentOutOfRangeException(nameof(index));
  569. }
  570. }
  571. /// <summary>
  572. /// Sets rows by index. Rows are not very useful for user code,
  573. /// but are more efficient for some internal calculations.
  574. /// </summary>
  575. /// <param name="index">Which row.</param>
  576. /// <param name="value">The vector to set the row to.</param>
  577. /// <exception cref="ArgumentOutOfRangeException">
  578. /// <paramref name="index"/> is not 0, 1 or 2.
  579. /// </exception>
  580. public void SetRow(int index, Vector3 value)
  581. {
  582. switch (index)
  583. {
  584. case 0:
  585. Row0 = value;
  586. return;
  587. case 1:
  588. Row1 = value;
  589. return;
  590. case 2:
  591. Row2 = value;
  592. return;
  593. default:
  594. throw new ArgumentOutOfRangeException(nameof(index));
  595. }
  596. }
  597. /// <summary>
  598. /// This function considers a discretization of rotations into
  599. /// 24 points on unit sphere, lying along the vectors (x, y, z) with
  600. /// each component being either -1, 0, or 1, and returns the index
  601. /// of the point best representing the orientation of the object.
  602. /// It is mainly used by the <see cref="GridMap"/> editor.
  603. ///
  604. /// For further details, refer to the Godot source code.
  605. /// </summary>
  606. /// <returns>The orthogonal index.</returns>
  607. public readonly int GetOrthogonalIndex()
  608. {
  609. var orth = this;
  610. for (int i = 0; i < 3; i++)
  611. {
  612. for (int j = 0; j < 3; j++)
  613. {
  614. var row = orth.GetRow(i);
  615. real_t v = row[j];
  616. if (v > 0.5f)
  617. {
  618. v = 1.0f;
  619. }
  620. else if (v < -0.5f)
  621. {
  622. v = -1.0f;
  623. }
  624. else
  625. {
  626. v = 0f;
  627. }
  628. row[j] = v;
  629. orth.SetRow(i, row);
  630. }
  631. }
  632. for (int i = 0; i < 24; i++)
  633. {
  634. if (orth == _orthoBases[i])
  635. {
  636. return i;
  637. }
  638. }
  639. return 0;
  640. }
  641. /// <summary>
  642. /// Returns the inverse of the matrix.
  643. /// </summary>
  644. /// <returns>The inverse matrix.</returns>
  645. public readonly Basis Inverse()
  646. {
  647. real_t cofac00 = Row1[1] * Row2[2] - Row1[2] * Row2[1];
  648. real_t cofac10 = Row1[2] * Row2[0] - Row1[0] * Row2[2];
  649. real_t cofac20 = Row1[0] * Row2[1] - Row1[1] * Row2[0];
  650. real_t det = Row0[0] * cofac00 + Row0[1] * cofac10 + Row0[2] * cofac20;
  651. if (det == 0)
  652. {
  653. throw new InvalidOperationException("Matrix determinant is zero and cannot be inverted.");
  654. }
  655. real_t detInv = 1.0f / det;
  656. real_t cofac01 = Row0[2] * Row2[1] - Row0[1] * Row2[2];
  657. real_t cofac02 = Row0[1] * Row1[2] - Row0[2] * Row1[1];
  658. real_t cofac11 = Row0[0] * Row2[2] - Row0[2] * Row2[0];
  659. real_t cofac12 = Row0[2] * Row1[0] - Row0[0] * Row1[2];
  660. real_t cofac21 = Row0[1] * Row2[0] - Row0[0] * Row2[1];
  661. real_t cofac22 = Row0[0] * Row1[1] - Row0[1] * Row1[0];
  662. return new Basis
  663. (
  664. cofac00 * detInv, cofac01 * detInv, cofac02 * detInv,
  665. cofac10 * detInv, cofac11 * detInv, cofac12 * detInv,
  666. cofac20 * detInv, cofac21 * detInv, cofac22 * detInv
  667. );
  668. }
  669. /// <summary>
  670. /// Returns <see langword="true"/> if this basis is finite, by calling
  671. /// <see cref="Mathf.IsFinite"/> on each component.
  672. /// </summary>
  673. /// <returns>Whether this vector is finite or not.</returns>
  674. public readonly bool IsFinite()
  675. {
  676. return Row0.IsFinite() && Row1.IsFinite() && Row2.IsFinite();
  677. }
  678. internal readonly Basis Lerp(Basis to, real_t weight)
  679. {
  680. Basis b = this;
  681. b.Row0 = Row0.Lerp(to.Row0, weight);
  682. b.Row1 = Row1.Lerp(to.Row1, weight);
  683. b.Row2 = Row2.Lerp(to.Row2, weight);
  684. return b;
  685. }
  686. /// <summary>
  687. /// Returns the orthonormalized version of the basis matrix (useful to
  688. /// call occasionally to avoid rounding errors for orthogonal matrices).
  689. /// This performs a Gram-Schmidt orthonormalization on the basis of the matrix.
  690. /// </summary>
  691. /// <returns>An orthonormalized basis matrix.</returns>
  692. public readonly Basis Orthonormalized()
  693. {
  694. Vector3 column0 = this[0];
  695. Vector3 column1 = this[1];
  696. Vector3 column2 = this[2];
  697. column0.Normalize();
  698. column1 = column1 - column0 * column0.Dot(column1);
  699. column1.Normalize();
  700. column2 = column2 - column0 * column0.Dot(column2) - column1 * column1.Dot(column2);
  701. column2.Normalize();
  702. return new Basis(column0, column1, column2);
  703. }
  704. /// <summary>
  705. /// Introduce an additional rotation around the given <paramref name="axis"/>
  706. /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
  707. /// </summary>
  708. /// <param name="axis">The axis to rotate around. Must be normalized.</param>
  709. /// <param name="angle">The angle to rotate, in radians.</param>
  710. /// <returns>The rotated basis matrix.</returns>
  711. public readonly Basis Rotated(Vector3 axis, real_t angle)
  712. {
  713. return new Basis(axis, angle) * this;
  714. }
  715. /// <summary>
  716. /// Introduce an additional scaling specified by the given 3D scaling factor.
  717. /// </summary>
  718. /// <param name="scale">The scale to introduce.</param>
  719. /// <returns>The scaled basis matrix.</returns>
  720. public readonly Basis Scaled(Vector3 scale)
  721. {
  722. Basis b = this;
  723. b.Row0 *= scale.x;
  724. b.Row1 *= scale.y;
  725. b.Row2 *= scale.z;
  726. return b;
  727. }
  728. /// <summary>
  729. /// Assuming that the matrix is a proper rotation matrix, slerp performs
  730. /// a spherical-linear interpolation with another rotation matrix.
  731. /// </summary>
  732. /// <param name="target">The destination basis for interpolation.</param>
  733. /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
  734. /// <returns>The resulting basis matrix of the interpolation.</returns>
  735. public readonly Basis Slerp(Basis target, real_t weight)
  736. {
  737. Quaternion from = new Quaternion(this);
  738. Quaternion to = new Quaternion(target);
  739. Basis b = new Basis(from.Slerp(to, weight));
  740. b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), weight);
  741. b.Row1 *= Mathf.Lerp(Row1.Length(), target.Row1.Length(), weight);
  742. b.Row2 *= Mathf.Lerp(Row2.Length(), target.Row2.Length(), weight);
  743. return b;
  744. }
  745. /// <summary>
  746. /// Transposed dot product with the X axis of the matrix.
  747. /// </summary>
  748. /// <param name="with">A vector to calculate the dot product with.</param>
  749. /// <returns>The resulting dot product.</returns>
  750. public readonly real_t Tdotx(Vector3 with)
  751. {
  752. return Row0[0] * with[0] + Row1[0] * with[1] + Row2[0] * with[2];
  753. }
  754. /// <summary>
  755. /// Transposed dot product with the Y axis of the matrix.
  756. /// </summary>
  757. /// <param name="with">A vector to calculate the dot product with.</param>
  758. /// <returns>The resulting dot product.</returns>
  759. public readonly real_t Tdoty(Vector3 with)
  760. {
  761. return Row0[1] * with[0] + Row1[1] * with[1] + Row2[1] * with[2];
  762. }
  763. /// <summary>
  764. /// Transposed dot product with the Z axis of the matrix.
  765. /// </summary>
  766. /// <param name="with">A vector to calculate the dot product with.</param>
  767. /// <returns>The resulting dot product.</returns>
  768. public readonly real_t Tdotz(Vector3 with)
  769. {
  770. return Row0[2] * with[0] + Row1[2] * with[1] + Row2[2] * with[2];
  771. }
  772. /// <summary>
  773. /// Returns the transposed version of the basis matrix.
  774. /// </summary>
  775. /// <returns>The transposed basis matrix.</returns>
  776. public readonly Basis Transposed()
  777. {
  778. Basis tr = this;
  779. tr.Row0[1] = Row1[0];
  780. tr.Row1[0] = Row0[1];
  781. tr.Row0[2] = Row2[0];
  782. tr.Row2[0] = Row0[2];
  783. tr.Row1[2] = Row2[1];
  784. tr.Row2[1] = Row1[2];
  785. return tr;
  786. }
  787. private static readonly Basis[] _orthoBases = {
  788. new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f),
  789. new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f),
  790. new Basis(-1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, 1f),
  791. new Basis(0f, 1f, 0f, -1f, 0f, 0f, 0f, 0f, 1f),
  792. new Basis(1f, 0f, 0f, 0f, 0f, -1f, 0f, 1f, 0f),
  793. new Basis(0f, 0f, 1f, 1f, 0f, 0f, 0f, 1f, 0f),
  794. new Basis(-1f, 0f, 0f, 0f, 0f, 1f, 0f, 1f, 0f),
  795. new Basis(0f, 0f, -1f, -1f, 0f, 0f, 0f, 1f, 0f),
  796. new Basis(1f, 0f, 0f, 0f, -1f, 0f, 0f, 0f, -1f),
  797. new Basis(0f, 1f, 0f, 1f, 0f, 0f, 0f, 0f, -1f),
  798. new Basis(-1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, -1f),
  799. new Basis(0f, -1f, 0f, -1f, 0f, 0f, 0f, 0f, -1f),
  800. new Basis(1f, 0f, 0f, 0f, 0f, 1f, 0f, -1f, 0f),
  801. new Basis(0f, 0f, -1f, 1f, 0f, 0f, 0f, -1f, 0f),
  802. new Basis(-1f, 0f, 0f, 0f, 0f, -1f, 0f, -1f, 0f),
  803. new Basis(0f, 0f, 1f, -1f, 0f, 0f, 0f, -1f, 0f),
  804. new Basis(0f, 0f, 1f, 0f, 1f, 0f, -1f, 0f, 0f),
  805. new Basis(0f, -1f, 0f, 0f, 0f, 1f, -1f, 0f, 0f),
  806. new Basis(0f, 0f, -1f, 0f, -1f, 0f, -1f, 0f, 0f),
  807. new Basis(0f, 1f, 0f, 0f, 0f, -1f, -1f, 0f, 0f),
  808. new Basis(0f, 0f, 1f, 0f, -1f, 0f, 1f, 0f, 0f),
  809. new Basis(0f, 1f, 0f, 0f, 0f, 1f, 1f, 0f, 0f),
  810. new Basis(0f, 0f, -1f, 0f, 1f, 0f, 1f, 0f, 0f),
  811. new Basis(0f, -1f, 0f, 0f, 0f, -1f, 1f, 0f, 0f)
  812. };
  813. private static readonly Basis _identity = new Basis(1, 0, 0, 0, 1, 0, 0, 0, 1);
  814. private static readonly Basis _flipX = new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
  815. private static readonly Basis _flipY = new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
  816. private static readonly Basis _flipZ = new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
  817. /// <summary>
  818. /// The identity basis, with no rotation or scaling applied.
  819. /// This is used as a replacement for <c>Basis()</c> in GDScript.
  820. /// Do not use <c>new Basis()</c> with no arguments in C#, because it sets all values to zero.
  821. /// </summary>
  822. /// <value>Equivalent to <c>new Basis(Vector3.Right, Vector3.Up, Vector3.Back)</c>.</value>
  823. public static Basis Identity { get { return _identity; } }
  824. /// <summary>
  825. /// The basis that will flip something along the X axis when used in a transformation.
  826. /// </summary>
  827. /// <value>Equivalent to <c>new Basis(Vector3.Left, Vector3.Up, Vector3.Back)</c>.</value>
  828. public static Basis FlipX { get { return _flipX; } }
  829. /// <summary>
  830. /// The basis that will flip something along the Y axis when used in a transformation.
  831. /// </summary>
  832. /// <value>Equivalent to <c>new Basis(Vector3.Right, Vector3.Down, Vector3.Back)</c>.</value>
  833. public static Basis FlipY { get { return _flipY; } }
  834. /// <summary>
  835. /// The basis that will flip something along the Z axis when used in a transformation.
  836. /// </summary>
  837. /// <value>Equivalent to <c>new Basis(Vector3.Right, Vector3.Up, Vector3.Forward)</c>.</value>
  838. public static Basis FlipZ { get { return _flipZ; } }
  839. /// <summary>
  840. /// Constructs a pure rotation basis matrix from the given quaternion.
  841. /// </summary>
  842. /// <param name="quaternion">The quaternion to create the basis from.</param>
  843. public Basis(Quaternion quaternion)
  844. {
  845. real_t s = 2.0f / quaternion.LengthSquared;
  846. real_t xs = quaternion.x * s;
  847. real_t ys = quaternion.y * s;
  848. real_t zs = quaternion.z * s;
  849. real_t wx = quaternion.w * xs;
  850. real_t wy = quaternion.w * ys;
  851. real_t wz = quaternion.w * zs;
  852. real_t xx = quaternion.x * xs;
  853. real_t xy = quaternion.x * ys;
  854. real_t xz = quaternion.x * zs;
  855. real_t yy = quaternion.y * ys;
  856. real_t yz = quaternion.y * zs;
  857. real_t zz = quaternion.z * zs;
  858. Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy);
  859. Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx);
  860. Row2 = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy));
  861. }
  862. /// <summary>
  863. /// Constructs a pure rotation basis matrix, rotated around the given <paramref name="axis"/>
  864. /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
  865. /// </summary>
  866. /// <param name="axis">The axis to rotate around. Must be normalized.</param>
  867. /// <param name="angle">The angle to rotate, in radians.</param>
  868. public Basis(Vector3 axis, real_t angle)
  869. {
  870. Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
  871. real_t cosine = Mathf.Cos(angle);
  872. Row0.x = axisSq.x + cosine * (1.0f - axisSq.x);
  873. Row1.y = axisSq.y + cosine * (1.0f - axisSq.y);
  874. Row2.z = axisSq.z + cosine * (1.0f - axisSq.z);
  875. real_t sine = Mathf.Sin(angle);
  876. real_t t = 1.0f - cosine;
  877. real_t xyzt = axis.x * axis.y * t;
  878. real_t zyxs = axis.z * sine;
  879. Row0.y = xyzt - zyxs;
  880. Row1.x = xyzt + zyxs;
  881. xyzt = axis.x * axis.z * t;
  882. zyxs = axis.y * sine;
  883. Row0.z = xyzt + zyxs;
  884. Row2.x = xyzt - zyxs;
  885. xyzt = axis.y * axis.z * t;
  886. zyxs = axis.x * sine;
  887. Row1.z = xyzt - zyxs;
  888. Row2.y = xyzt + zyxs;
  889. }
  890. /// <summary>
  891. /// Constructs a basis matrix from 3 axis vectors (matrix columns).
  892. /// </summary>
  893. /// <param name="column0">The X vector, or Column0.</param>
  894. /// <param name="column1">The Y vector, or Column1.</param>
  895. /// <param name="column2">The Z vector, or Column2.</param>
  896. public Basis(Vector3 column0, Vector3 column1, Vector3 column2)
  897. {
  898. Row0 = new Vector3(column0.x, column1.x, column2.x);
  899. Row1 = new Vector3(column0.y, column1.y, column2.y);
  900. Row2 = new Vector3(column0.z, column1.z, column2.z);
  901. // Same as:
  902. // Column0 = column0;
  903. // Column1 = column1;
  904. // Column2 = column2;
  905. // We need to assign the struct fields here first so we can't do it that way...
  906. }
  907. // Arguments are named such that xy is equal to calling x.y
  908. internal Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
  909. {
  910. Row0 = new Vector3(xx, yx, zx);
  911. Row1 = new Vector3(xy, yy, zy);
  912. Row2 = new Vector3(xz, yz, zz);
  913. }
  914. /// <summary>
  915. /// Constructs a Basis matrix from Euler angles in the specified rotation order. By default, use YXZ order (most common).
  916. /// </summary>
  917. /// <param name="euler">The Euler angles to use.</param>
  918. /// <param name="order">The order to compose the Euler angles.</param>
  919. public static Basis FromEuler(Vector3 euler, EulerOrder order = EulerOrder.Yxz)
  920. {
  921. real_t c, s;
  922. c = Mathf.Cos(euler.x);
  923. s = Mathf.Sin(euler.x);
  924. Basis xmat = new Basis(new Vector3(1, 0, 0), new Vector3(0, c, s), new Vector3(0, -s, c));
  925. c = Mathf.Cos(euler.y);
  926. s = Mathf.Sin(euler.y);
  927. Basis ymat = new Basis(new Vector3(c, 0, -s), new Vector3(0, 1, 0), new Vector3(s, 0, c));
  928. c = Mathf.Cos(euler.z);
  929. s = Mathf.Sin(euler.z);
  930. Basis zmat = new Basis(new Vector3(c, s, 0), new Vector3(-s, c, 0), new Vector3(0, 0, 1));
  931. switch (order)
  932. {
  933. case EulerOrder.Xyz:
  934. return xmat * ymat * zmat;
  935. case EulerOrder.Xzy:
  936. return xmat * zmat * ymat;
  937. case EulerOrder.Yxz:
  938. return ymat * xmat * zmat;
  939. case EulerOrder.Yzx:
  940. return ymat * zmat * xmat;
  941. case EulerOrder.Zxy:
  942. return zmat * xmat * ymat;
  943. case EulerOrder.Zyx:
  944. return zmat * ymat * xmat;
  945. default:
  946. throw new ArgumentOutOfRangeException(nameof(order));
  947. }
  948. }
  949. /// <summary>
  950. /// Constructs a pure scale basis matrix with no rotation or shearing.
  951. /// The scale values are set as the main diagonal of the matrix,
  952. /// and all of the other parts of the matrix are zero.
  953. /// </summary>
  954. /// <param name="scale">The scale Vector3.</param>
  955. /// <returns>A pure scale Basis matrix.</returns>
  956. public static Basis FromScale(Vector3 scale)
  957. {
  958. return new Basis(
  959. scale.x, 0, 0,
  960. 0, scale.y, 0,
  961. 0, 0, scale.z
  962. );
  963. }
  964. /// <summary>
  965. /// Composes these two basis matrices by multiplying them
  966. /// together. This has the effect of transforming the second basis
  967. /// (the child) by the first basis (the parent).
  968. /// </summary>
  969. /// <param name="left">The parent basis.</param>
  970. /// <param name="right">The child basis.</param>
  971. /// <returns>The composed basis.</returns>
  972. public static Basis operator *(Basis left, Basis right)
  973. {
  974. return new Basis
  975. (
  976. right.Tdotx(left.Row0), right.Tdoty(left.Row0), right.Tdotz(left.Row0),
  977. right.Tdotx(left.Row1), right.Tdoty(left.Row1), right.Tdotz(left.Row1),
  978. right.Tdotx(left.Row2), right.Tdoty(left.Row2), right.Tdotz(left.Row2)
  979. );
  980. }
  981. /// <summary>
  982. /// Returns a Vector3 transformed (multiplied) by the basis matrix.
  983. /// </summary>
  984. /// <param name="basis">The basis matrix transformation to apply.</param>
  985. /// <param name="vector">A Vector3 to transform.</param>
  986. /// <returns>The transformed Vector3.</returns>
  987. public static Vector3 operator *(Basis basis, Vector3 vector)
  988. {
  989. return new Vector3
  990. (
  991. basis.Row0.Dot(vector),
  992. basis.Row1.Dot(vector),
  993. basis.Row2.Dot(vector)
  994. );
  995. }
  996. /// <summary>
  997. /// Returns a Vector3 transformed (multiplied) by the transposed basis matrix.
  998. ///
  999. /// Note: This results in a multiplication by the inverse of the
  1000. /// basis matrix only if it represents a rotation-reflection.
  1001. /// </summary>
  1002. /// <param name="vector">A Vector3 to inversely transform.</param>
  1003. /// <param name="basis">The basis matrix transformation to apply.</param>
  1004. /// <returns>The inversely transformed vector.</returns>
  1005. public static Vector3 operator *(Vector3 vector, Basis basis)
  1006. {
  1007. return new Vector3
  1008. (
  1009. basis.Row0[0] * vector.x + basis.Row1[0] * vector.y + basis.Row2[0] * vector.z,
  1010. basis.Row0[1] * vector.x + basis.Row1[1] * vector.y + basis.Row2[1] * vector.z,
  1011. basis.Row0[2] * vector.x + basis.Row1[2] * vector.y + basis.Row2[2] * vector.z
  1012. );
  1013. }
  1014. /// <summary>
  1015. /// Returns <see langword="true"/> if the basis matrices are exactly
  1016. /// equal. Note: Due to floating-point precision errors, consider using
  1017. /// <see cref="IsEqualApprox"/> instead, which is more reliable.
  1018. /// </summary>
  1019. /// <param name="left">The left basis.</param>
  1020. /// <param name="right">The right basis.</param>
  1021. /// <returns>Whether or not the basis matrices are exactly equal.</returns>
  1022. public static bool operator ==(Basis left, Basis right)
  1023. {
  1024. return left.Equals(right);
  1025. }
  1026. /// <summary>
  1027. /// Returns <see langword="true"/> if the basis matrices are not equal.
  1028. /// Note: Due to floating-point precision errors, consider using
  1029. /// <see cref="IsEqualApprox"/> instead, which is more reliable.
  1030. /// </summary>
  1031. /// <param name="left">The left basis.</param>
  1032. /// <param name="right">The right basis.</param>
  1033. /// <returns>Whether or not the basis matrices are not equal.</returns>
  1034. public static bool operator !=(Basis left, Basis right)
  1035. {
  1036. return !left.Equals(right);
  1037. }
  1038. /// <summary>
  1039. /// Returns <see langword="true"/> if the <see cref="Basis"/> is
  1040. /// exactly equal to the given object (<see paramref="obj"/>).
  1041. /// Note: Due to floating-point precision errors, consider using
  1042. /// <see cref="IsEqualApprox"/> instead, which is more reliable.
  1043. /// </summary>
  1044. /// <param name="obj">The object to compare with.</param>
  1045. /// <returns>Whether or not the basis matrix and the object are exactly equal.</returns>
  1046. public override readonly bool Equals(object obj)
  1047. {
  1048. return obj is Basis other && Equals(other);
  1049. }
  1050. /// <summary>
  1051. /// Returns <see langword="true"/> if the basis matrices are exactly
  1052. /// equal. Note: Due to floating-point precision errors, consider using
  1053. /// <see cref="IsEqualApprox"/> instead, which is more reliable.
  1054. /// </summary>
  1055. /// <param name="other">The other basis.</param>
  1056. /// <returns>Whether or not the basis matrices are exactly equal.</returns>
  1057. public readonly bool Equals(Basis other)
  1058. {
  1059. return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2);
  1060. }
  1061. /// <summary>
  1062. /// Returns <see langword="true"/> if this basis and <paramref name="other"/> are approximately equal,
  1063. /// by running <see cref="Vector3.IsEqualApprox(Vector3)"/> on each component.
  1064. /// </summary>
  1065. /// <param name="other">The other basis to compare.</param>
  1066. /// <returns>Whether or not the bases are approximately equal.</returns>
  1067. public readonly bool IsEqualApprox(Basis other)
  1068. {
  1069. return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2);
  1070. }
  1071. /// <summary>
  1072. /// Serves as the hash function for <see cref="Basis"/>.
  1073. /// </summary>
  1074. /// <returns>A hash code for this basis.</returns>
  1075. public override readonly int GetHashCode()
  1076. {
  1077. return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode();
  1078. }
  1079. /// <summary>
  1080. /// Converts this <see cref="Basis"/> to a string.
  1081. /// </summary>
  1082. /// <returns>A string representation of this basis.</returns>
  1083. public override readonly string ToString()
  1084. {
  1085. return $"[X: {x}, Y: {y}, Z: {z}]";
  1086. }
  1087. /// <summary>
  1088. /// Converts this <see cref="Basis"/> to a string with the given <paramref name="format"/>.
  1089. /// </summary>
  1090. /// <returns>A string representation of this basis.</returns>
  1091. public readonly string ToString(string format)
  1092. {
  1093. return $"[X: {x.ToString(format)}, Y: {y.ToString(format)}, Z: {z.ToString(format)}]";
  1094. }
  1095. }
  1096. }