#ifndef __TEST_RECTANGLE_H__

#define __TEST_RECTANGLE_H__

 

/*

 *   Testing for rectangle overlap

 */

 

 

struct TestPoint {

     int x;

     int y;

 

     TestPoint() : x(0), y(0) {}

     TestPoint(int x, int y)

     {

          this->x = x;

          this->y = y;

     }

};

 

struct TestRect {

     int m_left;

     int m_top;

     int m_right;

     int m_bottom;

 

     TestRect()

     {

          SetEmpty();

     }

 

     TestRect(const TestRect & aCopy)

     {

          SetRect(aCopy);

     }

 

     TestRect(int left, int top, int right, int bottom)

     {

          SetRect(left,top,right,bottom);

     }

 

     void SetEmpty()

     {

          m_left = m_top = m_right = m_bottom;

     }

 

     void SetRect(const TestRect & aCopy)

     {

          SetRect(aCopy.m_left,aCopy.m_top,aCopy.m_right,aCopy.m_bottom);

     }

 

     void SetRect(int left, int top, int right, int bottom)

     {

          m_left   = left;

          m_top    = top;

          m_right  = right;

          m_bottom = bottom;

     }

 

     TestPoint TopLeft() const

     {

          return TestPoint(m_top,m_left);

     }

 

     TestPoint TopRight() const

     {

          return TestPoint(m_top,m_right);

     }

 

     TestPoint BottomLeft() const

     {

          return TestPoint(m_bottom,m_left);

     }

 

     TestPoint BottomRight() const

     {

          return TestPoint(m_bottom,m_right);

     }

 

     bool IsEqual(const TestRect & other) const

     {

          return( (other.m_left  == m_left ) && (other.m_top    == m_top   ) &&

                  (other.m_right == m_right) && (other.m_bottom == m_bottom) );

     }

 

     int Width() const

     {

          return m_right-m_left;

     }

 

     int Height() const

     {

          return m_bottom-m_top;

     }

 

     bool HasArea() const

     {

          return(Width() > 0 && Height() > 0);

     }

 

     bool PointOnRect(int x, int y) const

     {

          return( x >= m_left && x <= m_right && y >= m_top && y <= m_bottom );

     }

 

     bool PointInRect(TestPoint point) const

     {

          return PointInRect(point.x, point.y);

     }

 

     bool PointInRect(int x, int y) const

     {

          return( x > m_left && x < m_right && y > m_top && y < m_bottom );

     }

 

#ifdef _DEBUG

     static bool TestGetUnion()

