core/vbl/vbl_bounding_box.h
Go to the documentation of this file.
00001 // This is core/vbl/vbl_bounding_box.h
00002 #ifndef vbl_bounding_box_h_
00003 #define vbl_bounding_box_h_
00004 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00005 #pragma interface
00006 #endif
00007 //:
00008 // \file
00009 // \brief Contains a bounding box class
00010 // \author awf@robots.ox.ac.uk
00011 // \date   17 Mar 00
00012 //
00013 // \verbatim
00014 // Modifications
00015 // 970807 AWF Initial version.
00016 // 07 Mar 2001 stewart@cs.rpi.edu added "inside" functions
00017 // 21 Mar 2001 PDA (Manchester)   Tidied up the documentation
00018 // 13 Jul 2001 Peter Vanroose     bug fix in inside() when box is empty
00019 // \endverbatim
00020 
00021 #include <vcl_iosfwd.h>
00022 #include <vcl_cassert.h>
00023 
00024 #if defined(VCL_SUNPRO_CC_50)
00025 // Non-type template parameters are not allowed for function templates.
00026 #endif
00027 
00028 
00029 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00030 // Helper class for vbl_bounding_box
00031 template <int DIM>
00032 struct vbl_bounding_box_DIM { enum { value = DIM }; };
00033 #endif // DOXYGEN_SHOULD_SKIP_THIS
00034 
00035 template <class T, class DIM_>
00036 class vbl_bounding_box_base
00037 {
00038  public:
00039   //: Construct an empty bounding box.
00040   inline vbl_bounding_box_base() : initialized_(false) { }
00041 
00042   //: Incorporate 1d point x
00043   inline void update(T const& x) {
00044     assert(DIM_::value == 1);
00045     update(&x);
00046   }
00047 
00048   //: Incorporate 2d point x, y
00049   inline void update(T const& x, T const& y) {
00050     assert(DIM_::value == 2);
00051     T tmp[2] = {x,y};
00052     update(tmp);
00053   }
00054 
00055   //: Incorporate 3d point x, y, z
00056   inline void update(T const& x, T const& y, T const& z) {
00057     assert(DIM_::value == 3);
00058     T tmp[3] = {x,y,z};
00059     update(tmp);
00060   }
00061 
00062   //: return dimension.
00063   inline int dimension() const { return DIM_::value; }
00064 
00065   //: Incorporate DIM-d point
00066   inline void update(T const* point) {
00067     if (!initialized_) {
00068       initialized_ = true;
00069       for (int i = 0; i < dimension(); ++i)
00070         min_[i] = max_[i] = point[i];
00071     } else {
00072       for (int i = 0; i < dimension(); ++i) {
00073         if (point[i] < min_[i]) min_[i] = point[i];
00074         if (point[i] > max_[i]) max_[i] = point[i];
00075       }
00076     }
00077   }
00078 
00079   //: Reset to empty
00080   inline void reset() { initialized_ = false; }
00081 
00082   //: Return initialisation status
00083   inline bool empty() const { return !initialized_; }
00084 
00085   //:  is a 2D point inside the bounding box
00086   inline bool inside( const T& x, const T& y) const {
00087     assert (DIM_::value == 2);
00088     return
00089       initialized_ &&
00090       min_[0] <= x && x <= max_[0] &&
00091       min_[1] <= y && y <= max_[1];
00092   }
00093 
00094   //:  is a 3D point inside the bounding box
00095   inline bool inside( const T& x, const T& y, const T& z) const {
00096     assert (DIM_::value == 3);
00097     return
00098       initialized_ &&
00099       min_[0] <= x && x <= max_[0] &&
00100       min_[1] <= y && y <= max_[1] &&
00101       min_[2] <= z && z <= max_[2];
00102   }
00103 
00104   //:  inside test for arbitrary dimension
00105   inline bool inside(T const* point) const {
00106     if (!initialized_) return false;
00107     for ( int i=0; i<dimension(); ++i )
00108       if ( point[i] < min_[i] || max_[i] < point[i] )
00109         return false;
00110     return true;
00111   }
00112 
00113   //: return "volume".
00114   inline T volume() const {
00115     if (!initialized_) return T(0);
00116     T vol = 1;
00117     for (int i=0; i<dimension(); ++i)
00118       vol *= max_[i] - min_[i];
00119     return vol;
00120   }
00121 
00122   vcl_ostream& print(vcl_ostream& s) const;
00123 
00124   inline T const* min() const { return min_; }
00125   inline T const* max() const { return max_; }
00126 
00127   inline T      * min() { return min_; }
00128   inline T      * max() { return max_; }
00129 
00130   inline T const& xmin() const { return min_[0]; }
00131   inline T const& xmax() const { return max_[0]; }
00132   inline T const& ymin() const { assert(DIM_::value >= 2); return min_[1]; }
00133   inline T const& ymax() const { assert(DIM_::value >= 2); return max_[1]; }
00134   inline T const& zmin() const { assert(DIM_::value >= 3); return min_[2]; }
00135   inline T const& zmax() const { assert(DIM_::value >= 3); return max_[2]; }
00136 
00137   //#pragma dogma
00138   // There is no need for the data members to be private to
00139   // this class. After all, the STL pair<> template has its
00140   // two main members first, second public without causing
00141   // any problems.
00142   // BUT...
00143   //#pragma practically
00144   // The main difference here is that min_ and max_ have to satisfy certain
00145   // constraints: e.g., min_[0] must be <= max_[0].  Hence we want write access
00146   // to the data members to go through update() and empty() which can enforce
00147   // this.  Also, the use of initialized_ is a bit tricky: it indicates whether
00148   // the bounding box is empty or not.  This information could have been stored
00149   // in the other data members instead (e.g. by setting min_[0] > max_[0])
00150   // but that was not the design choice.  Hence, leaving the really private
00151   // (because subject to removal) data member initialized_ freely accessible
00152   // is a very bad idea...
00153   // HUH???
00154   //#pragma reality_check
00155   // But those members are still public; they are exposed by min() and max(),
00156   // except the client must use the odd "bb.min()[i]" instead of "bb.min[i]".
00157   // I predict the response to this observation will be the removal of the two
00158   // non-const versions.
00159 
00160  private:
00161   bool initialized_;
00162   T min_[DIM_::value];
00163   T max_[DIM_::value];
00164 };
00165 
00166 //: A class to hold and update a bounding box.
00167 //  Save valuable time not writing
00168 // \code
00169 //    if (x > xmax).....
00170 // \endcode
00171 
00172 template <class T, int DIM>
00173 class vbl_bounding_box : public vbl_bounding_box_base<T, vbl_bounding_box_DIM<DIM> >
00174 {
00175  public:
00176 };
00177 
00178 //------------------------------------------------------------
00179 
00180 //: this is "operator \subseteq"
00181 template <class T, class DIM_>
00182 inline
00183 bool nested(vbl_bounding_box_base<T,DIM_> const &a, vbl_bounding_box_base<T,DIM_> const &b)
00184 {
00185   for (int i=0; i<DIM_::value; ++i)
00186     if (a.min()[i] < b.min()[i] || a.max()[i] > b.max()[i])
00187       return false;
00188   return true;
00189 }
00190 
00191 //: is the intersection empty?
00192 template <class T, class DIM_>
00193 inline
00194 bool disjoint(vbl_bounding_box_base<T,DIM_> const &a,
00195               vbl_bounding_box_base<T,DIM_> const &b)
00196 {
00197   for (int i=0; i<DIM_::value; ++i)
00198     if (a.min()[i] > b.max()[i] || a.max()[i] < b.min()[i])
00199       return true;
00200   return false;
00201 }
00202 
00203 //: is the intersection nonempty?
00204 template <class T, class DIM_>
00205 inline
00206 bool meet(vbl_bounding_box_base<T,DIM_> const &a,
00207           vbl_bounding_box_base<T,DIM_> const &b)
00208 { return ! disjoint(a, b); }
00209 
00210 // VC50 has trouble with this
00211 template <class T, class DIM_>
00212 vcl_ostream& operator << (vcl_ostream& s, const vbl_bounding_box_base<T,DIM_>& bbox);
00213 
00214 #endif // vbl_bounding_box_h_