[ 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 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 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.7.1 (3 Dec 2010)