TrinityCore
Rect2D.h
Go to the documentation of this file.
1
13 #ifndef G3D_Rect2D_h
14 #define G3D_Rect2D_h
15
16 // Linux defines this as a macro
17 #ifdef border
18 #undef border
19 #endif
20
21 #include "G3D/platform.h"
22 #include "G3D/Array.h"
23 #include "G3D/Vector2.h"
24
25 #ifdef _MSC_VER
26 // Turn off "conditional expression is constant" warning; MSVC generates this
27 // for debug assertions in inlined methods.
28 # pragma warning (disable : 4127)
29 #endif
30
31
32 namespace G3D {
33
34 class Any;
35
40 class Rect2D {
41 private:
43
52  template<class T>
53  static bool clipSide2D(
54  const float p, bool clipGreater, int axis,
55  const Array<T>& inPoly, Array<T>& outPoly) {
56
57  outPoly.clear();
58  int i0 = -1;
59
60  Vector2 pt1;
61  bool c1 = true;
62
63  float negate = clipGreater ? -1 : 1;
64
65  // Find a point that is not clipped
66  for (i0 = 0; (i0 < inPoly.length()) && c1; ++i0) {
67  pt1 = inPoly[i0];
68  c1 = (negate * pt1[axis]) < (negate * p);
69  }
70
71  // We incremented i0 one time to many
72  --i0;
73
74  if (c1) {
75  // We could not find an unclipped point
76  return true;
77  }
78
79  outPoly.append(pt1);
80
81  // for each point in inPoly,
82  // if the point is outside the side and the previous one was also outside, continue
83  // if the point is outside the side and the previous one was inside, cut the line
84  // if the point is inside the side and the previous one was also inside, append the points
85  // if the point is inside the side and the previous one was outside, cut the line
86  for (int i = 1; i <= inPoly.length(); ++i) {
87  T pt2 = inPoly[(i + i0) % inPoly.length()];
88  bool c2 = (negate * pt2[axis]) < (negate * p);
89
90  if (c1 ^ c2) {
91
92  if (!c1 && c2 && (i > 1)) {
93  // Unclipped to clipped trasition and not the first iteration
94  outPoly.append(pt1);
95  }
96
97  // only one point is clipped, find where the line crosses the clipping plane
98
99
100  float alpha;
101  if (pt2[axis] == pt1[axis]) {
102  alpha = 0;
103  } else {
104  alpha = (p - pt1[axis]) / (pt2[axis] - pt1[axis]);
105  }
106  outPoly.append(pt1.lerp(pt2, alpha));
107  } else if (! (c1 || c2) && (i != 1)) {
108  // neither point is clipped (don't do this the first time
109  // because we appended the first pt before the loop)
110  outPoly.append(pt1);
111  }
112
113  pt1 = pt2;
114  c1 = c2;
115  }
116
117  return false;
118  }
119
121  Rect2D(bool /*b*/) {}
122 public:
123
125  Rect2D(const Any& any);
126
128  Any toAny() const;
129
130  Rect2D(const Rect2D& r) : min(r.min), max(r.max) {}
131
134  Rect2D() : min(fnan(), fnan()), max(fnan(), fnan()) {}
135
136  static const Rect2D& empty();
137
139  inline bool isEmpty() const {
140  return min.isNaN() && max.isNaN();
141  }
142
144  Rect2D(const Vector2& wh) : min(0, 0), max(wh.x, wh.y) {}
145
146  Vector2 extent() const {
147  if (isEmpty()) {
148  return Vector2::zero();
149  } else {
150  return max - min;
151  }
152  }
153
155  Point2 randomPoint() const {
156  return Point2(uniformRandom(0, max.x - min.x) + min.x,
157  uniformRandom(0, max.y - min.y) + min.y);
158  }
159
160  float width() const {
161  if (isEmpty()) {
162  return 0;
163  } else {
164  return max.x - min.x;
165  }
166  }
167
168  float height() const {
169  if (isEmpty()) {
170  return 0;
171  } else {
172  return max.y - min.y;
173  }
174  }
175
176  float x0() const {
177  return min.x;
178  }
179
180  float x1() const {
181  return max.x;
182  }
183
184  float y0() const {
185  return min.y;
186  }
187
188  float y1() const {
189  return max.y;
190  }
191
193  Point2 x0y0() const {
194  return min;
195  }
196
197  Point2 x1y0() const {
198  return Point2(max.x, min.y);
199  }
200
201  Point2 x0y1() const {
202  return Point2(min.x, max.y);
203  }
204
206  Point2 x1y1() const {
207  return max;
208  }
209
211  Vector2 wh() const {
212  if (isEmpty()) {
213  return Vector2::zero();
214  } else {
215  return max - min;
216  }
217  }
218
219  Point2 center() const {
220  return (max + min) * 0.5;
221  }
222
223  float area() const {
224  return width() * height();
225  }
226
227  bool isFinite() const {
228  return (min.isFinite() && max.isFinite());
229  }
230
231  Rect2D lerp(const Rect2D& other, float alpha) const {
232  Rect2D out(false);
233
234  out.min = min.lerp(other.min, alpha);
235  out.max = max.lerp(other.max, alpha);
236
237  return out;
238  }
239
240  static Rect2D xyxy(float x0, float y0, float x1, float y1) {
241  Rect2D r(false);
242
243  r.min.x = G3D::min(x0, x1);
244  r.min.y = G3D::min(y0, y1);
245  r.max.x = G3D::max(x0, x1);
246  r.max.y = G3D::max(y0, y1);
247
248  return r;
249  }
250
251  static Rect2D xyxy(const Point2& v0, const Point2& v1) {
252  Rect2D r(false);
253
254  r.min = v0.min(v1);
255  r.max = v0.max(v1);
256
257  return r;
258  }
259
260  static Rect2D xywh(float x, float y, float w, float h) {
261  return xyxy(x, y, x + w, y + h);
262  }
263
264  static Rect2D xywh(const Point2& v, const Vector2& w) {
265  return xyxy(v.x, v.y, v.x + w.x, v.y + w.y);
266  }
267
271  static Rect2D inf() {
272  return xyxy(Vector2::inf(), Vector2::inf());
273  }
274
275  bool contains(const Point2& v) const {
276  // This will automatically return false if isEmpty()
277  return (v.x >= min.x) && (v.y >= min.y) && (v.x <= max.x) && (v.y <= max.y);
278  }
279
280  bool contains(const Rect2D& r) const {
281  // This will automatically return false if isEmpty()
282  return (min.x <= r.min.x) && (min.y <= r.min.y) &&
283  (max.x >= r.max.x) && (max.y >= r.max.y);
284  }
285
289  bool intersects(const Rect2D& r) const {
290  // This will automatically return false if isEmpty()
291  return (min.x < r.max.x) && (min.y < r.max.y) &&
292  (max.x > r.min.x) && (max.y > r.min.y);
293  }
294
296  bool intersectsOrTouches(const Rect2D& r) const {
297  // This will automatically return false if isEmpty()
298  return (min.x <= r.max.x) && (min.y <= r.max.y) &&
299  (max.x >= r.min.x) && (max.y >= r.min.y);
300  }
301
302  Rect2D operator*(float s) const {
303  return xyxy(min.x * s, min.y * s, max.x * s, max.y * s);
304  }
305
306  Rect2D operator*(const Vector2& s) const {
307  return xyxy(min * s, max * s);
308  }
309
310  Rect2D operator/(float s) const {
311  return xyxy(min / s, max / s);
312  }
313
314  Rect2D operator/(const Vector2& s) const {
315  return xyxy(min / s, max / s);
316  }
317
318  Rect2D operator+(const Vector2& v) const {
319  return xyxy(min + v, max + v);
320  }
321
322  Rect2D operator-(const Vector2& v) const {
323  return xyxy(min - v, max - v);
324  }
325
326  bool operator==(const Rect2D& other) const {
327  return (min == other.min) && (max == other.max);
328  }
329
330  bool operator!=(const Rect2D& other) const {
331  return (min != other.min) || (max != other.max);
332  }
333
334  void serialize(class BinaryOutput& b) const;
335
336  void deserialize(class BinaryInput& b);
337
339  Point2 corner(int i) const {
340  debugAssert(i >= 0 && i < 4);
341  switch (i & 3) {
342  case 0:
343  return Point2(min.x, min.y);
344  case 1:
345  return Point2(max.x, min.y);
346  case 2:
347  return Point2(max.x, max.y);
348  case 3:
349  return Point2(min.x, max.y);
350  default:
351  // Should never get here
352  return Point2(0, 0);
353  }
354  }
355
356
359  Rect2D border(float delta) const {
360  return Rect2D::xywh(x0() + delta,
361  y0() + delta,
362  width() - 2.0f * delta,
363  height() - 2.0f * delta);
364  }
365
368  Rect2D expand(float delta) const {
369  float newX = x0() - delta;
370  float newY = y0() - delta;
371  float newW = width() + 2.0f * delta;
372  float newH = height() + 2.0f * delta;
373
374  if (newW < 0.0f) {
375  newX = (x0() + width()) / 2.0f;
376  newW = 0.0f;
377  }
378
379  if (newH < 0.0f) {
380  newY = (y0() + height()) / 2.0f;
381  newH = 0.0f;
382  }
383  return Rect2D::xywh(newX, newY, newW, newH);
384  }
385
386  void merge(const Rect2D& other) {
387  if (isEmpty()) {
388  *this = other;
389  } else if (! other.isEmpty()) {
390  min = min.min(other.min);
391  max = max.max(other.max);
392  }
393  }
394
397  Rect2D(const Rect2D& a, const Rect2D& b) {
398  *this = a;
399  merge(b);
400  }
401
411  template<class T>
412  void clip(const Array<T>& inPoly, Array<T>& outPoly) const {
413
414  const bool greaterThan = true;
415  const bool lessThan = false;
416  const int X = 0;
417  const int Y = 1;
418
419  Array<T> temp;
420
421  bool entirelyClipped =
422  clipSide2D(x0(), lessThan, X, inPoly, temp) ||
423  clipSide2D(x1(), greaterThan, X, temp, outPoly) ||
424  clipSide2D(y0(), lessThan, Y, outPoly, temp) ||
425  clipSide2D(y1(), greaterThan, Y, temp, outPoly);
426
427  if (entirelyClipped) {
428  outPoly.clear();
429  }
430  }
431
432
437  Rect2D largestCenteredSubRect(float ww, float hh) const {
438  float textureAspect = hh / ww;
439  float viewAspect = height() / width();
440
441  if (viewAspect > textureAspect) {
442  // The view is too tall
443  float h = width() * textureAspect;
444  float y = (height() - h) / 2;
445  return Rect2D::xywh(0, y, width(), h) + corner(0);
446  } else {
447  // The view is too wide
448  float w = height() / textureAspect;
449  float x = (width() - w) / 2;
450  return Rect2D::xywh(x, 0, w, height()) + corner(0);
451  }
452  }
453
460  Rect2D intersect(const Rect2D& other) const {
461  if (intersects(other)) {
462  return Rect2D::xyxy(min.max(other.min), max.min(other.max));
463  } else {
464  return empty();
465  }
466  }
467 };
468
469 typedef Rect2D AABox2D;
470 }
471
472 #endif
Vector2 extent() const
Definition: Rect2D.h:146
bool operator!=(const Rect2D &other) const
Definition: Rect2D.h:330
float area() const
Definition: Rect2D.h:223
class Rect2D AABox2D
Definition: Box2D.h:24
Rect2D operator/(const Vector2 &s) const
Definition: Rect2D.h:314
Definition: Vector2.h:40
Rect2D operator/(float s) const
Definition: Rect2D.h:310
void clip(const Array< T > &inPoly, Array< T > &outPoly) const
Definition: Rect2D.h:412
Vector2 wh() const
Definition: Rect2D.h:211
float fnan()
Definition: g3dmath.cpp:82
Point2 corner(int i) const
Definition: Rect2D.h:339
float y0() const
Definition: Rect2D.h:184
bool intersects(const Rect2D &r) const
Definition: Rect2D.h:289
bool isFinite() const
Definition: Rect2D.h:227
bool isFinite() const
Definition: Vector2.h:476
Definition: BinaryInput.h:69
Point2 x0y1() const
Definition: Rect2D.h:201
#define X
Definition: CollisionDetection.cpp:2281
static bool clipSide2D(const float p, bool clipGreater, int axis, const Array< T > &inPoly, Array< T > &outPoly)
Definition: Rect2D.h:53
Vector2 min(const Vector2 &v) const
Definition: Vector2.h:452
static Rect2D inf()
Definition: Rect2D.h:271
Rect2D operator*(float s) const
Definition: Rect2D.h:302
Rect2D(bool)
Definition: Rect2D.h:121
Rect2D largestCenteredSubRect(float ww, float hh) const
Definition: Rect2D.h:437
bool operator==(const Rect2D &other) const
Definition: Rect2D.h:326
Definition: AABox.h:25
Rect2D lerp(const Rect2D &other, float alpha) const
Definition: Rect2D.h:231
Rect2D(const Rect2D &r)
Definition: Rect2D.h:130
bool any(float x)
Definition: g3dmath.h:424
static G3D::Matrix::T negate(G3D::Matrix::T x)
Definition: Matrix.cpp:8
Vector2 lerp(const Vector2 &v, float alpha) const
Definition: Vector2.h:133
bool isEmpty() const
Definition: Rect2D.h:139
int length() const
Definition: Array.h:438
Point2 x1y1() const
Definition: Rect2D.h:206
Rect2D border(float delta) const
Definition: Rect2D.h:359
void serialize(class BinaryOutput &b) const
Definition: Rect2D.cpp:28
Definition: Rect2D.h:40
Rect2D operator+(const Vector2 &v) const
Definition: Rect2D.h:318
T max(const T &x, const T &y)
Definition: g3dmath.h:320
Rect2D expand(float delta) const
Definition: Rect2D.h:368
Vector2 Point2
Definition: Vector2.h:492
float width() const
Definition: Rect2D.h:160
float y
Definition: Vector2.h:50
float y1() const
Definition: Rect2D.h:188
Rect2D(const Rect2D &a, const Rect2D &b)
Definition: Rect2D.h:397
float uniformRandom(float low=0.0f, float hi=1.0f)
Definition: g3dmath.h:694
T min(const T &x, const T &y)
Definition: g3dmath.h:305
Definition: Any.h:184
static const Rect2D & empty()
Definition: Rect2D.cpp:22
Rect2D operator*(const Vector2 &s) const
Definition: Rect2D.h:306
float height() const
Definition: Rect2D.h:168
void deserialize(class BinaryInput &b)
Definition: Rect2D.cpp:34
#define debugAssert(exp)
Definition: debugAssert.h:160
G3D::int16 y
Definition: Vector2int16.h:38
void merge(const Rect2D &other)
Definition: Rect2D.h:386
float x0() const
Definition: Rect2D.h:176
float x
Definition: Vector2.h:49
void clear(bool shrink=true)
Definition: Array.h:407
Rect2D intersect(const Rect2D &other) const
Definition: Rect2D.h:460
Any toAny() const
Definition: Rect2D.cpp:59
Point2 x1y0() const
Definition: Rect2D.h:197
bool contains(const Point2 &v) const
Definition: Rect2D.h:275
Point2 randomPoint() const
Uniformly random point on the interior.
Definition: Rect2D.h:155
static Rect2D xyxy(float x0, float y0, float x1, float y1)
Definition: Rect2D.h:240
bool intersectsOrTouches(const Rect2D &r) const
Definition: Rect2D.h:296
static Rect2D xyxy(const Point2 &v0, const Point2 &v1)
Definition: Rect2D.h:251
Point2 x0y0() const
Definition: Rect2D.h:193
Definition: BinaryOutput.h:52
bool contains(const Rect2D &r) const
Definition: Rect2D.h:280
Point2 center() const
Definition: Rect2D.h:219
bool isNaN() const
Definition: Vector2.h:95
Rect2D operator-(const Vector2 &v) const
Definition: Rect2D.h:322
static Rect2D xywh(float x, float y, float w, float h)
Definition: Rect2D.h:260
Point2 max
Definition: Rect2D.h:42
G3D::int16 x
Definition: Vector2int16.h:37
static Rect2D xywh(const Point2 &v, const Vector2 &w)
Definition: Rect2D.h:264
void append(const T &value)
Definition: Array.h:583
static const Vector2 & zero()
Definition: Vector2.cpp:67
Point2 min
Definition: Rect2D.h:42
Vector2 max(const Vector2 &v) const
Definition: Vector2.h:458
float x1() const
Definition: Rect2D.h:180
Rect2D(const Vector2 &wh)
Definition: Rect2D.h:144
#define Y
Definition: CollisionDetection.cpp:2282
static const Vector2 & inf()
Definition: Vector2.cpp:82
Rect2D()
Definition: Rect2D.h:134