Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

Rectangle.H

Go to the documentation of this file.
00001 /*!@file Image/Rectangle.H A basic rectangle class */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00005 // University of Southern California (USC) and the iLab at USC.         //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/Rectangle.H $
00035 // $Id: Rectangle.H 10908 2009-02-22 16:16:28Z lior $
00036 //
00037 
00038 #ifndef RECTANGLE_H_DEFINED
00039 #define RECTANGLE_H_DEFINED
00040 
00041 #include "Image/Dims.H"
00042 #include "Image/Point2D.H"
00043 #include "Util/Assert.H"
00044 
00045 #include <algorithm>
00046 #include <string> // for string conversions
00047 
00048 //! A basic rectangle class
00049 /*! This is a shorthand class to represent a 2D rectangle, as defined
00050     by integer top, left, bottom and right coordinates.  The goal of
00051     this object is not to have to check if left < right, etc...  for
00052     each function using a Rectangle. The object checks for that at its
00053     creation, and is always internally coherent.  Image convention:
00054     top < bottom, left < right.
00055 
00056     There is often some ambiguity about how to represent the
00057     left-right and top-bottom ranges involved in a rectangle. Imagine
00058     a pixel grid like this:
00059 
00060     +---+---+---+---+
00061     |   |   |   |   |
00062     |   |   |   |   |
00063     +---+---+---+---+
00064     |   |   |   |   |
00065     |   |   |   |   |
00066     +---+---+---+---+
00067     |   |   |   |   |
00068     |   |   |   |   |
00069     +---+---+---+---+
00070     |   |   |   |   |
00071     |   |   |   |   |
00072     +---+---+---+---+
00073 
00074 
00075     If we want a Rectangle that covers this whole 4x4 grid, how should
00076     we represent the coordinates? Clearly the upper left corner is
00077     (0,0), but what about the bottom right corner? One answer would be
00078     that the lower right corner is (4,4), in which we imagine the
00079     coordinate numbers falling between the cracks of the pixels:
00080 
00081     . 0...1...2...3...4
00082     0 +---+---+---+---+
00083     . |   |   |   |   |
00084     . |   |   |   |   |
00085     1 +---+---+---+---+
00086     . |   |   |   |   |
00087     . |   |   |   |   |
00088     2 +---+---+---+---+
00089     . |   |   |   |   |
00090     . |   |   |   |   |
00091     3 +---+---+---+---+
00092     . |   |   |   |   |
00093     . |   |   |   |   |
00094     4 +---+---+---+---+
00095 
00096     Another answer is that the lower right corner should be labeled as
00097     (3,3), if we envision the coordinate numbers labeling the pixel
00098     centers, and this approach is more natural if we want to draw a
00099     line just inside the border of the rectangle as shown by the '*'
00100     here:
00101 
00102     . ..0...1...2...3..
00103     . +---+---+---+---+
00104     0 |***|***|***|***|
00105     . |***|***|***|***|
00106     . +---+---+---+---+
00107     1 |***|   |   |***|
00108     . |***|   |   |***|
00109     . +---+---+---+---+
00110     2 |***|   |   |***|
00111     . |***|   |   |***|
00112     . +---+---+---+---+
00113     3 |***|***|***|***|
00114     . |***|***|***|***|
00115     . +---+---+---+---+
00116 
00117     In the Rectangle class we support both approaches; the (4,4)
00118     coords are called 'outer' coordinates and corresponding functions
00119     have a 'O' suffix (bottomO(), right(), and tlbrO()), while the
00120     (3,3) coords are called 'inner' coordinates and corresponding
00121     functions have an 'I' suffix (bottomI(), rightI(), and tlbrI()).
00122 
00123     The internal representation of Rectangle is based on outer
00124     coordinates, but this has no effect on users of the class who are
00125     free to user whichever of inner or outer coords are more
00126     convenient for their purposes.
00127 
00128     Outer coordinates are more natural for uniformly scaling a
00129     rectangle up or down by a factor. For example, if we want to scale
00130     the 4x4 rect up by a factor of 2 giving an 8x8 rect, then in outer
00131     coords we just do newright=right*2=4*2=8 and
00132     newbottom=bottom*2=4*2=8. But with inner coords we can't just
00133     multiply by 2: the inner bottom-right coords are (3,3), and if we
00134     scale those by 2 we get (6,6) which represents a 7x7 rectangle
00135     rather than the correct 8x8 result.
00136 
00137     HISTORICAL NOTE (2007-Mar-20): The Rectangle class previously used
00138     only inner coordinates both for its implementation and in its
00139     public interface. This lead to clunky code in some places where
00140     many -1 or +1 offsets were needed to handle rectangle coordinates.
00141 */
00142 
00143 class Rectangle {
00144 
00145   //! Private constructor; use the tlbrO() pseudo-constructor if you want to call this publicly
00146   inline Rectangle(int tt, int ll, int bb1, int rr1);
00147 
00148 public:
00149   // ############################################################
00150   // ##### Constructors & Destructors:
00151   // ############################################################
00152 
00153   //! Build from 4 coordinates (top, left, inner-bottom, inner-right)
00154   static inline Rectangle tlbrI(int tt, int ll, int bb, int rr);
00155 
00156   //! Build from 4 coordinates (top, left, outer-bottom, outer-right)
00157   static inline Rectangle tlbrO(int tt, int ll, int bb, int rr);
00158 
00159   //! Build from a top-left corner and some dims
00160   inline Rectangle(const Point2D<int>& topleft, const Dims& dims);
00161 
00162   //! Copy constructor
00163   inline Rectangle(const Rectangle& rect);
00164 
00165   //! Uninitialized constructor (useful for arrays).
00166   inline Rectangle();
00167 
00168   // Default assignment operator ok
00169 
00170   // ############################################################
00171   // ##### Access functions:
00172   // ############################################################
00173 
00174   //! get overlap between this rectangle and passed in rectangle
00175   inline Rectangle getOverlap(const Rectangle& r2) const;
00176 
00177   //! check if point p is within rectangle
00178   /*! CAUTION: boundaries are included. */
00179   inline bool contains(const Point2D<int>& p) const;
00180 
00181   //! check if this rect contains another
00182   /*! The boundaries are allowed to coincide, such that by this
00183       definition a rectangle "contains" itself. */
00184   inline bool contains(const Rectangle& r) const;
00185 
00186   inline int top() const;     //!< get (inner) top coordinate
00187   inline int bottomI() const; //!< get inner bottom coordinate (=top+height-1)
00188   inline int bottomO() const; //!< get outer bottom coordinate (=top+height)
00189   inline int left() const;    //!< get (inner) left coordinate
00190   inline int rightI() const;  //!< get inner right coordinate (=left+width-1)
00191   inline int rightO() const;  //!< get outer right coordinate (=left+width)
00192 
00193   inline Point2D<int> topLeft() const;     //!< Get (outer) top left corner point
00194   inline Point2D<int> topRight() const;    //!< Get (outer) top right corner point
00195   inline Point2D<int> bottomLeft() const;  //!< Get (outer) bottom left corner point
00196   inline Point2D<int> bottomRight() const; //!< Get (outer) bottom right corner point
00197 
00198   //! Get the rectangle's width, height
00199   inline Dims dims() const;
00200 
00201   //! Access some metric info
00202   inline int width() const;
00203   //! Access some metric info
00204   inline int height() const;
00205   //! Access some metric info
00206   inline int area() const;
00207   //! Access some metric info
00208   inline float aspect() const;
00209 
00210   //!The center of the rectangle
00211   inline Point2D<int> center() const;
00212 
00213   //! whether the rectangle is valid
00214   inline bool isValid() const;
00215 
00216 private:
00217   inline void tlbrInitOuter(int tt, int ll, int bb1, int rr1);
00218 
00219   bool valid;       //!< True if Rectangle contains something coherent
00220   int t, b1, l, r1;   //!< top, bottom, left, right
00221 };
00222 
00223 
00224 // ######################################################################
00225 // Rectangle FREE FUNCTIONS:
00226 // ######################################################################
00227 
00228 // ######################################################################
00229 //! Rectangle overload: format is "<int>,<int>,<int>,<int>"
00230 /*! Format corresponds to "xtopleft,ytopleft,xbottomright,ybottomright" */
00231 std::string convertToString(const Rectangle& val);
00232 
00233 // ######################################################################
00234 //! Rectangle overload: format is "<int>,<int>,<int>,<int>"
00235 void convertFromString(const std::string& str, Rectangle& val);
00236 
00237 
00238 // ######################################################################
00239 //! Return a new rectangle that is a constrained version of the input.
00240 /*! @param in The original rectangle on which to base the constrained
00241     output.
00242 
00243     @param bounds The output rectangle will be constrained to be
00244     contained within these bounds.
00245 
00246     @param minw The minimum width for the output rectangle. Caller
00247     must ensure minw>=0. If the output rectangle would naturally be
00248     narrower than this width, then it will be widened to the smaller
00249     of minw and bounds.width().
00250 
00251     @param maxw The maximum width for the output rectangle. Caller
00252     must ensure maxw>=minw. If the output rectangle would naturally be
00253     wider than this width, then it will be narrowed to the smaller of
00254     maxw and bounds.width().
00255 
00256     @param minh The minimum height for the output rectangle. Caller
00257     must ensure minh>=0. If the output rectangle would naturally be
00258     shorter than this height, then it will be lengthened to the
00259     smaller of minh and bounds.height().
00260 
00261     @param maxh The maximum height for the output rectangle. Caller
00262     must ensure maxh>=minh. If the output rectangle would naturally be
00263     taller than this height, then it will be shortened to the smaller
00264     of maxh and bounds.height().
00265 
00266     @return The result is guaranteed to be such that the following
00267     conditions are all true:
00268     \code
00269     bounds.contains(result);
00270     result.width() >= std::min(minw, bounds.width());
00271     result.width() <= std::min(maxw, bounds.width());
00272     result.height() >= std::min(minh, bounds.height());
00273     result.height() <= std::min(maxh, bounds.height());
00274     \endcode
00275 */
00276 Rectangle constrainRect(const Rectangle& in,
00277                         const Rectangle& bounds,
00278                         int minw, int maxw,
00279                         int minh, int maxh);
00280 
00281 
00282 // ######################################################################
00283 //! Like the main constrainRect(), but use the same limits for width as for height
00284 inline Rectangle constrainRect(const Rectangle& in,
00285                                const Rectangle& bounds,
00286                                int minsz, int maxsz)
00287 {
00288   return constrainRect(in, bounds, minsz, maxsz, minsz, maxsz);
00289 }
00290 
00291 // ######################################################################
00292 inline bool operator==(const Rectangle& r1, const Rectangle& r2)
00293 {
00294   if (!r1.isValid() || !r2.isValid()) return r1.isValid() == r2.isValid();
00295 
00296   return (r1.top() == r2.top() &&
00297           r1.bottomO() == r2.bottomO() &&
00298           r1.left() == r2.left() &&
00299           r1.rightO() == r2.rightO());
00300 }
00301 
00302 // ######################################################################
00303 inline Rectangle operator*(const Rectangle& r, const double s)
00304 {
00305   if (!r.isValid())
00306     return Rectangle();
00307   else
00308     return Rectangle::tlbrO(int(r.top() * s),
00309                             int(r.left() * s),
00310                             int(r.bottomO() * s),
00311                             int(r.rightO() * s));
00312 }
00313 
00314 // ######################################################################
00315 inline Rectangle operator*(const Rectangle& r, const int s)
00316 {
00317   if (!r.isValid())
00318     return Rectangle();
00319   else
00320     return Rectangle::tlbrO(r.top() * s,
00321                             r.left() * s,
00322                             r.bottomO() * s,
00323                             r.rightO() * s);
00324 }
00325 
00326 // ######################################################################
00327 inline Rectangle operator/(const Rectangle& r, const int div)
00328 {
00329   if (!r.isValid() || div == 0)
00330     return Rectangle();
00331   else
00332     return Rectangle::tlbrO(r.top() / div,
00333                             r.left() / div,
00334                             r.bottomO() / div,
00335                             r.rightO() / div);
00336 }
00337 
00338 // ######################################################################
00339 inline Rectangle operator+(const Rectangle& r, const Point2D<int>& p)
00340 {
00341   return Rectangle::tlbrO(r.top() + p.j,
00342                           r.left() + p.i,
00343                           r.bottomO() + p.j,
00344                           r.rightO() + p.i);
00345 }
00346 
00347 // ######################################################################
00348 inline Rectangle& operator+=(Rectangle& r, const Point2D<int>& p)
00349 {
00350   return (r = r + p);
00351 }
00352 
00353 // ######################################################################
00354 inline Rectangle operator-(const Rectangle& r, const Point2D<int>& p)
00355 {
00356   return Rectangle::tlbrO(r.top() - p.j,
00357                           r.left() - p.i,
00358                           r.bottomO() - p.j,
00359                           r.rightO() - p.i);
00360 }
00361 
00362 // ######################################################################
00363 inline Rectangle& operator-=(Rectangle& r, const Point2D<int>& p)
00364 {
00365   return (r = r - p);
00366 }
00367 
00368 // ######################################################################
00369 // Rectangle INLINE MEMBER FUNCTIONS:
00370 // ######################################################################
00371 
00372 // ######################################################################
00373 inline Rectangle::Rectangle(int tt, int ll, int bb1, int rr1)
00374 { tlbrInitOuter(tt, ll, bb1, rr1); }
00375 
00376 // ######################################################################
00377 inline Rectangle Rectangle::tlbrI(int tt, int ll, int bb, int rr)
00378 { return Rectangle(tt, ll, bb+1, rr+1); }
00379 
00380 // ######################################################################
00381 inline Rectangle Rectangle::tlbrO(int tt, int ll, int bb, int rr)
00382 { return Rectangle(tt, ll, bb, rr); }
00383 
00384 // ######################################################################
00385 inline Rectangle::Rectangle(const Point2D<int>& topleft, const Dims& d)
00386   : valid(true),
00387     t(topleft.j), b1(topleft.j+d.h()),
00388     l(topleft.i), r1(topleft.i+d.w())
00389 {}
00390 
00391 // ######################################################################
00392 inline Rectangle::Rectangle(const Rectangle& rect)
00393   : valid(rect.valid), t(rect.t), b1(rect.b1), l(rect.l), r1(rect.r1)
00394 {}
00395 
00396 // ######################################################################
00397 inline Rectangle::Rectangle()
00398   : valid(false), t(-1), b1(-1), l(-1), r1(-1)
00399 {}
00400 
00401 // ######################################################################
00402 inline void Rectangle::tlbrInitOuter(int tt, int ll, int bb1, int rr1)
00403 {
00404   if (bb1 - tt < 0) { t = bb1; b1 = tt; } else { t = tt; b1 = bb1; }
00405   if (rr1 - ll < 0) { l = rr1; r1 = ll; } else { l = ll; r1 = rr1; }
00406   valid = true;
00407 }
00408 
00409 // ######################################################################
00410 inline Rectangle Rectangle::getOverlap(const Rectangle& r2) const
00411 {
00412   if (!this->isValid() || !r2.isValid()) return Rectangle();
00413 
00414   const int le = std::max(l, r2.left());
00415   const int ri = std::min(r1, r2.rightO());
00416   const int to = std::max(t, r2.top());
00417   const int bo = std::min(b1, r2.bottomO());
00418 
00419   if (le >= ri || to >= bo) return Rectangle();
00420   else return Rectangle::tlbrO(to, le, bo, ri);
00421 }
00422 
00423 // ######################################################################
00424 inline int Rectangle::area() const
00425 {
00426   return width() * height();
00427 }
00428 
00429 // ######################################################################
00430 inline float Rectangle::aspect() const
00431 {
00432   return (float)width() / (float)height();
00433 }
00434 
00435 // ######################################################################
00436 inline Point2D<int> Rectangle::center() const
00437 {
00438   return Point2D<int>(l+(r1-l)/2, t+(b1-t)/2);
00439   //int t, b1, l, r1;   //!< top, bottom, left, right
00440 }
00441 
00442 // ######################################################################
00443 inline bool Rectangle::contains(const Point2D<int>& p) const
00444 {
00445   return (p.i >= l && p.i < r1 && p.j >= t && p.j < b1);
00446 }
00447 
00448 // ######################################################################
00449 inline bool Rectangle::contains(const Rectangle& r) const
00450 {
00451   return (   r.l >= this->l
00452           && r.t >= this->t
00453           && r.r1 <= this->r1
00454           && r.b1 <= this->b1);
00455 }
00456 
00457 // ######################################################################
00458 inline int Rectangle::top() const
00459 { ASSERT(valid); return t; }
00460 
00461 inline int Rectangle::bottomI() const
00462 { ASSERT(valid); return b1-1; }
00463 
00464 inline int Rectangle::bottomO() const
00465 { ASSERT(valid); return b1; }
00466 
00467 inline int Rectangle::left() const
00468 { ASSERT(valid); return l; }
00469 
00470 inline int Rectangle::rightI() const
00471 { ASSERT(valid); return r1-1; }
00472 
00473 inline int Rectangle::rightO() const
00474 { ASSERT(valid); return r1; }
00475 
00476 inline Point2D<int> Rectangle::topLeft() const
00477 { ASSERT(valid); return Point2D<int>(l, t); }
00478 
00479 inline Point2D<int> Rectangle::topRight() const
00480 { ASSERT(valid); return Point2D<int>(r1, t); }
00481 
00482 inline Point2D<int> Rectangle::bottomLeft() const
00483 { ASSERT(valid); return Point2D<int>(l, b1); }
00484 
00485 inline Point2D<int> Rectangle::bottomRight() const
00486 { ASSERT(valid); return Point2D<int>(r1, b1); }
00487 
00488 inline Dims Rectangle::dims() const
00489 {
00490   ASSERT(valid);
00491   return Dims(r1 - l, b1 - t); // *** CAUTION: BOUNDARIES ARE INCLUDED
00492 }
00493 
00494 inline int Rectangle::width() const
00495 { ASSERT(valid); return r1 - l; } // *** CAUTION: BOUNDARIES ARE INCLUDED
00496 
00497 inline int Rectangle::height() const
00498 { ASSERT(valid); return b1 - t; } // *** CAUTION: BOUNDARIES ARE INCLUDED
00499 
00500 inline bool Rectangle::isValid() const
00501 { return valid; }
00502 
00503 #endif
00504 
00505 // ######################################################################
00506 /* So things look consistent in everyone's emacs... */
00507 /* Local Variables: */
00508 /* indent-tabs-mode: nil */
00509 /* End: */

Generated on Mon Nov 23 15:46:23 2009 for iLab Neuromorphic Vision Toolkit by  doxygen 1.4.4