-
Notifications
You must be signed in to change notification settings - Fork 6
/
Rect.h
363 lines (342 loc) · 8.14 KB
/
Rect.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/*
This file is part of the Geometry library.
Copyright (C) 2007-2012 Benjamin Eikel <[email protected]>
Copyright (C) 2007-2012 Claudius Jähn <[email protected]>
Copyright (C) 2007-2012 Ralf Petring <[email protected]>
This library is subject to the terms of the Mozilla Public License, v. 2.0.
You should have received a copy of the MPL along with this library; see the
file LICENSE. If not, you can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef GEOMETRY_RECT_H
#define GEOMETRY_RECT_H
#include "Definitions.h"
#include "Vec2.h"
#include <istream>
#include <ostream>
namespace Geometry {
/**
* Two-dimensional rectangle.
*
@verbatim
^Y
|
|
|
o---> X
--- width ----
+------------+ |
| | |
| | height
| | |
o------------+ |
(x, y)
@endverbatim
*/
template <typename T_>
class _Rect {
public:
typedef T_ value_t;
typedef _Vec2<value_t> vec2_t;
/**
* @name Main
*/
//@{
_Rect()
: x(static_cast<value_t>(0)),
y(static_cast<value_t>(0)),
width(static_cast<value_t>(0)),
height(static_cast<value_t>(0)) {
}
_Rect(value_t posX, value_t posY, value_t w, value_t h) : x(posX), y(posY), width(w), height(h) {
}
_Rect(const vec2_t & pos, const vec2_t & size) : x(pos.x()), y(pos.y()), width(size.x()), height(size.y()) {
}
template <class other_t>
explicit _Rect(const _Rect<other_t> & other)
: x(static_cast<value_t>(other.getX())),
y(static_cast<value_t>(other.getY())),
width(static_cast<value_t>(other.getWidth())),
height(static_cast<value_t>(other.getHeight())) {
}
//@}
/**
* @name Information
*/
//@{
vec2_t getSize() const {
return vec2_t(width, height);
}
vec2_t getMin() const {
return vec2_t(x, y);
}
vec2_t getMax() const {
return vec2_t(x+width, y+height);
}
value_t getX() const {
return x;
}
value_t getMinX() const {
return x;
}
value_t getMaxX() const {
return x + width;
}
value_t getY() const {
return y;
}
value_t getMinY() const {
return y;
}
value_t getMaxY() const {
return y + height;
}
value_t getWidth() const {
return width;
}
value_t getHeight() const {
return height;
}
value_t getArea() const {
return width * height;
}
vec2_t getPosition() const {
return vec2_t(x, y);
}
vec2_t getCenter() const {
return vec2_t((getMinX() + getMaxX()) / static_cast<value_t>(2),
(getMinY() + getMaxY()) / static_cast<value_t>(2));
}
bool contains(value_t _x, value_t _y) const {
return _x >= x && _x <= x + width && _y >= y && _y <= y + height;
}
bool contains(const _Rect<value_t> & rect) const {
return contains(rect.getMinX(), rect.getMinY()) && contains(rect.getMaxX(), rect.getMaxY());
}
bool contains(const vec2_t & vec) const {
return contains(vec.getX(), vec.getY());
}
bool isInvalid() const {
return width < static_cast<value_t>(0) || height < static_cast<value_t>(0);
}
bool isValid() const {
return width >= static_cast<value_t>(0) && height >= static_cast<value_t>(0);
}
bool intersects(const _Rect<value_t> & rect) const {
return isValid() && rect.isValid() && rect.getMaxX() >= getMinX() && rect.getMinX() <= getMaxX()
&& rect.getMaxY() >= getMinY() && rect.getMinY() <= getMaxY();
}
vec2_t getCorner(const rectCorner_t corner) const {
auto nr = static_cast<std::size_t>(corner);
return vec2_t((nr & 1) ? getMaxX() : getMinX(), (nr & 2) ? getMaxY() : getMinY());
}
vec2_t getClosestPoint(const vec2_t& pos) const {
vec2_t closest = pos;
if(isInvalid())
return closest;
if(pos.x() < x)
closest.x(x);
else if(pos.x() > x+width)
closest.x(x+width);
if(pos.y() < y)
closest.y(y);
else if(pos.y() > y+height)
closest.y(y+height);
return closest;
}
//@}
/**
* @name Read-Write Access
* @note Do not use these functions, if not really necessary.
*/
//@{
value_t & _accessX() {
return x;
}
value_t & _accessY() {
return y;
}
value_t & _accessWidth() {
return width;
}
value_t & _accessHeight() {
return height;
}
//@}
/**
* @name Modification
*/
//@{
void setPosition(value_t _x, value_t _y) {
x = _x;
y = _y;
}
void setPosition(const vec2_t & vec) {
x = vec.getX();
y = vec.getY();
}
void setX(value_t _x) {
x = _x;
}
void setY(value_t _y) {
y = _y;
}
void setWidth(value_t w) {
width = w;
}
void setHeight(value_t h) {
height = h;
}
void setSize(value_t w, value_t h) {
width = w;
height = h;
}
void setSize(const vec2_t & s) {
width = s.x();
height = s.y();
}
void invalidate() {
width = static_cast<value_t>(-1);
height = static_cast<value_t>(-1);
}
_Rect<value_t> & moveRel(value_t _x, value_t _y) {
x += _x;
y += _y;
return *this;
}
_Rect<value_t> & moveRel(const vec2_t & vec) {
x += vec.getX();
y += vec.getY();
return *this;
}
//! Move by given vector
_Rect<value_t> & operator+=(const vec2_t & vec) {
return moveRel(vec);
}
//! Move by given vector in negative direction
_Rect<value_t> & operator-=(const vec2_t & vec) {
return moveRel(-vec);
}
//! Change size around upper left corner
_Rect<value_t> & changeSize(value_t dw, value_t dh) {
width += dw;
height += dh;
return *this;
}
//! Change size around upper left corner
_Rect<value_t> & changeSize(const vec2_t & vec) {
return changeSize(vec.getWidth(), vec.getHeight());
}
//! Change size around center
_Rect<value_t> & changeSizeCentered(value_t dw, value_t dh) {
changeSize(dw, dh);
moveRel(-dw / static_cast<value_t>(2), -dh / static_cast<value_t>(2));
return *this;
}
//! Change size around center
_Rect<value_t> & changeSizeCentered(const vec2_t & vec) {
return changeSizeCentered(vec.getWidth(), vec.getHeight());
}
_Rect<value_t> & include(const vec2_t & vec) {
return include(vec.getX(), vec.getY());
}
_Rect<value_t> & include(value_t px, value_t py) {
if (isInvalid()) {
x = px;
y = py;
width = static_cast<value_t>(0);
height = static_cast<value_t>(0);
return *this;
}
if (px > getMaxX()) {
width = px - x;
} else if (px < getMinX()) {
width += x - px;
x = px;
}
if (py > getMaxY()) {
height = py - y;
} else if (py < y) {
height += y - py;
y = py;
}
return *this;
}
_Rect<value_t> & include(const _Rect<value_t> & rect) {
if (rect.isInvalid()) {
return *this;
} else if (isInvalid()) {
*this = rect;
} else {
include(rect.getMinX(), rect.getMinY());
include(rect.getMaxX(), rect.getMaxY());
}
return *this;
}
_Rect<value_t> & clipBy(const _Rect<value_t> & rect) {
if (!intersects(rect)) {
invalidate();
return *this;
}
if (getMinX() < rect.getMinX()) {
width -= rect.getMinX() - getMinX();
x = rect.getMinX();
}
if (getMaxX() > rect.getMaxX()) {
width -= getMaxX() - rect.getMaxX();
}
if (getMinY() < rect.getMinY()) {
height -= rect.getMinY() - getMinY();
y = rect.getMinY();
}
if (getMaxY() > rect.getMaxY()) {
height -= getMaxY() - rect.getMaxY();
}
return *this;
}
//@}
/**
* @name Creation
*/
//@{
//! Create Rect by moving this by given vector
const _Rect<value_t> operator+(const vec2_t & vec) const {
return _Rect<value_t>(x + vec.getX(), y + vec.getY(), width, height);
}
//! Create Rect by moving this by given vector in negative direction
const _Rect<value_t> operator-(const vec2_t & vec) const {
return _Rect<value_t>(x - vec.getX(), y - vec.getY(), width, height);
}
//@}
/**
* @name Comparators
*/
//@{
bool operator==(const _Rect<value_t> & rect) const {
return rect.x == x && rect.y == y && rect.width == width && rect.height == height;
}
bool operator!=(const _Rect<value_t> & rect) const {
return rect.x != x || rect.y != y || rect.width != width || rect.height != height;
}
//@}
private:
value_t x;
value_t y;
value_t width;
value_t height;
//! @name Serialization
//@{
public:
friend std::ostream & operator<<(std::ostream & out, const _Rect<value_t> & rect) {
return out << rect.x << ' ' << rect.y << ' ' << rect.width << ' ' << rect.height;
}
friend std::istream & operator>>(std::istream & in, _Rect<value_t> & rect) {
return in >> rect.x >> rect.y >> rect.width >> rect.height;
}
//@}
};
typedef _Rect<float> Rect;
typedef _Rect<float> Rect_f;
typedef _Rect<int> Rect_i;
typedef _Rect<double> Rect_d;
}
#endif /* GEOMETRY_RECT_H */