| 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 | |
|---|
| 27 | namespace 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). */ |
|---|
| 33 | class 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 |
|---|