Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "Test.h"
      9 #include "SkMatrix44.h"
     10 
     11 static bool nearly_equal_double(double a, double b) {
     12     const double tolerance = 1e-7;
     13     double diff = a - b;
     14     if (diff < 0)
     15         diff = -diff;
     16     return diff <= tolerance;
     17 }
     18 
     19 static bool nearly_equal_scalar(SkMScalar a, SkMScalar b) {
     20     // Note that we get more compounded error for multiple operations when
     21     // SK_SCALAR_IS_FIXED.
     22 #ifdef SK_SCALAR_IS_FLOAT
     23     const SkScalar tolerance = SK_Scalar1 / 200000;
     24 #else
     25     const SkScalar tolerance = SK_Scalar1 / 1024;
     26 #endif
     27 
     28     return SkTAbs<SkMScalar>(a - b) <= tolerance;
     29 }
     30 
     31 template <typename T> void assert16(skiatest::Reporter* reporter, const T data[],
     32                                     T m0,  T m1,  T m2,  T m3,
     33                                     T m4,  T m5,  T m6,  T m7,
     34                                     T m8,  T m9,  T m10, T m11,
     35                                     T m12, T m13, T m14, T m15) {
     36     REPORTER_ASSERT(reporter, data[0] == m0);
     37     REPORTER_ASSERT(reporter, data[1] == m1);
     38     REPORTER_ASSERT(reporter, data[2] == m2);
     39     REPORTER_ASSERT(reporter, data[3] == m3);
     40 
     41     REPORTER_ASSERT(reporter, data[4] == m4);
     42     REPORTER_ASSERT(reporter, data[5] == m5);
     43     REPORTER_ASSERT(reporter, data[6] == m6);
     44     REPORTER_ASSERT(reporter, data[7] == m7);
     45 
     46     REPORTER_ASSERT(reporter, data[8] == m8);
     47     REPORTER_ASSERT(reporter, data[9] == m9);
     48     REPORTER_ASSERT(reporter, data[10] == m10);
     49     REPORTER_ASSERT(reporter, data[11] == m11);
     50 
     51     REPORTER_ASSERT(reporter, data[12] == m12);
     52     REPORTER_ASSERT(reporter, data[13] == m13);
     53     REPORTER_ASSERT(reporter, data[14] == m14);
     54     REPORTER_ASSERT(reporter, data[15] == m15);
     55 }
     56 
     57 static bool nearly_equal(const SkMatrix44& a, const SkMatrix44& b) {
     58     for (int i = 0; i < 4; ++i) {
     59         for (int j = 0; j < 4; ++j) {
     60             if (!nearly_equal_scalar(a.get(i, j), b.get(i, j))) {
     61                 printf("not equal %g %g\n", a.get(i, j), b.get(i, j));
     62                 return false;
     63             }
     64         }
     65     }
     66     return true;
     67 }
     68 
     69 static bool is_identity(const SkMatrix44& m) {
     70     SkMatrix44 identity;
     71     identity.reset();
     72     return nearly_equal(m, identity);
     73 }
     74 
     75 ///////////////////////////////////////////////////////////////////////////////
     76 static bool bits_isonly(int value, int mask) {
     77     return 0 == (value & ~mask);
     78 }
     79 
     80 static void test_constructor(skiatest::Reporter* reporter) {
     81     // Allocate a matrix on the heap
     82     SkMatrix44* placeholderMatrix = new SkMatrix44();
     83     for (int row = 0; row < 4; ++row) {
     84         for (int col = 0; col < 4; ++col) {
     85             placeholderMatrix->setDouble(row, col, row * col);
     86         }
     87     }
     88 
     89     // Use placement-new syntax to trigger the constructor on top of the heap
     90     // address we already initialized. This allows us to check that the
     91     // constructor did avoid initializing the matrix contents.
     92     SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
     93     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
     94     REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
     95     for (int row = 0; row < 4; ++row) {
     96         for (int col = 0; col < 4; ++col) {
     97             REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
     98         }
     99     }
    100 
    101     // Verify that kIdentity_Constructor really does initialize to an identity matrix.
    102     testMatrix = 0;
    103     testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
    104     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
    105     REPORTER_ASSERT(reporter, testMatrix->isIdentity());
    106     REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
    107 }
    108 
    109 static void test_translate(skiatest::Reporter* reporter) {
    110     SkMatrix44 mat, inverse;
    111 
    112     mat.setTranslate(0, 0, 0);
    113     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
    114     mat.setTranslate(1, 2, 3);
    115     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
    116     REPORTER_ASSERT(reporter, mat.invert(&inverse));
    117     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
    118 
    119     SkMatrix44 a, b, c;
    120     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
    121     b.setTranslate(10, 11, 12);
    122 
    123     c.setConcat(a, b);
    124     mat = a;
    125     mat.preTranslate(10, 11, 12);
    126     REPORTER_ASSERT(reporter, mat == c);
    127 
    128     c.setConcat(b, a);
    129     mat = a;
    130     mat.postTranslate(10, 11, 12);
    131     REPORTER_ASSERT(reporter, mat == c);
    132 }
    133 
    134 static void test_scale(skiatest::Reporter* reporter) {
    135     SkMatrix44 mat, inverse;
    136 
    137     mat.setScale(1, 1, 1);
    138     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
    139     mat.setScale(1, 2, 3);
    140     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
    141     REPORTER_ASSERT(reporter, mat.invert(&inverse));
    142     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
    143 
    144     SkMatrix44 a, b, c;
    145     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
    146     b.setScale(10, 11, 12);
    147 
    148     c.setConcat(a, b);
    149     mat = a;
    150     mat.preScale(10, 11, 12);
    151     REPORTER_ASSERT(reporter, mat == c);
    152 
    153     c.setConcat(b, a);
    154     mat = a;
    155     mat.postScale(10, 11, 12);
    156     REPORTER_ASSERT(reporter, mat == c);
    157 }
    158 
    159 static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
    160 static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
    161 static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
    162 static void make_st(SkMatrix44* mat) {
    163     mat->setScale(1, 2, 3);
    164     mat->postTranslate(1, 2, 3);
    165 }
    166 static void make_a(SkMatrix44* mat) {
    167     mat->setRotateDegreesAbout(1, 2, 3, 45);
    168 }
    169 static void make_p(SkMatrix44* mat) {
    170     SkMScalar data[] = {
    171         1, 2, 3, 4, 5, 6, 7, 8,
    172         1, 2, 3, 4, 5, 6, 7, 8,
    173     };
    174     mat->setRowMajor(data);
    175 }
    176 
    177 typedef void (*Make44Proc)(SkMatrix44*);
    178 
    179 static const Make44Proc gMakeProcs[] = {
    180     make_i, make_t, make_s, make_st, make_a, make_p
    181 };
    182 
    183 static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
    184     SkMScalar src2[] = { 1, 2 };
    185     SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
    186     SkMScalar dstA[4], dstB[4];
    187 
    188     for (int i = 0; i < 4; ++i) {
    189         dstA[i] = 123456789;
    190         dstB[i] = 987654321;
    191     }
    192 
    193     mat.map2(src2, 1, dstA);
    194     mat.mapMScalars(src4, dstB);
    195 
    196     for (int i = 0; i < 4; ++i) {
    197         REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
    198     }
    199 }
    200 
    201 static void test_map2(skiatest::Reporter* reporter) {
    202     SkMatrix44 mat;
    203 
    204     for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
    205         gMakeProcs[i](&mat);
    206         test_map2(reporter, mat);
    207     }
    208 }
    209 
    210 static void test_gettype(skiatest::Reporter* reporter) {
    211     SkMatrix44 matrix;
    212 
    213     REPORTER_ASSERT(reporter, matrix.isIdentity());
    214     REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
    215 
    216     int expectedMask;
    217 
    218     matrix.set(1, 1, 0);
    219     expectedMask = SkMatrix44::kScale_Mask;
    220     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    221 
    222     matrix.set(0, 3, 1);    // translate-x
    223     expectedMask |= SkMatrix44::kTranslate_Mask;
    224     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    225 
    226     matrix.set(2, 0, 1);
    227     expectedMask |= SkMatrix44::kAffine_Mask;
    228     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    229 
    230     matrix.set(3, 2, 1);
    231     REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
    232 }
    233 
    234 static void test_common_angles(skiatest::Reporter* reporter) {
    235     SkMatrix44 rot;
    236     // Test precision of rotation in common cases
    237     int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
    238     for (int i = 0; i < 9; ++i) {
    239         rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
    240 
    241         SkMatrix rot3x3 = rot;
    242         REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
    243     }
    244 }
    245 
    246 static void test_concat(skiatest::Reporter* reporter) {
    247     int i;
    248     SkMatrix44 a, b, c, d;
    249 
    250     a.setTranslate(10, 10, 10);
    251     b.setScale(2, 2, 2);
    252 
    253     SkScalar src[8] = {
    254         0, 0, 0, 1,
    255         1, 1, 1, 1
    256     };
    257     SkScalar dst[8];
    258 
    259     c.setConcat(a, b);
    260 
    261     d = a;
    262     d.preConcat(b);
    263     REPORTER_ASSERT(reporter, d == c);
    264 
    265     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
    266     for (i = 0; i < 3; ++i) {
    267         REPORTER_ASSERT(reporter, 10 == dst[i]);
    268         REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
    269     }
    270 
    271     c.setConcat(b, a);
    272 
    273     d = a;
    274     d.postConcat(b);
    275     REPORTER_ASSERT(reporter, d == c);
    276 
    277     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
    278     for (i = 0; i < 3; ++i) {
    279         REPORTER_ASSERT(reporter, 20 == dst[i]);
    280         REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
    281     }
    282 }
    283 
    284 static void test_determinant(skiatest::Reporter* reporter) {
    285     SkMatrix44 a;
    286     REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
    287     a.set(1, 1, 2);
    288     REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
    289     SkMatrix44 b;
    290     REPORTER_ASSERT(reporter, a.invert(&b));
    291     REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
    292     SkMatrix44 c = b = a;
    293     c.set(0, 1, 4);
    294     b.set(1, 0, 4);
    295     REPORTER_ASSERT(reporter,
    296                     nearly_equal_double(a.determinant(),
    297                                         b.determinant()));
    298     SkMatrix44 d = a;
    299     d.set(0, 0, 8);
    300     REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
    301 
    302     SkMatrix44 e = a;
    303     e.postConcat(d);
    304     REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
    305     e.set(0, 0, 0);
    306     REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
    307 }
    308 
    309 static void test_transpose(skiatest::Reporter* reporter) {
    310     SkMatrix44 a;
    311     SkMatrix44 b;
    312 
    313     int i = 0;
    314     for (int row = 0; row < 4; ++row) {
    315         for (int col = 0; col < 4; ++col) {
    316             a.setDouble(row, col, i);
    317             b.setDouble(col, row, i++);
    318         }
    319     }
    320 
    321     a.transpose();
    322     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    323 }
    324 
    325 static void test_get_set_double(skiatest::Reporter* reporter) {
    326     SkMatrix44 a;
    327     for (int row = 0; row < 4; ++row) {
    328         for (int col = 0; col < 4; ++col) {
    329             a.setDouble(row, col, 3.141592653589793);
    330             REPORTER_ASSERT(reporter,
    331                             nearly_equal_double(3.141592653589793,
    332                                                 a.getDouble(row, col)));
    333             a.setDouble(row, col, 0);
    334             REPORTER_ASSERT(reporter,
    335                             nearly_equal_double(0, a.getDouble(row, col)));
    336         }
    337     }
    338 }
    339 
    340 static void test_set_row_col_major(skiatest::Reporter* reporter) {
    341     SkMatrix44 a, b, c, d;
    342     for (int row = 0; row < 4; ++row) {
    343         for (int col = 0; col < 4; ++col) {
    344             a.setDouble(row, col, row * 4 + col);
    345         }
    346     }
    347 
    348     double bufferd[16];
    349     float bufferf[16];
    350     a.asColMajord(bufferd);
    351     b.setColMajord(bufferd);
    352     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    353     b.setRowMajord(bufferd);
    354     b.transpose();
    355     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    356     a.asColMajorf(bufferf);
    357     b.setColMajorf(bufferf);
    358     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    359     b.setRowMajorf(bufferf);
    360     b.transpose();
    361     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    362 }
    363 
    364 static void TestMatrix44(skiatest::Reporter* reporter) {
    365     SkMatrix44 mat, inverse, iden1, iden2, rot;
    366 
    367     mat.reset();
    368     mat.setTranslate(1, 1, 1);
    369     mat.invert(&inverse);
    370     iden1.setConcat(mat, inverse);
    371     REPORTER_ASSERT(reporter, is_identity(iden1));
    372 
    373     mat.setScale(2, 2, 2);
    374     mat.invert(&inverse);
    375     iden1.setConcat(mat, inverse);
    376     REPORTER_ASSERT(reporter, is_identity(iden1));
    377 
    378     mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
    379     mat.invert(&inverse);
    380     iden1.setConcat(mat, inverse);
    381     REPORTER_ASSERT(reporter, is_identity(iden1));
    382 
    383     mat.setScale(3, 3, 3);
    384     rot.setRotateDegreesAbout(0, 0, -1, 90);
    385     mat.postConcat(rot);
    386     REPORTER_ASSERT(reporter, mat.invert(NULL));
    387     mat.invert(&inverse);
    388     iden1.setConcat(mat, inverse);
    389     REPORTER_ASSERT(reporter, is_identity(iden1));
    390     iden2.setConcat(inverse, mat);
    391     REPORTER_ASSERT(reporter, is_identity(iden2));
    392 
    393     // test rol/col Major getters
    394     {
    395         mat.setTranslate(2, 3, 4);
    396         float dataf[16];
    397         double datad[16];
    398 
    399         mat.asColMajorf(dataf);
    400         assert16<float>(reporter, dataf,
    401                  1, 0, 0, 0,
    402                  0, 1, 0, 0,
    403                  0, 0, 1, 0,
    404                  2, 3, 4, 1);
    405         mat.asColMajord(datad);
    406         assert16<double>(reporter, datad, 1, 0, 0, 0,
    407                         0, 1, 0, 0,
    408                         0, 0, 1, 0,
    409                         2, 3, 4, 1);
    410         mat.asRowMajorf(dataf);
    411         assert16<float>(reporter, dataf, 1, 0, 0, 2,
    412                         0, 1, 0, 3,
    413                         0, 0, 1, 4,
    414                         0, 0, 0, 1);
    415         mat.asRowMajord(datad);
    416         assert16<double>(reporter, datad, 1, 0, 0, 2,
    417                         0, 1, 0, 3,
    418                         0, 0, 1, 4,
    419                         0, 0, 0, 1);
    420     }
    421 
    422     test_concat(reporter);
    423 
    424     if (false) { // avoid bit rot, suppress warning (working on making this pass)
    425         test_common_angles(reporter);
    426     }
    427 
    428     test_constructor(reporter);
    429     test_gettype(reporter);
    430     test_determinant(reporter);
    431     test_transpose(reporter);
    432     test_get_set_double(reporter);
    433     test_set_row_col_major(reporter);
    434     test_translate(reporter);
    435     test_scale(reporter);
    436     test_map2(reporter);
    437 }
    438 
    439 #include "TestClassDef.h"
    440 DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44)
    441