Przeglądaj źródła

Point and Rect now reside in library

Ivan Savenko 2 lat temu
rodzic
commit
9a30484183

+ 15 - 17
client/gui/Geometries.cpp

@@ -1,4 +1,5 @@
 /*
+ *
  * Geometries.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
@@ -7,32 +8,29 @@
  * Full text of license available in license.txt file, in main folder
  *
  */
+
 #include "StdInc.h"
 #include "Geometries.h"
-#include "../CMT.h"
-#include <SDL_events.h>
-#include "../../lib/int3.h"
 
-Point::Point(const int3 &a)
-	:x(a.x),y(a.y)
-{}
-
-Point::Point(const SDL_MouseMotionEvent &a)
-	:x(a.x),y(a.y)
-{}
+#include <SDL_rect.h>
+#include <SDL_events.h>
 
-Rect Rect::createCentered( int w, int h )
+Rect Geometry::fromSDL(const SDL_Rect & rect)
 {
-	return Rect(screen->w/2 - w/2, screen->h/2 - h/2, w, h);
+	return Rect(Point(rect.x, rect.y), Point(rect.w, rect.h));
 }
 
-Rect Rect::around(const Rect &r, int width)
+SDL_Rect Geometry::toSDL(const Rect & rect)
 {
-	return Rect(r.x - width, r.y - width, r.w + width * 2, r.h + width * 2);
+	SDL_Rect result;
+	result.x = rect.x;
+	result.y = rect.y;
+	result.w = rect.w;
+	result.h = rect.h;
+	return result;
 }
 
-Rect Rect::centerIn(const Rect &r)
+Point Geometry::fromSDL(const SDL_MouseMotionEvent & motion)
 {
-	return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h);
+	return { motion.x, motion.y };
 }
-

+ 17 - 224
client/gui/Geometries.h

@@ -9,241 +9,34 @@
  */
 #pragma once
 
-#include <SDL2/SDL_rect.h>
-
-enum class ETextAlignment {TOPLEFT, CENTER, BOTTOMRIGHT};
-
 struct SDL_MouseMotionEvent;
+struct SDL_Rect;
+
+#include "../../lib/Point.h"
+#include "../../lib/Rect.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 class int3;
 VCMI_LIB_NAMESPACE_END
 
-// A point with x/y coordinate, used mostly for graphic rendering
-struct Point
-{
-	int x, y;
-
-	//constructors
-	Point()
-	{
-		x = y = 0;
-	};
-
-	Point(int X, int Y)
-		:x(X),y(Y)
-	{};
-
-	Point(const int3 &a);
-
-	explicit Point(const SDL_MouseMotionEvent &a);
-
-	template<typename T>
-	Point operator+(const T &b) const
-	{
-		return Point(x+b.x,y+b.y);
-	}
-
-	template<typename T>
-	Point operator/(const T &div) const
-	{
-		return Point(x/div, y/div);
-	}
+#ifdef VCMI_LIB_NAMESPACE
+using VCMI_LIB_WRAP_NAMESPACE(Rect);
+using VCMI_LIB_WRAP_NAMESPACE(Point);
+#endif
 
-	template<typename T>
-	Point operator*(const T &mul) const
-	{
-		return Point(x*mul, y*mul);
-	}
-
-	template<typename T>
-	Point& operator+=(const T &b)
-	{
-		x += b.x;
-		y += b.y;
-		return *this;
-	}
-
-	template<typename T>
-	Point operator-(const T &b) const
-	{
-		return Point(x - b.x, y - b.y);
-	}
-
-	template<typename T>
-	Point& operator-=(const T &b)
-	{
-		x -= b.x;
-		y -= b.y;
-		return *this;
-	}
-
-	template<typename T> Point& operator=(const T &t)
-	{
-		x = t.x;
-		y = t.y;
-		return *this;
-	}
-	template<typename T> bool operator==(const T &t) const
-	{
-		return x == t.x  &&  y == t.y;
-	}
-	template<typename T> bool operator!=(const T &t) const
-	{
-		return !(*this == t);
-	}
-};
+enum class ETextAlignment {TOPLEFT, CENTER, BOTTOMRIGHT};
 
