00001 /*---------------------------------------------------------------------* 00002 | Library QgarLib, graphics analysis and recognition | 00003 | Copyright (C) 2004 Qgar Project, LORIA | 00004 | | 00005 | This library is free software; you can redistribute it and/or | 00006 | modify it under the terms of the GNU Lesser General Public | 00007 | License version 2.1, as published by the Free Software Foundation. | 00008 | | 00009 | This library is distributed in the hope that it will be useful, | 00010 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 00011 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 00012 | See the GNU Lesser General Public License for more details. | 00013 | | 00014 | The GNU Lesser General Public License is included in the file | 00015 | LICENSE.LGPL, in the root directory of the Qgar packaging. See | 00016 | http://www.gnu.org/licenses/lgpl.html for the terms of the license. | 00017 | To receive a paper copy, write to the Free Software Foundation, | 00018 | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. | 00019 | | 00020 | Contact Project Qgar for any information: | 00021 | LORIA - équipe Qgar | 00022 | B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France | 00023 | email: qgar-contact@loria.fr | 00024 | http://www.qgar.org/ | 00025 *---------------------------------------------------------------------*/ 00026 00027 00028 #ifndef __BOUNDINGBOX_H_INCLUDED__ 00029 #define __BOUNDINGBOX_H_INCLUDED__ 00030 00031 00032 /** 00033 * @file BoundingBox.H 00034 * @brief Header file of class qgar::BoundingBox. 00035 * 00036 * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Jan Rendek">Jan Rendek</a> 00037 * @date February 23, 2004 16:08 00038 * @since Qgar 2.1.1 00039 */ 00040 00041 00042 // For RCS/CVS use: Do not delete 00043 /* $Id: BoundingBox.H,v 1.21 2005/10/14 17:05:45 masini Exp $ */ 00044 00045 00046 // STL 00047 #include <iosfwd> // Avoid including classes when not necessary 00048 // QGAR 00049 #include <qgarlib/ISerializable.H> 00050 #include <qgarlib/primitives.H> 00051 #include <qgarlib/QgarErrorDomain.H> 00052 00053 00054 00055 namespace qgar 00056 { 00057 00058 00059 /** 00060 * @class BoundingBox BoundingBox.H "qgarlib/BoundingBox.H" 00061 * @ingroup DS_MISC 00062 * @brief A bounding box. 00063 * 00064 * A bounding box is a rectangle with sides parallel 00065 * to the coordinate system axis. It is represented 00066 * by its top left and bottom right corners. 00067 * 00068 @verbatim 00069 0 00070 +---------------------------------------> X 00071 | 00072 | <---- length ----> 00073 | top left o----------------+ ^ 00074 | | | | 00075 | | Bounding Box |height 00076 | | | | 00077 | +----------------o v 00078 V bottom right 00079 00080 Y 00081 @endverbatim 00082 * @warning 00083 * <ul> 00084 * <li>A bounding box is supposed to be used 00085 * within an <b>integer</b> coordinate system only.</li> 00086 * <li><b>As the origin of the coordinates system in images 00087 * is at the top left corner of the plane, the top left and bottom 00088 * right corners of the box are topographically upside down for 00089 * more convenience.</b></li> 00090 * <li>The borders of a bounding box are part of the bounding box. 00091 * In particular, the corresponding pixels are taken into account 00092 * to compute the geometrical characteristics of the box: 00093 * width, height, area...</li> 00094 * </ul> 00095 * 00096 * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Jan Rendek">Jan Rendek</a> 00097 * @date February 23, 2004 16:08 00098 * @since Qgar 2.1.1 00099 */ 00100 class BoundingBox 00101 00102 : public ISerializable 00103 00104 { 00105 // ------------------------------------------------------------------- 00106 // P U B L I C M E M B E R S 00107 // ------------------------------------------------------------------- 00108 public: 00109 00110 00111 /** @name Constructors */ 00112 // ============ 00113 //@{ 00114 00115 /** 00116 * @brief Default constructor. 00117 * 00118 * One-unit-length and one-unit-width bounding box located 00119 * at the origin of the coordinate system. 00120 */ 00121 BoundingBox(); 00122 00123 /** 00124 * @brief Copy constructor. 00125 * 00126 * @param aBox a bounding box 00127 */ 00128 BoundingBox(const BoundingBox& aBox); 00129 00130 /** 00131 * @brief Initialize from two points. 00132 * 00133 * The two given points, <b>aPt1</b> and <b>aPt2</b>, are supposed 00134 * to be two opposite corners (top left and bottom right, or top right 00135 * and bottom left) of the resulting bounding box. The corresponding 00136 * coordinates of top left and bottom right corners are automatically 00137 * computed. 00138 * 00139 * @param aPt1 a point 00140 * @param aPt2 a point 00141 */ 00142 BoundingBox(const GenPoint<int>& aPt1, const GenPoint<int>& aPt2); 00143 00144 /** 00145 * @brief Initialize from coordinates of two points. 00146 * 00147 * The two given points are supposed to be two opposite corners (top 00148 * left and bottom right, or top right and bottom left) of the 00149 * resulting bounding box. The corresponding coordinates of top left 00150 * and bottom right corners are automatically computed. 00151 * 00152 * @param aX1 X coordinate of first point 00153 * @param aY1 Y coordinate of first point 00154 * @param aX2 X coordinate of second point 00155 * @param aY2 Y coordinate of second point 00156 */ 00157 BoundingBox(int aX1, int aY1, int aX2, int aY2); 00158 00159 /** 00160 * @brief Initialize from top left corner, length and height. 00161 * 00162 * The length and the height must be greater than 0. 00163 * 00164 * @param aTopLeft top left corner of the resulting bounding box 00165 * @param aLength length of the resulting bounding box 00166 * @param aHeight height of the resulting bounding box 00167 * 00168 * @exception 00169 * qgar::QgarErrorDomain if the length or the height is not valid. 00170 */ 00171 BoundingBox(const GenPoint<int>& aTopLeft, int aLength, int aHeight) 00172 throw(QgarErrorDomain); 00173 00174 /** 00175 * @brief Initialize from bottom right corner, length and height. 00176 * 00177 * The length and the height must be greater than 0. 00178 * 00179 * @param aLength length of the resulting bounding box 00180 * @param aHeight height of the resulting bounding box 00181 * @param aBottomRight bottom right corner of the resulting bounding box 00182 * 00183 * @exception 00184 * qgar::QgarErrorDomain if the length or the height is not valid. 00185 */ 00186 BoundingBox(int aLength, int aHeight, const GenPoint<int>& aBottomRight) 00187 throw(QgarErrorDomain); 00188 00189 //@} 00190 00191 00192 /** @name Destructor */ 00193 // ========== 00194 //@{ 00195 00196 /** 00197 * @brief Non-virtual destructor. 00198 */ 00199 ~BoundingBox(); 00200 00201 //@} 00202 00203 00204 /** @name Access to corners */ 00205 // ================= 00206 //@{ 00207 00208 /** 00209 * @brief Get top left corner. 00210 */ 00211 inline const GenPoint<int>& accessTopLeft() const; 00212 00213 /** 00214 * @brief Get a copy of the top left corner. 00215 */ 00216 GenPoint<int> topLeft() const; 00217 00218 /** 00219 * @brief Get bottom right corner. 00220 */ 00221 inline const GenPoint<int>& accessBottomRight() const; 00222 00223 /** 00224 * @brief Get a copy of the bottom right corner. 00225 */ 00226 inline GenPoint<int> bottomRight() const; 00227 00228 //@} 00229 00230 00231 /** @name Access to coordinates */ 00232 // ===================== 00233 //@{ 00234 00235 /** 00236 * @brief Get X coordinate of top left corner. 00237 */ 00238 inline int xTopLeft() const; 00239 00240 /** 00241 * @brief Get Y coordinate of top left corner. 00242 */ 00243 inline int yTopLeft() const; 00244 00245 /** 00246 * @brief Get X coordinate of bottom right corner. 00247 */ 00248 inline int xBottomRight() const; 00249 00250 /** 00251 * @brief Get Y coordinate of bottom right corner. 00252 */ 00253 inline int yBottomRight() const; 00254 00255 //@} 00256 00257 00258 /** @name Access to dimensions */ 00259 // ==================== 00260 //@{ 00261 00262 /** 00263 * @brief Same as qgar::BoundingBox::width. 00264 */ 00265 inline int length() const; 00266 00267 /** 00268 * @brief Get width. 00269 * 00270 * @warning As the pixels of the borders belong to the box, 00271 * the width is 00272 * \f$ X_{bottom-right-corner} - X_{top-left-corner} + 1 \f$ 00273 */ 00274 inline int width() const; 00275 00276 /** 00277 * @brief Get height. 00278 * 00279 * @warning As the pixels of the borders belong to the box, 00280 * the width is 00281 * \f$ Y_{bottom-right-corner} - Y_{top-left-corner} + 1 \f$ 00282 */ 00283 inline int height() const; 00284 00285 /** 00286 * @brief Get area. 00287 * 00288 * @warning The pixels of the borders belong to the box, 00289 * and thus are counted in the area. 00290 */ 00291 inline int area() const; 00292 00293 //@} 00294 00295 00296 /** @name Geometrical predicates */ 00297 // ====================== 00298 //@{ 00299 00300 /** 00301 * @brief Return <b>true</b> if the given point belongs to 00302 * the current bounding box, including borders. 00303 * 00304 * @param aPt a point with <b>integer</b> coordinates 00305 */ 00306 inline bool contains(const GenPoint<int>& aPt) const; 00307 00308 /** 00309 * @brief Return <b>true</b> if the point defined 00310 * by the given coordinates belongs to the current 00311 * bounding box, including borders. 00312 * 00313 * @param aX an <b>integer</b> X coordinate 00314 * @param aY an <b>integer</b> Y coordinate 00315 */ 00316 bool contains(int aX, int aY) const; 00317 00318 /** 00319 * @brief Return <b>true</b> if the current bounding box 00320 * contains the given bounding box. 00321 * 00322 * @param aBox a bounding box 00323 */ 00324 inline bool contains(const BoundingBox& aBox) const; 00325 00326 /** 00327 * @brief Return <b>true</b> if the current bounding box 00328 * intersects the given bounding box. 00329 * 00330 * @param aBox a bounding box 00331 */ 00332 bool intersects(const BoundingBox& aBox) const; 00333 00334 //@} 00335 00336 00337 /** @name Geometrical operations */ 00338 // ====================== 00339 //@{ 00340 00341 /** 00342 * @brief Intersection 00343 * between the current and given bounding boxes. 00344 * 00345 * If the two bounding boxes intersect, returns a pointer 00346 * to the bounding box representing the intersection. 00347 * <b>If the two bounding boxes do not intersect, returns 00348 * a null pointer.</b> 00349 * 00350 * @param aBox a bounding box 00351 */ 00352 BoundingBox* intersection(const BoundingBox& aBox) const; 00353 00354 //@} 00355 00356 00357 /** @name Set corners */ 00358 // =========== 00359 //@{ 00360 00361 /** 00362 * @brief Set top left corner using a point. 00363 * 00364 * @param aPt a point 00365 * 00366 * @warning If the new corner (point <b>aPt</b>) does not match 00367 * the current bottom right corner, the function raises an exception. 00368 * 00369 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00370 */ 00371 void setTopLeft(const GenPoint<int>& aPt) throw(QgarErrorDomain); 00372 00373 /** 00374 * @brief Set top left corner using X and Y coordinates. 00375 * 00376 * @param aX X coordinate 00377 * @param aY Y coordinate 00378 * 00379 * @warning If the new corner does not match the current bottom 00380 * right corner, the function raises an exception. 00381 * 00382 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00383 */ 00384 void setTopLeft(int aX, int aY) throw(QgarErrorDomain); 00385 00386 /** 00387 * @brief Set X coordinate of top left corner. 00388 * 00389 * @param aX X coordinate 00390 * 00391 * @warning If the new corner does not match the current bottom 00392 * right corner, the function raises an exception. 00393 * 00394 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00395 */ 00396 void setXTopLeft(int aX) throw(QgarErrorDomain); 00397 00398 /** 00399 * @brief Set Y coordinate of top left corner. 00400 * 00401 * @param aY Y coordinate 00402 * 00403 * @warning If the new corner does not match the current top left 00404 * corner, the function raises an exception. 00405 * 00406 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00407 */ 00408 void setYTopLeft(int aY) throw(QgarErrorDomain); 00409 00410 /** 00411 * @brief Set bottom right corner using a point. 00412 * 00413 * @param aPt a point 00414 * 00415 * @warning If the new corner (point <b>aPt</b>) does not match 00416 * the current top left corner, the function raises an exception. 00417 * 00418 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00419 */ 00420 void setBottomRight(const GenPoint<int>& aPt) throw(QgarErrorDomain); 00421 00422 /** 00423 * @brief Set bottom right corner using X and Y coordinates. 00424 * 00425 * @param aX X coordinate 00426 * @param aY Y coordinate 00427 * 00428 * @warning If the new corner does not match the current top left 00429 * corner, the function raises an exception. 00430 * 00431 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00432 */ 00433 void setBottomRight(int aX, int aY) throw(QgarErrorDomain); 00434 00435 /** 00436 * @brief Set X coordinate of bottom right corner. 00437 * 00438 * @param aX X coordinate 00439 * 00440 * @warning If the new corner does not match the top left corner, 00441 * the function raises an exception. 00442 * 00443 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00444 */ 00445 void setXBottomRight(int aX) throw(QgarErrorDomain); 00446 00447 /** 00448 * @brief Set Y coordinate of bottom right corner. 00449 * 00450 * @param aY Y coordinate 00451 * 00452 * @warning If the new corner does not match the current top left 00453 * corner, the function raises an exception. 00454 * 00455 * @exception qgar::QgarErrorDomain (new corner does not fit box) 00456 */ 00457 void setYBottomRight(int aY) throw(QgarErrorDomain); 00458 00459 /** 00460 * @brief Set both top left and bottom right corners from two points. 00461 * 00462 * The two given points, <b>aPt1</b> and <b>aPt2</b>, are supposed 00463 * to be two opposite corners (top left and bottom right, or top 00464 * right and bottom left) of the resulting bounding box. 00465 * The corresponding coordinates of top left and bottom right 00466 * corners are automatically computed. 00467 * 00468 * @param aPt1 a point 00469 * @param aPt2 a point 00470 */ 00471 void setCorners(const GenPoint<int>& aPt1, const GenPoint<int>& aPt2); 00472 00473 /** 00474 * @brief Set both top left and bottom right corners 00475 * from coordinates of two points. 00476 * 00477 * The two given points are supposed to be two opposite corners 00478 * (top left and bottom right, or top right and bottom left) 00479 * of the resulting bounding box. The corresponding coordinates 00480 * of top left and bottom right corners are automatically computed. 00481 * 00482 * @param aX1 X coordinate of first corner 00483 * @param aY1 Y coordinate of first corner 00484 * @param aX2 X coordinate of second corner 00485 * @param aY2 Y coordinate of second corner 00486 */ 00487 void setCorners(int aX1, int aY1, int aX2, int aY2); 00488 00489 //@} 00490 00491 00492 /** @name Operators */ 00493 // ========= 00494 //@{ 00495 00496 /** 00497 * @brief Assign the given bounding box to the current bounding box. 00498 * 00499 * @param aBox a bounding box 00500 */ 00501 BoundingBox& operator=(const BoundingBox& aBox); 00502 00503 /** 00504 * @brief Same as function qgar::BoundingBox::eq. 00505 * 00506 * @param aBox a bounding box 00507 */ 00508 inline bool operator==(const BoundingBox& aBox) const; 00509 00510 /** 00511 * @brief Same as function qgar::BoundingBox::NotEq. 00512 * 00513 * @param aBox a bounding box 00514 */ 00515 inline bool operator!=(const BoundingBox& aBox) const; 00516 00517 //@} 00518 00519 00520 /**@name Functional operators */ 00521 // ==================== 00522 //@{ 00523 00524 /** 00525 * @brief Equality. 00526 * 00527 * Return <b>true</b> if the current bounding box 00528 * and the given bounding box have the same coordinates. 00529 * 00530 * @param aBox a bounding box 00531 */ 00532 bool eq(const BoundingBox& aBox) const; 00533 00534 /** 00535 * @brief Inequality. 00536 * 00537 * Return <b>true</b> if the current bounding box 00538 * and the given bounding box have different coordinates. 00539 * 00540 * @param aBox a bounding box 00541 */ 00542 bool notEq(const BoundingBox& aBox) const; 00543 00544 //@} 00545 00546 00547 /** @name Serialization/deserialization */ 00548 // ============================= 00549 //@{ 00550 00551 /** 00552 * @brief Deserializes the current box from an input stream. 00553 * 00554 * A serialized bounding box is represented as: 00555 @verbatim 00556 BoundingBox(<TOP LEFT CORNER>)(<BOTTOM RIGHT CORNER>) 00557 @endverbatim 00558 * 00559 * @param anInStream the input stream 00560 */ 00561 virtual std::istream& read(std::istream& anInStream); 00562 00563 /** 00564 * @brief Serializes the current box to an input stream. 00565 * 00566 * A serialized bounding boxi is represented as: 00567 @verbatim 00568 BoundingBox(<TOP LEFT CORNER>)(<BOTTOM RIGHT CORNER>) 00569 @endverbatim 00570 * 00571 * @param anOutStream the output stream 00572 */ 00573 virtual std::ostream& write(std::ostream& anOutStream) const; 00574 00575 //@} 00576 00577 00578 // ------------------------------------------------------------------- 00579 // P R O T E C T E D M E M B E R S 00580 // ------------------------------------------------------------------- 00581 protected: 00582 00583 00584 /** @name Representation of a bounding box */ 00585 // ================================ 00586 //@{ 00587 00588 /** 00589 * @brief Top left corner. 00590 */ 00591 GenPoint<int> _topLeft; 00592 00593 /** 00594 * @brief Bottom right corner. 00595 */ 00596 GenPoint<int> _bottomRight; 00597 00598 //@} 00599 00600 // ------------------------------------------------------------------- 00601 00602 }; // class BoundingBox 00603 00604 00605 00606 00607 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 00608 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 00609 // I N L I N E F U N C T I O N S I M P L E M E N T A T I O N 00610 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 00611 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 00612 00613 00614 // ================= 00615 // ACCESS TO CORNERS 00616 // ================= 00617 00618 00619 // GET TOP LEFT CORNER 00620 00621 inline const GenPoint<int>& 00622 BoundingBox::accessTopLeft() const 00623 { 00624 return _topLeft; 00625 } 00626 00627 00628 // GET A COPY OF THE TOP LEFT CORNER 00629 00630 inline GenPoint<int> 00631 BoundingBox::topLeft() const 00632 { 00633 return _topLeft; 00634 } 00635 00636 00637 // GET BOTTOM RIGHT CORNER 00638 00639 inline const GenPoint<int>& 00640 BoundingBox::accessBottomRight() const 00641 { 00642 return _bottomRight; 00643 } 00644 00645 00646 // GET A COPY OF THE BOTTOM RIGHT CORNER 00647 00648 inline GenPoint<int> 00649 BoundingBox::bottomRight() const 00650 { 00651 return _bottomRight; 00652 } 00653 00654 00655 // ===================== 00656 // ACCESS TO COORDINATES 00657 // ===================== 00658 00659 00660 // GET X COORDINATE OF TOP LEFT CORNER 00661 00662 inline int 00663 BoundingBox::xTopLeft() const 00664 { 00665 return _topLeft.x(); 00666 } 00667 00668 00669 // GET Y COORDINATE OF TOP LEFT CORNER 00670 00671 inline int 00672 BoundingBox::yTopLeft() const 00673 { 00674 return _topLeft.y(); 00675 } 00676 00677 00678 // GET X COORDINATE OF BOTTOM RIGHT CORNER 00679 00680 inline int 00681 BoundingBox::xBottomRight() const 00682 { 00683 return _bottomRight.x(); 00684 } 00685 00686 00687 // GET Y COORDINATE OF BOTTOM RIGHT CORNER 00688 00689 inline int 00690 BoundingBox::yBottomRight() const 00691 { 00692 return _bottomRight.y(); 00693 } 00694 00695 00696 // ==================== 00697 // ACCESS TO DIMENSIONS 00698 // ==================== 00699 00700 00701 // SAME AS qgar::BoundingBox::width 00702 00703 inline int 00704 BoundingBox::length() const 00705 { 00706 return width(); 00707 } 00708 00709 00710 // GET WIDTH 00711 00712 inline int 00713 BoundingBox::width() const 00714 { 00715 return _bottomRight.x() - _topLeft.x() + 1; 00716 } 00717 00718 00719 // GET HEIGHT 00720 00721 inline int 00722 BoundingBox::height() const 00723 { 00724 return _bottomRight.y() - _topLeft.y() + 1; 00725 } 00726 00727 00728 // GET AREA 00729 00730 inline int 00731 BoundingBox::area() const 00732 { 00733 return length() * height(); 00734 } 00735 00736 00737 // =========================================== 00738 // G E O M E T R I C A L P R E D I C A T E S 00739 // =========================================== 00740 00741 00742 // DOES THE GIVEN POINT BELONG TO THE CURRENT BOUNDING BOX? 00743 00744 inline bool 00745 BoundingBox::contains(const GenPoint<int>& aPt) const 00746 { 00747 return this->contains(aPt.x(), aPt.y()); 00748 } 00749 00750 00751 // DOES THE CURRENT BOUNDING BOX CONTAIN THE GIVEN BOUNDING BOX? 00752 00753 inline bool 00754 BoundingBox::contains(const BoundingBox& aBox) const 00755 { 00756 return (this->contains(aBox.topLeft())) 00757 && (this->contains(aBox.bottomRight())); 00758 } 00759 00760 00761 // ========= 00762 // OPERATORS 00763 // ========= 00764 00765 00766 // EQUALITY 00767 00768 inline bool 00769 BoundingBox::operator==(const BoundingBox& aBox) const 00770 { 00771 return eq(aBox); 00772 } 00773 00774 00775 // INEQUALITY 00776 00777 inline bool 00778 BoundingBox::operator!=(const BoundingBox& aBox) const 00779 { 00780 return notEq(aBox); 00781 } 00782 00783 00784 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 00785 // IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII 00786 00787 00788 } // namespace qgar 00789 00790 00791 #endif /* __BOUNDINGBOX_H_INCLUDED__ */