[ 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 */
101 typedef TinyVector<VALUETYPE, DIMENSION> Vector;
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 */
152 Vector & begin()
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 */
174 Vector & end()
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 */
217 VolumeType volume() const
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::moveBy
void moveBy(Vector const &offset)
Definition: box.hxx:207
vigra::Box::operator &
Box operator &(Box const &r) const
Definition: box.hxx:454
vigra::Box::Box
Box(Vector const &size)
Definition: box.hxx:135
vigra::Box::operator/=
Box & operator/=(double scale)
Definition: box.hxx:489
vigra::Box::contains
bool contains(Vector const &p) const
Definition: box.hxx:314
vigra::Box::end
Vector & end()
Definition: box.hxx:174
vigra::Box::setSize
void setSize(Vector const &size)
Definition: box.hxx:240
vigra::Box::operator|
Box operator|(Vector const &p) const
Definition: box.hxx:388
vigra::Box::operator|=
Box & operator|=(Vector const &p)
Definition: box.hxx:362
vigra::Box::operator*=
Box & operator*=(double scale)
Definition: box.hxx:466
vigra::Box::intersects
bool intersects(Box const &r) const
Definition: box.hxx:346
vigra::Box::operator+
Box operator+(const Vector &offset) const
Definition: box.hxx:523
vigra::Box::isEmpty
bool isEmpty() const
Definition: box.hxx:302
vigra::Box::value_type
VALUETYPE value_type
Definition: box.hxx:93
vigra::Box::moveTo
void moveTo(Vector const &newBegin)
Definition: box.hxx:198
vigra::Box::VolumeType
NumericTraits< VALUETYPE >::Promote VolumeType
Definition: box.hxx:97
vigra::TinyVectorBase::end
iterator end()
Definition: tinyvector.hxx:864
vigra::Box::begin
Vector & begin()
Definition: box.hxx:152
vigra::Box::Box
Box()
Definition: box.hxx:119
vigra
Definition: accessor.hxx:43
vigra::Box::operator|
Box operator|(Box const &r) const
Definition: box.hxx:420
vigra::Box::operator*
Box operator*(double scale) const
Definition: box.hxx:477
vigra::Box::operator-=
Box & operator-=(const Vector &offset)
Definition: box.hxx:535
vigra::Box::contains
bool contains(Box const &r) const
Definition: box.hxx:329
vigra::Box::operator+=
Box & operator+=(const Vector &offset)
Definition: box.hxx:512
vigra::Box::addBorder
void addBorder(const Vector &borderWidth)
Definition: box.hxx:274
vigra::Box
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
vigra::Box::Vector
TinyVector< VALUETYPE, DIMENSION > Vector
Definition: box.hxx:101
vigra::Box::end
Vector const & end() const
Definition: box.hxx:163
vigra::Box::setEnd
void setEnd(Vector const &end)
Definition: box.hxx:190
vigra::Box::operator &=
Box & operator &=(Box const &r)
Definition: box.hxx:432
vigra::Box::Box
Box(Vector const &begin, Vector const &end)
Definition: box.hxx:128
vigra::TinyVector< VALUETYPE, DIMENSION >
vigra::Box::addSize
void addSize(Vector const &offset)
Definition: box.hxx:250
vigra::Box::operator-
Box operator-(const Vector &offset) const
Definition: box.hxx:546
vigra::Box::RangePolicy
If< typename NumericTraits< VALUETYPE >::isIntegral, detail::EndOutsidePolicy< VALUETYPE >, detail::EndInsidePolicy< VALUETYPE > >::type RangePolicy
Definition: box.hxx:112
vigra::Box::volume
VolumeType volume() const
Definition: box.hxx:217
vigra::Box::operator!=
bool operator!=(Box const &r) const
inequality check
Definition: box.hxx:289
vigra::Box::setBegin
void setBegin(Vector const &begin)
Definition: box.hxx:182
vigra::Box::size
Vector size() const
Definition: box.hxx:232
vigra::Box::begin
Vector const & begin() const
Definition: box.hxx:143
vigra::Box::addBorder
void addBorder(VALUETYPE borderWidth)
Definition: box.hxx:260
vigra::Box::operator|=
Box & operator|=(Box const &r)
Definition: box.hxx:399
vigra::Box::operator/
Box operator/(double scale) const
Definition: box.hxx:500
vigra::Box::operator==
bool operator==(Box const &r) const
equality check
Definition: box.hxx:283

© 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.0