/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #ifndef OSG_PLANE #define OSG_PLANE 1 #include #include #include #include #include #include #include namespace osg { /** A plane class. It can be used to represent an infinite plane.*/ class OSG_EXPORT Plane { public: #ifdef OSG_USE_FLOAT_PLANE /** Type of Plane class.*/ typedef float value_type; typedef Vec3f Vec3_type; typedef Vec4f Vec4_type; #else /** Type of Plane class.*/ typedef double value_type; typedef Vec3d Vec3_type; typedef Vec4d Vec4_type; #endif /** Number of vector components. */ enum { num_components = 3 }; inline Plane() { _fv[0]=0.0; _fv[1]=0.0; _fv[2]=0.0; _fv[3]=0.0; _lowerBBCorner = 0; _upperBBCorner = 0; } inline Plane(const Plane& pl) { set(pl); } inline Plane(value_type a,value_type b,value_type c,value_type d) { set(a,b,c,d); } inline Plane(const Vec4f& vec) { set(vec); } inline Plane(const Vec4d& vec) { set(vec); } inline Plane(const Vec3_type& norm,value_type d) { set(norm,d); } inline Plane(const Vec3_type& v1, const Vec3_type& v2, const Vec3_type& v3) { set(v1,v2,v3); } inline Plane(const Vec3_type& norm, const Vec3_type& point) { set(norm,point); } inline Plane& operator = (const Plane& pl) { if (&pl==this) return *this; set(pl); return *this; } inline void set(const Plane& pl) { _fv[0]=pl._fv[0]; _fv[1]=pl._fv[1]; _fv[2]=pl._fv[2]; _fv[3]=pl._fv[3]; calculateUpperLowerBBCorners(); } inline void set(value_type a, value_type b, value_type c, value_type d) { _fv[0]=a; _fv[1]=b; _fv[2]=c; _fv[3]=d; calculateUpperLowerBBCorners(); } inline void set(const Vec4f& vec) { set(vec[0],vec[1],vec[2],vec[3]); } inline void set(const Vec4d& vec) { set(vec[0],vec[1],vec[2],vec[3]); } inline void set(const Vec3_type& norm, double d) { set(norm[0],norm[1],norm[2],d); } inline void set(const Vec3_type& v1, const Vec3_type& v2, const Vec3_type& v3) { Vec3_type norm = (v2-v1)^(v3-v2); value_type length = norm.length(); if (length>1e-6) norm/= length; else norm.set(0.0,0.0,0.0); set(norm[0],norm[1],norm[2],-(v1*norm)); } inline void set(const Vec3_type& norm, const Vec3_type& point) { value_type d = -norm[0]*point[0] - norm[1]*point[1] - norm[2]*point[2]; set(norm[0],norm[1],norm[2],d); } /** flip/reverse the orientation of the plane.*/ inline void flip() { _fv[0] = -_fv[0]; _fv[1] = -_fv[1]; _fv[2] = -_fv[2]; _fv[3] = -_fv[3]; calculateUpperLowerBBCorners(); } inline void makeUnitLength() { value_type inv_length = 1.0 / sqrt(_fv[0]*_fv[0] + _fv[1]*_fv[1]+ _fv[2]*_fv[2]); _fv[0] *= inv_length; _fv[1] *= inv_length; _fv[2] *= inv_length; _fv[3] *= inv_length; } /** calculate the upper and lower bounding box corners to be used * in the intersect(BoundingBox&) method for speeding calculations.*/ inline void calculateUpperLowerBBCorners() { _upperBBCorner = (_fv[0]>=0.0?1:0) | (_fv[1]>=0.0?2:0) | (_fv[2]>=0.0?4:0); _lowerBBCorner = (~_upperBBCorner)&7; } inline bool valid() const { return !isNaN(); } inline bool isNaN() const { return osg::isNaN(_fv[0]) || osg::isNaN(_fv[1]) || osg::isNaN(_fv[2]) || osg::isNaN(_fv[3]); } inline bool operator == (const Plane& plane) const { return _fv[0]==plane._fv[0] && _fv[1]==plane._fv[1] && _fv[2]==plane._fv[2] && _fv[3]==plane._fv[3]; } inline bool operator != (const Plane& plane) const { return _fv[0]!=plane._fv[0] || _fv[1]!=plane._fv[1] || _fv[2]!=plane._fv[2] || _fv[3]!=plane._fv[3]; } inline bool operator < (const Plane& plane) const { if (_fv[0]plane._fv[0]) return false; else if (_fv[1]plane._fv[1]) return false; else if (_fv[2]plane._fv[2]) return false; else return (_fv[3]& vertices) const { if (vertices.empty()) return -1; int noAbove = 0; int noBelow = 0; int noOn = 0; for(std::vector::const_iterator itr=vertices.begin(); itr != vertices.end(); ++itr) { float d = distance(*itr); if (d>0.0f) ++noAbove; else if (d<0.0f) ++noBelow; else ++noOn; } if (noAbove>0) { if (noBelow>0) return 0; else return 1; } return -1; // treat points on line as outside... } /** intersection test between plane and vertex list return 1 if the bs is completely above plane, return 0 if the bs intersects the plane, return -1 if the bs is completely below the plane.*/ inline int intersect(const std::vector& vertices) const { if (vertices.empty()) return -1; int noAbove = 0; int noBelow = 0; int noOn = 0; for(std::vector::const_iterator itr=vertices.begin(); itr != vertices.end(); ++itr) { float d = distance(*itr); if (d>0.0f) ++noAbove; else if (d<0.0f) ++noBelow; else ++noOn; } if (noAbove>0) { if (noBelow>0) return 0; else return 1; } return -1; // treat points on line as outside... } /** intersection test between plane and bounding sphere. return 1 if the bs is completely above plane, return 0 if the bs intersects the plane, return -1 if the bs is completely below the plane.*/ inline int intersect(const BoundingSphere& bs) const { float d = distance(bs.center()); if (d>bs.radius()) return 1; else if (d<-bs.radius()) return -1; else return 0; } /** intersection test between plane and bounding sphere. return 1 if the bs is completely above plane, return 0 if the bs intersects the plane, return -1 if the bs is completely below the plane.*/ inline int intersect(const BoundingBox& bb) const { // if lowest point above plane than all above. if (distance(bb.corner(_lowerBBCorner))>0.0f) return 1; // if highest point is below plane then all below. if (distance(bb.corner(_upperBBCorner))<0.0f) return -1; // d_lower<=0.0f && d_upper>=0.0f // therefore must be crossing plane. return 0; } /** Transform the plane by matrix. Note, this operation carries out * the calculation of the inverse of the matrix since a plane * must be multiplied by the inverse transposed to transform it. This * make this operation expensive. If the inverse has been already * calculated elsewhere then use transformProvidingInverse() instead. * See http://www.worldserver.com/turk/computergraphics/NormalTransformations.pdf*/ inline void transform(const osg::Matrix& matrix) { osg::Matrix inverse; inverse.invert(matrix); transformProvidingInverse(inverse); } /** Transform the plane by providing a pre inverted matrix. * see transform for details. */ inline void transformProvidingInverse(const osg::Matrix& matrix) { // note pre multiplications, which effectively transposes matrix. Vec4_type vec(_fv[0],_fv[1],_fv[2],_fv[3]); vec = matrix * vec; set(vec); makeUnitLength(); } protected: /** Vec member variable. */ value_type _fv[4]; // variables cached to optimize calcs against bounding boxes. unsigned int _upperBBCorner; unsigned int _lowerBBCorner; }; } // end of namespace #endif