Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 | |
| OLD | NEW |