1064 lines
31 KiB
Text
1064 lines
31 KiB
Text
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: block.cpp
|
|
// Purpose: Rectangular selection storage classes for ints and doubles
|
|
// Author: John Labenski
|
|
// Created: 07/01/02
|
|
// Copyright: (c) John Labenski 2004
|
|
// Licence: wxWidgets
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
|
|
#pragma implementation "block.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
//#include "wx/object.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/things/block.h"
|
|
|
|
// use this to check to see if there is any overlap after minimizing
|
|
//#define CHECK_BLOCK_OVERLAP 1
|
|
|
|
#define PRINT_BLOCK(msg, b) { wxPrintf(wxT("Block '%s' %lg %lg %lg %lg\n"), msg, (double)(b).m_x1, (double)(b).m_y1, (double)(b).m_x2, (double)(b).m_y2); }
|
|
|
|
wxBlockInt const wxEmptyBlockInt(0, 0, -1, -1);
|
|
wxBlockDouble const wxEmptyBlockDouble(0, 0, -1, -1);
|
|
|
|
#include "wx/arrimpl.cpp"
|
|
WX_DEFINE_OBJARRAY(wxArrayBlockInt);
|
|
WX_DEFINE_OBJARRAY(wxArrayBlockDouble);
|
|
WX_DEFINE_OBJARRAY(wxArrayBlockIntSelection);
|
|
WX_DEFINE_OBJARRAY(wxArrayBlockDoubleSelection);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Sorting functions for wxBlockInt
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static int wxCMPFUNC_CONV wxblockint_sort_topleft_bottomright( wxBlockInt **a, wxBlockInt **b)
|
|
{
|
|
register int y = ((*a)->m_y1 - (*b)->m_y1);
|
|
|
|
if (y < 0) return -1;
|
|
if (y == 0) return ((*a)->m_x1 - (*b)->m_x1);
|
|
return 1;
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockint_sort_topright_bottomleft( wxBlockInt **a, wxBlockInt **b)
|
|
{
|
|
register int y = ((*a)->m_y1 - (*b)->m_y1);
|
|
|
|
if (y < 0) return -1;
|
|
if (y == 0) return ((*a)->m_x2 - (*b)->m_x2);
|
|
return 1;
|
|
}
|
|
|
|
static int wxCMPFUNC_CONV wxblockint_sort_bottomleft_topright( wxBlockInt **a, wxBlockInt **b)
|
|
{
|
|
register int y = ((*a)->m_y2 - (*b)->m_y2);
|
|
|
|
if (y > 0) return -1;
|
|
if (y == 0) return ((*a)->m_x1 - (*b)->m_x1);
|
|
return 1;
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockint_sort_bottomright_topleft( wxBlockInt **a, wxBlockInt **b)
|
|
{
|
|
register int y = ((*a)->m_y2 - (*b)->m_y2);
|
|
|
|
if (y > 0) return -1;
|
|
if (y == 0) return ((*a)->m_x2 - (*b)->m_x2);
|
|
return 1;
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockint_sort_largest_to_smallest( wxBlockInt **a, wxBlockInt **b)
|
|
{
|
|
return (*a)->IsLarger(**b);
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockint_sort_smallest_to_largest( wxBlockInt **a, wxBlockInt **b)
|
|
{
|
|
return -(*a)->IsLarger(**b);
|
|
}
|
|
|
|
void wxArrayBlockIntSort(wxArrayBlockInt &blocks, wxBlockSort_Type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT : blocks.Sort(wxblockint_sort_topleft_bottomright); break;
|
|
case wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT : blocks.Sort(wxblockint_sort_topright_bottomleft); break;
|
|
case wxBLOCKSORT_BOTTOMLEFT_TOPRIGHT : blocks.Sort(wxblockint_sort_bottomleft_topright); break;
|
|
case wxBLOCKSORT_BOTTOMRIGHT_TOPLEFT : blocks.Sort(wxblockint_sort_bottomright_topleft); break;
|
|
case wxBLOCKSORT_SMALLEST_TO_LARGEST : blocks.Sort(wxblockint_sort_smallest_to_largest); break;
|
|
case wxBLOCKSORT_LARGEST_TO_SMALLEST : blocks.Sort(wxblockint_sort_largest_to_smallest); break;
|
|
default : wxFAIL_MSG(wxT("unknown block sort type"));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Sorting functions for wxBlockDouble
|
|
// ----------------------------------------------------------------------------
|
|
|
|
static int wxCMPFUNC_CONV wxblockdouble_sort_topleft_bottomright( wxBlockDouble **a, wxBlockDouble **b)
|
|
{
|
|
register wxDouble y = ((*a)->m_y1 - (*b)->m_y1);
|
|
|
|
if (y < 0) return -1;
|
|
if (y == 0) return int((*a)->m_x1 - (*b)->m_x1);
|
|
return 1;
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockdouble_sort_topright_bottomleft( wxBlockDouble **a, wxBlockDouble **b)
|
|
{
|
|
register wxDouble y = ((*a)->m_y1 - (*b)->m_y1);
|
|
|
|
if (y < 0) return -1;
|
|
if (y == 0) return int((*a)->m_x2 - (*b)->m_x2);
|
|
return 1;
|
|
}
|
|
|
|
static int wxCMPFUNC_CONV wxblockdouble_sort_bottomleft_topright( wxBlockDouble **a, wxBlockDouble **b)
|
|
{
|
|
register wxDouble y = ((*a)->m_y2 - (*b)->m_y2);
|
|
|
|
if (y > 0) return -1;
|
|
if (y == 0) return int((*a)->m_x1 - (*b)->m_x1);
|
|
return 1;
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockdouble_sort_bottomright_topleft( wxBlockDouble **a, wxBlockDouble **b)
|
|
{
|
|
register wxDouble y = ((*a)->m_y2 - (*b)->m_y2);
|
|
|
|
if (y > 0) return -1;
|
|
if (y == 0) return int((*a)->m_x2 - (*b)->m_x2);
|
|
return 1;
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockdouble_sort_largest_to_smallest( wxBlockDouble **a, wxBlockDouble **b)
|
|
{
|
|
return (*a)->IsLarger(**b);
|
|
}
|
|
static int wxCMPFUNC_CONV wxblockdouble_sort_smallest_to_largest( wxBlockDouble **a, wxBlockDouble **b)
|
|
{
|
|
return -(*a)->IsLarger(**b);
|
|
}
|
|
|
|
void wxArrayBlockDoubleSort(wxArrayBlockDouble &blocks, wxBlockSort_Type type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT : blocks.Sort(wxblockdouble_sort_topleft_bottomright); break;
|
|
case wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT : blocks.Sort(wxblockdouble_sort_topright_bottomleft); break;
|
|
case wxBLOCKSORT_BOTTOMLEFT_TOPRIGHT : blocks.Sort(wxblockdouble_sort_bottomleft_topright); break;
|
|
case wxBLOCKSORT_BOTTOMRIGHT_TOPLEFT : blocks.Sort(wxblockdouble_sort_bottomright_topleft); break;
|
|
case wxBLOCKSORT_SMALLEST_TO_LARGEST : blocks.Sort(wxblockdouble_sort_smallest_to_largest); break;
|
|
case wxBLOCKSORT_LARGEST_TO_SMALLEST : blocks.Sort(wxblockdouble_sort_largest_to_smallest); break;
|
|
default : wxFAIL_MSG(wxT("unknown block sort type"));
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// wxBlockInt
|
|
//=============================================================================
|
|
|
|
#define TEST_BLOCKS
|
|
|
|
#ifdef TEST_BLOCKS
|
|
void TestBlocks()
|
|
{
|
|
printf("Start Testing blocks -----------------------------------------\n");
|
|
wxBlockInt b1(1,1,4,4);
|
|
wxBlockInt b2(5,4,10,11);
|
|
PRINT_BLOCK("b1", b1)
|
|
PRINT_BLOCK("b2", b2)
|
|
|
|
wxBlockInt iB;
|
|
iB.Intersect(b1, b2, &iB);
|
|
PRINT_BLOCK("Intersect b1 b2", iB)
|
|
|
|
wxBlockInt uB;
|
|
uB.Union(b1, b2, &uB);
|
|
PRINT_BLOCK("Union b1 b2", uB)
|
|
|
|
printf("Touches b1 b2 %d %d\n", b1.Touches(b2), b2.Touches(b1));
|
|
|
|
b1 = wxBlockInt(2,3,7,9);
|
|
b2 = wxBlockInt(8,3,8,3);
|
|
printf("Touches b1 b2 %d %d\n", b1.Touches(b2), b2.Touches(b1));
|
|
|
|
b1 = wxBlockInt(2,3,7,9);
|
|
b2 = wxBlockInt(1,3,1,3);
|
|
printf("Touches b1 b2 %d %d\n", b1.Touches(b2), b2.Touches(b1));
|
|
iB.Intersect(b1, b2, &iB);
|
|
PRINT_BLOCK("Intersect b1 b2", iB)
|
|
|
|
b1 = wxBlockInt(2,3,7,9);
|
|
b2 = wxBlockInt(2,2,2,2);
|
|
printf("Touches b1 b2 %d %d\n", b1.Touches(b2), b2.Touches(b1));
|
|
|
|
b1 = wxBlockInt(2,3,7,9);
|
|
b2 = wxBlockInt(7,10,7,10);
|
|
printf("Touches b1 b2 %d %d\n", b1.Touches(b2), b2.Touches(b1));
|
|
|
|
printf("End Testing blocks -----------------------------------------\n");
|
|
fflush(stdout);
|
|
}
|
|
#endif //TEST_BLOCKS
|
|
|
|
bool wxBlockInt::Touches(const wxBlockInt &b) const // see Intersects
|
|
{
|
|
//if (((wxMax(m_x1, b.m_x1)) <= (wxMin(m_x2, b.m_x2))) &&
|
|
// ((wxMax(m_y1, b.m_y1)) <= (wxMin(m_y2, b.m_y2))))
|
|
// return true;
|
|
|
|
return Intersects(wxBlockInt(b.m_x1-1, b.m_y1-1, b.m_x2+1, b.m_y2+1));
|
|
|
|
/*
|
|
wxInt32 left = wxMax( m_x1, b.m_x1 );
|
|
wxInt32 right = wxMin( m_x2, b.m_x2 );
|
|
|
|
if (labs(left - right) <= 1)
|
|
{
|
|
wxInt32 top = wxMax( m_y1, b.m_y1 );
|
|
wxInt32 bottom = wxMin( m_y2, b.m_y2 );
|
|
if (labs(top - bottom) <= 1)
|
|
return true;
|
|
}
|
|
return false;
|
|
*/
|
|
}
|
|
|
|
bool wxBlockInt::Combine(const wxBlockInt &b)
|
|
{
|
|
if (!Touches(b)) return false;
|
|
if (Contains(b)) return true;
|
|
if (b.Contains(*this))
|
|
{
|
|
*this = b;
|
|
return true;
|
|
}
|
|
|
|
wxBlockInt unionBlock;
|
|
Union( *this, b, &unionBlock );
|
|
|
|
if (unionBlock.IsEmpty()) return false;
|
|
|
|
// at least one of the two blocks has to be at each corner of the union
|
|
if (((unionBlock.GetLeftTop() == GetLeftTop()) || (unionBlock.GetLeftTop() == b.GetLeftTop())) &&
|
|
((unionBlock.GetRightTop() == GetRightTop()) || (unionBlock.GetRightTop() == b.GetRightTop())) &&
|
|
((unionBlock.GetLeftBottom() == GetLeftBottom()) || (unionBlock.GetLeftBottom() == b.GetLeftBottom())) &&
|
|
((unionBlock.GetRightBottom() == GetRightBottom()) || (unionBlock.GetRightBottom() == b.GetRightBottom())) )
|
|
{
|
|
*this = unionBlock;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBlockInt::Combine( const wxBlockInt &block,
|
|
wxBlockInt &top, wxBlockInt &bottom,
|
|
wxBlockInt &left, wxBlockInt &right) const
|
|
{
|
|
top = bottom = left = right = wxEmptyBlockInt;
|
|
|
|
wxBlockInt iBlock;
|
|
Intersect(*this, block, &iBlock);
|
|
|
|
if (iBlock.IsEmpty()) return false; // nothing to combine
|
|
if (iBlock == *this) return true; // can combine all of this, no leftover
|
|
|
|
bool combined = false;
|
|
|
|
if ( block.m_y1 < m_y1 )
|
|
{
|
|
top = wxBlockInt( block.m_x1, block.m_y1, block.m_x2, m_y1-1 );
|
|
combined = true;
|
|
}
|
|
if ( block.m_y2 > m_y2 )
|
|
{
|
|
bottom = wxBlockInt( block.m_x1, m_y2+1, block.m_x2, block.m_y2 );
|
|
combined = true;
|
|
}
|
|
if ( block.m_x1 < m_x1 )
|
|
{
|
|
left = wxBlockInt( block.m_x1, iBlock.m_y1, m_x1-1, iBlock.m_y2 );
|
|
combined = true;
|
|
}
|
|
if ( block.m_x2 > m_x2 )
|
|
{
|
|
right = wxBlockInt( m_x2+1, iBlock.m_y1, block.m_x2, iBlock.m_y2 );
|
|
combined = true;
|
|
}
|
|
|
|
return combined;
|
|
}
|
|
|
|
bool wxBlockInt::Delete( const wxBlockInt &block,
|
|
wxBlockInt &top, wxBlockInt &bottom,
|
|
wxBlockInt &left, wxBlockInt &right) const
|
|
{
|
|
top = bottom = left = right = wxEmptyBlockInt;
|
|
|
|
wxBlockInt iBlock;
|
|
Intersect(*this, block, &iBlock);
|
|
|
|
if (iBlock.IsEmpty()) return false; // nothing to delete
|
|
if (iBlock == *this) return true; // can delete all of this, no leftover
|
|
|
|
bool deleted = false;
|
|
|
|
if ( m_y1 < iBlock.m_y1 )
|
|
{
|
|
top = wxBlockInt( m_x1, m_y1, m_x2, iBlock.m_y1-1 );
|
|
deleted = true;
|
|
}
|
|
if ( GetBottom() > iBlock.GetBottom() )
|
|
{
|
|
bottom = wxBlockInt( m_x1, iBlock.m_y2+1, m_x2, m_y2 );
|
|
deleted = true;
|
|
}
|
|
if ( m_x1 < iBlock.m_x1 )
|
|
{
|
|
left = wxBlockInt( m_x1, iBlock.m_y1, iBlock.m_x1-1, iBlock.m_y2 );
|
|
deleted = true;
|
|
}
|
|
if ( GetRight() > iBlock.GetRight() )
|
|
{
|
|
right = wxBlockInt( iBlock.m_x2+1, iBlock.m_y1, m_x2, iBlock.m_y2 );
|
|
deleted = true;
|
|
}
|
|
|
|
return deleted;
|
|
}
|
|
|
|
//=============================================================================
|
|
// wxBlockDouble
|
|
//=============================================================================
|
|
|
|
bool wxBlockDouble::Touches(const wxBlockDouble &b) const // see Intersects
|
|
{
|
|
if (((wxMax(m_x1, b.m_x1)) <= (wxMin(m_x2, b.m_x2))) &&
|
|
((wxMax(m_y1, b.m_y1)) <= (wxMin(m_y2, b.m_y2))))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBlockDouble::Combine(const wxBlockDouble &b)
|
|
{
|
|
if (!Touches(b)) return false;
|
|
if (Contains(b)) return true;
|
|
if (b.Contains(*this))
|
|
{
|
|
*this = b;
|
|
return true;
|
|
}
|
|
|
|
wxBlockDouble unionBlock;
|
|
Union( *this, b, &unionBlock );
|
|
|
|
if (unionBlock.IsEmpty()) return false;
|
|
|
|
// at least one of the two blocks has to be at each corner of the union
|
|
if (((unionBlock.GetLeftTop() == GetLeftTop()) || (unionBlock.GetLeftTop() == b.GetLeftTop())) &&
|
|
((unionBlock.GetRightTop() == GetRightTop()) || (unionBlock.GetRightTop() == b.GetRightTop())) &&
|
|
((unionBlock.GetLeftBottom() == GetLeftBottom()) || (unionBlock.GetLeftBottom() == b.GetLeftBottom())) &&
|
|
((unionBlock.GetRightBottom() == GetRightBottom()) || (unionBlock.GetRightBottom() == b.GetRightBottom())) )
|
|
{
|
|
*this = unionBlock;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBlockDouble::Combine( const wxBlockDouble &block,
|
|
wxBlockDouble &top, wxBlockDouble &bottom,
|
|
wxBlockDouble &left, wxBlockDouble &right) const
|
|
{
|
|
top = bottom = left = right = wxEmptyBlockDouble;
|
|
|
|
wxBlockDouble iBlock;
|
|
Intersect(*this, block, &iBlock);
|
|
|
|
if (iBlock.IsEmpty()) return false; // nothing to combine
|
|
if (iBlock == *this) return true; // can combine all of this, no leftover
|
|
|
|
bool combined = false;
|
|
|
|
if ( block.m_y1 < m_y1 )
|
|
{
|
|
top = wxBlockDouble( block.m_x1, block.m_y1, block.m_x2, m_y1 );
|
|
combined = true;
|
|
}
|
|
if ( block.m_y2 > m_y2 )
|
|
{
|
|
bottom = wxBlockDouble( block.m_x1, m_y2, block.m_x2, block.m_y2 );
|
|
combined = true;
|
|
}
|
|
if ( block.m_x1 < m_x1 )
|
|
{
|
|
left = wxBlockDouble( block.m_x1, iBlock.m_y1, m_x1, iBlock.m_y2 );
|
|
combined = true;
|
|
}
|
|
if ( block.m_x2 > m_x2 )
|
|
{
|
|
right = wxBlockDouble( m_x2, iBlock.m_y1, block.m_x2, iBlock.m_y2 );
|
|
combined = true;
|
|
}
|
|
|
|
return combined;
|
|
}
|
|
|
|
bool wxBlockDouble::Delete( const wxBlockDouble &block,
|
|
wxBlockDouble &top, wxBlockDouble &bottom,
|
|
wxBlockDouble &left, wxBlockDouble &right) const
|
|
{
|
|
top = bottom = left = right = wxEmptyBlockDouble;
|
|
|
|
wxBlockDouble iBlock;
|
|
Intersect(*this, block, &iBlock);
|
|
|
|
if (iBlock.IsEmpty()) return false; // nothing to delete
|
|
if (iBlock == *this) return true; // can delete all of this, no leftover
|
|
|
|
bool deleted = false;
|
|
|
|
if ( m_y1 < iBlock.m_y1 )
|
|
{
|
|
top = wxBlockDouble( m_x1, m_y1, m_x2, iBlock.m_y1 );
|
|
deleted = true;
|
|
}
|
|
if ( m_y2 > iBlock.m_y2 )
|
|
{
|
|
bottom = wxBlockDouble( m_x1, iBlock.m_y2, m_x2, m_y2 );
|
|
deleted = true;
|
|
}
|
|
if ( m_x1 < iBlock.m_x1 )
|
|
{
|
|
left = wxBlockDouble( m_x1, iBlock.m_y1, iBlock.m_x1, iBlock.m_y2 );
|
|
deleted = true;
|
|
}
|
|
if ( m_x2 > iBlock.m_x2 )
|
|
{
|
|
right = wxBlockDouble( iBlock.m_x2, iBlock.m_y1, m_x2, iBlock.m_y2 );
|
|
deleted = true;
|
|
}
|
|
|
|
return deleted;
|
|
}
|
|
|
|
//=============================================================================
|
|
// wxBlockIntSelection
|
|
//=============================================================================
|
|
wxBlockInt wxBlockIntSelection::GetBlock( int index ) const
|
|
{
|
|
wxCHECK_MSG((index>=0) && (index<int(m_blocks.GetCount())), wxEmptyBlockInt, wxT("Invalid index"));
|
|
return m_blocks[index];
|
|
}
|
|
|
|
#ifdef USE_wxRANGE
|
|
wxArrayRangeInt wxBlockIntSelection::GetBlockCol(int col) const
|
|
{
|
|
wxArrayRangeInt ranges;
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if ((col >= m_blocks[n].m_x1) && (col <= m_blocks[n].m_x2))
|
|
{
|
|
wxRangeInt range(m_blocks[n].m_y1, m_blocks[n].m_y2);
|
|
ranges.Add(range);
|
|
}
|
|
}
|
|
return ranges;
|
|
}
|
|
|
|
wxArrayRangeInt wxBlockIntSelection::GetBlockRow(int row) const
|
|
{
|
|
wxArrayRangeInt ranges;
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if ((row >= m_blocks[n].m_y1) && (row <= m_blocks[n].m_y2))
|
|
ranges.Add(wxRangeInt(m_blocks[n].m_x1, m_blocks[n].m_x2));
|
|
}
|
|
return ranges;
|
|
}
|
|
#endif // USE_wxRANGE
|
|
|
|
wxBlockInt wxBlockIntSelection::GetBoundingBlock() const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
if (count == 0) return wxEmptyBlockInt;
|
|
wxBlockInt bound = m_blocks[0];
|
|
for (n=1; n<count; n++) bound.Union(m_blocks[n]);
|
|
return bound;
|
|
}
|
|
|
|
int wxBlockIntSelection::Index( int x, int y ) const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if ( m_blocks[n].Contains(x, y) )
|
|
return n;
|
|
}
|
|
return wxNOT_FOUND;
|
|
}
|
|
|
|
int wxBlockIntSelection::Index( const wxBlockInt &b ) const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if (m_blocks[n].Intersects(b))
|
|
return n;
|
|
}
|
|
return wxNOT_FOUND;
|
|
}
|
|
|
|
void wxBlockIntSelection::Sort(wxBlockSort_Type type)
|
|
{
|
|
m_sort = type;
|
|
wxArrayBlockIntSort(m_blocks, type);
|
|
}
|
|
|
|
bool wxBlockIntSelection::DeselectBlock( const wxBlockInt &block, bool combineNow)
|
|
{
|
|
wxCHECK_MSG(!block.IsEmpty(), false, wxT("Invalid block") );
|
|
|
|
bool done = false;
|
|
|
|
wxBlockInt top, bottom, left, right;
|
|
for (int n=0; n<int(m_blocks.GetCount()); n++)
|
|
{
|
|
if (m_blocks[n].Delete(block, top, bottom, left, right))
|
|
{
|
|
done = true;
|
|
m_blocks.RemoveAt(n);
|
|
n = (n > 0) ? n - 1 : -1;
|
|
|
|
if (!top.IsEmpty()) m_blocks.Add(top);
|
|
if (!bottom.IsEmpty()) m_blocks.Add(bottom);
|
|
if (!left.IsEmpty()) m_blocks.Add(left);
|
|
if (!right.IsEmpty()) m_blocks.Add(right);
|
|
}
|
|
}
|
|
|
|
if (combineNow)
|
|
Minimize();
|
|
|
|
return done;
|
|
}
|
|
|
|
bool wxBlockIntSelection::SelectBlock( const wxBlockInt &block, bool combineNow,
|
|
wxArrayBlockInt *addedBlocks )
|
|
{
|
|
wxCHECK_MSG(!block.IsEmpty(), false, wxT("Invalid block") );
|
|
|
|
//TestBlocks();
|
|
|
|
wxArrayBlockInt extraBlocks;
|
|
wxArrayBlockInt *extra = &extraBlocks;
|
|
|
|
if (addedBlocks != NULL)
|
|
{
|
|
addedBlocks->Clear();
|
|
extra = addedBlocks;
|
|
}
|
|
|
|
extra->Add(block);
|
|
|
|
int n, count = m_blocks.GetCount();
|
|
wxBlockInt top, bottom, left, right;
|
|
|
|
for (n=0; n<count; n++)
|
|
{
|
|
for (int k=0; k<int(extra->GetCount()); k++)
|
|
{
|
|
if (m_blocks[n].Combine(extra->Item(k), top, bottom, left, right))
|
|
{
|
|
extra->RemoveAt(k);
|
|
if (!top.IsEmpty()) extra->Add(top);
|
|
if (!bottom.IsEmpty()) extra->Add(bottom);
|
|
if (!left.IsEmpty()) extra->Add(left);
|
|
if (!right.IsEmpty()) extra->Add(right);
|
|
//DoMinimize( *extra );
|
|
n = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (extra->GetCount() > 0u)
|
|
{
|
|
WX_APPEND_ARRAY(m_blocks, *extra);
|
|
if (combineNow)
|
|
Minimize();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBlockIntSelection::Minimize()
|
|
{
|
|
bool ret = DoMinimize(m_blocks);
|
|
Sort(m_sort);
|
|
return ret;
|
|
}
|
|
|
|
bool wxBlockIntSelection::DoMinimize(wxArrayBlockInt &blocks)
|
|
{
|
|
int n;
|
|
for (n=0; n<1000; n++) // should probably just take a few
|
|
{
|
|
if (!DoDoMinimize(blocks)) break;
|
|
}
|
|
|
|
#ifdef CHECK_BLOCK_OVERLAP
|
|
for (size_t a=0; a<blocks.GetCount(); a++)
|
|
{
|
|
for (size_t b=a+1; b<blocks.GetCount(); b++)
|
|
{
|
|
if (blocks[a].Intersects(blocks[b]))
|
|
{
|
|
printf("Intersecting blocks in wxBlockIntSelection::DoMinimize"); fflush(stdout);
|
|
wxBell();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return n != 0;
|
|
}
|
|
|
|
bool wxBlockIntSelection::DoDoMinimize(wxArrayBlockInt &blocks)
|
|
{
|
|
// wxBlockInt top, bottom, left, right;
|
|
bool done = false;
|
|
for (int i=0; i<int(blocks.GetCount())-1; i++)
|
|
{
|
|
for (int j=i+1; j<int(blocks.GetCount()); j++)
|
|
{
|
|
if (blocks[i].Combine(blocks[j]))
|
|
{
|
|
blocks.RemoveAt(j);
|
|
j--;
|
|
done = true;
|
|
//return true;
|
|
}
|
|
/*
|
|
else if (blocks[i].Combine(blocks[j], top, bottom, left, right))
|
|
{
|
|
printf("INTERSECTION!?---------------------------\n"); fflush(stdout);
|
|
blocks.RemoveAt(j);
|
|
if (!top.IsEmpty()) blocks.Add(top);
|
|
if (!bottom.IsEmpty()) blocks.Add(bottom);
|
|
if (!left.IsEmpty()) blocks.Add(left);
|
|
if (!right.IsEmpty()) blocks.Add(right);
|
|
return true;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
return done;
|
|
}
|
|
|
|
//=============================================================================
|
|
// wxBlockDoubleSelection
|
|
//=============================================================================
|
|
wxBlockDouble wxBlockDoubleSelection::GetBlock( int index ) const
|
|
{
|
|
wxCHECK_MSG((index>=0) && (index<int(m_blocks.GetCount())), wxEmptyBlockDouble, wxT("Invalid index"));
|
|
return m_blocks[index];
|
|
}
|
|
|
|
#ifdef USE_wxRANGE
|
|
wxArrayRangeDouble wxBlockDoubleSelection::GetBlockCol(wxDouble col) const
|
|
{
|
|
wxArrayRangeDouble ranges;
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if ((col >= m_blocks[n].m_x1) && (col <= m_blocks[n].m_x2))
|
|
{
|
|
wxRangeDouble range(m_blocks[n].m_y1, m_blocks[n].m_y2);
|
|
ranges.Add(range);
|
|
}
|
|
}
|
|
return ranges;
|
|
}
|
|
|
|
wxArrayRangeDouble wxBlockDoubleSelection::GetBlockRow(wxDouble row) const
|
|
{
|
|
wxArrayRangeDouble ranges;
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if ((row >= m_blocks[n].m_y1) && (row <= m_blocks[n].m_y2))
|
|
ranges.Add(wxRangeDouble(m_blocks[n].m_x1, m_blocks[n].m_x2));
|
|
}
|
|
return ranges;
|
|
}
|
|
#endif // USE_wxRANGE
|
|
|
|
wxBlockDouble wxBlockDoubleSelection::GetBoundingBlock() const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
if (count == 0) return wxEmptyBlockDouble;
|
|
wxBlockDouble bound = m_blocks[0];
|
|
for (n=1; n<count; n++) bound.Union(m_blocks[n]);
|
|
return bound;
|
|
}
|
|
|
|
int wxBlockDoubleSelection::Index( wxDouble x, wxDouble y ) const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if ( (x >= m_blocks[n].m_x1) && (y >= m_blocks[n].m_y1) &&
|
|
(x <= m_blocks[n].m_x2) && (y <= m_blocks[n].m_y2) )
|
|
return true;
|
|
}
|
|
return wxNOT_FOUND;
|
|
}
|
|
|
|
int wxBlockDoubleSelection::Index( const wxBlockDouble &b ) const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if (m_blocks[n].Intersects(b))
|
|
return n;
|
|
}
|
|
return wxNOT_FOUND;
|
|
}
|
|
|
|
void wxBlockDoubleSelection::Sort(wxBlockSort_Type type)
|
|
{
|
|
m_sort = type;
|
|
wxArrayBlockDoubleSort(m_blocks, type);
|
|
}
|
|
|
|
bool wxBlockDoubleSelection::DeselectBlock( const wxBlockDouble &block, bool combineNow)
|
|
{
|
|
//wxCHECK_MSG(!block.IsEmpty(), false, wxT("Invalid block") );
|
|
|
|
bool done = false;
|
|
|
|
wxBlockDouble top, bottom, left, right;
|
|
for (int n=0; n<int(m_blocks.GetCount()); n++)
|
|
{
|
|
if (m_blocks[n].Delete(block, top, bottom, left, right))
|
|
{
|
|
done = true;
|
|
m_blocks.RemoveAt(n);
|
|
n = (n > 0) ? n - 1 : -1;
|
|
|
|
if (!top.IsEmpty()) m_blocks.Add(top);
|
|
if (!bottom.IsEmpty()) m_blocks.Add(bottom);
|
|
if (!left.IsEmpty()) m_blocks.Add(left);
|
|
if (!right.IsEmpty()) m_blocks.Add(right);
|
|
}
|
|
}
|
|
|
|
if (combineNow)
|
|
Minimize();
|
|
|
|
return done;
|
|
}
|
|
|
|
bool wxBlockDoubleSelection::SelectBlock( const wxBlockDouble &block, bool combineNow)
|
|
{
|
|
// It's valid to select a block with a width and height 0 since that means that point
|
|
//wxCHECK_MSG(!block.IsEmpty(), false, wxT("Invalid block") );
|
|
|
|
wxArrayBlockDouble extra;
|
|
extra.Add(block);
|
|
wxBlockDouble top, bottom, left, right;
|
|
|
|
for (int n=0; n<int(m_blocks.GetCount()); n++)
|
|
{
|
|
for (int k=0; k<int(extra.GetCount()); k++)
|
|
{
|
|
bool done = false;
|
|
|
|
// Doubles are different than ints - roundoff error problems
|
|
// always use the bigger block to soak up the smaller blocks
|
|
// this reduces problems with tiny roundoff error produced blocks
|
|
if (m_blocks[n].Intersects(extra[k]))
|
|
{
|
|
if (m_blocks[n].Contains(extra[k]))
|
|
{
|
|
extra.RemoveAt(k);
|
|
k--;
|
|
continue;
|
|
}
|
|
else if (extra[k].Contains(m_blocks[n]))
|
|
{
|
|
m_blocks.RemoveAt(n);
|
|
n = -1;
|
|
break;
|
|
}
|
|
else if (m_blocks[n].IsLarger(extra[k]) > 0)
|
|
{
|
|
done = m_blocks[n].Combine(extra[k], top, bottom, left, right);
|
|
if (done)
|
|
{
|
|
extra.RemoveAt(k);
|
|
k--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
done = extra[k].Combine(m_blocks[n], top, bottom, left, right);
|
|
if (done)
|
|
{
|
|
m_blocks.RemoveAt(n);
|
|
n = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (done)
|
|
{
|
|
if (!top.IsEmpty()) extra.Add(top);
|
|
if (!bottom.IsEmpty()) extra.Add(bottom);
|
|
if (!left.IsEmpty()) extra.Add(left);
|
|
if (!right.IsEmpty()) extra.Add(right);
|
|
//DoMinimize( extra );
|
|
if (n == -1)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (extra.GetCount() > 0u)
|
|
{
|
|
WX_APPEND_ARRAY(m_blocks, extra);
|
|
if (combineNow)
|
|
Minimize();
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBlockDoubleSelection::Minimize()
|
|
{
|
|
bool ret = DoMinimize(m_blocks);
|
|
Sort(m_sort);
|
|
return ret;
|
|
}
|
|
|
|
bool wxBlockDoubleSelection::DoMinimize(wxArrayBlockDouble &blocks)
|
|
{
|
|
int n;
|
|
for (n=0; n<1000; n++) // should probably just take < 10 at most
|
|
{
|
|
if (!DoDoMinimize(blocks)) break;
|
|
}
|
|
|
|
#ifdef CHECK_BLOCK_OVERLAP
|
|
for (size_t a=0; a<blocks.GetCount(); a++)
|
|
{
|
|
printf("Checking wxBlockDoubleSelection::DoMinimize %d =", a); PRINT_BLOCK("", blocks[a])
|
|
for (size_t b=a+1; b<blocks.GetCount(); b++)
|
|
{
|
|
if (blocks[a].Intersects(blocks[b]))
|
|
{
|
|
printf("Intersecting blocks in wxBlockDoubleSelection::DoMinimize\n"); fflush(stdout);
|
|
PRINT_BLOCK("",blocks[a])
|
|
PRINT_BLOCK("",blocks[b])
|
|
wxBell();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return n != 0;
|
|
}
|
|
|
|
bool wxBlockDoubleSelection::DoDoMinimize(wxArrayBlockDouble &blocks)
|
|
{
|
|
//wxBlockDouble top, bottom, left, right;
|
|
bool done = false;
|
|
|
|
for (int i=0; i<int(blocks.GetCount())-1; i++)
|
|
{
|
|
for (int j=i+1; j<int(blocks.GetCount()); j++)
|
|
{
|
|
if (blocks[i].Combine(blocks[j]))
|
|
{
|
|
blocks.RemoveAt(j);
|
|
done = true;
|
|
j--;
|
|
}
|
|
/*
|
|
else if (blocks[i].Combine(blocks[j], top, bottom, left, right))
|
|
{
|
|
blocks.RemoveAt(j);
|
|
if (!top.IsEmpty()) blocks.Add(top);
|
|
if (!bottom.IsEmpty()) blocks.Add(bottom);
|
|
if (!left.IsEmpty()) blocks.Add(left);
|
|
if (!right.IsEmpty()) blocks.Add(right);
|
|
return true;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
return done;
|
|
}
|
|
|
|
//=============================================================================
|
|
// wxBlockIntSelectionIterator - iterates through a wxBlockIntSelection
|
|
//=============================================================================
|
|
|
|
wxBlockIntSelectionIterator::wxBlockIntSelectionIterator( const wxBlockIntSelection &sel,
|
|
wxBISI_Type type )
|
|
{
|
|
m_type = type;
|
|
WX_APPEND_ARRAY(m_blocks, sel.GetBlockArray());
|
|
m_blocks.Sort(wxblockint_sort_topleft_bottomright);
|
|
Reset();
|
|
}
|
|
|
|
wxBlockIntSelectionIterator::wxBlockIntSelectionIterator( const wxArrayBlockInt &blocks,
|
|
wxBISI_Type type )
|
|
{
|
|
m_type = type;
|
|
WX_APPEND_ARRAY(m_blocks, blocks);
|
|
m_blocks.Sort(wxblockint_sort_topleft_bottomright);
|
|
Reset();
|
|
}
|
|
|
|
void wxBlockIntSelectionIterator::Reset()
|
|
{
|
|
m_block_index = -1;
|
|
m_pt = wxPoint2DInt(0, 0);
|
|
}
|
|
|
|
bool wxBlockIntSelectionIterator::GetNext(wxBlockInt &block)
|
|
{
|
|
wxCHECK_MSG(m_type == wxBISI_BLOCK, false, wxT("wrong selection type"));
|
|
if (m_block_index+1 < int(m_blocks.GetCount()))
|
|
{
|
|
++m_block_index;
|
|
block = m_blocks[m_block_index];
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBlockIntSelectionIterator::GetNext(wxPoint2DInt &pt)
|
|
{
|
|
wxCHECK_MSG(m_type == wxBISI_POINT, false, wxT("wrong selection type"));
|
|
if ((m_blocks.GetCount() < 1u) || (m_block_index >= int(m_blocks.GetCount())))
|
|
return false;
|
|
|
|
// first time here
|
|
if (m_block_index < 0)
|
|
{
|
|
m_block_index = 0;
|
|
pt = m_pt = m_blocks[m_block_index].GetLeftTop();
|
|
return true;
|
|
}
|
|
|
|
// at end of block swap to new one
|
|
if (m_pt == m_blocks[m_block_index].GetRightBottom())
|
|
{
|
|
++m_block_index;
|
|
if (int(m_blocks.GetCount()) > m_block_index)
|
|
{
|
|
pt = m_pt = m_blocks[m_block_index].GetLeftTop();
|
|
return true;
|
|
}
|
|
else // past end nothing more to check
|
|
return false;
|
|
}
|
|
// at end of col, down to next row
|
|
if (m_pt.m_x == m_blocks[m_block_index].GetRight())
|
|
{
|
|
m_pt.m_x = m_blocks[m_block_index].m_x1;
|
|
m_pt.m_y++;
|
|
|
|
pt = m_pt;
|
|
return true;
|
|
}
|
|
|
|
// increment the col
|
|
m_pt.m_x++;
|
|
pt = m_pt;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxBlockIntSelectionIterator::IsInSelection(const wxPoint2DInt &pt) const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if (m_blocks[n].Contains(pt))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//=============================================================================
|
|
// wxBlockDoubleSelectionIterator - iterates through a wxBlockDoubleSelection
|
|
//=============================================================================
|
|
|
|
wxBlockDoubleSelectionIterator::wxBlockDoubleSelectionIterator( const wxBlockDoubleSelection &sel )
|
|
{
|
|
WX_APPEND_ARRAY(m_blocks, sel.GetBlockArray());
|
|
m_blocks.Sort(wxblockdouble_sort_topleft_bottomright);
|
|
Reset();
|
|
}
|
|
|
|
wxBlockDoubleSelectionIterator::wxBlockDoubleSelectionIterator( const wxArrayBlockDouble &blocks )
|
|
{
|
|
WX_APPEND_ARRAY(m_blocks, blocks);
|
|
m_blocks.Sort(wxblockdouble_sort_topleft_bottomright);
|
|
Reset();
|
|
}
|
|
|
|
void wxBlockDoubleSelectionIterator::Reset()
|
|
{
|
|
m_block_index = 0;
|
|
}
|
|
|
|
bool wxBlockDoubleSelectionIterator::GetNext(wxBlockDouble &block)
|
|
{
|
|
if (m_block_index < m_blocks.GetCount())
|
|
{
|
|
block = m_blocks[m_block_index];
|
|
m_block_index++;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool wxBlockDoubleSelectionIterator::IsInSelection(const wxPoint2DDouble &pt) const
|
|
{
|
|
register int n, count = m_blocks.GetCount();
|
|
for (n=0; n<count; n++)
|
|
{
|
|
if (m_blocks[n].Contains(pt))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ============================================================================
|
|
// ============================================================================
|
|
// ============================================================================
|
|
// ============================================================================
|
|
// ============================================================================
|
|
// Unit testing, sortof
|