///////////////////////////////////////////////////////////////////////////// // Name: block.h // Purpose: Rectangular selection storage classes for ints and doubles // Author: John Labenski // Created: 07/01/02 // Copyright: (c) John Labenski, 2004 // License: wxWidgets ///////////////////////////////////////////////////////////////////////////// #ifndef __wxBLOCK_H__ #define __wxBLOCK_H__ #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma interface "block.h" #endif #include "wx/geometry.h" #include "wx/things/thingdef.h" //#define USE_wxRANGE #ifdef USE_wxRANGE #include "wx/things/range.h" #endif // Note: Why are these not just wxRect2DXXX with m_x and m_width? // because the double blocks need to match up at the edges and x+width // does not always exactly equal the edge of an adjoining block class WXDLLIMPEXP_THINGS wxBlockInt; class WXDLLIMPEXP_THINGS wxBlockDouble; class WXDLLIMPEXP_THINGS wxBlockIntSelection; class WXDLLIMPEXP_THINGS wxBlockDoubleSelection; #include "wx/dynarray.h" WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockInt, wxArrayBlockInt, class WXDLLIMPEXP_THINGS); WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockDouble, wxArrayBlockDouble, class WXDLLIMPEXP_THINGS); WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockIntSelection, wxArrayBlockIntSelection, class WXDLLIMPEXP_THINGS); WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockDoubleSelection, wxArrayBlockDoubleSelection, class WXDLLIMPEXP_THINGS); //============================================================================= // wxBlockXXX constants //============================================================================= // wxEmptyBlockXXX = (0,0,-1,-1) WXDLLIMPEXP_DATA_THINGS(extern const wxBlockInt) wxEmptyBlockInt; WXDLLIMPEXP_DATA_THINGS(extern const wxBlockDouble) wxEmptyBlockDouble; //============================================================================= // wxBlockXXX sorting functions //============================================================================= enum wxBlockSort_Type { wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT, wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT, wxBLOCKSORT_BOTTOMLEFT_TOPRIGHT, wxBLOCKSORT_BOTTOMRIGHT_TOPLEFT, wxBLOCKSORT_SMALLEST_TO_LARGEST, wxBLOCKSORT_LARGEST_TO_SMALLEST }; // functions to sort an array of blocks from any corner extern void wxArrayBlockIntSort(wxArrayBlockInt &blocks, wxBlockSort_Type type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT); extern void wxArrayBlockDoubleSort(wxArrayBlockDouble &blocks, wxBlockSort_Type type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT); //============================================================================= // wxBlockInt - a rectangle bounded by the corner points that can combine with // other wxBlockInts //============================================================================= class WXDLLIMPEXP_THINGS wxBlockInt { public: inline wxBlockInt(wxInt32 x1=0, wxInt32 y1=0, wxInt32 x2=0, wxInt32 y2=0) : m_x1(x1), m_y1(y1), m_x2(x2), m_y2(y2) {} inline wxBlockInt(const wxRect2DInt &rect) : m_x1(rect.m_x), m_y1(rect.m_y), m_x2(rect.GetRight()), m_y2(rect.GetBottom()) {} inline wxInt32 GetLeft() const { return m_x1; } inline wxInt32 GetRight() const { return m_x2; } inline wxInt32 GetTop() const { return m_y1; } inline wxInt32 GetBottom() const { return m_y2; } inline wxInt32 GetWidth() const { return m_x2 - m_x1 + 1; } inline wxInt32 GetHeight() const { return m_y2 - m_y1 + 1; } inline wxPoint2DInt GetLeftTop() const { return wxPoint2DInt(m_x1, m_y1); } inline wxPoint2DInt GetLeftBottom() const { return wxPoint2DInt(m_x1, m_y2); } inline wxPoint2DInt GetRightTop() const { return wxPoint2DInt(m_x2, m_y1); } inline wxPoint2DInt GetRightBottom() const { return wxPoint2DInt(m_x2, m_y2); } inline wxRect2DInt GetRect2DInt() const { return wxRect2DInt(m_x1, m_y1, m_x2-m_x1+1, m_y2-m_y1+1); } inline void SetRect2DInt(const wxRect2DInt &r) { m_x1=r.m_x; m_y1=r.m_y, m_x2=r.GetRight(); m_y2=r.GetBottom(); } inline bool Contains( wxInt32 x, wxInt32 y ) const { return ((x >= m_x1) && (x <= m_x2) && (y >= m_y1) && (y <= m_y2)); } inline bool Contains( const wxPoint2DInt &pt ) const { return Contains(pt.m_x, pt.m_y); } inline bool Contains( const wxBlockInt &b ) const { return ((m_x1 <= b.m_x1) && (b.m_x2 <= m_x2) && (m_y1 <= b.m_y1) && (b.m_y2 <= m_y2)); } inline bool Intersects( const wxBlockInt &b ) const { return (wxMax(m_x1, b.m_x1)<=wxMin(m_x2, b.m_x2)) && (wxMax(m_y1, b.m_y1)<=wxMin(m_y2, b.m_y2)); } inline void Intersect( const wxBlockInt &otherBlock ) { Intersect( *this, otherBlock, this ); } inline void Intersect( const wxBlockInt &src1 , const wxBlockInt &src2 , wxBlockInt *dest ) const { dest->m_x1 = wxMax(src1.m_x1, src2.m_x1); dest->m_x2 = wxMin(src1.m_x2, src2.m_x2); dest->m_y1 = wxMax(src1.m_y1, src2.m_y1); dest->m_y2 = wxMin(src1.m_y2, src2.m_y2); } inline void Union( const wxBlockInt &otherBlock ) { Union(*this, otherBlock, this); } inline void Union( const wxBlockInt &src1, const wxBlockInt &src2, wxBlockInt *dest ) const { dest->m_x1 = wxMin(src1.m_x1, src2.m_x1); dest->m_x2 = wxMax(src1.m_x2, src2.m_x2); dest->m_y1 = wxMin(src1.m_y1, src2.m_y1); dest->m_y2 = wxMax(src1.m_y2, src2.m_y2); } // is this block larger than input block, return 1 = larger, 0 = equal, -1 = smaller int IsLarger(const wxBlockInt &b) const { wxInt32 width = m_x2 - m_x1 + 1, height = m_y2 - m_y1 + 1, b_width = b.m_x2 - b.m_x1 + 1, b_height = b.m_y2 - b.m_y1 + 1; if ((width <= 0) || (height <= 0)) return (b_width > 0) && (b_height > 0) ? -1 : 0; if ((b_width <= 0) || (b_height <= 0)) return (width > 0) && (height > 0) ? 1 : 0; wxDouble w_bw = wxDouble(width)/b_width, bh_h = wxDouble(b_height)/height; return (w_bw == bh_h) ? 0 : ((w_bw > bh_h) ? 1 : -1); } bool IsEmpty() const { return (m_x1 > m_x2) || (m_y1 > m_y2); } // Unlike Intersects this also includes just touching the other block bool Touches(const wxBlockInt &block) const; // Try to combine these blocks, they must touch and fit to make a single larger block // this block is expanded if possible bool Combine(const wxBlockInt &block); // test combining the input block with this one, returning the // remainder of block in top, bottom, left, right - each may be IsEmpty() // returns false if blocks don't touch or this block already contains block // |---------------------------| // | top | // |---------------------------| // | left |block| right | // |---------------------------| // | bottom | // |---------------------------| bool Combine( const wxBlockInt &block, wxBlockInt &top, wxBlockInt &bottom, wxBlockInt &left, wxBlockInt &right) const; // test removal of a portion or all of this contained in block returning the // remainder in top, bottom, left, right - each may be IsEmpty() // returns false if nothing to delete, this cell is not changed bool Delete(const wxBlockInt &block, wxBlockInt &top, wxBlockInt &bottom, wxBlockInt &left, wxBlockInt &right) const; // operators inline bool operator == (const wxBlockInt& b) { return (m_x1==b.m_x1) && (m_y1==b.m_y1) && (m_x2==b.m_x2) && (m_y2==b.m_y2); } inline bool operator != (const wxBlockInt& b) { return !(*this == b); } wxInt32 m_x1, m_y1, m_x2, m_y2; }; //============================================================================= // wxBlockDouble //============================================================================= class WXDLLIMPEXP_THINGS wxBlockDouble { public: inline wxBlockDouble(wxDouble x1=0, wxDouble y1=0, wxDouble x2=0, wxDouble y2=0) : m_x1(x1), m_y1(y1), m_x2(x2), m_y2(y2) {} inline wxBlockDouble(const wxRect2DDouble &rect) { m_x1=rect.m_x; m_y1=rect.m_y; m_x2=rect.GetRight(); m_y2=rect.GetBottom(); } inline wxDouble GetLeft() const { return m_x1; } inline wxDouble GetRight() const { return m_x2; } inline wxDouble GetTop() const { return m_y1; } inline wxDouble GetBottom() const { return m_y2; } inline wxDouble GetWidth() const { return m_x2 - m_x1; } inline wxDouble GetHeight() const { return m_y2 - m_y1; } inline wxPoint2DDouble GetLeftTop() const { return wxPoint2DDouble(m_x1, m_y1); } inline wxPoint2DDouble GetLeftBottom() const { return wxPoint2DDouble(m_x1, m_y2); } inline wxPoint2DDouble GetRightTop() const { return wxPoint2DDouble(m_x2, m_y1); } inline wxPoint2DDouble GetRightBottom() const { return wxPoint2DDouble(m_x2, m_y2); } inline wxRect2DDouble GetRect2DDouble() const { return wxRect2DDouble(m_x1, m_y1, m_x2-m_x1, m_y2-m_y1); } inline void SetRect2DDouble(const wxRect2DDouble &r) { m_x1=r.m_x; m_y1=r.m_y, m_x2=r.GetRight(); m_y2=r.GetBottom(); } inline bool Contains( wxDouble x, wxDouble y ) const { return ((x >= m_x1) && (x <= m_x2) && (y >= m_y1) && (y <= m_y2)); } inline bool Contains( const wxPoint2DDouble &pt ) const { return Contains(pt.m_x, pt.m_y); } inline bool Contains( const wxBlockDouble &b ) const { return ((m_x1 <= b.m_x1) && (b.m_x2 <= m_x2) && (m_y1 <= b.m_y1) && (b.m_y2 <= m_y2)); } inline bool Intersects( const wxBlockDouble &b ) const { return (wxMax(m_x1, b.m_x1)m_x1 = wxMax(src1.m_x1, src2.m_x1); dest->m_x2 = wxMin(src1.m_x2, src2.m_x2); dest->m_y1 = wxMax(src1.m_y1, src2.m_y1); dest->m_y2 = wxMin(src1.m_y2, src2.m_y2); } inline void Union( const wxBlockDouble &otherBlock ) { Union( *this, otherBlock, this ); } inline void Union( const wxBlockDouble &src1, const wxBlockDouble &src2, wxBlockDouble *dest ) const { dest->m_x1 = wxMin(src1.m_x1, src2.m_x1); dest->m_x2 = wxMax(src1.m_x2, src2.m_x2); dest->m_y1 = wxMin(src1.m_y1, src2.m_y1); dest->m_y2 = wxMax(src1.m_y2, src2.m_y2); } // is this block larger than input block, return 1 - larger, 0 = equal, -1 smaller int IsLarger(const wxBlockDouble &b) const { wxDouble width = m_x2 - m_x1, height = m_y2 - m_y1, b_width = b.m_x2 - b.m_x1, b_height = b.m_y2 - b.m_y1; if ((width <= 0) || (height <= 0)) return (b_width > 0) && (b_height > 0) ? -1 : 0; if ((b_width <= 0) || (b_height <= 0)) return (width > 0) && (height > 0) ? 1 : 0; wxDouble w_bw = width/b_width, bh_h = b_height/height; return (w_bw == bh_h) ? 0 : ((w_bw > bh_h) ? 1 : -1); } inline bool IsEmpty() const { return (m_x1 > m_x2) || (m_y1 > m_y2); } // Unlike Intersects this also includes just touching the other block bool Touches(const wxBlockDouble &block) const; // Try to combine these blocks, they must touch and fit to make a single larger block // this block is expanded if possible bool Combine(const wxBlockDouble &block); // test combining the input block with this one, returning the // remainder of block in top, bottom, left, right - each may be IsEmpty() // returns false if blocks don't touch or this block already contains block // |---------------------------| // | top | // |---------------------------| // | left |block| right | // |---------------------------| // | bottom | // |---------------------------| bool Combine( const wxBlockDouble &block, wxBlockDouble &top, wxBlockDouble &bottom, wxBlockDouble &left, wxBlockDouble &right) const; // test removal of a portion or all of this contained in block returning the // remainder in top, bottom, left, right - each may be IsEmpty() // returns false if nothing to delete, this cell is not changed bool Delete( const wxBlockDouble &block, wxBlockDouble &top, wxBlockDouble &bottom, wxBlockDouble &left, wxBlockDouble &right) const; // operators inline bool operator == (const wxBlockDouble& b) { return (m_x1==b.m_x1) && (m_y1==b.m_y1) && (m_x2==b.m_x2) && (m_y2==b.m_y2); } inline bool operator != (const wxBlockDouble& b) { return !(*this == b); } wxDouble m_x1, m_y1, m_x2, m_y2; }; //============================================================================= // wxBlockIntSelection - ordered 2D array of wxBlockInts, combines to minimize size // blocks never overlap each other //============================================================================= class WXDLLIMPEXP_THINGS wxBlockIntSelection { public : wxBlockIntSelection(wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT) : m_sort(sort_type) {} wxBlockIntSelection(const wxBlockIntSelection &blocks, wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT) : m_sort(sort_type) { Copy(blocks); } // Make a full copy of the source void Copy(const wxBlockIntSelection &source) { m_blocks.Clear(); WX_APPEND_ARRAY(m_blocks, source.GetBlockArray()); m_sort = source.GetSortType(); } inline int GetCount() const { return m_blocks.GetCount(); } inline void Clear() { m_blocks.Clear(); } wxArrayBlockInt GetBlockArray() const { return m_blocks; } #ifdef USE_wxRANGE // Get an array of ranges cutting though these blocks wxArrayRangeInt GetBlockCol(int col) const; wxArrayRangeInt GetBlockRow(int row) const; #endif wxBlockInt GetBlock( int index ) const; inline wxBlockInt Item( int index ) const { return GetBlock(index); } // Get a block that bounds the selection wxBlockInt GetBoundingBlock() const; // do any of the blocks contains elements inline bool Contains( int x, int y ) const { return Index(x,y) != wxNOT_FOUND; } inline bool Contains( const wxPoint2DInt &pt ) const { return Index(pt) != wxNOT_FOUND; } inline bool Contains( const wxBlockInt &b ) const { return Index(b) != wxNOT_FOUND; } // what is the index of a block that contains element int Index( int x, int y ) const; inline int Index( const wxPoint2DInt &pt ) const { return Index(pt.m_x, pt.m_y); } int Index( const wxBlockInt &b ) const; // Sorts the blocks according to the wxBlockIntSort_Type void Sort(wxBlockSort_Type type = wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT); wxBlockSort_Type GetSortType() const { return m_sort; } // Add the block to the selection, returns false if nothing was done // use combineNow=false to make quick additions, when done call Minimize() // addedBlocks (if !NULL) will be filled with the actual changed selections // by removing the previous selections from the input block bool SelectBlock( const wxBlockInt &block, bool combineNow=true, wxArrayBlockInt *addedBlocks=NULL); // Remove the block to the selection, return false if nothing was done // use combineNow=false to make quick additions, when done call Minimize() bool DeselectBlock( const wxBlockInt &block, bool combineNow=true); // Try to combine the blocks if possible, returns if anything was done // only need to call this if you've called (De)SelectBlock(..., false) bool Minimize(); // Operators inline wxBlockInt operator[](int index) const { return GetBlock(index); } //wxBlockIntSelection& operator = (const wxBlockIntSelection& other) { Copy(other); return *this; } // generic routine using if (b1.Combine(b2)) remove b2 to cleanup array // sort top_left_bottom_right first (internal use) static bool DoMinimize( wxArrayBlockInt &blocks ); // DoMinimize calls this internally static bool DoDoMinimize( wxArrayBlockInt &blocks ); protected : wxArrayBlockInt m_blocks; wxBlockSort_Type m_sort; }; //============================================================================= // wxBlockDoubleSelection - ordered 2D array of wxBlockDoubles, combines to minimze size // blocks never overlap each other //============================================================================= class WXDLLIMPEXP_THINGS wxBlockDoubleSelection { public : wxBlockDoubleSelection(wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT) : m_sort(sort_type) {} wxBlockDoubleSelection(const wxBlockDoubleSelection &blocks, wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT) : m_sort(sort_type) { Copy(blocks); } // Make a full copy of the source void Copy(const wxBlockDoubleSelection &source) { m_blocks.Clear(); WX_APPEND_ARRAY(m_blocks, source.GetBlockArray()); m_sort = source.GetSortType(); } inline int GetCount() const { return m_blocks.GetCount(); } inline void Clear() { m_blocks.Clear(); } wxArrayBlockDouble GetBlockArray() const { return m_blocks; } #ifdef USE_wxRANGE // Get an array of ranges cutting though these blocks wxArrayRangeDouble GetBlockCol(wxDouble col) const; wxArrayRangeDouble GetBlockRow(wxDouble row) const; #endif wxBlockDouble GetBlock( int index ) const; inline wxBlockDouble Item( int index ) const { return GetBlock(index); } // Get a block that bounds the selection wxBlockDouble GetBoundingBlock() const; // do any of the blocks contains elements inline bool Contains( wxDouble x, wxDouble y ) const { return Index(wxPoint2DDouble(x,y)) != wxNOT_FOUND; } inline bool Contains( const wxPoint2DInt &pt ) const { return Index(pt) != wxNOT_FOUND; } inline bool Contains( const wxBlockDouble &b ) const { return Index(b) != wxNOT_FOUND; } // what is the index of a block that contains element int Index( wxDouble x, wxDouble y ) const; inline int Index( const wxPoint2DDouble &pt ) const { return Index(pt.m_x, pt.m_y); } int Index( const wxBlockDouble &b ) const; // Sorts the blocks according to the wxBlockIntSort_Type void Sort(wxBlockSort_Type type = wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT); wxBlockSort_Type GetSortType() const { return m_sort; } // Add the block to the selection, returns false if nothing was done // use combineNow=false to make quick additions, when done call Minimize() bool SelectBlock( const wxBlockDouble &block, bool combineNow=true); // Remove the block to the selection, return false if nothing was done // use combineNow=false to make quick additions, when done call Minimize() bool DeselectBlock( const wxBlockDouble &block, bool combineNow=true); // Try to combine the blocks if possible, returns if anything was done // only need to call this if you've called (De)SelectBlock(..., false) bool Minimize(); // Operators inline wxBlockDouble operator[](int index) const { return GetBlock(index); } //wxBlockIntSelection& operator = (const wxBlockIntSelection& other) { Copy(other); return *this; } // generic routine using if (b1.Combine(b2)) remove b2 to cleanup array // sort top_left_bottom_right first (internal use) static bool DoMinimize( wxArrayBlockDouble &blocks ); // DoMinimize calls this internally static bool DoDoMinimize( wxArrayBlockDouble &blocks ); protected : wxArrayBlockDouble m_blocks; wxBlockSort_Type m_sort; }; //============================================================================= // wxBlockIntSelectionIterator - iterates through a wxBlockIntSelection //============================================================================= enum wxBISI_Type { wxBISI_POINT, // wxBlockIntSelectionIterator::SetType go point by point wxBISI_BLOCK // go block by block }; class WXDLLIMPEXP_THINGS wxBlockIntSelectionIterator { public : wxBlockIntSelectionIterator( const wxBlockIntSelection &sel, wxBISI_Type type = wxBISI_POINT ); wxBlockIntSelectionIterator( const wxArrayBlockInt &blocks, wxBISI_Type type = wxBISI_POINT ); // resets the iterating to start at the beginning void Reset(); // Set the method to get the blocks, either point by point or each whole block // also resets the iteration to the beginning void SetType( wxBISI_Type type ) { m_type = type; Reset(); } wxBISI_Type GetType() const { return m_type; } // Get next selection, returns false if at end (only valid for wxBISI_point) bool GetNext(wxPoint2DInt &pt); // Get next selection, returns false if at end (only valid for wxBISI_block) bool GetNext(wxBlockInt &block); // checks if this row and col are in this selection bool IsInSelection(const wxPoint2DInt &pt) const; inline bool IsInSelection( int x, int y ) const { return IsInSelection(wxPoint2DInt(x,y)); } protected : wxBISI_Type m_type; int m_block_index; wxPoint2DInt m_pt; wxArrayBlockInt m_blocks; }; //============================================================================= // wxBlockDoubleSelectionIterator - iterates through a wxBlockDoubleSelection //============================================================================= class WXDLLIMPEXP_THINGS wxBlockDoubleSelectionIterator { public : wxBlockDoubleSelectionIterator( const wxBlockDoubleSelection &sel ); wxBlockDoubleSelectionIterator( const wxArrayBlockDouble &blocks ); // resets the iterating to start at the beginning void Reset(); // Get next selection, returns false if at the end bool GetNext(wxBlockDouble &block); // checks if this row and col are in this selection bool IsInSelection(const wxPoint2DDouble &pt) const; inline bool IsInSelection( int x, int y ) const { return IsInSelection(wxPoint2DDouble(x,y)); } protected : size_t m_block_index; wxArrayBlockDouble m_blocks; }; #endif // __wxBLOCK_H__