     {

          /* Samples of content overlap we check for

 

          0123456789ABCD     0123456789ABC    0123456789    0123456

          1 aaaaa  aaaaa         aaaaa        aaaaaaaaaa    aaaabbb

          2 a   a  a   a         a   a        a        a    a  a  b

          3 a BBBBBBBB a         a   a        a  bbbb  a    aaaa  b

          4 a B a  a B a         a   a        a  b  b  a    b     b

          5 aaBaa  aaBaa     bbbbabbbabbbb    a  b  b  a    bbbbbbb

          6   B      B       b   a   a   b    a  bbbb  a

          7 aaBaa  aaBaa     bbbbabbbabbbb    a        a    ababab

          8 a B a  a B a         a   a        aaaaaaaaaa    b    a

          9 a BBBBBBBB a         a   a                      ababab

          A a   a  a   a         a   a

          B aaaaa  aaaaa         aaaaa

         

          1 aaaa      aaabbbaaa

          2 a  a      a  b b  a

          3 bbbbbbb   aaababbaa

          4 b  a  b      b b

          5 bbbbbbb      bbb

 

          If the content does not overlap, we're not interested...

 

          0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789

          1 aaaaa       aaaa         aaa

          2 a   bbbbb   a  a         a a

          3 a   a   b   aaaBbbb      aaa  

          4 a   b   b      b  b      

          5 a   abbbb      bbbb       bbbbb

          6 aaaaa

          */

 

          typedef struct _tagTestData {

               int aLeftint aTopint aRight; int aBottom;

               int bLeftint bTopint bRight; int bBottom;

               bool shouldPass;

          } TestData;

 

          TestData data[] = {

               // Connect 4

               { 0x2,0x1,0x5,0x6, 0x4,0x3,0xb,0x9, true },

               { 0x9,0x1,0xd,0x5, 0x4,0x3,0xb,0x9, true },

               { 0x2,0x7,0x6,0xb, 0x4,0x3,0xb,0x9, true },

               { 0x9,0x7,0xd,0xb, 0x4,0x3,0xb,0x9, true },

              

               // +

               { 0x4,0x1,0x8,0xb, 0x0,0x5,0xc,0x7, true },

 

               // doughnut

               { 0x0,0x0,0x8,0x9, 0x3,0x3,0x6,0x6, true },

 

               // same overlapping area

               { 0,0,5,5,  0,0,5,5, true  },

 

               // smaller, but in the corner

               { 0,0,3,3,  0,0,6,6, true  },

              

               // "L"

               { 1,1,4,5,  1,3,7,5, true  },

 

               // "T"

               { 1,1,9,3,  4,1,6,5, true  },

 

               // Side by side

               { 1,1,6,6,  6,2,9,5, false },

 

               // Shared corner

               { 0,0,3,3,  3,3,6,6, false },

 

               // Off to the right

               { 0,0,2,2,  3,0,5,2, false },

              

               // Off to the bottom right

               { 0,0,2,2,  4,4,6,6, false },

 

               // Off to the bottom

               { 0,0,2,2,  0,4,2,4, false },

 

               // Null rect

               { 0,0,0,0,  0,0,4,4, false },

 

               // Inverted rect

               { 5,5,0,0,  0,0,5,5, false }

          };

 

          const int count = sizeof(data)/sizeof(data[0]);

 

          TestRect aBox,bBox;

          bool aResult = false, bResult = false;

          int maxX = 0, maxY = 0, x = 0, y = 0;

          enum {

               space   = 0x00,

               alpha   = 0x01,

               beta    = 0x02,

               overlap = alpha|beta

          };

          int character = space;

 

          for( int idx = 0; idx < count; idx++ )

          {

               // Build the rects

               aBox.SetRect( data[idx].aLeft, data[idx].aTop, data[idx].aRight, data[idx].aBottom );

               bBox.SetRect( data[idx].bLeft, data[idx].bTop, data[idx].bRight, data[idx].bBottom );

 

               // Test it both ways

               aResult = aBox.GetUnion(bBox, NULL);

               bResult = bBox.GetUnion(aBox, NULL);             

 

               // In an ideal world - this will always be false, but then again - we wouldn't need this test harness either

               if( (aResult != bResult) || (aResult != data[idx].shouldPass) )

               {

                    ATLTRACE("\nFound a problem with (%d,%d,%d,%d) (%d,%d,%d,%d) %d %d %d\n",

                         aBox.m_left,aBox.m_top,aBox.m_right,aBox.m_bottom,

                         bBox.m_left,bBox.m_top,bBox.m_right,bBox.m_bottom,

                         aResult, bResult, data[idx].shouldPass );

                    // Dump the rects to the output window so we can see what happened

                    maxX = max(aBox.m_right, bBox.m_right);

                    maxY = max(aBox.m_bottom, bBox.m_bottom);

                    for( y = 0; y <= maxY; y++ )

                    {                       

                         for( x = 0; x <= maxX; x++ )

                         {

                              character = space;

 

                              if( (aBox.m_left  == x && aBox.m_top    == y) || (aBox.m_left  == x && aBox.m_bottom == y) ||

                                   (aBox.m_right == x && aBox.m_top    == y) || (aBox.m_right == x && aBox.m_bottom == y) )

                              {

                                   character |= alpha;

                              }

                             

                              if( (bBox.m_left  == x && bBox.m_top    == y) || (bBox.m_left  == x && bBox.m_bottom == y) ||

                                   (bBox.m_right == x && bBox.m_top    == y) || (bBox.m_right == x && bBox.m_bottom == y) )

                              {

                                   character |= beta;

                              }

                             

                              switch( character )

                              {

                              case space:   ATLTRACE("."); break;

                              case alpha:   ATLTRACE("A"); break;

                              case beta:    ATLTRACE("B"); break;

                              case overlap: ATLTRACE("X"); break;

                              default:      ATLTRACE("?");

                              }

                         }

                         ATLTRACE("\n");

                    }

 

                    ATLASSERT(!"Not what we were expecting!");

                    return false;

               }

          }

 

          return true;

     }

#endif //_DEBUG

 

     bool GetUnion(const TestRect & other, TestRect * result) const

     {

          TestRect calc;

 

          // Make sure we have area

          if( !HasArea() || !other.HasArea() )

               return false;

 

          // Check for identical

          if( IsEqual(other) )

          {

               if( result )

                    result->SetRect(calc);

               return true;

          }

 

          // Disregard the obvious - boxes that are outside other boxes

          if( m_right < other.m_left )

               return false;

          if( m_bottom < other.m_top )

               return false;

          if( m_left > other.m_right )

               return false;

          if( m_top > other.m_bottom )

               return false;

 

          // Snap the edges to the minimum constraints of both boxes

          calc.m_left   = max(m_leftother.m_left);

          calc.m_right  = min(m_right, other.m_right);

          calc.m_top    = max(m_top,   other.m_top);

          calc.m_bottom = min(m_bottom,other.m_bottom);

 

          // No area == no union

          if( !calc.HasArea() )

               return false;

 

          // Set the union result value?

          if( result )

               result->SetRect(calc);

    

          return true;

     }

};

 

 

#endif //__TEST_RECTANGLE_H__