Sirikata
libcore/include/sirikata/core/util/BoundingSphere.hpp
Go to the documentation of this file.
00001 /*  Sirikata Utilities -- Math Library
00002  *  BoundingSphere.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_SPHERE_HPP
00033 #define _SIRIKATA_BOUNDING_SPHERE_HPP
00034 namespace Sirikata {
00035 template <typename real> class BoundingSphere {
00036     Vector3<real> mCenter;
00037     float32 mRadius;
00038 public:
00039 
00040     static BoundingSphere<real> null() {
00041         return BoundingSphere<real>(Vector3<real>(0,0,0),0);
00042     }
00043     BoundingSphere()
00044      : mRadius(-1)
00045     {}
00046     BoundingSphere(const Vector3<real>&center, float radius){
00047         mCenter=center;
00048         mRadius=radius;
00049     }
00050     float32 radius()const{
00051         return mRadius;
00052     }
00053     Vector3<real> center() const {
00054         return mCenter;
00055     }
00056     BoundingSphere<real> recenter(const Vector3<real>&newCenter) {
00057         mRadius+=(newCenter-mCenter).length();
00058         mCenter=newCenter;
00059     }
00060     BoundingSphere& mergeIn(const BoundingSphere& rhs) {
00061         *this = merge(rhs);
00062         return *this;
00063     }
00064 
00065     BoundingSphere merge(const BoundingSphere& rhs) const {
00066         if (rhs.invalid())
00067             return *this;
00068 
00069         if (this->invalid())
00070             return rhs;
00071 
00072         // Check if one is entirely contained within the other
00073         Vector3<real> to_other_center = rhs.mCenter - mCenter;
00074         real center_dist = to_other_center.length();
00075         if (center_dist + mRadius <= rhs.mRadius)
00076             return rhs;
00077         if (center_dist + rhs.mRadius <= mRadius)
00078             return *this;
00079 
00080         real new_radius2 = (mRadius + center_dist + rhs.mRadius);
00081         real new_radius = new_radius2 * 0.5;
00082         if (center_dist > 1e-08) {
00083             Vector3<real> to_other_center_normalized = to_other_center / center_dist;
00084             Vector3<real> farthest_point_from_other = mCenter - (mRadius * to_other_center_normalized);
00085             Vector3<real> half_new_span = to_other_center_normalized * new_radius;
00086             Vector3<real> new_center = farthest_point_from_other + half_new_span;
00087             return BoundingSphere(new_center, new_radius);
00088         }
00089         else {
00090             return BoundingSphere(mCenter, new_radius);
00091         }
00092     }
00093 
00094     bool contains(const BoundingSphere& other) const {
00095         real centers_len = (mCenter - other.mCenter).length();
00096         return (mRadius >= centers_len + other.mRadius);
00097     }
00098 
00099     bool contains(const BoundingSphere& other, real epsilon) const {
00100         real centers_len = (mCenter - other.mCenter).length();
00101         return (mRadius + epsilon >= centers_len + other.mRadius);
00102     }
00103 
00104     bool contains(const Vector3<real>& pt) const {
00105         return ( (mCenter-pt).lengthSquared() <= mRadius*mRadius );
00106     }
00107 
00108     bool invalid() const {
00109         return (mRadius < 0);
00110     }
00111 
00112     bool degenerate() const {
00113         return ( mRadius <= 0 );
00114     }
00115 
00116     real volume() const {
00117         if (degenerate()) return 0.0;
00118         real Pi = 3.1415926536;//cannot initialize in class due to nonintegral type VC++ err
00119         return 4.0 / 3.0 * Pi * mRadius * mRadius * mRadius;
00120     }
00121 
00122     bool operator==(const BoundingSphere& rhs) {
00123         return (mCenter == rhs.mCenter && mRadius == rhs.mRadius);
00124     }
00125     bool operator!=(const BoundingSphere& rhs) {
00126         return (mCenter != rhs.mCenter || mRadius != rhs.mRadius);
00127     }
00128 };
00129 
00130 template<typename scalar>
00131 inline std::ostream& operator <<(std::ostream& os, const BoundingSphere<scalar> &rhs) {
00132   os << '<' << rhs.center() << ',' << rhs.radius() << '>';
00133   return os;
00134 }
00135 
00136 }
00137 #endif