mRect.h

Engine/source/math/mRect.h

More...

Classes:

class
class
class

Public Functions

Detailed Description

Public Functions

lineToLineIntersect(const Point2F & a1, const Point2F & a2, const Point2F & b1, const Point2F & b2)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#ifndef _MRECT_H_
 25#define _MRECT_H_
 26
 27#ifndef _MPOINT2_H_
 28#include "math/mPoint2.h"
 29#endif
 30
 31
 32class RectI
 33{
 34  public:
 35   Point2I  point;
 36   Point2I  extent;
 37
 38  public:
 39   RectI() { }
 40   RectI(const Point2I& in_rMin,
 41         const Point2I& in_rExtent);
 42   RectI(const S32 in_left,  const S32 in_top,
 43         const S32 in_width, const S32 in_height);
 44
 45   void set(const Point2I& in_rMin, const Point2I& in_rExtent);
 46   void set(const S32 in_left,  const S32 in_top,
 47         const S32 in_width, const S32 in_height);
 48
 49   bool intersect(const RectI& clipRect);
 50   bool pointInRect(const Point2I& pt) const;
 51   bool overlaps(RectI R) const;
 52   bool contains(const RectI& R) const;
 53   void inset(S32 x, S32 y);
 54
 55   void unionRects(const RectI&);
 56
 57   S32   len_x() const;
 58   S32   len_y() const;
 59
 60   /// Returns the area of the rectangle.
 61   S32 area() const { return extent.x * extent.y; }
 62
 63   bool operator==(const RectI&) const;
 64   bool operator!=(const RectI&) const;
 65
 66   bool isValidRect() const { return (extent.x > 0 && extent.y > 0); }
 67
 68public:
 69
 70   /// A rect of zero extent.
 71   static const RectI Zero;
 72
 73   /// A rect of 1,1 extent.
 74   static const RectI One;
 75
 76};
 77
 78class RectF
 79{
 80  public:
 81   Point2F  point;
 82   Point2F  extent;
 83
 84  public:
 85   RectF() { }
 86   RectF(const Point2F& in_rMin,
 87         const Point2F& in_rExtent);
 88   RectF(const F32 in_left,  const F32 in_top,
 89         const F32 in_width, const F32 in_height);
 90
 91   void set(const Point2F& in_rMin, const Point2F& in_rExtent);
 92   void set(const F32 in_left,  const F32 in_top,
 93      const F32 in_width, const F32 in_height);
 94
 95   void inset(F32 x, F32 y);
 96
 97   /// Return distance of the reference point to the rectangle.
 98   F32 getDistanceToPoint( const Point2F &refPt ) const;
 99
100   /// Return the squared distance of the reference point to the rectangle.
101   F32 getSqDistanceToPoint( const Point2F &refPt ) const;
102
103   bool intersect(const RectF& clipRect);
104   bool pointInRect(const Point2F& pt) const;
105   bool overlaps(const RectF&) const;
106   bool contains(const Point2F &p) const
107   {
108      Point2F minkowskiP = p - point;
109
110      // If we're beyond origin...
111      if(minkowskiP.x < 0 || minkowskiP.y < 0)
112         return false;
113
114      // Or past extent...
115      if(minkowskiP.x > extent.x || minkowskiP.y > extent.y)
116         return false;
117
118      // Otherwise we're ok.
119      return true;
120   }
121
122   bool contains(const RectF& R) const;
123
124   void unionRects( const RectF &rect );
125
126   F32 len_x() const;
127   F32 len_y() const;
128
129   bool isValidRect() const { return (extent.x > 0.0f && extent.y > 0.0f); }
130   inline bool intersectTriangle(const Point2F &a, const Point2F &b, const Point2F &c);
131
132};
133
134class RectD
135{
136  public:
137   Point2D  point;
138   Point2D  extent;
139
140  public:
141   RectD() { }
142   RectD(const Point2D& in_rMin,
143         const Point2D& in_rExtent);
144   RectD(const F64 in_left,  const F64 in_top,
145         const F64 in_width, const F64 in_height);
146   void inset(F64 x, F64 y);
147
148   bool intersect(const RectD& clipRect);
149   F64 len_x() const;
150   F64 len_y() const;
151
152   bool isValidRect() const { return (extent.x > 0 && extent.y > 0); }
153};
154
155//------------------------------------------------------------------------------
156//-------------------------------------- INLINES (RectI)
157//
158inline
159RectI::RectI(const Point2I& in_rMin,
160             const Point2I& in_rExtent)
161 : point(in_rMin),
162   extent(in_rExtent)
163{
164   //
165}
166
167inline
168RectI::RectI(const S32 in_left,  const S32 in_top,
169             const S32 in_width, const S32 in_height)
170 : point(in_left,  in_top),
171   extent(in_width, in_height)
172{
173   //
174}
175
176inline void RectI::set(const Point2I& in_rMin, const Point2I& in_rExtent)
177{
178   point = in_rMin;
179   extent = in_rExtent;
180}
181
182inline void RectI::set(const S32 in_left,  const S32 in_top,
183                      const S32 in_width, const S32 in_height)
184{
185   point.set(in_left,  in_top);
186   extent.set(in_width, in_height);
187}
188
189inline bool RectI::intersect(const RectI& clipRect)
190{
191   Point2I bottomL;
192   bottomL.x = getMin(point.x + extent.x - 1, clipRect.point.x + clipRect.extent.x - 1);
193   bottomL.y = getMin(point.y + extent.y - 1, clipRect.point.y + clipRect.extent.y - 1);
194
195   point.x = getMax(point.x, clipRect.point.x);
196   point.y = getMax(point.y, clipRect.point.y);
197
198   extent.x = bottomL.x - point.x + 1;
199   extent.y = bottomL.y - point.y + 1;
200
201   return isValidRect();
202}
203
204inline bool RectI::pointInRect(const Point2I &pt) const
205{
206   return (pt.x >= point.x && pt.x < point.x + extent.x && pt.y >= point.y && pt.y < point.y + extent.y);
207}
208
209inline bool RectI::contains(const RectI& R) const
210{
211   if (point.x <= R.point.x && point.y <= R.point.y)
212    if (R.point.x + R.extent.x <= point.x + extent.x)
213     if (R.point.y + R.extent.y <= point.y + extent.y)
214      return true;
215   return false;
216}
217
218inline bool RectI::overlaps(RectI R) const
219{
220   return R.intersect (* this);
221}
222
223inline void RectI::inset(S32 x, S32 y)
224{
225   point.x += x;
226   point.y += y;
227   extent.x -= 2 * x;
228   extent.y -= 2 * y;
229}
230
231inline void RectF::inset(F32 x, F32 y)
232{
233   point.x += x;
234   point.y += y;
235   extent.x -= 2.0f * x;
236   extent.y -= 2.0f * y;
237}
238
239inline void RectD::inset(F64 x, F64 y)
240{
241   point.x += x;
242   point.y += y;
243   extent.x -= 2.0 * x;
244   extent.y -= 2.0 * y;
245}
246
247
248inline void RectI::unionRects(const RectI& u)
249{
250   S32 minx = point.x < u.point.x ? point.x : u.point.x;
251   S32 miny = point.y < u.point.y ? point.y : u.point.y;
252   S32 maxx = (point.x + extent.x) > (u.point.x + u.extent.x) ? (point.x + extent.x) : (u.point.x + u.extent.x);
253   S32 maxy = (point.y + extent.y) > (u.point.y + u.extent.y) ? (point.y + extent.y) : (u.point.y + u.extent.y);
254
255   point.x  = minx;
256   point.y  = miny;
257   extent.x = maxx - minx;
258   extent.y = maxy - miny;
259}
260
261inline S32
262RectI::len_x() const
263{
264   return extent.x;
265}
266
267inline S32
268RectI::len_y() const
269{
270   return extent.y;
271}
272
273inline bool
274RectI::operator==(const RectI& in_rCompare) const
275{
276   return (point == in_rCompare.point) && (extent == in_rCompare.extent);
277}
278
279inline bool
280RectI::operator!=(const RectI& in_rCompare) const
281{
282   return (operator==(in_rCompare) == false);
283}
284
285//------------------------------------------------------------------------------
286//-------------------------------------- INLINES (RectF)
287//
288inline
289RectF::RectF(const Point2F& in_rMin,
290             const Point2F& in_rExtent)
291 : point(in_rMin),
292   extent(in_rExtent)
293{
294   //
295}
296
297inline
298RectF::RectF(const F32 in_left,  const F32 in_top,
299             const F32 in_width, const F32 in_height)
300 : point(in_left,  in_top),
301   extent(in_width, in_height)
302{
303   //
304}
305
306inline F32
307RectF::len_x() const
308{
309   return extent.x;
310}
311
312inline F32
313RectF::len_y() const
314{
315   return extent.y;
316}
317
318inline void RectF::set(const Point2F& in_rMin, const Point2F& in_rExtent)
319{
320   point = in_rMin;
321   extent = in_rExtent;
322}
323
324inline void RectF::set(const F32 in_left,  const F32 in_top,
325                       const F32 in_width, const F32 in_height)
326{
327   point.set(in_left,  in_top);
328   extent.set(in_width, in_height);
329}
330
331inline F32 RectF::getDistanceToPoint( const Point2F &refPt ) const
332{
333   return mSqrt( getSqDistanceToPoint( refPt ) );
334}
335
336inline F32 RectF::getSqDistanceToPoint( const Point2F &refPt ) const
337{
338   const Point2F maxPoint( point + extent );
339
340   F32 sqDist = 0.0f;
341
342   for ( U32 i=0; i < 2; i++ )
343   {
344      const F32 v = refPt[i];
345      if ( v < point[i] )
346         sqDist += mSquared( point[i] - v );
347      else if ( v > maxPoint[i] )
348         sqDist += mSquared( v - maxPoint[i] );
349   }
350
351   return sqDist;
352}
353
354inline bool RectF::intersect(const RectF& clipRect)
355{
356   Point2F bottomL;
357   bottomL.x = getMin(point.x + extent.x, clipRect.point.x + clipRect.extent.x);
358   bottomL.y = getMin(point.y + extent.y, clipRect.point.y + clipRect.extent.y);
359
360   point.x = getMax(point.x, clipRect.point.x);
361   point.y = getMax(point.y, clipRect.point.y);
362
363   extent.x = bottomL.x - point.x;
364   extent.y = bottomL.y - point.y;
365
366   return isValidRect();
367}
368
369inline bool RectF::pointInRect(const Point2F &pt) const
370{
371   return (pt.x >= point.x && pt.x < point.x + extent.x && pt.y >= point.y && pt.y < point.y + extent.y);
372}
373
374inline bool RectF::overlaps(const RectF& clipRect) const
375{
376   RectF test = *this;
377   return test.intersect(clipRect);
378}
379
380inline bool lineToLineIntersect(const Point2F & a1, const Point2F & a2, const Point2F & b1, const Point2F & b2)
381{
382   const F32 ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x);
383   const F32 ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x);
384   const F32 u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
385
386   if(u_b != 0)
387   {
388      const F32 ua = ua_t / u_b;
389      const F32 ub = ub_t / u_b;
390
391      return ( 0.0f <= ua && ua <= 1.0f && 0.0f <= ub && ub <= 1.0f );
392   }
393   else
394   {
395      return ( ua_t == 0 || ub_t == 0 );
396   }
397}
398
399inline bool RectF::intersectTriangle(const Point2F &a, const Point2F &b, const Point2F &c)
400{
401   const Point2F topLeft     = point;
402   const Point2F topRight    = Point2F( point.x + extent.x, point.y );
403   const Point2F bottomLeft  = Point2F( point.x, point.y + extent.y );
404   const Point2F bottomRight = point + extent;
405
406   // 3 point plus 12 edge tests.
407
408   // Check each triangle point to see if it's in us.
409   if(contains(a) || contains(b) || contains(c))
410      return true;
411
412   // Check a-b against the rect.
413   if(lineToLineIntersect(topLeft, topRight, a, b))
414      return true;
415
416   if(lineToLineIntersect(topRight, bottomRight, a, b))
417      return true;
418
419   if(lineToLineIntersect(bottomRight, bottomLeft, a, b))
420      return true;
421
422   if(lineToLineIntersect(bottomLeft, topLeft, a, b))
423      return true;
424
425   // Check b-c
426   if(lineToLineIntersect(topLeft, topRight, b, c))
427      return true;
428
429   if(lineToLineIntersect(topRight, bottomRight, b, c))
430      return true;
431
432   if(lineToLineIntersect(bottomRight, bottomLeft, b, c))
433      return true;
434
435   if(lineToLineIntersect(bottomLeft, topLeft, b, c))
436      return true;
437
438   // Check c-a
439   if(lineToLineIntersect(topLeft, topRight, c, a))
440      return true;
441
442   if(lineToLineIntersect(topRight, bottomRight, c, a))
443      return true;
444
445   if(lineToLineIntersect(bottomRight, bottomLeft, c, a))
446      return true;
447
448   if(lineToLineIntersect(bottomLeft, topLeft, c, a))
449      return true;
450
451   return false;
452}
453
454inline bool RectF::contains(const RectF& R) const
455{
456   if (point.x <= R.point.x && point.y <= R.point.y)
457      if (R.point.x + R.extent.x <= point.x + extent.x)
458         if (R.point.y + R.extent.y <= point.y + extent.y)
459            return true;
460   return false;
461}
462
463inline void RectF::unionRects( const RectF &r )
464{
465   F32 minx = point.x < r.point.x ? point.x : r.point.x;
466   F32 miny = point.y < r.point.y ? point.y : r.point.y;
467   F32 maxx = (point.x + extent.x) > (r.point.x + r.extent.x) ? (point.x + extent.x) : (r.point.x + r.extent.x);
468   F32 maxy = (point.y + extent.y) > (r.point.y + r.extent.y) ? (point.y + extent.y) : (r.point.y + r.extent.y);
469
470   point.x  = minx;
471   point.y  = miny;
472   extent.x = maxx - minx;
473   extent.y = maxy - miny;
474}
475
476//------------------------------------------------------------------------------
477//-------------------------------------- INLINES (RectD)
478//
479inline
480RectD::RectD(const Point2D& in_rMin,
481             const Point2D& in_rExtent)
482 : point(in_rMin),
483   extent(in_rExtent)
484{
485   //
486}
487
488inline
489RectD::RectD(const F64 in_left,  const F64 in_top,
490             const F64 in_width, const F64 in_height)
491 : point(in_left,  in_top),
492   extent(in_width, in_height)
493{
494   //
495}
496
497inline F64
498RectD::len_x() const
499{
500   return extent.x;
501}
502
503inline F64
504RectD::len_y() const
505{
506   return extent.y;
507}
508
509inline bool RectD::intersect(const RectD& clipRect)
510{
511   Point2D bottomL;
512   bottomL.x = getMin(point.x + extent.x, clipRect.point.x + clipRect.extent.x);
513   bottomL.y = getMin(point.y + extent.y, clipRect.point.y + clipRect.extent.y);
514
515   point.x = getMax(point.x, clipRect.point.x);
516   point.y = getMax(point.y, clipRect.point.y);
517
518   extent.x = bottomL.x - point.x;
519   extent.y = bottomL.y - point.y;
520
521   return isValidRect();
522}
523
524#endif //_RECT_H_
525