[ 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 /// 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
vigra::Box::size
Vector size() const
Definition: box.hxx:232
vigra::Box::moveBy
void moveBy(Vector const &offset)
Definition: box.hxx:207
vigra::Box::contains
bool contains(Box const &r) const
Definition: box.hxx:316
vigra::Box::Box
Box(Vector const &size)
Definition: box.hxx:135
vigra::Box::operator/=
Box & operator/=(double scale)
Definition: box.hxx:476
vigra::Box::operator/
Box operator/(double scale)
Definition: box.hxx:487
vigra::Box::contains
bool contains(Vector const &p) const
Definition: box.hxx:301
vigra::Box::operator&=
Box & operator&=(Box const &r)
Definition: box.hxx:419
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)
Definition: box.hxx:349
vigra::Box::operator*=
Box & operator*=(double scale)
Definition: box.hxx:453
vigra::Box::operator-
Box operator-(const Vector &offset)
Definition: box.hxx:533
vigra::Box::volume
VolumeType volume() const
Definition: box.hxx:217
vigra::Box::end
Vector const & end() const
Definition: box.hxx:163
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::Box::operator&
Box operator&(Box const &r) const
Definition: box.hxx:441
vigra::Box::begin
Vector & begin()
Definition: box.hxx:152
vigra::Box::Box
Box()
Definition: box.hxx:119
vigra::Box::begin
Vector const & begin() const
Definition: box.hxx:143
vigra
Definition: accessor.hxx:43
vigra::Box::operator-=
Box & operator-=(const Vector &offset)
Definition: box.hxx:522
vigra::Box::operator+=
Box & operator+=(const Vector &offset)
Definition: box.hxx:499
vigra::Box::operator|
Box operator|(Box const &r) const
Definition: box.hxx:407
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::setEnd
void setEnd(Vector const &end)
Definition: box.hxx:190
vigra::Box::Box
Box(Vector const &begin, Vector const &end)
Definition: box.hxx:128
vigra::TinyVector< VALUETYPE, DIMENSION >
vigra::Box::intersects
bool intersects(Box const &r) const
Definition: box.hxx:333
vigra::Box::addSize
void addSize(Vector const &offset)
Definition: box.hxx:250
vigra::Box::operator==
bool operator==(Box const &r) const
equality check
Definition: box.hxx:270
vigra::Box::operator+
Box operator+(const Vector &offset)
Definition: box.hxx:510
vigra::Box::isEmpty
bool isEmpty() const
Definition: box.hxx:289
vigra::Box::operator*
Box operator*(double scale)
Definition: box.hxx:464
vigra::Box::RangePolicy
If< typename NumericTraits< VALUETYPE >::isIntegral, detail::EndOutsidePolicy< VALUETYPE >, detail::EndInsidePolicy< VALUETYPE > >::type RangePolicy
Definition: box.hxx:112
vigra::Box::setBegin
void setBegin(Vector const &begin)
Definition: box.hxx:182
vigra::Box::addBorder
void addBorder(VALUETYPE borderWidth)
Definition: box.hxx:260
vigra::Box::operator|=
Box & operator|=(Box const &r)
Definition: box.hxx:386
vigra::Box::operator!=
bool operator!=(Box const &r) const
inequality check
Definition: box.hxx:276
vigra::Box::operator|
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