blob: 8aa511e4a0a97e92647983b967eb14bddc2aca3c [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/fml/build_config.h"
#if defined(OS_WIN)
#define _USE_MATH_DEFINES
#endif
#include <cmath>
#include "flutter/flow/matrix_decomposition.h"
#include "gtest/gtest.h"
namespace flutter {
namespace testing {
TEST(MatrixDecomposition, Rotation) {
SkMatrix44 matrix = SkMatrix44::I();
const auto angle = M_PI_4;
matrix.setRotateAbout(0.0, 0.0, 1.0, angle);
flutter::MatrixDecomposition decomposition(matrix);
ASSERT_TRUE(decomposition.IsValid());
const auto sine = sin(angle * 0.5);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[1]);
ASSERT_FLOAT_EQ(sine, decomposition.rotation().fData[2]);
ASSERT_FLOAT_EQ(cos(angle * 0.5), decomposition.rotation().fData[3]);
}
TEST(MatrixDecomposition, Scale) {
SkMatrix44 matrix = SkMatrix44::I();
const auto scale = 5.0;
matrix.setScale(scale + 0, scale + 1, scale + 2);
flutter::MatrixDecomposition decomposition(matrix);
ASSERT_TRUE(decomposition.IsValid());
ASSERT_FLOAT_EQ(scale + 0, decomposition.scale().fX);
ASSERT_FLOAT_EQ(scale + 1, decomposition.scale().fY);
ASSERT_FLOAT_EQ(scale + 2, decomposition.scale().fZ);
}
TEST(MatrixDecomposition, Translate) {
SkMatrix44 matrix = SkMatrix44::I();
const auto translate = 125.0;
matrix.setTranslate(translate + 0, translate + 1, translate + 2);
flutter::MatrixDecomposition decomposition(matrix);
ASSERT_TRUE(decomposition.IsValid());
ASSERT_FLOAT_EQ(translate + 0, decomposition.translation().fX);
ASSERT_FLOAT_EQ(translate + 1, decomposition.translation().fY);
ASSERT_FLOAT_EQ(translate + 2, decomposition.translation().fZ);
}
TEST(MatrixDecomposition, Combination) {
const auto rotation = M_PI_4;
const auto scale = 5;
const auto translate = 125.0;
SkMatrix44 m1 = SkMatrix44::I();
m1.setRotateAbout(0, 0, 1, rotation);
SkMatrix44 m2 = SkMatrix44::I();
m2.setScale(scale);
SkMatrix44 m3 = SkMatrix44::I();
m3.setTranslate(translate, translate, translate);
SkMatrix44 combined = m3 * m2 * m1;
flutter::MatrixDecomposition decomposition(combined);
ASSERT_TRUE(decomposition.IsValid());
ASSERT_FLOAT_EQ(translate, decomposition.translation().fX);
ASSERT_FLOAT_EQ(translate, decomposition.translation().fY);
ASSERT_FLOAT_EQ(translate, decomposition.translation().fZ);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fX);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fY);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fZ);
const auto sine = sin(rotation * 0.5);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[1]);
ASSERT_FLOAT_EQ(sine, decomposition.rotation().fData[2]);
ASSERT_FLOAT_EQ(cos(rotation * 0.5), decomposition.rotation().fData[3]);
}
TEST(MatrixDecomposition, ScaleFloatError) {
constexpr float scale_increment = 0.00001f;
for (float scale = 0.0001f; scale < 2.0f; scale += scale_increment) {
SkMatrix44 matrix = SkMatrix44::I();
matrix.setScale(scale, scale, 1.0f);
flutter::MatrixDecomposition decomposition3(matrix);
ASSERT_TRUE(decomposition3.IsValid());
ASSERT_FLOAT_EQ(scale, decomposition3.scale().fX);
ASSERT_FLOAT_EQ(scale, decomposition3.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition3.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[2]);
}
SkMatrix44 matrix = SkMatrix44::I();
const auto scale = 1.7734375f;
matrix.setScale(scale, scale, 1.f);
// Bug upper bound (empirical)
const auto scale2 = 1.773437559603f;
SkMatrix44 matrix2 = SkMatrix44::I();
matrix2.setScale(scale2, scale2, 1.f);
// Bug lower bound (empirical)
const auto scale3 = 1.7734374403954f;
SkMatrix44 matrix3 = SkMatrix44::I();
matrix3.setScale(scale3, scale3, 1.f);
flutter::MatrixDecomposition decomposition(matrix);
ASSERT_TRUE(decomposition.IsValid());
flutter::MatrixDecomposition decomposition2(matrix2);
ASSERT_TRUE(decomposition2.IsValid());
flutter::MatrixDecomposition decomposition3(matrix3);
ASSERT_TRUE(decomposition3.IsValid());
ASSERT_FLOAT_EQ(scale, decomposition.scale().fX);
ASSERT_FLOAT_EQ(scale, decomposition.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition.rotation().fData[2]);
ASSERT_FLOAT_EQ(scale2, decomposition2.scale().fX);
ASSERT_FLOAT_EQ(scale2, decomposition2.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition2.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition2.rotation().fData[2]);
ASSERT_FLOAT_EQ(scale3, decomposition3.scale().fX);
ASSERT_FLOAT_EQ(scale3, decomposition3.scale().fY);
ASSERT_FLOAT_EQ(1.f, decomposition3.scale().fZ);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[0]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[1]);
ASSERT_FLOAT_EQ(0, decomposition3.rotation().fData[2]);
}
} // namespace testing
} // namespace flutter