Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: ui/gfx/matrix3_f.cc

Issue 12096069: New Matrix3F class added in gfx. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Completed renaming + a float PI. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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.
4
5 #include "ui/gfx/matrix3_f.h"
6
7 #include <algorithm>
8 #include <cmath>
9 #include <limits>
10
11 #ifndef M_PI
12 #define M_PI 3.14159265358979323846f
13 #endif
14
15 namespace {
16
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
29 };
30
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]);
46 }
47
48 } // namespace
49
50 namespace gfx {
51
52 Matrix3F::Matrix3F() {
53 }
54
55 Matrix3F::Matrix3F(const Matrix3F& rhs) {
56 memcpy(data_, rhs.data_, sizeof(data_));
57 }
58
59 Matrix3F::~Matrix3F() {
60 }
61
62 bool Matrix3F::IsEqual(const Matrix3F& rhs) const {
63 return 0 == memcmp(data_, rhs.data_, sizeof(data_));
64 }
65
66 bool Matrix3F::IsNear(const Matrix3F& rhs, float precision) const {
67 DCHECK(precision >= 0);
68 for (int i = 0; i < M_END; ++i) {
69 if (std::abs(data_[i] - rhs.data_[i]) > precision)
70 return false;
71 }
72 return true;
73 }
74
75 void Matrix3F::set(float m00, float m01, float m02,
76 float m10, float m11, float m12,
77 float m20, float m21, float m22) {
danakj 2013/02/01 00:02:34 oh, missed this. i think this belongs in the heade
motek. 2013/02/01 00:14:02 Done.
78 data_[0] = m00;
79 data_[1] = m01;
80 data_[2] = m02;
81 data_[3] = m10;
82 data_[4] = m11;
83 data_[5] = m12;
84 data_[6] = m20;
85 data_[7] = m21;
86 data_[8] = m22;
87 }
88
89 Matrix3F Matrix3F::Inverse() const {
90 Matrix3F inverse = Matrix3F::Zeros();
91 double determinant = Determinant3x3(data_);
92 if (std::numeric_limits<float>::epsilon() > std::abs(determinant))
93 return inverse; // Singular matrix. Return Zeros().
94
95 inverse.set(
96 (data_[M11] * data_[M22] - data_[M12] * data_[M21]) / determinant,
97 (data_[M02] * data_[M21] - data_[M01] * data_[M22]) / determinant,
98 (data_[M01] * data_[M12] - data_[M02] * data_[M11]) / determinant,
99 (data_[M12] * data_[M20] - data_[M10] * data_[M22]) / determinant,
100 (data_[M00] * data_[M22] - data_[M02] * data_[M20]) / determinant,
101 (data_[M02] * data_[M10] - data_[M00] * data_[M12]) / determinant,
102 (data_[M10] * data_[M21] - data_[M11] * data_[M20]) / determinant,
103 (data_[M01] * data_[M20] - data_[M00] * data_[M21]) / determinant,
104 (data_[M00] * data_[M11] - data_[M01] * data_[M10]) / determinant);
105 return inverse;
106 }
107
108 float Matrix3F::Determinant() const {
109 return static_cast<float>(Determinant3x3(data_));
110 }
111
112 Vector3dF Matrix3F::SolveEigenproblem(Matrix3F* eigenvectors) const {
113 // The matrix must be symmetric.
114 const float epsilon = std::numeric_limits<float>::epsilon();
115 if (std::abs(data_[M01] - data_[M10]) > epsilon ||
116 std::abs(data_[M02] - data_[M02]) > epsilon ||
117 std::abs(data_[M12] - data_[M21]) > epsilon) {
118 NOTREACHED();
119 return Vector3dF();
120 }
121
122 float eigenvalues[3];
123 float p =
124 data_[M01] * data_[M01] +
125 data_[M02] * data_[M02] +
126 data_[M12] * data_[M12];
127
128 bool diagonal = std::abs(p) < epsilon;
129 if (diagonal) {
130 eigenvalues[0] = data_[M00];
131 eigenvalues[1] = data_[M11];
132 eigenvalues[2] = data_[M22];
133 } else {
134 float q = Trace() / 3.0f;
135 p = (data_[M00] - q) * (data_[M00] - q) +
136 (data_[M11] - q) * (data_[M11] - q) +
137 (data_[M22] - q) * (data_[M22] - q) +
138 2 * p;
139 p = sqrt(p / 6);
danakj 2013/02/01 00:02:34 nit: std::sqrt
motek. 2013/02/01 00:14:02 Done.
140
141 // The computation below puts B as (A - qI) / p, where A is *this.
142 Matrix3F matrix_B(*this);
danakj 2013/02/01 00:02:34 nit: matrix_b
motek. 2013/02/01 00:14:02 Done.
143 matrix_B.data_[M00] -= q;
144 matrix_B.data_[M11] -= q;
145 matrix_B.data_[M22] -= q;
146 for (int i = 0; i < M_END; ++i)
147 matrix_B.data_[i] /= p;
148
149 float half_det_b = matrix_B.Determinant() / 2.0f;
150 // half_det_b should be in <-1, 1>, but beware of rounding error.
151 float phi = 0.0f;
152 if (half_det_b <= -1.0f)
153 phi = M_PI / 3;
154 else if (half_det_b < 1.0f)
155 phi = acos(half_det_b) / 3;
156
157 eigenvalues[0] = q + 2 * p * cos(phi);
158 eigenvalues[2] = q + 2 * p * cos(phi + 2.0f * M_PI / 3.0f);
159 eigenvalues[1] = 3 * q - eigenvalues[0] - eigenvalues[2];
160 }
161
162 // Put eigenvalues in the descending order.
163 int indices[3] = {0, 1, 2};
164 if (eigenvalues[2] > eigenvalues[1]) {
165 std::swap(eigenvalues[2], eigenvalues[1]);
166 std::swap(indices[2], indices[1]);
167 }
168
169 if (eigenvalues[1] > eigenvalues[0]) {
170 std::swap(eigenvalues[1], eigenvalues[0]);
171 std::swap(indices[1], indices[0]);
172 }
173
174 if (eigenvalues[2] > eigenvalues[1]) {
175 std::swap(eigenvalues[2], eigenvalues[1]);
176 std::swap(indices[2], indices[1]);
177 }
178
179 if (eigenvectors != NULL && diagonal) {
180 // Eigenvectors are e-vectors, just need to be sorted accordingly.
181 *eigenvectors = Zeros();
182 for (int i = 0; i < 3; ++i)
183 eigenvectors->set(indices[i], i, 1.0f);
184 } else if (eigenvectors != NULL) {
185 // Consult the following for a detailed discussion:
186 // Joachim Kopp
187 // Numerical diagonalization of hermitian 3x3 matrices
188 // arXiv.org preprint: physics/0610206
189 // Int. J. Mod. Phys. C19 (2008) 523-548
190
191 // TODO(motek): expand to handle correctly negative and multiple
192 // eigenvalues.
193 for (int i = 0; i < 3; ++i) {
194 float l = eigenvalues[i];
195 // B = A - l * I
196 Matrix3F matrix_B(*this);
197 matrix_B.data_[M00] -= l;
198 matrix_B.data_[M11] -= l;
199 matrix_B.data_[M22] -= l;
200 Vector3dF e1 = CrossProduct(matrix_B.get_column(0),
201 matrix_B.get_column(1));
202 Vector3dF e2 = CrossProduct(matrix_B.get_column(1),
203 matrix_B.get_column(2));
204 Vector3dF e3 = CrossProduct(matrix_B.get_column(2),
205 matrix_B.get_column(0));
206
207 // e1, e2 and e3 should point in the same direction.
208 if (DotProduct(e1, e2) < 0) {
209 e2.set_x(-e2.x());
danakj 2013/02/01 00:02:34 can use e2 = -e2; ?
motek. 2013/02/01 00:14:02 Ah, didn't notice the op. Cool. Done.
210 e2.set_y(-e2.y());
211 e2.set_z(-e2.z());
212 }
213
214 if (DotProduct(e1, e3) < 0) {
215 e3.set_x(-e3.x());
danakj 2013/02/01 00:02:34 e3 = -e3; ?
motek. 2013/02/01 00:14:02 Done.
216 e3.set_y(-e3.y());
217 e3.set_z(-e3.z());
218 }
219
220 Vector3dF eigvec = e1 + e2 + e3;
221 // Normalize.
222 eigvec.Scale(1.0f / eigvec.Length());
223 eigenvectors->set_column(i, eigvec);
224 }
225 }
226
227 return Vector3dF(eigenvalues[0], eigenvalues[1], eigenvalues[2]);
228 }
229
230 // static
231 Matrix3F Matrix3F::Zeros() {
232 Matrix3F matrix;
233 matrix.set(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
234 return matrix;
235 }
236
237 // static
238 Matrix3F Matrix3F::Ones() {
239 Matrix3F matrix;
240 matrix.set(1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
241 return matrix;
242 }
243
244 // static
245 Matrix3F Matrix3F::Identity() {
246 Matrix3F matrix;
247 matrix.set(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f);
248 return matrix;
249 }
250
251 // static
252 Matrix3F Matrix3F::FromOuterProduct(const Vector3dF& a, const Vector3dF& bt) {
253 Matrix3F matrix;
254 matrix.set(a.x() * bt.x(), a.x() * bt.y(), a.x() * bt.z(),
255 a.y() * bt.x(), a.y() * bt.y(), a.y() * bt.z(),
256 a.z() * bt.x(), a.z() * bt.y(), a.z() * bt.z());
257 return matrix;
258 }
259
260 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698