[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
vigra/box.hxx | ![]() |
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 2009-2010 by Ullrich Koethe and Hans Meine */ 00004 /* */ 00005 /* This file is part of the VIGRA computer vision library. */ 00006 /* The VIGRA Website is */ 00007 /* http://hci.iwr.uni-heidelberg.de/vigra/ */ 00008 /* Please direct questions, bug reports, and contributions to */ 00009 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00010 /* vigra@informatik.uni-hamburg.de */ 00011 /* */ 00012 /* Permission is hereby granted, free of charge, to any person */ 00013 /* obtaining a copy of this software and associated documentation */ 00014 /* files (the "Software"), to deal in the Software without */ 00015 /* restriction, including without limitation the rights to use, */ 00016 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00017 /* sell copies of the Software, and to permit persons to whom the */ 00018 /* Software is furnished to do so, subject to the following */ 00019 /* conditions: */ 00020 /* */ 00021 /* The above copyright notice and this permission notice shall be */ 00022 /* included in all copies or substantial portions of the */ 00023 /* Software. */ 00024 /* */ 00025 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00026 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00027 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00028 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00029 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00030 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00031 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00032 /* OTHER DEALINGS IN THE SOFTWARE. */ 00033 /* */ 00034 /************************************************************************/ 00035 00036 #ifndef VIGRA_BOX_HXX 00037 #define VIGRA_BOX_HXX 00038 00039 #include "metaprogramming.hxx" 00040 #include "numerictraits.hxx" 00041 #include "tinyvector.hxx" 00042 00043 namespace vigra { 00044 00045 namespace detail { 00046 00047 // RangePolicy used for floating point coordinate types 00048 template<class VALUETYPE> 00049 struct EndInsidePolicy 00050 { 00051 static inline bool isEmptyRange(VALUETYPE b, VALUETYPE e) 00052 { 00053 return e < b; // <= 00054 } 00055 00056 static inline VALUETYPE pointEnd(VALUETYPE p) 00057 { 00058 return p; // +1 00059 } 00060 }; 00061 00062 // RangePolicy used for integer coordinate types 00063 template<class VALUETYPE> 00064 struct EndOutsidePolicy 00065 { 00066 static inline bool isEmptyRange(VALUETYPE b, VALUETYPE e) 00067 { 00068 return e <= b; 00069 } 00070 00071 static inline VALUETYPE pointEnd(VALUETYPE p) 00072 { 00073 return p+1; 00074 } 00075 }; 00076 00077 } // namespace vigra::detail 00078 00079 /** \addtogroup RangesAndPoints */ 00080 //@{ 00081 /** \brief Represent an n-dimensional box as a (begin, end) pair. 00082 * Depending on the value type, end() is considered to be 00083 * outside the box (as in the STL, for integer types), or 00084 * inside (for floating point types). size() will always be 00085 * end() - begin(). 00086 */ 00087 template<class VALUETYPE, unsigned int DIMENSION> 00088 class Box 00089 { 00090 public: 00091 /** STL-compatible definition of coordinate valuetype 00092 */ 00093 typedef VALUETYPE value_type; 00094 00095 /** Promoted coordinate valuetype, used for volume() 00096 */ 00097 typedef typename NumericTraits<VALUETYPE>::Promote VolumeType; 00098 00099 /** Vector type used for begin() and end() 00100 */ 00101 typedef TinyVector<VALUETYPE, DIMENSION> Vector; 00102 00103 enum { Dimension = DIMENSION }; 00104 00105 protected: 00106 Vector begin_, end_; 00107 00108 /** Range policy (EndInsidePolicy/EndOutsidePolicy, depending on valuetype) 00109 */ 00110 typedef typename If<typename NumericTraits<VALUETYPE>::isIntegral, 00111 detail::EndOutsidePolicy<VALUETYPE>, 00112 detail::EndInsidePolicy<VALUETYPE> >::type RangePolicy; 00113 00114 public: 00115 /** Construct an empty box (isEmpty() will return true). 00116 * (Internally, this will initialize all dimensions with the 00117 * empty range [1..0].) 00118 */ 00119 Box() 00120 : begin_(NumericTraits<Vector>::one()) 00121 {} 00122 00123 /** Construct a box representing the given range. Depending 00124 * on the value type, end() is considered to be outside the 00125 * box (as in the STL, for integer types), or inside (for 00126 * floating point types). 00127 */ 00128 Box(Vector const &begin, Vector const &end) 00129 : begin_(begin), end_(end) 00130 {} 00131 00132 /** Construct a box of given size at the origin (i.e. end() == 00133 * size()). 00134 */ 00135 explicit Box(Vector const &size) 00136 : end_(size) 00137 {} 00138 00139 /** Get begin vector (i.e. smallest coordinates for each 00140 * dimension). This is the first point (scan-order wise) 00141 * which is considered to be "in" the box. 00142 */ 00143 Vector const & begin() const 00144 { 00145 return begin_; 00146 } 00147 00148 /** Access begin vector (i.e. smallest coordinates for each 00149 * dimension). This is the first point (scan-order wise) 00150 * which is considered to be "in" the box. 00151 */ 00152 Vector & begin() 00153 { 00154 return begin_; 00155 } 00156 00157 /** Get end vector (i.e. coordinates higher than begin() in 00158 * each dimension for non-empty boxes). This is begin() + 00159 * size(), and depending on the valuetype (float/int), this is 00160 * the last point within or the first point outside the box, 00161 * respectively. 00162 */ 00163 Vector const & end() const 00164 { 00165 return end_; 00166 } 00167 00168 /** Access end vector (i.e. coordinates higher than begin() in 00169 * each dimension for non-empty boxes). This is begin() + 00170 * size(), and depending on the valuetype (float/int), this is 00171 * the last point within or the first point outside the box, 00172 * respectively. 00173 */ 00174 Vector & end() 00175 { 00176 return end_; 00177 } 00178 00179 /** Change begin() without changing end(), changing size() 00180 * accordingly. 00181 */ 00182 void setBegin(Vector const &begin) 00183 { 00184 begin_ = begin; 00185 } 00186 00187 /** Change end() without changing begin(), which will change 00188 * the size() most probably. 00189 */ 00190 void setEnd(Vector const &end) 00191 { 00192 end_ = end; 00193 } 00194 00195 /** Move the whole box so that the given point will be 00196 * begin() afterwards. 00197 */ 00198 void moveTo(Vector const &newBegin) 00199 { 00200 end_ += newBegin - begin_; 00201 begin_ = newBegin; 00202 } 00203 00204 /** Move the whole box by the given offset. 00205 * (Equivalent to operator+=) 00206 */ 00207 void moveBy(Vector const &offset) 00208 { 00209 begin_ += offset; 00210 end_ += offset; 00211 } 00212 00213 /** Determine and return the area of this box. That is, 00214 * if this rect isEmpty(), returns zero, otherwise returns the 00215 * product of the extents in each dimension. 00216 */ 00217 VolumeType volume() const 00218 { 00219 if(isEmpty()) 00220 return 0; 00221 00222 VolumeType result(end_[0] - begin_[0]); 00223 for(unsigned int i = 1; i < DIMENSION; ++i) 00224 result *= end_[i] - begin_[i]; 00225 return result; 00226 } 00227 00228 /** Determine and return the size of this box. The size 00229 * might be zero or even negative in one or more dimensions, 00230 * and if so, isEmpty() will return true. 00231 */ 00232 Vector size() const 00233 { 00234 return end_ - begin_; 00235 } 00236 00237 /** Resize this box to the given extents. This will 00238 * change end() only. 00239 */ 00240 void setSize(Vector const &size) 00241 { 00242 end_ = begin_ + size; 00243 } 00244 00245 /** Increase the size of the box by the given 00246 * offset. This will move end() only. (If any of offset's 00247 * components is negative, the box will get smaller 00248 * accordingly.) 00249 */ 00250 void addSize(Vector const &offset) 00251 { 00252 end_ += offset; 00253 } 00254 00255 /** Adds a border of the given width around the box. That 00256 * means, begin()'s components are moved by -borderWidth 00257 * and end()'s by borderWidth. (If borderWidth is 00258 * negative, the box will get smaller accordingly.) 00259 */ 00260 void addBorder(VALUETYPE borderWidth) 00261 { 00262 for(unsigned int i = 0; i < DIMENSION; ++i) 00263 { 00264 begin_[i] -= borderWidth; 00265 end_[i] += borderWidth; 00266 } 00267 } 00268 00269 /// equality check 00270 bool operator==(Box const &r) const 00271 { 00272 return (begin_ == r.begin_) && (end_ == r.end_); 00273 } 00274 00275 /// inequality check 00276 bool operator!=(Box const &r) const 00277 { 00278 return (begin_ != r.begin_) || (end_ != r.end_); 00279 } 00280 00281 /** Return whether this box is considered empty. It is 00282 * non-empty if all end() coordinates are greater than (or 00283 * equal, for floating point valuetypes) the corresponding 00284 * begin() coordinates. Uniting an empty box with something 00285 * will return the bounding box of the 'something', and 00286 * intersecting any box with an empty box will again yield an 00287 * empty box. 00288 */ 00289 bool isEmpty() const 00290 { 00291 for(unsigned int i = 0; i < DIMENSION; ++i) 00292 if(RangePolicy::isEmptyRange(begin_[i], end_[i])) 00293 return true; 00294 return false; 00295 } 00296 00297 /** Return whether this box contains the given point. 00298 * That is, if the point lies within the range [begin, end] in 00299 * each dimension (excluding end() itself for integer valuetypes). 00300 */ 00301 bool contains(Vector const &p) const 00302 { 00303 for(unsigned int i = 0; i < DIMENSION; ++i) 00304 if((p[i] < begin_[i]) || 00305 RangePolicy::isEmptyRange(p[i], end_[i])) 00306 return false; 00307 return true; 00308 } 00309 00310 /** Return whether this box contains the given 00311 * one. <tt>r1.contains(r2)</tt> returns the same as 00312 * <tt>r1 == (r1|r2)</tt> (but is of course more 00313 * efficient). That also means, a box (even an empty one!) 00314 * contains() any empty box. 00315 */ 00316 bool contains(Box const &r) const 00317 { 00318 if(r.isEmpty()) 00319 return true; 00320 if(!contains(r.begin_)) 00321 return false; 00322 for(unsigned int i = 0; i < DIMENSION; ++i) 00323 if(r.end_[i] > end_[i]) 00324 return false; 00325 return true; 00326 } 00327 00328 /** Return whether this box overlaps with the given 00329 * one. <tt>r1.intersects(r2)</tt> returns the same as 00330 * <tt>!(r1&r2).isEmpty()</tt> (but is of course much more 00331 * efficient). 00332 */ 00333 bool intersects(Box const &r) const 00334 { 00335 if(r.isEmpty() || isEmpty()) 00336 return false; 00337 for(unsigned int i = 0; i < DIMENSION; ++i) 00338 if(RangePolicy::isEmptyRange(r.begin_[i], end_[i]) || 00339 RangePolicy::isEmptyRange(begin_[i], r.end_[i])) 00340 return false; 00341 return true; 00342 } 00343 00344 /** Modifies this box by including the given point. 00345 * The result will be the bounding box of the box and the 00346 * point. If isEmpty() returns true on the original box, the 00347 * union will be a box containing only the given point. 00348 */ 00349 Box &operator|=(Vector const &p) 00350 { 00351 if(isEmpty()) 00352 { 00353 begin_ = p; 00354 for(unsigned int i = 0; i < DIMENSION; ++i) 00355 end_[i] = RangePolicy::pointEnd(p[i]); 00356 } 00357 else 00358 { 00359 for(unsigned int i = 0; i < DIMENSION; ++i) 00360 { 00361 if(p[i] < begin_[i]) 00362 begin_[i] = p[i]; 00363 if(RangePolicy::isEmptyRange(p[i], end_[i])) 00364 end_[i] = RangePolicy::pointEnd(p[i]); 00365 } 00366 } 00367 return *this; 00368 } 00369 00370 /** Returns the union of this box and the given point. 00371 * The result will be the bounding box of the box and the 00372 * point. If isEmpty() returns true on the original box, the 00373 * union will be a box containing only the given point. 00374 */ 00375 Box operator|(Vector const &p) const 00376 { 00377 Box result(*this); 00378 result |= p; 00379 return result; 00380 } 00381 00382 /** Modifies this box by uniting it with the given one. 00383 * The result will be the bounding box of both boxs. If one of 00384 * the boxes isEmpty(), the union will be the other one. 00385 */ 00386 Box &operator|=(Box const &r) 00387 { 00388 if(r.isEmpty()) 00389 return *this; 00390 if(isEmpty()) 00391 return this->operator=(r); 00392 00393 for(unsigned int i = 0; i < DIMENSION; ++i) 00394 { 00395 if(r.begin_[i] < begin_[i]) 00396 begin_[i] = r.begin_[i]; 00397 if(end_[i] < r.end_[i]) 00398 end_[i] = r.end_[i]; 00399 } 00400 return *this; 00401 } 00402 00403 /** Returns the union of this box and the given one. 00404 * The result will be the bounding box of both boxs. If one of 00405 * the boxes isEmpty(), the union will be the other one. 00406 */ 00407 Box operator|(Box const &r) const 00408 { 00409 Box result(*this); 00410 result |= r; 00411 return result; 00412 } 00413 00414 /** Modifies this box by intersecting it with the given one. 00415 * The result will be the maximal box contained in both 00416 * original ones. Intersecting with an empty box will yield 00417 * again an empty box. 00418 */ 00419 Box &operator&=(Box const &r) 00420 { 00421 if(isEmpty()) 00422 return *this; 00423 if(r.isEmpty()) 00424 return this->operator=(r); 00425 00426 for(unsigned int i = 0; i < DIMENSION; ++i) 00427 { 00428 if(begin_[i] < r.begin_[i]) 00429 begin_[i] = r.begin_[i]; 00430 if(r.end_[i] < end_[i]) 00431 end_[i] = r.end_[i]; 00432 } 00433 return *this; 00434 } 00435 00436 /** Intersects this box with the given one. 00437 * The result will be the maximal box contained in both 00438 * original ones. Intersecting with an empty box will yield 00439 * again an empty box. 00440 */ 00441 Box operator&(Box const &r) const 00442 { 00443 Box result(*this); 00444 result &= r; 00445 return result; 00446 } 00447 00448 /** 00449 * Scale box by scalar multiply-assignment. The same scalar 00450 * multiply-assignment operation will be performed on both 00451 * begin() and end(). 00452 */ 00453 Box &operator*=(double scale) 00454 { 00455 begin_ *= scale; 00456 end_ *= scale; 00457 return *this; 00458 } 00459 00460 /** 00461 * Return box scaled by given factor. The same scalar 00462 * multiplication will be performed on both begin() and end(). 00463 */ 00464 Box operator*(double scale) 00465 { 00466 Box result(*this); 00467 result *= scale; 00468 return result; 00469 } 00470 00471 /** 00472 * Scale box by scalar divide-assignment. The same scalar 00473 * divide-assignment operation will be performed on both 00474 * begin() and end(). 00475 */ 00476 Box &operator/=(double scale) 00477 { 00478 begin_ /= scale; 00479 end_ /= scale; 00480 return *this; 00481 } 00482 00483 /** 00484 * Return box scaled by inverse of given factor. The same scalar 00485 * division will be performed on both begin() and end(). 00486 */ 00487 Box operator/(double scale) 00488 { 00489 Box result(*this); 00490 result /= scale; 00491 return result; 00492 } 00493 00494 /** 00495 * Translate box by vector addition-assignment. The same vector 00496 * addition-assignment operation will be performed on both 00497 * begin() and end(). 00498 */ 00499 Box &operator+=(const Vector &offset) 00500 { 00501 begin_ += offset; 00502 end_ += offset; 00503 return *this; 00504 } 00505 00506 /** 00507 * Translate box by vector addition. The same vector addition 00508 * operation will be performed on both begin() and end(). 00509 */ 00510 Box operator+(const Vector &offset) 00511 { 00512 Box result(*this); 00513 result += offset; 00514 return result; 00515 } 00516 00517 /** 00518 * Translate box by vector subtract-assignment. The same vector 00519 * subtract-assignment operation will be performed on both 00520 * begin() and end(). 00521 */ 00522 Box &operator-=(const Vector &offset) 00523 { 00524 begin_ -= offset; 00525 end_ -= offset; 00526 return *this; 00527 } 00528 00529 /** 00530 * Translate box by vector subtract. The same vector subtract 00531 * operation will be performed on both begin() and end(). 00532 */ 00533 Box operator-(const Vector &offset) 00534 { 00535 Box result(*this); 00536 result -= offset; 00537 return result; 00538 } 00539 }; 00540 00541 //@} 00542 00543 } // namespace vigra 00544 00545 #endif // VIGRA_BOX_HXX
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|