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

sglPlane.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: sglPlane.hpp
00021  *  Created: 2 January 1999
00022  *  Summary: defines a plane in 3D space for defining polytopes
00023  *****************************************************************************/
00024 
00025 #ifndef __SGL_PLANE_HPP
00026 #define __SGL_PLANE_HPP
00027 
00028 #include <assert.h>
00029 #include <sgl.h>
00030 #include <sglVector.hpp>
00031 #include <sglMatrix.hpp>
00032 
00033 //----------------------------------------------------------------------------
00034 // convenience types:
00035 //    template class 'should' only be float or double
00036 
00037 template <class T> class sglPlane;
00038 
00039 typedef sglPlane<float>  sglPlanef;
00040 typedef sglPlane<double> sglPlaned;
00041 
00042 //----------------------------------------------------------------------------
00043 template <class T>
00044 class sglPlane
00045 {
00046 public:
00047    sglPlane() {};
00048    sglPlane(const sglPlane &rhs) :
00049          m_normal(rhs.m_normal), m_distance(rhs.m_distance) {};
00050 
00051    sglPlane(const sglVec3<T> &n, T d) :
00052          m_normal(n), m_distance(d) { normalize(); }
00053 
00054    sglPlane(T x, T y, T z, T d) :
00055          m_normal(x,y,z), m_distance(d) { normalize(); }
00056 
00057    ~sglPlane() {};
00058 
00059 #ifndef WIN32
00060    inline sglPlane& operator=(const sglPlane &rhs)
00061       {
00062          if (this != &rhs)
00063          {
00064             m_normal   = rhs.m_normal;
00065             m_distance = rhs.m_distance;
00066          }
00067          return *this;
00068       }
00069 #endif
00070 
00071    template <class S>
00072    inline sglPlane<T>& operator=(const sglPlane<S> &rhs)
00073       {
00074          if (this != (sglPlane<T>*) &rhs)
00075          {
00076             m_normal   = rhs.getNormal();
00077             m_distance = rhs.getDistance();
00078          }
00079          return *this;
00080       }
00081 
00082    template <class S>
00083    inline void set(const sglVec3<S>& normal, T distance)
00084       {
00085          m_normal = normal; m_distance = distance; normalize();
00086       }
00087    inline const sglVec3<T>& getNormal() const { return m_normal; }
00088    inline T getDistance() const { return m_distance; }
00089 
00090    // convert plane equation to "hessian normal" form for fast distance calc. 
00091    inline void normalize()
00092       {
00093          T len = m_normal.normalize();
00094          m_distance *= (1.0/len);
00095       }
00096 
00097    // build a plane from 3 points
00098    // convention is that the points are given in direct (CCW) order
00099    bool build(const sglVec3<T>& p1,
00100               const sglVec3<T>& p2,
00101               const sglVec3<T>& p3);
00102 
00103    // get 3 points that define the plane
00104    bool getVertices(sglVec3<T>& p1, sglVec3<T>& p2, sglVec3<T>& p3) const;
00105 
00106    // apply a 3x3 transformation
00107    template <class S>
00108    inline void mul(const sglPlane<T>& p, const sglMat3<S>& m)
00109       {
00110          ::mulTranspose(p.getNormal(), m, m_normal);
00111          m_distance = p.getDistance();
00112       }
00113         
00114    // apply a 4x4 transformation
00115    template <class S>
00116    void mul(const sglPlane<T>& p, const sglMat4<S>& m)
00117       {
00118          // find out what the normal is now
00119          sglVec4<T> normal;
00120          ::mul(p.getNormal(), (T)0, m, normal);
00121          T zoom = normal.normalize();
00122 
00123          // What is the transformed distance ?
00124          sglVec3<T> translation(m[3][0],m[3][1],m[3][2]);
00125          translation *= (1.0/zoom);
00126          m_distance = p.getDistance() - (normal[0]*translation[0] +
00127                                          normal[1]*translation[1] +
00128                                          normal[2]*translation[2]);
00129          m_distance *= zoom;
00130          m_normal.set(normal[0], normal[1], normal[2]);
00131       }
00132 
00133    // apply a translation only
00134    void translate(const sglPlane<T>& p, T x, T y, T z)
00135       {
00136          m_normal = p.getNormal();
00137 
00138          m_distance = p.getDistance() - (m_normal[0]*x +
00139                                          m_normal[1]*y +
00140                                          m_normal[2]*z);
00141       }
00142 
00143    // apply a scale only VERIFY
00144    void scale(const sglPlane<T>& p, T scale)
00145       {
00146          m_normal = p.getNormal();
00147          m_distance = p.getDistance()*scale;
00148       }
00149 
00150    // apply a rotation only
00151    template <class S>
00152    void rotate(const sglPlane<T>& p, const sglMat4<S>& m)
00153       {
00154          sglVec4<T> normal;
00155          ::mul(p.getNormal(), (T)0, m, normal);
00156          T zoom = normal.normalize();
00157 
00158          m_distance = p.getDistance()*zoom;
00159          m_normal.set(normal[0], normal[1], normal[2]);
00160       }
00161    template <class S>
00162    void rotate(const sglPlane<T>& p, const sglMat3<S>& m)
00163       {
00164          sglVec3<T> normal;
00165          ::mul(p.getNormal(), m, normal);
00166          T zoom = normal.normalize();
00167 
00168          m_distance = p.getDistance()*zoom;
00169          m_normal = normal;
00170       }
00171 
00172    // compute the signed distance of a vertex
00173    template <class S>
00174    inline float signedDistance(const sglVec3<S>& p) const
00175       {
00176          return m_normal.dot(p) + m_distance;
00177       }
00178 
00179    friend ostream& operator<<(ostream& ostrm, const sglPlane<T>& p)
00180       {
00181          return (ostrm << "[" << p.getNormal() << ", "
00182                        << p.getDistance() << "]");
00183       }
00184 
00185 private:
00186    sglVec3<T> m_normal;
00187    T          m_distance;
00188 };
00189 
00190 //----------------------------------------------------------------------------
00191 //    Summary: 
00192 // Parameters: 
00193 //    Returns: 
00194 //----------------------------------------------------------------------------
00195 template <class T>
00196 inline bool sglPlane<T>::build(const sglVec3<T>& p1,
00197                                const sglVec3<T>& p2,
00198                                const sglVec3<T>& p3)
00199 {
00200    sglVec3<T> v1,v2;
00201    v1.sub(p1,p2);
00202    v2.sub(p3,p2);
00203 
00204    m_normal.cross(v1,v2);
00205    float d = m_normal.normalize();
00206    if (d == 0.f)
00207       return false;
00208 
00209    // p2 is on the plane
00210    m_distance = -(m_normal.dot(p2));
00211 
00212    return true;
00213 }
00214 
00215 //----------------------------------------------------------------------------
00216 //    Summary: 
00217 // Parameters: 
00218 //    Returns: 
00219 //----------------------------------------------------------------------------
00220 template <class T>
00221 inline bool sglPlane<T>::getVertices(sglVec3<T>& pnt1,
00222                                      sglVec3<T>& pnt2,
00223                                      sglVec3<T>& pnt3) const
00224 {
00225    // find a starting point
00226    sglVec3<T> p1,p2,p3;
00227 
00228    int index = 0;
00229    float max = SGL_ABS(m_normal[index]);
00230    if (SGL_ABS(m_normal[1]) > max)
00231    {
00232       index = 1;
00233       max = SGL_ABS(m_normal[index]);
00234    }
00235    if (SGL_ABS(m_normal[2]) > max)
00236    {
00237       index = 2;
00238    }
00239 
00240    p2.set(((index == 0) ? (-m_distance/m_normal[0]) : 0),
00241           ((index == 1) ? (-m_distance/m_normal[1]) : 0),
00242           ((index == 2) ? (-m_distance/m_normal[2]) : 0));
00243 
00244    // search for two vectors
00245    sglVec3<T> temp(((index == 0) ? 0 : 1),
00246                    ((index == 1) ? 0 : 1),
00247                    ((index == 2) ? 0 : 1));
00248 
00249    p1.cross(m_normal,temp);
00250    p3.cross(m_normal,p1);
00251 
00252    temp.cross(p1,p3);
00253         
00254    p1 += p2;
00255    p3 += p2;
00256 
00257    // check for consistency
00258    sglPlane<T> testplane;
00259    testplane.build(p1,p2,p3);
00260 
00261    sglVec3<T> n = testplane.getNormal();
00262    if (n[0]*m_normal[0] < 0)
00263    {
00264       pnt1 = p3;
00265       pnt2 = p2;
00266       pnt3 = p1;
00267    }
00268    else
00269    {
00270       pnt1 = p1;
00271       pnt2 = p2;
00272       pnt3 = p3;
00273    }
00274    return true;
00275 }
00276 
00277 #endif

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