openscenegraph
Plane
Go to the documentation of this file.
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
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.
7 *
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.
12*/
13
14#ifndef OSG_PLANE
15#define OSG_PLANE 1
16
17#include <osg/Config>
18#include <osg/Export>
19#include <osg/Vec3>
20#include <osg/Vec4>
21#include <osg/Matrix>
22#include <osg/BoundingSphere>
23#include <osg/BoundingBox>
24
25#include <vector>
26
27namespace osg {
28
29/** @brief A plane class. It can be used to represent an infinite plane.
30 *
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). */
33class OSG_EXPORT Plane
34{
35
36 public:
37
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;
43#else
44 /** Type of Plane class.*/
45 typedef double value_type;
46 typedef Vec3d Vec3_type;
47 typedef Vec4d Vec4_type;
48#endif
49
50 /** Number of vector components. */
51 enum { num_components = 3 };
52
53
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); }
60 /// Constructor
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); }
64
65 /// Constructor
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); }
69 /// Constructor
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); }
73
74 /// Constructor
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); }
80
81 /// Constructor
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
87 * valid plane.
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); }
90
91 /// Constructor
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); }
97
98 inline Plane& operator = (const Plane& pl)
99 {
100 if (&pl==this) return *this;
101 set(pl);
102 return *this;
103 }
104
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(); }
107
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]); }
110
111 inline void set(const Vec3_type& norm, double d) { set(norm[0],norm[1],norm[2],d); }
112
113 inline void set(const Vec3_type& v1, const Vec3_type& v2, const Vec3_type& v3)
114 {
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));
120 }
121
122 inline void set(const Vec3_type& norm, const Vec3_type& point)
123 {
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);
126 }
127
128 /** flip/reverse the orientation of the plane.*/
129 inline void flip()
130 {
131 _fv[0] = -_fv[0];
132 _fv[1] = -_fv[1];
133 _fv[2] = -_fv[2];
134 _fv[3] = -_fv[3];
135 calculateUpperLowerBBCorners();
136 }
137
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()
141 {
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;
147 }
148
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()
152 {
153 _upperBBCorner = (_fv[0]>=0.0?1:0) |
154 (_fv[1]>=0.0?2:0) |
155 (_fv[2]>=0.0?4:0);
156
157 _lowerBBCorner = (~_upperBBCorner)&7;
158
159 }
160
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
164 * is zero. */
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]); }
167
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]; }
169
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]; }
171
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
175 {
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]);
183 }
184
185
186 inline value_type* ptr() { return _fv; }
187 inline const value_type* ptr() const { return _fv; }
188
189 inline Vec4_type asVec4() const { return Vec4_type(_fv[0],_fv[1],_fv[2],_fv[3]); }
190
191 inline value_type& operator [] (unsigned int i) { return _fv[i]; }
192 inline value_type operator [] (unsigned int i) const { return _fv[i]; }
193
194
195 inline Vec3_type getNormal() const { return Vec3_type(_fv[0],_fv[1],_fv[2]); }
196
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
201 {
202 return _fv[0]*v.x()+
203 _fv[1]*v.y()+
204 _fv[2]*v.z()+
205 _fv[3];
206 }
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
211 {
212 return _fv[0]*v.x()+
213 _fv[1]*v.y()+
214 _fv[2]*v.z()+
215 _fv[3];
216 }
217
218 /** calculate the dot product of the plane normal and a point.*/
219 inline float dotProductNormal(const osg::Vec3f& v) const
220 {
221 return _fv[0]*v.x()+
222 _fv[1]*v.y()+
223 _fv[2]*v.z();
224 }
225
226 /** calculate the dot product of the plane normal and a point.*/
227 inline double dotProductNormal(const osg::Vec3d& v) const
228 {
229 return _fv[0]*v.x()+
230 _fv[1]*v.y()+
231 _fv[2]*v.z();
232 }
233
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
239 {
240 if (vertices.empty()) return -1;
241
242 int noAbove = 0;
243 int noBelow = 0;
244 int noOn = 0;
245 for(std::vector<Vec3f>::const_iterator itr=vertices.begin();
246 itr != vertices.end();
247 ++itr)
248 {
249 float d = distance(*itr);
250 if (d>0.0f) ++noAbove;
251 else if (d<0.0f) ++noBelow;
252 else ++noOn;
253 }
254
255 if (noAbove>0)
256 {
257 if (noBelow>0) return 0;
258 else return 1;
259 }
260 return -1; // treat points on line as outside...
261 }
262
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
268 {
269 if (vertices.empty()) return -1;
270
271 int noAbove = 0;
272 int noBelow = 0;
273 int noOn = 0;
274 for(std::vector<Vec3d>::const_iterator itr=vertices.begin();
275 itr != vertices.end();
276 ++itr)
277 {
278 double d = distance(*itr);
279 if (d>0.0) ++noAbove;
280 else if (d<0.0) ++noBelow;
281 else ++noOn;
282 }
283
284 if (noAbove>0)
285 {
286 if (noBelow>0) return 0;
287 else return 1;
288 }
289 return -1; // treat points on line as outside...
290 }
291
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
297 {
298 float d = distance(bs.center());
299
300 if (d>bs.radius()) return 1;
301 else if (d<-bs.radius()) return -1;
302 else return 0;
303 }
304
305
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
311 {
312 // if lowest point above plane than all above.
313 if (distance(bb.corner(_lowerBBCorner))>0.0f) return 1;
314
315 // if highest point is below plane then all below.
316 if (distance(bb.corner(_upperBBCorner))<0.0f) return -1;
317
318 // d_lower<=0.0f && d_upper>=0.0f
319 // therefore must be crossing plane.
320 return 0;
321
322 }
323
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)
331 {
332 osg::Matrix inverse;
333 inverse.invert(matrix);
334 transformProvidingInverse(inverse);
335 }
336
337 /** Transform the plane by providing a pre inverted matrix.
338 * see transform for details. */
339 inline void transformProvidingInverse(const osg::Matrix& matrix)
340 {
341 // note pre multiplications, which effectively transposes matrix.
342 Vec4_type vec(_fv[0],_fv[1],_fv[2],_fv[3]);
343 vec = matrix * vec;
344 set(vec);
345 makeUnitLength();
346 }
347
348 protected:
349
350 /** Vec member variable. */
351 value_type _fv[4];
352
353 // variables cached to optimize calcs against bounding boxes.
354 unsigned int _upperBBCorner;
355 unsigned int _lowerBBCorner;
356
357
358};
359
360} // end of namespace
361
362#endif