From f4823de989e6094c21528ef7a399630e1dbcc53b Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Mon, 29 Dec 2014 21:54:14 +0300 Subject: [PATCH 1/9] Add Point memberwise division/multiplication --- SDL2pp/Point.cc | 22 +++++++++++++++++++++ SDL2pp/Point.hh | 52 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/SDL2pp/Point.cc b/SDL2pp/Point.cc index b2e7cdb..7a48881 100644 --- a/SDL2pp/Point.cc +++ b/SDL2pp/Point.cc @@ -88,6 +88,14 @@ Point Point::operator-(const Point& other) const { return Point(x - other.x, y - other.y); } +Point Point::operator/(int value) const { + return Point(x / value, y / value); +} + +Point Point::operator*(int value) const { + return Point(x * value, y * value); +} + Point& Point::operator+=(const Point& other) { x += other.x; y += other.y; @@ -102,4 +110,18 @@ Point& Point::operator-=(const Point& other) { return *this; } +Point& Point::operator/=(int value) { + x /= value; + y /= value; + + return *this; +} + +Point& Point::operator*=(int value) { + x *= value; + y *= value; + + return *this; +} + } diff --git a/SDL2pp/Point.hh b/SDL2pp/Point.hh index 98bcaaf..4fe66cb 100644 --- a/SDL2pp/Point.hh +++ b/SDL2pp/Point.hh @@ -159,27 +159,47 @@ public: void SetY(int ny); //////////////////////////////////////////////////////////// - /// \brief Get sum of two points + /// \brief Get point's memberwise addition with another point /// /// \param other Point to add /// - /// \returns New Point representing memberwise addition of two points + /// \returns New Point representing memberwise addition with another point /// //////////////////////////////////////////////////////////// Point operator+(const Point& other) const; //////////////////////////////////////////////////////////// - /// \brief Get subtraction of two points + /// \brief Get point's memberwise subtraction with another point /// /// \param other Point to subtract /// - /// \returns New Point representing memberwise subtraction of two points + /// \returns New Point representing memberwise subtraction of another point /// //////////////////////////////////////////////////////////// Point operator-(const Point& other) const; //////////////////////////////////////////////////////////// - /// \brief Add another point + /// \brief Get point's memberwise division by an integer + /// + /// \param value Divisor + /// + /// \returns New Point representing memberwise division of point by and integer + /// + //////////////////////////////////////////////////////////// + Point operator/(int value) const; + + //////////////////////////////////////////////////////////// + /// \brief Get point's memberwise multiplication by an integer + /// + /// \param value Multiplier + /// + /// \returns New Point representing memberwise multiplication of point by an integer + /// + //////////////////////////////////////////////////////////// + Point operator*(int value) const; + + //////////////////////////////////////////////////////////// + /// \brief Memberwise add another point /// /// \param other Point to add to the current one /// @@ -189,7 +209,7 @@ public: Point& operator+=(const Point& other); //////////////////////////////////////////////////////////// - /// \brief Substact another point + /// \brief Memberwise subtract another point /// /// \param other Point to subtract from the current one /// @@ -197,6 +217,26 @@ public: /// //////////////////////////////////////////////////////////// Point& operator-=(const Point& other); + + //////////////////////////////////////////////////////////// + /// \brief Memberwise divide by an inteher + /// + /// \param value Divisor + /// + /// \returns Reference to self + /// + //////////////////////////////////////////////////////////// + Point& operator/=(int value); + + //////////////////////////////////////////////////////////// + /// \brief Memberwise multiply by an integer + /// + /// \param value Multiplier + /// + /// \returns Reference to self + /// + //////////////////////////////////////////////////////////// + Point& operator*=(int value); }; } From e18f54d30270a30880a48303dd6bd854d4ad569c Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Mon, 29 Dec 2014 21:57:09 +0300 Subject: [PATCH 2/9] Add test for Point/Rect construction and comparison from/with corresponding SDL objects --- tests/test_pointrect.cc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/test_pointrect.cc b/tests/test_pointrect.cc index 4fb529c..58daf22 100644 --- a/tests/test_pointrect.cc +++ b/tests/test_pointrect.cc @@ -163,4 +163,23 @@ BEGIN_TEST() EXPECT_TRUE(r == Rect(-9, -18, 3, 4)); } + + { + // Construction from and comparison with SDL objects + SDL_Rect sdlrect = { 1, 2, 3, 4 }; + + SDL_Point sdlpoint = { 6, 7 }; + + EXPECT_TRUE(Rect(sdlrect) == Rect(1, 2, 3, 4)); + EXPECT_TRUE(Point(sdlpoint) == Point(6, 7)); + + EXPECT_TRUE(Rect(sdlrect) != Rect(0, 2, 3, 4)); + EXPECT_TRUE(Point(sdlpoint) != Point(0, 7)); + + EXPECT_TRUE(Rect(1, 2, 3, 4) == sdlrect); + EXPECT_TRUE(Point(6, 7) == sdlpoint); + + EXPECT_TRUE(Rect(0, 2, 3, 4) != sdlrect); + EXPECT_TRUE(Point(0, 7) != sdlpoint); + } END_TEST() From 518f9fff35aec928945945f49ebadfa9c648562f Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Mon, 29 Dec 2014 22:00:49 +0300 Subject: [PATCH 3/9] Add test for multiplication/division --- tests/test_pointrect.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_pointrect.cc b/tests/test_pointrect.cc index 58daf22..9e8597d 100644 --- a/tests/test_pointrect.cc +++ b/tests/test_pointrect.cc @@ -66,6 +66,15 @@ BEGIN_TEST() EXPECT_TRUE(sum.GetX() == 111 && sum.GetY() == 222); EXPECT_TRUE(diff.GetX() == -111 && diff.GetY() == -222); + + sum /= 111; + diff *= 2; + + EXPECT_TRUE(sum == Point(1, 2)); + EXPECT_TRUE(diff == Point(-222, -444)); + + EXPECT_TRUE(sum * 2 == Point(2, 4)); + EXPECT_TRUE(diff / 2 == Point(-111, -222)); } { From 7506b05a7764382bdda50049e58d261af83f5fd4 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Mon, 29 Dec 2014 22:04:43 +0300 Subject: [PATCH 4/9] Implement Rect::Contains(Rect), add corresponding test --- SDL2pp/Rect.cc | 4 ++++ SDL2pp/Rect.hh | 10 ++++++++++ tests/test_pointrect.cc | 9 +++++++++ 3 files changed, 23 insertions(+) diff --git a/SDL2pp/Rect.cc b/SDL2pp/Rect.cc index 9b739e9..55d41c7 100644 --- a/SDL2pp/Rect.cc +++ b/SDL2pp/Rect.cc @@ -129,6 +129,10 @@ bool Rect::Contains(const Point& point) const { return !(point.x < x || point.y < y || point.x > GetX2() || point.y > GetY2()); } +bool Rect::Contains(const Rect& rect) const { + return rect.x >= x && rect.y >= y && rect.GetX2() <= GetX2() && rect.GetY2() <= GetY2(); +} + Rect Rect::operator+(const Point& offset) const { return Rect(x + offset.x, y + offset.y, w, h); } diff --git a/SDL2pp/Rect.hh b/SDL2pp/Rect.hh index 4439396..58305d3 100644 --- a/SDL2pp/Rect.hh +++ b/SDL2pp/Rect.hh @@ -253,6 +253,16 @@ public: //////////////////////////////////////////////////////////// bool Contains(const Point& point) const; + //////////////////////////////////////////////////////////// + /// \brief Check whether the rect contains another rect + /// + /// \param rect Rect to check + /// + /// \returns True if the checked rect is contained in this rect + /// + //////////////////////////////////////////////////////////// + bool Contains(const Rect& rect) const; + //////////////////////////////////////////////////////////// /// \brief Get rectangle moved by a given offset /// diff --git a/tests/test_pointrect.cc b/tests/test_pointrect.cc index 9e8597d..beaac28 100644 --- a/tests/test_pointrect.cc +++ b/tests/test_pointrect.cc @@ -155,6 +155,15 @@ BEGIN_TEST() EXPECT_TRUE(!r.Contains(Point(10, 19))); EXPECT_TRUE(!r.Contains(Point(15, 20))); EXPECT_TRUE(!r.Contains(Point(10, 25))); + + // Rect contains rect + EXPECT_TRUE(r.Contains(r)); + EXPECT_TRUE(r.Contains(Rect(11, 21, 3, 3))); + + EXPECT_TRUE(!r.Contains(Rect(9, 20, 5, 5))); + EXPECT_TRUE(!r.Contains(Rect(10, 19, 5, 5))); + EXPECT_TRUE(!r.Contains(Rect(10, 20, 6, 5))); + EXPECT_TRUE(!r.Contains(Rect(10, 20, 5, 6))); } { From a5d558b1c10fb93c89e5745d29a09d3d0ed8c49d Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Tue, 30 Dec 2014 00:12:54 +0300 Subject: [PATCH 5/9] Remove unused includes --- SDL2pp/Point.cc | 2 -- SDL2pp/Rect.cc | 2 -- 2 files changed, 4 deletions(-) diff --git a/SDL2pp/Point.cc b/SDL2pp/Point.cc index 7a48881..5f71f00 100644 --- a/SDL2pp/Point.cc +++ b/SDL2pp/Point.cc @@ -19,8 +19,6 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include - #include namespace SDL2pp { diff --git a/SDL2pp/Rect.cc b/SDL2pp/Rect.cc index 55d41c7..bad4cd2 100644 --- a/SDL2pp/Rect.cc +++ b/SDL2pp/Rect.cc @@ -19,8 +19,6 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include - #include #include From 837772dac0e3c77bba909d23215d1c6e9742ed34 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Tue, 30 Dec 2014 00:13:27 +0300 Subject: [PATCH 6/9] Add various Rect constructors --- SDL2pp/Rect.cc | 19 +++++++++++++++++++ SDL2pp/Rect.hh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/SDL2pp/Rect.cc b/SDL2pp/Rect.cc index bad4cd2..05cfb78 100644 --- a/SDL2pp/Rect.cc +++ b/SDL2pp/Rect.cc @@ -39,6 +39,13 @@ Rect::Rect(const SDL_Rect& rect) { h = rect.h; } +Rect::Rect(const Point& corner, const Point& size) { + x = corner.x; + y = corner.y; + w = size.x; + h = size.y; +} + Rect::Rect(int nx, int ny, int nw, int nh) { x = nx; y = ny; @@ -71,6 +78,18 @@ Rect Rect::FromCenter(int cx, int cy, int w, int h) { return Rect(cx - w/2, cy - h/2, w, h); } +Rect Rect::FromCenter(const Point& center, const Point& size) { + return Rect(center - size / 2, size); +} + +Rect Rect::FromCorners(int x1, int y1, int x2, int y2) { + return Rect(x1, y1, x2 - x1 + 1, y2 - y1 + 1); +} + +Rect Rect::FromCorners(const Point& p1, const Point& p2) { + return Rect(p1, p2 - p1 + Point(1, 1)); +} + bool Rect::IsNull() const { return false; } diff --git a/SDL2pp/Rect.hh b/SDL2pp/Rect.hh index 58305d3..bedf764 100644 --- a/SDL2pp/Rect.hh +++ b/SDL2pp/Rect.hh @@ -66,6 +66,15 @@ public: //////////////////////////////////////////////////////////// Rect(const SDL_Rect& rect); + //////////////////////////////////////////////////////////// + /// \brief Construct the rect from given corner coordinates, and size + /// + /// \param corner Coordinates of the top left rectangle corner + /// \param size Dimensions of the rectangle + /// + //////////////////////////////////////////////////////////// + Rect(const Point& corner, const Point& size); + //////////////////////////////////////////////////////////// /// \brief Construct the rect from given corner coordinates, width and height /// @@ -90,6 +99,35 @@ public: //////////////////////////////////////////////////////////// static Rect FromCenter(int cx, int cy, int w, int h); + //////////////////////////////////////////////////////////// + /// \brief Construct the rect from given center coordinates and size + /// + /// \param center Coordinates of the rectangle center + /// \param size Dimensions of the rectangle + /// + //////////////////////////////////////////////////////////// + static Rect FromCenter(const Point& center, const Point& size); + + //////////////////////////////////////////////////////////// + /// \brief Construct the rect from given center coordinates, width and height + /// + /// \param x1 X coordinate of the top left rectangle corner + /// \param y1 Y coordinate of the top left rectangle corner + /// \param x2 X coordinate of the bottom right rectangle corner + /// \param y2 Y coordinate of the bottom right rectangle corner + /// + //////////////////////////////////////////////////////////// + static Rect FromCorners(int x1, int y1, int x2, int y2); + + //////////////////////////////////////////////////////////// + /// \brief Construct the rect from given center coordinates and size + /// + /// \param p1 Coordinates of the top left rectangle corner + /// \param p2 Coordinates of the bottom right rectangle corner + /// + //////////////////////////////////////////////////////////// + static Rect FromCorners(const Point& p1, const Point& p2); + //////////////////////////////////////////////////////////// /// \brief Copy constructor /// From c584b1a00593a07bfd572a3a7fea0cf4b0890093 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Tue, 30 Dec 2014 00:14:14 +0300 Subject: [PATCH 7/9] Add Rect intersection and union methods --- SDL2pp/Rect.cc | 27 +++++++++++++++++++++++++++ SDL2pp/Rect.hh | 30 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/SDL2pp/Rect.cc b/SDL2pp/Rect.cc index 05cfb78..b2bb830 100644 --- a/SDL2pp/Rect.cc +++ b/SDL2pp/Rect.cc @@ -19,6 +19,8 @@ 3. This notice may not be removed or altered from any source distribution. */ +#include + #include #include @@ -150,6 +152,31 @@ bool Rect::Contains(const Rect& rect) const { return rect.x >= x && rect.y >= y && rect.GetX2() <= GetX2() && rect.GetY2() <= GetY2(); } +bool Rect::Intersects(const Rect& rect) const { + return !(rect.GetX2() < x || rect.GetY2() < y || rect.x > GetX2() || rect.y > GetY2()); +} + +Rect Rect::GetUnion(const Rect& rect) const { + return Rect::FromCorners( + std::min(x, rect.x), + std::min(y, rect.y), + std::max(GetX2(), rect.GetX2()), + std::max(GetY2(), rect.GetY2()) + ); +} + +Optional Rect::GetIntersection(const Rect& rect) const { + if (!Intersects(rect)) + return NullOpt; + + return Rect::FromCorners( + std::max(x, rect.x), + std::max(y, rect.y), + std::min(GetX2(), rect.GetX2()), + std::min(GetY2(), rect.GetY2()) + ); +} + Rect Rect::operator+(const Point& offset) const { return Rect(x + offset.x, y + offset.y, w, h); } diff --git a/SDL2pp/Rect.hh b/SDL2pp/Rect.hh index bedf764..cbf54e9 100644 --- a/SDL2pp/Rect.hh +++ b/SDL2pp/Rect.hh @@ -301,6 +301,36 @@ public: //////////////////////////////////////////////////////////// bool Contains(const Rect& rect) const; + //////////////////////////////////////////////////////////// + /// \brief Check whether the rect intersects another rect + /// + /// \param rect Rect to check + /// + /// \returns True if the rects intersect + /// + //////////////////////////////////////////////////////////// + bool Intersects(const Rect& rect) const; + + //////////////////////////////////////////////////////////// + /// \brief Calculate union with another rect + /// + /// \param rect Rect to union with + /// + /// \returns Rect representing intersection area or NullOpt if there was no intersection + /// + //////////////////////////////////////////////////////////// + Rect GetUnion(const Rect& rect) const; + + //////////////////////////////////////////////////////////// + /// \brief Calculate intersection with another rect + /// + /// \param rect Rect to intersect with + /// + /// \returns Rect representing intersection area or NullOpt if there was no intersection + /// + //////////////////////////////////////////////////////////// + Optional GetIntersection(const Rect& rect) const; + //////////////////////////////////////////////////////////// /// \brief Get rectangle moved by a given offset /// From 325a7fef2ac6637d72f28ccea7cb85afecd42e8b Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Tue, 30 Dec 2014 00:14:21 +0300 Subject: [PATCH 8/9] Simplify logic --- SDL2pp/Rect.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDL2pp/Rect.cc b/SDL2pp/Rect.cc index b2bb830..b9a1479 100644 --- a/SDL2pp/Rect.cc +++ b/SDL2pp/Rect.cc @@ -145,7 +145,7 @@ void Rect::SetY2(int y2) { } bool Rect::Contains(const Point& point) const { - return !(point.x < x || point.y < y || point.x > GetX2() || point.y > GetY2()); + return point.x >= x && point.y >= y && point.x <= GetX2() && point.y <= GetY2(); } bool Rect::Contains(const Rect& rect) const { From 5ea7b7fc895687b3173bfa54eb1dad176b16d2f5 Mon Sep 17 00:00:00 2001 From: Dmitry Marakasov Date: Tue, 30 Dec 2014 00:14:36 +0300 Subject: [PATCH 9/9] Update Rect tests --- tests/test_pointrect.cc | 67 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/tests/test_pointrect.cc b/tests/test_pointrect.cc index beaac28..7c387bb 100644 --- a/tests/test_pointrect.cc +++ b/tests/test_pointrect.cc @@ -138,10 +138,12 @@ BEGIN_TEST() } { - Rect r = Rect::FromCenter(100, 100, 5, 7); + // Constructors + EXPECT_TRUE(Rect::FromCenter(100, 100, 5, 7) == Rect(98, 97, 5, 7)); + EXPECT_TRUE(Rect::FromCenter(Point(100, 100), Point(5, 7)) == Rect(98, 97, 5, 7)); - EXPECT_TRUE(r.GetX() == 98 && r.GetY() == 97); - EXPECT_TRUE(r.GetX2() == 102 && r.GetY2() == 103); + EXPECT_TRUE(Rect::FromCorners(10, 20, 30, 40) == Rect(10, 20, 21, 21)); + EXPECT_TRUE(Rect::FromCorners(Point(10, 20), Point(30, 40)) == Rect(10, 20, 21, 21)); } { @@ -166,6 +168,65 @@ BEGIN_TEST() EXPECT_TRUE(!r.Contains(Rect(10, 20, 5, 6))); } + { + // Rect intersections + // test both GetIntersection() and Intersects() as the former uses the latter + Rect rect(10, 20, 30, 40); + + EXPECT_TRUE(rect.Intersects(rect)); + EXPECT_TRUE(rect.GetIntersection(rect) == rect); + + // simple intersection + EXPECT_TRUE(rect.GetIntersection(Rect(5, 15, 30, 40)) == Rect(10, 20, 25, 35)); + EXPECT_TRUE(rect.GetIntersection(Rect(15, 25, 30, 40)) == Rect(15, 25, 25, 35)); + + // larger at left + EXPECT_TRUE(rect.GetIntersection(Rect(0, 0, 10, 80)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(0, 0, 11, 80)) == Rect(10, 20, 1, 40)); + + // larger at top + EXPECT_TRUE(rect.GetIntersection(Rect(0, 0, 50, 20)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(0, 0, 50, 21)) == Rect(10, 20, 30, 1)); + + // larger at bottom + EXPECT_TRUE(rect.GetIntersection(Rect(0, 60, 50, 20)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(0, 59, 50, 20)) == Rect(10, 59, 30, 1)); + + // larger at right + EXPECT_TRUE(rect.GetIntersection(Rect(40, 0, 20, 80)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(39, 0, 20, 80)) == Rect(39, 20, 1, 40)); + + // smaller at left + EXPECT_TRUE(rect.GetIntersection(Rect(0, 30, 10, 20)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(0, 30, 20, 20)) == Rect(10, 30, 10, 20)); + + // smaller at top + EXPECT_TRUE(rect.GetIntersection(Rect(20, 10, 10, 10)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(20, 10, 10, 20)) == Rect(20, 20, 10, 10)); + + // smaller at bottom + EXPECT_TRUE(rect.GetIntersection(Rect(20, 60, 10, 10)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(20, 50, 10, 20)) == Rect(20, 50, 10, 10)); + + // smaller at right + EXPECT_TRUE(rect.GetIntersection(Rect(40, 30, 10, 20)) == NullOpt); + EXPECT_TRUE(rect.GetIntersection(Rect(30, 30, 20, 20)) == Rect(30, 30, 10, 20)); + + // smaller + EXPECT_TRUE(rect.GetIntersection(Rect(20, 30, 10, 20)) == Rect(20, 30, 10, 20)); + + // larger + EXPECT_TRUE(rect.GetIntersection(Rect(0, 0, 100, 100)) == rect); + } + + { + // Rect unions + EXPECT_TRUE(Rect(10, 20, 1, 1).GetUnion(Rect(30, 40, 1, 1)) == Rect::FromCorners(10, 20, 30, 40)); + EXPECT_TRUE(Rect(30, 20, 1, 1).GetUnion(Rect(10, 40, 1, 1)) == Rect::FromCorners(10, 20, 30, 40)); + EXPECT_TRUE(Rect(10, 40, 1, 1).GetUnion(Rect(30, 20, 1, 1)) == Rect::FromCorners(10, 20, 30, 40)); + EXPECT_TRUE(Rect(30, 40, 1, 1).GetUnion(Rect(10, 20, 1, 1)) == Rect::FromCorners(10, 20, 30, 40)); + } + { // Rect offset Rect r(1, 2, 3, 4);