#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 aLeft; int aTop; int aRight; int aBottom; int bLeft; int bTop; int 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_left, other.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__