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

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: Addressed reviewer's remarks (re-do). 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 #include "base/logging.h"
12
13 namespace {
14
15 // This is only to make accessing indices self-explanatory.
16 enum MatrixCoordinates {
17 kM00,
18 kM01,
19 kM02,
20 kM10,
21 kM11,
22 kM12,
23 kM20,
24 kM21,
25 kM22,
26 kMEnd
27 };
28
29 template<typename T>
30 double Determinant3x3(T data[kMEnd]) {
Alexei Svitkine (slow) 2013/01/31 20:02:38 Add a comment explaining the purpose (same as you
motek. 2013/01/31 22:00:24 Done.
31 return (double)data[kM00] * ((double)data[kM11] * data[kM22] -
Alexei Svitkine (slow) 2013/01/31 20:02:38 Use C++ casts, rather than C-style casts.
motek. 2013/01/31 22:00:24 Done.
32 (double)data[kM12] * data[kM21]) +
33 data[kM01] * ((double)data[kM12] * data[kM20] -
34 (double)data[kM10] * data[kM22]) +
35 data[kM02] * ((double)data[kM10] * data[kM21] -
36 (double)data[kM11] * data[kM20]);
37 }
38
39 } // namespace
40
41 namespace gfx {
42
43 Matrix3F::Matrix3F() {
44 }
45
46 Matrix3F::Matrix3F(const VectorType& a, const VectorType& bt) {
47 set(a.x() * bt.x(), a.x() * bt.y(), a.x() * bt.z(),
48 a.y() * bt.x(), a.y() * bt.y(), a.y() * bt.z(),
49 a.z() * bt.x(), a.z() * bt.y(), a.z() * bt.z());
50 }
51
52 Matrix3F::Matrix3F(const Matrix3F& rhs) {
53 memcpy(data_, rhs.data_, sizeof(data_));
54 }
55
56 Matrix3F::~Matrix3F() {
57 }
58
59 bool Matrix3F::IsEqual(const Matrix3F& rhs) const {
60 return 0 == memcmp(data_, rhs.data_, sizeof(data_));
61 }
62
63 bool Matrix3F::IsNear(const Matrix3F& rhs, ScalarType precision) const {
64 DCHECK(precision >= 0);
65 for (int i = 0; i < kMEnd; ++i) {
66 if (std::abs(data_[i] - rhs.data_[i]) > precision)
67 return false;
68 }
69 return true;
70 }
71
72 Matrix3F::ScalarType Matrix3F::get(int i, int j) const {
73 DCHECK(i >= 0 && i < 3);
74 DCHECK(j >= 0 && j < 3);
75 return data_[i * 3 + j];
Alexei Svitkine (slow) 2013/01/31 20:02:38 Make a function in the anon namespace that gives y
motek. 2013/01/31 22:00:24 Done.
76 }
77
78 void Matrix3F::set(int i, int j, ScalarType v) {
79 DCHECK(i >= 0 && i < 3);
80 DCHECK(j >= 0 && j < 3);
81 data_[i * 3 + j] = v;
82 }
83
84 void Matrix3F::set(ScalarType v) {
85 for (int i = 0; i < kMEnd; i++)
86 data_[i] = v;
87 }
88
89 void Matrix3F::set(ScalarType m00, ScalarType m01, ScalarType m02,
90 ScalarType m10, ScalarType m11, ScalarType m12,
91 ScalarType m20, ScalarType m21, ScalarType m22) {
92 data_[0] = m00;
93 data_[1] = m01;
94 data_[2] = m02;
95 data_[3] = m10;
96 data_[4] = m11;
97 data_[5] = m12;
98 data_[6] = m20;
99 data_[7] = m21;
100 data_[8] = m22;
101 }
102
103 Matrix3F::VectorType Matrix3F::GetColumn(int i) const {
104 DCHECK(i >= 0 && i < 3);
105 return VectorType(data_[i], data_[3 + i], data_[6 + i]);
106 }
107
108 void Matrix3F::SetColumn(int i, const VectorType& c) {
109 DCHECK(i >= 0 && i < 3);
110 data_[i] = c.x();
111 data_[3 + i] = c.y();
112 data_[6 + i] = c.z();
113 }
114
115 Matrix3F Matrix3F::Inverse() const {
116 Matrix3F inverse = Matrix3F::Zeros();
117 double det = Determinant3x3(data_);
Alexei Svitkine (slow) 2013/01/31 20:02:38 Nit: det -> determinant
motek. 2013/01/31 22:00:24 Done.
118 if (std::numeric_limits<ScalarType>::epsilon() > std::abs(det))
119 return inverse; // Singular matrix. Return Zeros().
120
121 inverse.set((data_[kM11] * data_[kM22] - data_[kM12] * data_[kM21]) / det,
122 (data_[kM02] * data_[kM21] - data_[kM01] * data_[kM22]) / det,
123 (data_[kM01] * data_[kM12] - data_[kM02] * data_[kM11]) / det,
124 (data_[kM12] * data_[kM20] - data_[kM10] * data_[kM22]) / det,
125 (data_[kM00] * data_[kM22] - data_[kM02] * data_[kM20]) / det,
126 (data_[kM02] * data_[kM10] - data_[kM00] * data_[kM12]) / det,
127 (data_[kM10] * data_[kM21] - data_[kM11] * data_[kM20]) / det,
128 (data_[kM01] * data_[kM20] - data_[kM00] * data_[kM21]) / det,
129 (data_[kM00] * data_[kM11] - data_[kM01] * data_[kM10]) / det);
130 return inverse;
131 }
132
133 Matrix3F::ScalarType Matrix3F::Determinant() const {
134 return ScalarType(Determinant3x3(data_));
135 }
136
137 Matrix3F::ScalarType Matrix3F::Trace() const {
138 return data_[kM00] + data_[kM11] + data_[kM22];
139 }
140
141 Matrix3F::VectorType Matrix3F::SolveEigenproblem(
142 Matrix3F* eigenvectors) const {
143 // The matrix must be symmetric.
144 const ScalarType epsilon = std::numeric_limits<ScalarType>::epsilon();
145 if (std::abs(data_[kM01] - data_[kM10]) > epsilon ||
146 std::abs(data_[kM02] - data_[kM02]) > epsilon ||
147 std::abs(data_[kM12] - data_[kM21]) > epsilon) {
148 NOTREACHED();
149 return Matrix3F::VectorType();
150 }
151
152 ScalarType eigenvalues[3];
153 ScalarType p =
154 data_[kM01] * data_[kM01] +
155 data_[kM02] * data_[kM02] +
156 data_[kM12] * data_[kM12];
157
158 bool diagonal = std::abs(p) < epsilon;
159 if (diagonal) {
160 eigenvalues[0] = data_[kM00];
161 eigenvalues[1] = data_[kM11];
162 eigenvalues[2] = data_[kM22];
163 } else {
164 ScalarType q = Trace() / 3.0;
165 p = (data_[kM00] - q) * (data_[kM00] - q) +
166 (data_[kM11] - q) * (data_[kM11] - q) +
167 (data_[kM22] - q) * (data_[kM22] - q) +
168 2 * p;
169 p = sqrt(p / 6);
170
171 // The computation below puts B as (A - qI) / p, where A is *this.
172 Matrix3F matrix_B(*this);
173 matrix_B.data_[kM00] -= q;
174 matrix_B.data_[kM11] -= q;
175 matrix_B.data_[kM22] -= q;
176 for (int i = 0; i < kMEnd; ++i)
177 matrix_B.data_[i] /= p;
178
179 ScalarType half_det_b = matrix_B.Determinant() / 2.0;
180 // half_det_b should be in <-1, 1>, but beware of rounding error.
181 ScalarType phi = 0.0;
182 if (half_det_b <= -1.0)
183 phi = M_PI / 3;
184 else if (half_det_b < 1.0)
185 phi = acos(half_det_b) / 3;
186
187 eigenvalues[0] = q + 2 * p * cos(phi);
188 eigenvalues[2] = q + 2 * p * cos(phi + 2.0 * M_PI / 3.0);
189 eigenvalues[1] = 3 * q - eigenvalues[0] - eigenvalues[2];
190 }
191
192 // Put eigenvalues in the descending order.
193 int indices[3] = {0, 1, 2};
194 if (eigenvalues[2] > eigenvalues[1]) {
195 std::swap(eigenvalues[2], eigenvalues[1]);
196 std::swap(indices[2], indices[1]);
197 }
198
199 if (eigenvalues[1] > eigenvalues[0]) {
200 std::swap(eigenvalues[1], eigenvalues[0]);
201 std::swap(indices[1], indices[0]);
202 }
203
204 if (eigenvalues[2] > eigenvalues[1]) {
205 std::swap(eigenvalues[2], eigenvalues[1]);
206 std::swap(indices[2], indices[1]);
207 }
208
209 if (eigenvectors != NULL && diagonal) {
210 // Eigenvectors are e-vectors, just need to be sorted accordingly.
211 *eigenvectors = Zeros();
212 for (int i = 0; i < 3; ++i)
213 eigenvectors->set(indices[i], i, 1.0);
214 } else if (eigenvectors != NULL) {
215 // Consult the following for a detailed discussion:
216 // Joachim Kopp
217 // Numerical diagonalization of hermitian 3x3 matrices
218 // arXiv.org preprint: physics/0610206
219 // Int. J. Mod. Phys. C19 (2008) 523-548
220
221 // TODO(motek): expand to handle correctly negative and multiple
222 // eigenvalues.
223 for (int i = 0; i < 3; ++i) {
224 ScalarType l = eigenvalues[i];
225 // B = A - l * I
226 Matrix3F matrix_B(*this);
227 matrix_B.data_[kM00] -= l;
228 matrix_B.data_[kM11] -= l;
229 matrix_B.data_[kM22] -= l;
230 VectorType e1 = CrossProduct(matrix_B.GetColumn(0),
231 matrix_B.GetColumn(1));
232 VectorType e2 = CrossProduct(matrix_B.GetColumn(1),
233 matrix_B.GetColumn(2));
234 VectorType e3 = CrossProduct(matrix_B.GetColumn(2),
235 matrix_B.GetColumn(0));
236
237 // e1, e2 and e3 should point in the same direction.
238 if (DotProduct(e1, e2) < 0) {
239 e2.set_x(-e2.x());
240 e2.set_y(-e2.y());
241 e2.set_z(-e2.z());
242 }
243
244 if (DotProduct(e1, e3) < 0) {
245 e3.set_x(-e3.x());
246 e3.set_y(-e3.y());
247 e3.set_z(-e3.z());
248 }
249
250 VectorType eigvec = e1 + e2 + e3;
251 // Normalize.
252 eigvec.Scale(1.0 / eigvec.Length());
253 eigenvectors->SetColumn(i, eigvec);
254 }
255 }
256
257 return Matrix3F::VectorType(eigenvalues[0],
258 eigenvalues[1],
259 eigenvalues[2]);
260 }
261
262 // static
263 Matrix3F Matrix3F::Zeros() {
264 Matrix3F matrix;
265 matrix.set(0.0);
266 return matrix;
267 }
268
269 // static
270 Matrix3F Matrix3F::Ones() {
271 Matrix3F matrix;
272 matrix.set(1.0);
273 return matrix;
274 }
275
276 // static
277 Matrix3F Matrix3F::Identity() {
278 Matrix3F matrix;
279 matrix.set(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
280 return matrix;
281 }
282
283 } // namespace gfx
OLDNEW
« ui/gfx/matrix3_f.h ('K') | « ui/gfx/matrix3_f.h ('k') | ui/gfx/matrix3_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698