12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <cmath>
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <limits>
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/basictypes.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/gfx/geometry/matrix3_f.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace gfx {
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, Constructors) {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F zeros = Matrix3F::Zeros();
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F ones = Matrix3F::Ones();
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F identity = Matrix3F::Identity();
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F product_ones = Matrix3F::FromOuterProduct(
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Vector3dF(1.0f, 1.0f, 1.0f), Vector3dF(1.0f, 1.0f, 1.0f));
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F product_zeros = Matrix3F::FromOuterProduct(
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Vector3dF(1.0f, 1.0f, 1.0f), Vector3dF(0.0f, 0.0f, 0.0f));
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(ones, product_ones);
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(zeros, product_zeros);
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (int i = 0; i < 3; ++i) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (int j = 0; j < 3; ++j)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      EXPECT_EQ(i == j ? 1.0f : 0.0f, identity.get(i, j));
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, DataAccess) {
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F matrix = Matrix3F::Ones();
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F identity = Matrix3F::Identity();
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(0.0f, 1.0f, 0.0f), identity.get_column(1));
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(2.0f, 5.0f, 8.0f), matrix.get_column(2));
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set_column(0, Vector3dF(0.1f, 0.2f, 0.3f));
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(0.1f, 0.2f, 0.3f), matrix.get_column(0));
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0.1f, matrix.get(0, 0));
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(5.0f, matrix.get(1, 2));
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, Determinant) {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(1.0f, Matrix3F::Identity().Determinant());
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0.0f, Matrix3F::Zeros().Determinant());
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0.0f, Matrix3F::Ones().Determinant());
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Now for something non-trivial...
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F matrix = Matrix3F::Zeros();
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(0, 5, 6, 8, 7, 0, 1, 9, 0);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(390.0f, matrix.Determinant());
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(2, 0, 3 * matrix.get(0, 0));
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(2, 1, 3 * matrix.get(0, 1));
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(2, 2, 3 * matrix.get(0, 2));
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0, matrix.Determinant());
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(0.57f,  0.205f,  0.942f,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             0.314f,  0.845f,  0.826f,
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             0.131f,  0.025f,  0.962f);
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_NEAR(0.3149f, matrix.Determinant(), 0.0001f);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, Inverse) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F identity = Matrix3F::Identity();
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F inv_identity = identity.Inverse();
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(identity, inv_identity);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F singular = Matrix3F::Zeros();
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  singular.set(1.0f, 3.0f, 4.0f,
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               2.0f, 11.0f, 5.0f,
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               0.5f, 1.5f, 2.0f);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(0, singular.Determinant());
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Matrix3F::Zeros(), singular.Inverse());
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F regular = Matrix3F::Zeros();
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  regular.set(0.57f,  0.205f,  0.942f,
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              0.314f,  0.845f,  0.826f,
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              0.131f,  0.025f,  0.962f);
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F inv_regular = regular.Inverse();
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  regular.set(2.51540616f, -0.55138018f, -1.98968043f,
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              -0.61552266f,  1.34920184f, -0.55573636f,
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              -0.32653861f,  0.04002158f,  1.32488726f);
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(regular.IsNear(inv_regular, 0.00001f));
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, EigenvectorsIdentity) {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This block tests the trivial case of eigenvalues of the identity matrix.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F identity = Matrix3F::Identity();
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Vector3dF eigenvals = identity.SolveEigenproblem(NULL);
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(1.0f, 1.0f, 1.0f), eigenvals);
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, EigenvectorsDiagonal)  {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This block tests the another trivial case of eigenvalues of a diagonal
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // matrix. Here we expect values to be sorted.
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F matrix = Matrix3F::Zeros();
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(0, 0, 1.0f);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(1, 1, -2.5f);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(2, 2, 3.14f);
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F eigenvectors = Matrix3F::Zeros();
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(3.14f, 1.0f, -2.5f), eigenvals);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(0.0f, 0.0f, 1.0f), eigenvectors.get_column(0));
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(1.0f, 0.0f, 0.0f), eigenvectors.get_column(1));
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(0.0f, 1.0f, 0.0f), eigenvectors.get_column(2));
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, EigenvectorsNiceNotPositive)  {
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This block tests computation of eigenvectors of a matrix where nice
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // round values are expected.
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F matrix = Matrix3F::Zeros();
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This is not a positive-definite matrix but eigenvalues and the first
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // eigenvector should nonetheless be computed correctly.
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(3, 2, 4, 2, 0, 2, 4, 2, 3);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F eigenvectors = Matrix3F::Zeros();
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Vector3dF eigenvals = matrix.SolveEigenproblem(&eigenvectors);
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(Vector3dF(8.0f, -1.0f, -1.0f), eigenvals);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Vector3dF expected_principal(0.66666667f, 0.33333333f, 0.66666667f);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_NEAR(0.0f,
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              (expected_principal - eigenvectors.get_column(0)).Length(),
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              0.000001f);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(Matrix3fTest, EigenvectorsPositiveDefinite) {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This block tests computation of eigenvectors of a matrix where output
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // is not as nice as above, but it actually meets the definition.
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F matrix = Matrix3F::Zeros();
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F eigenvectors = Matrix3F::Zeros();
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Matrix3F expected_eigenvectors = Matrix3F::Zeros();
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  matrix.set(1, -1,  2, -1,  4,  5, 2,  5,  0);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Vector3dF eigenvals =  matrix.SolveEigenproblem(&eigenvectors);
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Vector3dF expected_eigv(7.3996266f, 1.91197255f, -4.31159915f);
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_eigv -= eigenvals;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_NEAR(0, expected_eigv.LengthSquared(), 0.00001f);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  expected_eigenvectors.set(0.04926317f, -0.92135662f, -0.38558414f,
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            0.82134249f, 0.25703273f, -0.50924521f,
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            0.56830419f, -0.2916096f, 0.76941158f);
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_TRUE(expected_eigenvectors.IsNear(eigenvectors, 0.00001f));
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
149