rotation.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. /*
  2. * Copyright 2019 Google Inc. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "rotation.h"
  17. #include <cmath>
  18. #include <limits>
  19. #include "vectorutils.h"
  20. namespace cardboard {
  21. void Rotation::SetAxisAndAngle(const VectorType& axis, double angle)
  22. {
  23. VectorType unit_axis = axis;
  24. if (!Normalize(&unit_axis)) {
  25. *this = Identity();
  26. } else {
  27. double a = angle / 2;
  28. const double s = sin(a);
  29. const VectorType v(unit_axis * s);
  30. SetQuaternion(QuaternionType(v[0], v[1], v[2], cos(a)));
  31. }
  32. }
  33. Rotation Rotation::FromRotationMatrix(const Matrix3x3& mat)
  34. {
  35. static const double kOne = 1.0;
  36. static const double kFour = 4.0;
  37. const double d0 = mat(0, 0), d1 = mat(1, 1), d2 = mat(2, 2);
  38. const double ww = kOne + d0 + d1 + d2;
  39. const double xx = kOne + d0 - d1 - d2;
  40. const double yy = kOne - d0 + d1 - d2;
  41. const double zz = kOne - d0 - d1 + d2;
  42. const double max = std::max(ww, std::max(xx, std::max(yy, zz)));
  43. if (ww == max) {
  44. const double w4 = sqrt(ww * kFour);
  45. return Rotation::FromQuaternion(QuaternionType((mat(2, 1) - mat(1, 2)) / w4,
  46. (mat(0, 2) - mat(2, 0)) / w4, (mat(1, 0) - mat(0, 1)) / w4, w4 / kFour));
  47. }
  48. if (xx == max) {
  49. const double x4 = sqrt(xx * kFour);
  50. return Rotation::FromQuaternion(QuaternionType(x4 / kFour, (mat(0, 1) + mat(1, 0)) / x4,
  51. (mat(0, 2) + mat(2, 0)) / x4, (mat(2, 1) - mat(1, 2)) / x4));
  52. }
  53. if (yy == max) {
  54. const double y4 = sqrt(yy * kFour);
  55. return Rotation::FromQuaternion(QuaternionType((mat(0, 1) + mat(1, 0)) / y4, y4 / kFour,
  56. (mat(1, 2) + mat(2, 1)) / y4, (mat(0, 2) - mat(2, 0)) / y4));
  57. }
  58. // zz is the largest component.
  59. const double z4 = sqrt(zz * kFour);
  60. return Rotation::FromQuaternion(QuaternionType((mat(0, 2) + mat(2, 0)) / z4,
  61. (mat(1, 2) + mat(2, 1)) / z4, z4 / kFour, (mat(1, 0) - mat(0, 1)) / z4));
  62. }
  63. void Rotation::GetAxisAndAngle(VectorType* axis, double* angle) const
  64. {
  65. VectorType vec(quat_[0], quat_[1], quat_[2]);
  66. if (Normalize(&vec)) {
  67. *angle = 2 * acos(quat_[3]);
  68. *axis = vec;
  69. } else {
  70. *axis = VectorType(1, 0, 0);
  71. *angle = 0.0;
  72. }
  73. }
  74. Rotation Rotation::RotateInto(const VectorType& from, const VectorType& to)
  75. {
  76. static const double kTolerance = std::numeric_limits<double>::epsilon() * 100;
  77. // Directly build the quaternion using the following technique:
  78. // http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
  79. const double norm_u_norm_v = sqrt(LengthSquared(from) * LengthSquared(to));
  80. double real_part = norm_u_norm_v + Dot(from, to);
  81. VectorType w;
  82. if (real_part < kTolerance * norm_u_norm_v) {
  83. // If |from| and |to| are exactly opposite, rotate 180 degrees around an
  84. // arbitrary orthogonal axis. Axis normalization can happen later, when we
  85. // normalize the quaternion.
  86. real_part = 0.0;
  87. w = (abs(from[0]) > abs(from[2])) ? VectorType(-from[1], from[0], 0)
  88. : VectorType(0, -from[2], from[1]);
  89. } else {
  90. // Otherwise, build the quaternion the standard way.
  91. w = Cross(from, to);
  92. }
  93. // Build and return a normalized quaternion.
  94. // Note that Rotation::FromQuaternion automatically performs normalization.
  95. return Rotation::FromQuaternion(QuaternionType(w[0], w[1], w[2], real_part));
  96. }
  97. Rotation::VectorType Rotation::operator*(const Rotation::VectorType& v) const
  98. {
  99. return ApplyToVector(v);
  100. }
  101. } // namespace cardboard