[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

box.hxx VIGRA

1 /************************************************************************/
2 /* */
3 /* Copyright 2009-2010 by Ullrich Koethe and Hans Meine */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 #ifndef VIGRA_BOX_HXX
37 #define VIGRA_BOX_HXX
38 
39 #include "metaprogramming.hxx"
40 #include "numerictraits.hxx"
41 #include "tinyvector.hxx"
42 
43 namespace vigra {
44 
45 namespace detail {
46 
47 // RangePolicy used for floating point coordinate types
48 template<class VALUETYPE>
49 struct EndInsidePolicy
50 {
51  static inline bool isEmptyRange(VALUETYPE b, VALUETYPE e)
52  {
53  return e < b; // <=
54  }
55 
56  static inline VALUETYPE pointEnd(VALUETYPE p)
57  {
58  return p; // +1
59  }
60 };
61 
62 // RangePolicy used for integer coordinate types
63 template<class VALUETYPE>
64 struct EndOutsidePolicy
65 {
66  static inline bool isEmptyRange(VALUETYPE b, VALUETYPE e)
67  {
68  return e <= b;
69  }
70 
71  static inline VALUETYPE pointEnd(VALUETYPE p)
72  {
73  return p+1;
74  }
75 };
76 
77 } // namespace vigra::detail
78 
79 /** \addtogroup RangesAndPoints */
80 //@{
81  /** \brief Represent an n-dimensional box as a (begin, end) pair.
82  * Depending on the value type, end() is considered to be
83  * outside the box (as in the STL, for integer types), or
84  * inside (for floating point types). size() will always be
85  * end() - begin().
86  */
87 template<class VALUETYPE, unsigned int DIMENSION>
88 class Box
89 {
90  public:
91  /** STL-compatible definition of coordinate valuetype
92  */
93  typedef VALUETYPE value_type;
94 
95  /** Promoted coordinate valuetype, used for volume()
96  */
97  typedef typename NumericTraits<VALUETYPE>::Promote VolumeType;
98 
99  /** Vector type used for begin() and end()
100  */
102 
103  enum { Dimension = DIMENSION };
104 
105  protected:
106  Vector begin_, end_;
107 
108  /** Range policy (EndInsidePolicy/EndOutsidePolicy, depending on valuetype)
109  */
110  typedef typename If<typename NumericTraits<VALUETYPE>::isIntegral,
111  detail::EndOutsidePolicy<VALUETYPE>,
112  detail::EndInsidePolicy<VALUETYPE> >::type RangePolicy;
113 
114  public:
115  /** Construct an empty box (isEmpty() will return true).
116  * (Internally, this will initialize all dimensions with the
117  * empty range [1..0].)
118  */
119  Box()
120  : begin_(NumericTraits<Vector>::one())
121  {}
122 
123  /** Construct a box representing the given range. Depending
124  * on the value type, end() is considered to be outside the
125  * box (as in the STL, for integer types), or inside (for
126  * floating point types).
127  */
128  Box(Vector const &begin, Vector const &end)
129  : begin_(begin), end_(end)
130  {}
131 
132  /** Construct a box of given size at the origin (i.e. end() ==
133  * size()).
134  */
135  explicit Box(Vector const &size)
136  : end_(size)
137  {}
138 
139  /** Get begin vector (i.e. smallest coordinates for each
140  * dimension). This is the first point (scan-order wise)
141  * which is considered to be "in" the box.
142  */
143  Vector const & begin() const
144  {
145  return begin_;
146  }
147 
148  /** Access begin vector (i.e. smallest coordinates for each
149  * dimension). This is the first point (scan-order wise)
150  * which is considered to be "in" the box.
151  */
153  {
154  return begin_;
155  }
156 
157  /** Get end vector (i.e. coordinates higher than begin() in
158  * each dimension for non-empty boxes). This is begin() +
159  * size(), and depending on the valuetype (float/int), this is
160  * the last point within or the first point outside the box,
161  * respectively.
162  */
163  Vector const & end() const
164  {
165  return end_;
166  }
167 
168  /** Access end vector (i.e. coordinates higher than begin() in
169  * each dimension for non-empty boxes). This is begin() +
170  * size(), and depending on the valuetype (float/int), this is
171  * the last point within or the first point outside the box,
172  * respectively.
173  */
175  {
176  return end_;
177  }
178 
179  /** Change begin() without changing end(), changing size()
180  * accordingly.
181  */
182  void setBegin(Vector const &begin)
183  {
184  begin_ = begin;
185  }
186 
187  /** Change end() without changing begin(), which will change
188  * the size() most probably.
189  */
190  void setEnd(Vector const &end)
191  {
192  end_ = end;
193  }
194 
195  /** Move the whole box so that the given point will be
196  * begin() afterwards.
197  */
198  void moveTo(Vector const &newBegin)
199  {
200  end_ += newBegin - begin_;
201  begin_ = newBegin;
202  }
203 
204  /** Move the whole box by the given offset.
205  * (Equivalent to operator+=)
206  */
207  void moveBy(Vector const &offset)
208  {
209  begin_ += offset;
210  end_ += offset;
211  }
212 
213  /** Determine and return the area of this box. That is,
214  * if this rect isEmpty(), returns zero, otherwise returns the
215  * product of the extents in each dimension.
216  */
218  {
219  if(isEmpty())
220  return 0;
221 
222  VolumeType result(end_[0] - begin_[0]);
223  for(unsigned int i = 1; i < DIMENSION; ++i)
224  result *= end_[i] - begin_[i];
225  return result;
226  }
227 
228  /** Determine and return the size of this box. The size
229  * might be zero or even negative in one or more dimensions,
230  * and if so, isEmpty() will return true.
231  */
232  Vector size() const
233  {
234  return end_ - begin_;
235  }
236 
237  /** Resize this box to the given extents. This will
238  * change end() only.
239  */
240  void setSize(Vector const &size)
241  {
242  end_ = begin_ + size;
243  }
244 
245  /** Increase the size of the box by the given
246  * offset. This will move end() only. (If any of offset's
247  * components is negative, the box will get smaller
248  * accordingly.)
249  */
250  void addSize(Vector const &offset)
251  {
252  end_ += offset;
253  }
254 
255  /** Adds a border of the given width around the box. That
256  * means, begin()'s components are moved by -borderWidth
257  * and end()'s by borderWidth. (If borderWidth is
258  * negative, the box will get smaller accordingly.)
259  */
260  void addBorder(VALUETYPE borderWidth)
261  {
262  for(unsigned int i = 0; i < DIMENSION; ++i)
263  {
264  begin_[i] -= borderWidth;
265  end_[i] += borderWidth;
266  }
267  }
268 
269  /** Adds a border of the given width around the box. That
270  * means, begin()'s components are moved by -borderWidth
271  * and end()'s by borderWidth. (If borderWidth is
272  * negative, the box will get smaller accordingly.)
273  */
274  void addBorder(const Vector & borderWidth)
275  {
276  begin_ -= borderWidth;
277  end_ += borderWidth;
278  }
279 
280 
281 
282  /// equality check
283  bool operator==(Box const &r) const
284  {
285  return (begin_ == r.begin_) && (end_ == r.end_);
286  }
287 
288  /// inequality check
289  bool operator!=(Box const &r) const
290  {
291  return (begin_ != r.begin_) || (end_ != r.end_);
292  }
293 
294  /** Return whether this box is considered empty. It is
295  * non-empty if all end() coordinates are greater than (or
296  * equal, for floating point valuetypes) the corresponding
297  * begin() coordinates. Uniting an empty box with something
298  * will return the bounding box of the 'something', and
299  * intersecting any box with an empty box will again yield an
300  * empty box.
301  */
302  bool isEmpty() const
303  {
304  for(unsigned int i = 0; i < DIMENSION; ++i)
305  if(RangePolicy::isEmptyRange(begin_[i], end_[i]))
306  return true;
307  return false;
308  }
309 
310  /** Return whether this box contains the given point.
311  * That is, if the point lies within the range [begin, end] in
312  * each dimension (excluding end() itself for integer valuetypes).
313  */
314  bool contains(Vector const &p) const
315  {
316  for(unsigned int i = 0; i < DIMENSION; ++i)
317  if((p[i] < begin_[i]) ||
318  RangePolicy::isEmptyRange(p[i], end_[i]))
319  return false;
320  return true;
321  }
322 
323  /** Return whether this box contains the given
324  * one. <tt>r1.contains(r2)</tt> returns the same as
325  * <tt>r1 == (r1|r2)</tt> (but is of course more
326  * efficient). That also means, a box (even an empty one!)
327  * contains() any empty box.
328  */
329  bool contains(Box const &r) const
330  {
331  if(r.isEmpty())
332  return true;
333  if(!contains(r.begin_))
334  return false;
335  for(unsigned int i = 0; i < DIMENSION; ++i)
336  if(r.end_[i] > end_[i])
337  return false;
338  return true;
339  }
340 
341  /** Return whether this box overlaps with the given
342  * one. <tt>r1.intersects(r2)</tt> returns the same as
343  * <tt>!(r1&r2).isEmpty()</tt> (but is of course much more
344  * efficient).
345  */
346  bool intersects(Box const &r) const
347  {
348  if(r.isEmpty() || isEmpty())
349  return false;
350  for(unsigned int i = 0; i < DIMENSION; ++i)
351  if(RangePolicy::isEmptyRange(r.begin_[i], end_[i]) ||
352  RangePolicy::isEmptyRange(begin_[i], r.end_[i]))
353  return false;
354  return true;
355  }
356 
357  /** Modifies this box by including the given point.
358  * The result will be the bounding box of the box and the
359  * point. If isEmpty() returns true on the original box, the
360  * union will be a box containing only the given point.
361  */
362  Box &operator|=(Vector const &p)
363  {
364  if(isEmpty())
365  {
366  begin_ = p;
367  for(unsigned int i = 0; i < DIMENSION; ++i)
368  end_[i] = RangePolicy::pointEnd(p[i]);
369  }
370  else
371  {
372  for(unsigned int i = 0; i < DIMENSION; ++i)
373  {
374  if(p[i] < begin_[i])
375  begin_[i] = p[i];
376  if(RangePolicy::isEmptyRange(p[i], end_[i]))
377  end_[i] = RangePolicy::pointEnd(p[i]);
378  }
379  }
380  return *this;
381  }
382 
383  /** Returns the union of this box and the given point.
384  * The result will be the bounding box of the box and the
385  * point. If isEmpty() returns true on the original box, the
386  * union will be a box containing only the given point.
387  */
388  Box operator|(Vector const &p) const
389  {
390  Box result(*this);
391  result |= p;
392  return result;
393  }
394 
395  /** Modifies this box by uniting it with the given one.
396  * The result will be the bounding box of both boxs. If one of
397  * the boxes isEmpty(), the union will be the other one.
398  */
399  Box &operator|=(Box const &r)
400  {
401  if(r.isEmpty())
402  return *this;
403  if(isEmpty())
404  return this->operator=(r);
405 
406  for(unsigned int i = 0; i < DIMENSION; ++i)
407  {
408  if(r.begin_[i] < begin_[i])
409  begin_[i] = r.begin_[i];
410  if(end_[i] < r.end_[i])
411  end_[i] = r.end_[i];
412  }
413  return *this;
414  }
415 
416  /** Returns the union of this box and the given one.
417  * The result will be the bounding box of both boxs. If one of
418  * the boxes isEmpty(), the union will be the other one.
419  */
420  Box operator|(Box const &r) const
421  {
422  Box result(*this);
423  result |= r;
424  return result;
425  }
426 
427  /** Modifies this box by intersecting it with the given one.
428  * The result will be the maximal box contained in both
429  * original ones. Intersecting with an empty box will yield
430  * again an empty box.
431  */
432  Box &operator&=(Box const &r)
433  {
434  if(isEmpty())
435  return *this;
436  if(r.isEmpty())
437  return this->operator=(r);
438 
439  for(unsigned int i = 0; i < DIMENSION; ++i)
440  {
441  if(begin_[i] < r.begin_[i])
442  begin_[i] = r.begin_[i];
443  if(r.end_[i] < end_[i])
444  end_[i] = r.end_[i];
445  }
446  return *this;
447  }
448 
449  /** Intersects this box with the given one.
450  * The result will be the maximal box contained in both
451  * original ones. Intersecting with an empty box will yield
452  * again an empty box.
453  */
454  Box operator&(Box const &r) const
455  {
456  Box result(*this);
457  result &= r;
458  return result;
459  }
460 
461  /**
462  * Scale box by scalar multiply-assignment. The same scalar
463  * multiply-assignment operation will be performed on both
464  * begin() and end().
465  */
466  Box &operator*=(double scale)
467  {
468  begin_ *= scale;
469  end_ *= scale;
470  return *this;
471  }
472 
473  /**
474  * Return box scaled by given factor. The same scalar
475  * multiplication will be performed on both begin() and end().
476  */
477  Box operator*(double scale)const
478  {
479  Box result(*this);
480  result *= scale;
481  return result;
482  }
483 
484  /**
485  * Scale box by scalar divide-assignment. The same scalar
486  * divide-assignment operation will be performed on both
487  * begin() and end().
488  */
489  Box &operator/=(double scale)
490  {
491  begin_ /= scale;
492  end_ /= scale;
493  return *this;
494  }
495 
496  /**
497  * Return box scaled by inverse of given factor. The same scalar
498  * division will be performed on both begin() and end().
499  */
500  Box operator/(double scale)const
501  {
502  Box result(*this);
503  result /= scale;
504  return result;
505  }
506 
507  /**
508  * Translate box by vector addition-assignment. The same vector
509  * addition-assignment operation will be performed on both
510  * begin() and end().
511  */
512  Box &operator+=(const Vector &offset)
513  {
514  begin_ += offset;
515  end_ += offset;
516  return *this;
517  }
518 
519  /**
520  * Translate box by vector addition. The same vector addition
521  * operation will be performed on both begin() and end().
522  */
523  Box operator+(const Vector &offset)const
524  {
525  Box result(*this);
526  result += offset;
527  return result;
528  }
529 
530  /**
531  * Translate box by vector subtract-assignment. The same vector
532  * subtract-assignment operation will be performed on both
533  * begin() and end().
534  */
535  Box &operator-=(const Vector &offset)
536  {
537  begin_ -= offset;
538  end_ -= offset;
539  return *this;
540  }
541 
542  /**
543  * Translate box by vector subtract. The same vector subtract
544  * operation will be performed on both begin() and end().
545  */
546  Box operator-(const Vector &offset)const
547  {
548  Box result(*this);
549  result -= offset;
550  return result;
551  }
552 };
553 
554 template<class VALUETYPE, unsigned int DIMENSION>
555 std::ostream& operator<< (std::ostream& stream, const Box<VALUETYPE, DIMENSION> & box) {
556  stream<<"["<<box.begin()<<", "<<box.end()<<" ]";
557  return stream;
558 }
559 
560 //@}
561 
562 } // namespace vigra
563 
564 #endif // VIGRA_BOX_HXX
vigra::Box::operator|=
Box & operator|=(Vector const &p)
Definition: box.hxx:362
vigra::Box::setBegin
void setBegin(Vector const &begin)
Definition: box.hxx:182
vigra::TinyVector< VALUETYPE, DIMENSION >
vigra::Box::operator/
Box operator/(double scale) const
Definition: box.hxx:500
vigra::Box::moveBy
void moveBy(Vector const &offset)
Definition: box.hxx:207
vigra::Box::Box
Box()
Definition: box.hxx:119
vigra::Box::operator|
Box operator|(Box const &r) const
Definition: box.hxx:420
vigra::Box::operator/=
Box & operator/=(double scale)
Definition: box.hxx:489
vigra::Box::begin
Vector & begin()
Definition: box.hxx:152
vigra::Box::operator+=
Box & operator+=(const Vector &offset)
Definition: box.hxx:512
vigra
vigra::Box::Box
Box(Vector const &size)
Definition: box.hxx:135
vigra::Box::operator*
Box operator*(double scale) const
Definition: box.hxx:477
vigra::Box::value_type
VALUETYPE value_type
Definition: box.hxx:93
vigra::Box::setSize
void setSize(Vector const &size)
Definition: box.hxx:240
vigra::Box::isEmpty
bool isEmpty() const
Definition: box.hxx:302
vigra::Box::Vector
TinyVector< VALUETYPE, DIMENSION > Vector
Definition: box.hxx:101
vigra::Box::end
Vector & end()
Definition: box.hxx:174
vigra::Box::intersects
bool intersects(Box const &r) const
Definition: box.hxx:346
vigra::Box::VolumeType
NumericTraits< VALUETYPE >::Promote VolumeType
Definition: box.hxx:97
vigra::Box::RangePolicy
If< typename NumericTraits< VALUETYPE >::isIntegral, detail::EndOutsidePolicy< VALUETYPE >, detail::EndInsidePolicy< VALUETYPE > >::type RangePolicy
Definition: box.hxx:112
vigra::Box::moveTo
void moveTo(Vector const &newBegin)
Definition: box.hxx:198
vigra::Box::contains
bool contains(Box const &r) const
Definition: box.hxx:329
vigra::Box::begin
Vector const & begin() const
Definition: box.hxx:143
vigra::Box::operator-=
Box & operator-=(const Vector &offset)
Definition: box.hxx:535
vigra::Box::addBorder
void addBorder(VALUETYPE borderWidth)
Definition: box.hxx:260
vigra::Box
Represent an n-dimensional box as a (begin, end) pair. Depending on the value type,...
Definition: box.hxx:89
vigra::Box::addBorder
void addBorder(const Vector &borderWidth)
Definition: box.hxx:274
vigra::Box::operator!=
bool operator!=(Box const &r) const
inequality check
Definition: box.hxx:289
vigra::Box::setEnd
void setEnd(Vector const &end)
Definition: box.hxx:190
vigra::Box::operator|=
Box & operator|=(Box const &r)
Definition: box.hxx:399
vigra::Box::end
Vector const & end() const
Definition: box.hxx:163
vigra::Box::Box
Box(Vector const &begin, Vector const &end)
Definition: box.hxx:128
vigra::Box::operator-
Box operator-(const Vector &offset) const
Definition: box.hxx:546
vigra::Box::addSize
void addSize(Vector const &offset)
Definition: box.hxx:250
vigra::Box::operator&
Box operator&(Box const &r) const
Definition: box.hxx:454
vigra::Box::operator==
bool operator==(Box const &r) const
equality check
Definition: box.hxx:283
vigra::Box::operator|
Box operator|(Vector const &p) const
Definition: box.hxx:388
vigra::Box::size
Vector size() const
Definition: box.hxx:232
vigra::Box::operator*=
Box & operator*=(double scale)
Definition: box.hxx:466
vigra::Box::volume
VolumeType volume() const
Definition: box.hxx:217
vigra::Box::operator+
Box operator+(const Vector &offset) const
Definition: box.hxx:523
vigra::Box::contains
bool contains(Vector const &p) const
Definition: box.hxx:314
vigra::Box::operator&=
Box & operator&=(Box const &r)
Definition: box.hxx:432

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.11.1