| // 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 "gtest/gtest.h" |
| |
| #include "flutter/impeller/geometry/rect.h" |
| |
| #include "flutter/impeller/geometry/geometry_asserts.h" |
| |
| namespace impeller { |
| namespace testing { |
| |
| TEST(RectTest, RectEmptyDeclaration) { |
| Rect rect; |
| |
| EXPECT_EQ(rect.GetLeft(), 0.0f); |
| EXPECT_EQ(rect.GetTop(), 0.0f); |
| EXPECT_EQ(rect.GetRight(), 0.0f); |
| EXPECT_EQ(rect.GetBottom(), 0.0f); |
| EXPECT_EQ(rect.GetX(), 0.0f); |
| EXPECT_EQ(rect.GetY(), 0.0f); |
| EXPECT_EQ(rect.GetWidth(), 0.0f); |
| EXPECT_EQ(rect.GetHeight(), 0.0f); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| TEST(RectTest, IRectEmptyDeclaration) { |
| IRect rect; |
| |
| EXPECT_EQ(rect.GetLeft(), 0); |
| EXPECT_EQ(rect.GetTop(), 0); |
| EXPECT_EQ(rect.GetRight(), 0); |
| EXPECT_EQ(rect.GetBottom(), 0); |
| EXPECT_EQ(rect.GetX(), 0); |
| EXPECT_EQ(rect.GetY(), 0); |
| EXPECT_EQ(rect.GetWidth(), 0); |
| EXPECT_EQ(rect.GetHeight(), 0); |
| EXPECT_TRUE(rect.IsEmpty()); |
| // EXPECT_TRUE(rect.IsFinite()); // should fail to compile |
| } |
| |
| TEST(RectTest, RectDefaultConstructor) { |
| Rect rect = Rect(); |
| |
| EXPECT_EQ(rect.GetLeft(), 0.0f); |
| EXPECT_EQ(rect.GetTop(), 0.0f); |
| EXPECT_EQ(rect.GetRight(), 0.0f); |
| EXPECT_EQ(rect.GetBottom(), 0.0f); |
| EXPECT_EQ(rect.GetX(), 0.0f); |
| EXPECT_EQ(rect.GetY(), 0.0f); |
| EXPECT_EQ(rect.GetWidth(), 0.0f); |
| EXPECT_EQ(rect.GetHeight(), 0.0f); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| TEST(RectTest, IRectDefaultConstructor) { |
| IRect rect = IRect(); |
| |
| EXPECT_EQ(rect.GetLeft(), 0); |
| EXPECT_EQ(rect.GetTop(), 0); |
| EXPECT_EQ(rect.GetRight(), 0); |
| EXPECT_EQ(rect.GetBottom(), 0); |
| EXPECT_EQ(rect.GetX(), 0); |
| EXPECT_EQ(rect.GetY(), 0); |
| EXPECT_EQ(rect.GetWidth(), 0); |
| EXPECT_EQ(rect.GetHeight(), 0); |
| EXPECT_TRUE(rect.IsEmpty()); |
| } |
| |
| TEST(RectTest, RectSimpleLTRB) { |
| // Using fractional-power-of-2 friendly values for equality tests |
| Rect rect = Rect::MakeLTRB(5.125f, 10.25f, 20.625f, 25.375f); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.125f); |
| EXPECT_EQ(rect.GetTop(), 10.25f); |
| EXPECT_EQ(rect.GetRight(), 20.625f); |
| EXPECT_EQ(rect.GetBottom(), 25.375f); |
| EXPECT_EQ(rect.GetX(), 5.125f); |
| EXPECT_EQ(rect.GetY(), 10.25f); |
| EXPECT_EQ(rect.GetWidth(), 15.5f); |
| EXPECT_EQ(rect.GetHeight(), 15.125f); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| TEST(RectTest, IRectSimpleLTRB) { |
| IRect rect = IRect::MakeLTRB(5, 10, 20, 25); |
| |
| EXPECT_EQ(rect.GetLeft(), 5); |
| EXPECT_EQ(rect.GetTop(), 10); |
| EXPECT_EQ(rect.GetRight(), 20); |
| EXPECT_EQ(rect.GetBottom(), 25); |
| EXPECT_EQ(rect.GetX(), 5); |
| EXPECT_EQ(rect.GetY(), 10); |
| EXPECT_EQ(rect.GetWidth(), 15); |
| EXPECT_EQ(rect.GetHeight(), 15); |
| EXPECT_FALSE(rect.IsEmpty()); |
| } |
| |
| TEST(RectTest, RectSimpleXYWH) { |
| // Using fractional-power-of-2 friendly values for equality tests |
| Rect rect = Rect::MakeXYWH(5.125f, 10.25f, 15.5f, 15.125f); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.125f); |
| EXPECT_EQ(rect.GetTop(), 10.25f); |
| EXPECT_EQ(rect.GetRight(), 20.625f); |
| EXPECT_EQ(rect.GetBottom(), 25.375f); |
| EXPECT_EQ(rect.GetX(), 5.125f); |
| EXPECT_EQ(rect.GetY(), 10.25f); |
| EXPECT_EQ(rect.GetWidth(), 15.5f); |
| EXPECT_EQ(rect.GetHeight(), 15.125f); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| TEST(RectTest, IRectSimpleXYWH) { |
| IRect rect = IRect::MakeXYWH(5, 10, 15, 16); |
| |
| EXPECT_EQ(rect.GetLeft(), 5); |
| EXPECT_EQ(rect.GetTop(), 10); |
| EXPECT_EQ(rect.GetRight(), 20); |
| EXPECT_EQ(rect.GetBottom(), 26); |
| EXPECT_EQ(rect.GetX(), 5); |
| EXPECT_EQ(rect.GetY(), 10); |
| EXPECT_EQ(rect.GetWidth(), 15); |
| EXPECT_EQ(rect.GetHeight(), 16); |
| EXPECT_FALSE(rect.IsEmpty()); |
| } |
| |
| TEST(RectTest, RectOverflowXYWH) { |
| auto min = std::numeric_limits<Scalar>::lowest(); |
| auto max = std::numeric_limits<Scalar>::max(); |
| auto inf = std::numeric_limits<Scalar>::infinity(); |
| |
| // 8 cases: |
| // finite X, max W |
| // max X, max W |
| // finite Y, max H |
| // max Y, max H |
| // finite X, min W |
| // min X, min W |
| // finite Y, min H |
| // min Y, min H |
| |
| // a small finite value added to a max value will remain max |
| // a very large finite value (like max) added to max will go to infinity |
| |
| { |
| Rect rect = Rect::MakeXYWH(5.0, 10.0f, max, 15.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), max); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), max); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeXYWH(max, 10.0f, max, 15.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), max); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), inf); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), max); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), inf); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_FALSE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeXYWH(5.0f, 10.0f, 20.0f, max); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), 25.0f); |
| EXPECT_EQ(rect.GetBottom(), max); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), 20.0f); |
| EXPECT_EQ(rect.GetHeight(), max); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeXYWH(5.0f, max, 20.0f, max); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), max); |
| EXPECT_EQ(rect.GetRight(), 25.0f); |
| EXPECT_EQ(rect.GetBottom(), inf); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), max); |
| EXPECT_EQ(rect.GetWidth(), 20.0f); |
| EXPECT_EQ(rect.GetHeight(), inf); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_FALSE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeXYWH(5.0, 10.0f, min, 15.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), min); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), min); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeXYWH(min, 10.0f, min, 15.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), min); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), -inf); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), min); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), -inf); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_FALSE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeXYWH(5.0f, 10.0f, 20.0f, min); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), 25.0f); |
| EXPECT_EQ(rect.GetBottom(), min); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), 20.0f); |
| EXPECT_EQ(rect.GetHeight(), min); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeXYWH(5.0f, min, 20.0f, min); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), min); |
| EXPECT_EQ(rect.GetRight(), 25.0f); |
| EXPECT_EQ(rect.GetBottom(), -inf); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), min); |
| EXPECT_EQ(rect.GetWidth(), 20.0f); |
| EXPECT_EQ(rect.GetHeight(), -inf); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_FALSE(rect.IsFinite()); |
| } |
| } |
| |
| TEST(RectTest, IRectOverflowXYWH) { |
| auto min = std::numeric_limits<int64_t>::min(); |
| auto max = std::numeric_limits<int64_t>::max(); |
| |
| // 4 cases |
| // x near max, positive w takes it past max |
| // x near min, negative w takes it below min |
| // y near max, positive h takes it past max |
| // y near min, negative h takes it below min |
| |
| { |
| IRect rect = IRect::MakeXYWH(max - 5, 10, 10, 16); |
| |
| EXPECT_EQ(rect.GetLeft(), max - 5); |
| EXPECT_EQ(rect.GetTop(), 10); |
| EXPECT_EQ(rect.GetRight(), max); |
| EXPECT_EQ(rect.GetBottom(), 26); |
| EXPECT_EQ(rect.GetX(), max - 5); |
| EXPECT_EQ(rect.GetY(), 10); |
| EXPECT_EQ(rect.GetWidth(), 5); |
| EXPECT_EQ(rect.GetHeight(), 16); |
| EXPECT_FALSE(rect.IsEmpty()); |
| } |
| |
| { |
| IRect rect = IRect::MakeXYWH(min + 5, 10, -10, 16); |
| |
| EXPECT_EQ(rect.GetLeft(), min + 5); |
| EXPECT_EQ(rect.GetTop(), 10); |
| EXPECT_EQ(rect.GetRight(), min); |
| EXPECT_EQ(rect.GetBottom(), 26); |
| EXPECT_EQ(rect.GetX(), min + 5); |
| EXPECT_EQ(rect.GetY(), 10); |
| EXPECT_EQ(rect.GetWidth(), -5); |
| EXPECT_EQ(rect.GetHeight(), 16); |
| EXPECT_TRUE(rect.IsEmpty()); |
| } |
| |
| { |
| IRect rect = IRect::MakeXYWH(5, max - 10, 10, 16); |
| |
| EXPECT_EQ(rect.GetLeft(), 5); |
| EXPECT_EQ(rect.GetTop(), max - 10); |
| EXPECT_EQ(rect.GetRight(), 15); |
| EXPECT_EQ(rect.GetBottom(), max); |
| EXPECT_EQ(rect.GetX(), 5); |
| EXPECT_EQ(rect.GetY(), max - 10); |
| EXPECT_EQ(rect.GetWidth(), 10); |
| EXPECT_EQ(rect.GetHeight(), 10); |
| EXPECT_FALSE(rect.IsEmpty()); |
| } |
| |
| { |
| IRect rect = IRect::MakeXYWH(5, min + 10, 10, -16); |
| |
| EXPECT_EQ(rect.GetLeft(), 5); |
| EXPECT_EQ(rect.GetTop(), min + 10); |
| EXPECT_EQ(rect.GetRight(), 15); |
| EXPECT_EQ(rect.GetBottom(), min); |
| EXPECT_EQ(rect.GetX(), 5); |
| EXPECT_EQ(rect.GetY(), min + 10); |
| EXPECT_EQ(rect.GetWidth(), 10); |
| EXPECT_EQ(rect.GetHeight(), -10); |
| EXPECT_TRUE(rect.IsEmpty()); |
| } |
| } |
| |
| TEST(RectTest, RectOverflowLTRB) { |
| auto min = std::numeric_limits<Scalar>::lowest(); |
| auto max = std::numeric_limits<Scalar>::max(); |
| auto inf = std::numeric_limits<Scalar>::infinity(); |
| |
| // 8 cases: |
| // finite negative X, max W |
| // ~min X, ~max W |
| // finite negative Y, max H |
| // ~min Y, ~max H |
| // finite positive X, min W |
| // ~min X, ~min W |
| // finite positive Y, min H |
| // ~min Y, ~min H |
| |
| // a small finite value subtracted from a max value will remain max |
| // a very large finite value (like min) subtracted from max will go to inf |
| |
| { |
| Rect rect = Rect::MakeLTRB(-5.0f, 10.0f, max, 25.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), -5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), max); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), -5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), max); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeLTRB(min + 5.0f, 10.0f, max - 5.0f, 25.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), min + 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), max - 5.0f); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), min + 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), inf); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeLTRB(5.0f, -10.0f, 20.0f, max); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), -10.0f); |
| EXPECT_EQ(rect.GetRight(), 20.0f); |
| EXPECT_EQ(rect.GetBottom(), max); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), -10.0f); |
| EXPECT_EQ(rect.GetWidth(), 15.0f); |
| EXPECT_EQ(rect.GetHeight(), max); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeLTRB(5.0f, min + 10.0f, 20.0f, max - 15.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), min + 10.0f); |
| EXPECT_EQ(rect.GetRight(), 20.0f); |
| EXPECT_EQ(rect.GetBottom(), max - 15.0f); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), min + 10.0f); |
| EXPECT_EQ(rect.GetWidth(), 15.0f); |
| EXPECT_EQ(rect.GetHeight(), inf); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeLTRB(5.0f, 10.0f, min, 25.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), min); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), min); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeLTRB(max - 5.0f, 10.0f, min + 10.0f, 25.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), max - 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), min + 10.0f); |
| EXPECT_EQ(rect.GetBottom(), 25.0f); |
| EXPECT_EQ(rect.GetX(), max - 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), -inf); |
| EXPECT_EQ(rect.GetHeight(), 15.0f); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeLTRB(5.0f, 10.0f, 20.0f, min); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), 10.0f); |
| EXPECT_EQ(rect.GetRight(), 20.0f); |
| EXPECT_EQ(rect.GetBottom(), min); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), 10.0f); |
| EXPECT_EQ(rect.GetWidth(), 15.0f); |
| EXPECT_EQ(rect.GetHeight(), min); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| { |
| Rect rect = Rect::MakeLTRB(5.0f, max - 5.0f, 20.0f, min + 10.0f); |
| |
| EXPECT_EQ(rect.GetLeft(), 5.0f); |
| EXPECT_EQ(rect.GetTop(), max - 5.0f); |
| EXPECT_EQ(rect.GetRight(), 20.0f); |
| EXPECT_EQ(rect.GetBottom(), min + 10.0f); |
| EXPECT_EQ(rect.GetX(), 5.0f); |
| EXPECT_EQ(rect.GetY(), max - 5.0f); |
| EXPECT_EQ(rect.GetWidth(), 15.0f); |
| EXPECT_EQ(rect.GetHeight(), -inf); |
| EXPECT_TRUE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| } |
| |
| TEST(RectTest, IRectOverflowLTRB) { |
| auto min = std::numeric_limits<int64_t>::min(); |
| auto max = std::numeric_limits<int64_t>::max(); |
| |
| // 4 cases |
| // negative l, r near max takes width past max |
| // positive l, r near min takes width below min |
| // negative t, b near max takes width past max |
| // positive t, b near min takes width below min |
| |
| { |
| IRect rect = IRect::MakeLTRB(-10, 10, max - 5, 26); |
| |
| EXPECT_EQ(rect.GetLeft(), -10); |
| EXPECT_EQ(rect.GetTop(), 10); |
| EXPECT_EQ(rect.GetRight(), max - 5); |
| EXPECT_EQ(rect.GetBottom(), 26); |
| EXPECT_EQ(rect.GetX(), -10); |
| EXPECT_EQ(rect.GetY(), 10); |
| EXPECT_EQ(rect.GetWidth(), max); |
| EXPECT_EQ(rect.GetHeight(), 16); |
| EXPECT_FALSE(rect.IsEmpty()); |
| } |
| |
| { |
| IRect rect = IRect::MakeLTRB(10, 10, min + 5, 26); |
| |
| EXPECT_EQ(rect.GetLeft(), 10); |
| EXPECT_EQ(rect.GetTop(), 10); |
| EXPECT_EQ(rect.GetRight(), min + 5); |
| EXPECT_EQ(rect.GetBottom(), 26); |
| EXPECT_EQ(rect.GetX(), 10); |
| EXPECT_EQ(rect.GetY(), 10); |
| EXPECT_EQ(rect.GetWidth(), min); |
| EXPECT_EQ(rect.GetHeight(), 16); |
| EXPECT_TRUE(rect.IsEmpty()); |
| } |
| |
| { |
| IRect rect = IRect::MakeLTRB(5, -10, 15, max - 5); |
| |
| EXPECT_EQ(rect.GetLeft(), 5); |
| EXPECT_EQ(rect.GetTop(), -10); |
| EXPECT_EQ(rect.GetRight(), 15); |
| EXPECT_EQ(rect.GetBottom(), max - 5); |
| EXPECT_EQ(rect.GetX(), 5); |
| EXPECT_EQ(rect.GetY(), -10); |
| EXPECT_EQ(rect.GetWidth(), 10); |
| EXPECT_EQ(rect.GetHeight(), max); |
| EXPECT_FALSE(rect.IsEmpty()); |
| } |
| |
| { |
| IRect rect = IRect::MakeLTRB(5, 10, 15, min + 5); |
| |
| EXPECT_EQ(rect.GetLeft(), 5); |
| EXPECT_EQ(rect.GetTop(), 10); |
| EXPECT_EQ(rect.GetRight(), 15); |
| EXPECT_EQ(rect.GetBottom(), min + 5); |
| EXPECT_EQ(rect.GetX(), 5); |
| EXPECT_EQ(rect.GetY(), 10); |
| EXPECT_EQ(rect.GetWidth(), 10); |
| EXPECT_EQ(rect.GetHeight(), min); |
| EXPECT_TRUE(rect.IsEmpty()); |
| } |
| } |
| |
| TEST(RectTest, RectMakeSize) { |
| { |
| Size s(100, 200); |
| Rect r = Rect::MakeSize(s); |
| Rect expected = Rect::MakeLTRB(0, 0, 100, 200); |
| EXPECT_RECT_NEAR(r, expected); |
| } |
| |
| { |
| ISize s(100, 200); |
| Rect r = Rect::MakeSize(s); |
| Rect expected = Rect::MakeLTRB(0, 0, 100, 200); |
| EXPECT_RECT_NEAR(r, expected); |
| } |
| |
| { |
| Size s(100, 200); |
| IRect r = IRect::MakeSize(s); |
| IRect expected = IRect::MakeLTRB(0, 0, 100, 200); |
| EXPECT_EQ(r, expected); |
| } |
| |
| { |
| ISize s(100, 200); |
| IRect r = IRect::MakeSize(s); |
| IRect expected = IRect::MakeLTRB(0, 0, 100, 200); |
| EXPECT_EQ(r, expected); |
| } |
| } |
| |
| TEST(RectTest, RectMakeMaximum) { |
| Rect rect = Rect::MakeMaximum(); |
| auto inf = std::numeric_limits<Scalar>::infinity(); |
| auto min = std::numeric_limits<Scalar>::lowest(); |
| auto max = std::numeric_limits<Scalar>::max(); |
| |
| EXPECT_EQ(rect.GetLeft(), min); |
| EXPECT_EQ(rect.GetTop(), min); |
| EXPECT_EQ(rect.GetRight(), max); |
| EXPECT_EQ(rect.GetBottom(), max); |
| EXPECT_EQ(rect.GetX(), min); |
| EXPECT_EQ(rect.GetY(), min); |
| EXPECT_EQ(rect.GetWidth(), inf); |
| EXPECT_EQ(rect.GetHeight(), inf); |
| EXPECT_FALSE(rect.IsEmpty()); |
| EXPECT_TRUE(rect.IsFinite()); |
| } |
| |
| TEST(RectTest, IRectMakeMaximum) { |
| IRect rect = IRect::MakeMaximum(); |
| auto min = std::numeric_limits<int64_t>::min(); |
| auto max = std::numeric_limits<int64_t>::max(); |
| |
| EXPECT_EQ(rect.GetLeft(), min); |
| EXPECT_EQ(rect.GetTop(), min); |
| EXPECT_EQ(rect.GetRight(), max); |
| EXPECT_EQ(rect.GetBottom(), max); |
| EXPECT_EQ(rect.GetX(), min); |
| EXPECT_EQ(rect.GetY(), min); |
| EXPECT_EQ(rect.GetWidth(), max); |
| EXPECT_EQ(rect.GetHeight(), max); |
| EXPECT_FALSE(rect.IsEmpty()); |
| } |
| |
| TEST(RectTest, RectFromRect) { |
| EXPECT_EQ(Rect(Rect::MakeXYWH(2, 3, 7, 15)), |
| Rect::MakeXYWH(2.0, 3.0, 7.0, 15.0)); |
| EXPECT_EQ(Rect(Rect::MakeLTRB(2, 3, 7, 15)), |
| Rect::MakeLTRB(2.0, 3.0, 7.0, 15.0)); |
| } |
| |
| TEST(RectTest, IRectFromIRect) { |
| EXPECT_EQ(IRect(IRect::MakeXYWH(2, 3, 7, 15)), // |
| IRect::MakeXYWH(2, 3, 7, 15)); |
| EXPECT_EQ(IRect(IRect::MakeLTRB(2, 3, 7, 15)), // |
| IRect::MakeLTRB(2, 3, 7, 15)); |
| } |
| |
| TEST(RectTest, RectCopy) { |
| // Using fractional-power-of-2 friendly values for equality tests |
| Rect rect = Rect::MakeLTRB(5.125f, 10.25f, 20.625f, 25.375f); |
| Rect copy = rect; |
| |
| EXPECT_EQ(rect, copy); |
| EXPECT_EQ(copy.GetLeft(), 5.125f); |
| EXPECT_EQ(copy.GetTop(), 10.25f); |
| EXPECT_EQ(copy.GetRight(), 20.625f); |
| EXPECT_EQ(copy.GetBottom(), 25.375f); |
| EXPECT_EQ(copy.GetX(), 5.125f); |
| EXPECT_EQ(copy.GetY(), 10.25f); |
| EXPECT_EQ(copy.GetWidth(), 15.5f); |
| EXPECT_EQ(copy.GetHeight(), 15.125f); |
| EXPECT_FALSE(copy.IsEmpty()); |
| EXPECT_TRUE(copy.IsFinite()); |
| } |
| |
| TEST(RectTest, IRectCopy) { |
| IRect rect = IRect::MakeLTRB(5, 10, 20, 25); |
| IRect copy = rect; |
| |
| EXPECT_EQ(rect, copy); |
| EXPECT_EQ(copy.GetLeft(), 5); |
| EXPECT_EQ(copy.GetTop(), 10); |
| EXPECT_EQ(copy.GetRight(), 20); |
| EXPECT_EQ(copy.GetBottom(), 25); |
| EXPECT_EQ(copy.GetX(), 5); |
| EXPECT_EQ(copy.GetY(), 10); |
| EXPECT_EQ(copy.GetWidth(), 15); |
| EXPECT_EQ(copy.GetHeight(), 15); |
| EXPECT_FALSE(copy.IsEmpty()); |
| } |
| |
| TEST(RectTest, RectOriginSizeXYWHGetters) { |
| { |
| Rect r = Rect::MakeOriginSize({10, 20}, {50, 40}); |
| EXPECT_EQ(r.GetOrigin(), Point(10, 20)); |
| EXPECT_EQ(r.GetSize(), Size(50, 40)); |
| EXPECT_EQ(r.GetX(), 10); |
| EXPECT_EQ(r.GetY(), 20); |
| EXPECT_EQ(r.GetWidth(), 50); |
| EXPECT_EQ(r.GetHeight(), 40); |
| auto expected_array = std::array<Scalar, 4>{10, 20, 50, 40}; |
| EXPECT_EQ(r.GetXYWH(), expected_array); |
| } |
| |
| { |
| Rect r = Rect::MakeLTRB(10, 20, 50, 40); |
| EXPECT_EQ(r.GetOrigin(), Point(10, 20)); |
| EXPECT_EQ(r.GetSize(), Size(40, 20)); |
| EXPECT_EQ(r.GetX(), 10); |
| EXPECT_EQ(r.GetY(), 20); |
| EXPECT_EQ(r.GetWidth(), 40); |
| EXPECT_EQ(r.GetHeight(), 20); |
| auto expected_array = std::array<Scalar, 4>{10, 20, 40, 20}; |
| EXPECT_EQ(r.GetXYWH(), expected_array); |
| } |
| } |
| |
| TEST(RectTest, IRectOriginSizeXYWHGetters) { |
| { |
| IRect r = IRect::MakeOriginSize({10, 20}, {50, 40}); |
| EXPECT_EQ(r.GetOrigin(), IPoint(10, 20)); |
| EXPECT_EQ(r.GetSize(), ISize(50, 40)); |
| EXPECT_EQ(r.GetX(), 10); |
| EXPECT_EQ(r.GetY(), 20); |
| EXPECT_EQ(r.GetWidth(), 50); |
| EXPECT_EQ(r.GetHeight(), 40); |
| auto expected_array = std::array<int64_t, 4>{10, 20, 50, 40}; |
| EXPECT_EQ(r.GetXYWH(), expected_array); |
| } |
| |
| { |
| IRect r = IRect::MakeLTRB(10, 20, 50, 40); |
| EXPECT_EQ(r.GetOrigin(), IPoint(10, 20)); |
| EXPECT_EQ(r.GetSize(), ISize(40, 20)); |
| EXPECT_EQ(r.GetX(), 10); |
| EXPECT_EQ(r.GetY(), 20); |
| EXPECT_EQ(r.GetWidth(), 40); |
| EXPECT_EQ(r.GetHeight(), 20); |
| auto expected_array = std::array<int64_t, 4>{10, 20, 40, 20}; |
| EXPECT_EQ(r.GetXYWH(), expected_array); |
| } |
| } |
| |
| TEST(RectTest, RectRoundOutEmpty) { |
| Rect rect; |
| |
| EXPECT_EQ(Rect::RoundOut(rect), Rect()); |
| |
| EXPECT_EQ(IRect::RoundOut(rect), IRect()); |
| } |
| |
| TEST(RectTest, RectRoundOutSimple) { |
| Rect rect = Rect::MakeLTRB(5.125f, 10.75f, 20.625f, 25.375f); |
| |
| EXPECT_EQ(Rect::RoundOut(rect), Rect::MakeLTRB(5.0f, 10.0f, 21.0f, 26.0f)); |
| |
| EXPECT_EQ(IRect::RoundOut(rect), IRect::MakeLTRB(5, 10, 21, 26)); |
| } |
| |
| TEST(RectTest, RectRoundOutToIRectHuge) { |
| auto test = [](int corners) { |
| EXPECT_TRUE(corners >= 0 && corners <= 0xf); |
| Scalar l, t, r, b; |
| int64_t il, it, ir, ib; |
| l = il = 50; |
| t = it = 50; |
| r = ir = 80; |
| b = ib = 80; |
| if ((corners & (1 << 0)) != 0) { |
| l = -1E20; |
| il = std::numeric_limits<int64_t>::min(); |
| } |
| if ((corners & (1 << 1)) != 0) { |
| t = -1E20; |
| it = std::numeric_limits<int64_t>::min(); |
| } |
| if ((corners & (1 << 2)) != 0) { |
| r = +1E20; |
| ir = std::numeric_limits<int64_t>::max(); |
| } |
| if ((corners & (1 << 3)) != 0) { |
| b = +1E20; |
| ib = std::numeric_limits<int64_t>::max(); |
| } |
| |
| Rect rect = Rect::MakeLTRB(l, t, r, b); |
| IRect irect = IRect::RoundOut(rect); |
| EXPECT_EQ(irect.GetLeft(), il) << corners; |
| EXPECT_EQ(irect.GetTop(), it) << corners; |
| EXPECT_EQ(irect.GetRight(), ir) << corners; |
| EXPECT_EQ(irect.GetBottom(), ib) << corners; |
| }; |
| |
| for (int corners = 0; corners <= 15; corners++) { |
| test(corners); |
| } |
| } |
| |
| TEST(RectTest, RectDoesNotIntersectEmpty) { |
| Rect rect = Rect::MakeLTRB(50, 50, 100, 100); |
| |
| auto test = [&rect](Scalar l, Scalar t, Scalar r, Scalar b, |
| const std::string& label) { |
| EXPECT_FALSE(rect.IntersectsWithRect(Rect::MakeLTRB(l, b, r, t))) |
| << label << " with Top/Bottom swapped"; |
| EXPECT_FALSE(rect.IntersectsWithRect(Rect::MakeLTRB(r, b, l, t))) |
| << label << " with Left/Right swapped"; |
| EXPECT_FALSE(rect.IntersectsWithRect(Rect::MakeLTRB(r, t, l, b))) |
| << label << " with all sides swapped"; |
| }; |
| |
| test(20, 20, 30, 30, "Above and Left"); |
| test(70, 20, 80, 30, "Above"); |
| test(120, 20, 130, 30, "Above and Right"); |
| test(120, 70, 130, 80, "Right"); |
| test(120, 120, 130, 130, "Below and Right"); |
| test(70, 120, 80, 130, "Below"); |
| test(20, 120, 30, 130, "Below and Left"); |
| test(20, 70, 30, 80, "Left"); |
| |
| test(70, 70, 80, 80, "Inside"); |
| |
| test(40, 70, 60, 80, "Straddling Left"); |
| test(70, 40, 80, 60, "Straddling Top"); |
| test(90, 70, 110, 80, "Straddling Right"); |
| test(70, 90, 80, 110, "Straddling Bottom"); |
| } |
| |
| TEST(RectTest, IRectDoesNotIntersectEmpty) { |
| IRect rect = IRect::MakeLTRB(50, 50, 100, 100); |
| |
| auto test = [&rect](int64_t l, int64_t t, int64_t r, int64_t b, |
| const std::string& label) { |
| EXPECT_FALSE(rect.IntersectsWithRect(IRect::MakeLTRB(l, b, r, t))) |
| << label << " with Top/Bottom swapped"; |
| EXPECT_FALSE(rect.IntersectsWithRect(IRect::MakeLTRB(r, b, l, t))) |
| << label << " with Left/Right swapped"; |
| EXPECT_FALSE(rect.IntersectsWithRect(IRect::MakeLTRB(r, t, l, b))) |
| << label << " with all sides swapped"; |
| }; |
| |
| test(20, 20, 30, 30, "Above and Left"); |
| test(70, 20, 80, 30, "Above"); |
| test(120, 20, 130, 30, "Above and Right"); |
| test(120, 70, 130, 80, "Right"); |
| test(120, 120, 130, 130, "Below and Right"); |
| test(70, 120, 80, 130, "Below"); |
| test(20, 120, 30, 130, "Below and Left"); |
| test(20, 70, 30, 80, "Left"); |
| |
| test(70, 70, 80, 80, "Inside"); |
| |
| test(40, 70, 60, 80, "Straddling Left"); |
| test(70, 40, 80, 60, "Straddling Top"); |
| test(90, 70, 110, 80, "Straddling Right"); |
| test(70, 90, 80, 110, "Straddling Bottom"); |
| } |
| |
| TEST(RectTest, EmptyRectDoesNotIntersect) { |
| Rect rect = Rect::MakeLTRB(50, 50, 100, 100); |
| |
| auto test = [&rect](Scalar l, Scalar t, Scalar r, Scalar b, |
| const std::string& label) { |
| EXPECT_FALSE(Rect::MakeLTRB(l, b, r, t).IntersectsWithRect(rect)) |
| << label << " with Top/Bottom swapped"; |
| EXPECT_FALSE(Rect::MakeLTRB(r, b, l, t).IntersectsWithRect(rect)) |
| << label << " with Left/Right swapped"; |
| EXPECT_FALSE(Rect::MakeLTRB(r, t, l, b).IntersectsWithRect(rect)) |
| << label << " with all sides swapped"; |
| }; |
| |
| test(20, 20, 30, 30, "Above and Left"); |
| test(70, 20, 80, 30, "Above"); |
| test(120, 20, 130, 30, "Above and Right"); |
| test(120, 70, 130, 80, "Right"); |
| test(120, 120, 130, 130, "Below and Right"); |
| test(70, 120, 80, 130, "Below"); |
| test(20, 120, 30, 130, "Below and Left"); |
| test(20, 70, 30, 80, "Left"); |
| |
| test(70, 70, 80, 80, "Inside"); |
| |
| test(40, 70, 60, 80, "Straddling Left"); |
| test(70, 40, 80, 60, "Straddling Top"); |
| test(90, 70, 110, 80, "Straddling Right"); |
| test(70, 90, 80, 110, "Straddling Bottom"); |
| } |
| |
| TEST(RectTest, EmptyIRectDoesNotIntersect) { |
| IRect rect = IRect::MakeLTRB(50, 50, 100, 100); |
| |
| auto test = [&rect](int64_t l, int64_t t, int64_t r, int64_t b, |
| const std::string& label) { |
| EXPECT_FALSE(IRect::MakeLTRB(l, b, r, t).IntersectsWithRect(rect)) |
| << label << " with Top/Bottom swapped"; |
| EXPECT_FALSE(IRect::MakeLTRB(r, b, l, t).IntersectsWithRect(rect)) |
| << label << " with Left/Right swapped"; |
| EXPECT_FALSE(IRect::MakeLTRB(r, t, l, b).IntersectsWithRect(rect)) |
| << label << " with all sides swapped"; |
| }; |
| |
| test(20, 20, 30, 30, "Above and Left"); |
| test(70, 20, 80, 30, "Above"); |
| test(120, 20, 130, 30, "Above and Right"); |
| test(120, 70, 130, 80, "Right"); |
| test(120, 120, 130, 130, "Below and Right"); |
| test(70, 120, 80, 130, "Below"); |
| test(20, 120, 30, 130, "Below and Left"); |
| test(20, 70, 30, 80, "Left"); |
| |
| test(70, 70, 80, 80, "Inside"); |
| |
| test(40, 70, 60, 80, "Straddling Left"); |
| test(70, 40, 80, 60, "Straddling Top"); |
| test(90, 70, 110, 80, "Straddling Right"); |
| test(70, 90, 80, 110, "Straddling Bottom"); |
| } |
| |
| TEST(RectTest, RectScale) { |
| auto test1 = [](Rect rect, Scalar scale) { |
| Rect expected = Rect::MakeXYWH(rect.GetX() * scale, // |
| rect.GetY() * scale, // |
| rect.GetWidth() * scale, // |
| rect.GetHeight() * scale); |
| |
| EXPECT_RECT_NEAR(rect.Scale(scale), expected) // |
| << rect << " * " << scale; |
| EXPECT_RECT_NEAR(rect.Scale(scale, scale), expected) // |
| << rect << " * " << scale; |
| EXPECT_RECT_NEAR(rect.Scale(Point(scale, scale)), expected) // |
| << rect << " * " << scale; |
| EXPECT_RECT_NEAR(rect.Scale(Size(scale, scale)), expected) // |
| << rect << " * " << scale; |
| }; |
| |
| auto test2 = [&test1](Rect rect, Scalar scale_x, Scalar scale_y) { |
| Rect expected = Rect::MakeXYWH(rect.GetX() * scale_x, // |
| rect.GetY() * scale_y, // |
| rect.GetWidth() * scale_x, // |
| rect.GetHeight() * scale_y); |
| |
| EXPECT_RECT_NEAR(rect.Scale(scale_x, scale_y), expected) // |
| << rect << " * " << scale_x << ", " << scale_y; |
| EXPECT_RECT_NEAR(rect.Scale(Point(scale_x, scale_y)), expected) // |
| << rect << " * " << scale_x << ", " << scale_y; |
| EXPECT_RECT_NEAR(rect.Scale(Size(scale_x, scale_y)), expected) // |
| << rect << " * " << scale_x << ", " << scale_y; |
| |
| test1(rect, scale_x); |
| test1(rect, scale_y); |
| }; |
| |
| test2(Rect::MakeLTRB(10, 15, 100, 150), 1.0, 0.0); |
| test2(Rect::MakeLTRB(10, 15, 100, 150), 0.0, 1.0); |
| test2(Rect::MakeLTRB(10, 15, 100, 150), 0.0, 0.0); |
| test2(Rect::MakeLTRB(10, 15, 100, 150), 2.5, 3.5); |
| test2(Rect::MakeLTRB(10, 15, 100, 150), 3.5, 2.5); |
| test2(Rect::MakeLTRB(10, 15, -100, 150), 2.5, 3.5); |
| test2(Rect::MakeLTRB(10, 15, 100, -150), 2.5, 3.5); |
| test2(Rect::MakeLTRB(10, 15, 100, 150), -2.5, 3.5); |
| test2(Rect::MakeLTRB(10, 15, 100, 150), 2.5, -3.5); |
| } |
| |
| TEST(RectTest, IRectScale) { |
| auto test1 = [](IRect rect, int64_t scale) { |
| IRect expected = IRect::MakeXYWH(rect.GetX() * scale, // |
| rect.GetY() * scale, // |
| rect.GetWidth() * scale, // |
| rect.GetHeight() * scale); |
| |
| EXPECT_EQ(rect.Scale(scale), expected) // |
| << rect << " * " << scale; |
| EXPECT_EQ(rect.Scale(scale, scale), expected) // |
| << rect << " * " << scale; |
| EXPECT_EQ(rect.Scale(IPoint(scale, scale)), expected) // |
| << rect << " * " << scale; |
| EXPECT_EQ(rect.Scale(ISize(scale, scale)), expected) // |
| << rect << " * " << scale; |
| }; |
| |
| auto test2 = [&test1](IRect rect, int64_t scale_x, int64_t scale_y) { |
| IRect expected = IRect::MakeXYWH(rect.GetX() * scale_x, // |
| rect.GetY() * scale_y, // |
| rect.GetWidth() * scale_x, // |
| rect.GetHeight() * scale_y); |
| |
| EXPECT_EQ(rect.Scale(scale_x, scale_y), expected) // |
| << rect << " * " << scale_x << ", " << scale_y; |
| EXPECT_EQ(rect.Scale(IPoint(scale_x, scale_y)), expected) // |
| << rect << " * " << scale_x << ", " << scale_y; |
| EXPECT_EQ(rect.Scale(ISize(scale_x, scale_y)), expected) // |
| << rect << " * " << scale_x << ", " << scale_y; |
| |
| test1(rect, scale_x); |
| test1(rect, scale_y); |
| }; |
| |
| test2(IRect::MakeLTRB(10, 15, 100, 150), 2, 3); |
| test2(IRect::MakeLTRB(10, 15, 100, 150), 3, 2); |
| test2(IRect::MakeLTRB(10, 15, -100, 150), 2, 3); |
| test2(IRect::MakeLTRB(10, 15, 100, -150), 2, 3); |
| test2(IRect::MakeLTRB(10, 15, 100, 150), -2, 3); |
| test2(IRect::MakeLTRB(10, 15, 100, 150), 2, -3); |
| } |
| |
| TEST(RectTest, RectArea) { |
| EXPECT_EQ(Rect::MakeXYWH(0, 0, 100, 200).Area(), 20000); |
| EXPECT_EQ(Rect::MakeXYWH(10, 20, 100, 200).Area(), 20000); |
| EXPECT_EQ(Rect::MakeXYWH(0, 0, 200, 100).Area(), 20000); |
| EXPECT_EQ(Rect::MakeXYWH(10, 20, 200, 100).Area(), 20000); |
| EXPECT_EQ(Rect::MakeXYWH(0, 0, 100, 100).Area(), 10000); |
| EXPECT_EQ(Rect::MakeXYWH(10, 20, 100, 100).Area(), 10000); |
| } |
| |
| TEST(RectTest, IRectArea) { |
| EXPECT_EQ(IRect::MakeXYWH(0, 0, 100, 200).Area(), 20000); |
| EXPECT_EQ(IRect::MakeXYWH(10, 20, 100, 200).Area(), 20000); |
| EXPECT_EQ(IRect::MakeXYWH(0, 0, 200, 100).Area(), 20000); |
| EXPECT_EQ(IRect::MakeXYWH(10, 20, 200, 100).Area(), 20000); |
| EXPECT_EQ(IRect::MakeXYWH(0, 0, 100, 100).Area(), 10000); |
| EXPECT_EQ(IRect::MakeXYWH(10, 20, 100, 100).Area(), 10000); |
| } |
| |
| TEST(RectTest, RectGetNormalizingTransform) { |
| { |
| // Checks for expected matrix values |
| |
| auto r = Rect::MakeXYWH(100, 200, 200, 400); |
| |
| EXPECT_EQ(r.GetNormalizingTransform(), |
| Matrix::MakeScale({0.005, 0.0025, 1.0}) * |
| Matrix::MakeTranslation({-100, -200})); |
| } |
| |
| { |
| // Checks for expected transform of points relative to the rect |
| |
| auto r = Rect::MakeLTRB(300, 500, 400, 700); |
| auto m = r.GetNormalizingTransform(); |
| |
| // The 4 corners of the rect => (0, 0) to (1, 1) |
| EXPECT_EQ(m * Point(300, 500), Point(0, 0)); |
| EXPECT_EQ(m * Point(400, 500), Point(1, 0)); |
| EXPECT_EQ(m * Point(400, 700), Point(1, 1)); |
| EXPECT_EQ(m * Point(300, 700), Point(0, 1)); |
| |
| // The center => (0.5, 0.5) |
| EXPECT_EQ(m * Point(350, 600), Point(0.5, 0.5)); |
| |
| // Outside the 4 corners => (-1, -1) to (2, 2) |
| EXPECT_EQ(m * Point(200, 300), Point(-1, -1)); |
| EXPECT_EQ(m * Point(500, 300), Point(2, -1)); |
| EXPECT_EQ(m * Point(500, 900), Point(2, 2)); |
| EXPECT_EQ(m * Point(200, 900), Point(-1, 2)); |
| } |
| |
| { |
| // Checks for behavior with empty rects |
| |
| auto zero = Matrix::MakeScale({0.0, 0.0, 1.0}); |
| |
| // Empty for width and/or height == 0 |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, 0, 10).GetNormalizingTransform(), zero); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, 0).GetNormalizingTransform(), zero); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, 0, 0).GetNormalizingTransform(), zero); |
| |
| // Empty for width and/or height < 0 |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, -1, 10).GetNormalizingTransform(), zero); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, -1).GetNormalizingTransform(), zero); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, -1, -1).GetNormalizingTransform(), zero); |
| } |
| |
| { |
| // Checks for behavior with non-finite rects |
| |
| auto z = Matrix::MakeScale({0.0, 0.0, 1.0}); |
| auto nan = std::numeric_limits<Scalar>::quiet_NaN(); |
| auto inf = std::numeric_limits<Scalar>::infinity(); |
| |
| // Non-finite for width and/or height == nan |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, nan, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, nan).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, nan, nan).GetNormalizingTransform(), z); |
| |
| // Non-finite for width and/or height == inf |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, inf, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, inf).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, inf, inf).GetNormalizingTransform(), z); |
| |
| // Non-finite for width and/or height == -inf |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, -inf, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, 10, -inf).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, 10, -inf, -inf).GetNormalizingTransform(), z); |
| |
| // Non-finite for origin X and/or Y == nan |
| EXPECT_EQ(Rect::MakeXYWH(nan, 10, 10, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, nan, 10, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(nan, nan, 10, 10).GetNormalizingTransform(), z); |
| |
| // Non-finite for origin X and/or Y == inf |
| EXPECT_EQ(Rect::MakeXYWH(inf, 10, 10, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, inf, 10, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(inf, inf, 10, 10).GetNormalizingTransform(), z); |
| |
| // Non-finite for origin X and/or Y == -inf |
| EXPECT_EQ(Rect::MakeXYWH(-inf, 10, 10, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(10, -inf, 10, 10).GetNormalizingTransform(), z); |
| EXPECT_EQ(Rect::MakeXYWH(-inf, -inf, 10, 10).GetNormalizingTransform(), z); |
| } |
| } |
| |
| TEST(RectTest, IRectGetNormalizingTransform) { |
| { |
| // Checks for expected matrix values |
| |
| auto r = IRect::MakeXYWH(100, 200, 200, 400); |
| |
| EXPECT_EQ(r.GetNormalizingTransform(), |
| Matrix::MakeScale({0.005, 0.0025, 1.0}) * |
| Matrix::MakeTranslation({-100, -200})); |
| } |
| |
| { |
| // Checks for expected transform of points relative to the rect |
| |
| auto r = IRect::MakeLTRB(300, 500, 400, 700); |
| auto m = r.GetNormalizingTransform(); |
| |
| // The 4 corners of the rect => (0, 0) to (1, 1) |
| EXPECT_EQ(m * Point(300, 500), Point(0, 0)); |
| EXPECT_EQ(m * Point(400, 500), Point(1, 0)); |
| EXPECT_EQ(m * Point(400, 700), Point(1, 1)); |
| EXPECT_EQ(m * Point(300, 700), Point(0, 1)); |
| |
| // The center => (0.5, 0.5) |
| EXPECT_EQ(m * Point(350, 600), Point(0.5, 0.5)); |
| |
| // Outside the 4 corners => (-1, -1) to (2, 2) |
| EXPECT_EQ(m * Point(200, 300), Point(-1, -1)); |
| EXPECT_EQ(m * Point(500, 300), Point(2, -1)); |
| EXPECT_EQ(m * Point(500, 900), Point(2, 2)); |
| EXPECT_EQ(m * Point(200, 900), Point(-1, 2)); |
| } |
| |
| { |
| // Checks for behavior with empty rects |
| |
| auto zero = Matrix::MakeScale({0.0, 0.0, 1.0}); |
| |
| // Empty for width and/or height == 0 |
| EXPECT_EQ(IRect::MakeXYWH(10, 10, 0, 10).GetNormalizingTransform(), zero); |
| EXPECT_EQ(IRect::MakeXYWH(10, 10, 10, 0).GetNormalizingTransform(), zero); |
| EXPECT_EQ(IRect::MakeXYWH(10, 10, 0, 0).GetNormalizingTransform(), zero); |
| |
| // Empty for width and/or height < 0 |
| EXPECT_EQ(IRect::MakeXYWH(10, 10, -1, 10).GetNormalizingTransform(), zero); |
| EXPECT_EQ(IRect::MakeXYWH(10, 10, 10, -1).GetNormalizingTransform(), zero); |
| EXPECT_EQ(IRect::MakeXYWH(10, 10, -1, -1).GetNormalizingTransform(), zero); |
| } |
| } |
| |
| TEST(RectTest, RectXYWHIsEmpty) { |
| auto nan = std::numeric_limits<Scalar>::quiet_NaN(); |
| |
| // Non-empty |
| EXPECT_FALSE(Rect::MakeXYWH(1.5, 2.3, 10.5, 7.2).IsEmpty()); |
| |
| // Empty both width and height both 0 or negative, in all combinations |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 0.0, 0.0).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, -1.0, -1.0).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 0.0, -1.0).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, -1.0, 0.0).IsEmpty()); |
| |
| // Empty for 0 or negative width or height (but not both at the same time) |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 10.5, 0.0).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 10.5, -1.0).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 0.0, 7.2).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, -1.0, 7.2).IsEmpty()); |
| |
| // Empty for NaN in width or height or both |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, 10.5, nan).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, nan, 7.2).IsEmpty()); |
| EXPECT_TRUE(Rect::MakeXYWH(1.5, 2.3, nan, nan).IsEmpty()); |
| } |
| |
| TEST(RectTest, IRectXYWHIsEmpty) { |
| // Non-empty |
| EXPECT_FALSE(IRect::MakeXYWH(1, 2, 10, 7).IsEmpty()); |
| |
| // Empty both width and height both 0 or negative, in all combinations |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, 0, 0).IsEmpty()); |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, -1, -1).IsEmpty()); |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, -1, 0).IsEmpty()); |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, 0, -1).IsEmpty()); |
| |
| // Empty for 0 or negative width or height (but not both at the same time) |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, 10, 0).IsEmpty()); |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, 10, -1).IsEmpty()); |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, 0, 7).IsEmpty()); |
| EXPECT_TRUE(IRect::MakeXYWH(1, 2, -1, 7).IsEmpty()); |
| } |
| |
| TEST(RectTest, MakePointBoundsQuad) { |
| Quad quad = { |
| Point(10, 10), |
| Point(20, 10), |
| Point(10, 20), |
| Point(20, 20), |
| }; |
| std::optional<Rect> bounds = Rect::MakePointBounds(quad); |
| EXPECT_TRUE(bounds.has_value()); |
| if (bounds.has_value()) { |
| EXPECT_TRUE(RectNear(bounds.value(), Rect::MakeLTRB(10, 10, 20, 20))); |
| } |
| } |
| |
| TEST(RectTest, IsSquare) { |
| EXPECT_TRUE(Rect::MakeXYWH(10, 30, 20, 20).IsSquare()); |
| EXPECT_FALSE(Rect::MakeXYWH(10, 30, 20, 19).IsSquare()); |
| EXPECT_FALSE(Rect::MakeXYWH(10, 30, 19, 20).IsSquare()); |
| EXPECT_TRUE(Rect::MakeMaximum().IsSquare()); |
| |
| EXPECT_TRUE(IRect::MakeXYWH(10, 30, 20, 20).IsSquare()); |
| EXPECT_FALSE(IRect::MakeXYWH(10, 30, 20, 19).IsSquare()); |
| EXPECT_FALSE(IRect::MakeXYWH(10, 30, 19, 20).IsSquare()); |
| EXPECT_TRUE(IRect::MakeMaximum().IsSquare()); |
| } |
| |
| TEST(RectTest, GetCenter) { |
| EXPECT_EQ(Rect::MakeXYWH(10, 30, 20, 20).GetCenter(), Point(20, 40)); |
| EXPECT_EQ(Rect::MakeXYWH(10, 30, 20, 19).GetCenter(), Point(20, 39.5)); |
| EXPECT_EQ(Rect::MakeMaximum().GetCenter(), Point(0, 0)); |
| |
| // Note that we expect a Point as the answer from an IRect |
| EXPECT_EQ(IRect::MakeXYWH(10, 30, 20, 20).GetCenter(), Point(20, 40)); |
| EXPECT_EQ(IRect::MakeXYWH(10, 30, 20, 19).GetCenter(), Point(20, 39.5)); |
| EXPECT_EQ(IRect::MakeMaximum().GetCenter(), Point(0, 0)); |
| } |
| |
| TEST(RectTest, RectExpand) { |
| auto rect = Rect::MakeLTRB(100, 100, 200, 200); |
| |
| // Expand(T amount) |
| EXPECT_EQ(rect.Expand(10), Rect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(-10), Rect::MakeLTRB(110, 110, 190, 190)); |
| |
| // Expand(amount, amount) |
| EXPECT_EQ(rect.Expand(10, 10), Rect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(10, -10), Rect::MakeLTRB(90, 110, 210, 190)); |
| EXPECT_EQ(rect.Expand(-10, 10), Rect::MakeLTRB(110, 90, 190, 210)); |
| EXPECT_EQ(rect.Expand(-10, -10), Rect::MakeLTRB(110, 110, 190, 190)); |
| |
| // Expand(amount, amount, amount, amount) |
| EXPECT_EQ(rect.Expand(10, 20, 30, 40), Rect::MakeLTRB(90, 80, 230, 240)); |
| EXPECT_EQ(rect.Expand(-10, 20, 30, 40), Rect::MakeLTRB(110, 80, 230, 240)); |
| EXPECT_EQ(rect.Expand(10, -20, 30, 40), Rect::MakeLTRB(90, 120, 230, 240)); |
| EXPECT_EQ(rect.Expand(10, 20, -30, 40), Rect::MakeLTRB(90, 80, 170, 240)); |
| EXPECT_EQ(rect.Expand(10, 20, 30, -40), Rect::MakeLTRB(90, 80, 230, 160)); |
| |
| // Expand(Point amount) |
| EXPECT_EQ(rect.Expand(Point{10, 10}), Rect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(Point{10, -10}), Rect::MakeLTRB(90, 110, 210, 190)); |
| EXPECT_EQ(rect.Expand(Point{-10, 10}), Rect::MakeLTRB(110, 90, 190, 210)); |
| EXPECT_EQ(rect.Expand(Point{-10, -10}), Rect::MakeLTRB(110, 110, 190, 190)); |
| |
| // Expand(Size amount) |
| EXPECT_EQ(rect.Expand(Size{10, 10}), Rect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(Size{10, -10}), Rect::MakeLTRB(90, 110, 210, 190)); |
| EXPECT_EQ(rect.Expand(Size{-10, 10}), Rect::MakeLTRB(110, 90, 190, 210)); |
| EXPECT_EQ(rect.Expand(Size{-10, -10}), Rect::MakeLTRB(110, 110, 190, 190)); |
| } |
| |
| TEST(RectTest, IRectExpand) { |
| auto rect = IRect::MakeLTRB(100, 100, 200, 200); |
| |
| // Expand(T amount) |
| EXPECT_EQ(rect.Expand(10), IRect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(-10), IRect::MakeLTRB(110, 110, 190, 190)); |
| |
| // Expand(amount, amount) |
| EXPECT_EQ(rect.Expand(10, 10), IRect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(10, -10), IRect::MakeLTRB(90, 110, 210, 190)); |
| EXPECT_EQ(rect.Expand(-10, 10), IRect::MakeLTRB(110, 90, 190, 210)); |
| EXPECT_EQ(rect.Expand(-10, -10), IRect::MakeLTRB(110, 110, 190, 190)); |
| |
| // Expand(amount, amount, amount, amount) |
| EXPECT_EQ(rect.Expand(10, 20, 30, 40), IRect::MakeLTRB(90, 80, 230, 240)); |
| EXPECT_EQ(rect.Expand(-10, 20, 30, 40), IRect::MakeLTRB(110, 80, 230, 240)); |
| EXPECT_EQ(rect.Expand(10, -20, 30, 40), IRect::MakeLTRB(90, 120, 230, 240)); |
| EXPECT_EQ(rect.Expand(10, 20, -30, 40), IRect::MakeLTRB(90, 80, 170, 240)); |
| EXPECT_EQ(rect.Expand(10, 20, 30, -40), IRect::MakeLTRB(90, 80, 230, 160)); |
| |
| // Expand(IPoint amount) |
| EXPECT_EQ(rect.Expand(IPoint{10, 10}), IRect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(IPoint{10, -10}), IRect::MakeLTRB(90, 110, 210, 190)); |
| EXPECT_EQ(rect.Expand(IPoint{-10, 10}), IRect::MakeLTRB(110, 90, 190, 210)); |
| EXPECT_EQ(rect.Expand(IPoint{-10, -10}), IRect::MakeLTRB(110, 110, 190, 190)); |
| |
| // Expand(ISize amount) |
| EXPECT_EQ(rect.Expand(ISize{10, 10}), IRect::MakeLTRB(90, 90, 210, 210)); |
| EXPECT_EQ(rect.Expand(ISize{10, -10}), IRect::MakeLTRB(90, 110, 210, 190)); |
| EXPECT_EQ(rect.Expand(ISize{-10, 10}), IRect::MakeLTRB(110, 90, 190, 210)); |
| EXPECT_EQ(rect.Expand(ISize{-10, -10}), IRect::MakeLTRB(110, 110, 190, 190)); |
| } |
| |
| TEST(RectTest, ContainsFloatingPoint) { |
| auto rect1 = |
| Rect::MakeXYWH(472.599945f, 440.999969f, 1102.80005f, 654.000061f); |
| auto rect2 = Rect::MakeXYWH(724.f, 618.f, 600.f, 300.f); |
| EXPECT_TRUE(rect1.Contains(rect2)); |
| } |
| |
| template <typename R> |
| static constexpr inline R flip_lr(R rect) { |
| return R::MakeLTRB(rect.GetRight(), rect.GetTop(), // |
| rect.GetLeft(), rect.GetBottom()); |
| } |
| |
| template <typename R> |
| static constexpr inline R flip_tb(R rect) { |
| return R::MakeLTRB(rect.GetLeft(), rect.GetBottom(), // |
| rect.GetRight(), rect.GetTop()); |
| } |
| |
| template <typename R> |
| static constexpr inline R flip_lrtb(R rect) { |
| return flip_lr(flip_tb(rect)); |
| } |
| |
| static constexpr inline Rect swap_nan(const Rect& rect, int index) { |
| Scalar nan = std::numeric_limits<Scalar>::quiet_NaN(); |
| FML_DCHECK(index >= 0 && index <= 15); |
| Scalar l = ((index & (1 << 0)) != 0) ? nan : rect.GetLeft(); |
| Scalar t = ((index & (1 << 1)) != 0) ? nan : rect.GetTop(); |
| Scalar r = ((index & (1 << 2)) != 0) ? nan : rect.GetRight(); |
| Scalar b = ((index & (1 << 3)) != 0) ? nan : rect.GetBottom(); |
| return Rect::MakeLTRB(l, t, r, b); |
| } |
| |
| static constexpr inline Point swap_nan(const Point& point, int index) { |
| Scalar nan = std::numeric_limits<Scalar>::quiet_NaN(); |
| FML_DCHECK(index >= 0 && index <= 3); |
| Scalar x = ((index & (1 << 0)) != 0) ? nan : point.x; |
| Scalar y = ((index & (1 << 1)) != 0) ? nan : point.y; |
| return Point(x, y); |
| } |
| |
| TEST(RectTest, RectUnion) { |
| auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) { |
| ASSERT_TRUE(a.IsFinite()) << label; |
| ASSERT_TRUE(b.IsFinite()) << label; |
| ASSERT_FALSE(a.Union(b).IsEmpty()); |
| |
| for (int i = 1; i < 16; i++) { |
| // NaN in a produces b |
| EXPECT_EQ(swap_nan(a, i).Union(b), b) << label << ", index = " << i; |
| // NaN in b produces a |
| EXPECT_EQ(a.Union(swap_nan(b, i)), a) << label << ", index = " << i; |
| // NaN in both is empty |
| for (int j = 1; j < 16; j++) { |
| EXPECT_TRUE(swap_nan(a, i).Union(swap_nan(b, j)).IsEmpty()) |
| << label << ", indices = " << i << ", " << j; |
| } |
| } |
| }; |
| |
| auto check_empty_flips = [](const Rect& a, const Rect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // b is allowed to be empty |
| |
| // unflipped a vs flipped (empty) b yields a |
| EXPECT_EQ(a.Union(flip_lr(b)), a) << label; |
| EXPECT_EQ(a.Union(flip_tb(b)), a) << label; |
| EXPECT_EQ(a.Union(flip_lrtb(b)), a) << label; |
| |
| // flipped (empty) a vs unflipped b yields b |
| EXPECT_EQ(flip_lr(a).Union(b), b) << label; |
| EXPECT_EQ(flip_tb(a).Union(b), b) << label; |
| EXPECT_EQ(flip_lrtb(a).Union(b), b) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_TRUE(flip_lr(a).Union(flip_lr(b)).IsEmpty()) << label; |
| EXPECT_TRUE(flip_tb(a).Union(flip_tb(b)).IsEmpty()) << label; |
| EXPECT_TRUE(flip_lrtb(a).Union(flip_lrtb(b)).IsEmpty()) << label; |
| }; |
| |
| auto test = [&check_nans, &check_empty_flips](const Rect& a, const Rect& b, |
| const Rect& result) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_EQ(a.Union(b), result) << label; |
| EXPECT_EQ(b.Union(a), result) << label; |
| check_empty_flips(a, b, label); |
| check_nans(a, b, label); |
| }; |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(0, 0, 0, 0); |
| auto expected = Rect::MakeXYWH(100, 100, 100, 100); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(0, 0, 1, 1); |
| auto expected = Rect::MakeXYWH(0, 0, 200, 200); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(10, 10, 1, 1); |
| auto expected = Rect::MakeXYWH(10, 10, 190, 190); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(0, 0, 100, 100); |
| auto b = Rect::MakeXYWH(10, 10, 100, 100); |
| auto expected = Rect::MakeXYWH(0, 0, 110, 110); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(0, 0, 100, 100); |
| auto b = Rect::MakeXYWH(100, 100, 100, 100); |
| auto expected = Rect::MakeXYWH(0, 0, 200, 200); |
| test(a, b, expected); |
| } |
| } |
| |
| TEST(RectTest, OptRectUnion) { |
| auto a = Rect::MakeLTRB(0, 0, 100, 100); |
| auto b = Rect::MakeLTRB(100, 100, 200, 200); |
| auto c = Rect::MakeLTRB(100, 0, 200, 100); |
| |
| // NullOpt, NullOpt |
| EXPECT_FALSE(Rect::Union(std::nullopt, std::nullopt).has_value()); |
| EXPECT_EQ(Rect::Union(std::nullopt, std::nullopt), std::nullopt); |
| |
| auto test1 = [](const Rect& r) { |
| // Rect, NullOpt |
| EXPECT_TRUE(Rect::Union(r, std::nullopt).has_value()); |
| EXPECT_EQ(Rect::Union(r, std::nullopt).value(), r); |
| |
| // OptRect, NullOpt |
| EXPECT_TRUE(Rect::Union(std::optional(r), std::nullopt).has_value()); |
| EXPECT_EQ(Rect::Union(std::optional(r), std::nullopt).value(), r); |
| |
| // NullOpt, Rect |
| EXPECT_TRUE(Rect::Union(std::nullopt, r).has_value()); |
| EXPECT_EQ(Rect::Union(std::nullopt, r).value(), r); |
| |
| // NullOpt, OptRect |
| EXPECT_TRUE(Rect::Union(std::nullopt, std::optional(r)).has_value()); |
| EXPECT_EQ(Rect::Union(std::nullopt, std::optional(r)).value(), r); |
| }; |
| |
| test1(a); |
| test1(b); |
| test1(c); |
| |
| auto test2 = [](const Rect& a, const Rect& b, const Rect& u) { |
| ASSERT_EQ(a.Union(b), u); |
| |
| // Rect, OptRect |
| EXPECT_TRUE(Rect::Union(a, std::optional(b)).has_value()); |
| EXPECT_EQ(Rect::Union(a, std::optional(b)).value(), u); |
| |
| // OptRect, Rect |
| EXPECT_TRUE(Rect::Union(std::optional(a), b).has_value()); |
| EXPECT_EQ(Rect::Union(std::optional(a), b).value(), u); |
| |
| // OptRect, OptRect |
| EXPECT_TRUE(Rect::Union(std::optional(a), std::optional(b)).has_value()); |
| EXPECT_EQ(Rect::Union(std::optional(a), std::optional(b)).value(), u); |
| }; |
| |
| test2(a, b, Rect::MakeLTRB(0, 0, 200, 200)); |
| test2(a, c, Rect::MakeLTRB(0, 0, 200, 100)); |
| test2(b, c, Rect::MakeLTRB(100, 0, 200, 200)); |
| } |
| |
| TEST(RectTest, IRectUnion) { |
| auto check_empty_flips = [](const IRect& a, const IRect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // b is allowed to be empty |
| |
| // unflipped a vs flipped (empty) b yields a |
| EXPECT_EQ(a.Union(flip_lr(b)), a) << label; |
| EXPECT_EQ(a.Union(flip_tb(b)), a) << label; |
| EXPECT_EQ(a.Union(flip_lrtb(b)), a) << label; |
| |
| // flipped (empty) a vs unflipped b yields b |
| EXPECT_EQ(flip_lr(a).Union(b), b) << label; |
| EXPECT_EQ(flip_tb(a).Union(b), b) << label; |
| EXPECT_EQ(flip_lrtb(a).Union(b), b) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_TRUE(flip_lr(a).Union(flip_lr(b)).IsEmpty()) << label; |
| EXPECT_TRUE(flip_tb(a).Union(flip_tb(b)).IsEmpty()) << label; |
| EXPECT_TRUE(flip_lrtb(a).Union(flip_lrtb(b)).IsEmpty()) << label; |
| }; |
| |
| auto test = [&check_empty_flips](const IRect& a, const IRect& b, |
| const IRect& result) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_EQ(a.Union(b), result) << label; |
| EXPECT_EQ(b.Union(a), result) << label; |
| check_empty_flips(a, b, label); |
| }; |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(0, 0, 0, 0); |
| auto expected = IRect::MakeXYWH(100, 100, 100, 100); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(0, 0, 1, 1); |
| auto expected = IRect::MakeXYWH(0, 0, 200, 200); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(10, 10, 1, 1); |
| auto expected = IRect::MakeXYWH(10, 10, 190, 190); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(0, 0, 100, 100); |
| auto b = IRect::MakeXYWH(10, 10, 100, 100); |
| auto expected = IRect::MakeXYWH(0, 0, 110, 110); |
| test(a, b, expected); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(0, 0, 100, 100); |
| auto b = IRect::MakeXYWH(100, 100, 100, 100); |
| auto expected = IRect::MakeXYWH(0, 0, 200, 200); |
| test(a, b, expected); |
| } |
| } |
| |
| TEST(RectTest, OptIRectUnion) { |
| auto a = IRect::MakeLTRB(0, 0, 100, 100); |
| auto b = IRect::MakeLTRB(100, 100, 200, 200); |
| auto c = IRect::MakeLTRB(100, 0, 200, 100); |
| |
| // NullOpt, NullOpt |
| EXPECT_FALSE(IRect::Union(std::nullopt, std::nullopt).has_value()); |
| EXPECT_EQ(IRect::Union(std::nullopt, std::nullopt), std::nullopt); |
| |
| auto test1 = [](const IRect& r) { |
| // Rect, NullOpt |
| EXPECT_TRUE(IRect::Union(r, std::nullopt).has_value()); |
| EXPECT_EQ(IRect::Union(r, std::nullopt).value(), r); |
| |
| // OptRect, NullOpt |
| EXPECT_TRUE(IRect::Union(std::optional(r), std::nullopt).has_value()); |
| EXPECT_EQ(IRect::Union(std::optional(r), std::nullopt).value(), r); |
| |
| // NullOpt, Rect |
| EXPECT_TRUE(IRect::Union(std::nullopt, r).has_value()); |
| EXPECT_EQ(IRect::Union(std::nullopt, r).value(), r); |
| |
| // NullOpt, OptRect |
| EXPECT_TRUE(IRect::Union(std::nullopt, std::optional(r)).has_value()); |
| EXPECT_EQ(IRect::Union(std::nullopt, std::optional(r)).value(), r); |
| }; |
| |
| test1(a); |
| test1(b); |
| test1(c); |
| |
| auto test2 = [](const IRect& a, const IRect& b, const IRect& u) { |
| ASSERT_EQ(a.Union(b), u); |
| |
| // Rect, OptRect |
| EXPECT_TRUE(IRect::Union(a, std::optional(b)).has_value()); |
| EXPECT_EQ(IRect::Union(a, std::optional(b)).value(), u); |
| |
| // OptRect, Rect |
| EXPECT_TRUE(IRect::Union(std::optional(a), b).has_value()); |
| EXPECT_EQ(IRect::Union(std::optional(a), b).value(), u); |
| |
| // OptRect, OptRect |
| EXPECT_TRUE(IRect::Union(std::optional(a), std::optional(b)).has_value()); |
| EXPECT_EQ(IRect::Union(std::optional(a), std::optional(b)).value(), u); |
| }; |
| |
| test2(a, b, IRect::MakeLTRB(0, 0, 200, 200)); |
| test2(a, c, IRect::MakeLTRB(0, 0, 200, 100)); |
| test2(b, c, IRect::MakeLTRB(100, 0, 200, 200)); |
| } |
| |
| TEST(RectTest, RectIntersection) { |
| auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) { |
| ASSERT_TRUE(a.IsFinite()) << label; |
| ASSERT_TRUE(b.IsFinite()) << label; |
| |
| for (int i = 1; i < 16; i++) { |
| // NaN in a produces empty |
| EXPECT_FALSE(swap_nan(a, i).Intersection(b).has_value()) |
| << label << ", index = " << i; |
| // NaN in b produces empty |
| EXPECT_FALSE(a.Intersection(swap_nan(b, i)).has_value()) |
| << label << ", index = " << i; |
| // NaN in both is empty |
| for (int j = 1; j < 16; j++) { |
| EXPECT_FALSE(swap_nan(a, i).Intersection(swap_nan(b, j)).has_value()) |
| << label << ", indices = " << i << ", " << j; |
| } |
| } |
| }; |
| |
| auto check_empty_flips = [](const Rect& a, const Rect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // b is allowed to be empty |
| |
| // unflipped a vs flipped (empty) b yields a |
| EXPECT_FALSE(a.Intersection(flip_lr(b)).has_value()) << label; |
| EXPECT_FALSE(a.Intersection(flip_tb(b)).has_value()) << label; |
| EXPECT_FALSE(a.Intersection(flip_lrtb(b)).has_value()) << label; |
| |
| // flipped (empty) a vs unflipped b yields b |
| EXPECT_FALSE(flip_lr(a).Intersection(b).has_value()) << label; |
| EXPECT_FALSE(flip_tb(a).Intersection(b).has_value()) << label; |
| EXPECT_FALSE(flip_lrtb(a).Intersection(b).has_value()) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_FALSE(flip_lr(a).Intersection(flip_lr(b)).has_value()) << label; |
| EXPECT_FALSE(flip_tb(a).Intersection(flip_tb(b)).has_value()) << label; |
| EXPECT_FALSE(flip_lrtb(a).Intersection(flip_lrtb(b)).has_value()) << label; |
| }; |
| |
| auto test_non_empty = [&check_nans, &check_empty_flips]( |
| const Rect& a, const Rect& b, const Rect& result) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(a.Intersection(b).has_value()) << label; |
| EXPECT_TRUE(b.Intersection(a).has_value()) << label; |
| EXPECT_EQ(a.Intersection(b), result) << label; |
| EXPECT_EQ(b.Intersection(a), result) << label; |
| check_empty_flips(a, b, label); |
| check_nans(a, b, label); |
| }; |
| |
| auto test_empty = [&check_nans, &check_empty_flips](const Rect& a, |
| const Rect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(a.Intersection(b).has_value()) << label; |
| EXPECT_FALSE(b.Intersection(a).has_value()) << label; |
| check_empty_flips(a, b, label); |
| check_nans(a, b, label); |
| }; |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(0, 0, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(10, 10, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(0, 0, 100, 100); |
| auto b = Rect::MakeXYWH(10, 10, 100, 100); |
| auto expected = Rect::MakeXYWH(10, 10, 90, 90); |
| |
| test_non_empty(a, b, expected); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(0, 0, 100, 100); |
| auto b = Rect::MakeXYWH(100, 100, 100, 100); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeMaximum(); |
| auto b = Rect::MakeXYWH(10, 10, 300, 300); |
| |
| test_non_empty(a, b, b); |
| } |
| |
| { |
| auto a = Rect::MakeMaximum(); |
| auto b = Rect::MakeMaximum(); |
| |
| test_non_empty(a, b, Rect::MakeMaximum()); |
| } |
| } |
| |
| TEST(RectTest, OptRectIntersection) { |
| auto a = Rect::MakeLTRB(0, 0, 110, 110); |
| auto b = Rect::MakeLTRB(100, 100, 200, 200); |
| auto c = Rect::MakeLTRB(100, 0, 200, 110); |
| |
| // NullOpt, NullOpt |
| EXPECT_FALSE(Rect::Intersection(std::nullopt, std::nullopt).has_value()); |
| EXPECT_EQ(Rect::Intersection(std::nullopt, std::nullopt), std::nullopt); |
| |
| auto test1 = [](const Rect& r) { |
| // Rect, NullOpt |
| EXPECT_TRUE(Rect::Intersection(r, std::nullopt).has_value()); |
| EXPECT_EQ(Rect::Intersection(r, std::nullopt).value(), r); |
| |
| // OptRect, NullOpt |
| EXPECT_TRUE(Rect::Intersection(std::optional(r), std::nullopt).has_value()); |
| EXPECT_EQ(Rect::Intersection(std::optional(r), std::nullopt).value(), r); |
| |
| // NullOpt, Rect |
| EXPECT_TRUE(Rect::Intersection(std::nullopt, r).has_value()); |
| EXPECT_EQ(Rect::Intersection(std::nullopt, r).value(), r); |
| |
| // NullOpt, OptRect |
| EXPECT_TRUE(Rect::Intersection(std::nullopt, std::optional(r)).has_value()); |
| EXPECT_EQ(Rect::Intersection(std::nullopt, std::optional(r)).value(), r); |
| }; |
| |
| test1(a); |
| test1(b); |
| test1(c); |
| |
| auto test2 = [](const Rect& a, const Rect& b, const Rect& i) { |
| ASSERT_EQ(a.Intersection(b), i); |
| |
| // Rect, OptRect |
| EXPECT_TRUE(Rect::Intersection(a, std::optional(b)).has_value()); |
| EXPECT_EQ(Rect::Intersection(a, std::optional(b)).value(), i); |
| |
| // OptRect, Rect |
| EXPECT_TRUE(Rect::Intersection(std::optional(a), b).has_value()); |
| EXPECT_EQ(Rect::Intersection(std::optional(a), b).value(), i); |
| |
| // OptRect, OptRect |
| EXPECT_TRUE( |
| Rect::Intersection(std::optional(a), std::optional(b)).has_value()); |
| EXPECT_EQ(Rect::Intersection(std::optional(a), std::optional(b)).value(), |
| i); |
| }; |
| |
| test2(a, b, Rect::MakeLTRB(100, 100, 110, 110)); |
| test2(a, c, Rect::MakeLTRB(100, 0, 110, 110)); |
| test2(b, c, Rect::MakeLTRB(100, 100, 200, 110)); |
| } |
| |
| TEST(RectTest, IRectIntersection) { |
| auto check_empty_flips = [](const IRect& a, const IRect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // b is allowed to be empty |
| |
| // unflipped a vs flipped (empty) b yields a |
| EXPECT_FALSE(a.Intersection(flip_lr(b)).has_value()) << label; |
| EXPECT_FALSE(a.Intersection(flip_tb(b)).has_value()) << label; |
| EXPECT_FALSE(a.Intersection(flip_lrtb(b)).has_value()) << label; |
| |
| // flipped (empty) a vs unflipped b yields b |
| EXPECT_FALSE(flip_lr(a).Intersection(b).has_value()) << label; |
| EXPECT_FALSE(flip_tb(a).Intersection(b).has_value()) << label; |
| EXPECT_FALSE(flip_lrtb(a).Intersection(b).has_value()) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_FALSE(flip_lr(a).Intersection(flip_lr(b)).has_value()) << label; |
| EXPECT_FALSE(flip_tb(a).Intersection(flip_tb(b)).has_value()) << label; |
| EXPECT_FALSE(flip_lrtb(a).Intersection(flip_lrtb(b)).has_value()) << label; |
| }; |
| |
| auto test_non_empty = [&check_empty_flips](const IRect& a, const IRect& b, |
| const IRect& result) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(a.Intersection(b).has_value()) << label; |
| EXPECT_TRUE(b.Intersection(a).has_value()) << label; |
| EXPECT_EQ(a.Intersection(b), result) << label; |
| EXPECT_EQ(b.Intersection(a), result) << label; |
| check_empty_flips(a, b, label); |
| }; |
| |
| auto test_empty = [&check_empty_flips](const IRect& a, const IRect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(a.Intersection(b).has_value()) << label; |
| EXPECT_FALSE(b.Intersection(a).has_value()) << label; |
| check_empty_flips(a, b, label); |
| }; |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(0, 0, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(10, 10, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(0, 0, 100, 100); |
| auto b = IRect::MakeXYWH(10, 10, 100, 100); |
| auto expected = IRect::MakeXYWH(10, 10, 90, 90); |
| |
| test_non_empty(a, b, expected); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(0, 0, 100, 100); |
| auto b = IRect::MakeXYWH(100, 100, 100, 100); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeMaximum(); |
| auto b = IRect::MakeXYWH(10, 10, 300, 300); |
| |
| test_non_empty(a, b, b); |
| } |
| |
| { |
| auto a = IRect::MakeMaximum(); |
| auto b = IRect::MakeMaximum(); |
| |
| test_non_empty(a, b, IRect::MakeMaximum()); |
| } |
| } |
| |
| TEST(RectTest, OptIRectIntersection) { |
| auto a = IRect::MakeLTRB(0, 0, 110, 110); |
| auto b = IRect::MakeLTRB(100, 100, 200, 200); |
| auto c = IRect::MakeLTRB(100, 0, 200, 110); |
| |
| // NullOpt, NullOpt |
| EXPECT_FALSE(IRect::Intersection(std::nullopt, std::nullopt).has_value()); |
| EXPECT_EQ(IRect::Intersection(std::nullopt, std::nullopt), std::nullopt); |
| |
| auto test1 = [](const IRect& r) { |
| // Rect, NullOpt |
| EXPECT_TRUE(IRect::Intersection(r, std::nullopt).has_value()); |
| EXPECT_EQ(IRect::Intersection(r, std::nullopt).value(), r); |
| |
| // OptRect, NullOpt |
| EXPECT_TRUE( |
| IRect::Intersection(std::optional(r), std::nullopt).has_value()); |
| EXPECT_EQ(IRect::Intersection(std::optional(r), std::nullopt).value(), r); |
| |
| // NullOpt, Rect |
| EXPECT_TRUE(IRect::Intersection(std::nullopt, r).has_value()); |
| EXPECT_EQ(IRect::Intersection(std::nullopt, r).value(), r); |
| |
| // NullOpt, OptRect |
| EXPECT_TRUE( |
| IRect::Intersection(std::nullopt, std::optional(r)).has_value()); |
| EXPECT_EQ(IRect::Intersection(std::nullopt, std::optional(r)).value(), r); |
| }; |
| |
| test1(a); |
| test1(b); |
| test1(c); |
| |
| auto test2 = [](const IRect& a, const IRect& b, const IRect& i) { |
| ASSERT_EQ(a.Intersection(b), i); |
| |
| // Rect, OptRect |
| EXPECT_TRUE(IRect::Intersection(a, std::optional(b)).has_value()); |
| EXPECT_EQ(IRect::Intersection(a, std::optional(b)).value(), i); |
| |
| // OptRect, Rect |
| EXPECT_TRUE(IRect::Intersection(std::optional(a), b).has_value()); |
| EXPECT_EQ(IRect::Intersection(std::optional(a), b).value(), i); |
| |
| // OptRect, OptRect |
| EXPECT_TRUE( |
| IRect::Intersection(std::optional(a), std::optional(b)).has_value()); |
| EXPECT_EQ(IRect::Intersection(std::optional(a), std::optional(b)).value(), |
| i); |
| }; |
| |
| test2(a, b, IRect::MakeLTRB(100, 100, 110, 110)); |
| test2(a, c, IRect::MakeLTRB(100, 0, 110, 110)); |
| test2(b, c, IRect::MakeLTRB(100, 100, 200, 110)); |
| } |
| |
| TEST(RectTest, RectIntersectsWithRect) { |
| auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) { |
| ASSERT_TRUE(a.IsFinite()) << label; |
| ASSERT_TRUE(b.IsFinite()) << label; |
| |
| for (int i = 1; i < 16; i++) { |
| // NaN in a produces b |
| EXPECT_FALSE(swap_nan(a, i).IntersectsWithRect(b)) |
| << label << ", index = " << i; |
| // NaN in b produces a |
| EXPECT_FALSE(a.IntersectsWithRect(swap_nan(b, i))) |
| << label << ", index = " << i; |
| // NaN in both is empty |
| for (int j = 1; j < 16; j++) { |
| EXPECT_FALSE(swap_nan(a, i).IntersectsWithRect(swap_nan(b, j))) |
| << label << ", indices = " << i << ", " << j; |
| } |
| } |
| }; |
| |
| auto check_empty_flips = [](const Rect& a, const Rect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // b is allowed to be empty |
| |
| // unflipped a vs flipped (empty) b yields a |
| EXPECT_FALSE(a.IntersectsWithRect(flip_lr(b))) << label; |
| EXPECT_FALSE(a.IntersectsWithRect(flip_tb(b))) << label; |
| EXPECT_FALSE(a.IntersectsWithRect(flip_lrtb(b))) << label; |
| |
| // flipped (empty) a vs unflipped b yields b |
| EXPECT_FALSE(flip_lr(a).IntersectsWithRect(b)) << label; |
| EXPECT_FALSE(flip_tb(a).IntersectsWithRect(b)) << label; |
| EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(b)) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_FALSE(flip_lr(a).IntersectsWithRect(flip_lr(b))) << label; |
| EXPECT_FALSE(flip_tb(a).IntersectsWithRect(flip_tb(b))) << label; |
| EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(flip_lrtb(b))) << label; |
| }; |
| |
| auto test_non_empty = [&check_nans, &check_empty_flips](const Rect& a, |
| const Rect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(a.IntersectsWithRect(b)) << label; |
| EXPECT_TRUE(b.IntersectsWithRect(a)) << label; |
| check_empty_flips(a, b, label); |
| check_nans(a, b, label); |
| }; |
| |
| auto test_empty = [&check_nans, &check_empty_flips](const Rect& a, |
| const Rect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(a.IntersectsWithRect(b)) << label; |
| EXPECT_FALSE(b.IntersectsWithRect(a)) << label; |
| check_empty_flips(a, b, label); |
| check_nans(a, b, label); |
| }; |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(0, 0, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(10, 10, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(0, 0, 100, 100); |
| auto b = Rect::MakeXYWH(10, 10, 100, 100); |
| |
| test_non_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeXYWH(0, 0, 100, 100); |
| auto b = Rect::MakeXYWH(100, 100, 100, 100); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeMaximum(); |
| auto b = Rect::MakeXYWH(10, 10, 100, 100); |
| |
| test_non_empty(a, b); |
| } |
| |
| { |
| auto a = Rect::MakeMaximum(); |
| auto b = Rect::MakeMaximum(); |
| |
| test_non_empty(a, b); |
| } |
| } |
| |
| TEST(RectTest, IRectIntersectsWithRect) { |
| auto check_empty_flips = [](const IRect& a, const IRect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // b is allowed to be empty |
| |
| // unflipped a vs flipped (empty) b yields a |
| EXPECT_FALSE(a.IntersectsWithRect(flip_lr(b))) << label; |
| EXPECT_FALSE(a.IntersectsWithRect(flip_tb(b))) << label; |
| EXPECT_FALSE(a.IntersectsWithRect(flip_lrtb(b))) << label; |
| |
| // flipped (empty) a vs unflipped b yields b |
| EXPECT_FALSE(flip_lr(a).IntersectsWithRect(b)) << label; |
| EXPECT_FALSE(flip_tb(a).IntersectsWithRect(b)) << label; |
| EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(b)) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_FALSE(flip_lr(a).IntersectsWithRect(flip_lr(b))) << label; |
| EXPECT_FALSE(flip_tb(a).IntersectsWithRect(flip_tb(b))) << label; |
| EXPECT_FALSE(flip_lrtb(a).IntersectsWithRect(flip_lrtb(b))) << label; |
| }; |
| |
| auto test_non_empty = [&check_empty_flips](const IRect& a, const IRect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(a.IntersectsWithRect(b)) << label; |
| EXPECT_TRUE(b.IntersectsWithRect(a)) << label; |
| check_empty_flips(a, b, label); |
| }; |
| |
| auto test_empty = [&check_empty_flips](const IRect& a, const IRect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // b is allowed to be empty |
| |
| std::stringstream stream; |
| stream << a << " union " << b; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(a.IntersectsWithRect(b)) << label; |
| EXPECT_FALSE(b.IntersectsWithRect(a)) << label; |
| check_empty_flips(a, b, label); |
| }; |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(0, 0, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(10, 10, 0, 0); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(0, 0, 100, 100); |
| auto b = IRect::MakeXYWH(10, 10, 100, 100); |
| |
| test_non_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeXYWH(0, 0, 100, 100); |
| auto b = IRect::MakeXYWH(100, 100, 100, 100); |
| |
| test_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeMaximum(); |
| auto b = IRect::MakeXYWH(10, 10, 100, 100); |
| |
| test_non_empty(a, b); |
| } |
| |
| { |
| auto a = IRect::MakeMaximum(); |
| auto b = IRect::MakeMaximum(); |
| |
| test_non_empty(a, b); |
| } |
| } |
| |
| TEST(RectTest, RectContainsPoint) { |
| auto check_nans = [](const Rect& rect, const Point& point, |
| const std::string& label) { |
| ASSERT_TRUE(rect.IsFinite()) << label; |
| ASSERT_TRUE(point.IsFinite()) << label; |
| |
| for (int i = 1; i < 16; i++) { |
| EXPECT_FALSE(swap_nan(rect, i).Contains(point)) |
| << label << ", index = " << i; |
| for (int j = 1; j < 4; j++) { |
| EXPECT_FALSE(swap_nan(rect, i).Contains(swap_nan(point, j))) |
| << label << ", indices = " << i << ", " << j; |
| } |
| } |
| }; |
| |
| auto check_empty_flips = [](const Rect& rect, const Point& point, |
| const std::string& label) { |
| ASSERT_FALSE(rect.IsEmpty()); |
| |
| EXPECT_FALSE(flip_lr(rect).Contains(point)) << label; |
| EXPECT_FALSE(flip_tb(rect).Contains(point)) << label; |
| EXPECT_FALSE(flip_lrtb(rect).Contains(point)) << label; |
| }; |
| |
| auto test_inside = [&check_nans, &check_empty_flips](const Rect& rect, |
| const Point& point) { |
| ASSERT_FALSE(rect.IsEmpty()) << rect; |
| |
| std::stringstream stream; |
| stream << rect << " contains " << point; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(rect.Contains(point)) << label; |
| check_empty_flips(rect, point, label); |
| check_nans(rect, point, label); |
| }; |
| |
| auto test_outside = [&check_nans, &check_empty_flips](const Rect& rect, |
| const Point& point) { |
| ASSERT_FALSE(rect.IsEmpty()) << rect; |
| |
| std::stringstream stream; |
| stream << rect << " contains " << point; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(rect.Contains(point)) << label; |
| check_empty_flips(rect, point, label); |
| check_nans(rect, point, label); |
| }; |
| |
| { |
| // Origin is inclusive |
| auto r = Rect::MakeXYWH(100, 100, 100, 100); |
| auto p = Point(100, 100); |
| |
| test_inside(r, p); |
| } |
| { |
| // Size is exclusive |
| auto r = Rect::MakeXYWH(100, 100, 100, 100); |
| auto p = Point(200, 200); |
| |
| test_outside(r, p); |
| } |
| { |
| auto r = Rect::MakeXYWH(100, 100, 100, 100); |
| auto p = Point(99, 99); |
| |
| test_outside(r, p); |
| } |
| { |
| auto r = Rect::MakeXYWH(100, 100, 100, 100); |
| auto p = Point(199, 199); |
| |
| test_inside(r, p); |
| } |
| |
| { |
| auto r = Rect::MakeMaximum(); |
| auto p = Point(199, 199); |
| |
| test_inside(r, p); |
| } |
| } |
| |
| TEST(RectTest, IRectContainsIPoint) { |
| auto check_empty_flips = [](const IRect& rect, const IPoint& point, |
| const std::string& label) { |
| ASSERT_FALSE(rect.IsEmpty()); |
| |
| EXPECT_FALSE(flip_lr(rect).Contains(point)) << label; |
| EXPECT_FALSE(flip_tb(rect).Contains(point)) << label; |
| EXPECT_FALSE(flip_lrtb(rect).Contains(point)) << label; |
| }; |
| |
| auto test_inside = [&check_empty_flips](const IRect& rect, |
| const IPoint& point) { |
| ASSERT_FALSE(rect.IsEmpty()) << rect; |
| |
| std::stringstream stream; |
| stream << rect << " contains " << point; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(rect.Contains(point)) << label; |
| check_empty_flips(rect, point, label); |
| }; |
| |
| auto test_outside = [&check_empty_flips](const IRect& rect, |
| const IPoint& point) { |
| ASSERT_FALSE(rect.IsEmpty()) << rect; |
| |
| std::stringstream stream; |
| stream << rect << " contains " << point; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(rect.Contains(point)) << label; |
| check_empty_flips(rect, point, label); |
| }; |
| |
| { |
| // Origin is inclusive |
| auto r = IRect::MakeXYWH(100, 100, 100, 100); |
| auto p = IPoint(100, 100); |
| |
| test_inside(r, p); |
| } |
| { |
| // Size is exclusive |
| auto r = IRect::MakeXYWH(100, 100, 100, 100); |
| auto p = IPoint(200, 200); |
| |
| test_outside(r, p); |
| } |
| { |
| auto r = IRect::MakeXYWH(100, 100, 100, 100); |
| auto p = IPoint(99, 99); |
| |
| test_outside(r, p); |
| } |
| { |
| auto r = IRect::MakeXYWH(100, 100, 100, 100); |
| auto p = IPoint(199, 199); |
| |
| test_inside(r, p); |
| } |
| |
| { |
| auto r = IRect::MakeMaximum(); |
| auto p = IPoint(199, 199); |
| |
| test_inside(r, p); |
| } |
| } |
| |
| TEST(RectTest, RectContainsRect) { |
| auto check_nans = [](const Rect& a, const Rect& b, const std::string& label) { |
| ASSERT_TRUE(a.IsFinite()) << label; |
| ASSERT_TRUE(b.IsFinite()) << label; |
| ASSERT_FALSE(a.IsEmpty()); |
| |
| for (int i = 1; i < 16; i++) { |
| // NaN in a produces false |
| EXPECT_FALSE(swap_nan(a, i).Contains(b)) << label << ", index = " << i; |
| // NaN in b produces false |
| EXPECT_TRUE(a.Contains(swap_nan(b, i))) << label << ", index = " << i; |
| // NaN in both is false |
| for (int j = 1; j < 16; j++) { |
| EXPECT_FALSE(swap_nan(a, i).Contains(swap_nan(b, j))) |
| << label << ", indices = " << i << ", " << j; |
| } |
| } |
| }; |
| |
| auto check_empty_flips = [](const Rect& a, const Rect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // test b rects are allowed to have 0 w/h, but not be backwards |
| ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom()); |
| |
| // unflipped a vs flipped (empty) b yields false |
| EXPECT_TRUE(a.Contains(flip_lr(b))) << label; |
| EXPECT_TRUE(a.Contains(flip_tb(b))) << label; |
| EXPECT_TRUE(a.Contains(flip_lrtb(b))) << label; |
| |
| // flipped (empty) a vs unflipped b yields false |
| EXPECT_FALSE(flip_lr(a).Contains(b)) << label; |
| EXPECT_FALSE(flip_tb(a).Contains(b)) << label; |
| EXPECT_FALSE(flip_lrtb(a).Contains(b)) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_FALSE(flip_lr(a).Contains(flip_lr(b))) << label; |
| EXPECT_FALSE(flip_tb(a).Contains(flip_tb(b))) << label; |
| EXPECT_FALSE(flip_lrtb(a).Contains(flip_lrtb(b))) << label; |
| }; |
| |
| auto test_inside = [&check_nans, &check_empty_flips](const Rect& a, |
| const Rect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // test b rects are allowed to have 0 w/h, but not be backwards |
| ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom()); |
| |
| std::stringstream stream; |
| stream << a << " contains " << b; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(a.Contains(b)) << label; |
| check_empty_flips(a, b, label); |
| check_nans(a, b, label); |
| }; |
| |
| auto test_not_inside = [&check_nans, &check_empty_flips](const Rect& a, |
| const Rect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // If b was empty, it would be contained and should not be tested with |
| // this function - use |test_inside| instead. |
| ASSERT_FALSE(b.IsEmpty()) << b; |
| |
| std::stringstream stream; |
| stream << a << " contains " << b; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(a.Contains(b)) << label; |
| check_empty_flips(a, b, label); |
| check_nans(a, b, label); |
| }; |
| |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| |
| test_inside(a, a); |
| } |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(0, 0, 0, 0); |
| |
| test_inside(a, b); |
| } |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(150, 150, 20, 20); |
| |
| test_inside(a, b); |
| } |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(150, 150, 100, 100); |
| |
| test_not_inside(a, b); |
| } |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(50, 50, 100, 100); |
| |
| test_not_inside(a, b); |
| } |
| { |
| auto a = Rect::MakeXYWH(100, 100, 100, 100); |
| auto b = Rect::MakeXYWH(0, 0, 300, 300); |
| |
| test_not_inside(a, b); |
| } |
| { |
| auto a = Rect::MakeMaximum(); |
| auto b = Rect::MakeXYWH(0, 0, 300, 300); |
| |
| test_inside(a, b); |
| } |
| } |
| |
| TEST(RectTest, IRectContainsIRect) { |
| auto check_empty_flips = [](const IRect& a, const IRect& b, |
| const std::string& label) { |
| ASSERT_FALSE(a.IsEmpty()); |
| // test b rects are allowed to have 0 w/h, but not be backwards |
| ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom()); |
| |
| // unflipped a vs flipped (empty) b yields true |
| EXPECT_TRUE(a.Contains(flip_lr(b))) << label; |
| EXPECT_TRUE(a.Contains(flip_tb(b))) << label; |
| EXPECT_TRUE(a.Contains(flip_lrtb(b))) << label; |
| |
| // flipped (empty) a vs unflipped b yields false |
| EXPECT_FALSE(flip_lr(a).Contains(b)) << label; |
| EXPECT_FALSE(flip_tb(a).Contains(b)) << label; |
| EXPECT_FALSE(flip_lrtb(a).Contains(b)) << label; |
| |
| // flipped (empty) a vs flipped (empty) b yields empty |
| EXPECT_FALSE(flip_lr(a).Contains(flip_lr(b))) << label; |
| EXPECT_FALSE(flip_tb(a).Contains(flip_tb(b))) << label; |
| EXPECT_FALSE(flip_lrtb(a).Contains(flip_lrtb(b))) << label; |
| }; |
| |
| auto test_inside = [&check_empty_flips](const IRect& a, const IRect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // test b rects are allowed to have 0 w/h, but not be backwards |
| ASSERT_FALSE(b.GetLeft() > b.GetRight() || b.GetTop() > b.GetBottom()); |
| |
| std::stringstream stream; |
| stream << a << " contains " << b; |
| auto label = stream.str(); |
| |
| EXPECT_TRUE(a.Contains(b)) << label; |
| check_empty_flips(a, b, label); |
| }; |
| |
| auto test_not_inside = [&check_empty_flips](const IRect& a, const IRect& b) { |
| ASSERT_FALSE(a.IsEmpty()) << a; |
| // If b was empty, it would be contained and should not be tested with |
| // this function - use |test_inside| instead. |
| ASSERT_FALSE(b.IsEmpty()) << b; |
| |
| std::stringstream stream; |
| stream << a << " contains " << b; |
| auto label = stream.str(); |
| |
| EXPECT_FALSE(a.Contains(b)) << label; |
| check_empty_flips(a, b, label); |
| }; |
| |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| |
| test_inside(a, a); |
| } |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(0, 0, 0, 0); |
| |
| test_inside(a, b); |
| } |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(150, 150, 20, 20); |
| |
| test_inside(a, b); |
| } |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(150, 150, 100, 100); |
| |
| test_not_inside(a, b); |
| } |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(50, 50, 100, 100); |
| |
| test_not_inside(a, b); |
| } |
| { |
| auto a = IRect::MakeXYWH(100, 100, 100, 100); |
| auto b = IRect::MakeXYWH(0, 0, 300, 300); |
| |
| test_not_inside(a, b); |
| } |
| { |
| auto a = IRect::MakeMaximum(); |
| auto b = IRect::MakeXYWH(0, 0, 300, 300); |
| |
| test_inside(a, b); |
| } |
| } |
| |
| TEST(RectTest, RectCutOut) { |
| Rect cull_rect = Rect::MakeLTRB(20, 20, 40, 40); |
| |
| auto check_nans = [&cull_rect](const Rect& diff_rect, |
| const std::string& label) { |
| EXPECT_TRUE(cull_rect.IsFinite()) << label; |
| EXPECT_TRUE(diff_rect.IsFinite()) << label; |
| |
| for (int i = 1; i < 16; i++) { |
| // NaN in cull_rect produces empty |
| EXPECT_FALSE(swap_nan(cull_rect, i).Cutout(diff_rect).has_value()) |
| << label << ", index " << i; |
| EXPECT_EQ(swap_nan(cull_rect, i).CutoutOrEmpty(diff_rect), Rect()) |
| << label << ", index " << i; |
| |
| // NaN in diff_rect is nop |
| EXPECT_TRUE(cull_rect.Cutout(swap_nan(diff_rect, i)).has_value()) |
| << label << ", index " << i; |
| EXPECT_EQ(cull_rect.CutoutOrEmpty(swap_nan(diff_rect, i)), cull_rect) |
| << label << ", index " << i; |
| |
| for (int j = 1; j < 16; j++) { |
| // NaN in both is also empty |
| EXPECT_FALSE( |
| swap_nan(cull_rect, i).Cutout(swap_nan(diff_rect, j)).has_value()) |
| << label << ", indices " << i << ", " << j; |
| EXPECT_EQ(swap_nan(cull_rect, i).CutoutOrEmpty(swap_nan(diff_rect, j)), |
| Rect()) |
| << label << ", indices " << i << ", " << j; |
| } |
| } |
| }; |
| |
| auto check_empty_flips = [&cull_rect](const Rect& diff_rect, |
| const std::string& label) { |
| EXPECT_FALSE(cull_rect.IsEmpty()) << label; |
| EXPECT_FALSE(diff_rect.IsEmpty()) << label; |
| |
| // unflipped cull_rect vs flipped(empty) diff_rect |
| // == cull_rect |
| EXPECT_TRUE(cull_rect.Cutout(flip_lr(diff_rect)).has_value()) << label; |
| EXPECT_EQ(cull_rect.Cutout(flip_lr(diff_rect)), cull_rect) << label; |
| EXPECT_TRUE(cull_rect.Cutout(flip_tb(diff_rect)).has_value()) << label; |
| EXPECT_EQ(cull_rect.Cutout(flip_tb(diff_rect)), cull_rect) << label; |
| EXPECT_TRUE(cull_rect.Cutout(flip_lrtb(diff_rect)).has_value()) << label; |
| EXPECT_EQ(cull_rect.Cutout(flip_lrtb(diff_rect)), cull_rect) << label; |
| |
| // flipped(empty) cull_rect vs unflipped diff_rect |
| // == empty |
| EXPECT_FALSE(flip_lr(cull_rect).Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(diff_rect), Rect()) << label; |
| EXPECT_FALSE(flip_tb(cull_rect).Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(diff_rect), Rect()) << label; |
| EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(diff_rect), Rect()) << label; |
| |
| // flipped(empty) cull_rect vs flipped(empty) diff_rect |
| // == empty |
| EXPECT_FALSE(flip_lr(cull_rect).Cutout(flip_lr(diff_rect)).has_value()) |
| << label; |
| EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(flip_lr(diff_rect)), Rect()) |
| << label; |
| EXPECT_FALSE(flip_tb(cull_rect).Cutout(flip_tb(diff_rect)).has_value()) |
| << label; |
| EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(flip_tb(diff_rect)), Rect()) |
| << label; |
| EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(flip_lrtb(diff_rect)).has_value()) |
| << label; |
| EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(flip_lrtb(diff_rect)), Rect()) |
| << label; |
| }; |
| |
| auto non_reducing = [&cull_rect, &check_empty_flips, &check_nans]( |
| const Rect& diff_rect, const std::string& label) { |
| EXPECT_EQ(cull_rect.Cutout(diff_rect), cull_rect) << label; |
| EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), cull_rect) << label; |
| check_empty_flips(diff_rect, label); |
| check_nans(diff_rect, label); |
| }; |
| |
| auto reducing = [&cull_rect, &check_empty_flips, &check_nans]( |
| const Rect& diff_rect, const Rect& result_rect, |
| const std::string& label) { |
| EXPECT_TRUE(!result_rect.IsEmpty()); |
| EXPECT_EQ(cull_rect.Cutout(diff_rect), result_rect) << label; |
| EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), result_rect) << label; |
| check_empty_flips(diff_rect, label); |
| check_nans(diff_rect, label); |
| }; |
| |
| auto emptying = [&cull_rect, &check_empty_flips, &check_nans]( |
| const Rect& diff_rect, const std::string& label) { |
| EXPECT_FALSE(cull_rect.Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), Rect()) << label; |
| check_empty_flips(diff_rect, label); |
| check_nans(diff_rect, label); |
| }; |
| |
| // Skim the corners and edge |
| non_reducing(Rect::MakeLTRB(10, 10, 20, 20), "outside UL corner"); |
| non_reducing(Rect::MakeLTRB(20, 10, 40, 20), "Above"); |
| non_reducing(Rect::MakeLTRB(40, 10, 50, 20), "outside UR corner"); |
| non_reducing(Rect::MakeLTRB(40, 20, 50, 40), "Right"); |
| non_reducing(Rect::MakeLTRB(40, 40, 50, 50), "outside LR corner"); |
| non_reducing(Rect::MakeLTRB(20, 40, 40, 50), "Below"); |
| non_reducing(Rect::MakeLTRB(10, 40, 20, 50), "outside LR corner"); |
| non_reducing(Rect::MakeLTRB(10, 20, 20, 40), "Left"); |
| |
| // Overlap corners |
| non_reducing(Rect::MakeLTRB(15, 15, 25, 25), "covering UL corner"); |
| non_reducing(Rect::MakeLTRB(35, 15, 45, 25), "covering UR corner"); |
| non_reducing(Rect::MakeLTRB(35, 35, 45, 45), "covering LR corner"); |
| non_reducing(Rect::MakeLTRB(15, 35, 25, 45), "covering LL corner"); |
| |
| // Overlap edges, but not across an entire side |
| non_reducing(Rect::MakeLTRB(20, 15, 39, 25), "Top edge left-biased"); |
| non_reducing(Rect::MakeLTRB(21, 15, 40, 25), "Top edge, right biased"); |
| non_reducing(Rect::MakeLTRB(35, 20, 45, 39), "Right edge, top-biased"); |
| non_reducing(Rect::MakeLTRB(35, 21, 45, 40), "Right edge, bottom-biased"); |
| non_reducing(Rect::MakeLTRB(20, 35, 39, 45), "Bottom edge, left-biased"); |
| non_reducing(Rect::MakeLTRB(21, 35, 40, 45), "Bottom edge, right-biased"); |
| non_reducing(Rect::MakeLTRB(15, 20, 25, 39), "Left edge, top-biased"); |
| non_reducing(Rect::MakeLTRB(15, 21, 25, 40), "Left edge, bottom-biased"); |
| |
| // Slice all the way through the middle |
| non_reducing(Rect::MakeLTRB(25, 15, 35, 45), "Vertical interior slice"); |
| non_reducing(Rect::MakeLTRB(15, 25, 45, 35), "Horizontal interior slice"); |
| |
| // Slice off each edge |
| reducing(Rect::MakeLTRB(20, 15, 40, 25), // |
| Rect::MakeLTRB(20, 25, 40, 40), // |
| "Slice off top"); |
| reducing(Rect::MakeLTRB(35, 20, 45, 40), // |
| Rect::MakeLTRB(20, 20, 35, 40), // |
| "Slice off right"); |
| reducing(Rect::MakeLTRB(20, 35, 40, 45), // |
| Rect::MakeLTRB(20, 20, 40, 35), // |
| "Slice off bottom"); |
| reducing(Rect::MakeLTRB(15, 20, 25, 40), // |
| Rect::MakeLTRB(25, 20, 40, 40), // |
| "Slice off left"); |
| |
| // cull rect contains diff rect |
| non_reducing(Rect::MakeLTRB(21, 21, 39, 39), "Contained, non-covering"); |
| |
| // cull rect equals diff rect |
| emptying(cull_rect, "Perfectly covering"); |
| |
| // diff rect contains cull rect |
| emptying(Rect::MakeLTRB(15, 15, 45, 45), "Smothering"); |
| } |
| |
| TEST(RectTest, IRectCutOut) { |
| IRect cull_rect = IRect::MakeLTRB(20, 20, 40, 40); |
| |
| auto check_empty_flips = [&cull_rect](const IRect& diff_rect, |
| const std::string& label) { |
| EXPECT_FALSE(diff_rect.IsEmpty()); |
| EXPECT_FALSE(cull_rect.IsEmpty()); |
| |
| // unflipped cull_rect vs flipped(empty) diff_rect |
| // == cull_rect |
| EXPECT_TRUE(cull_rect.Cutout(flip_lr(diff_rect)).has_value()) << label; |
| EXPECT_EQ(cull_rect.Cutout(flip_lr(diff_rect)), cull_rect) << label; |
| EXPECT_TRUE(cull_rect.Cutout(flip_tb(diff_rect)).has_value()) << label; |
| EXPECT_EQ(cull_rect.Cutout(flip_tb(diff_rect)), cull_rect) << label; |
| EXPECT_TRUE(cull_rect.Cutout(flip_lrtb(diff_rect)).has_value()) << label; |
| EXPECT_EQ(cull_rect.Cutout(flip_lrtb(diff_rect)), cull_rect) << label; |
| |
| // flipped(empty) cull_rect vs flipped(empty) diff_rect |
| // == empty |
| EXPECT_FALSE(flip_lr(cull_rect).Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(diff_rect), IRect()) << label; |
| EXPECT_FALSE(flip_tb(cull_rect).Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(diff_rect), IRect()) << label; |
| EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(diff_rect), IRect()) << label; |
| |
| // flipped(empty) cull_rect vs unflipped diff_rect |
| // == empty |
| EXPECT_FALSE(flip_lr(cull_rect).Cutout(flip_lr(diff_rect)).has_value()) |
| << label; |
| EXPECT_EQ(flip_lr(cull_rect).CutoutOrEmpty(flip_lr(diff_rect)), IRect()) |
| << label; |
| EXPECT_FALSE(flip_tb(cull_rect).Cutout(flip_tb(diff_rect)).has_value()) |
| << label; |
| EXPECT_EQ(flip_tb(cull_rect).CutoutOrEmpty(flip_tb(diff_rect)), IRect()) |
| << label; |
| EXPECT_FALSE(flip_lrtb(cull_rect).Cutout(flip_lrtb(diff_rect)).has_value()) |
| << label; |
| EXPECT_EQ(flip_lrtb(cull_rect).CutoutOrEmpty(flip_lrtb(diff_rect)), IRect()) |
| << label; |
| }; |
| |
| auto non_reducing = [&cull_rect, &check_empty_flips]( |
| const IRect& diff_rect, const std::string& label) { |
| EXPECT_EQ(cull_rect.Cutout(diff_rect), cull_rect) << label; |
| EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), cull_rect) << label; |
| check_empty_flips(diff_rect, label); |
| }; |
| |
| auto reducing = [&cull_rect, &check_empty_flips](const IRect& diff_rect, |
| const IRect& result_rect, |
| const std::string& label) { |
| EXPECT_TRUE(!result_rect.IsEmpty()); |
| EXPECT_EQ(cull_rect.Cutout(diff_rect), result_rect) << label; |
| EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), result_rect) << label; |
| check_empty_flips(diff_rect, label); |
| }; |
| |
| auto emptying = [&cull_rect, &check_empty_flips](const IRect& diff_rect, |
| const std::string& label) { |
| EXPECT_FALSE(cull_rect.Cutout(diff_rect).has_value()) << label; |
| EXPECT_EQ(cull_rect.CutoutOrEmpty(diff_rect), IRect()) << label; |
| check_empty_flips(diff_rect, label); |
| }; |
| |
| // Skim the corners and edge |
| non_reducing(IRect::MakeLTRB(10, 10, 20, 20), "outside UL corner"); |
| non_reducing(IRect::MakeLTRB(20, 10, 40, 20), "Above"); |
| non_reducing(IRect::MakeLTRB(40, 10, 50, 20), "outside UR corner"); |
| non_reducing(IRect::MakeLTRB(40, 20, 50, 40), "Right"); |
| non_reducing(IRect::MakeLTRB(40, 40, 50, 50), "outside LR corner"); |
| non_reducing(IRect::MakeLTRB(20, 40, 40, 50), "Below"); |
| non_reducing(IRect::MakeLTRB(10, 40, 20, 50), "outside LR corner"); |
| non_reducing(IRect::MakeLTRB(10, 20, 20, 40), "Left"); |
| |
| // Overlap corners |
| non_reducing(IRect::MakeLTRB(15, 15, 25, 25), "covering UL corner"); |
| non_reducing(IRect::MakeLTRB(35, 15, 45, 25), "covering UR corner"); |
| non_reducing(IRect::MakeLTRB(35, 35, 45, 45), "covering LR corner"); |
| non_reducing(IRect::MakeLTRB(15, 35, 25, 45), "covering LL corner"); |
| |
| // Overlap edges, but not across an entire side |
| non_reducing(IRect::MakeLTRB(20, 15, 39, 25), "Top edge left-biased"); |
| non_reducing(IRect::MakeLTRB(21, 15, 40, 25), "Top edge, right biased"); |
| non_reducing(IRect::MakeLTRB(35, 20, 45, 39), "Right edge, top-biased"); |
| non_reducing(IRect::MakeLTRB(35, 21, 45, 40), "Right edge, bottom-biased"); |
| non_reducing(IRect::MakeLTRB(20, 35, 39, 45), "Bottom edge, left-biased"); |
| non_reducing(IRect::MakeLTRB(21, 35, 40, 45), "Bottom edge, right-biased"); |
| non_reducing(IRect::MakeLTRB(15, 20, 25, 39), "Left edge, top-biased"); |
| non_reducing(IRect::MakeLTRB(15, 21, 25, 40), "Left edge, bottom-biased"); |
| |
| // Slice all the way through the middle |
| non_reducing(IRect::MakeLTRB(25, 15, 35, 45), "Vertical interior slice"); |
| non_reducing(IRect::MakeLTRB(15, 25, 45, 35), "Horizontal interior slice"); |
| |
| // Slice off each edge |
| reducing(IRect::MakeLTRB(20, 15, 40, 25), // |
| IRect::MakeLTRB(20, 25, 40, 40), // |
| "Slice off top"); |
| reducing(IRect::MakeLTRB(35, 20, 45, 40), // |
| IRect::MakeLTRB(20, 20, 35, 40), // |
| "Slice off right"); |
| reducing(IRect::MakeLTRB(20, 35, 40, 45), // |
| IRect::MakeLTRB(20, 20, 40, 35), // |
| "Slice off bottom"); |
| reducing(IRect::MakeLTRB(15, 20, 25, 40), // |
| IRect::MakeLTRB(25, 20, 40, 40), // |
| "Slice off left"); |
| |
| // cull rect contains diff rect |
| non_reducing(IRect::MakeLTRB(21, 21, 39, 39), "Contained, non-covering"); |
| |
| // cull rect equals diff rect |
| emptying(cull_rect, "Perfectly covering"); |
| |
| // diff rect contains cull rect |
| emptying(IRect::MakeLTRB(15, 15, 45, 45), "Smothering"); |
| } |
| |
| TEST(RectTest, RectGetPoints) { |
| { |
| Rect r = Rect::MakeXYWH(100, 200, 300, 400); |
| auto points = r.GetPoints(); |
| EXPECT_POINT_NEAR(points[0], Point(100, 200)); |
| EXPECT_POINT_NEAR(points[1], Point(400, 200)); |
| EXPECT_POINT_NEAR(points[2], Point(100, 600)); |
| EXPECT_POINT_NEAR(points[3], Point(400, 600)); |
| } |
| |
| { |
| Rect r = Rect::MakeMaximum(); |
| auto points = r.GetPoints(); |
| EXPECT_EQ(points[0], Point(std::numeric_limits<float>::lowest(), |
| std::numeric_limits<float>::lowest())); |
| EXPECT_EQ(points[1], Point(std::numeric_limits<float>::max(), |
| std::numeric_limits<float>::lowest())); |
| EXPECT_EQ(points[2], Point(std::numeric_limits<float>::lowest(), |
| std::numeric_limits<float>::max())); |
| EXPECT_EQ(points[3], Point(std::numeric_limits<float>::max(), |
| std::numeric_limits<float>::max())); |
| } |
| } |
| |
| TEST(RectTest, RectShift) { |
| auto r = Rect::MakeLTRB(0, 0, 100, 100); |
| |
| EXPECT_EQ(r.Shift(Point(10, 5)), Rect::MakeLTRB(10, 5, 110, 105)); |
| EXPECT_EQ(r.Shift(Point(-10, -5)), Rect::MakeLTRB(-10, -5, 90, 95)); |
| } |
| |
| TEST(RectTest, RectGetTransformedPoints) { |
| Rect r = Rect::MakeXYWH(100, 200, 300, 400); |
| auto points = r.GetTransformedPoints(Matrix::MakeTranslation({10, 20})); |
| EXPECT_POINT_NEAR(points[0], Point(110, 220)); |
| EXPECT_POINT_NEAR(points[1], Point(410, 220)); |
| EXPECT_POINT_NEAR(points[2], Point(110, 620)); |
| EXPECT_POINT_NEAR(points[3], Point(410, 620)); |
| } |
| |
| TEST(RectTest, RectMakePointBounds) { |
| { |
| std::vector<Point> points{{1, 5}, {4, -1}, {0, 6}}; |
| auto r = Rect::MakePointBounds(points.begin(), points.end()); |
| auto expected = Rect::MakeXYWH(0, -1, 4, 7); |
| EXPECT_TRUE(r.has_value()); |
| if (r.has_value()) { |
| EXPECT_RECT_NEAR(r.value(), expected); |
| } |
| } |
| { |
| std::vector<Point> points; |
| std::optional<Rect> r = Rect::MakePointBounds(points.begin(), points.end()); |
| EXPECT_FALSE(r.has_value()); |
| } |
| } |
| |
| TEST(RectTest, RectGetPositive) { |
| { |
| Rect r = Rect::MakeXYWH(100, 200, 300, 400); |
| auto actual = r.GetPositive(); |
| EXPECT_RECT_NEAR(r, actual); |
| } |
| { |
| Rect r = Rect::MakeXYWH(100, 200, -100, -100); |
| auto actual = r.GetPositive(); |
| Rect expected = Rect::MakeXYWH(0, 100, 100, 100); |
| EXPECT_RECT_NEAR(expected, actual); |
| } |
| } |
| |
| TEST(RectTest, RectDirections) { |
| auto r = Rect::MakeLTRB(1, 2, 3, 4); |
| |
| EXPECT_EQ(r.GetLeft(), 1); |
| EXPECT_EQ(r.GetTop(), 2); |
| EXPECT_EQ(r.GetRight(), 3); |
| EXPECT_EQ(r.GetBottom(), 4); |
| |
| EXPECT_POINT_NEAR(r.GetLeftTop(), Point(1, 2)); |
| EXPECT_POINT_NEAR(r.GetRightTop(), Point(3, 2)); |
| EXPECT_POINT_NEAR(r.GetLeftBottom(), Point(1, 4)); |
| EXPECT_POINT_NEAR(r.GetRightBottom(), Point(3, 4)); |
| } |
| |
| TEST(RectTest, RectProject) { |
| { |
| auto r = Rect::MakeLTRB(-100, -100, 100, 100); |
| auto actual = r.Project(r); |
| auto expected = Rect::MakeLTRB(0, 0, 1, 1); |
| EXPECT_RECT_NEAR(expected, actual); |
| } |
| { |
| auto r = Rect::MakeLTRB(-100, -100, 100, 100); |
| auto actual = r.Project(Rect::MakeLTRB(0, 0, 100, 100)); |
| auto expected = Rect::MakeLTRB(0.5, 0.5, 1, 1); |
| EXPECT_RECT_NEAR(expected, actual); |
| } |
| } |
| |
| TEST(RectTest, RectRoundOut) { |
| { |
| auto r = Rect::MakeLTRB(-100, -200, 300, 400); |
| EXPECT_EQ(Rect::RoundOut(r), r); |
| } |
| { |
| auto r = Rect::MakeLTRB(-100.1, -200.1, 300.1, 400.1); |
| EXPECT_EQ(Rect::RoundOut(r), Rect::MakeLTRB(-101, -201, 301, 401)); |
| } |
| } |
| |
| TEST(RectTest, IRectRoundOut) { |
| { |
| auto r = Rect::MakeLTRB(-100, -200, 300, 400); |
| auto ir = IRect::MakeLTRB(-100, -200, 300, 400); |
| EXPECT_EQ(IRect::RoundOut(r), ir); |
| } |
| { |
| auto r = Rect::MakeLTRB(-100.1, -200.1, 300.1, 400.1); |
| auto ir = IRect::MakeLTRB(-101, -201, 301, 401); |
| EXPECT_EQ(IRect::RoundOut(r), ir); |
| } |
| } |
| |
| TEST(RectTest, RectRound) { |
| { |
| auto r = Rect::MakeLTRB(-100, -200, 300, 400); |
| EXPECT_EQ(Rect::Round(r), r); |
| } |
| { |
| auto r = Rect::MakeLTRB(-100.4, -200.4, 300.4, 400.4); |
| EXPECT_EQ(Rect::Round(r), Rect::MakeLTRB(-100, -200, 300, 400)); |
| } |
| { |
| auto r = Rect::MakeLTRB(-100.5, -200.5, 300.5, 400.5); |
| EXPECT_EQ(Rect::Round(r), Rect::MakeLTRB(-101, -201, 301, 401)); |
| } |
| } |
| |
| TEST(RectTest, IRectRound) { |
| { |
| auto r = Rect::MakeLTRB(-100, -200, 300, 400); |
| auto ir = IRect::MakeLTRB(-100, -200, 300, 400); |
| EXPECT_EQ(IRect::Round(r), ir); |
| } |
| { |
| auto r = Rect::MakeLTRB(-100.4, -200.4, 300.4, 400.4); |
| auto ir = IRect::MakeLTRB(-100, -200, 300, 400); |
| EXPECT_EQ(IRect::Round(r), ir); |
| } |
| { |
| auto r = Rect::MakeLTRB(-100.5, -200.5, 300.5, 400.5); |
| auto ir = IRect::MakeLTRB(-101, -201, 301, 401); |
| EXPECT_EQ(IRect::Round(r), ir); |
| } |
| } |
| |
| TEST(RectTest, TransformAndClipBounds) { |
| { |
| // This matrix should clip no corners. |
| auto matrix = impeller::Matrix::MakeColumn( |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, 0.0f, |
| 0.0f, 4.0f, 0.0f, 0.0f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 8.0f |
| // clang-format on |
| ); |
| Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); |
| // None of these should have a W<0 |
| EXPECT_EQ(matrix.TransformHomogenous(src.GetLeftTop()), |
| Vector3(200.0f, 400.0f, 8.0f)); |
| EXPECT_EQ(matrix.TransformHomogenous(src.GetRightTop()), |
| Vector3(400.0f, 400.0f, 8.0f)); |
| EXPECT_EQ(matrix.TransformHomogenous(src.GetLeftBottom()), |
| Vector3(200.0f, 800.0f, 8.0f)); |
| EXPECT_EQ(matrix.TransformHomogenous(src.GetRightBottom()), |
| Vector3(400.0f, 800.0f, 8.0f)); |
| |
| Rect expect = Rect::MakeLTRB(25.0f, 50.0f, 50.0f, 100.0f); |
| EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty()); |
| EXPECT_EQ(src.TransformAndClipBounds(matrix), expect); |
| } |
| |
| { |
| // This matrix should clip one corner. |
| auto matrix = impeller::Matrix::MakeColumn( |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -0.01f, |
| 0.0f, 2.0f, 0.0f, -0.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| ); |
| Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); |
| // Exactly one of these should have a W<0 |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()), |
| Vector3(200.0f, 200.0f, 1.4f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()), |
| Vector3(400.0f, 200.0f, 0.4f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()), |
| Vector3(200.0f, 400.0f, 0.8f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()), |
| Vector3(400.0f, 400.0f, -0.2f)); |
| |
| Rect expect = Rect::MakeLTRB(142.85715f, 142.85715f, 6553600.f, 6553600.f); |
| EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty()); |
| EXPECT_RECT_NEAR(src.TransformAndClipBounds(matrix), expect); |
| } |
| |
| { |
| // This matrix should clip two corners. |
| auto matrix = impeller::Matrix::MakeColumn( |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -.015f, |
| 0.0f, 2.0f, 0.0f, -.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| ); |
| Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); |
| // Exactly two of these should have a W<0 |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()), |
| Vector3(200.0f, 200.0f, 0.9f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()), |
| Vector3(400.0f, 200.0f, -0.6f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()), |
| Vector3(200.0f, 400.0f, 0.3f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()), |
| Vector3(400.0f, 400.0f, -1.2f)); |
| |
| Rect expect = Rect::MakeLTRB(222.2222f, 222.2222f, 5898373.f, 6553600.f); |
| EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty()); |
| EXPECT_RECT_NEAR(src.TransformAndClipBounds(matrix), expect); |
| } |
| |
| { |
| // This matrix should clip three corners. |
| auto matrix = impeller::Matrix::MakeColumn( |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -.02f, |
| 0.0f, 2.0f, 0.0f, -.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| ); |
| Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); |
| // Exactly three of these should have a W<0 |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()), |
| Vector3(200.0f, 200.0f, 0.4f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()), |
| Vector3(400.0f, 200.0f, -1.6f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()), |
| Vector3(200.0f, 400.0f, -0.2f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()), |
| Vector3(400.0f, 400.0f, -2.2f)); |
| |
| Rect expect = Rect::MakeLTRB(499.99988f, 499.99988f, 5898340.f, 4369400.f); |
| EXPECT_FALSE(src.TransformAndClipBounds(matrix).IsEmpty()); |
| EXPECT_RECT_NEAR(src.TransformAndClipBounds(matrix), expect); |
| } |
| |
| { |
| // This matrix should clip all four corners. |
| auto matrix = impeller::Matrix::MakeColumn( |
| // clang-format off |
| 2.0f, 0.0f, 0.0f, -.025f, |
| 0.0f, 2.0f, 0.0f, -.006f, |
| 0.0f, 0.0f, 1.0f, 0.0f, |
| 0.0f, 0.0f, 0.0f, 3.0f |
| // clang-format on |
| ); |
| Rect src = Rect::MakeLTRB(100.0f, 100.0f, 200.0f, 200.0f); |
| // All of these should have a W<0 |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftTop()), |
| Vector3(200.0f, 200.0f, -0.1f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightTop()), |
| Vector3(400.0f, 200.0f, -2.6f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetLeftBottom()), |
| Vector3(200.0f, 400.0f, -0.7f)); |
| EXPECT_VECTOR3_NEAR(matrix.TransformHomogenous(src.GetRightBottom()), |
| Vector3(400.0f, 400.0f, -3.2f)); |
| |
| EXPECT_TRUE(src.TransformAndClipBounds(matrix).IsEmpty()); |
| } |
| } |
| |
| } // namespace testing |
| } // namespace impeller |