Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   Related Pages  

sglSphereBound.hpp

00001 /*****************************************************************************
00002  * SGL: A Scene Graph Library
00003  *
00004  * Copyright (C) 1997-2001  Scott McMillan   All Rights Reserved.
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Library General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Library General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Library General Public
00017  * License along with this library; if not, write to the Free
00018  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  *****************************************************************************
00020  *     File: sglSphereBound.hpp
00021  *  Created: 14 November 1998
00022  *  Summary: bounding sphere class (for view frustum culling)
00023  *****************************************************************************/
00024 
00025 #ifndef __SGL_SPHERE_BOUND_HPP
00026 #define __SGL_SPHERE_BOUND_HPP
00027 
00028 #include <sgl.h>
00029 #include <sglVector.hpp>
00030 #include <sglPlane.hpp>
00031 #include <sglPolytope.hpp>
00032 
00033 #include <sglSegment.hpp>
00034 #include <sglBound.hpp>
00035 #include <sglBoxBound.hpp>
00036 
00037 // zero radius is empty, negative radius is infinite
00038 
00039 //----------------------------------------------------------------------------
00040 
00041 template <class T>
00042 class sglSphereBound : public sglBound
00043 {
00044 public:
00045    sglSphereBound() : m_radius(0), m_center(0,0,0) {};
00046 
00047    template <class S>
00048    sglSphereBound(const sglSphereBound<S> &rhs)
00049          : m_radius((T)rhs.getRadius()),m_center(rhs.getCenter()) {}
00050          
00051 
00052    ~sglSphereBound() {};
00053 
00054 #ifndef WIN32
00055    sglSphereBound &operator=(const sglSphereBound<T> &rhs)
00056       {
00057          if (this != &rhs)   // check for self assignment
00058          {
00059             m_radius = rhs.m_radius;
00060             m_center = rhs.m_center;
00061          }
00062          return *this;
00063       }
00064 #endif
00065 
00066    template <class S>
00067    sglSphereBound &operator=(const sglSphereBound<S> &rhs)
00068       {
00069          if (this != (sglSphereBound<T>*)&rhs)   // check for self assignment
00070          {
00071             m_radius = rhs.getRadius();
00072             m_center = rhs.getCenter();
00073          }
00074          return *this;
00075       }
00076 
00077    template <class S>
00078    bool operator==(const sglSphereBound<S> &rhs) const
00079       {
00080          return ((m_radius == rhs.getRadius()) &&
00081                  (m_center == rhs.getCenter()));
00082       }
00083 
00084    void makeEmpty() { m_radius = 0.0; }
00085    bool isEmpty() const { return (m_radius == 0.0); }
00086    bool isInfinite() const { return (m_radius < 0.0); }
00087 
00088    // ---------------------------------------------------------
00089    // get/set center and radius
00090    void setCenter(T x, T y, T z) {m_center.set(x,y,z);}
00091    template <class S> void setCenter(const sglVec3<S> &v) { m_center = v; }
00092    const sglVec3<T> &getCenter() const  { return m_center; }
00093 
00094    void setRadius(T radius) { m_radius = radius; }
00095    T getRadius() const { return m_radius; }
00096 
00097    // ---------------------------------------------------------
00098    // transform the sphere
00099    template <class S>
00100    void mul(const sglMat4<S>& mat)
00101       {
00102          sglVec3<T> center;
00103          center[0] = (T)(m_center[0]*mat[0][0] + m_center[1]*mat[1][0] +
00104                          m_center[2]*mat[2][0] + mat[3][0]);
00105          center[1] = (T)(m_center[0]*mat[0][1] + m_center[1]*mat[1][1] +
00106                          m_center[2]*mat[2][1] + mat[3][1]);
00107          center[2] = (T)(m_center[0]*mat[0][2] + m_center[1]*mat[1][2] +
00108                          m_center[2]*mat[2][2] + mat[3][2]);
00109          m_center = center;
00110 
00111          // STILL NEED TO DO THE SCALE for the radius
00112       }
00113 
00114    // ---------------------------------------------------------
00115    // generate bounding spheres from other volumes
00116    void computeFromBox(const sglBoxBound &box);
00117 
00118    void expandToInclude(const sglSphereBound<T> &sphere);
00119 
00120    // ---------------------------------------------------------
00121    // intersection routines
00122    template <class S>
00123    IntersectResultEnum intersect(sglSegment<S> &ray) const
00124       {
00125          // check special cases of bounding sphere
00126          if (isEmpty()) return eOUTSIDE;
00127          if (isInfinite()) return eINSIDE;
00128 
00129          // if ray starts inside sphere return inside
00130          sglVec3<S> eo = m_center - ray.getPos();
00131          //cout << "eo = " << eo << endl;
00132          double d_sqr = eo.dot(eo);
00133          double r_sqr = m_radius*m_radius;
00134          if (d_sqr < r_sqr)
00135          {
00136             return eINSIDE;
00137          }
00138 
00139          // ray starts outside now find out if it crosses into sphere
00140          double v = eo.dot(ray.getDir());
00141          //cout << "eo.dot(dir) = " << v << endl;
00142          if ((v < 0) || (v > (m_radius + ray.getLen())))
00143          {
00144             return eOUTSIDE;
00145          }
00146 
00147          double disc = r_sqr - d_sqr + v*v;
00148          //cout << "disc = " << disc << endl;
00149 
00150          if (disc < 0)
00151          {
00152             return eOUTSIDE;
00153          }
00154          else
00155          {
00156             double new_len = v - sqrt(disc);
00157             if (ray.getLen() < new_len)
00158             {
00159                return eOUTSIDE;
00160             }
00161             else
00162             {
00163                ray.setLen(new_len);
00164                return eINTERSECT;
00165             }
00166          }
00167       }
00168 
00169    template <class S>
00170    IntersectResultEnum intersect(const sglPlane<S> &plane) const
00171       {
00172          // by definition a plane cuts the space in two parts
00173 
00174          // an infinite sphere is always bisected
00175          if (m_radius < 0.0)  return eINTERSECT;
00176 
00177          // an empty sphere is culled, so it is outside
00178          if (m_radius == 0.0) return eOUTSIDE;
00179 
00180          // check a finite sphere
00181          T p = (T)plane.signedDistance(m_center);
00182 
00183          if (p - m_radius > 0.0)      return eINSIDE;
00184          else if (p + m_radius < 0.0) return eOUTSIDE;
00185          else                         return eINTERSECT;
00186       }
00187 
00188    template <class S>
00189    IntersectResultEnum intersect(const sglPolytope<S> &ptope) const
00190       {
00191          // if sphere is infinite set all cull flags back on and return
00192          // eINTERSECT (basically reset the intersection
00193          if (isInfinite())
00194          {
00195             return eINTERSECT;
00196          }
00197 
00198          bool intersect_flag = false;
00199 
00200          for (unsigned int i=0; i<ptope.getNumPlanes(); i++)
00201          {
00202             IntersectResultEnum result = intersect(ptope.getPlane(i));
00203             if (result == eOUTSIDE)
00204             {
00205                return eOUTSIDE;
00206             }
00207             else if (result == eINTERSECT)
00208             {
00209                intersect_flag = true;
00210             }
00211          }
00212 
00213          if (!intersect_flag)
00214          {
00215             return eINSIDE;
00216          }
00217 
00218          // note: this is not optimal as we may be outside at a corner and
00219          // still return eINTERSECT
00220          return eINTERSECT;
00221       }
00222 
00223    template <class S>
00224    IntersectResultEnum intersect(const sglPolytope<S> &ptope,
00225                                  unsigned int &cull_flags) const
00226       {
00227          // if sphere is infinite set all cull flags back on and return
00228          // eINTERSECT (basically reset the intersection
00229          if (isInfinite())
00230          {
00231             for (unsigned int i=0; i<ptope.getNumPlanes(); i++)
00232             {
00233                cull_flags |= (1<<i);
00234             }
00235             return eINTERSECT;
00236          }
00237 
00238          unsigned int new_flags = 0;
00239 
00240          for (unsigned int i=0; i<ptope.getNumPlanes(); i++)
00241          {
00242             // do the intersection test if this plane is still active as
00243             // indicated by a bit in the cull_flags bit field;
00244             if (cull_flags & (1<<i))
00245             {
00246                IntersectResultEnum result = intersect(ptope.getPlane(i));
00247                if (result == eOUTSIDE)
00248                {
00249                   cull_flags=0;
00250                   return eOUTSIDE;
00251                }
00252                else if (result == eINTERSECT)
00253                {
00254                   new_flags |= (1<<i);
00255                }
00256             }
00257          }
00258 
00259          if (new_flags == 0)
00260          {
00261             cull_flags=0;
00262             return eINSIDE;
00263          }
00264 
00265          // note: this is not optimal as we may be outside at a corner and
00266          // still return eINTERSECT
00267          cull_flags = new_flags;
00268          return eINTERSECT;
00269       }
00270 
00271    //bool contains(const sglVec3f& pnt) const;
00272    //bool contains(const sglSphereBound& sph) const;
00273 
00274    // ---------------------------------------------------------
00275    // Informational output
00276    void drawImmediate() const;
00277 
00278    friend ostream &operator<<(ostream &ostrm, const sglSphereBound<T> &sphere)
00279       {
00280          if (sphere.isEmpty())
00281             return (ostrm << "bsphere: [empty]");
00282          if (sphere.isInfinite())
00283             return (ostrm << "bsphere: [infinite]");
00284 
00285          return (ostrm << "bsphere:  [" << setprecision(12)
00286                  << sphere.m_radius << setprecision(6) << ", "
00287                  << sphere.m_center << "]");
00288       }
00289 
00290 protected:
00291    T m_radius;
00292    sglVec3<T> m_center;
00293 };
00294 
00295 
00296 //----------------------------------------------------------------------------
00297 // convenience types:
00298 //    template class 'should' only be float or double
00299 
00301 typedef sglSphereBound<float>  sglSphereBoundf;
00303 typedef sglSphereBound<double> sglSphereBoundd;
00304 
00305 #endif

Generated at Mon Jul 1 18:00:05 2002 for SGL by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001