1 | // This file is a part of Framsticks SDK. http://www.framsticks.com/ |
---|
2 | // Copyright (C) 1999-2019 Maciej Komosinski and Szymon Ulatowski. |
---|
3 | // See LICENSE.txt for details. |
---|
4 | |
---|
5 | #ifndef _2D_H_ |
---|
6 | #define _2D_H_ |
---|
7 | |
---|
8 | #include "nonstd_stl.h" |
---|
9 | #include <math.h> |
---|
10 | |
---|
11 | //unification of old GUIXY and Pt2D |
---|
12 | template <typename T> class XY |
---|
13 | { |
---|
14 | public: |
---|
15 | T x, y; |
---|
16 | XY() {} |
---|
17 | XY(T _x, T _y) :x(_x), y(_y) {} |
---|
18 | template <typename Q> XY(const Q& other) : x(other.x), y(other.y) {} |
---|
19 | template <typename Q> const XY& operator=(const Q& other) { x = other.x; y = other.y; return *this; } |
---|
20 | template <typename Q> const XY operator()(const Q& other) { return XY(other.x, other.y); } |
---|
21 | XY operator+(const XY&p) const { return XY(x + p.x, y + p.y); } |
---|
22 | XY operator-(const XY&p) const { return XY(x - p.x, y - p.y); } |
---|
23 | XY operator+=(const XY&p) { x += p.x; y += p.y; return *this; } |
---|
24 | XY operator-=(const XY&p) { x -= p.x; y -= p.y; return *this; } |
---|
25 | XY operator-() const { return XY(-x, -y); } |
---|
26 | // allows float operations on ints |
---|
27 | template <typename Q> XY operator*=(Q q) { x *= q; y *= q; return *this; } |
---|
28 | template <typename Q> XY operator/=(Q q) { x /= q; y /= q; return *this; } |
---|
29 | template <typename Q> XY operator/(Q q) const { return XY(x / q, y / q); } |
---|
30 | template <typename Q> XY operator*(Q q) const { return XY(q*x, q*y); } |
---|
31 | void set(T _x, T _y) { x = _x; y = _y; } |
---|
32 | void add(T _x, T _y) { x += _x; y += _y; } |
---|
33 | void sub(T _x, T _y) { x -= _x; y -= _y; } |
---|
34 | bool operator==(const XY& p) const { return (fabs(double(x - p.x)) < 1e-20) && (fabs(double(y - p.y)) < 1e-20); } |
---|
35 | bool operator!=(const XY& p) const { return !operator==(p); } |
---|
36 | T distanceTo(const XY& p) const { return sqrt(double((p.x - x)*(p.x - x) + (p.y - y)*(p.y - y))); } |
---|
37 | T magnitude() const { return sqrt(x*x + y * y); } |
---|
38 | T length() const { return sqrt(x*x + y * y); } |
---|
39 | T lengthSq() const { return x * x + y * y; } |
---|
40 | T dotProduct(const XY& v) const { return x * v.x + y * v.y; } |
---|
41 | T crossProduct(const XY& v) const { return x * v.y - y * v.x; } |
---|
42 | void normalize() { operator/=(length()); } // length becomes 1 |
---|
43 | static XY average(const XY& v1, const XY& v2) { return XY((v1.x + v2.x)*0.5, (v1.y + v2.y)*0.5); } |
---|
44 | double getDirection() const { return atan2(y, x); } |
---|
45 | static XY interpolate(const XY& v1, const XY& v2, double t) { return v1 + (v2 - v1)*t; } |
---|
46 | XY toInt() const { return XY(int(x), int(y)); } |
---|
47 | XY transpose() const { return XY(y, x); } |
---|
48 | static const XY& zero() { static XY t(0, 0); return t; } |
---|
49 | static const XY& one() { static XY t(1, 1); return t; } |
---|
50 | }; |
---|
51 | |
---|
52 | //specialized: int equality not using fabs() |
---|
53 | template<> inline bool XY<int>::operator==(const XY<int>& p) const { return (x == p.x) && (y == p.y); } |
---|
54 | |
---|
55 | template <typename T> XY<T> xymin(const XY<T>& a, const XY<T>& b) { return XY<T>(min(a.x, b.x), min(a.y, b.y)); } |
---|
56 | template <typename T> XY<T> xymax(const XY<T>& a, const XY<T>& b) { return XY<T>(max(a.x, b.x), max(a.y, b.y)); } |
---|
57 | |
---|
58 | template <typename T> |
---|
59 | class XYMargin |
---|
60 | { |
---|
61 | public: |
---|
62 | XYMargin(T x = 0) :left(x), top(x), right(x), bottom(x) {} |
---|
63 | XYMargin(T l, T t, T r, T b) :left(l), top(t), right(r), bottom(b) {} |
---|
64 | T left, top, right, bottom; |
---|
65 | void operator=(T x) { left = top = right = bottom = x; } |
---|
66 | XYMargin operator-() const { return XYMargin(-left, -top, -right, -bottom); } |
---|
67 | void operator=(const XYMargin<T> &other) { left = other.left; top = other.top; right = other.right; bottom = other.bottom; } |
---|
68 | T horizontal() const { return left + right; } |
---|
69 | T vertical() const { return top + bottom; } |
---|
70 | bool operator==(const XYMargin &other) const { return left == other.left && top == other.top && right == other.right && bottom == other.bottom; } |
---|
71 | XYMargin normalized() const { return XYMargin(max(left, T(0)), max(top, T(0)), max(right, T(0)), max(bottom, T(0))); } |
---|
72 | }; |
---|
73 | |
---|
74 | template <typename T> |
---|
75 | class XYRect |
---|
76 | { |
---|
77 | public: |
---|
78 | XY<T> p, size; |
---|
79 | XYRect() {} |
---|
80 | XYRect(const XY<T>& p1, const XY<T>& s) :p(p1), size(s) {} |
---|
81 | template <typename Q> XYRect(const Q& other) : p(other.p), size(other.size) {} |
---|
82 | XYRect(T _x, T _y, T _w, T _h) :p(_x, _y), size(_w, _h) {} |
---|
83 | static XYRect<T> centeredAt(const XY<T>& p, XY<T> s) { return XYRect<T>(p - s * 0.5, s); } |
---|
84 | |
---|
85 | bool isEmpty() const { return (size.x < 0) || (size.y < 0); } |
---|
86 | XYRect toInt() const { return XYRect(int(p.x), int(p.y), int(p.x + size.x) - int(p.x), int(p.y + size.y) - int(p.y)); } |
---|
87 | bool operator==(const XYRect& r) const { return (p == r.p) && (size == r.size); } |
---|
88 | template <typename Q> const XYRect& operator=(const Q& other) { p = other.p; size = other.size; return *this; } |
---|
89 | |
---|
90 | T right() const { return p.x + size.x; } |
---|
91 | T bottom() const { return p.y + size.y; } |
---|
92 | T top() const { return p.y; } |
---|
93 | T left() const { return p.x; } |
---|
94 | XY<T> center() const { return p + size / 2; } |
---|
95 | const XY<T>& topLeft() const { return p; } |
---|
96 | XY<T> bottomRight() const { return p + size; } |
---|
97 | XY<T> topRight() const { return XY<T>(p.x + size.x, p.y); } |
---|
98 | XY<T> bottomLeft() const { return XY<T>(p.x, p.y + size.y); } |
---|
99 | |
---|
100 | T area() const { return size.x*size.y; } |
---|
101 | |
---|
102 | bool intersects(const XYRect& r) const |
---|
103 | { |
---|
104 | if (r.p.x >= (p.x + size.x)) return false; |
---|
105 | if (r.p.y >= (p.y + size.y)) return false; |
---|
106 | if ((r.p.x + r.size.x) <= p.x) return false; |
---|
107 | if ((r.p.y + r.size.y) <= p.y) return false; |
---|
108 | return true; |
---|
109 | } |
---|
110 | |
---|
111 | bool contains(const XY<T>& n) const |
---|
112 | { |
---|
113 | if (n.x < p.x) return false; |
---|
114 | if (n.x > (p.x + size.x)) return false; |
---|
115 | if (n.y < p.y) return false; |
---|
116 | if (n.y > (p.y + size.y)) return false; |
---|
117 | return true; |
---|
118 | } |
---|
119 | |
---|
120 | bool contains(const XYRect& r) const |
---|
121 | { |
---|
122 | return contains(r.p) && contains(r.p + r.size); |
---|
123 | } |
---|
124 | |
---|
125 | void add(const XY<T>& n) |
---|
126 | { |
---|
127 | if (n.x < p.x) { size.x += p.x - n.x; p.x = n.x; } |
---|
128 | else if (n.x > (p.x + size.x)) size.x = n.x - p.x; |
---|
129 | if (n.y < p.y) { size.y += p.y - n.y; p.y = n.y; } |
---|
130 | else if (n.y > (p.y + size.y)) size.y = n.y - p.y; |
---|
131 | } |
---|
132 | |
---|
133 | XYRect extendBy(const XY<T>& border_size) const |
---|
134 | { |
---|
135 | return XYRect(p - border_size, size + border_size * 2); |
---|
136 | } |
---|
137 | |
---|
138 | XYRect shrinkBy(const XY<T>& border_size) const |
---|
139 | { |
---|
140 | return XYRect(p + border_size, size - border_size * 2); |
---|
141 | } |
---|
142 | |
---|
143 | XYRect extendBy(const XYMargin<T>& m) const |
---|
144 | { |
---|
145 | return XYRect(p.x - m.left, p.y - m.top, size.x + m.horizontal(), size.y + m.vertical()); |
---|
146 | } |
---|
147 | |
---|
148 | XYRect shrinkBy(const XYMargin<T>& m) const |
---|
149 | { |
---|
150 | return XYRect(p.x + m.left, p.y + m.top, size.x - m.horizontal(), size.y - m.vertical()); |
---|
151 | } |
---|
152 | |
---|
153 | XYMargin<T> marginTowards(const XYRect &r) const |
---|
154 | { |
---|
155 | return XYMargin<T>(r.p.x - p.x, r.p.y - p.y, |
---|
156 | (p.x + size.x) - (r.p.x + r.size.x), (p.y + size.y) - (r.p.y + r.size.y)); |
---|
157 | } |
---|
158 | |
---|
159 | XYRect intersection(const XYRect& r) const |
---|
160 | { |
---|
161 | XYRect i; |
---|
162 | XY<T> p2 = p + size; |
---|
163 | XY<T> rp2 = r.p + r.size; |
---|
164 | i.p.x = max(p.x, r.p.x); |
---|
165 | i.p.y = max(p.y, r.p.y); |
---|
166 | i.size.x = min(p2.x, rp2.x) - i.p.x; |
---|
167 | i.size.y = min(p2.y, rp2.y) - i.p.y; |
---|
168 | return i; |
---|
169 | } |
---|
170 | |
---|
171 | XYRect translation(const XY<T>& t) const |
---|
172 | { |
---|
173 | return XYRect(p + t, size); |
---|
174 | } |
---|
175 | |
---|
176 | T distanceTo(const XY<T>& n) const |
---|
177 | { |
---|
178 | XY<T> tp = n; |
---|
179 | if (n.x < p.x) tp.x = p.x; else if (n.x >= (p.x + size.x)) tp.x = p.x + size.x; |
---|
180 | if (n.y < p.y) tp.y = p.y; else if (n.y >= (p.y + size.y)) tp.y = p.y + size.y; |
---|
181 | return tp.distanceTo(n); |
---|
182 | } |
---|
183 | |
---|
184 | T distanceTo(const XYRect<T>& r) const |
---|
185 | { |
---|
186 | bool r_above = (r.bottom() <= top()); |
---|
187 | bool r_below = (r.top() >= bottom()); |
---|
188 | bool r_left = (r.right() <= left()); |
---|
189 | bool r_right = (r.left() >= right()); |
---|
190 | |
---|
191 | if (r_above) |
---|
192 | { |
---|
193 | if (r_left) return r.bottomRight().distanceTo(topLeft()); |
---|
194 | else if (r_right) return r.bottomLeft().distanceTo(topRight()); |
---|
195 | else return top() - r.bottom(); |
---|
196 | } |
---|
197 | else if (r_below) |
---|
198 | { |
---|
199 | if (r_left) return r.topRight().distanceTo(bottomLeft()); |
---|
200 | else if (r_right) return r.topLeft().distanceTo(bottomRight()); |
---|
201 | else return r.top() - bottom(); |
---|
202 | } |
---|
203 | else if (r_left) |
---|
204 | { |
---|
205 | return left() - r.right(); |
---|
206 | } |
---|
207 | else if (r_right) |
---|
208 | { |
---|
209 | return r.left() - right(); |
---|
210 | } |
---|
211 | else |
---|
212 | return 0; //intersection |
---|
213 | } |
---|
214 | |
---|
215 | static const XYRect& zero() { static XYRect t(0, 0, 0, 0); return t; } |
---|
216 | static const XYRect& one() { static XYRect t(0, 0, 1, 1); return t; } |
---|
217 | }; |
---|
218 | |
---|
219 | typedef XY<int> IntXY; |
---|
220 | typedef XYRect<int> IntRect; |
---|
221 | |
---|
222 | typedef XY<float> FloatXY; |
---|
223 | typedef XYRect<float> FloatRect; |
---|
224 | |
---|
225 | #endif |
---|