1 /*
2 * Copyright (C) 1999 Antti Koivisto (koivisto@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 *
20 */
21
22 #include "third_party/blink/renderer/platform/transforms/rotation.h"
23
24 #include "third_party/blink/renderer/platform/geometry/blend.h"
25 #include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
26
27 namespace blink {
28
29 namespace {
30
31 const double kAngleEpsilon = 1e-4;
32
ExtractFromMatrix(const TransformationMatrix & matrix,const Rotation & fallback_value)33 Rotation ExtractFromMatrix(const TransformationMatrix& matrix,
34 const Rotation& fallback_value) {
35 TransformationMatrix::DecomposedType decomp;
36 if (!matrix.Decompose(decomp))
37 return fallback_value;
38 double x = -decomp.quaternion_x;
39 double y = -decomp.quaternion_y;
40 double z = -decomp.quaternion_z;
41 double length = std::sqrt(x * x + y * y + z * z);
42 double angle = 0;
43 if (length > 0.00001) {
44 x /= length;
45 y /= length;
46 z /= length;
47 angle = rad2deg(std::acos(decomp.quaternion_w) * 2);
48 } else {
49 x = 0;
50 y = 0;
51 z = 1;
52 }
53 return Rotation(FloatPoint3D(x, y, z), angle);
54 }
55
56 } // namespace
57
GetCommonAxis(const Rotation & a,const Rotation & b,FloatPoint3D & result_axis,double & result_angle_a,double & result_angle_b)58 bool Rotation::GetCommonAxis(const Rotation& a,
59 const Rotation& b,
60 FloatPoint3D& result_axis,
61 double& result_angle_a,
62 double& result_angle_b) {
63 result_axis = FloatPoint3D(0, 0, 1);
64 result_angle_a = 0;
65 result_angle_b = 0;
66
67 bool is_zero_a = a.axis.IsZero() || fabs(a.angle) < kAngleEpsilon;
68 bool is_zero_b = b.axis.IsZero() || fabs(b.angle) < kAngleEpsilon;
69
70 if (is_zero_a && is_zero_b)
71 return true;
72
73 if (is_zero_a) {
74 result_axis = b.axis;
75 result_angle_b = b.angle;
76 return true;
77 }
78
79 if (is_zero_b) {
80 result_axis = a.axis;
81 result_angle_a = a.angle;
82 return true;
83 }
84
85 double dot = a.axis.Dot(b.axis);
86 if (dot < 0)
87 return false;
88
89 double a_squared = a.axis.LengthSquared();
90 double b_squared = b.axis.LengthSquared();
91 double error = std::abs(1 - (dot * dot) / (a_squared * b_squared));
92 if (error > kAngleEpsilon)
93 return false;
94
95 result_axis = a.axis;
96 result_angle_a = a.angle;
97 result_angle_b = b.angle;
98 return true;
99 }
100
Slerp(const Rotation & from,const Rotation & to,double progress)101 Rotation Rotation::Slerp(const Rotation& from,
102 const Rotation& to,
103 double progress) {
104 double from_angle;
105 double to_angle;
106 FloatPoint3D axis;
107 if (GetCommonAxis(from, to, axis, from_angle, to_angle))
108 return Rotation(axis, blink::Blend(from_angle, to_angle, progress));
109
110 TransformationMatrix from_matrix;
111 TransformationMatrix to_matrix;
112 from_matrix.Rotate3d(from);
113 to_matrix.Rotate3d(to);
114 to_matrix.Blend(from_matrix, progress);
115 return ExtractFromMatrix(to_matrix, progress < 0.5 ? from : to);
116 }
117
Add(const Rotation & a,const Rotation & b)118 Rotation Rotation::Add(const Rotation& a, const Rotation& b) {
119 double angle_a;
120 double angle_b;
121 FloatPoint3D axis;
122 if (GetCommonAxis(a, b, axis, angle_a, angle_b))
123 return Rotation(axis, angle_a + angle_b);
124
125 TransformationMatrix matrix;
126 matrix.Rotate3d(a);
127 matrix.Rotate3d(b);
128 return ExtractFromMatrix(matrix, b);
129 }
130
131 } // namespace blink
132