mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
268 lines
9.1 KiB
C++
268 lines
9.1 KiB
C++
//+----------------------------------------------------------------------------+
|
|
//| 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 <util/prec.hpp>
|
|
#include <util/vector2d.hpp>
|
|
|
|
// ----------------------------------------------------------------------------- : 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<void(RealRect&,int&,double,double,int)> 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;
|
|
}
|
|
|