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

vigra/box.hxx VIGRA

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)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.8.0 (20 Sep 2011)