rect.h

Go to the documentation of this file.
00001 /**
00002  * \file rect.h <mi32/rect.h>
00003  * \brief Definitions for 2D and 3D rectangle structures
00004  *
00005  * \if NODOC
00006  * $Id: rect.h_v 1.45 2004/11/16 16:53:28 dwilliss Exp $
00007  *
00008  * $Log: rect.h_v $
00009  * Revision 1.45  2004/11/16 16:53:28  dwilliss
00010  * Added a GetRectTruncate to DRECT2D
00011  *
00012  * Revision 1.44  2004/10/14 21:58:11  scowan
00013  * Added ctor's for 2d and 3d rect using two points.
00014  *
00015  * Revision 1.43  2004/03/02 00:24:17  scowan
00016  * Made non-inline functions inline to calls to exported functions.
00017  *
00018  * Revision 1.42  2003/11/28 16:45:16  scowan
00019  * Added is equiv to method.
00020  *
00021  * Revision 1.41  2003/11/12 13:20:00  mju
00022  * Add drect3d.getMinimum/Maximum.
00023  *
00024  * Revision 1.40  2003/09/15 13:49:56  fileserver!dwilliss
00025  * Doxygen
00026  *
00027  * Revision 1.39  2003/04/15 13:34:06  mju
00028  * Add IniRead/Write methods.
00029  *
00030  * Revision 1.38  2003/02/21 15:19:44  mju
00031  * Add SwapBytes method.
00032  *
00033  * Revision 1.37  2003/02/04 20:24:31  vdronov
00034  * ctor for DRECTXD from FPOINTXD
00035  *
00036  * Revision 1.36  2002/12/04 16:27:47  dwilliss
00037  * Fixed a compiler warning
00038  *
00039  * Revision 1.35  2002/08/19 17:56:04  mju
00040  * Change GetArea() to do getwidth*getheight.
00041  *
00042  * Revision 1.34  2002/08/19 17:35:37  mju
00043  * In LRECT2D ctor init to 'empty' rectangle.
00044  *
00045  * Revision 1.33  2002/08/13 14:23:01  scowan
00046  * Added more distance methods.
00047  *
00048  * Revision 1.32  2002/07/02 20:17:04  scowan
00049  * Added get corners for 3d point array.
00050  *
00051  * Revision 1.31  2002/06/13 21:50:24  scowan
00052  * Added compute edge method.
00053  *
00054  * Revision 1.30  2002/01/22 18:52:36  scowan
00055  * Nothing.
00056  *
00057  * Revision 1.29  2001/12/11 17:44:34  scowan
00058  * Added swap bytes functions for rects.
00059  *
00060  * Revision 1.28  2001/09/26 17:26:09  scowan
00061  * Fixed equality operator.
00062  *
00063  * Revision 1.26  2001/02/07 23:01:20  scowan
00064  * Added 3D extend method.
00065  *
00066  * Revision 1.25  2001/01/17 14:45:37  mju
00067  * Add LRECT2D:Extend(x,y).
00068  *
00069  * Revision 1.24  2000/12/20 21:44:42  mju
00070  * Add Limit() method.
00071  *
00072  * Revision 1.23  2000/11/28 15:26:41  scowan
00073  * Added more methods.
00074  *
00075  * Revision 1.22  2000/11/07 15:58:47  scowan
00076  * Added casting that I believe Dave finds so unnecessary.
00077  *
00078  * Revision 1.21  2000/11/06 15:28:16  asavant
00079  * equality/inequality operators should return bool
00080  *
00081  * Revision 1.20  2000/11/03 21:15:13  mju
00082  * Add equality/inequality operators.
00083  *
00084  * Revision 1.19  2000/09/20 22:28:52  dwilliss
00085  * Added a few methods
00086  *
00087  * Revision 1.18  2000/08/02 14:22:02  dwilliss
00088  * LRECT2D didn't have a SetInvalid() method.
00089  *
00090  * Revision 1.17  2000/07/11 19:37:00  sparsons
00091  * Genitor documentation.
00092  *
00093  * Revision 1.16  2000/03/07 20:43:43  scowan
00094  * *** empty log message ***
00095  *
00096  * Revision 1.15  2000/01/26 15:51:44  mju
00097  * Don't use STL as MSVC won't inline it.
00098  *
00099  * Revision 1.14  2000/01/07 20:54:49  mju
00100  * Fix DRECT2D::GetTopRight.
00101  *
00102  * Revision 1.13  1999/12/23 00:58:23  scowan
00103  * Yet more methods.
00104  *
00105  * Revision 1.12  1999/12/22 16:52:23  mju
00106  * Add SetInvalid() for DRECT2D/3D.
00107  *
00108  * Revision 1.11  1999/12/15 17:19:53  mju
00109  * Add options for GetCorners and make non-inline.
00110  *
00111  * Revision 1.10  1999/12/15 16:41:06  mju
00112  * Restore DRECT3D::GetCenter which returns DPOINT3D.
00113  *
00114  * Revision 1.9  1999/12/15 15:55:44  mju
00115  * All reference for all "Get" methods that return non-scalar.
00116  * Eliminate return-by-value for all Get methods except GetCenter.
00117  * Add GetCorners() for RECT2D types.
00118  *
00119  * Revision 1.8  1999/12/02 23:23:43  mju
00120  * Add ClipTo method.
00121  *
00122  * Revision 1.7  1999/10/05 21:57:59  dwilliss
00123  * Seems to me like LRECT2D should have same methods as DRECT2D, no?
00124  *
00125  * Revision 1.6  1999/09/07 13:51:40  mju
00126  * Add constructors and methods for LRECT2D.
00127  *
00128  * Revision 1.5  1999/05/19  13:51:54  mju
00129  * Add Expand method with different X/Y values.
00130  * Add DRECT2D construction/assignment from LRECT2D.
00131  *
00132  * Revision 1.4  1999/05/12  16:50:02  mju
00133  * Add DRECT3D ctor that takes DRECT2D and z min/max values.
00134  *
00135  * Revision 1.3  1999/05/07  21:21:05  mju
00136  * Header restruct.
00137  *
00138  * Revision 1.1  1999/05/05  17:30:09  mju
00139  * Initial revision
00140  * \endif
00141 **/
00142 
00143 #ifndef  INC_MI32_RECT_H
00144 #define  INC_MI32_RECT_H
00145 
00146 //!*****************************************************************************
00147 //!      The structures defined here must not change in size as they are stored
00148 //!      in many existing data files, as well as passed to DLLs.  The members
00149 //!      must remain public and their names may not be changed for any reason.
00150 //!*****************************************************************************
00151 
00152 #ifndef  INC_MI32_STDDEFNS_H
00153 #include <mi32/stddefns.h>
00154 #endif
00155 
00156 #ifndef  INC_MI32_INIDEFNS_H
00157 #include <mi32/inidefns.h>
00158 #endif
00159 
00160 #ifdef ALLOW_NAMESPACES
00161    #include <limits>
00162    #include <cmath>
00163 #else
00164    #include <limits.h>
00165    #include <math.h>
00166    #include <float.h>
00167 #endif
00168 
00169 #ifndef  INC_MI32_POINT_H
00170 #include <mi32/point.h>
00171 #endif
00172 
00173 #ifndef GENERATING_DOXYGEN_OUTPUT
00174 
00175 #ifdef GEOMDLL
00176    #define GEOMLIBEXPORT MI_DLLEXPORT
00177    #define GEOMLIBCLASSEXPORT MI_DLLCLASSEXPORT
00178 #else
00179    #define GEOMLIBEXPORT MI_DLLIMPORT
00180    #define GEOMLIBCLASSEXPORT MI_DLLCLASSIMPORT
00181 #endif
00182 
00183 GEOMLIBEXPORT void LRect2DGetCorners (const LRECT2D& rect, LPOINT2D *pts, bool ClosePoly, bool OrientCCW);
00184 GEOMLIBEXPORT bool DRect2DComputeEdgePoint (const DRECT2D& rect, const DPOINT2D& OutsidePt, DPOINT2D& EdgePt);
00185 GEOMLIBEXPORT void DRect2DGetCorners (const DRECT2D& rect, DPOINT2D *pts, bool ClosePoly, bool OrientCCW);
00186 GEOMLIBEXPORT void DRect2DGetCorners (const DRECT2D& rect, DPOINT3D *pts, bool ClosePoly, bool OrientCCW);
00187 GEOMLIBEXPORT double DRect2DGetDistance (const DRECT2D& trect, const DRECT2D& rect);
00188 GEOMLIBEXPORT double DRect2DGetMaxDistance (const DRECT2D& trect, const DRECT2D& rect);
00189 GEOMLIBEXPORT double DRect2DGetMaxDistanceSquared (const DRECT2D& trect, const DRECT2D& rect);
00190 GEOMLIBEXPORT bool DRect2DIsEquivalentTo (const DRECT2D& trect, const DRECT2D& rect, double thresold);
00191 
00192 #endif      //GENERATING_DOXYGEN_OUTPUT
00193 
00194 //-------------------------------------------------------------------------------------------------------------------
00195 
00196 //! 2D rectangle using 16-bit integer coordinates.
00197 struct WRECT2D {
00198    INT16 xinit;                     //!< Minimum X coordinate (inclusive)
00199    INT16 yinit;                     //!< Minimum Y coordinate (inclusive)
00200    INT16 xlast;                     //!< Maximum X coordinate (inclusive)
00201    INT16 ylast;                     //!< Maximum Y coordinate (inclusive)
00202 
00203    //! Make compiler validate structure size.
00204    CHECKSIZE(8);                       
00205    };
00206 
00207 //-------------------------------------------------------------------------------------------------------------------
00208 
00209 //! 2D rectangle using 32-bit integer coordinates.
00210 struct LRECT2D {
00211 
00212    INT32 xinit;                     //!< Minimum X coordinate (inclusive)
00213    INT32 yinit;                     //!< Minimum Y coordinate (inclusive)
00214    INT32 xlast;                     //!< Maximum X coordinate (inclusive)
00215    INT32 ylast;                     //!< Maximum Y coordinate (inclusive)
00216 
00217    //! Default constructor, initializes to invalid (empty) rectangle.
00218    LRECT2D (                           
00219       ): xinit(INT32_MAX), yinit(INT32_MAX), xlast(INT32_MIN), ylast(INT32_MIN) { }
00220 
00221    //! Construct rectangle of specified size.
00222    LRECT2D (                           
00223       INT32 xsize,
00224       INT32 ysize
00225       ) : xinit(0), yinit(0), xlast(xsize-1), ylast(ysize-1) { }
00226 
00227    //! Construction from X/Y ranges.
00228    LRECT2D (                           
00229       INT32 xi,
00230       INT32 yi,
00231       INT32 xl,
00232       INT32 yl
00233       ) : xinit(xi), yinit(yi), xlast(xl), ylast(yl) { }
00234 
00235    //! Check if contains specified point.
00236    bool Contains (                     
00237       INT32 x,
00238       INT32 y
00239       ) const { return (x >= xinit && x <= xlast && y >= yinit && y <= ylast); }
00240 
00241    //! Check if contains specified point.
00242    bool Contains (                     
00243       const LPOINT2D& pt
00244       ) const { return (pt.x >= xinit && pt.x <= xlast && pt.y >= yinit && pt.y <= ylast); }
00245 
00246    //! Check if contains specified rectangle.
00247    bool Contains (                     
00248       const LRECT2D& rhs
00249       ) const { return (rhs.xinit >= xinit && rhs.xlast <= xlast && rhs.yinit >= yinit && rhs.ylast <= ylast); }
00250 
00251    //! Expand the rectangle by 'value' amount.
00252    void Expand (                       
00253       const INT32 value
00254       ) { xinit -= value; yinit -= value; xlast += value; ylast += value; }
00255    
00256    //! Expand the rectangle by 'value' amount.
00257    void Expand (                       
00258       const INT32 xval,
00259       const INT32 yval
00260       ) { xinit -= xval; yinit -= yval; xlast += xval; ylast += yval; }
00261 
00262    //! Extend rectangle to encompass both rectangles.
00263    void Extend (                       
00264       const LRECT2D& rect
00265       ) {
00266       if (rect.xinit < xinit) xinit = rect.xinit;
00267       if (rect.yinit < yinit) yinit = rect.yinit;
00268       if (rect.xlast > xlast) xlast = rect.xlast;
00269       if (rect.ylast > ylast) ylast = rect.ylast;
00270       }
00271 
00272    //! Extend rectangle to include specified LPOINT2D point.
00273    void Extend (
00274       const LPOINT2D& pt
00275       ) {
00276       if (pt.x < xinit) xinit = pt.x;
00277       if (pt.x > xlast) xlast = pt.x;
00278       if (pt.y < yinit) yinit = pt.y;
00279       if (pt.y > ylast) ylast = pt.y;
00280       }
00281 
00282    //! Extend rectangle to include specified X,Y point.
00283    void Extend (
00284       const INT32 xval,
00285       const INT32 yval
00286       ) {
00287       if (xval < xinit) xinit = xval;
00288       if (yval < yinit) yinit = yval;
00289       if (xval > xlast) xlast = xval;
00290       if (yval > ylast) ylast = yval;
00291       }
00292 
00293    //! Compute area of rectangle (Could be negative if invalid rectangle).
00294    INT32 GetArea (
00295       ) const { return (GetWidth() * GetHeight()); }
00296 
00297    //! Return bottom left corner.
00298    void GetBottomLeft (                
00299       LPOINT2D& ret
00300       ) const { ret.x = xinit; ret.y = yinit; }
00301 
00302    //! Get bottom right corner.
00303    void GetBottomRight (               
00304       LPOINT2D& ret
00305       ) const { ret.x = xlast; ret.y = yinit; }
00306 
00307    //! Return center point of rectangle.
00308    DPOINT2D GetCenter (                
00309       ) const { return (DPOINT2D((xlast + xinit)/2.0, (ylast + yinit)/2.0)); }
00310 
00311    //! Get center point of rectangle.
00312    void GetCenter (                    
00313       DPOINT2D& ret
00314       ) const { ret.x = (xinit + xlast) / 2.0; ret.y = (yinit + ylast) / 2.0; }
00315 
00316    //! Get corners as array.
00317    void GetCorners (                   
00318       LPOINT2D *corners,               //!< Array of points to fill in
00319       bool ClosePoly = false,          //!< Return "closed" polygon, corners[4] = corners[0]
00320       bool OrientCCW = false           //!< Orient points in counterclockwise order for right-hand cartesian
00321       ) const { LRect2DGetCorners(*this, corners, ClosePoly, OrientCCW); }
00322 
00323    //! Compute number of non zero dimensions (0, 1, or 2).
00324    int GetDimension (                  
00325       ) const {
00326       int count(0);
00327       if (xinit < xlast) count ++;
00328       if (yinit < ylast) count ++;
00329       return (count);
00330       }
00331 
00332    //! Return height (Y size) of rectangle.
00333    UINT32 GetHeight (                  
00334       ) const { return (ylast - yinit + 1); }
00335 
00336    //! Get size of rectangle.
00337    void GetSize (                      
00338       LPOINT2D& ret
00339       ) const { ret.x = xlast - xinit; ret.y = ylast - yinit; }
00340 
00341    //! Return top left point of rectangle.
00342    void GetTopLeft (                   
00343       LPOINT2D& ret
00344       ) const { ret.x = xinit; ret.y = ylast; }
00345 
00346    //! Return top right point of rectangle.
00347    void GetTopRight (                  
00348       LPOINT2D& ret
00349       ) const { ret.x = xlast; ret.y = ylast; }
00350 
00351    //! Return width (X size) of rectangle.
00352    UINT32 GetWidth (                   
00353       ) const { return (xlast - xinit + 1); }
00354 
00355    //! Read rectangle from INI file.
00356    bool IniRead (
00357       INIHANDLE IniHandle,
00358       const char *IniGroup,
00359       const char *IniName
00360       ) { return (_iniRead(IniHandle,IniGroup,IniName,INITYPE_INT32,this,4) == 4); }
00361 
00362    //! Read rectangle from INI file.
00363    void IniWrite (
00364       INIHANDLE IniHandle,
00365       const char *IniGroup,
00366       const char *IniName
00367       ) const { _iniWrite(IniHandle,IniGroup,IniName,INITYPE_INT32,this,4); }
00368 
00369    //! Intersect two DRECT2D's, may result in an invalid rectangle.
00370    void Intersect (                    
00371       const LRECT2D& rect
00372       ) {
00373       if (rect.IsValid()) {
00374          if (rect.xinit > xinit) xinit = rect.xinit;
00375          if (rect.yinit > yinit) yinit = rect.yinit;
00376          if (rect.xlast < xlast) xlast = rect.xlast;
00377          if (rect.ylast < ylast) ylast = rect.ylast;
00378          }
00379       else {
00380          *this = rect;
00381          }
00382       return;
00383       }
00384 
00385    //! Check if rectangle is valid.
00386    bool IsValid (                      
00387       ) const { return (xinit <= xlast && yinit <= ylast); }
00388 
00389    //! Limit point (LPOINT2D) to extents specified by rectangle.
00390    void Limit (
00391       LPOINT2D& point
00392       ) const {
00393       if (point.x < xinit) point.x = xinit; else if (point.x > xlast) point.x = xlast;
00394       if (point.y < yinit) point.y = yinit; else if (point.y > ylast) point.y = ylast;
00395       }
00396 
00397    //! Limit point (DPOINT2D) to extents specified by rectangle.
00398    void Limit (
00399       DPOINT2D& point
00400       ) const {
00401       if (point.x < xinit) point.x = xinit; else if (point.x > xlast) point.x = xlast;
00402       if (point.y < yinit) point.y = yinit; else if (point.y > ylast) point.y = ylast;
00403       }
00404 
00405    //! Check if rectangle overlaps.
00406    bool Overlaps (                     
00407       const LRECT2D& rhs
00408       ) const {
00409       return (!(rhs.xlast < xinit || rhs.xinit > xlast || rhs.ylast < yinit || rhs.yinit > ylast));
00410       }
00411    
00412    //! Set given (x1,y1), (x2,y2)
00413    void Set (
00414       INT32 x1,
00415       INT32 y1,
00416       INT32 x2,
00417       INT32 y2
00418       ) { xinit = x1; yinit = y1; xlast = x2; ylast = y2; }
00419 
00420    //! Sets the initial values to the maximum possible and the final values to the minimum possible, thus making the rectangle "invalid".
00421    //! Setting a rectangle to invalid means that no point will be in it.  It also makes it easy 
00422    //! to compute the min/max of a bunch of points.  You just iterate through all the points 
00423    //! and Extend() the rectangle.  Normally, you'd have to handle the first point specially.
00424    void SetInvalid (
00425       ) { xinit = yinit = INT32_MAX; xlast = ylast = INT32_MIN; }
00426 
00427    //! Perform byte-order swapping.
00428    void SwapBytes (
00429       ) { ::SwapBytes(xinit); ::SwapBytes(xlast); ::SwapBytes(yinit); ::SwapBytes(ylast); }
00430 
00431    //! Make compiler validate structure size.
00432    CHECKSIZE(16);                      
00433    };
00434 
00435 inline bool operator== (
00436    const LRECT2D& lhs,
00437    const LRECT2D& rhs
00438    ) {
00439    return (lhs.xinit == rhs.xinit && lhs.xlast == rhs.xlast && lhs.yinit == rhs.yinit && lhs.ylast == rhs.ylast);
00440    }
00441 
00442 inline bool operator!= (
00443    const LRECT2D& lhs,
00444    const LRECT2D& rhs
00445    ) {
00446    return (!operator==(lhs,rhs));
00447    }
00448 
00449 
00450 //-------------------------------------------------------------------------------------------------------------------
00451 
00452 //! 2D rectangle using 'double' precision coordinates.
00453 struct DRECT2D {
00454    
00455    double xinit;                    //!< Minimum X coordinate (inclusive)
00456    double yinit;                    //!< Minimum Y coordinate (inclusive)
00457    double xlast;                    //!< Maximum X coordinate (inclusive)
00458    double ylast;                    //!< Maximum Y coordinate (inclusive)
00459 
00460    //! Default constructor, initialize to "invalid" area.
00461    DRECT2D (                           
00462       ) : xinit(DBL_MAX), yinit(DBL_MAX), xlast(-DBL_MAX), ylast(-DBL_MAX) {
00463       }
00464 
00465    //! Construct from FPOINT2D (or FPOINT3D).
00466    DRECT2D (                           
00467       const FPOINT2D& pt
00468       ) : xinit(pt.x), yinit(pt.y), xlast(pt.x), ylast(pt.y) { }
00469 
00470    //! Construct from DPOINT2D (or DPOINT3D).
00471    DRECT2D (                           
00472       const DPOINT2D& pt
00473       ) : xinit(pt.x), yinit(pt.y), xlast(pt.x), ylast(pt.y) { }
00474 
00475    //! Construct from two DPOINT2D's (or DPOINT3D's).
00476    //! A regular ctor from DPOINT2D and then a call to ::Extend(DPOINT2D&) would use
00477    //! 6 assignments and 4 comparisons, this uses 2 compares and 4 assignments
00478    DRECT2D (                           
00479       const DPOINT2D& pt1,
00480       const DPOINT2D& pt2
00481       ) {
00482       if (pt1.x < pt2.x) {
00483          xinit = pt1.x;
00484          xlast = pt2.x;
00485          }
00486       else {
00487          xinit = pt2.x;
00488          xlast = pt1.x;
00489          }
00490       if (pt1.y < pt2.y) {
00491          yinit = pt1.y;
00492          ylast = pt2.y;
00493          }
00494       else {
00495          yinit = pt2.y;
00496          ylast = pt1.y;
00497          }
00498       }
00499 
00500    DRECT2D (
00501       double xi,
00502       double yi,
00503       double xl,
00504       double yl
00505       ) : xinit(xi), yinit(yi), xlast(xl), ylast(yl) { }
00506 
00507    //! Implicit conversion from LRECT2D.
00508    DRECT2D (                           
00509       const LRECT2D& rect
00510       ) : xinit(rect.xinit), yinit(rect.yinit), xlast(rect.xlast), ylast(rect.ylast) { }
00511 
00512    //! Assignment from DPOINT2D
00513    DRECT2D& operator= (                
00514       const DPOINT2D& pt
00515       ) { xinit = xlast = pt.x; yinit = ylast = pt.y; return (*this); }
00516 
00517    //! Assignment from LRECT2D.
00518    DRECT2D& operator= (                
00519       const LRECT2D& rhs
00520       ) { xinit = rhs.xinit; yinit = rhs.yinit; xlast = rhs.xlast; ylast = rhs.ylast; return (*this); }
00521 
00522    //! Clip this rectangle to specified rectangle.
00523    void ClipTo (                       
00524       const DRECT2D& rect
00525       ) {
00526       if (xinit < rect.xinit) xinit = rect.xinit;
00527       if (yinit < rect.yinit) yinit = rect.yinit;
00528       if (xlast > rect.xlast) xlast = rect.xlast;
00529       if (ylast > rect.ylast) ylast = rect.ylast;
00530       return;
00531       }
00532 
00533    //! Given the center point of the DRECT2D and the 'TestPt' which is outside the box,
00534    //! compute the point on the edge of the box which falls between the center point and
00535    //! the 'TestPt'.
00536    //! @return 'true' if the point is found, false if the 'TestPt' is inside the box or the box is invalid
00537    bool ComputeEdgePoint (
00538       const DPOINT2D& OutsidePt,       //!< Point outside of 'this' 
00539       DPOINT2D& EdgePt                 //!< Point on the rectangle edge RETURNED if 'true' returned, center of the box if 'false' is returned
00540       ) const { return (DRect2DComputeEdgePoint(*this, OutsidePt, EdgePt)); }
00541 
00542    //! Check if contains specified point.
00543    bool Contains (                     
00544       double x,
00545       double y
00546       ) const { return (x >= xinit && x <= xlast && y >= yinit && y <= ylast); }
00547 
00548    //! Check if contains specified point.
00549    bool Contains (                     
00550       const DPOINT2D& pt
00551       ) const { return (pt.x >= xinit && pt.x <= xlast && pt.y >= yinit && pt.y <= ylast); }
00552 
00553    //! Check if contains specified point.
00554    bool Contains (                     
00555       const DRECT2D& rhs
00556       ) const { return (rhs.xinit >= xinit && rhs.xlast <= xlast && rhs.yinit >= yinit && rhs.ylast <= ylast); }
00557 
00558    //! Expand the rectangle by 'value' amount.
00559    void Expand (                       
00560       const double value
00561       ) { xinit -= value; yinit -= value; xlast += value; ylast += value; }
00562 
00563    //! Expand the rectangle by 'value' amount.
00564    void Expand (                       
00565       const double xval,
00566       const double yval
00567       ) { xinit -= xval; yinit -= yval; xlast += xval; ylast += yval; }
00568 
00569    //! Extend rectangle to include specified X,Y point.
00570    void Extend (                       
00571       const double xval,
00572       const double yval
00573       ) {
00574       if (xval < xinit) xinit = xval;
00575       if (yval < yinit) yinit = yval;
00576       if (xval > xlast) xlast = xval;
00577       if (yval > ylast) ylast = yval;
00578       return;
00579       }
00580 
00581    //! Extend rectangle to encompass both rectangles.
00582    void Extend (                       
00583       const DRECT2D& rect
00584       ) {
00585       if (rect.xinit < xinit) xinit = rect.xinit;
00586       if (rect.yinit < yinit) yinit = rect.yinit;
00587       if (rect.xlast > xlast) xlast = rect.xlast;
00588       if (rect.ylast > ylast) ylast = rect.ylast;
00589       return;
00590       }
00591 
00592    //! Extend rectangle to include specified DPOINT2D point.
00593    void Extend (                       
00594       const DPOINT2D& pt
00595       ) {
00596       if (pt.x < xinit) xinit = pt.x;
00597       if (pt.x > xlast) xlast = pt.x;
00598       if (pt.y < yinit) yinit = pt.y;
00599       if (pt.y > ylast) ylast = pt.y;
00600       return;
00601       }
00602 
00603    //! Compute area of rectangle.
00604    double GetArea (                    
00605       ) const { return ((xlast - xinit) * (ylast - yinit)); }
00606 
00607    //! Return bottom left point of rectangle.
00608    void GetBottomLeft (                
00609       DPOINT2D& ret
00610       ) const { ret.x = xinit; ret.y = yinit; }
00611 
00612    //! Return bottom right point of rectangle.
00613    void GetBottomRight (               
00614       DPOINT2D& ret
00615       ) const { ret.x = xlast; ret.y = yinit; }
00616 
00617    //! Return center point of rectangle.
00618    DPOINT2D GetCenter (                
00619       ) const { return (DPOINT2D((xlast + xinit)/2.0, (ylast + yinit)/2.0)); }
00620 
00621    //! Return center point of rectangle.
00622    void GetCenter (                    
00623       DPOINT2D& ret
00624       ) const { ret.x = (xinit + xlast) / 2.0; ret.y = (yinit + ylast) / 2.0; }
00625 
00626    //! Get corners as array.
00627    void GetCorners (                   
00628       DPOINT2D *corners,               //!< Array of points to fill in
00629       bool ClosePoly = false,          //!< Return "closed" polygon, corners[4] = corners[0]
00630       bool OrientCCW = false           //!< Orient points in counterclockwise order for right-hand cartesian
00631       ) const { DRect2DGetCorners(*this, corners, ClosePoly, OrientCCW); }
00632 
00633    //! Get corners as array.
00634    void GetCorners (                   
00635       DPOINT3D *corners,               //!< Array of points to fill in
00636       bool ClosePoly = false,          //!< Return "closed" polygon, corners[4] = corners[0]
00637       bool OrientCCW = false           //!< Orient points in counterclockwise order for right-hand cartesian
00638       ) const { DRect2DGetCorners(*this, corners, ClosePoly, OrientCCW); }
00639 
00640    //! Compute number of non zero dimensions (0, 1, or 2).
00641    int GetDimension (                  
00642       ) const {
00643       int count(0);
00644       if (xinit < xlast) count ++;
00645       if (yinit < ylast) count ++;
00646       return (count);
00647       }
00648 
00649    //! Compute the distance between two disjoint rectangles
00650    //! @return Distance between two disjoint rectangles, 0.0 if they overlap.
00651    double GetDistance (
00652       const DRECT2D& rect
00653       ) const { return (DRect2DGetDistance(*this, rect)); }
00654 
00655    //! Return height of rectangle.
00656    double GetHeight (                  
00657       ) const { return (ylast - yinit); }
00658 
00659    //! Compute the maximum distance between two rectangles
00660    //! Uses Extend() and then computes the diagonal distance
00661    //! @return Max distance between two rectangles
00662    double GetMaxDistance (
00663       const DRECT2D& rect
00664       ) const { return (DRect2DGetMaxDistance(*this, rect)); }
00665 
00666    //! Compute the maximum distance between two rectangles
00667    //! Uses Extend() and then computes the diagonal distance
00668    //! @return Max distance between two rectangles
00669    double GetMaxDistanceSquared (
00670       const DRECT2D& rect
00671       ) const { return (DRect2DGetMaxDistanceSquared(*this, rect)); }
00672 
00673    //! Get the rectangle as an LRECT2D (with rounding)
00674    void GetRect (
00675       LRECT2D& rect
00676       ) const {
00677       rect.xinit = static_cast<INT32>(FAST_ROUND(xinit));
00678       rect.yinit = static_cast<INT32>(FAST_ROUND(yinit));
00679       rect.xlast = static_cast<INT32>(FAST_ROUND(xlast));
00680       rect.ylast = static_cast<INT32>(FAST_ROUND(ylast));
00681       return;
00682       }
00683 
00684    //! Get the rectangle as an LRECT2D (with truncating towards 0)
00685    void GetRectTruncate (
00686       LRECT2D& rect
00687       ) const {
00688       rect.xinit = static_cast<INT32>(FAST_TRUNCATE(xinit));
00689       rect.yinit = static_cast<INT32>(FAST_TRUNCATE(yinit));
00690       rect.xlast = static_cast<INT32>(FAST_TRUNCATE(xlast));
00691       rect.ylast = static_cast<INT32>(FAST_TRUNCATE(ylast));
00692       return;
00693       }
00694 
00695    //! Get size of rectangle.
00696    void GetSize (                      
00697       DPOINT2D& ret
00698       ) const { ret.x = xlast - xinit; ret.y = ylast - yinit; }
00699 
00700    //! Return top left point of rectangle.
00701    void GetTopLeft (                   
00702       DPOINT2D& ret
00703       ) const { ret.x = xinit; ret.y = ylast; }
00704 
00705    //! Return top right point of rectangle.
00706    void GetTopRight (                  
00707       DPOINT2D& ret
00708       ) const { ret.x = xlast; ret.y = ylast; }
00709 
00710    //! Return width of rectangle.
00711    double GetWidth (                   
00712       ) const { return (xlast - xinit); }
00713 
00714    //! Read rectangle from INI file.
00715    bool IniRead (
00716       INIHANDLE IniHandle,
00717       const char *IniGroup,
00718       const char *IniName
00719       ) { return (_iniRead(IniHandle,IniGroup,IniName,INITYPE_DRECT2D,this,1) == 1); }
00720 
00721    //! Read rectangle from INI file with default.
00722    bool IniRead (
00723       INIHANDLE IniHandle,
00724       const char *IniGroup,
00725       const char *IniName,
00726       const DRECT2D& dft
00727       ) { if (IniRead(IniHandle,IniGroup,IniName)) return (true); else { *this = dft; return (false); } }
00728 
00729    //! Read rectangle from INI file.
00730    void IniWrite (
00731       INIHANDLE IniHandle,
00732       const char *IniGroup,
00733       const char *IniName
00734       ) const { _iniWrite(IniHandle,IniGroup,IniName,INITYPE_DRECT2D,this,1); }
00735 
00736    //! Intersect two DRECT2D's, may result in an invalid rectangle.
00737    void Intersect (                    
00738       const DRECT2D& rect
00739       ) {
00740       if (rect.IsValid()) {
00741          if (rect.xinit > xinit) xinit = rect.xinit;
00742          if (rect.yinit > yinit) yinit = rect.yinit;
00743          if (rect.xlast < xlast) xlast = rect.xlast;
00744          if (rect.ylast < ylast) ylast = rect.ylast;
00745          }
00746       else {
00747          *this = rect;
00748          }
00749       return;
00750       }
00751       
00752    //! Determine if the two rectangles are equivalent 
00753    //! This method uses "Fuzzy" edge comparisons
00754    //! Specify a different threshold to allow greater distances
00755    //! @return 'True' if they are, 'False' if not
00756    bool IsEquivalentTo (
00757       const DRECT2D& rhs,
00758       double threshold = 0.0        //!< Default threshold is max absolute value of rectangle coordinate * 1.0E-13
00759       ) const { return (DRect2DIsEquivalentTo(*this, rhs, threshold)); }
00760 
00761    //! Check if rectangle is valid.
00762    bool IsValid (                      
00763       ) const { return (xinit <= xlast && yinit <= ylast); }
00764 
00765    //! Limit point to extents specified by rectangle.
00766    void Limit (
00767       DPOINT2D& point
00768       ) const {
00769       if (point.x < xinit) point.x = xinit; else if (point.x > xlast) point.x = xlast;
00770       if (point.y < yinit) point.y = yinit; else if (point.y > ylast) point.y = ylast;
00771       return;
00772       }
00773 
00774    //! Check if rectangle overlaps.
00775    bool Overlaps (                     
00776       const DRECT2D& rhs
00777       ) const { return (!(rhs.xlast < xinit || rhs.xinit > xlast || rhs.ylast < yinit || rhs.yinit > ylast)); }
00778 
00779    //! Set given (x1,y1), (x2,y2)
00780    void Set (
00781       double x1,
00782       double y1,
00783       double x2,
00784       double y2
00785       ) { xinit = x1; yinit = y1; xlast = x2; ylast = y2; }
00786 
00787    //! Sets the initial values to the maximum possible and the final values to the minimum possible, thus making the rectangle "invalid".
00788    //! Setting a rectangle to invalid means that no point will be in it.  It also makes it easy 
00789    //! to compute the min/max of a bunch of points.  You just iterate through all the points 
00790    //! and Extend() the rectangle.  Normally, you'd have to handle the first point specially.
00791    void SetInvalid (
00792       ) { xinit = yinit = DBL_MAX; xlast = ylast = -DBL_MAX; }
00793 
00794    //! Perform byte-order swapping.
00795    void SwapBytes (
00796       ) { ::SwapBytes(xinit); ::SwapBytes(xlast); ::SwapBytes(yinit); ::SwapBytes(ylast); }
00797 
00798    //! Make compiler validate structure size.
00799    CHECKSIZE(32);                      
00800    };
00801 
00802 inline bool operator== (
00803    const DRECT2D& lhs,
00804    const DRECT2D& rhs
00805    ) {
00806    return (lhs.xinit == rhs.xinit && lhs.xlast == rhs.xlast && lhs.yinit == rhs.yinit && lhs.ylast == rhs.ylast);
00807    }
00808 
00809 inline bool operator!= (
00810    const DRECT2D& lhs,
00811    const DRECT2D& rhs
00812    ) {
00813    return (!operator==(lhs,rhs));
00814    }
00815 
00816 inline void SwapBytes (
00817    DRECT2D& rect
00818    ) {
00819    rect.SwapBytes();
00820    }
00821 
00822 //! Read 'DRECT2D' value from INI file.
00823 inline int IniRead (INIHANDLE hdl, const char *group, const char *field, DRECT2D& value) { return (_iniRead(hdl,group,field,INITYPE_DRECT2D,&value,1)); }
00824 
00825 //! Read 'DRECT2D' value from INI file with default.
00826 inline int IniRead (INIHANDLE hdl, const char *group, const char *field, DRECT2D& value, const DRECT2D& dft) { value = dft; return (IniRead(hdl,group,field,value)); }
00827 
00828 //! Write 'DRECT2D' value to INI file.
00829 inline int IniWrite (INIHANDLE hdl, const char *group, const char *field, const DRECT2D& value) { return (_iniWrite(hdl,group,field,INITYPE_DRECT2D,&value,1)); }
00830 
00831 
00832 //-------------------------------------------------------------------------------------------------------------------
00833 
00834 //! 3D rectangle using 'double' precision coordinates.
00835 struct DRECT3D : public DRECT2D {
00836    
00837    double zinit;
00838    double zlast;
00839 
00840    //! Initialize to nonexistent area.
00841    DRECT3D (                           
00842       ) : DRECT2D(), zinit(DBL_MAX), zlast(-DBL_MAX) { }
00843 
00844    //! Construct from FPOINT3D.
00845    DRECT3D (                           
00846       const FPOINT3D& pt
00847       ) : DRECT2D(pt), zinit(pt.z), zlast(pt.z) { }
00848 
00849    //! Construct from DPOINT3D.
00850    DRECT3D (                           
00851       const DPOINT3D& pt
00852       ) : DRECT2D(pt), zinit(pt.z), zlast(pt.z) { }
00853 
00854    //! Construct from two DPOINT3D's
00855    //! A regular ctor from DPOINT3D and then a call to ::Extend(DPOINT3D&) would use
00856    //! 9 assignments and 6 comparisons, this uses 3 compares and 6 assignments
00857    DRECT3D (                           
00858       const DPOINT3D& pt1,
00859       const DPOINT3D& pt2
00860       ) {
00861       if (pt1.x < pt2.x) {
00862          xinit = pt1.x;
00863          xlast = pt2.x;
00864          }
00865       else {
00866          xinit = pt2.x;
00867          xlast = pt1.x;
00868          }
00869       if (pt1.y < pt2.y) {
00870          yinit = pt1.y;
00871          ylast = pt2.y;
00872          }
00873       else {
00874          yinit = pt2.y;
00875          ylast = pt1.y;
00876          }
00877       if (pt1.z < pt2.z) {
00878          zinit = pt1.z;
00879          zlast = pt2.z;
00880          }
00881       else {
00882          zinit = pt2.z;
00883          zlast = pt1.z;
00884          }
00885       }
00886 
00887    //! Construct from DRECT2D.
00888    DRECT3D (                           
00889       const DRECT2D& rect
00890       ) : DRECT2D(rect), zinit(0.0), zlast(0.0) { }
00891 
00892    //! Construct from DRECT2D and Z min/max.
00893    DRECT3D (                           
00894       const DRECT2D& rect,
00895       double zmin,
00896       double zmax
00897       ) : DRECT2D(rect), zinit(zmin), zlast(zmax) { }
00898 
00899    //! Assignment from DPOINT3D
00900    DRECT3D& operator= (                
00901       const DPOINT3D& pt
00902       ) {
00903       xinit = xlast = pt.x;
00904       yinit = ylast = pt.y;
00905       zinit = zlast = pt.z;
00906       return (*this);
00907       }
00908 
00909    //! Check if point is inside.
00910    bool Contains (                     
00911       const DPOINT3D& pt
00912       ) const { return (DRECT2D::Contains(pt) && pt.z >= zinit && pt.z <= zlast); }
00913    
00914    //! Check if rectangle is inside.
00915    bool Contains (                     
00916       const DRECT3D& rhs
00917       ) const { return (DRECT2D::Contains(rhs) && rhs.zinit >= zinit && rhs.zlast <= zlast); }
00918 
00919    //! Expand the rectangle by 'value' amount.
00920    void Expand (                       
00921       const double value
00922       ) {
00923       DRECT2D::Expand(value);
00924       zinit -= value; zlast += value;
00925       return;
00926       }
00927 
00928    //! Expand the rectangle by 'value' amount.
00929    void Expand (                       
00930       const double xval,
00931       const double yval
00932       ) { DRECT2D::Expand(xval, yval); }
00933 
00934    //! Extend rectangle to encompass both rectangles.
00935    void Extend (                       
00936       const double xval,
00937       const double yval
00938       ) { DRECT2D::Extend(xval, yval); }
00939 
00940    //! Extend rectangle to encompass both rectangles.
00941    void Extend (                       
00942       const double xval,
00943       const double yval,
00944       const double zval
00945       ) {
00946       DRECT2D::Extend(xval, yval);
00947       if (zval < zinit) zinit = zval;
00948       if (zval > zlast) zlast = zval;
00949       return;
00950       }
00951 
00952    //! Union rectangles together, resulting rect is extents of both
00953    void Extend (                       
00954       const DRECT3D& rect
00955       ) {
00956       DRECT2D::Extend(rect);
00957       if (rect.zinit < zinit) zinit = rect.zinit;
00958       if (rect.zlast > zlast) zlast = rect.zlast;
00959       return;
00960       }
00961 
00962    //! Extend to contain specified point.
00963    void Extend (                       
00964       const DPOINT2D& pt
00965       ) { DRECT2D::Extend(pt); }
00966 
00967    //! Extend to contain specified point.
00968    void Extend (                       
00969       const DPOINT3D& pt
00970       ) {
00971       DRECT2D::Extend(pt);
00972       if (pt.z < zinit) zinit = pt.z;
00973       if (pt.z > zlast) zlast = pt.z;
00974       return;
00975       }
00976 
00977    //! Return center of the box.
00978    DPOINT3D GetCenter (
00979       ) const { return (DPOINT3D((xinit+xlast)/2.0,(yinit+ylast)/2.0,(zinit+zlast)/2.0)); }
00980 
00981    //! Return center of the box.
00982    void GetCenter (
00983       DPOINT3D& ret
00984       ) const {
00985       ret.x = (xinit + xlast) / 2.0;
00986       ret.y = (yinit + ylast) / 2.0;
00987       ret.z = (zinit + zlast) / 2.0;
00988       return;
00989       }
00990 
00991    //! Return depth of the box (z distance).
00992    double GetDepth (                   
00993       ) const { return (zlast - zinit); }
00994 
00995    //! Compute number of non zero dimensions (0, 1, 2, or 3).
00996    int GetDimension (                  
00997       ) const {
00998       int count(DRECT2D::GetDimension());
00999       if (zinit < zlast) count ++;
01000       return (count);
01001       }
01002 
01003    //! Get maximum coordinate.
01004    void GetMaximum (
01005       DPOINT3D& maximum
01006       ) const { maximum.x = xlast; maximum.y = ylast; maximum.z = zlast; }
01007 
01008    //! Get minimum coordinate.
01009    void GetMinimum (
01010       DPOINT3D& minimum
01011       ) const { minimum.x = xinit; minimum.y = yinit; minimum.z = zinit; }
01012 
01013    //! Get size of box.
01014    void GetSize (                      
01015       DPOINT3D& ret
01016       ) const {
01017       ret.x = xlast - xinit;
01018       ret.y = ylast - yinit;
01019       ret.z = zlast - zinit;
01020       return;
01021       }
01022 
01023    //! Compute volume of box.
01024    double GetVolume (                  
01025       ) const { return (DRECT2D::GetArea() * (zlast - zinit)); }
01026 
01027    //! Read rectangle from INI file.
01028    bool IniRead (
01029       INIHANDLE IniHandle,
01030       const char *IniGroup,
01031       const char *IniName
01032       ) { return (_iniRead(IniHandle,IniGroup,IniName,INITYPE_Double,this,6) == 6); }
01033 
01034    //! Read rectangle from INI file.
01035    void IniWrite (
01036       INIHANDLE IniHandle,
01037       const char *IniGroup,
01038       const char *IniName
01039       ) const { _iniWrite(IniHandle,IniGroup,IniName,INITYPE_Double,this,6); }
01040 
01041    //! Intersect two DRECT3D's, may result in an invalid rectangle.
01042    void Intersect (                    
01043       const DRECT3D& rect
01044       ) {
01045       if (rect.IsValid()) {
01046          DRECT2D::Intersect(rect);
01047          if (rect.zinit > zinit) zinit = rect.zinit;
01048          if (rect.zlast < zlast) zlast = rect.zlast;
01049          }
01050       else {
01051          *this = rect;
01052          }
01053       return;
01054       }
01055    
01056    //! Check if rectangle is valid.
01057    bool IsValid (                      
01058       ) const { return (DRECT2D::IsValid() && zinit <= zlast); }
01059 
01060    //! Check if rectangle overlaps.
01061    bool Overlaps (                     
01062       const DRECT3D& rhs
01063       ) const { return (DRECT2D::Overlaps(rhs) && !(rhs.zlast < zinit || rhs.zinit > zlast)); }
01064 
01065    //! Set given (x1,y1), (x2,y2)
01066    void Set (
01067       double x1,
01068       double y1,
01069       double x2,
01070       double y2
01071       ) { xinit = x1; yinit = y1; xlast = x2; ylast = y2; zinit = zlast = 0.0; }
01072 
01073    //! Sets the initial values to the maximum possible and the final values to the minimum possible, thus making the rectangle "invalid".
01074    //!
01075    //! Setting a rectangle to invalid means that no point will be in it.  It also makes it easy 
01076    //! to compute the min/max of a bunch of points.  You just iterate through all the points 
01077    //! and Extend() the rectangle.  Normally, you'd have to handle the first point specially.
01078    void SetInvalid (
01079       ) { DRECT2D::SetInvalid(); zinit = DBL_MAX; zlast = -DBL_MAX; }
01080 
01081    //! Perform byte-order swapping.
01082    void SwapBytes (
01083       ) { ::SwapBytes(xinit); ::SwapBytes(xlast); ::SwapBytes(yinit); ::SwapBytes(ylast); ::SwapBytes(zinit); ::SwapBytes(zlast); }
01084 
01085    //! Make compiler validate structure size.
01086    CHECKSIZE(48);                      
01087    };
01088 
01089 inline bool operator== (
01090    const DRECT3D& lhs,
01091    const DRECT3D& rhs
01092    ) {
01093    return (lhs.xinit == rhs.xinit && lhs.xlast == rhs.xlast && lhs.yinit == rhs.yinit && lhs.ylast == rhs.ylast && lhs.zinit == rhs.zinit && lhs.zlast == rhs.zlast);
01094    }
01095 
01096 inline bool operator!= (
01097    const DRECT3D& lhs,
01098    const DRECT3D& rhs
01099    ) {
01100    return (!operator==(lhs,rhs));
01101    }
01102 
01103 inline void SwapBytes (
01104    DRECT3D& rect
01105    ) {
01106    rect.SwapBytes();
01107    }
01108 
01109 
01110 //-------------------------------------------------------------------------------------------------------------------
01111 
01112 #endif   //!< INC_MI32_RECT_H

Generated on Tue Dec 14 13:18:32 2004 for TNTsdk by