1
/////////////////////////////////////////////////////////////////////////////
3
// Purpose: Rectangular selection storage classes for ints and doubles
4
// Author: John Labenski
6
// Copyright: (c) John Labenski, 2004
8
/////////////////////////////////////////////////////////////////////////////
13
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
14
#pragma interface "block.h"
17
#include "wx/geometry.h"
18
#include "wx/things/thingdef.h"
23
#include "wx/things/range.h"
26
// Note: Why are these not just wxRect2DXXX with m_x and m_width?
27
// because the double blocks need to match up at the edges and x+width
28
// does not always exactly equal the edge of an adjoining block
30
class WXDLLIMPEXP_THINGS wxBlockInt;
31
class WXDLLIMPEXP_THINGS wxBlockDouble;
32
class WXDLLIMPEXP_THINGS wxBlockIntSelection;
33
class WXDLLIMPEXP_THINGS wxBlockDoubleSelection;
35
#include "wx/dynarray.h"
36
WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockInt, wxArrayBlockInt, class WXDLLIMPEXP_THINGS);
37
WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockDouble, wxArrayBlockDouble, class WXDLLIMPEXP_THINGS);
38
WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockIntSelection, wxArrayBlockIntSelection, class WXDLLIMPEXP_THINGS);
39
WX_DECLARE_OBJARRAY_WITH_DECL(wxBlockDoubleSelection, wxArrayBlockDoubleSelection, class WXDLLIMPEXP_THINGS);
41
//=============================================================================
42
// wxBlockXXX constants
43
//=============================================================================
45
// wxEmptyBlockXXX = (0,0,-1,-1)
46
WXDLLIMPEXP_DATA_THINGS(extern const wxBlockInt) wxEmptyBlockInt;
47
WXDLLIMPEXP_DATA_THINGS(extern const wxBlockDouble) wxEmptyBlockDouble;
49
//=============================================================================
50
// wxBlockXXX sorting functions
51
//=============================================================================
55
wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT,
56
wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT,
57
wxBLOCKSORT_BOTTOMLEFT_TOPRIGHT,
58
wxBLOCKSORT_BOTTOMRIGHT_TOPLEFT,
59
wxBLOCKSORT_SMALLEST_TO_LARGEST,
60
wxBLOCKSORT_LARGEST_TO_SMALLEST
63
// functions to sort an array of blocks from any corner
64
extern void wxArrayBlockIntSort(wxArrayBlockInt &blocks,
65
wxBlockSort_Type type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT);
67
extern void wxArrayBlockDoubleSort(wxArrayBlockDouble &blocks,
68
wxBlockSort_Type type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT);
70
//=============================================================================
71
// wxBlockInt - a rectangle bounded by the corner points that can combine with
73
//=============================================================================
75
class WXDLLIMPEXP_THINGS wxBlockInt
78
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) {}
79
inline wxBlockInt(const wxRect2DInt &rect) : m_x1(rect.m_x), m_y1(rect.m_y), m_x2(rect.GetRight()), m_y2(rect.GetBottom()) {}
81
inline wxInt32 GetLeft() const { return m_x1; }
82
inline wxInt32 GetRight() const { return m_x2; }
83
inline wxInt32 GetTop() const { return m_y1; }
84
inline wxInt32 GetBottom() const { return m_y2; }
86
inline wxInt32 GetWidth() const { return m_x2 - m_x1 + 1; }
87
inline wxInt32 GetHeight() const { return m_y2 - m_y1 + 1; }
89
inline wxPoint2DInt GetLeftTop() const { return wxPoint2DInt(m_x1, m_y1); }
90
inline wxPoint2DInt GetLeftBottom() const { return wxPoint2DInt(m_x1, m_y2); }
91
inline wxPoint2DInt GetRightTop() const { return wxPoint2DInt(m_x2, m_y1); }
92
inline wxPoint2DInt GetRightBottom() const { return wxPoint2DInt(m_x2, m_y2); }
94
inline wxRect2DInt GetRect2DInt() const { return wxRect2DInt(m_x1, m_y1, m_x2-m_x1+1, m_y2-m_y1+1); }
95
inline void SetRect2DInt(const wxRect2DInt &r) { m_x1=r.m_x; m_y1=r.m_y, m_x2=r.GetRight(); m_y2=r.GetBottom(); }
97
inline bool Contains( wxInt32 x, wxInt32 y ) const
98
{ return ((x >= m_x1) && (x <= m_x2) && (y >= m_y1) && (y <= m_y2)); }
99
inline bool Contains( const wxPoint2DInt &pt ) const { return Contains(pt.m_x, pt.m_y); }
100
inline bool Contains( const wxBlockInt &b ) const
101
{ return ((m_x1 <= b.m_x1) && (b.m_x2 <= m_x2) && (m_y1 <= b.m_y1) && (b.m_y2 <= m_y2)); }
103
inline bool Intersects( const wxBlockInt &b ) const
104
{ 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)); }
105
inline void Intersect( const wxBlockInt &otherBlock ) { Intersect( *this, otherBlock, this ); }
106
inline void Intersect( const wxBlockInt &src1 , const wxBlockInt &src2 , wxBlockInt *dest ) const
108
dest->m_x1 = wxMax(src1.m_x1, src2.m_x1);
109
dest->m_x2 = wxMin(src1.m_x2, src2.m_x2);
110
dest->m_y1 = wxMax(src1.m_y1, src2.m_y1);
111
dest->m_y2 = wxMin(src1.m_y2, src2.m_y2);
114
inline void Union( const wxBlockInt &otherBlock ) { Union(*this, otherBlock, this); }
115
inline void Union( const wxBlockInt &src1, const wxBlockInt &src2, wxBlockInt *dest ) const
117
dest->m_x1 = wxMin(src1.m_x1, src2.m_x1);
118
dest->m_x2 = wxMax(src1.m_x2, src2.m_x2);
119
dest->m_y1 = wxMin(src1.m_y1, src2.m_y1);
120
dest->m_y2 = wxMax(src1.m_y2, src2.m_y2);
123
// is this block larger than input block, return 1 = larger, 0 = equal, -1 = smaller
124
int IsLarger(const wxBlockInt &b) const
126
wxInt32 width = m_x2 - m_x1 + 1,
127
height = m_y2 - m_y1 + 1,
128
b_width = b.m_x2 - b.m_x1 + 1,
129
b_height = b.m_y2 - b.m_y1 + 1;
131
if ((width <= 0) || (height <= 0))
132
return (b_width > 0) && (b_height > 0) ? -1 : 0;
133
if ((b_width <= 0) || (b_height <= 0))
134
return (width > 0) && (height > 0) ? 1 : 0;
136
wxDouble w_bw = wxDouble(width)/b_width,
137
bh_h = wxDouble(b_height)/height;
138
return (w_bw == bh_h) ? 0 : ((w_bw > bh_h) ? 1 : -1);
141
bool IsEmpty() const { return (m_x1 > m_x2) || (m_y1 > m_y2); }
143
// Unlike Intersects this also includes just touching the other block
144
bool Touches(const wxBlockInt &block) const;
146
// Try to combine these blocks, they must touch and fit to make a single larger block
147
// this block is expanded if possible
148
bool Combine(const wxBlockInt &block);
150
// test combining the input block with this one, returning the
151
// remainder of block in top, bottom, left, right - each may be IsEmpty()
152
// returns false if blocks don't touch or this block already contains block
153
// |---------------------------|
155
// |---------------------------|
156
// | left |block| right |
157
// |---------------------------|
159
// |---------------------------|
160
bool Combine( const wxBlockInt &block,
161
wxBlockInt &top, wxBlockInt &bottom,
162
wxBlockInt &left, wxBlockInt &right) const;
164
// test removal of a portion or all of this contained in block returning the
165
// remainder in top, bottom, left, right - each may be IsEmpty()
166
// returns false if nothing to delete, this cell is not changed
167
bool Delete(const wxBlockInt &block, wxBlockInt &top, wxBlockInt &bottom,
168
wxBlockInt &left, wxBlockInt &right) const;
171
inline bool operator == (const wxBlockInt& b)
172
{ return (m_x1==b.m_x1) && (m_y1==b.m_y1) && (m_x2==b.m_x2) && (m_y2==b.m_y2); }
173
inline bool operator != (const wxBlockInt& b)
174
{ return !(*this == b); }
176
wxInt32 m_x1, m_y1, m_x2, m_y2;
179
//=============================================================================
181
//=============================================================================
183
class WXDLLIMPEXP_THINGS wxBlockDouble
186
inline wxBlockDouble(wxDouble x1=0, wxDouble y1=0, wxDouble x2=0, wxDouble y2=0)
187
: m_x1(x1), m_y1(y1), m_x2(x2), m_y2(y2) {}
188
inline wxBlockDouble(const wxRect2DDouble &rect)
189
{ m_x1=rect.m_x; m_y1=rect.m_y; m_x2=rect.GetRight(); m_y2=rect.GetBottom(); }
191
inline wxDouble GetLeft() const { return m_x1; }
192
inline wxDouble GetRight() const { return m_x2; }
193
inline wxDouble GetTop() const { return m_y1; }
194
inline wxDouble GetBottom() const { return m_y2; }
196
inline wxDouble GetWidth() const { return m_x2 - m_x1; }
197
inline wxDouble GetHeight() const { return m_y2 - m_y1; }
199
inline wxPoint2DDouble GetLeftTop() const { return wxPoint2DDouble(m_x1, m_y1); }
200
inline wxPoint2DDouble GetLeftBottom() const { return wxPoint2DDouble(m_x1, m_y2); }
201
inline wxPoint2DDouble GetRightTop() const { return wxPoint2DDouble(m_x2, m_y1); }
202
inline wxPoint2DDouble GetRightBottom() const { return wxPoint2DDouble(m_x2, m_y2); }
204
inline wxRect2DDouble GetRect2DDouble() const { return wxRect2DDouble(m_x1, m_y1, m_x2-m_x1, m_y2-m_y1); }
205
inline void SetRect2DDouble(const wxRect2DDouble &r) { m_x1=r.m_x; m_y1=r.m_y, m_x2=r.GetRight(); m_y2=r.GetBottom(); }
207
inline bool Contains( wxDouble x, wxDouble y ) const
208
{ return ((x >= m_x1) && (x <= m_x2) && (y >= m_y1) && (y <= m_y2)); }
209
inline bool Contains( const wxPoint2DDouble &pt ) const { return Contains(pt.m_x, pt.m_y); }
210
inline bool Contains( const wxBlockDouble &b ) const
211
{ return ((m_x1 <= b.m_x1) && (b.m_x2 <= m_x2) && (m_y1 <= b.m_y1) && (b.m_y2 <= m_y2)); }
213
inline bool Intersects( const wxBlockDouble &b ) const
214
{ 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)); }
215
inline void Intersect( const wxBlockDouble &otherBlock ) { Intersect( *this, otherBlock, this ); }
216
inline void Intersect( const wxBlockDouble &src1 , const wxBlockDouble &src2 , wxBlockDouble *dest ) const
218
dest->m_x1 = wxMax(src1.m_x1, src2.m_x1);
219
dest->m_x2 = wxMin(src1.m_x2, src2.m_x2);
220
dest->m_y1 = wxMax(src1.m_y1, src2.m_y1);
221
dest->m_y2 = wxMin(src1.m_y2, src2.m_y2);
224
inline void Union( const wxBlockDouble &otherBlock ) { Union( *this, otherBlock, this ); }
225
inline void Union( const wxBlockDouble &src1, const wxBlockDouble &src2, wxBlockDouble *dest ) const
227
dest->m_x1 = wxMin(src1.m_x1, src2.m_x1);
228
dest->m_x2 = wxMax(src1.m_x2, src2.m_x2);
229
dest->m_y1 = wxMin(src1.m_y1, src2.m_y1);
230
dest->m_y2 = wxMax(src1.m_y2, src2.m_y2);
233
// is this block larger than input block, return 1 - larger, 0 = equal, -1 smaller
234
int IsLarger(const wxBlockDouble &b) const
236
wxDouble width = m_x2 - m_x1,
237
height = m_y2 - m_y1,
238
b_width = b.m_x2 - b.m_x1,
239
b_height = b.m_y2 - b.m_y1;
241
if ((width <= 0) || (height <= 0))
242
return (b_width > 0) && (b_height > 0) ? -1 : 0;
243
if ((b_width <= 0) || (b_height <= 0))
244
return (width > 0) && (height > 0) ? 1 : 0;
246
wxDouble w_bw = width/b_width,
247
bh_h = b_height/height;
248
return (w_bw == bh_h) ? 0 : ((w_bw > bh_h) ? 1 : -1);
250
inline bool IsEmpty() const { return (m_x1 > m_x2) || (m_y1 > m_y2); }
252
// Unlike Intersects this also includes just touching the other block
253
bool Touches(const wxBlockDouble &block) const;
255
// Try to combine these blocks, they must touch and fit to make a single larger block
256
// this block is expanded if possible
257
bool Combine(const wxBlockDouble &block);
259
// test combining the input block with this one, returning the
260
// remainder of block in top, bottom, left, right - each may be IsEmpty()
261
// returns false if blocks don't touch or this block already contains block
262
// |---------------------------|
264
// |---------------------------|
265
// | left |block| right |
266
// |---------------------------|
268
// |---------------------------|
269
bool Combine( const wxBlockDouble &block,
270
wxBlockDouble &top, wxBlockDouble &bottom,
271
wxBlockDouble &left, wxBlockDouble &right) const;
273
// test removal of a portion or all of this contained in block returning the
274
// remainder in top, bottom, left, right - each may be IsEmpty()
275
// returns false if nothing to delete, this cell is not changed
276
bool Delete( const wxBlockDouble &block,
277
wxBlockDouble &top, wxBlockDouble &bottom,
278
wxBlockDouble &left, wxBlockDouble &right) const;
281
inline bool operator == (const wxBlockDouble& b)
282
{ return (m_x1==b.m_x1) && (m_y1==b.m_y1) && (m_x2==b.m_x2) && (m_y2==b.m_y2); }
283
inline bool operator != (const wxBlockDouble& b)
284
{ return !(*this == b); }
286
wxDouble m_x1, m_y1, m_x2, m_y2;
289
//=============================================================================
290
// wxBlockIntSelection - ordered 2D array of wxBlockInts, combines to minimize size
291
// blocks never overlap each other
292
//=============================================================================
294
class WXDLLIMPEXP_THINGS wxBlockIntSelection
297
wxBlockIntSelection(wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT)
298
: m_sort(sort_type) {}
299
wxBlockIntSelection(const wxBlockIntSelection &blocks,
300
wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT)
301
: m_sort(sort_type) { Copy(blocks); }
303
// Make a full copy of the source
304
void Copy(const wxBlockIntSelection &source)
307
WX_APPEND_ARRAY(m_blocks, source.GetBlockArray());
308
m_sort = source.GetSortType();
311
inline int GetCount() const { return m_blocks.GetCount(); }
313
inline void Clear() { m_blocks.Clear(); }
315
wxArrayBlockInt GetBlockArray() const { return m_blocks; }
318
// Get an array of ranges cutting though these blocks
319
wxArrayRangeInt GetBlockCol(int col) const;
320
wxArrayRangeInt GetBlockRow(int row) const;
323
wxBlockInt GetBlock( int index ) const;
324
inline wxBlockInt Item( int index ) const { return GetBlock(index); }
326
// Get a block that bounds the selection
327
wxBlockInt GetBoundingBlock() const;
329
// do any of the blocks contains elements
330
inline bool Contains( int x, int y ) const { return Index(x,y) != wxNOT_FOUND; }
331
inline bool Contains( const wxPoint2DInt &pt ) const { return Index(pt) != wxNOT_FOUND; }
332
inline bool Contains( const wxBlockInt &b ) const { return Index(b) != wxNOT_FOUND; }
334
// what is the index of a block that contains element
335
int Index( int x, int y ) const;
336
inline int Index( const wxPoint2DInt &pt ) const { return Index(pt.m_x, pt.m_y); }
337
int Index( const wxBlockInt &b ) const;
339
// Sorts the blocks according to the wxBlockIntSort_Type
340
void Sort(wxBlockSort_Type type = wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT);
341
wxBlockSort_Type GetSortType() const { return m_sort; }
343
// Add the block to the selection, returns false if nothing was done
344
// use combineNow=false to make quick additions, when done call Minimize()
345
// addedBlocks (if !NULL) will be filled with the actual changed selections
346
// by removing the previous selections from the input block
347
bool SelectBlock( const wxBlockInt &block, bool combineNow=true, wxArrayBlockInt *addedBlocks=NULL);
349
// Remove the block to the selection, return false if nothing was done
350
// use combineNow=false to make quick additions, when done call Minimize()
351
bool DeselectBlock( const wxBlockInt &block, bool combineNow=true);
353
// Try to combine the blocks if possible, returns if anything was done
354
// only need to call this if you've called (De)SelectBlock(..., false)
358
inline wxBlockInt operator[](int index) const { return GetBlock(index); }
360
//wxBlockIntSelection& operator = (const wxBlockIntSelection& other) { Copy(other); return *this; }
362
// generic routine using if (b1.Combine(b2)) remove b2 to cleanup array
363
// sort top_left_bottom_right first (internal use)
364
static bool DoMinimize( wxArrayBlockInt &blocks );
365
// DoMinimize calls this internally
366
static bool DoDoMinimize( wxArrayBlockInt &blocks );
369
wxArrayBlockInt m_blocks;
370
wxBlockSort_Type m_sort;
373
//=============================================================================
374
// wxBlockDoubleSelection - ordered 2D array of wxBlockDoubles, combines to minimze size
375
// blocks never overlap each other
376
//=============================================================================
378
class WXDLLIMPEXP_THINGS wxBlockDoubleSelection
381
wxBlockDoubleSelection(wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT)
382
: m_sort(sort_type) {}
383
wxBlockDoubleSelection(const wxBlockDoubleSelection &blocks,
384
wxBlockSort_Type sort_type = wxBLOCKSORT_TOPLEFT_BOTTOMRIGHT)
385
: m_sort(sort_type) { Copy(blocks); }
387
// Make a full copy of the source
388
void Copy(const wxBlockDoubleSelection &source)
391
WX_APPEND_ARRAY(m_blocks, source.GetBlockArray());
392
m_sort = source.GetSortType();
395
inline int GetCount() const { return m_blocks.GetCount(); }
397
inline void Clear() { m_blocks.Clear(); }
399
wxArrayBlockDouble GetBlockArray() const { return m_blocks; }
402
// Get an array of ranges cutting though these blocks
403
wxArrayRangeDouble GetBlockCol(wxDouble col) const;
404
wxArrayRangeDouble GetBlockRow(wxDouble row) const;
407
wxBlockDouble GetBlock( int index ) const;
408
inline wxBlockDouble Item( int index ) const { return GetBlock(index); }
410
// Get a block that bounds the selection
411
wxBlockDouble GetBoundingBlock() const;
413
// do any of the blocks contains elements
414
inline bool Contains( wxDouble x, wxDouble y ) const { return Index(wxPoint2DDouble(x,y)) != wxNOT_FOUND; }
415
inline bool Contains( const wxPoint2DInt &pt ) const { return Index(pt) != wxNOT_FOUND; }
416
inline bool Contains( const wxBlockDouble &b ) const { return Index(b) != wxNOT_FOUND; }
418
// what is the index of a block that contains element
419
int Index( wxDouble x, wxDouble y ) const;
420
inline int Index( const wxPoint2DDouble &pt ) const { return Index(pt.m_x, pt.m_y); }
421
int Index( const wxBlockDouble &b ) const;
423
// Sorts the blocks according to the wxBlockIntSort_Type
424
void Sort(wxBlockSort_Type type = wxBLOCKSORT_TOPRIGHT_BOTTOMLEFT);
425
wxBlockSort_Type GetSortType() const { return m_sort; }
427
// Add the block to the selection, returns false if nothing was done
428
// use combineNow=false to make quick additions, when done call Minimize()
429
bool SelectBlock( const wxBlockDouble &block, bool combineNow=true);
431
// Remove the block to the selection, return false if nothing was done
432
// use combineNow=false to make quick additions, when done call Minimize()
433
bool DeselectBlock( const wxBlockDouble &block, bool combineNow=true);
435
// Try to combine the blocks if possible, returns if anything was done
436
// only need to call this if you've called (De)SelectBlock(..., false)
440
inline wxBlockDouble operator[](int index) const { return GetBlock(index); }
442
//wxBlockIntSelection& operator = (const wxBlockIntSelection& other) { Copy(other); return *this; }
444
// generic routine using if (b1.Combine(b2)) remove b2 to cleanup array
445
// sort top_left_bottom_right first (internal use)
446
static bool DoMinimize( wxArrayBlockDouble &blocks );
447
// DoMinimize calls this internally
448
static bool DoDoMinimize( wxArrayBlockDouble &blocks );
451
wxArrayBlockDouble m_blocks;
452
wxBlockSort_Type m_sort;
455
//=============================================================================
456
// wxBlockIntSelectionIterator - iterates through a wxBlockIntSelection
457
//=============================================================================
460
wxBISI_POINT, // wxBlockIntSelectionIterator::SetType go point by point
461
wxBISI_BLOCK // go block by block
464
class WXDLLIMPEXP_THINGS wxBlockIntSelectionIterator
467
wxBlockIntSelectionIterator( const wxBlockIntSelection &sel, wxBISI_Type type = wxBISI_POINT );
468
wxBlockIntSelectionIterator( const wxArrayBlockInt &blocks, wxBISI_Type type = wxBISI_POINT );
470
// resets the iterating to start at the beginning
472
// Set the method to get the blocks, either point by point or each whole block
473
// also resets the iteration to the beginning
474
void SetType( wxBISI_Type type ) { m_type = type; Reset(); }
475
wxBISI_Type GetType() const { return m_type; }
477
// Get next selection, returns false if at end (only valid for wxBISI_point)
478
bool GetNext(wxPoint2DInt &pt);
479
// Get next selection, returns false if at end (only valid for wxBISI_block)
480
bool GetNext(wxBlockInt &block);
482
// checks if this row and col are in this selection
483
bool IsInSelection(const wxPoint2DInt &pt) const;
484
inline bool IsInSelection( int x, int y ) const { return IsInSelection(wxPoint2DInt(x,y)); }
490
wxArrayBlockInt m_blocks;
493
//=============================================================================
494
// wxBlockDoubleSelectionIterator - iterates through a wxBlockDoubleSelection
495
//=============================================================================
497
class WXDLLIMPEXP_THINGS wxBlockDoubleSelectionIterator
500
wxBlockDoubleSelectionIterator( const wxBlockDoubleSelection &sel );
501
wxBlockDoubleSelectionIterator( const wxArrayBlockDouble &blocks );
503
// resets the iterating to start at the beginning
505
// Get next selection, returns false if at the end
506
bool GetNext(wxBlockDouble &block);
507
// checks if this row and col are in this selection
508
bool IsInSelection(const wxPoint2DDouble &pt) const;
509
inline bool IsInSelection( int x, int y ) const { return IsInSelection(wxPoint2DDouble(x,y)); }
512
size_t m_block_index;
513
wxArrayBlockDouble m_blocks;
516
#endif // __wxBLOCK_H__