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

box.hxx
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

© 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.7.1 (Thu Jun 14 2012)