diff --git a/gfx/rect.h b/gfx/rect.h index c2652d877..c523679a5 100644 --- a/gfx/rect.h +++ b/gfx/rect.h @@ -409,6 +409,81 @@ class RectT { return *this; } + // Slices vertically this Rect along the provided px coordinate. + // Sets the left and right rects in the references of the same name. + const RectT& sliceV(T px, RectT& left, RectT& right) const { + if (px < x) { + left = RectT(); + right = *this; + } + else if (px > x2()) { + left = *this; + right = RectT(); + } + else { + left = RectT(x, y, px - x, h); + right = RectT(px, y, x2() - px, h); + } + + return *this; + } + + // Slices horizontally this Rect along the provided py coordinate. + // Sets the top and bottom rects in the references of the same name. + const RectT& sliceH(T py, RectT& top, RectT& bottom) const { + if (py < y) { + top = RectT(); + bottom = *this; + } + else if (py > y2()) { + top = *this; + bottom = RectT(); + } + else { + top = RectT(x, y, w, py - y); + bottom = RectT(x, py, w, y2() - py); + } + + return *this; + } + + // Slices this rect in nine pieces and returns all the rects in the slices + // output array. The center rect defines the relative coordinates where the + // cuts are going to be made: + // + // this (x, y, w=23, h=7) slices output + // +---------------------+ +--------+-----+------+ + // | center (9,2,w=7,h=3)| | [0] | [1] | [2] | + // | +-----+ | +--------+-----+------+ + // | | | | => | [3] | [4] | [5] | + // | +-----+ | +--------+-----+------+ + // | | | [6] | [7] | [8] | + // +---------------------+ +--------+-----+------+ + // + const RectT& nineSlice(const RectT& center, RectT slices[9]) const { + gfx::RectT left, middle, right; + + { + gfx::RectT remaining; + this->sliceV(x + center.x, left, remaining); + remaining.sliceV(x + center.x2(), middle, right); + } + + left .sliceH(y + center.y , slices[0], left); + middle.sliceH(y + center.y , slices[1], middle); + right .sliceH(y + center.y , slices[2], right); + + left .sliceH(y + center.y2(), slices[3], left); + middle.sliceH(y + center.y2(), slices[4], middle); + right .sliceH(y + center.y2(), slices[5], right); + + slices[6] = left; + slices[7] = middle; + slices[8] = right; + + return *this; + } + }; typedef RectT Rect; diff --git a/gfx/rect_tests.cpp b/gfx/rect_tests.cpp index 937921e39..23519a803 100644 --- a/gfx/rect_tests.cpp +++ b/gfx/rect_tests.cpp @@ -64,6 +64,113 @@ TEST(Rect, Floor) EXPECT_EQ(gfx::Rect(-1, -1, 1, 2), gfx::RectF(-0.25, -0.75, 1, 2).floor()); } + +TEST(Rect, SliceV) +{ + const int x = 3, y = 4; + gfx::Rect l, r; + auto rect = gfx::Rect(x, y, 5, 7); + rect.sliceV(x, l, r); + EXPECT_EQ(gfx::Rect(x,y,0,7), l); + EXPECT_EQ(gfx::Rect(x,y,5,7), r); + + rect.sliceV(x-1, l, r); + EXPECT_EQ(gfx::Rect(0,0,0,0), l); + EXPECT_EQ(gfx::Rect(x,y,5,7), r); + + rect.sliceV(x+1, l, r); + EXPECT_EQ(gfx::Rect(x,y,1,7), l); + EXPECT_EQ(gfx::Rect(x+1,y,4,7), r); + + rect.sliceV(x+4, l, r); + EXPECT_EQ(gfx::Rect(x,y,4,7), l); + EXPECT_EQ(gfx::Rect(x+4,y,1,7), r); + + rect.sliceV(x+5, l, r); + EXPECT_EQ(gfx::Rect(x,y,5,7), l); + EXPECT_EQ(gfx::Rect(x+5,y,0,7), r); + + rect.sliceV(x+6, l, r); + EXPECT_EQ(gfx::Rect(x,y,5,7), l); + EXPECT_EQ(gfx::Rect(0,0,0,0), r); +} + +TEST(Rect, SliceH) +{ + const int x = 3, y = 4; + gfx::Rect t, b; + auto rect = gfx::Rect(x, y, 5, 7); + rect.sliceH(y, t, b); + EXPECT_EQ(gfx::Rect(x,y,5,0), t); + EXPECT_EQ(gfx::Rect(x,y,5,7), b); + + rect.sliceH(y-1, t, b); + EXPECT_EQ(gfx::Rect(0,0,0,0), t); + EXPECT_EQ(gfx::Rect(x,y,5,7), b); + + rect.sliceH(y+1, t, b); + EXPECT_EQ(gfx::Rect(x,y,5,1), t); + EXPECT_EQ(gfx::Rect(x,y+1,5,6), b); + + rect.sliceH(y+6, t, b); + EXPECT_EQ(gfx::Rect(x,y,5,6), t); + EXPECT_EQ(gfx::Rect(x,y+6,5,1), b); + + rect.sliceH(y+7, t, b); + EXPECT_EQ(gfx::Rect(x,y,5,7), t); + EXPECT_EQ(gfx::Rect(x,y+7,5,0), b); + + rect.sliceH(y+8, t, b); + EXPECT_EQ(gfx::Rect(x,y,5,7), t); + EXPECT_EQ(gfx::Rect(0,0,0,0), b); +} + +TEST(Rect, NineSlice) +{ + const int x = 3, y = 4; + auto rect = gfx::Rect(x, y, 6, 6); + gfx::Rect slices[9]; + + // Slice using an inner rect. + rect.nineSlice(gfx::Rect(3, 3, 2, 2), slices); + EXPECT_EQ(gfx::Rect(x,y,6,6), rect); + EXPECT_EQ(gfx::Rect(x ,y ,3,3), slices[0]); + EXPECT_EQ(gfx::Rect(x+3,y ,2,3), slices[1]); + EXPECT_EQ(gfx::Rect(x+5,y ,1,3), slices[2]); + EXPECT_EQ(gfx::Rect(x ,y+3,3,2), slices[3]); + EXPECT_EQ(gfx::Rect(x+3,y+3,2,2), slices[4]); + EXPECT_EQ(gfx::Rect(x+5,y+3,1,2), slices[5]); + EXPECT_EQ(gfx::Rect(x ,y+5,3,1), slices[6]); + EXPECT_EQ(gfx::Rect(x+3,y+5,2,1), slices[7]); + EXPECT_EQ(gfx::Rect(x+5,y+5,1,1), slices[8]); + + // Slice using a center rect with the same size as the rect being sliced. + rect.nineSlice(gfx::Rect(0, 0, 6, 6), slices); + EXPECT_EQ(gfx::Rect(x,y,6,6), rect); + EXPECT_EQ(gfx::Rect(x ,y ,0,0), slices[0]); + EXPECT_EQ(gfx::Rect(x ,y ,6,0), slices[1]); + EXPECT_EQ(gfx::Rect(x+6,y ,0,0), slices[2]); + EXPECT_EQ(gfx::Rect(x ,y ,0,6), slices[3]); + EXPECT_EQ(gfx::Rect(x ,y ,6,6), slices[4]); + EXPECT_EQ(gfx::Rect(x+6,y ,0,6), slices[5]); + EXPECT_EQ(gfx::Rect(x ,y+6,0,0), slices[6]); + EXPECT_EQ(gfx::Rect(x ,y+6,6,0), slices[7]); + EXPECT_EQ(gfx::Rect(x+6,y+6,0,0), slices[8]); + + // Slice using an outer rect. + rect.nineSlice(gfx::Rect(-1, -1, 8, 8), slices); + EXPECT_EQ(gfx::Rect(x,y,6,6), rect); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[0]); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[1]); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[2]); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[3]); + EXPECT_EQ(gfx::Rect(x,y,6,6), slices[4]); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[5]); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[6]); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[7]); + EXPECT_EQ(gfx::Rect(0,0,0,0), slices[8]); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv);