source: cpp/common/2d.h @ 1327

Last change on this file since 1327 was 1327, checked in by Maciej Komosinski, 3 days ago

Added a helper function and an operator

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