Home | History | Annotate | Download | only in geometry
      1 // Copyright (c) 2012 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 "base/basictypes.h"
      6 #include "testing/gtest/include/gtest/gtest.h"
      7 #include "ui/gfx/geometry/quad_f.h"
      8 #include "ui/gfx/geometry/rect_f.h"
      9 
     10 namespace gfx {
     11 
     12 TEST(QuadTest, Construction) {
     13   // Verify constructors.
     14   PointF a(1, 1);
     15   PointF b(2, 1);
     16   PointF c(2, 2);
     17   PointF d(1, 2);
     18   PointF e;
     19   QuadF q1;
     20   QuadF q2(e, e, e, e);
     21   QuadF q3(a, b, c, d);
     22   QuadF q4(BoundingRect(a, c));
     23   EXPECT_EQ(q1, q2);
     24   EXPECT_EQ(q3, q4);
     25 
     26   // Verify getters.
     27   EXPECT_EQ(q3.p1(), a);
     28   EXPECT_EQ(q3.p2(), b);
     29   EXPECT_EQ(q3.p3(), c);
     30   EXPECT_EQ(q3.p4(), d);
     31 
     32   // Verify setters.
     33   q3.set_p1(b);
     34   q3.set_p2(c);
     35   q3.set_p3(d);
     36   q3.set_p4(a);
     37   EXPECT_EQ(q3.p1(), b);
     38   EXPECT_EQ(q3.p2(), c);
     39   EXPECT_EQ(q3.p3(), d);
     40   EXPECT_EQ(q3.p4(), a);
     41 
     42   // Verify operator=(Rect)
     43   EXPECT_NE(q1, q4);
     44   q1 = BoundingRect(a, c);
     45   EXPECT_EQ(q1, q4);
     46 
     47   // Verify operator=(Quad)
     48   EXPECT_NE(q1, q3);
     49   q1 = q3;
     50   EXPECT_EQ(q1, q3);
     51 }
     52 
     53 TEST(QuadTest, AddingVectors) {
     54   PointF a(1, 1);
     55   PointF b(2, 1);
     56   PointF c(2, 2);
     57   PointF d(1, 2);
     58   Vector2dF v(3.5f, -2.5f);
     59 
     60   QuadF q1(a, b, c, d);
     61   QuadF added = q1 + v;
     62   q1 += v;
     63   QuadF expected1(PointF(4.5f, -1.5f),
     64                   PointF(5.5f, -1.5f),
     65                   PointF(5.5f, -0.5f),
     66                   PointF(4.5f, -0.5f));
     67   EXPECT_EQ(expected1, added);
     68   EXPECT_EQ(expected1, q1);
     69 
     70   QuadF q2(a, b, c, d);
     71   QuadF subtracted = q2 - v;
     72   q2 -= v;
     73   QuadF expected2(PointF(-2.5f, 3.5f),
     74                   PointF(-1.5f, 3.5f),
     75                   PointF(-1.5f, 4.5f),
     76                   PointF(-2.5f, 4.5f));
     77   EXPECT_EQ(expected2, subtracted);
     78   EXPECT_EQ(expected2, q2);
     79 
     80   QuadF q3(a, b, c, d);
     81   q3 += v;
     82   q3 -= v;
     83   EXPECT_EQ(QuadF(a, b, c, d), q3);
     84   EXPECT_EQ(q3, (q3 + v - v));
     85 }
     86 
     87 TEST(QuadTest, IsRectilinear) {
     88   PointF a(1, 1);
     89   PointF b(2, 1);
     90   PointF c(2, 2);
     91   PointF d(1, 2);
     92   Vector2dF v(3.5f, -2.5f);
     93 
     94   EXPECT_TRUE(QuadF().IsRectilinear());
     95   EXPECT_TRUE(QuadF(a, b, c, d).IsRectilinear());
     96   EXPECT_TRUE((QuadF(a, b, c, d) + v).IsRectilinear());
     97 
     98   float epsilon = std::numeric_limits<float>::epsilon();
     99   PointF a2(1 + epsilon / 2, 1 + epsilon / 2);
    100   PointF b2(2 + epsilon / 2, 1 + epsilon / 2);
    101   PointF c2(2 + epsilon / 2, 2 + epsilon / 2);
    102   PointF d2(1 + epsilon / 2, 2 + epsilon / 2);
    103   EXPECT_TRUE(QuadF(a2, b, c, d).IsRectilinear());
    104   EXPECT_TRUE((QuadF(a2, b, c, d) + v).IsRectilinear());
    105   EXPECT_TRUE(QuadF(a, b2, c, d).IsRectilinear());
    106   EXPECT_TRUE((QuadF(a, b2, c, d) + v).IsRectilinear());
    107   EXPECT_TRUE(QuadF(a, b, c2, d).IsRectilinear());
    108   EXPECT_TRUE((QuadF(a, b, c2, d) + v).IsRectilinear());
    109   EXPECT_TRUE(QuadF(a, b, c, d2).IsRectilinear());
    110   EXPECT_TRUE((QuadF(a, b, c, d2) + v).IsRectilinear());
    111 
    112   struct {
    113     PointF a_off, b_off, c_off, d_off;
    114   } tests[] = {
    115     {
    116       PointF(1, 1.00001f),
    117       PointF(2, 1.00001f),
    118       PointF(2, 2.00001f),
    119       PointF(1, 2.00001f)
    120     },
    121     {
    122       PointF(1.00001f, 1),
    123       PointF(2.00001f, 1),
    124       PointF(2.00001f, 2),
    125       PointF(1.00001f, 2)
    126     },
    127     {
    128       PointF(1.00001f, 1.00001f),
    129       PointF(2.00001f, 1.00001f),
    130       PointF(2.00001f, 2.00001f),
    131       PointF(1.00001f, 2.00001f)
    132     },
    133     {
    134       PointF(1, 0.99999f),
    135       PointF(2, 0.99999f),
    136       PointF(2, 1.99999f),
    137       PointF(1, 1.99999f)
    138     },
    139     {
    140       PointF(0.99999f, 1),
    141       PointF(1.99999f, 1),
    142       PointF(1.99999f, 2),
    143       PointF(0.99999f, 2)
    144     },
    145     {
    146       PointF(0.99999f, 0.99999f),
    147       PointF(1.99999f, 0.99999f),
    148       PointF(1.99999f, 1.99999f),
    149       PointF(0.99999f, 1.99999f)
    150     }
    151   };
    152 
    153   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    154     PointF a_off = tests[i].a_off;
    155     PointF b_off = tests[i].b_off;
    156     PointF c_off = tests[i].c_off;
    157     PointF d_off = tests[i].d_off;
    158 
    159     EXPECT_FALSE(QuadF(a_off, b, c, d).IsRectilinear());
    160     EXPECT_FALSE((QuadF(a_off, b, c, d) + v).IsRectilinear());
    161     EXPECT_FALSE(QuadF(a, b_off, c, d).IsRectilinear());
    162     EXPECT_FALSE((QuadF(a, b_off, c, d) + v).IsRectilinear());
    163     EXPECT_FALSE(QuadF(a, b, c_off, d).IsRectilinear());
    164     EXPECT_FALSE((QuadF(a, b, c_off, d) + v).IsRectilinear());
    165     EXPECT_FALSE(QuadF(a, b, c, d_off).IsRectilinear());
    166     EXPECT_FALSE((QuadF(a, b, c, d_off) + v).IsRectilinear());
    167     EXPECT_FALSE(QuadF(a_off, b, c_off, d).IsRectilinear());
    168     EXPECT_FALSE((QuadF(a_off, b, c_off, d) + v).IsRectilinear());
    169     EXPECT_FALSE(QuadF(a, b_off, c, d_off).IsRectilinear());
    170     EXPECT_FALSE((QuadF(a, b_off, c, d_off) + v).IsRectilinear());
    171     EXPECT_FALSE(QuadF(a, b_off, c_off, d_off).IsRectilinear());
    172     EXPECT_FALSE((QuadF(a, b_off, c_off, d_off) + v).IsRectilinear());
    173     EXPECT_FALSE(QuadF(a_off, b, c_off, d_off).IsRectilinear());
    174     EXPECT_FALSE((QuadF(a_off, b, c_off, d_off) + v).IsRectilinear());
    175     EXPECT_FALSE(QuadF(a_off, b_off, c, d_off).IsRectilinear());
    176     EXPECT_FALSE((QuadF(a_off, b_off, c, d_off) + v).IsRectilinear());
    177     EXPECT_FALSE(QuadF(a_off, b_off, c_off, d).IsRectilinear());
    178     EXPECT_FALSE((QuadF(a_off, b_off, c_off, d) + v).IsRectilinear());
    179     EXPECT_TRUE(QuadF(a_off, b_off, c_off, d_off).IsRectilinear());
    180     EXPECT_TRUE((QuadF(a_off, b_off, c_off, d_off) + v).IsRectilinear());
    181   }
    182 }
    183 
    184 TEST(QuadTest, IsCounterClockwise) {
    185   PointF a1(1, 1);
    186   PointF b1(2, 1);
    187   PointF c1(2, 2);
    188   PointF d1(1, 2);
    189   EXPECT_FALSE(QuadF(a1, b1, c1, d1).IsCounterClockwise());
    190   EXPECT_FALSE(QuadF(b1, c1, d1, a1).IsCounterClockwise());
    191   EXPECT_TRUE(QuadF(a1, d1, c1, b1).IsCounterClockwise());
    192   EXPECT_TRUE(QuadF(c1, b1, a1, d1).IsCounterClockwise());
    193 
    194   // Slightly more complicated quads should work just as easily.
    195   PointF a2(1.3f, 1.4f);
    196   PointF b2(-0.7f, 4.9f);
    197   PointF c2(1.8f, 6.2f);
    198   PointF d2(2.1f, 1.6f);
    199   EXPECT_TRUE(QuadF(a2, b2, c2, d2).IsCounterClockwise());
    200   EXPECT_TRUE(QuadF(b2, c2, d2, a2).IsCounterClockwise());
    201   EXPECT_FALSE(QuadF(a2, d2, c2, b2).IsCounterClockwise());
    202   EXPECT_FALSE(QuadF(c2, b2, a2, d2).IsCounterClockwise());
    203 
    204   // Quads with 3 collinear points should work correctly, too.
    205   PointF a3(0, 0);
    206   PointF b3(1, 0);
    207   PointF c3(2, 0);
    208   PointF d3(1, 1);
    209   EXPECT_FALSE(QuadF(a3, b3, c3, d3).IsCounterClockwise());
    210   EXPECT_FALSE(QuadF(b3, c3, d3, a3).IsCounterClockwise());
    211   EXPECT_TRUE(QuadF(a3, d3, c3, b3).IsCounterClockwise());
    212   // The next expectation in particular would fail for an implementation
    213   // that incorrectly uses only a cross product of the first 3 vertices.
    214   EXPECT_TRUE(QuadF(c3, b3, a3, d3).IsCounterClockwise());
    215 
    216   // Non-convex quads should work correctly, too.
    217   PointF a4(0, 0);
    218   PointF b4(1, 1);
    219   PointF c4(2, 0);
    220   PointF d4(1, 3);
    221   EXPECT_FALSE(QuadF(a4, b4, c4, d4).IsCounterClockwise());
    222   EXPECT_FALSE(QuadF(b4, c4, d4, a4).IsCounterClockwise());
    223   EXPECT_TRUE(QuadF(a4, d4, c4, b4).IsCounterClockwise());
    224   EXPECT_TRUE(QuadF(c4, b4, a4, d4).IsCounterClockwise());
    225 
    226   // A quad with huge coordinates should not fail this check due to
    227   // single-precision overflow.
    228   PointF a5(1e30f, 1e30f);
    229   PointF b5(1e35f, 1e30f);
    230   PointF c5(1e35f, 1e35f);
    231   PointF d5(1e30f, 1e35f);
    232   EXPECT_FALSE(QuadF(a5, b5, c5, d5).IsCounterClockwise());
    233   EXPECT_FALSE(QuadF(b5, c5, d5, a5).IsCounterClockwise());
    234   EXPECT_TRUE(QuadF(a5, d5, c5, b5).IsCounterClockwise());
    235   EXPECT_TRUE(QuadF(c5, b5, a5, d5).IsCounterClockwise());
    236 }
    237 
    238 TEST(QuadTest, BoundingBox) {
    239   RectF r(3.2f, 5.4f, 7.007f, 12.01f);
    240   EXPECT_EQ(r, QuadF(r).BoundingBox());
    241 
    242   PointF a(1.3f, 1.4f);
    243   PointF b(-0.7f, 4.9f);
    244   PointF c(1.8f, 6.2f);
    245   PointF d(2.1f, 1.6f);
    246   float left = -0.7f;
    247   float top = 1.4f;
    248   float right = 2.1f;
    249   float bottom = 6.2f;
    250   EXPECT_EQ(RectF(left, top, right - left, bottom - top),
    251             QuadF(a, b, c, d).BoundingBox());
    252 }
    253 
    254 TEST(QuadTest, ContainsPoint) {
    255   PointF a(1.3f, 1.4f);
    256   PointF b(-0.8f, 4.4f);
    257   PointF c(1.8f, 6.1f);
    258   PointF d(2.1f, 1.6f);
    259 
    260   Vector2dF epsilon_x(2 * std::numeric_limits<float>::epsilon(), 0);
    261   Vector2dF epsilon_y(0, 2 * std::numeric_limits<float>::epsilon());
    262 
    263   Vector2dF ac_center = c - a;
    264   ac_center.Scale(0.5f);
    265   Vector2dF bd_center = d - b;
    266   bd_center.Scale(0.5f);
    267 
    268   EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + ac_center));
    269   EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + bd_center));
    270   EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - ac_center));
    271   EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - bd_center));
    272   EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - ac_center));
    273   EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - bd_center));
    274   EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + ac_center));
    275   EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + bd_center));
    276 
    277   EXPECT_TRUE(QuadF(a, b, c, d).Contains(a));
    278   EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_x));
    279   EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_y));
    280   EXPECT_FALSE(QuadF(a, b, c, d).Contains(a + epsilon_x));
    281   EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + epsilon_y));
    282 
    283   EXPECT_TRUE(QuadF(a, b, c, d).Contains(b));
    284   EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_x));
    285   EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_y));
    286   EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + epsilon_x));
    287   EXPECT_FALSE(QuadF(a, b, c, d).Contains(b + epsilon_y));
    288 
    289   EXPECT_TRUE(QuadF(a, b, c, d).Contains(c));
    290   EXPECT_FALSE(QuadF(a, b, c, d).Contains(c - epsilon_x));
    291   EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - epsilon_y));
    292   EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_x));
    293   EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_y));
    294 
    295   EXPECT_TRUE(QuadF(a, b, c, d).Contains(d));
    296   EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - epsilon_x));
    297   EXPECT_FALSE(QuadF(a, b, c, d).Contains(d - epsilon_y));
    298   EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_x));
    299   EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_y));
    300 
    301   // Test a simple square.
    302   PointF s1(-1, -1);
    303   PointF s2(1, -1);
    304   PointF s3(1, 1);
    305   PointF s4(-1, 1);
    306   // Top edge.
    307   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, -1.0f)));
    308   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
    309   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, -1.0f)));
    310   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
    311   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, -1.0f)));
    312   // Bottom edge.
    313   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 1.0f)));
    314   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
    315   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, 1.0f)));
    316   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
    317   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 1.0f)));
    318   // Left edge.
    319   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.1f)));
    320   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
    321   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 0.0f)));
    322   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
    323   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.1f)));
    324   // Right edge.
    325   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.1f)));
    326   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
    327   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 0.0f)));
    328   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
    329   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.1f)));
    330   // Centered inside.
    331   EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 0)));
    332   // Centered outside.
    333   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 0)));
    334   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 0)));
    335   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, -1.1f)));
    336   EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 1.1f)));
    337 }
    338 
    339 TEST(QuadTest, Scale) {
    340   PointF a(1.3f, 1.4f);
    341   PointF b(-0.8f, 4.4f);
    342   PointF c(1.8f, 6.1f);
    343   PointF d(2.1f, 1.6f);
    344   QuadF q1(a, b, c, d);
    345   q1.Scale(1.5f);
    346 
    347   PointF a_scaled = ScalePoint(a, 1.5f);
    348   PointF b_scaled = ScalePoint(b, 1.5f);
    349   PointF c_scaled = ScalePoint(c, 1.5f);
    350   PointF d_scaled = ScalePoint(d, 1.5f);
    351   EXPECT_EQ(q1, QuadF(a_scaled, b_scaled, c_scaled, d_scaled));
    352 
    353   QuadF q2;
    354   q2.Scale(1.5f);
    355   EXPECT_EQ(q2, q2);
    356 }
    357 
    358 }  // namespace gfx
    359