ConvertCoordinates.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Matrix.h>
  9. #include <Mathematics/GaussianElimination.h>
  10. // Convert points and transformations between two coordinate systems.
  11. // The mathematics involves a change of basis. See the document
  12. // https://www.geometrictools.com/Documentation/ConvertingBetweenCoordinateSystems.pdf
  13. // for the details. Typical usage for 3D conversion is shown next.
  14. //
  15. // // Linear change of basis. The columns of U are the basis vectors for the
  16. // // source coordinate system. A vector X = { x0, x1, x2 } in the source
  17. // // coordinate system is represented by
  18. // // X = x0*(1,0,0) + x1*(0,1,0) + x2*(0,0,1)
  19. // // The Cartesian coordinates for the point are the combination of these
  20. // // terms,
  21. // // X = (x0, x1, x2)
  22. // // The columns of V are the basis vectors for the target coordinate system.
  23. // // A vector Y = { y0, y1, y2 } in the target coordinate system is
  24. // // represented by
  25. // // Y = y0*(1,0,0,0) + y1*(0,0,1) + y2*(0,1,0)
  26. // // The Cartesian coordinates for the vector are the combination of these
  27. // // terms,
  28. // // Y = (y0, y2, y1)
  29. // // The call Y = convert.UToV(X) computes y0, y1 and y2 so that the Cartesian
  30. // // coordinates for X and for Y are the same. For example,
  31. // // X = { 1.0, 2.0, 3.0 }
  32. // // = 1.0*(1,0,0) + 2.0*(0,1,0) + 3.0*(0,0,1)
  33. // // = (1, 2, 3)
  34. // // Y = { 1.0, 3.0, 2.0 }
  35. // // = 1.0*(1,0,0) + 3.0*(0,0,1) + 2.0*(0,1,0)
  36. // // = (1, 2, 3)
  37. // // X and Y represent the same vector (equal Cartesian coordinates) but have
  38. // // different representations in the source and target coordinates.
  39. //
  40. // ConvertCoordinates<3, double> convert;
  41. // Vector<3, double> X, Y, P0, P1, diff;
  42. // Matrix<3, 3, double> U, V, A, B;
  43. // bool isRHU, isRHV;
  44. // U.SetCol(0, Vector3<double>{1.0, 0.0, 0.0});
  45. // U.SetCol(1, Vector3<double>{0.0, 1.0, 0.0});
  46. // U.SetCol(2, Vector3<double>{0.0, 0.0, 1.0});
  47. // V.SetCol(0, Vector3<double>{1.0, 0.0, 0.0});
  48. // V.SetCol(1, Vector3<double>{0.0, 0.0, 1.0});
  49. // V.SetCol(2, Vector3<double>{0.0, 1.0, 0.0});
  50. // convert(U, true, V, true);
  51. // isRHU = convert.IsRightHandedU(); // true
  52. // isRHV = convert.IsRightHandedV(); // false
  53. // X = { 1.0, 2.0, 3.0 };
  54. // Y = convert.UToV(X); // { 1.0, 3.0, 2.0 }
  55. // P0 = U*X;
  56. // P1 = V*Y;
  57. // diff = P0 - P1; // { 0, 0, 0 }
  58. // Y = { 0.0, 1.0, 2.0 };
  59. // X = convert.VToU(Y); // { 0.0, 2.0, 1.0 }
  60. // P0 = U*X;
  61. // P1 = V*Y;
  62. // diff = P0 - P1; // { 0, 0, 0 }
  63. // double cs = 0.6, sn = 0.8; // cs*cs + sn*sn = 1
  64. // A.SetCol(0, Vector3<double>{ c, s, 0.0});
  65. // A.SetCol(1, Vector3<double>{ -s, c, 0.0});
  66. // A.SetCol(2, Vector3<double>{0.0, 0.0, 1.0});
  67. // B = convert.UToV(A);
  68. // // B.GetCol(0) = { c, 0, s}
  69. // // B.GetCol(1) = { 0, 1, 0}
  70. // // B.GetCol(2) = {-s, 0, c}
  71. // X = A*X; // U is VOR
  72. // Y = B*Y; // V is VOR
  73. // P0 = U*X;
  74. // P1 = V*Y;
  75. // diff = P0 - P1; // { 0, 0, 0 }
  76. //
  77. // // Affine change of basis. The first three columns of U are the basis
  78. // // vectors for the source coordinate system and must have last components
  79. // // set to 0. The last column is the origin for that system and must have
  80. // // last component set to 1. A point X = { x0, x1, x2, 1 } in the source
  81. // // coordinate system is represented by
  82. // // X = x0*(-1,0,0,0) + x1*(0,0,1,0) + x2*(0,-1,0,0) + 1*(1,2,3,1)
  83. // // The Cartesian coordinates for the point are the combination of these
  84. // // terms,
  85. // // X = (-x0 + 1, -x2 + 2, x1 + 3, 1)
  86. // // The first three columns of V are the basis vectors for the target
  87. // // coordinate system and must have last components set to 0. The last
  88. // // column is the origin for that system and must have last component set
  89. // // to 1. A point Y = { y0, y1, y2, 1 } in the target coordinate system is
  90. // // represented by
  91. // // Y = y0*(0,1,0,0) + y1*(-1,0,0,0) + y2*(0,0,1,0) + 1*(4,5,6,1)
  92. // // The Cartesian coordinates for the point are the combination of these
  93. // // terms,
  94. // // Y = (-y1 + 4, y0 + 5, y2 + 6, 1)
  95. // // The call Y = convert.UToV(X) computes y0, y1 and y2 so that the Cartesian
  96. // // coordinates for X and for Y are the same. For example,
  97. // // X = { -1.0, 4.0, -3.0, 1.0 }
  98. // // = -1.0*(-1,0,0,0) + 4.0*(0,0,1,0) - 3.0*(0,-1,0,0) + 1.0*(1,2,3,1)
  99. // // = (2, 5, 7, 1)
  100. // // Y = { 0.0, 2.0, 1.0, 1.0 }
  101. // // = 0.0*(0,1,0,0) + 2.0*(-1,0,0,0) + 1.0*(0,0,1,0) + 1.0*(4,5,6,1)
  102. // // = (2, 5, 7, 1)
  103. // // X and Y represent the same point (equal Cartesian coordinates) but have
  104. // // different representations in the source and target affine coordinates.
  105. //
  106. // ConvertCoordinates<4, double> convert;
  107. // Vector<4, double> X, Y, P0, P1, diff;
  108. // Matrix<4, 4, double> U, V, A, B;
  109. // bool isRHU, isRHV;
  110. // U.SetCol(0, Vector4<double>{-1.0, 0.0, 0.0, 0.0});
  111. // U.SetCol(1, Vector4<double>{0.0, 0.0, 1.0, 0.0});
  112. // U.SetCol(2, Vector4<double>{0.0, -1.0, 0.0, 0.0});
  113. // U.SetCol(3, Vector4<double>{1.0, 2.0, 3.0, 1.0});
  114. // V.SetCol(0, Vector4<double>{0.0, 1.0, 0.0, 0.0});
  115. // V.SetCol(1, Vector4<double>{-1.0, 0.0, 0.0, 0.0});
  116. // V.SetCol(2, Vector4<double>{0.0, 0.0, 1.0, 0.0});
  117. // V.SetCol(3, Vector4<double>{4.0, 5.0, 6.0, 1.0});
  118. // convert(U, true, V, false);
  119. // isRHU = convert.IsRightHandedU(); // false
  120. // isRHV = convert.IsRightHandedV(); // true
  121. // X = { -1.0, 4.0, -3.0, 1.0 };
  122. // Y = convert.UToV(X); // { 0.0, 2.0, 1.0, 1.0 }
  123. // P0 = U*X;
  124. // P1 = V*Y;
  125. // diff = P0 - P1; // { 0, 0, 0, 0 }
  126. // Y = { 1.0, 2.0, 3.0, 1.0 };
  127. // X = convert.VToU(Y); // { -1.0, 6.0, -4.0, 1.0 }
  128. // P0 = U*X;
  129. // P1 = V*Y;
  130. // diff = P0 - P1; // { 0, 0, 0, 0 }
  131. // double c = 0.6, s = 0.8; // c*c + s*s = 1
  132. // A.SetCol(0, Vector4<double>{ c, s, 0.0, 0.0});
  133. // A.SetCol(1, Vector4<double>{ -s, c, 0.0, 0.0});
  134. // A.SetCol(2, Vector4<double>{0.0, 0.0, 1.0, 0.0});
  135. // A.SetCol(3, Vector4<double>{0.3, 1.0, -2.0, 1.0});
  136. // B = convert.UToV(A);
  137. // // B.GetCol(0) = { 1, 0, 0, 0 }
  138. // // B.GetCol(1) = { 0, c, s, 0 }
  139. // // B.GetCol(2) = { 0, -s, c, 0 }
  140. // // B.GetCol(3) = { 2.0, -0.9, -2.6, 1 }
  141. // X = A*X; // U is VOR
  142. // Y = Y*B; // V is VOL (not VOR)
  143. // P0 = U*X;
  144. // P1 = V*Y;
  145. // diff = P0 - P1; // { 0, 0, 0, 0 }
  146. namespace WwiseGTE
  147. {
  148. template <int N, typename Real>
  149. class ConvertCoordinates
  150. {
  151. public:
  152. // Construction of the change of basis matrix. The implementation
  153. // supports both linear change of basis and affine change of basis.
  154. ConvertCoordinates()
  155. :
  156. mIsVectorOnRightU(true),
  157. mIsVectorOnRightV(true),
  158. mIsRightHandedU(true),
  159. mIsRightHandedV(true)
  160. {
  161. mC.MakeIdentity();
  162. mInverseC.MakeIdentity();
  163. }
  164. // Compute a change of basis between two coordinate systems. The
  165. // return value is 'true' iff U and V are invertible. The
  166. // matrix-vector multiplication conventions affect the conversion of
  167. // matrix transformations. The Boolean inputs indicate how you want
  168. // the matrices to be interpreted when applied as transformations of
  169. // a vector.
  170. bool operator()(
  171. Matrix<N, N, Real> const& U, bool vectorOnRightU,
  172. Matrix<N, N, Real> const& V, bool vectorOnRightV)
  173. {
  174. // Initialize in case of early exit.
  175. mC.MakeIdentity();
  176. mInverseC.MakeIdentity();
  177. mIsVectorOnRightU = true;
  178. mIsVectorOnRightV = true;
  179. mIsRightHandedU = true;
  180. mIsRightHandedV = true;
  181. Matrix<N, N, Real> inverseU;
  182. Real determinantU;
  183. bool invertibleU = GaussianElimination<Real>()(N, &U[0], &inverseU[0],
  184. determinantU, nullptr, nullptr, nullptr, 0, nullptr);
  185. if (!invertibleU)
  186. {
  187. return false;
  188. }
  189. Matrix<N, N, Real> inverseV;
  190. Real determinantV;
  191. bool invertibleV = GaussianElimination<Real>()(N, &V[0], &inverseV[0],
  192. determinantV, nullptr, nullptr, nullptr, 0, nullptr);
  193. if (!invertibleV)
  194. {
  195. return false;
  196. }
  197. mC = inverseU * V;
  198. mInverseC = inverseV * U;
  199. mIsVectorOnRightU = vectorOnRightU;
  200. mIsVectorOnRightV = vectorOnRightV;
  201. mIsRightHandedU = (determinantU > (Real)0);
  202. mIsRightHandedV = (determinantV > (Real)0);
  203. return true;
  204. }
  205. // Member access.
  206. inline Matrix<N, N, Real> const& GetC() const
  207. {
  208. return mC;
  209. }
  210. inline Matrix<N, N, Real> const& GetInverseC() const
  211. {
  212. return mInverseC;
  213. }
  214. inline bool IsVectorOnRightU() const
  215. {
  216. return mIsVectorOnRightU;
  217. }
  218. inline bool IsVectorOnRightV() const
  219. {
  220. return mIsVectorOnRightV;
  221. }
  222. inline bool IsRightHandedU() const
  223. {
  224. return mIsRightHandedU;
  225. }
  226. inline bool IsRightHandedV() const
  227. {
  228. return mIsRightHandedV;
  229. }
  230. // Convert points between coordinate systems. The names of the
  231. // systems are U and V to make it clear which inputs of operator()
  232. // they are associated with. The X vector stores coordinates for the
  233. // U-system and the Y vector stores coordinates for the V-system.
  234. // Y = C^{-1}*X
  235. inline Vector<N, Real> UToV(Vector<N, Real> const& X) const
  236. {
  237. return mInverseC * X;
  238. }
  239. // X = C*Y
  240. inline Vector<N, Real> VToU(Vector<N, Real> const& Y) const
  241. {
  242. return mC * Y;
  243. }
  244. // Convert transformations between coordinate systems. The outputs
  245. // are computed according to the tables shown before the function
  246. // declarations. The superscript T denotes the transpose operator.
  247. // vectorOnRightU = true: transformation is X' = A*X
  248. // vectorOnRightU = false: transformation is (X')^T = X^T*A
  249. // vectorOnRightV = true: transformation is Y' = B*Y
  250. // vectorOnRightV = false: transformation is (Y')^T = Y^T*B
  251. // vectorOnRightU | vectorOnRightV | output
  252. // ----------------+-----------------+---------------------
  253. // true | true | C^{-1} * A * C
  254. // true | false | (C^{-1} * A * C)^T
  255. // false | true | C^{-1} * A^T * C
  256. // false | false | (C^{-1} * A^T * C)^T
  257. Matrix<N, N, Real> UToV(Matrix<N, N, Real> const& A) const
  258. {
  259. Matrix<N, N, Real> product;
  260. if (mIsVectorOnRightU)
  261. {
  262. product = mInverseC * A * mC;
  263. if (mIsVectorOnRightV)
  264. {
  265. return product;
  266. }
  267. else
  268. {
  269. return Transpose(product);
  270. }
  271. }
  272. else
  273. {
  274. product = mInverseC * MultiplyATB(A, mC);
  275. if (mIsVectorOnRightV)
  276. {
  277. return product;
  278. }
  279. else
  280. {
  281. return Transpose(product);
  282. }
  283. }
  284. }
  285. // vectorOnRightU | vectorOnRightV | output
  286. // ----------------+-----------------+---------------------
  287. // true | true | C * B * C^{-1}
  288. // true | false | C * B^T * C^{-1}
  289. // false | true | (C * B * C^{-1})^T
  290. // false | false | (C * B^T * C^{-1})^T
  291. Matrix<N, N, Real> VToU(Matrix<N, N, Real> const& B) const
  292. {
  293. // vectorOnRightU | vectorOnRightV | output
  294. // ----------------+-----------------+---------------------
  295. // true | true | C * B * C^{-1}
  296. // true | false | C * B^T * C^{-1}
  297. // false | true | (C * B * C^{-1})^T
  298. // false | false | (C * B^T * C^{-1})^T
  299. Matrix<N, N, Real> product;
  300. if (mIsVectorOnRightV)
  301. {
  302. product = mC * B * mInverseC;
  303. if (mIsVectorOnRightU)
  304. {
  305. return product;
  306. }
  307. else
  308. {
  309. return Transpose(product);
  310. }
  311. }
  312. else
  313. {
  314. product = mC * MultiplyATB(B, mInverseC);
  315. if (mIsVectorOnRightU)
  316. {
  317. return product;
  318. }
  319. else
  320. {
  321. return Transpose(product);
  322. }
  323. }
  324. }
  325. private:
  326. // C = U^{-1}*V, C^{-1} = V^{-1}*U
  327. Matrix<N, N, Real> mC, mInverseC;
  328. bool mIsVectorOnRightU, mIsVectorOnRightV;
  329. bool mIsRightHandedU, mIsRightHandedV;
  330. };
  331. }