//+----------------------------------------------------------------------------+ //| Description: Magic Set Editor - Program to make card games | //| Copyright: (C) Twan van Laarhoven and the other MSE developers | //| License: GNU General Public License 2 or later (see file COPYING) | //+----------------------------------------------------------------------------+ #pragma once /** @file util/real_point.hpp * * @brief Points and sizes with floating point (real) coordinates. */ // ----------------------------------------------------------------------------- : Includes #include #include // ----------------------------------------------------------------------------- : Point using doubles /// A point using real (double) coordinates typedef Vector2D RealPoint; /// A transformation function on a rect and an angle in degrees class RealRect; typedef std::function RectTransform; // ----------------------------------------------------------------------------- : Size using doubles /// A size (width,height) using real (double) coordinates class RealSize { public: double width; double height; inline RealSize() : width(0), height(0) {} inline RealSize(double w, double h) : width(w), height(h) {} inline RealSize(wxSize s) : width(s.x), height(s.y) {} inline explicit RealSize(const Vector2D& v) : width(v.x), height(v.y) {} /// size of an image inline explicit RealSize(const wxImage& img) : width(img.GetWidth()), height(img.GetHeight()) {} /// size of a bitmap inline explicit RealSize(const wxBitmap& img) : width(img.GetWidth()), height(img.GetHeight()) {} /// Negation of a size, negates both components inline RealSize operator - () const { return RealSize(-width, -height); } /// Multiplying a size by a scalar r, multiplies both components inline void operator *= (double r) { width *= r; height *= r; } /// Multiplying a size by a scalar r, multiplies both components inline RealSize operator * (double r) const { return RealSize(width * r, height * r); } /// Dividing a size by a scalar r, divides both components inline RealSize operator / (double r) const { return RealSize(width / r, height / r); } /// Can be converted to a wxSize, with integer components inline operator wxSize() { return wxSize(to_int(width), to_int(height)); } }; /// Add two sizes horizontally /** #### $$$ ####$$$ * #### + $$$ = ####$$$ * #### ####... */ inline RealSize add_horizontal(const RealSize& a, const RealSize& b) { return RealSize(a.width + b.width, max(a.height, b.height)); } /// Add two sizes vertically /** #### $$$ #### * #### + $$$ = #### * #### #### * $$$. * $$$. */ inline RealSize add_vertical(const RealSize& a, const RealSize& b) { return RealSize(max(a.width, b.width), a.height + b.height); } /// Add two sizes diagonally /** #### $$$ ####... * #### + $$$ = ####... * #### ####... * ....$$$ * ....$$$ */ inline RealSize add_diagonal(const RealSize& a, const RealSize& b) { return RealSize(a.width + b.width, a.height + b.height); } /// Piecewise minimum inline RealSize piecewise_min(const RealSize& a, const RealSize& b) { return RealSize( a.width < b.width ? a.width : b.width, a.height < b.height ? a.height : b.height ); } /// Piecewise maximum inline RealSize piecewise_max(const RealSize& a, const RealSize& b) { return RealSize( a.width < b.width ? b.width : a.width, a.height < b.height ? b.height : a.height ); } // ----------------------------------------------------------------------------- : Rectangle using doubles /// A rectangle (postion and size) using real (double) coordinats class RealRect : private RealPoint, private RealSize { public: using RealPoint::x; using RealPoint::y; using RealSize::width; using RealSize::height; inline RealRect(const wxRect& rect) : RealPoint(rect.x, rect.y), RealSize(rect.width, rect.height) {} inline RealRect(const RealPoint& position, const RealSize& size) : RealPoint(position), RealSize(size) {} inline RealRect(double x, double y, double w, double h) : RealPoint(x,y), RealSize(w,h) {} /// Position of the top left corner inline RealPoint& position() { return *this; } inline const RealPoint& position() const { return *this; } /// Size of the rectangle inline RealSize& size() { return *this; } inline const RealSize& size() const { return *this; } inline double left() const { return x; } inline double right() const { return x + width; } inline double top() const { return y; } inline double bottom() const { return y + height; } inline RealPoint topLeft () const { return *this; } inline RealPoint topRight () const { return RealPoint(x + width, y); } inline RealPoint bottomLeft () const { return RealPoint(x, y + height); } inline RealPoint bottomRight() const { return RealPoint(x + width, y + height); } /// Return a rectangle that is amount larger to all sides inline RealRect grow(double amount) const { return RealRect(x - amount, y - amount, width + 2 * amount, height + 2 * amount); } /// Move the coordinates by some amount inline RealRect move(double dx, double dy, double dw, double dh) const { return RealRect(x + dx, y + dy, width + dw, height + dh); } /// Return a rectangle that is the intersection between this and the given rectangle inline RealRect intersect(RealRect rect) const { double left = max(x, rect.x); double top = max(y, rect.y); double right = min(x + width, rect.x + rect.width); double bottom = min(y + height, rect.y + rect.height); return RealRect(left, top, right - left, bottom - top); } /// Transformation methods with the same signature for encoded rects inline static void scale(RealRect& rect, int& degrees, double scale_x, double scale_y, int unused = 0) { rect = RealRect(scale_x * rect.x, scale_y * rect.y, scale_x * rect.width, scale_y * rect.height); } inline static void translate(RealRect& rect, int& degrees, double offset_x, double offset_y, int unused = 0) { rect = RealRect(offset_x + rect.x, offset_y + rect.y, rect.width, rect.height); } inline static void flip(RealRect& rect, int& degrees, double width, double height, int horizontal) { if (horizontal) { rect = RealRect(width - rect.x - rect.width, rect.y, rect.width, rect.height); } else { rect = RealRect(rect.x, height - rect.y - rect.height, rect.width, rect.height); } } inline static void rotate(RealRect& rect, int& degrees, double width, double height, int angle) { // only handles right angle rotations degrees += angle; if (degrees >= 360) degrees -= 360; if (angle == 180) { rect = RealRect(width - rect.x - rect.width, height - rect.y - rect.height, rect.width, rect.height); } else if (angle == 90) { rect = RealRect(rect.y, width - rect.x - rect.width, rect.height, rect.width); } else if (angle == 270) { rect = RealRect(height - rect.y - rect.height, rect.x, rect.height, rect.width); } } inline operator wxRect() const { // Prevent rounding errors, for example if // x = 0.6 and width = 0.6 // the right = 1.2 // so we want a rectangle from 0 to 1 // not from 0 to 0 int i_l = to_int(x), i_r = to_int(right()); int i_t = to_int(y), i_b = to_int(bottom()); return wxRect(i_l, i_t, i_r - i_l, i_b - i_t); } /// Explicit conversion to wxRect, to not confuse gcc inline wxRect toRect() const { return *this; } }; /// Split a rectangle horizontally /** Returns a section from the left of this rectangle witht the given width * The rectangle will change to become the part remaining to the right * For example given a rectangle: * +------------+ * | R | * +------------+ * A = split_left(R,5) * +----+-------+ * | A | R | * +----+-------+ */ inline RealRect split_left(RealRect& r, double w) { RealRect result(r.x, r.y, w, r.height); r.width -= w; r.x += w; return result; } /// Split a rectangle horizontally inline RealRect split_left(RealRect& r, const RealSize& s) { return split_left(r, s.width); } // ----------------------------------------------------------------------------- : Operators inline RealPoint operator + (const RealSize& s, const RealPoint& p) { return RealPoint(p.x + s.width, p.y + s.height); } inline RealPoint operator + (const RealPoint& p, const RealSize& s) { return RealPoint(p.x + s.width, p.y + s.height); } inline RealPoint operator - (const RealPoint& p, const RealSize& s) { return RealPoint(p.x - s.width, p.y - s.height); } inline void operator += (RealPoint& p, const RealSize& s) { p.x += s.width; p.y += s.height; }