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     SkAutoTDelete<SkMatrix44> deleteMe(placeholderMatrix);
     84 
     85     for (int row = 0; row < 4; ++row) {
     86         for (int col = 0; col < 4; ++col) {
     87             placeholderMatrix->setDouble(row, col, row * col);
     88         }
     89     }
     90 
     91     // Use placement-new syntax to trigger the constructor on top of the heap
     92     // address we already initialized. This allows us to check that the
     93     // constructor did avoid initializing the matrix contents.
     94     SkMatrix44* testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kUninitialized_Constructor);
     95     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
     96     REPORTER_ASSERT(reporter, !testMatrix->isIdentity());
     97     for (int row = 0; row < 4; ++row) {
     98         for (int col = 0; col < 4; ++col) {
     99             REPORTER_ASSERT(reporter, nearly_equal_double(row * col, testMatrix->getDouble(row, col)));
    100         }
    101     }
    102 
    103     // Verify that kIdentity_Constructor really does initialize to an identity matrix.
    104     testMatrix = 0;
    105     testMatrix = new(placeholderMatrix) SkMatrix44(SkMatrix44::kIdentity_Constructor);
    106     REPORTER_ASSERT(reporter, testMatrix == placeholderMatrix);
    107     REPORTER_ASSERT(reporter, testMatrix->isIdentity());
    108     REPORTER_ASSERT(reporter, *testMatrix == SkMatrix44::I());
    109 }
    110 
    111 static void test_translate(skiatest::Reporter* reporter) {
    112     SkMatrix44 mat, inverse;
    113 
    114     mat.setTranslate(0, 0, 0);
    115     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
    116     mat.setTranslate(1, 2, 3);
    117     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kTranslate_Mask));
    118     REPORTER_ASSERT(reporter, mat.invert(&inverse));
    119     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kTranslate_Mask));
    120 
    121     SkMatrix44 a, b, c;
    122     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
    123     b.setTranslate(10, 11, 12);
    124 
    125     c.setConcat(a, b);
    126     mat = a;
    127     mat.preTranslate(10, 11, 12);
    128     REPORTER_ASSERT(reporter, mat == c);
    129 
    130     c.setConcat(b, a);
    131     mat = a;
    132     mat.postTranslate(10, 11, 12);
    133     REPORTER_ASSERT(reporter, mat == c);
    134 }
    135 
    136 static void test_scale(skiatest::Reporter* reporter) {
    137     SkMatrix44 mat, inverse;
    138 
    139     mat.setScale(1, 1, 1);
    140     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kIdentity_Mask));
    141     mat.setScale(1, 2, 3);
    142     REPORTER_ASSERT(reporter, bits_isonly(mat.getType(), SkMatrix44::kScale_Mask));
    143     REPORTER_ASSERT(reporter, mat.invert(&inverse));
    144     REPORTER_ASSERT(reporter, bits_isonly(inverse.getType(), SkMatrix44::kScale_Mask));
    145 
    146     SkMatrix44 a, b, c;
    147     a.set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
    148     b.setScale(10, 11, 12);
    149 
    150     c.setConcat(a, b);
    151     mat = a;
    152     mat.preScale(10, 11, 12);
    153     REPORTER_ASSERT(reporter, mat == c);
    154 
    155     c.setConcat(b, a);
    156     mat = a;
    157     mat.postScale(10, 11, 12);
    158     REPORTER_ASSERT(reporter, mat == c);
    159 }
    160 
    161 static void make_i(SkMatrix44* mat) { mat->setIdentity(); }
    162 static void make_t(SkMatrix44* mat) { mat->setTranslate(1, 2, 3); }
    163 static void make_s(SkMatrix44* mat) { mat->setScale(1, 2, 3); }
    164 static void make_st(SkMatrix44* mat) {
    165     mat->setScale(1, 2, 3);
    166     mat->postTranslate(1, 2, 3);
    167 }
    168 static void make_a(SkMatrix44* mat) {
    169     mat->setRotateDegreesAbout(1, 2, 3, 45);
    170 }
    171 static void make_p(SkMatrix44* mat) {
    172     SkMScalar data[] = {
    173         1, 2, 3, 4, 5, 6, 7, 8,
    174         1, 2, 3, 4, 5, 6, 7, 8,
    175     };
    176     mat->setRowMajor(data);
    177 }
    178 
    179 typedef void (*Make44Proc)(SkMatrix44*);
    180 
    181 static const Make44Proc gMakeProcs[] = {
    182     make_i, make_t, make_s, make_st, make_a, make_p
    183 };
    184 
    185 static void test_map2(skiatest::Reporter* reporter, const SkMatrix44& mat) {
    186     SkMScalar src2[] = { 1, 2 };
    187     SkMScalar src4[] = { src2[0], src2[1], 0, 1 };
    188     SkMScalar dstA[4], dstB[4];
    189 
    190     for (int i = 0; i < 4; ++i) {
    191         dstA[i] = 123456789;
    192         dstB[i] = 987654321;
    193     }
    194 
    195     mat.map2(src2, 1, dstA);
    196     mat.mapMScalars(src4, dstB);
    197 
    198     for (int i = 0; i < 4; ++i) {
    199         REPORTER_ASSERT(reporter, dstA[i] == dstB[i]);
    200     }
    201 }
    202 
    203 static void test_map2(skiatest::Reporter* reporter) {
    204     SkMatrix44 mat;
    205 
    206     for (size_t i = 0; i < SK_ARRAY_COUNT(gMakeProcs); ++i) {
    207         gMakeProcs[i](&mat);
    208         test_map2(reporter, mat);
    209     }
    210 }
    211 
    212 static void test_gettype(skiatest::Reporter* reporter) {
    213     SkMatrix44 matrix;
    214 
    215     REPORTER_ASSERT(reporter, matrix.isIdentity());
    216     REPORTER_ASSERT(reporter, SkMatrix44::kIdentity_Mask == matrix.getType());
    217 
    218     int expectedMask;
    219 
    220     matrix.set(1, 1, 0);
    221     expectedMask = SkMatrix44::kScale_Mask;
    222     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    223 
    224     matrix.set(0, 3, 1);    // translate-x
    225     expectedMask |= SkMatrix44::kTranslate_Mask;
    226     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    227 
    228     matrix.set(2, 0, 1);
    229     expectedMask |= SkMatrix44::kAffine_Mask;
    230     REPORTER_ASSERT(reporter, matrix.getType() == expectedMask);
    231 
    232     matrix.set(3, 2, 1);
    233     REPORTER_ASSERT(reporter, matrix.getType() & SkMatrix44::kPerspective_Mask);
    234 
    235     // ensure that negative zero is treated as zero
    236     SkMScalar dx = 0;
    237     SkMScalar dy = 0;
    238     SkMScalar dz = 0;
    239     matrix.setTranslate(-dx, -dy, -dz);
    240     REPORTER_ASSERT(reporter, matrix.isIdentity());
    241     matrix.preTranslate(-dx, -dy, -dz);
    242     REPORTER_ASSERT(reporter, matrix.isIdentity());
    243     matrix.postTranslate(-dx, -dy, -dz);
    244     REPORTER_ASSERT(reporter, matrix.isIdentity());
    245 }
    246 
    247 static void test_common_angles(skiatest::Reporter* reporter) {
    248     SkMatrix44 rot;
    249     // Test precision of rotation in common cases
    250     int common_angles[] = { 0, 90, -90, 180, -180, 270, -270, 360, -360 };
    251     for (int i = 0; i < 9; ++i) {
    252         rot.setRotateDegreesAbout(0, 0, -1, SkIntToScalar(common_angles[i]));
    253 
    254         SkMatrix rot3x3 = rot;
    255         REPORTER_ASSERT(reporter, rot3x3.rectStaysRect());
    256     }
    257 }
    258 
    259 static void test_concat(skiatest::Reporter* reporter) {
    260     int i;
    261     SkMatrix44 a, b, c, d;
    262 
    263     a.setTranslate(10, 10, 10);
    264     b.setScale(2, 2, 2);
    265 
    266     SkScalar src[8] = {
    267         0, 0, 0, 1,
    268         1, 1, 1, 1
    269     };
    270     SkScalar dst[8];
    271 
    272     c.setConcat(a, b);
    273 
    274     d = a;
    275     d.preConcat(b);
    276     REPORTER_ASSERT(reporter, d == c);
    277 
    278     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
    279     for (i = 0; i < 3; ++i) {
    280         REPORTER_ASSERT(reporter, 10 == dst[i]);
    281         REPORTER_ASSERT(reporter, 12 == dst[i + 4]);
    282     }
    283 
    284     c.setConcat(b, a);
    285 
    286     d = a;
    287     d.postConcat(b);
    288     REPORTER_ASSERT(reporter, d == c);
    289 
    290     c.mapScalars(src, dst); c.mapScalars(src + 4, dst + 4);
    291     for (i = 0; i < 3; ++i) {
    292         REPORTER_ASSERT(reporter, 20 == dst[i]);
    293         REPORTER_ASSERT(reporter, 22 == dst[i + 4]);
    294     }
    295 }
    296 
    297 static void test_determinant(skiatest::Reporter* reporter) {
    298     SkMatrix44 a;
    299     REPORTER_ASSERT(reporter, nearly_equal_double(1, a.determinant()));
    300     a.set(1, 1, 2);
    301     REPORTER_ASSERT(reporter, nearly_equal_double(2, a.determinant()));
    302     SkMatrix44 b;
    303     REPORTER_ASSERT(reporter, a.invert(&b));
    304     REPORTER_ASSERT(reporter, nearly_equal_double(0.5, b.determinant()));
    305     SkMatrix44 c = b = a;
    306     c.set(0, 1, 4);
    307     b.set(1, 0, 4);
    308     REPORTER_ASSERT(reporter,
    309                     nearly_equal_double(a.determinant(),
    310                                         b.determinant()));
    311     SkMatrix44 d = a;
    312     d.set(0, 0, 8);
    313     REPORTER_ASSERT(reporter, nearly_equal_double(16, d.determinant()));
    314 
    315     SkMatrix44 e = a;
    316     e.postConcat(d);
    317     REPORTER_ASSERT(reporter, nearly_equal_double(32, e.determinant()));
    318     e.set(0, 0, 0);
    319     REPORTER_ASSERT(reporter, nearly_equal_double(0, e.determinant()));
    320 }
    321 
    322 static void test_transpose(skiatest::Reporter* reporter) {
    323     SkMatrix44 a;
    324     SkMatrix44 b;
    325 
    326     int i = 0;
    327     for (int row = 0; row < 4; ++row) {
    328         for (int col = 0; col < 4; ++col) {
    329             a.setDouble(row, col, i);
    330             b.setDouble(col, row, i++);
    331         }
    332     }
    333 
    334     a.transpose();
    335     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    336 }
    337 
    338 static void test_get_set_double(skiatest::Reporter* reporter) {
    339     SkMatrix44 a;
    340     for (int row = 0; row < 4; ++row) {
    341         for (int col = 0; col < 4; ++col) {
    342             a.setDouble(row, col, 3.141592653589793);
    343             REPORTER_ASSERT(reporter,
    344                             nearly_equal_double(3.141592653589793,
    345                                                 a.getDouble(row, col)));
    346             a.setDouble(row, col, 0);
    347             REPORTER_ASSERT(reporter,
    348                             nearly_equal_double(0, a.getDouble(row, col)));
    349         }
    350     }
    351 }
    352 
    353 static void test_set_row_col_major(skiatest::Reporter* reporter) {
    354     SkMatrix44 a, b, c, d;
    355     for (int row = 0; row < 4; ++row) {
    356         for (int col = 0; col < 4; ++col) {
    357             a.setDouble(row, col, row * 4 + col);
    358         }
    359     }
    360 
    361     double bufferd[16];
    362     float bufferf[16];
    363     a.asColMajord(bufferd);
    364     b.setColMajord(bufferd);
    365     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    366     b.setRowMajord(bufferd);
    367     b.transpose();
    368     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    369     a.asColMajorf(bufferf);
    370     b.setColMajorf(bufferf);
    371     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    372     b.setRowMajorf(bufferf);
    373     b.transpose();
    374     REPORTER_ASSERT(reporter, nearly_equal(a, b));
    375 }
    376 
    377 static void TestMatrix44(skiatest::Reporter* reporter) {
    378     SkMatrix44 mat, inverse, iden1, iden2, rot;
    379 
    380     mat.reset();
    381     mat.setTranslate(1, 1, 1);
    382     mat.invert(&inverse);
    383     iden1.setConcat(mat, inverse);
    384     REPORTER_ASSERT(reporter, is_identity(iden1));
    385 
    386     mat.setScale(2, 2, 2);
    387     mat.invert(&inverse);
    388     iden1.setConcat(mat, inverse);
    389     REPORTER_ASSERT(reporter, is_identity(iden1));
    390 
    391     mat.setScale(SK_MScalar1/2, SK_MScalar1/2, SK_MScalar1/2);
    392     mat.invert(&inverse);
    393     iden1.setConcat(mat, inverse);
    394     REPORTER_ASSERT(reporter, is_identity(iden1));
    395 
    396     mat.setScale(3, 3, 3);
    397     rot.setRotateDegreesAbout(0, 0, -1, 90);
    398     mat.postConcat(rot);
    399     REPORTER_ASSERT(reporter, mat.invert(NULL));
    400     mat.invert(&inverse);
    401     iden1.setConcat(mat, inverse);
    402     REPORTER_ASSERT(reporter, is_identity(iden1));
    403     iden2.setConcat(inverse, mat);
    404     REPORTER_ASSERT(reporter, is_identity(iden2));
    405 
    406     // test rol/col Major getters
    407     {
    408         mat.setTranslate(2, 3, 4);
    409         float dataf[16];
    410         double datad[16];
    411 
    412         mat.asColMajorf(dataf);
    413         assert16<float>(reporter, dataf,
    414                  1, 0, 0, 0,
    415                  0, 1, 0, 0,
    416                  0, 0, 1, 0,
    417                  2, 3, 4, 1);
    418         mat.asColMajord(datad);
    419         assert16<double>(reporter, datad, 1, 0, 0, 0,
    420                         0, 1, 0, 0,
    421                         0, 0, 1, 0,
    422                         2, 3, 4, 1);
    423         mat.asRowMajorf(dataf);
    424         assert16<float>(reporter, dataf, 1, 0, 0, 2,
    425                         0, 1, 0, 3,
    426                         0, 0, 1, 4,
    427                         0, 0, 0, 1);
    428         mat.asRowMajord(datad);
    429         assert16<double>(reporter, datad, 1, 0, 0, 2,
    430                         0, 1, 0, 3,
    431                         0, 0, 1, 4,
    432                         0, 0, 0, 1);
    433     }
    434 
    435     test_concat(reporter);
    436 
    437     if (false) { // avoid bit rot, suppress warning (working on making this pass)
    438         test_common_angles(reporter);
    439     }
    440 
    441     test_constructor(reporter);
    442     test_gettype(reporter);
    443     test_determinant(reporter);
    444     test_transpose(reporter);
    445     test_get_set_double(reporter);
    446     test_set_row_col_major(reporter);
    447     test_translate(reporter);
    448     test_scale(reporter);
    449     test_map2(reporter);
    450 }
    451 
    452 #include "TestClassDef.h"
    453 DEFINE_TESTCLASS("Matrix44", Matrix44TestClass, TestMatrix44)
    454