[ 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
43namespace vigra {
44
45namespace detail {
46
47// RangePolicy used for floating point coordinate types
48template<class VALUETYPE>
49struct 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
63template<class VALUETYPE>
64struct 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 */
87template<class VALUETYPE, unsigned int DIMENSION>
88class 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 */
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 */
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
554template<class VALUETYPE, unsigned int DIMENSION>
555std::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
Represent an n-dimensional box as a (begin, end) pair. Depending on the value type,...
Definition: box.hxx:89
Box operator|(Box const &r) const
Definition: box.hxx:420
Vector const & end() const
Definition: box.hxx:163
void setBegin(Vector const &begin)
Definition: box.hxx:182
Vector size() const
Definition: box.hxx:232
Vector & begin()
Definition: box.hxx:152
void setSize(Vector const &size)
Definition: box.hxx:240
If< typenameNumericTraits< VALUETYPE >::isIntegral, detail::EndOutsidePolicy< VALUETYPE >, detail::EndInsidePolicy< VALUETYPE > >::type RangePolicy
Definition: box.hxx:112
void addSize(Vector const &offset)
Definition: box.hxx:250
Box operator&(Box const &r) const
Definition: box.hxx:454
Box & operator|=(Vector const &p)
Definition: box.hxx:362
Box operator*(double scale) const
Definition: box.hxx:477
Vector & end()
Definition: box.hxx:174
Vector const & begin() const
Definition: box.hxx:143
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
Box & operator+=(const Vector &offset)
Definition: box.hxx:512
Box operator|(Vector const &p) const
Definition: box.hxx:388
bool intersects(Box const &r) const
Definition: box.hxx:346
Box & operator&=(Box const &r)
Definition: box.hxx:432
Box operator/(double scale) const
Definition: box.hxx:500
void moveTo(Vector const &newBegin)
Definition: box.hxx:198
NumericTraits< VALUETYPE >::Promote VolumeType
Definition: box.hxx:97
Box & operator*=(double scale)
Definition: box.hxx:466
Box & operator-=(const Vector &offset)
Definition: box.hxx:535
Box operator-(const Vector &offset) const
Definition: box.hxx:546
bool contains(Vector const &p) const
Definition: box.hxx:314
bool isEmpty() const
Definition: box.hxx:302
TinyVector< VALUETYPE, DIMENSION > Vector
Definition: box.hxx:101
void moveBy(Vector const &offset)
Definition: box.hxx:207
void addBorder(const Vector &borderWidth)
Definition: box.hxx:274
Box(Vector const &begin, Vector const &end)
Definition: box.hxx:128
VALUETYPE value_type
Definition: box.hxx:93
Box()
Definition: box.hxx:119
Box & operator|=(Box const &r)
Definition: box.hxx:399
VolumeType volume() const
Definition: box.hxx:217
void addBorder(VALUETYPE borderWidth)
Definition: box.hxx:260
bool operator==(Box const &r) const
equality check
Definition: box.hxx:283
Box operator+(const Vector &offset) const
Definition: box.hxx:523
bool operator!=(Box const &r) const
inequality check
Definition: box.hxx:289
void setEnd(Vector const &end)
Definition: box.hxx:190
iterator end()
Definition: tinyvector.hxx:864

© 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