[ 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  /// equality check
270  bool operator==(Box const &r) const
271  {
272  return (begin_ == r.begin_) && (end_ == r.end_);
273  }
274 
275  /// inequality check
276  bool operator!=(Box const &r) const
277  {
278  return (begin_ != r.begin_) || (end_ != r.end_);
279  }
280 
281  /** Return whether this box is considered empty. It is
282  * non-empty if all end() coordinates are greater than (or
283  * equal, for floating point valuetypes) the corresponding
284  * begin() coordinates. Uniting an empty box with something
285  * will return the bounding box of the 'something', and
286  * intersecting any box with an empty box will again yield an
287  * empty box.
288  */
289  bool isEmpty() const
290  {
291  for(unsigned int i = 0; i < DIMENSION; ++i)
292  if(RangePolicy::isEmptyRange(begin_[i], end_[i]))
293  return true;
294  return false;
295  }
296 
297  /** Return whether this box contains the given point.
298  * That is, if the point lies within the range [begin, end] in
299  * each dimension (excluding end() itself for integer valuetypes).
300  */
301  bool contains(Vector const &p) const
302  {
303  for(unsigned int i = 0; i < DIMENSION; ++i)
304  if((p[i] < begin_[i]) ||
305  RangePolicy::isEmptyRange(p[i], end_[i]))
306  return false;
307  return true;
308  }
309 
310  /** Return whether this box contains the given
311  * one. <tt>r1.contains(r2)</tt> returns the same as
312  * <tt>r1 == (r1|r2)</tt> (but is of course more
313  * efficient). That also means, a box (even an empty one!)
314  * contains() any empty box.
315  */
316  bool contains(Box const &r) const
317  {
318  if(r.isEmpty())
319  return true;
320  if(!contains(r.begin_))
321  return false;
322  for(unsigned int i = 0; i < DIMENSION; ++i)
323  if(r.end_[i] > end_[i])
324  return false;
325  return true;
326  }
327 
328  /** Return whether this box overlaps with the given
329  * one. <tt>r1.intersects(r2)</tt> returns the same as
330  * <tt>!(r1&r2).isEmpty()</tt> (but is of course much more
331  * efficient).
332  */
333  bool intersects(Box const &r) const
334  {
335  if(r.isEmpty() || isEmpty())
336  return false;
337  for(unsigned int i = 0; i < DIMENSION; ++i)
338  if(RangePolicy::isEmptyRange(r.begin_[i], end_[i]) ||
339  RangePolicy::isEmptyRange(begin_[i], r.end_[i]))
340  return false;
341  return true;
342  }
343 
344  /** Modifies this box by including the given point.
345  * The result will be the bounding box of the box and the
346  * point. If isEmpty() returns true on the original box, the
347  * union will be a box containing only the given point.
348  */
349  Box &operator|=(Vector const &p)
350  {
351  if(isEmpty())
352  {
353  begin_ = p;
354  for(unsigned int i = 0; i < DIMENSION; ++i)
355  end_[i] = RangePolicy::pointEnd(p[i]);
356  }
357  else
358  {
359  for(unsigned int i = 0; i < DIMENSION; ++i)
360  {
361  if(p[i] < begin_[i])
362  begin_[i] = p[i];
363  if(RangePolicy::isEmptyRange(p[i], end_[i]))
364  end_[i] = RangePolicy::pointEnd(p[i]);
365  }
366  }
367  return *this;
368  }
369 
370  /** Returns the union of this box and the given point.
371  * The result will be the bounding box of the box and the
372  * point. If isEmpty() returns true on the original box, the
373  * union will be a box containing only the given point.
374  */
375  Box operator|(Vector const &p) const
376  {
377  Box result(*this);
378  result |= p;
379  return result;
380  }
381 
382  /** Modifies this box by uniting it with the given one.
383  * The result will be the bounding box of both boxs. If one of
384  * the boxes isEmpty(), the union will be the other one.
385  */
386  Box &operator|=(Box const &r)
387  {
388  if(r.isEmpty())
389  return *this;
390  if(isEmpty())
391  return this->operator=(r);
392 
393  for(unsigned int i = 0; i < DIMENSION; ++i)
394  {
395  if(r.begin_[i] < begin_[i])
396  begin_[i] = r.begin_[i];
397  if(end_[i] < r.end_[i])
398  end_[i] = r.end_[i];
399  }
400  return *this;
401  }
402 
403  /** Returns the union of this box and the given one.
404  * The result will be the bounding box of both boxs. If one of
405  * the boxes isEmpty(), the union will be the other one.
406  */
407  Box operator|(Box const &r) const
408  {
409  Box result(*this);
410  result |= r;
411  return result;
412  }
413 
414  /** Modifies this box by intersecting it with the given one.
415  * The result will be the maximal box contained in both
416  * original ones. Intersecting with an empty box will yield
417  * again an empty box.
418  */
419  Box &operator&=(Box const &r)
420  {
421  if(isEmpty())
422  return *this;
423  if(r.isEmpty())
424  return this->operator=(r);
425 
426  for(unsigned int i = 0; i < DIMENSION; ++i)
427  {
428  if(begin_[i] < r.begin_[i])
429  begin_[i] = r.begin_[i];
430  if(r.end_[i] < end_[i])
431  end_[i] = r.end_[i];
432  }
433  return *this;
434  }
435 
436  /** Intersects this box with the given one.
437  * The result will be the maximal box contained in both
438  * original ones. Intersecting with an empty box will yield
439  * again an empty box.
440  */
441  Box operator&(Box const &r) const
442  {
443  Box result(*this);
444  result &= r;
445  return result;
446  }
447 
448  /**
449  * Scale box by scalar multiply-assignment. The same scalar
450  * multiply-assignment operation will be performed on both
451  * begin() and end().
452  */
453  Box &operator*=(double scale)
454  {
455  begin_ *= scale;
456  end_ *= scale;
457  return *this;
458  }
459 
460  /**
461  * Return box scaled by given factor. The same scalar
462  * multiplication will be performed on both begin() and end().
463  */
464  Box operator*(double scale)
465  {
466  Box result(*this);
467  result *= scale;
468  return result;
469  }
470 
471  /**
472  * Scale box by scalar divide-assignment. The same scalar
473  * divide-assignment operation will be performed on both
474  * begin() and end().
475  */
476  Box &operator/=(double scale)
477  {
478  begin_ /= scale;
479  end_ /= scale;
480  return *this;
481  }
482 
483  /**
484  * Return box scaled by inverse of given factor. The same scalar
485  * division will be performed on both begin() and end().
486  */
487  Box operator/(double scale)
488  {
489  Box result(*this);
490  result /= scale;
491  return result;
492  }
493 
494  /**
495  * Translate box by vector addition-assignment. The same vector
496  * addition-assignment operation will be performed on both
497  * begin() and end().
498  */
499  Box &operator+=(const Vector &offset)
500  {
501  begin_ += offset;
502  end_ += offset;
503  return *this;
504  }
505 
506  /**
507  * Translate box by vector addition. The same vector addition
508  * operation will be performed on both begin() and end().
509  */
510  Box operator+(const Vector &offset)
511  {
512  Box result(*this);
513  result += offset;
514  return result;
515  }
516 
517  /**
518  * Translate box by vector subtract-assignment. The same vector
519  * subtract-assignment operation will be performed on both
520  * begin() and end().
521  */
522  Box &operator-=(const Vector &offset)
523  {
524  begin_ -= offset;
525  end_ -= offset;
526  return *this;
527  }
528 
529  /**
530  * Translate box by vector subtract. The same vector subtract
531  * operation will be performed on both begin() and end().
532  */
533  Box operator-(const Vector &offset)
534  {
535  Box result(*this);
536  result -= offset;
537  return result;
538  }
539 };
540 
541 //@}
542 
543 } // namespace vigra
544 
545 #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:316
Box(Vector const &size)
Definition: box.hxx:135
Box & operator/=(double scale)
Definition: box.hxx:476
Box operator/(double scale)
Definition: box.hxx:487
bool contains(Vector const &p) const
Definition: box.hxx:301
Box & operator&=(Box const &r)
Definition: box.hxx:419
Vector & end()
Definition: box.hxx:174
void setSize(Vector const &size)
Definition: box.hxx:240
Box & operator|=(Vector const &p)
Definition: box.hxx:349
Box & operator*=(double scale)
Definition: box.hxx:453
Box operator-(const Vector &offset)
Definition: box.hxx:533
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:441
Vector & begin()
Definition: box.hxx:152
Box()
Definition: box.hxx:119
Vector const & begin() const
Definition: box.hxx:143
Box & operator-=(const Vector &offset)
Definition: box.hxx:522
Box & operator+=(const Vector &offset)
Definition: box.hxx:499
Box operator|(Box const &r) const
Definition: box.hxx:407
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:333
void addSize(Vector const &offset)
Definition: box.hxx:250
bool operator==(Box const &r) const
equality check
Definition: box.hxx:270
Box operator+(const Vector &offset)
Definition: box.hxx:510
bool isEmpty() const
Definition: box.hxx:289
Box operator*(double scale)
Definition: box.hxx:464
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|=(Box const &r)
Definition: box.hxx:386
bool operator!=(Box const &r) const
inequality check
Definition: box.hxx:276
Box operator|(Vector const &p) const
Definition: box.hxx:375

© 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.10.0 (Mon Apr 28 2014)