Sirikata
libcore/include/sirikata/core/util/BoundingBox.hpp
Go to the documentation of this file.
00001 /*  Sirikata Utilities -- Math Library
00002  *  BoundingBox.hpp
00003  *
00004  *  Copyright (c) 2009, Daniel Reiter Horn
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 #ifndef _SIRIKATA_BOUNDING_BOX_HPP
00033 #define _SIRIKATA_BOUNDING_BOX_HPP
00034 
00035 #define BBOX_CONTAINS_EPSILON 0.0005
00036 
00037 namespace Sirikata {
00038 template <typename real> class BoundingBox {
00039     Vector3<real> mMin;
00040     Vector3f mAcross;
00041 public:
00042     BoundingBox() {}
00043     static BoundingBox<real> null() {
00044         return BoundingBox<real>(Vector3<real>(0,0,0),0);
00045     }
00046 
00047     BoundingBox(const Vector3<real>&center, float radius){
00048         mMin=center-Vector3<real>(radius,radius,radius);
00049         mAcross=Vector3f(2.0f*radius,2.0f*radius,2.0f*radius);
00050     }
00051     template <typename flt> BoundingBox(const BoundingBox<flt>&input) {
00052         mMin=Vector3<real>(input.min());
00053         mAcross=input.across();
00054     }
00055     BoundingBox(const Vector3<real>&imin,const Vector3<real>&imax){
00056         mMin=imin;
00057         Vector3<real> tmp(imax-imin);
00058         mAcross.x=(float)tmp.x;
00059         mAcross.y=(float)tmp.y;
00060         mAcross.z=(float)tmp.z;
00061     }
00062 
00063     const Vector3<real> &min()const{
00064         return mMin;
00065     }
00066     const Vector3f& across() const {
00067         return mAcross;
00068     }
00069     const Vector3f& diag() const {
00070         return mAcross;
00071     }
00072     const Vector3f& extents() const {
00073         return mAcross;
00074     }
00075     Vector3<real> max() const {
00076         return mMin+Vector3<real>(mAcross);
00077     }
00078     Vector3<real> center() const {
00079         return mMin+Vector3<real>(mAcross * 0.5f);
00080     }
00081     BoundingSphere<real> toBoundingSphere() const{
00082         Vector3<real> center=this->center();
00083         float maxlen=(this->max()-this->center()).lengthSquared();
00084         float minlen=(this->min()-this->center()).lengthSquared();
00085         float radius=std::sqrt(minlen<maxlen?maxlen:minlen);
00086         return BoundingSphere<real>(center,radius);
00087     }
00088 
00089     BoundingBox<real> merge(const BoundingBox<real>&other) {
00090         return BoundingBox<real>(min().min(other.min()),
00091                            max().max(other.max()));
00092     }
00093     BoundingBox merge(const Vector3<real>&other) {
00094         return BoundingBox(min().min(other),
00095                            max().max(other));
00096     }
00097 
00098     BoundingBox& mergeIn(const BoundingBox<real>& other) {
00099          Vector3<real> mmax = max().max(other.max());
00100          Vector3<real> mmin= min().min(other.min());
00101          mMin = mmin;
00102          mAcross = Vector3f(mmax - mmin);
00103          return *this;
00104     }
00105 
00106     BoundingBox& mergeIn(const Vector3<real>& other) {
00107         Vector3<real> mmin=min().min(other);
00108         Vector3<real> mmax = max().max(other);
00109         mMin=mmin;
00110         mAcross = Vector3f(mmax - mmin);
00111         return *this;
00112     }
00113 
00121     bool contains(const Vector3<real>& point, real eps = BBOX_CONTAINS_EPSILON) const {
00122         Vector3<real> mmax = max();
00123         Vector3<real> mmin = min();
00124         for(int i = 0; i < Vector3<real>::size; i++) {
00125             if ( (point[i] - mmin[i] < -eps) ||
00126                 (mmax[i] - point[i] < -eps) )
00127                 return false;
00128         }
00129         return true;
00130     }
00131 
00132 
00133     bool degenerate() const {
00134         for(int i = 0; i < Vector3<real>::size; i++)
00135             if (mAcross[i] <= 0) return true;
00136         return false;
00137     }
00138 
00139     real volume() const {
00140         if (degenerate()) return 0.0;
00141         real vol = 1;
00142         for(int i = 0; i < Vector3<real>::size; i++)
00143             vol *= mAcross[i];
00144         return vol;
00145     }
00146 
00147     Vector3<real> clamp(const Vector3<real>& v) const {
00148         return v.max(min()).min(max());
00149     }
00150 
00151     bool intersects(const BoundingBox& bbox2) const {
00152       BoundingBox bbox = BoundingBox(min().max(bbox2.min()),
00153                                          max().min(bbox2.max()));
00154 
00155       if (bbox.min().x < bbox.max().x &&
00156           bbox.min().y < bbox.max().y &&
00157           bbox.min().z < bbox.max().z)
00158       {
00159         return true;
00160       }
00161 
00162       return false;
00163     }
00164 
00165     bool operator==(const BoundingBox& rhs) const{
00166         return (mMin == rhs.mMin && mAcross == rhs.mAcross);
00167     }
00168     bool operator!=(const BoundingBox& rhs) const{
00169         return (mMin != rhs.mMin || mAcross != rhs.mAcross);
00170     }
00171 
00172 };
00173 
00174 template<typename scalar>
00175 inline std::ostream& operator <<(std::ostream& os, const BoundingBox<scalar> &rhs) {
00176   os << '<' << rhs.min() << ',' << rhs.max() << '>';
00177   return os;
00178 }
00179 
00180 template<typename scalar>
00181 inline std::istream& operator >>(std::istream& is, BoundingBox<scalar> &rhs) {
00182   // FIXME this should be more robust.  It currently relies on the exact format provided by operator <<
00183   char dummy;
00184   Vector3<scalar> minval, maxval;
00185   is >> dummy >> minval >> dummy >> maxval >> dummy;
00186   rhs = BoundingBox<scalar>(minval, maxval);
00187   return is;
00188 }
00189 
00190 
00191 }
00192 #endif