1*635a8641SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker #include "ui/gfx/geometry/quaternion.h"
6*635a8641SAndroid Build Coastguard Worker
7*635a8641SAndroid Build Coastguard Worker #include <algorithm>
8*635a8641SAndroid Build Coastguard Worker #include <cmath>
9*635a8641SAndroid Build Coastguard Worker
10*635a8641SAndroid Build Coastguard Worker #include "base/numerics/math_constants.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
12*635a8641SAndroid Build Coastguard Worker #include "ui/gfx/geometry/vector3d_f.h"
13*635a8641SAndroid Build Coastguard Worker
14*635a8641SAndroid Build Coastguard Worker namespace gfx {
15*635a8641SAndroid Build Coastguard Worker
16*635a8641SAndroid Build Coastguard Worker namespace {
17*635a8641SAndroid Build Coastguard Worker
18*635a8641SAndroid Build Coastguard Worker const double kEpsilon = 1e-5;
19*635a8641SAndroid Build Coastguard Worker
20*635a8641SAndroid Build Coastguard Worker } // namespace
21*635a8641SAndroid Build Coastguard Worker
Quaternion(const Vector3dF & axis,double theta)22*635a8641SAndroid Build Coastguard Worker Quaternion::Quaternion(const Vector3dF& axis, double theta) {
23*635a8641SAndroid Build Coastguard Worker // Rotation angle is the product of |angle| and the magnitude of |axis|.
24*635a8641SAndroid Build Coastguard Worker double length = axis.Length();
25*635a8641SAndroid Build Coastguard Worker if (std::abs(length) < kEpsilon)
26*635a8641SAndroid Build Coastguard Worker return;
27*635a8641SAndroid Build Coastguard Worker
28*635a8641SAndroid Build Coastguard Worker Vector3dF normalized = axis;
29*635a8641SAndroid Build Coastguard Worker normalized.Scale(1.0 / length);
30*635a8641SAndroid Build Coastguard Worker
31*635a8641SAndroid Build Coastguard Worker theta *= 0.5;
32*635a8641SAndroid Build Coastguard Worker double s = sin(theta);
33*635a8641SAndroid Build Coastguard Worker x_ = normalized.x() * s;
34*635a8641SAndroid Build Coastguard Worker y_ = normalized.y() * s;
35*635a8641SAndroid Build Coastguard Worker z_ = normalized.z() * s;
36*635a8641SAndroid Build Coastguard Worker w_ = cos(theta);
37*635a8641SAndroid Build Coastguard Worker }
38*635a8641SAndroid Build Coastguard Worker
Quaternion(const Vector3dF & from,const Vector3dF & to)39*635a8641SAndroid Build Coastguard Worker Quaternion::Quaternion(const Vector3dF& from, const Vector3dF& to) {
40*635a8641SAndroid Build Coastguard Worker double dot = gfx::DotProduct(from, to);
41*635a8641SAndroid Build Coastguard Worker double norm = sqrt(from.LengthSquared() * to.LengthSquared());
42*635a8641SAndroid Build Coastguard Worker double real = norm + dot;
43*635a8641SAndroid Build Coastguard Worker gfx::Vector3dF axis;
44*635a8641SAndroid Build Coastguard Worker if (real < kEpsilon * norm) {
45*635a8641SAndroid Build Coastguard Worker real = 0.0f;
46*635a8641SAndroid Build Coastguard Worker axis = std::abs(from.x()) > std::abs(from.z())
47*635a8641SAndroid Build Coastguard Worker ? gfx::Vector3dF{-from.y(), from.x(), 0.0}
48*635a8641SAndroid Build Coastguard Worker : gfx::Vector3dF{0.0, -from.z(), from.y()};
49*635a8641SAndroid Build Coastguard Worker } else {
50*635a8641SAndroid Build Coastguard Worker axis = gfx::CrossProduct(from, to);
51*635a8641SAndroid Build Coastguard Worker }
52*635a8641SAndroid Build Coastguard Worker x_ = axis.x();
53*635a8641SAndroid Build Coastguard Worker y_ = axis.y();
54*635a8641SAndroid Build Coastguard Worker z_ = axis.z();
55*635a8641SAndroid Build Coastguard Worker w_ = real;
56*635a8641SAndroid Build Coastguard Worker *this = this->Normalized();
57*635a8641SAndroid Build Coastguard Worker }
58*635a8641SAndroid Build Coastguard Worker
59*635a8641SAndroid Build Coastguard Worker // Taken from http://www.w3.org/TR/css3-transforms/.
Slerp(const Quaternion & q,double t) const60*635a8641SAndroid Build Coastguard Worker Quaternion Quaternion::Slerp(const Quaternion& q, double t) const {
61*635a8641SAndroid Build Coastguard Worker double dot = x_ * q.x_ + y_ * q.y_ + z_ * q.z_ + w_ * q.w_;
62*635a8641SAndroid Build Coastguard Worker
63*635a8641SAndroid Build Coastguard Worker // Clamp dot to -1.0 <= dot <= 1.0.
64*635a8641SAndroid Build Coastguard Worker dot = std::min(std::max(dot, -1.0), 1.0);
65*635a8641SAndroid Build Coastguard Worker
66*635a8641SAndroid Build Coastguard Worker // Quaternions are facing the same direction.
67*635a8641SAndroid Build Coastguard Worker if (std::abs(dot - 1.0) < kEpsilon || std::abs(dot + 1.0) < kEpsilon)
68*635a8641SAndroid Build Coastguard Worker return *this;
69*635a8641SAndroid Build Coastguard Worker
70*635a8641SAndroid Build Coastguard Worker double denom = std::sqrt(1.0 - dot * dot);
71*635a8641SAndroid Build Coastguard Worker double theta = std::acos(dot);
72*635a8641SAndroid Build Coastguard Worker double w = std::sin(t * theta) * (1.0 / denom);
73*635a8641SAndroid Build Coastguard Worker
74*635a8641SAndroid Build Coastguard Worker double s1 = std::cos(t * theta) - dot * w;
75*635a8641SAndroid Build Coastguard Worker double s2 = w;
76*635a8641SAndroid Build Coastguard Worker
77*635a8641SAndroid Build Coastguard Worker return (s1 * *this) + (s2 * q);
78*635a8641SAndroid Build Coastguard Worker }
79*635a8641SAndroid Build Coastguard Worker
Lerp(const Quaternion & q,double t) const80*635a8641SAndroid Build Coastguard Worker Quaternion Quaternion::Lerp(const Quaternion& q, double t) const {
81*635a8641SAndroid Build Coastguard Worker return (((1.0 - t) * *this) + (t * q)).Normalized();
82*635a8641SAndroid Build Coastguard Worker }
83*635a8641SAndroid Build Coastguard Worker
Length() const84*635a8641SAndroid Build Coastguard Worker double Quaternion::Length() const {
85*635a8641SAndroid Build Coastguard Worker return x_ * x_ + y_ * y_ + z_ * z_ + w_ * w_;
86*635a8641SAndroid Build Coastguard Worker }
87*635a8641SAndroid Build Coastguard Worker
Normalized() const88*635a8641SAndroid Build Coastguard Worker Quaternion Quaternion::Normalized() const {
89*635a8641SAndroid Build Coastguard Worker double length = Length();
90*635a8641SAndroid Build Coastguard Worker if (length < kEpsilon)
91*635a8641SAndroid Build Coastguard Worker return *this;
92*635a8641SAndroid Build Coastguard Worker return *this / sqrt(length);
93*635a8641SAndroid Build Coastguard Worker }
94*635a8641SAndroid Build Coastguard Worker
ToString() const95*635a8641SAndroid Build Coastguard Worker std::string Quaternion::ToString() const {
96*635a8641SAndroid Build Coastguard Worker // q = (con(abs(v_theta)/2), v_theta/abs(v_theta) * sin(abs(v_theta)/2))
97*635a8641SAndroid Build Coastguard Worker float abs_theta = acos(w_) * 2;
98*635a8641SAndroid Build Coastguard Worker float scale = 1. / sin(abs_theta * .5);
99*635a8641SAndroid Build Coastguard Worker gfx::Vector3dF v(x_, y_, z_);
100*635a8641SAndroid Build Coastguard Worker v.Scale(scale);
101*635a8641SAndroid Build Coastguard Worker return base::StringPrintf("[%f %f %f %f], v:", x_, y_, z_, w_) +
102*635a8641SAndroid Build Coastguard Worker v.ToString() +
103*635a8641SAndroid Build Coastguard Worker base::StringPrintf(", θ:%fπ", abs_theta / base::kPiFloat);
104*635a8641SAndroid Build Coastguard Worker }
105*635a8641SAndroid Build Coastguard Worker
106*635a8641SAndroid Build Coastguard Worker } // namespace gfx
107