345810ef22
Performance tests on big models did not indicate any performance penalty in using doubles over floats, so the move to doubles should mainly impact precision improvements for whole earth databases. Also made improvements to osgUtil::PlaneIntersector and osgSim::ElevationSlice classes
290 lines
10 KiB
C++
290 lines
10 KiB
C++
/* -*-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 <osg/Export>
|
|
#include <osg/Vec3>
|
|
#include <osg/Vec4>
|
|
#include <osg/Matrix>
|
|
#include <osg/BoundingSphere>
|
|
#include <osg/BoundingBox>
|
|
|
|
#include <vector>
|
|
|
|
#define OSG_USE_DOUBLE_PLANE 1
|
|
|
|
namespace osg {
|
|
|
|
/** A plane class. It can be used to represent an infinite plane.*/
|
|
class OSG_EXPORT Plane
|
|
{
|
|
|
|
public:
|
|
|
|
#ifdef OSG_USE_DOUBLE_PLANE
|
|
/** Type of Plane class.*/
|
|
typedef double value_type;
|
|
typedef Vec3d Vec3_type;
|
|
typedef Vec4d Vec4_type;
|
|
#else
|
|
/** Type of Plane class.*/
|
|
typedef float value_type;
|
|
typedef Vec3f Vec3_type;
|
|
typedef Vec4f 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 true;
|
|
else if (_fv[0]>plane._fv[0]) return false;
|
|
else if (_fv[1]<plane._fv[1]) return true;
|
|
else if (_fv[1]>plane._fv[1]) return false;
|
|
else if (_fv[2]<plane._fv[2]) return true;
|
|
else if (_fv[2]>plane._fv[2]) return false;
|
|
else return (_fv[3]<plane._fv[3]);
|
|
}
|
|
|
|
|
|
inline value_type* ptr() { return _fv; }
|
|
inline const value_type* ptr() const { return _fv; }
|
|
|
|
inline Vec4_type asVec4() const { return Vec4(_fv[0],_fv[1],_fv[2],_fv[3]); }
|
|
|
|
inline value_type& operator [] (unsigned int i) { return _fv[i]; }
|
|
inline value_type operator [] (unsigned int i) const { return _fv[i]; }
|
|
|
|
|
|
inline Vec3_type getNormal() const { return Vec3_type(_fv[0],_fv[1],_fv[2]); }
|
|
|
|
/** calculate the distance between a point and the plane.*/
|
|
inline float distance(const osg::Vec3f& v) const
|
|
{
|
|
return _fv[0]*v.x()+
|
|
_fv[1]*v.y()+
|
|
_fv[2]*v.z()+
|
|
_fv[3];
|
|
}
|
|
|
|
inline float distance(const osg::Vec3d& v) const
|
|
{
|
|
return _fv[0]*v.x()+
|
|
_fv[1]*v.y()+
|
|
_fv[2]*v.z()+
|
|
_fv[3];
|
|
}
|
|
|
|
/** calculate the dot product of the plane normal and a point.*/
|
|
inline float dotProductNormal(const osg::Vec3f& v) const
|
|
{
|
|
return _fv[0]*v.x()+
|
|
_fv[1]*v.y()+
|
|
_fv[2]*v.z();
|
|
}
|
|
|
|
/** calculate the dot product of the plane normal and a point.*/
|
|
inline float dotProductNormal(const osg::Vec3d& v) const
|
|
{
|
|
return _fv[0]*v.x()+
|
|
_fv[1]*v.y()+
|
|
_fv[2]*v.z();
|
|
}
|
|
|
|
/** 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<Vec3>& vertices) const
|
|
{
|
|
if (vertices.empty()) return -1;
|
|
|
|
int noAbove = 0;
|
|
int noBelow = 0;
|
|
int noOn = 0;
|
|
for(std::vector<Vec3>::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 varaible. */
|
|
value_type _fv[4];
|
|
|
|
// variables cached to optimize calcs against bounding boxes.
|
|
unsigned int _upperBBCorner;
|
|
unsigned int _lowerBBCorner;
|
|
|
|
|
|
};
|
|
|
|
} // end of namespace
|
|
|
|
#endif
|