1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
22#include <osg/BoundingSphere>
23#include <osg/BoundingBox>
29/** @brief A plane class. It can be used to represent an infinite plane.
31 * The infinite plane is described by an implicit plane equation a*x+b*y+c*z+d = 0. Though it is not mandatory that
32 * a^2+b^2+c^2 = 1 is fulfilled in general some methods require it (@see osg::Plane::distance). */
38#ifdef OSG_USE_FLOAT_PLANE
39 /** Type of Plane class.*/
40 typedef float value_type;
41 typedef Vec3f Vec3_type;
42 typedef Vec4f Vec4_type;
44 /** Type of Plane class.*/
45 typedef double value_type;
46 typedef Vec3d Vec3_type;
47 typedef Vec4d Vec4_type;
50 /** Number of vector components. */
51 enum { num_components = 3 };
54 /// Default constructor
55 /** The default constructor initializes all values to zero.
56 * @warning Although the method osg::Plane::valid() will return true after the default constructors call the plane
57 * is mathematically invalid! Default data do not describe a valid plane. */
58 inline Plane() { _fv[0]=0.0; _fv[1]=0.0; _fv[2]=0.0; _fv[3]=0.0; _lowerBBCorner = 0; _upperBBCorner = 0; }
59 inline Plane(const Plane& pl) { set(pl); }
61 /** The plane is described as a*x+b*y+c*z+d = 0.
62 * @remark You may call osg::Plane::MakeUnitLength afterwards if the passed values are not normalized. */
63 inline Plane(value_type a,value_type b,value_type c,value_type d) { set(a,b,c,d); }
66 /** The plane can also be described as vec*[x,y,z,1].
67 * @remark You may call osg::Plane::MakeUnitLength afterwards if the passed values are not normalized. */
68 inline Plane(const Vec4f& vec) { set(vec); }
70 /** The plane can also be described as vec*[x,y,z,1].
71 * @remark You may call osg::Plane::MakeUnitLength afterwards if the passed values are not normalized. */
72 inline Plane(const Vec4d& vec) { set(vec); }
75 /** This constructor initializes the internal values directly without any checking or manipulation.
76 * @param norm The normal of the plane.
77 * @param d The negative distance from the point of origin to the plane.
78 * @remark You may call osg::Plane::MakeUnitLength afterwards if the passed normal was not normalized. */
79 inline Plane(const Vec3_type& norm,value_type d) { set(norm,d); }
82 /** This constructor calculates from the three points describing an infinite plane the internal values.
83 * @param v1 Point in the plane.
84 * @param v2 Point in the plane.
85 * @param v3 Point in the plane.
86 * @remark After this constructor call the plane's normal is normalized in case the three points described a mathematically
88 * @remark The normal is determined by building the cross product of (v2-v1) ^ (v3-v2). */
89 inline Plane(const Vec3_type& v1, const Vec3_type& v2, const Vec3_type& v3) { set(v1,v2,v3); }
92 /** This constructor initializes the internal values directly without any checking or manipulation.
93 * @param norm The normal of the plane.
94 * @param point A point of the plane.
95 * @remark You may call osg::Plane::MakeUnitLength afterwards if the passed normal was not normalized. */
96 inline Plane(const Vec3_type& norm, const Vec3_type& point) { set(norm,point); }
98 inline Plane& operator = (const Plane& pl)
100 if (&pl==this) return *this;
105 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(); }
106 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(); }
108 inline void set(const Vec4f& vec) { set(vec[0],vec[1],vec[2],vec[3]); }
109 inline void set(const Vec4d& vec) { set(vec[0],vec[1],vec[2],vec[3]); }
111 inline void set(const Vec3_type& norm, double d) { set(norm[0],norm[1],norm[2],d); }
113 inline void set(const Vec3_type& v1, const Vec3_type& v2, const Vec3_type& v3)
115 Vec3_type norm = (v2-v1)^(v3-v2);
116 value_type length = norm.length();
117 if (length>1e-6) norm/= length;
118 else norm.set(0.0,0.0,0.0);
119 set(norm[0],norm[1],norm[2],-(v1*norm));
122 inline void set(const Vec3_type& norm, const Vec3_type& point)
124 value_type d = -norm[0]*point[0] - norm[1]*point[1] - norm[2]*point[2];
125 set(norm[0],norm[1],norm[2],d);
128 /** flip/reverse the orientation of the plane.*/
135 calculateUpperLowerBBCorners();
138 /** This method multiplies the coefficients of the plane equation with a constant factor so that the
139 * equation a^2+b^2+c^2 = 1 holds. */
140 inline void makeUnitLength()
142 value_type inv_length = 1.0 / sqrt(_fv[0]*_fv[0] + _fv[1]*_fv[1]+ _fv[2]*_fv[2]);
143 _fv[0] *= inv_length;
144 _fv[1] *= inv_length;
145 _fv[2] *= inv_length;
146 _fv[3] *= inv_length;
149 /** calculate the upper and lower bounding box corners to be used
150 * in the intersect(BoundingBox&) method for speeding calculations.*/
151 inline void calculateUpperLowerBBCorners()
153 _upperBBCorner = (_fv[0]>=0.0?1:0) |
157 _lowerBBCorner = (~_upperBBCorner)&7;
161 /// Checks if all internal values describing the plane have valid numbers
162 /** @warning This method does not check if the plane is mathematically correctly described!
163 * @remark The only case where all elements have valid numbers and the plane description is invalid occurs if the plane's normal
165 inline bool valid() const { return !isNaN(); }
166 inline bool isNaN() const { return osg::isNaN(_fv[0]) || osg::isNaN(_fv[1]) || osg::isNaN(_fv[2]) || osg::isNaN(_fv[3]); }
168 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]; }
170 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]; }
172 /** A plane is said to be smaller than another plane if the first non-identical element of the internal array is smaller than the
173 * corresponding element of the other plane. */
174 inline bool operator < (const Plane& plane) const
176 if (_fv[0]<plane._fv[0]) return true;
177 else if (_fv[0]>plane._fv[0]) return false;
178 else if (_fv[1]<plane._fv[1]) return true;
179 else if (_fv[1]>plane._fv[1]) return false;
180 else if (_fv[2]<plane._fv[2]) return true;
181 else if (_fv[2]>plane._fv[2]) return false;
182 else return (_fv[3]<plane._fv[3]);
186 inline value_type* ptr() { return _fv; }
187 inline const value_type* ptr() const { return _fv; }
189 inline Vec4_type asVec4() const { return Vec4_type(_fv[0],_fv[1],_fv[2],_fv[3]); }
191 inline value_type& operator [] (unsigned int i) { return _fv[i]; }
192 inline value_type operator [] (unsigned int i) const { return _fv[i]; }
195 inline Vec3_type getNormal() const { return Vec3_type(_fv[0],_fv[1],_fv[2]); }
197 /** Calculate the distance between a point and the plane.
198 * @remark This method only leads to real distance values if the plane's norm is 1.
199 * @sa osg::Plane::makeUnitLength */
200 inline float distance(const osg::Vec3f& v) const
207 /** Calculate the distance between a point and the plane.
208 * @remark This method only leads to real distance values if the plane's norm is 1.
209 * @sa osg::Plane::makeUnitLength */
210 inline double distance(const osg::Vec3d& v) const
218 /** calculate the dot product of the plane normal and a point.*/
219 inline float dotProductNormal(const osg::Vec3f& v) const
226 /** calculate the dot product of the plane normal and a point.*/
227 inline double dotProductNormal(const osg::Vec3d& v) const
234 /** intersection test between plane and vertex list
235 return 1 if the bs is completely above plane,
236 return 0 if the bs intersects the plane,
237 return -1 if the bs is completely below the plane.*/
238 inline int intersect(const std::vector<Vec3f>& vertices) const
240 if (vertices.empty()) return -1;
245 for(std::vector<Vec3f>::const_iterator itr=vertices.begin();
246 itr != vertices.end();
249 float d = distance(*itr);
250 if (d>0.0f) ++noAbove;
251 else if (d<0.0f) ++noBelow;
257 if (noBelow>0) return 0;
260 return -1; // treat points on line as outside...
263 /** intersection test between plane and vertex list
264 return 1 if the bs is completely above plane,
265 return 0 if the bs intersects the plane,
266 return -1 if the bs is completely below the plane.*/
267 inline int intersect(const std::vector<Vec3d>& vertices) const
269 if (vertices.empty()) return -1;
274 for(std::vector<Vec3d>::const_iterator itr=vertices.begin();
275 itr != vertices.end();
278 double d = distance(*itr);
279 if (d>0.0) ++noAbove;
280 else if (d<0.0) ++noBelow;
286 if (noBelow>0) return 0;
289 return -1; // treat points on line as outside...
292 /** intersection test between plane and bounding sphere.
293 return 1 if the bs is completely above plane,
294 return 0 if the bs intersects the plane,
295 return -1 if the bs is completely below the plane.*/
296 inline int intersect(const BoundingSphere& bs) const
298 float d = distance(bs.center());
300 if (d>bs.radius()) return 1;
301 else if (d<-bs.radius()) return -1;
306 /** intersection test between plane and bounding sphere.
307 return 1 if the bs is completely above plane,
308 return 0 if the bs intersects the plane,
309 return -1 if the bs is completely below the plane.*/
310 inline int intersect(const BoundingBox& bb) const
312 // if lowest point above plane than all above.
313 if (distance(bb.corner(_lowerBBCorner))>0.0f) return 1;
315 // if highest point is below plane then all below.
316 if (distance(bb.corner(_upperBBCorner))<0.0f) return -1;
318 // d_lower<=0.0f && d_upper>=0.0f
319 // therefore must be crossing plane.
324 /** Transform the plane by matrix. Note, this operation carries out
325 * the calculation of the inverse of the matrix since a plane
326 * must be multiplied by the inverse transposed to transform it. This
327 * make this operation expensive. If the inverse has been already
328 * calculated elsewhere then use transformProvidingInverse() instead.
329 * See http://www.worldserver.com/turk/computergraphics/NormalTransformations.pdf*/
330 inline void transform(const osg::Matrix& matrix)
333 inverse.invert(matrix);
334 transformProvidingInverse(inverse);
337 /** Transform the plane by providing a pre inverted matrix.
338 * see transform for details. */
339 inline void transformProvidingInverse(const osg::Matrix& matrix)
341 // note pre multiplications, which effectively transposes matrix.
342 Vec4_type vec(_fv[0],_fv[1],_fv[2],_fv[3]);
350 /** Vec member variable. */
353 // variables cached to optimize calcs against bounding boxes.
354 unsigned int _upperBBCorner;
355 unsigned int _lowerBBCorner;