Vector4.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  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/Vector3.h>
  9. namespace WwiseGTE
  10. {
  11. // Template alias for convenience.
  12. template <typename Real>
  13. using Vector4 = Vector<4, Real>;
  14. // In Vector3.h, the Vector3 Cross, UnitCross, and DotCross have a
  15. // template parameter N that should be 3 or 4. The latter case supports
  16. // affine vectors in 4D (last component w = 0) when you want to use
  17. // 4-tuples and 4x4 matrices for affine algebra. Thus, you may use those
  18. // template functions for Vector4.
  19. // Compute the hypercross product using the formal determinant:
  20. // hcross = det{{e0,e1,e2,e3},{x0,x1,x2,x3},{y0,y1,y2,y3},{z0,z1,z2,z3}}
  21. // where e0 = (1,0,0,0), e1 = (0,1,0,0), e2 = (0,0,1,0), e3 = (0,0,0,1),
  22. // v0 = (x0,x1,x2,x3), v1 = (y0,y1,y2,y3), and v2 = (z0,z1,z2,z3).
  23. template <typename Real>
  24. Vector4<Real> HyperCross(Vector4<Real> const& v0, Vector4<Real> const& v1, Vector4<Real> const& v2)
  25. {
  26. Real m01 = v0[0] * v1[1] - v0[1] * v1[0]; // x0*y1 - y0*x1
  27. Real m02 = v0[0] * v1[2] - v0[2] * v1[0]; // x0*z1 - z0*x1
  28. Real m03 = v0[0] * v1[3] - v0[3] * v1[0]; // x0*w1 - w0*x1
  29. Real m12 = v0[1] * v1[2] - v0[2] * v1[1]; // y0*z1 - z0*y1
  30. Real m13 = v0[1] * v1[3] - v0[3] * v1[1]; // y0*w1 - w0*y1
  31. Real m23 = v0[2] * v1[3] - v0[3] * v1[2]; // z0*w1 - w0*z1
  32. return Vector4<Real>
  33. {
  34. +m23 * v2[1] - m13 * v2[2] + m12 * v2[3], // +m23*y2 - m13*z2 + m12*w2
  35. -m23 * v2[0] + m03 * v2[2] - m02 * v2[3], // -m23*x2 + m03*z2 - m02*w2
  36. +m13 * v2[0] - m03 * v2[1] + m01 * v2[3], // +m13*x2 - m03*y2 + m01*w2
  37. -m12 * v2[0] + m02 * v2[1] - m01 * v2[2] // -m12*x2 + m02*y2 - m01*z2
  38. };
  39. }
  40. // Compute the normalized hypercross product.
  41. template <typename Real>
  42. Vector4<Real> UnitHyperCross(Vector4<Real> const& v0,
  43. Vector4<Real> const& v1, Vector4<Real> const& v2, bool robust = false)
  44. {
  45. Vector4<Real> unitHyperCross = HyperCross(v0, v1, v2);
  46. Normalize(unitHyperCross, robust);
  47. return unitHyperCross;
  48. }
  49. // Compute Dot(HyperCross((x0,x1,x2,x3),(y0,y1,y2,y3),(z0,z1,z2,z3)),
  50. // (w0,w1,w2,w3)), where v0 = (x0,x1,x2,x3), v1 = (y0,y1,y2,y3),
  51. // v2 = (z0,z1,z2,z3), and v3 = (w0,w1,w2,w3).
  52. template <typename Real>
  53. Real DotHyperCross(Vector4<Real> const& v0, Vector4<Real> const& v1,
  54. Vector4<Real> const& v2, Vector4<Real> const& v3)
  55. {
  56. return Dot(HyperCross(v0, v1, v2), v3);
  57. }
  58. // Compute a right-handed orthonormal basis for the orthogonal complement
  59. // of the input vectors. The function returns the smallest length of the
  60. // unnormalized vectors computed during the process. If this value is
  61. // nearly zero, it is possible that the inputs are linearly dependent
  62. // (within numerical round-off errors). On input, numInputs must be 1, 2
  63. // or 3, and v[0] through v[numInputs-1] must be initialized. On output,
  64. // the vectors v[0] through v[3] form an orthonormal set.
  65. template <typename Real>
  66. Real ComputeOrthogonalComplement(int numInputs, Vector4<Real>* v, bool robust = false)
  67. {
  68. if (numInputs == 1)
  69. {
  70. int maxIndex = 0;
  71. Real maxAbsValue = std::fabs(v[0][0]);
  72. for (int i = 1; i < 4; ++i)
  73. {
  74. Real absValue = std::fabs(v[0][i]);
  75. if (absValue > maxAbsValue)
  76. {
  77. maxIndex = i;
  78. maxAbsValue = absValue;
  79. }
  80. }
  81. if (maxIndex < 2)
  82. {
  83. v[1][0] = -v[0][1];
  84. v[1][1] = +v[0][0];
  85. v[1][2] = (Real)0;
  86. v[1][3] = (Real)0;
  87. }
  88. else if (maxIndex == 3)
  89. {
  90. // Generally, you can skip this clause and swap the last two
  91. // components. However, by swapping 2 and 3 in this case, we
  92. // allow the function to work properly when the inputs are 3D
  93. // vectors represented as 4D affine vectors (w = 0).
  94. v[1][0] = (Real)0;
  95. v[1][1] = +v[0][2];
  96. v[1][2] = -v[0][1];
  97. v[1][3] = (Real)0;
  98. }
  99. else
  100. {
  101. v[1][0] = (Real)0;
  102. v[1][1] = (Real)0;
  103. v[1][2] = -v[0][3];
  104. v[1][3] = +v[0][2];
  105. }
  106. numInputs = 2;
  107. }
  108. if (numInputs == 2)
  109. {
  110. Real det[6] =
  111. {
  112. v[0][0] * v[1][1] - v[1][0] * v[0][1],
  113. v[0][0] * v[1][2] - v[1][0] * v[0][2],
  114. v[0][0] * v[1][3] - v[1][0] * v[0][3],
  115. v[0][1] * v[1][2] - v[1][1] * v[0][2],
  116. v[0][1] * v[1][3] - v[1][1] * v[0][3],
  117. v[0][2] * v[1][3] - v[1][2] * v[0][3]
  118. };
  119. int maxIndex = 0;
  120. Real maxAbsValue = std::fabs(det[0]);
  121. for (int i = 1; i < 6; ++i)
  122. {
  123. Real absValue = std::fabs(det[i]);
  124. if (absValue > maxAbsValue)
  125. {
  126. maxIndex = i;
  127. maxAbsValue = absValue;
  128. }
  129. }
  130. if (maxIndex == 0)
  131. {
  132. v[2] = { -det[4], +det[2], (Real)0, -det[0] };
  133. }
  134. else if (maxIndex <= 2)
  135. {
  136. v[2] = { +det[5], (Real)0, -det[2], +det[1] };
  137. }
  138. else
  139. {
  140. v[2] = { (Real)0, -det[5], +det[4], -det[3] };
  141. }
  142. numInputs = 3;
  143. }
  144. if (numInputs == 3)
  145. {
  146. v[3] = HyperCross(v[0], v[1], v[2]);
  147. return Orthonormalize<4, Real>(4, v, robust);
  148. }
  149. return (Real)0;
  150. }
  151. }