-/// Rectangle class, which have a position and a size
-struct Rect : public SDL_Rect
+namespace Geometry
 {
-	Rect()
-	{
-		x = y = w = h = -1;
-	}
-	Rect(int X, int Y, int W, int H)
-	{
-		x = X;
-		y = Y;
-		w = W;
-		h = H;
-	}
-	Rect(const Point & position, const Point & size)
-	{
-		x = position.x;
-		y = position.y;
-		w = size.x;
-		h = size.y;
-	}
-	Rect(const SDL_Rect & r)
-	{
-		x = r.x;
-		y = r.y;
-		w = r.w;
-		h = r.h;
-	}
-	Rect(const Rect& r) = default;
-
-	Rect centerIn(const Rect &r);
-	static Rect createCentered(int w, int h);
-	static Rect around(const Rect &r, int width = 1);
-
-	bool isIn(int qx, int qy) const
-	{
-		if (qx > x   &&   qx<x+w   &&   qy>y   &&   qy<y+h)
-			return true;
-		return false;
-	}
-	bool isIn(const Point & q) const
-	{
-		return isIn(q.x,q.y);
-	}
-	Point topLeft() const
-	{
-		return Point(x,y);
-	}
-	Point topRight() const
-	{
-		return Point(x+w,y);
-	}
-	Point bottomLeft() const
-	{
-		return Point(x,y+h);
-	}
-	Point bottomRight() const
-	{
-		return Point(x+w,y+h);
-	}
-	Point center() const
-	{
-		return Point(x+w/2,y+h/2);
-	}
-	Point dimensions() const
-	{
-		return Point(w,h);
-	}
-
-	void moveTo(const Point & dest)
-	{
-		x = dest.x;
-		y = dest.y;
-	}
-
-	Rect operator+(const Point &p) const
-	{
-		return Rect(x+p.x,y+p.y,w,h);
-	}
-
-	Rect& operator=(const Rect &p)
-	{
-		x = p.x;
-		y = p.y;
-		w = p.w;
-		h = p.h;
-		return *this;
-	}
 
-	Rect& operator+=(const Point &p)
-	{
-		x += p.x;
-		y += p.y;
-		return *this;
-	}
+/// creates Point using provided event
+Point fromSDL(const SDL_MouseMotionEvent & motion);
 
-	Rect& operator-=(const Point &p)
-	{
-		x -= p.x;
-		y -= p.y;
-		return *this;
-	}
+/// creates Rect using provided rect
+Rect fromSDL(const SDL_Rect & rect);
 
-	Rect operator&(const Rect &p) const //rect intersection
-	{
-		bool intersect = true;
+/// creates SDL_Rect using provided rect
+SDL_Rect toSDL(const Rect & rect);
 
-		if(p.topLeft().y < y && p.bottomLeft().y < y) //rect p is above *this
-		{
-			intersect = false;
-		}
-		else if(p.topLeft().y > y+h && p.bottomLeft().y > y+h) //rect p is below *this
-		{
-			intersect = false;
-		}
-		else if(p.topLeft().x > x+w && p.topRight().x > x+w) //rect p is on the right hand side of this
-		{
-			intersect = false;
-		}
-		else if(p.topLeft().x < x && p.topRight().x < x) //rect p is on the left hand side of this
-		{
-			intersect = false;
-		}
+}
 
-		if(intersect)
-		{
-			Rect ret;
-			ret.x = std::max(this->x, p.x);
-			ret.y = std::max(this->y, p.y);
-			Point bR; //bottomRight point of returned rect
-			bR.x = std::min(this->w+this->x, p.w+p.x);
-			bR.y = std::min(this->h+this->y, p.h+p.y);
-			ret.w = bR.x - ret.x;
-			ret.h = bR.y - ret.y;
-			return ret;
-		}
-		else
-		{
-			return Rect();
-		}
-	}
-	Rect operator|(const Rect &p) const //union of two rects
-	{
-		Rect ret;
-		ret.x =  std::min(p.x, this->x);
-		ret.y =  std::min(p.y, this->y);
-		int x2 = std::max(p.x+p.w, this->x+this->w);
-		int y2 = std::max(p.y+p.h, this->y+this->h);
-		ret.w = x2 -ret.x;
-		ret.h = y2 -ret.y;
-		return ret;
-	}
-};

+ 3 - 0
cmake_modules/VCMI_lib.cmake

