gpu: Tweak Android WebGL test expectations
[chromium-blink-merge.git] / ui / gfx / matrix3_f.cc
blob562fdb3a96470aeb50a516e72c08a2fd0e43f8f4
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ui/gfx/matrix3_f.h"
7 #include <algorithm>
8 #include <cmath>
9 #include <limits>
11 #ifndef M_PI
12 #define M_PI 3.14159265358979323846
13 #endif
15 namespace {
17 // This is only to make accessing indices self-explanatory.
18 enum MatrixCoordinates {
19 M00,
20 M01,
21 M02,
22 M10,
23 M11,
24 M12,
25 M20,
26 M21,
27 M22,
28 M_END
31 template<typename T>
32 double Determinant3x3(T data[M_END]) {
33 // This routine is separated from the Matrix3F::Determinant because in
34 // computing inverse we do want higher precision afforded by the explicit
35 // use of 'double'.
36 return
37 static_cast<double>(data[M00]) * (
38 static_cast<double>(data[M11]) * data[M22] -
39 static_cast<double>(data[M12]) * data[M21]) +
40 static_cast<double>(data[M01]) * (
41 static_cast<double>(data[M12]) * data[M20] -
42 static_cast<double>(data[M10]) * data[M22]) +
43 static_cast<double>(data[M02]) * (
44 static_cast<double>(data[M10]) * data[M21] -
45 static_cast<double>(data[M11]) * data[M20]);
48 } // namespace
50 namespace gfx {
52 Matrix3F::Matrix3F() {
55 Matrix3F::~Matrix3F() {
58 // static
59 Matrix3F Matrix3F::Zeros() {
60 Matrix3F matrix;
61 matrix.set(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
62 return matrix;
65 // static
66 Matrix3F Matrix3F::Ones() {
67 Matrix3F matrix;
68 matrix.set(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
69 return matrix;
72 // static
73 Matrix3F Matrix3F::Identity() {
74 Matrix3F matrix;
75 matrix.set(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
76 return matrix;
79 // static
80 Matrix3F Matrix3F::FromOuterProduct(const Vector3dF& a, const Vector3dF& bt) {
81 Matrix3F matrix;
82 matrix.set(a.x() * bt.x(), a.x() * bt.y(), a.x() * bt.z(),
83 a.y() * bt.x(), a.y() * bt.y(), a.y() * bt.z(),
84 a.z() * bt.x(), a.z() * bt.y(), a.z() * bt.z());
85 return matrix;
88 bool Matrix3F::IsEqual(const Matrix3F& rhs) const {
89 return 0 == memcmp(data_, rhs.data_, sizeof(data_));
92 bool Matrix3F::IsNear(const Matrix3F& rhs, float precision) const {
93 DCHECK(precision >= 0);
94 for (int i = 0; i < M_END; ++i) {
95 if (std::abs(data_[i] - rhs.data_[i]) > precision)
96 return false;
98 return true;
101 Matrix3F Matrix3F::Inverse() const {
102 Matrix3F inverse = Matrix3F::Zeros();
103 double determinant = Determinant3x3(data_);
104 if (std::numeric_limits<float>::epsilon() > std::abs(determinant))
105 return inverse; // Singular matrix. Return Zeros().
107 inverse.set(
108 (data_[M11] * data_[M22] - data_[M12] * data_[M21]) / determinant,
109 (data_[M02] * data_[M21] - data_[M01] * data_[M22]) / determinant,
110 (data_[M01] * data_[M12] - data_[M02] * data_[M11]) / determinant,
111 (data_[M12] * data_[M20] - data_[M10] * data_[M22]) / determinant,
112 (data_[M00] * data_[M22] - data_[M02] * data_[M20]) / determinant,
113 (data_[M02] * data_[M10] - data_[M00] * data_[M12]) / determinant,
114 (data_[M10] * data_[M21] - data_[M11] * data_[M20]) / determinant,
115 (data_[M01] * data_[M20] - data_[M00] * data_[M21]) / determinant,
116 (data_[M00] * data_[M11] - data_[M01] * data_[M10]) / determinant);
117 return inverse;
120 float Matrix3F::Determinant() const {
121 return static_cast<float>(Determinant3x3(data_));
124 Vector3dF Matrix3F::SolveEigenproblem(Matrix3F* eigenvectors) const {
125 // The matrix must be symmetric.
126 const float epsilon = std::numeric_limits<float>::epsilon();
127 if (std::abs(data_[M01] - data_[M10]) > epsilon ||
128 std::abs(data_[M02] - data_[M20]) > epsilon ||
129 std::abs(data_[M12] - data_[M21]) > epsilon) {
130 NOTREACHED();
131 return Vector3dF();
134 float eigenvalues[3];
135 float p =
136 data_[M01] * data_[M01] +
137 data_[M02] * data_[M02] +
138 data_[M12] * data_[M12];
140 bool diagonal = std::abs(p) < epsilon;
141 if (diagonal) {
142 eigenvalues[0] = data_[M00];
143 eigenvalues[1] = data_[M11];
144 eigenvalues[2] = data_[M22];
145 } else {
146 float q = Trace() / 3.0f;
147 p = (data_[M00] - q) * (data_[M00] - q) +
148 (data_[M11] - q) * (data_[M11] - q) +
149 (data_[M22] - q) * (data_[M22] - q) +
150 2 * p;
151 p = std::sqrt(p / 6);
153 // The computation below puts B as (A - qI) / p, where A is *this.
154 Matrix3F matrix_b(*this);
155 matrix_b.data_[M00] -= q;
156 matrix_b.data_[M11] -= q;
157 matrix_b.data_[M22] -= q;
158 for (int i = 0; i < M_END; ++i)
159 matrix_b.data_[i] /= p;
161 double half_det_b = Determinant3x3(matrix_b.data_) / 2.0;
162 // half_det_b should be in <-1, 1>, but beware of rounding error.
163 double phi = 0.0f;
164 if (half_det_b <= -1.0)
165 phi = M_PI / 3;
166 else if (half_det_b < 1.0)
167 phi = acos(half_det_b) / 3;
169 eigenvalues[0] = q + 2 * p * static_cast<float>(cos(phi));
170 eigenvalues[2] = q + 2 * p *
171 static_cast<float>(cos(phi + 2.0 * M_PI / 3.0));
172 eigenvalues[1] = 3 * q - eigenvalues[0] - eigenvalues[2];
175 // Put eigenvalues in the descending order.
176 int indices[3] = {0, 1, 2};
177 if (eigenvalues[2] > eigenvalues[1]) {
178 std::swap(eigenvalues[2], eigenvalues[1]);
179 std::swap(indices[2], indices[1]);
182 if (eigenvalues[1] > eigenvalues[0]) {
183 std::swap(eigenvalues[1], eigenvalues[0]);
184 std::swap(indices[1], indices[0]);
187 if (eigenvalues[2] > eigenvalues[1]) {
188 std::swap(eigenvalues[2], eigenvalues[1]);
189 std::swap(indices[2], indices[1]);
192 if (eigenvectors != NULL && diagonal) {
193 // Eigenvectors are e-vectors, just need to be sorted accordingly.
194 *eigenvectors = Zeros();
195 for (int i = 0; i < 3; ++i)
196 eigenvectors->set(indices[i], i, 1.0f);
197 } else if (eigenvectors != NULL) {
198 // Consult the following for a detailed discussion:
199 // Joachim Kopp
200 // Numerical diagonalization of hermitian 3x3 matrices
201 // arXiv.org preprint: physics/0610206
202 // Int. J. Mod. Phys. C19 (2008) 523-548
204 // TODO(motek): expand to handle correctly negative and multiple
205 // eigenvalues.
206 for (int i = 0; i < 3; ++i) {
207 float l = eigenvalues[i];
208 // B = A - l * I
209 Matrix3F matrix_b(*this);
210 matrix_b.data_[M00] -= l;
211 matrix_b.data_[M11] -= l;
212 matrix_b.data_[M22] -= l;
213 Vector3dF e1 = CrossProduct(matrix_b.get_column(0),
214 matrix_b.get_column(1));
215 Vector3dF e2 = CrossProduct(matrix_b.get_column(1),
216 matrix_b.get_column(2));
217 Vector3dF e3 = CrossProduct(matrix_b.get_column(2),
218 matrix_b.get_column(0));
220 // e1, e2 and e3 should point in the same direction.
221 if (DotProduct(e1, e2) < 0)
222 e2 = -e2;
224 if (DotProduct(e1, e3) < 0)
225 e3 = -e3;
227 Vector3dF eigvec = e1 + e2 + e3;
228 // Normalize.
229 eigvec.Scale(1.0f / eigvec.Length());
230 eigenvectors->set_column(i, eigvec);
234 return Vector3dF(eigenvalues[0], eigenvalues[1], eigenvalues[2]);
237 } // namespace gfx