You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

517 lines
22 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// 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)<wxMin(m_x2, b.m_x2)) && (wxMax(m_y1, b.m_y1)<wxMin(m_y2, b.m_y2)); }
inline void Intersect( const wxBlockDouble &otherBlock ) { Intersect( *this, otherBlock, this ); }
inline void Intersect( const wxBlockDouble &src1 , const wxBlockDouble &src2 , wxBlockDouble *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 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__