@@ -442,6 +442,9 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/NetPacksLobby.h
 		${MAIN_LIB_DIR}/ObstacleHandler.h
 		${MAIN_LIB_DIR}/PathfinderUtil.h
+		${MAIN_LIB_DIR}/Point.h
+		${MAIN_LIB_DIR}/Rect.h
+		${MAIN_LIB_DIR}/Rect.cpp
 		${MAIN_LIB_DIR}/ResourceSet.h
 		${MAIN_LIB_DIR}/RiverHandler.h
 		${MAIN_LIB_DIR}/RoadHandler.h

+ 96 - 0
lib/Point.h

@@ -0,0 +1,96 @@
+/*
+ * Geometries.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+class int3;
+
+// A point with x/y coordinate, used mostly for graphic rendering
+class Point
+{
+public:
+	int x, y;
+
+	//constructors
+	Point()
+	{
+		x = y = 0;
+	};
+
+	Point(int X, int Y)
+		:x(X),y(Y)
+	{};
+
+	Point(const int3 &a);
+
+	template<typename T>
+	Point operator+(const T &b) const
+	{
+		return Point(x+b.x,y+b.y);
+	}
+
+	template<typename T>
+	Point operator/(const T &div) const
+	{
+		return Point(x/div, y/div);
+	}
+
+	template<typename T>
+	Point operator*(const T &mul) const
+	{
+		return Point(x*mul, y*mul);
+	}
+
+	template<typename T>
+	Point& operator+=(const T &b)
+	{
+		x += b.x;
+		y += b.y;
+		return *this;
+	}
+
+	template<typename T>
+	Point operator-(const T &b) const
+	{
+		return Point(x - b.x, y - b.y);
+	}
+
+	template<typename T>
+	Point& operator-=(const T &b)
+	{
+		x -= b.x;
+		y -= b.y;
+		return *this;
+	}
+
+	template<typename T> Point& operator=(const T &t)
+	{
+		x = t.x;
+		y = t.y;
+		return *this;
+	}
+	template<typename T> bool operator==(const T &t) const
+	{
+		return x == t.x  &&  y == t.y;
+	}
+	template<typename T> bool operator!=(const T &t) const
+	{
+		return !(*this == t);
+	}
+
+	template <typename Handler>
+	void serialize(Handler &h, const int version)
+	{
+		h & x;
+		h & y;
+	}
+};
+
+VCMI_LIB_NAMESPACE_END

+ 133 - 0
lib/Rect.cpp

@@ -0,0 +1,133 @@
+/*
+ * ResourceSet.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "Rect.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+/// Returns rect union - rect that covers both this rect and provided rect
+Rect Rect::include(const Rect & other) const
+{
+	Point topLeft{
+		std::min(this->topLeft().x, other.topLeft().x),
+		std::min(this->topLeft().y, other.topLeft().y)
+	};
+
+	Point bottomRight{
+		std::max(this->bottomRight().x, other.bottomRight().x),
+		std::max(this->bottomRight().y, other.bottomRight().y)
+	};
+
+	return Rect(topLeft, bottomRight - topLeft);
+
+}
+
+Rect Rect::createCentered( const Point & around, const Point & dimensions )
+{
+	return Rect(around - dimensions/2, dimensions);
+}
+
+Rect Rect::createAround(const Rect &r, int width)
+{
+	return Rect(r.x - width, r.y - width, r.w + width * 2, r.h + width * 2);
+}
+
+Rect Rect::createCentered( const Rect & rect, const Point & dimensions)
+{
+	return createCentered(rect.center(), dimensions);
+}
+
+bool Rect::intersectionTest(const Rect & other) const
+{
+	// this rect is above other rect
+	if(this->bottomLeft().y < other.topLeft().y)
+		return false;
+
+	// this rect is below other rect
+	if(this->topLeft().y > other.bottomLeft().y )
+		return false;
+
+	// this rect is to the left of other rect
+	if(this->topRight().x < other.topLeft().x)
+		return false;
+
+	// this rect is to the right of other rect
+	if(this->topLeft().x > other.topRight().x)
+		return false;
+
+	return true;
+}
+
+/// Algorithm to test whether line segment between points line1-line2 will intersect with
+/// rectangle specified by top-left and bottom-right points
+/// Note that in order to avoid floating point rounding errors algorithm uses integers with no divisions
+bool Rect::intersectionTest(const Point & line1, const Point & line2) const
+{
+	// check whether segment is located to the left of our rect
+	if (line1.x < topLeft().x && line2.x < topLeft().x)
+		return false;
+
+	// check whether segment is located to the right of our rect
+	if (line1.x > bottomRight().x && line2.x > bottomRight().x)
+		return false;
+
+	// check whether segment is located on top of our rect
+	if (line1.y < topLeft().y && line2.y < topLeft().y)
+		return false;
+
+	// check whether segment is located below of our rect
+	if (line1.y > bottomRight().y && line2.y > bottomRight().y)
+		return false;
+
+	Point vector { line2.x - line1.x, line2.y - line1.y};
+
+	// compute position of corners relative to our line
+	int tlTest = vector.y*topLeft().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
+	int trTest = vector.y*bottomRight().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
+	int blTest = vector.y*topLeft().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
+	int brTest = vector.y*bottomRight().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
+
+	// if all points are on the left of our line then there is no intersection
+	if ( tlTest > 0 && trTest > 0 && blTest > 0 && brTest > 0 )
+		return false;
+
+	// if all points are on the right of our line then there is no intersection
+	if ( tlTest < 0 && trTest < 0 && blTest < 0 && brTest < 0 )
+		return false;
+
+	// if all previous checks failed, this means that there is an intersection between line and AABB
+	return true;
+}
+
+
+Rect Rect::intersect(const Rect & other) const
+{
+	if(intersectionTest(other))
+	{
+		Point topLeft{
+			std::max(this->topLeft().x, other.topLeft().x),
+			std::max(this->topLeft().y, other.topLeft().y)
+		};
+
+		Point bottomRight{
+			std::min(this->bottomRight().x, other.bottomRight().x),
+			std::min(this->bottomRight().y, other.bottomRight().y)
+		};
+
+		return Rect(topLeft, bottomRight - topLeft);
+	}
+	else
+	{
+		return Rect();
+	}
+}
+
+VCMI_LIB_NAMESPACE_END

+ 155 - 0
lib/Rect.h

@@ -0,0 +1,155 @@
+/*
+ * Geometries.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "Point.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+/// Rectangle class, which have a position and a size
+class Rect
+{
+public:
+	int x;
+	int y;
+	int w;
+	int h;
+
+	Rect()
+	{
+		x = y = w = h = -1;
+	}
+	Rect(int X, int Y, int W, int H)
+	{
+		x = X;
+		y = Y;
+		w = W;
+		h = H;
+	}
+	Rect(const Point & position, const Point & size)
+	{
+		x = position.x;
+		y = position.y;
+		w = size.x;
+		h = size.y;
+	}
+	Rect(const Rect& r) = default;
+
+	DLL_LINKAGE static Rect createCentered( const Point & around, const Point & size );
+	DLL_LINKAGE static Rect createCentered( const Rect  & target, const Point & size );
+	DLL_LINKAGE static Rect createAround(const Rect &r, int borderWidth);
+
+	bool isIn(int qx, int qy) const
+	{
+		if (qx > x && qx<x+w && qy>y && qy<y+h)
+			return true;
+		return false;
+	}
+	bool isIn(const Point & q) const
+	{
+		return isIn(q.x,q.y);
+	}
+	int top() const
+	{
+		return y;
+	}
+	int bottom() const
+	{
+		return y+h;
+	}
+	int left() const
+	{
+		return x;
+	}
+	int right() const
+	{
+		return x+w;
+	}
+
+	Point topLeft() const
+	{
+		return Point(x,y);
+	}
+	Point topRight() const
+	{
+		return Point(x+w,y);
+	}
+	Point bottomLeft() const
+	{
+		return Point(x,y+h);
+	}
+	Point bottomRight() const
+	{
+		return Point(x+w,y+h);
+	}
+	Point center() const
+	{
+		return Point(x+w/2,y+h/2);
+	}
+	Point dimensions() const
+	{
+		return Point(w,h);
+	}
+
+	void moveTo(const Point & dest)
+	{
+		x = dest.x;
+		y = dest.y;
+	}
+
+	Rect operator+(const Point &p) const
+	{
+		return Rect(x+p.x,y+p.y,w,h);
+	}
+
+	Rect& operator=(const Rect &p)
+	{
+		x = p.x;
+		y = p.y;
+		w = p.w;
+		h = p.h;
+		return *this;
+	}
+
+	Rect& operator+=(const Point &p)
+	{
+		x += p.x;
+		y += p.y;
+		return *this;
+	}
+
+	Rect& operator-=(const Point &p)
+	{
+		x -= p.x;
+		y -= p.y;
+		return *this;
+	}
+
+	/// returns true if this rect intersects with another rect
+	DLL_LINKAGE bool intersectionTest(const Rect & other) const;
+
+	/// returns true if this rect intersects with line specified by two points
+	DLL_LINKAGE bool intersectionTest(const Point & line1, const Point & line2) const;
+
+	/// Returns rect that represents intersection of two rects
+	DLL_LINKAGE Rect intersect(const Rect & other) const;
+
+	/// Returns rect union - rect that covers both this rect and provided rect
+	DLL_LINKAGE Rect include(const Rect & other) const;
+
+	template <typename Handler>
+	void serialize(Handler &h, const int version)
+	{
+		h & x;
+		h & y;
+	}
+};
+
+VCMI_LIB_NAMESPACE_END

+ 6 - 52
lib/battle/CBattleInfoCallback.cpp

@@ -20,6 +20,7 @@
 #include "../mapObjects/CGTownInstance.h"
 #include "../BattleFieldHandler.h"
 #include "../CModHandler.h"
+#include "../Rect.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -131,55 +132,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
 	return ESpellCastProblem::OK;
 }
 
-struct Point
-{
-	int x,y;
-};
-
-/// Algorithm to test whether line segment between points line1-line2 will intersect with
-/// rectangle specified by top-left and bottom-right points
-/// Note that in order to avoid floating point rounding errors algorithm uses integers with no divisions
-static bool intersectionSegmentRect(Point line1, Point line2, Point rectTL, Point rectBR)
-{
-	assert(rectTL.x < rectBR.x);
-	assert(rectTL.y < rectBR.y);
-
-	// check whether segment is located to the left of our AABB
-	if (line1.x < rectTL.x && line2.x < rectTL.x)
-		return false;
-
-	// check whether segment is located to the right of our AABB
-	if (line1.x > rectBR.x && line2.x > rectBR.x)
-		return false;
-
-	// check whether segment is located on top of our AABB
-	if (line1.y < rectTL.y && line2.y < rectTL.y)
-		return false;
-
-	// check whether segment is located below of our AABB
-	if (line1.y > rectBR.y && line2.y > rectBR.y)
-		return false;
-
-	Point vector { line2.x - line1.x, line2.y - line1.y};
-
-	// compute position of AABB corners relative to our line
-	int tlTest = vector.y*rectTL.x - vector.x*rectTL.y + (line2.x*line1.y-line1.x*line2.y);
-	int trTest = vector.y*rectBR.x - vector.x*rectTL.y + (line2.x*line1.y-line1.x*line2.y);
-	int blTest = vector.y*rectTL.x - vector.x*rectBR.y + (line2.x*line1.y-line1.x*line2.y);
-	int brTest = vector.y*rectBR.x - vector.x*rectBR.y + (line2.x*line1.y-line1.x*line2.y);
-
-	// if all points are on the left of our line then there is no intersection
-	if ( tlTest > 0 && trTest > 0 && blTest > 0 && brTest > 0 )
-		return false;
-
-	// if all points are on the right of our line then there is no intersection
-	if ( tlTest < 0 && trTest < 0 && blTest < 0 && brTest < 0 )
-		return false;
-
-	// if all previous checks failed, this means that there is an intersection between line and AABB
-	return true;
-}
-
 bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const
 {
 	auto isTileBlocked = [&](BattleHex tile)
@@ -214,10 +166,12 @@ bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, Bat
 				continue;
 
 			// create rect around cell with an obstacle
-			Point rectTL{ obstacle.getX()*cellSize, obstacle.getY()*cellSize };
-			Point recrBR{ obstacle.getX()*(cellSize+1), obstacle.getY()*(cellSize+1) };
+			Rect rect {
+				Point(obstacle.getX(), obstacle.getY()) * cellSize,
+				Point( cellSize, cellSize)
+			};
 
-			if ( intersectionSegmentRect(line1, line2, rectTL, recrBR))
+			if ( rect.intersectionTest(line1, line2))
 				return true;
 		}
 		return false;