[ 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
Vector size() const
Definition: box.hxx:232
void moveBy(Vector const &offset)
Definition: box.hxx:207
bool contains(Box const &r) const
Definition: box.hxx:329
Box(Vector const &size)
Definition: box.hxx:135
Box & operator/=(double scale)
Definition: box.hxx:489
bool contains(Vector const &p) const
Definition: box.hxx:314
Box & operator&=(Box const &r)
Definition: box.hxx:432
Vector & end()
Definition: box.hxx:174
void setSize(Vector const &size)
Definition: box.hxx:240
Box operator+(const Vector &offset) const
Definition: box.hxx:523
Box & operator|=(Vector const &p)
Definition: box.hxx:362
Box & operator*=(double scale)
Definition: box.hxx:466
VolumeType volume() const
Definition: box.hxx:217
Vector const & end() const
Definition: box.hxx:163
VALUETYPE value_type
Definition: box.hxx:93
void moveTo(Vector const &newBegin)
Definition: box.hxx:198
NumericTraits< VALUETYPE >::Promote VolumeType
Definition: box.hxx:97
Box operator&(Box const &r) const
Definition: box.hxx:454
iterator end()
Definition: tinyvector.hxx:864
Vector & begin()
Definition: box.hxx:152
Box()
Definition: box.hxx:119
Vector const & begin() const
Definition: box.hxx:143
Box operator*(double scale) const
Definition: box.hxx:477
Box & operator-=(const Vector &offset)
Definition: box.hxx:535
Box operator-(const Vector &offset) const
Definition: box.hxx:546
Box & operator+=(const Vector &offset)
Definition: box.hxx:512
void addBorder(const Vector &borderWidth)
Definition: box.hxx:274
Box operator|(Box const &r) const
Definition: box.hxx:420
Represent an n-dimensional box as a (begin, end) pair. Depending on the value type, end() is considered to be outside the box (as in the STL, for integer types), or inside (for floating point types). size() will always be end() - begin().
Definition: box.hxx:88
TinyVector< VALUETYPE, DIMENSION > Vector
Definition: box.hxx:101
void setEnd(Vector const &end)
Definition: box.hxx:190
Box(Vector const &begin, Vector const &end)
Definition: box.hxx:128
bool intersects(Box const &r) const
Definition: box.hxx:346
void addSize(Vector const &offset)
Definition: box.hxx:250
bool operator==(Box const &r) const
equality check
Definition: box.hxx:283
bool isEmpty() const
Definition: box.hxx:302
If< typename NumericTraits< VALUETYPE >::isIntegral, detail::EndOutsidePolicy< VALUETYPE >, detail::EndInsidePolicy< VALUETYPE > >::type RangePolicy
Definition: box.hxx:112
void setBegin(Vector const &begin)
Definition: box.hxx:182
void addBorder(VALUETYPE borderWidth)
Definition: box.hxx:260
Box operator/(double scale) const
Definition: box.hxx:500
Box & operator|=(Box const &r)
Definition: box.hxx:399
bool operator!=(Box const &r) const
inequality check
Definition: box.hxx:289
Box operator|(Vector const &p) const
Definition: box.hxx:388

© 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 (Fri May 19 2017)