1
/////////////////////////////////////////////////////////////////////////////
3
// Purpose: Simple min-max range class and associated selection array class
4
// Author: John Labenski
6
// Copyright: (c) John Labenski 2004
8
/////////////////////////////////////////////////////////////////////////////
10
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
11
#pragma implementation "range.h"
14
// For compilers that support precompilation, includes "wx.h".
15
#include "wx/wxprec.h"
25
#include "wx/things/range.h"
28
const wxRangeInt wxEmptyRangeInt(0, -1);
29
const wxRangeDouble wxEmptyRangeDouble(0, -1);
31
#include "wx/arrimpl.cpp"
32
WX_DEFINE_OBJARRAY(wxArrayRangeInt);
33
WX_DEFINE_OBJARRAY(wxArrayRangeDouble);
34
WX_DEFINE_OBJARRAY(wxArrayRangeIntSelection);
35
WX_DEFINE_OBJARRAY(wxArrayRangeDoubleSelection);
38
// set this if you want to double check that that ranges are really working
39
//#define CHECK_RANGES
41
//=============================================================================
43
//=============================================================================
45
bool wxRangeInt::Combine(int i, bool only_if_touching)
49
if (i == m_min-1) { m_min--; return true; }
50
else if (i == m_max+1) { m_max++; return true; }
54
if (i < m_min) { m_min = i; return true; }
55
else if (i > m_max) { m_max = i; return true; }
60
bool wxRangeInt::Combine( const wxRangeInt &r, bool only_if_touching )
73
if (r.m_min < m_min) { m_min = r.m_min; added = true; }
74
if (r.m_max > m_max) { m_max = r.m_max; added = true; }
80
bool wxRangeInt::Delete( const wxRangeInt &r, wxRangeInt *right )
85
if (right) *right = wxEmptyRangeInt;
91
*this = wxEmptyRangeInt;
106
*right = wxRangeInt(r.m_max + 1, m_max);
112
//=============================================================================
113
// wxRangeIntSelection
114
//=============================================================================
115
const wxRangeInt& wxRangeIntSelection::GetRange( int index ) const
117
wxCHECK_MSG((index>=0) && (index<int(m_ranges.GetCount())), wxEmptyRangeInt, wxT("Invalid index"));
118
return m_ranges[index];
121
wxRangeInt wxRangeIntSelection::GetBoundingRange() const
123
if (int(m_ranges.GetCount()) < 1) return wxEmptyRangeInt;
124
return wxRangeInt(m_ranges[0].m_min, m_ranges[m_ranges.GetCount()-1].m_max);
127
int wxRangeIntSelection::Index( int i ) const
129
int count = m_ranges.GetCount();
130
if (count < 1) return wxNOT_FOUND;
132
if (i < m_ranges[0].m_min) return wxNOT_FOUND;
133
if (i > m_ranges[count-1].m_max) return wxNOT_FOUND;
136
int res, tmp, lo = 0, hi = count;
141
res = m_ranges[tmp].Position(i);
147
else //if ( res > 0 )
154
int wxRangeIntSelection::Index( const wxRangeInt &r ) const
156
register int i, count = m_ranges.GetCount();
157
for (i=0; i<count; i++) if (m_ranges[i].Contains(r)) return i;
161
int wxRangeIntSelection::NearestIndex( int i ) const
163
int count = m_ranges.GetCount();
164
if (count < 1) return -1;
166
if (i < m_ranges[0].m_min) return -1;
167
if (i > m_ranges[count-1].m_max) return count;
170
int res, tmp, lo = 0, hi = count;
175
res = m_ranges[tmp].Position(i);
179
else if ((i >= m_ranges[tmp].m_max) && (i < m_ranges[wxMin(tmp+1, count-1)].m_min))
183
else //if ( res > 0 )
187
// oops shouldn't get here
188
wxCHECK_MSG(0, -1, wxT("Error calculating NearestIndex in wxRangeIntSelection"));
191
int wxRangeIntSelection::GetItemCount() const
193
register int i, items = 0, count = m_ranges.GetCount();
194
for (i=0; i<count; i++) items += m_ranges[i].GetRange();
198
bool wxRangeIntSelection::DeselectRange(const wxRangeInt &range)
200
wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Selection Range") );
203
int i, count = m_ranges.GetCount();
204
int nearest = count > 0 ? NearestIndex(range.m_min) : -1;
206
if ((nearest < 0) || (nearest == count))
210
for (i=nearest; i<int(m_ranges.GetCount()); i++)
212
if (range.m_max < m_ranges[i].m_min)
214
else if (m_ranges[i].Delete(range, &r))
216
if (m_ranges[i].IsEmpty())
218
m_ranges.RemoveAt(i);
219
i = (i > 0) ? i-1 : -1;
221
else if (!r.IsEmpty())
222
m_ranges.Insert(r, i+1);
231
bool wxRangeIntSelection::SelectRange(const wxRangeInt &range)
233
wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Selection Range") );
235
// Try to find a range that includes this one and combine it, else insert it, else append it
237
int i, count = m_ranges.GetCount();
238
int nearest = count > 0 ? NearestIndex(range.m_min) : -1;
242
if (!((count > 0) && m_ranges[0].Combine(range, true)))
243
m_ranges.Insert(range, 0);
246
else if (nearest == count)
248
if (!((count > 0) && m_ranges[count-1].Combine(range, true)))
254
if (m_ranges[nearest].Contains(range))
257
for (i=nearest; i<count; i++)
259
if (m_ranges[i].Combine(range, true))
264
else if (range.m_max < m_ranges[i].m_min)
266
m_ranges.Insert(range, i);
271
count = m_ranges.GetCount();
272
for (i=wxMax(nearest-1, 1); i<count; i++)
274
if (range.m_max+1 < m_ranges[i-1].m_min)
276
else if (m_ranges[i-1].Combine(m_ranges[i], true))
278
m_ranges.RemoveAt(i);
286
printf("Selecting ranges %d %d count %d\n", range.m_min, range.m_max, m_ranges.GetCount());
288
for (i=1; i<int(m_ranges.GetCount()); i++)
290
if (m_ranges[i-1].Contains(m_ranges[i]))
291
printf("Error in Selecting ranges %d %d, %d %d count %d\n", m_ranges[i-1].m_min, m_ranges[i-1].m_max, m_ranges[i].m_min, m_ranges[i].m_max, m_ranges.GetCount());
292
if (m_ranges[i-1].Touches(m_ranges[i]))
293
printf("Could have minimzed ranges %d %d, %d %d count %d\n", m_ranges[i-1].m_min, m_ranges[i-1].m_max, m_ranges[i].m_min, m_ranges[i].m_max, m_ranges.GetCount());
296
#endif // CHECK_RANGES
301
bool wxRangeIntSelection::BoundRanges(const wxRangeInt& range)
303
wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Bounding Range") );
304
int i, count = m_ranges.GetCount();
307
for (i = 0; i < count; i++)
309
if (m_ranges[i].m_min >= range.m_min)
312
if (m_ranges[i].m_max < range.m_min) // range is out of bounds
315
m_ranges.RemoveAt(i);
322
m_ranges[i].m_min = range.m_min;
327
for (i = m_ranges.GetCount() - 1; i >= 0; i--)
329
if (m_ranges[i].m_max <= range.m_max)
332
if (m_ranges[i].m_min > range.m_max) // range is out of bounds
335
m_ranges.RemoveAt(i);
340
m_ranges[i].m_max = range.m_max;
348
//=============================================================================
350
//=============================================================================
352
bool wxRangeDouble::Combine(double i)
354
if (i < m_min) { m_min = i; return true; }
355
else if (i > m_max) { m_max = i; return true; }
359
bool wxRangeDouble::Combine( const wxRangeDouble &r, bool only_if_touching )
361
if (only_if_touching)
372
if (r.m_min < m_min) { m_min = r.m_min; added = true; }
373
if (r.m_max > m_max) { m_max = r.m_max; added = true; }
379
bool wxRangeDouble::Delete( const wxRangeDouble &r, wxRangeDouble *right )
384
if (right) *right = wxEmptyRangeDouble;
386
if (r.m_min <= m_min)
388
if (r.m_max >= m_max)
390
*this = wxEmptyRangeDouble;
398
if (r.m_max >= m_max)
405
*right = wxRangeDouble(r.m_max, m_max);
411
//=============================================================================
412
// wxRangeDoubleSelection
413
//=============================================================================
414
const wxRangeDouble& wxRangeDoubleSelection::GetRange( int index ) const
416
wxCHECK_MSG((index>=0) && (index<int(m_ranges.GetCount())), wxEmptyRangeDouble, wxT("Invalid index"));
417
return m_ranges[index];
420
wxRangeDouble wxRangeDoubleSelection::GetBoundingRange() const
422
if (int(m_ranges.GetCount()) < 1) return wxEmptyRangeDouble;
423
return wxRangeDouble(m_ranges[0].m_min, m_ranges[m_ranges.GetCount()-1].m_max);
426
int wxRangeDoubleSelection::Index( wxDouble i ) const
428
int count = m_ranges.GetCount();
429
if (count < 1) return wxNOT_FOUND;
431
if (i < m_ranges[0].m_min) return wxNOT_FOUND;
432
if (i > m_ranges[count-1].m_max) return wxNOT_FOUND;
435
int res, tmp, lo = 0, hi = count;
440
res = m_ranges[tmp].Position(i);
446
else //if ( res > 0 )
453
for (register int j=0; j<count; j++)
455
if (m_ranges[j].Contains(i)) return j;
460
int wxRangeDoubleSelection::Index( const wxRangeDouble &r ) const
462
register int i, count = m_ranges.GetCount();
463
for (i=0; i<count; i++) if (m_ranges[i].Contains(r)) return i;
467
int wxRangeDoubleSelection::NearestIndex( wxDouble i ) const
469
register int count = m_ranges.GetCount();
470
if (count < 1) return -1;
472
if (i < m_ranges[0].m_min) return -1;
473
if (i > m_ranges[count-1].m_max) return count;
476
int res, tmp, lo = 0, hi = count;
481
res = m_ranges[tmp].Position(i);
485
else if ((i >= m_ranges[tmp].m_max) && (i < m_ranges[wxMin(tmp+1, count-1)].m_min))
489
else //if ( res > 0 )
493
// oops shouldn't get here
494
wxCHECK_MSG(0, -1, wxT("Error calculating NearestIndex in wxRangeDoubleSelection"));
497
bool wxRangeDoubleSelection::SelectRange(const wxRangeDouble &range)
499
wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Selection Range") );
501
// Try to find a range that includes this one and combine it, else insert it, else append it
503
int i, count = m_ranges.GetCount();
504
int nearest = count > 0 ? NearestIndex(range.m_min) : -1;
508
if (!((count > 0) && m_ranges[0].Combine(range, true)))
509
m_ranges.Insert(range, 0);
512
else if (nearest == count)
514
if (!((count > 0) && m_ranges[count-1].Combine(range, true)))
520
if (m_ranges[nearest].Contains(range))
523
for (i=nearest; i<count; i++)
525
if (m_ranges[i].Combine(range, true))
530
else if (range.m_max < m_ranges[i].m_min)
532
m_ranges.Insert(range, i);
536
for (i=wxMax(nearest-1, 1); i<int(m_ranges.GetCount()); i++)
538
if (range.m_max+1 < m_ranges[i-1].m_min)
540
else if (m_ranges[i-1].Combine(m_ranges[i], true))
542
m_ranges.RemoveAt(i);
549
printf("Selecting ranges %g %g count %d\n", range.m_min, range.m_max, m_ranges.GetCount());
551
for (i=1; i<int(m_ranges.GetCount()); i++)
553
if (m_ranges[i-1].Contains(m_ranges[i]))
554
printf("Error in Selecting ranges %g %g, %g %g count %d\n", m_ranges[i-1].m_min, m_ranges[i-1].m_max, m_ranges[i].m_min, m_ranges[i].m_max, m_ranges.GetCount());
555
//if (m_ranges[i-1].Touches(m_ranges[i]))
556
// printf("Could have minimzed ranges %g %g, %g %g count %d\n", m_ranges[i-1].m_min, m_ranges[i-1].m_max, m_ranges[i].m_min, m_ranges[i].m_max, m_ranges.GetCount());
559
#endif // CHECK_RANGES
564
bool wxRangeDoubleSelection::DeselectRange(const wxRangeDouble &range)
566
wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Selection Range") );
569
int i, count = m_ranges.GetCount();
570
int nearest = count > 0 ? NearestIndex(range.m_min) : -1;
572
if ((nearest < 0) || (nearest == count))
576
for (i=nearest; i<int(m_ranges.GetCount()); i++)
578
if (range.m_max < m_ranges[i].m_min)
580
else if (m_ranges[i].Delete(range, &r))
582
if (m_ranges[i].IsEmpty())
584
m_ranges.RemoveAt(i);
585
i = (i > 0) ? i-1 : -1;
587
else if (!r.IsEmpty())
588
m_ranges.Insert(r, i+1);
597
bool wxRangeDoubleSelection::BoundRanges(const wxRangeDouble& range)
599
wxCHECK_MSG(!range.IsEmpty(), false, wxT("Invalid Bounding Range") );
600
int i, count = m_ranges.GetCount();
603
for (i = 0; i < count; i++)
605
if (m_ranges[i].m_min >= range.m_min)
608
if (m_ranges[i].m_max < range.m_min) // range is out of bounds
611
m_ranges.RemoveAt(i);
618
m_ranges[i].m_min = range.m_min;
623
for (i = m_ranges.GetCount() - 1; i >= 0; i--)
625
if (m_ranges[i].m_max <= range.m_max)
628
if (m_ranges[i].m_min > range.m_max) // range is out of bounds
631
m_ranges.RemoveAt(i);
636
m_ranges[i].m_max = range.m_max;