Plane.h (11614B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #ifndef __MATH_PLANE_H__ 30 #define __MATH_PLANE_H__ 31 32 /* 33 =============================================================================== 34 35 3D plane with equation: a * x + b * y + c * z + d = 0 36 37 =============================================================================== 38 */ 39 40 41 class idVec3; 42 class idMat3; 43 44 #define ON_EPSILON 0.1f 45 #define DEGENERATE_DIST_EPSILON 1e-4f 46 47 #define SIDE_FRONT 0 48 #define SIDE_BACK 1 49 #define SIDE_ON 2 50 #define SIDE_CROSS 3 51 52 // plane sides 53 #define PLANESIDE_FRONT 0 54 #define PLANESIDE_BACK 1 55 #define PLANESIDE_ON 2 56 #define PLANESIDE_CROSS 3 57 58 // plane types 59 #define PLANETYPE_X 0 60 #define PLANETYPE_Y 1 61 #define PLANETYPE_Z 2 62 #define PLANETYPE_NEGX 3 63 #define PLANETYPE_NEGY 4 64 #define PLANETYPE_NEGZ 5 65 #define PLANETYPE_TRUEAXIAL 6 // all types < 6 are true axial planes 66 #define PLANETYPE_ZEROX 6 67 #define PLANETYPE_ZEROY 7 68 #define PLANETYPE_ZEROZ 8 69 #define PLANETYPE_NONAXIAL 9 70 71 class idPlane { 72 public: 73 idPlane(); 74 explicit idPlane( float a, float b, float c, float d ); 75 explicit idPlane( const idVec3 &normal, const float dist ); 76 explicit idPlane( const idVec3 & v0, const idVec3 & v1, const idVec3 & v2, bool fixDegenerate = false ); 77 78 float operator[]( int index ) const; 79 float & operator[]( int index ); 80 idPlane operator-() const; // flips plane 81 idPlane & operator=( const idVec3 &v ); // sets normal and sets idPlane::d to zero 82 idPlane operator+( const idPlane &p ) const; // add plane equations 83 idPlane operator-( const idPlane &p ) const; // subtract plane equations 84 idPlane operator*( const float s ) const; // scale plane 85 idPlane & operator*=( const idMat3 &m ); // Normal() *= m 86 87 bool Compare( const idPlane &p ) const; // exact compare, no epsilon 88 bool Compare( const idPlane &p, const float epsilon ) const; // compare with epsilon 89 bool Compare( const idPlane &p, const float normalEps, const float distEps ) const; // compare with epsilon 90 bool operator==( const idPlane &p ) const; // exact compare, no epsilon 91 bool operator!=( const idPlane &p ) const; // exact compare, no epsilon 92 93 void Zero(); // zero plane 94 void SetNormal( const idVec3 &normal ); // sets the normal 95 const idVec3 & Normal() const; // reference to const normal 96 idVec3 & Normal(); // reference to normal 97 float Normalize( bool fixDegenerate = true ); // only normalizes the plane normal, does not adjust d 98 bool FixDegenerateNormal(); // fix degenerate normal 99 bool FixDegeneracies( float distEpsilon ); // fix degenerate normal and dist 100 float Dist() const; // returns: -d 101 void SetDist( const float dist ); // sets: d = -dist 102 int Type() const; // returns plane type 103 104 bool FromPoints( const idVec3 &p1, const idVec3 &p2, const idVec3 &p3, bool fixDegenerate = true ); 105 bool FromVecs( const idVec3 &dir1, const idVec3 &dir2, const idVec3 &p, bool fixDegenerate = true ); 106 void FitThroughPoint( const idVec3 &p ); // assumes normal is valid 107 bool HeightFit( const idVec3 *points, const int numPoints ); 108 idPlane Translate( const idVec3 &translation ) const; 109 idPlane & TranslateSelf( const idVec3 &translation ); 110 idPlane Rotate( const idVec3 &origin, const idMat3 &axis ) const; 111 idPlane & RotateSelf( const idVec3 &origin, const idMat3 &axis ); 112 113 float Distance( const idVec3 &v ) const; 114 int Side( const idVec3 &v, const float epsilon = 0.0f ) const; 115 116 bool LineIntersection( const idVec3 &start, const idVec3 &end ) const; 117 // intersection point is start + dir * scale 118 bool RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const; 119 bool PlaneIntersection( const idPlane &plane, idVec3 &start, idVec3 &dir ) const; 120 121 int GetDimension() const; 122 123 const idVec4 & ToVec4() const; 124 idVec4 & ToVec4(); 125 const float * ToFloatPtr() const; 126 float * ToFloatPtr(); 127 const char * ToString( int precision = 2 ) const; 128 129 private: 130 float a; 131 float b; 132 float c; 133 float d; 134 }; 135 136 extern idPlane plane_origin; 137 #define plane_zero plane_origin 138 139 ID_INLINE idPlane::idPlane() { 140 } 141 142 ID_INLINE idPlane::idPlane( float a, float b, float c, float d ) { 143 this->a = a; 144 this->b = b; 145 this->c = c; 146 this->d = d; 147 } 148 149 ID_INLINE idPlane::idPlane( const idVec3 &normal, const float dist ) { 150 this->a = normal.x; 151 this->b = normal.y; 152 this->c = normal.z; 153 this->d = -dist; 154 } 155 156 ID_INLINE idPlane::idPlane( const idVec3 & v0, const idVec3 & v1, const idVec3 & v2, bool fixDegenerate ) { 157 FromPoints( v0, v1, v2, fixDegenerate ); 158 } 159 160 ID_INLINE float idPlane::operator[]( int index ) const { 161 return ( &a )[ index ]; 162 } 163 164 ID_INLINE float& idPlane::operator[]( int index ) { 165 return ( &a )[ index ]; 166 } 167 168 ID_INLINE idPlane idPlane::operator-() const { 169 return idPlane( -a, -b, -c, -d ); 170 } 171 172 ID_INLINE idPlane &idPlane::operator=( const idVec3 &v ) { 173 a = v.x; 174 b = v.y; 175 c = v.z; 176 d = 0; 177 return *this; 178 } 179 180 ID_INLINE idPlane idPlane::operator+( const idPlane &p ) const { 181 return idPlane( a + p.a, b + p.b, c + p.c, d + p.d ); 182 } 183 184 ID_INLINE idPlane idPlane::operator-( const idPlane &p ) const { 185 return idPlane( a - p.a, b - p.b, c - p.c, d - p.d ); 186 } 187 188 ID_INLINE idPlane idPlane::operator*( const float s ) const { 189 return idPlane( a * s, b * s, c * s, d * s ); 190 } 191 192 ID_INLINE idPlane &idPlane::operator*=( const idMat3 &m ) { 193 Normal() *= m; 194 return *this; 195 } 196 197 ID_INLINE bool idPlane::Compare( const idPlane &p ) const { 198 return ( a == p.a && b == p.b && c == p.c && d == p.d ); 199 } 200 201 ID_INLINE bool idPlane::Compare( const idPlane &p, const float epsilon ) const { 202 if ( idMath::Fabs( a - p.a ) > epsilon ) { 203 return false; 204 } 205 206 if ( idMath::Fabs( b - p.b ) > epsilon ) { 207 return false; 208 } 209 210 if ( idMath::Fabs( c - p.c ) > epsilon ) { 211 return false; 212 } 213 214 if ( idMath::Fabs( d - p.d ) > epsilon ) { 215 return false; 216 } 217 218 return true; 219 } 220 221 ID_INLINE bool idPlane::Compare( const idPlane &p, const float normalEps, const float distEps ) const { 222 if ( idMath::Fabs( d - p.d ) > distEps ) { 223 return false; 224 } 225 if ( !Normal().Compare( p.Normal(), normalEps ) ) { 226 return false; 227 } 228 return true; 229 } 230 231 ID_INLINE bool idPlane::operator==( const idPlane &p ) const { 232 return Compare( p ); 233 } 234 235 ID_INLINE bool idPlane::operator!=( const idPlane &p ) const { 236 return !Compare( p ); 237 } 238 239 ID_INLINE void idPlane::Zero() { 240 a = b = c = d = 0.0f; 241 } 242 243 ID_INLINE void idPlane::SetNormal( const idVec3 &normal ) { 244 a = normal.x; 245 b = normal.y; 246 c = normal.z; 247 } 248 249 ID_INLINE const idVec3 &idPlane::Normal() const { 250 return *reinterpret_cast<const idVec3 *>(&a); 251 } 252 253 ID_INLINE idVec3 &idPlane::Normal() { 254 return *reinterpret_cast<idVec3 *>(&a); 255 } 256 257 ID_INLINE float idPlane::Normalize( bool fixDegenerate ) { 258 float length = reinterpret_cast<idVec3 *>(&a)->Normalize(); 259 260 if ( fixDegenerate ) { 261 FixDegenerateNormal(); 262 } 263 return length; 264 } 265 266 ID_INLINE bool idPlane::FixDegenerateNormal() { 267 return Normal().FixDegenerateNormal(); 268 } 269 270 ID_INLINE bool idPlane::FixDegeneracies( float distEpsilon ) { 271 bool fixedNormal = FixDegenerateNormal(); 272 // only fix dist if the normal was degenerate 273 if ( fixedNormal ) { 274 if ( idMath::Fabs( d - idMath::Rint( d ) ) < distEpsilon ) { 275 d = idMath::Rint( d ); 276 } 277 } 278 return fixedNormal; 279 } 280 281 ID_INLINE float idPlane::Dist() const { 282 return -d; 283 } 284 285 ID_INLINE void idPlane::SetDist( const float dist ) { 286 d = -dist; 287 } 288 289 ID_INLINE bool idPlane::FromPoints( const idVec3 &p1, const idVec3 &p2, const idVec3 &p3, bool fixDegenerate ) { 290 Normal() = (p1 - p2).Cross( p3 - p2 ); 291 if ( Normalize( fixDegenerate ) == 0.0f ) { 292 return false; 293 } 294 d = -( Normal() * p2 ); 295 return true; 296 } 297 298 ID_INLINE bool idPlane::FromVecs( const idVec3 &dir1, const idVec3 &dir2, const idVec3 &p, bool fixDegenerate ) { 299 Normal() = dir1.Cross( dir2 ); 300 if ( Normalize( fixDegenerate ) == 0.0f ) { 301 return false; 302 } 303 d = -( Normal() * p ); 304 return true; 305 } 306 307 ID_INLINE void idPlane::FitThroughPoint( const idVec3 &p ) { 308 d = -( Normal() * p ); 309 } 310 311 ID_INLINE idPlane idPlane::Translate( const idVec3 &translation ) const { 312 return idPlane( a, b, c, d - translation * Normal() ); 313 } 314 315 ID_INLINE idPlane &idPlane::TranslateSelf( const idVec3 &translation ) { 316 d -= translation * Normal(); 317 return *this; 318 } 319 320 ID_INLINE idPlane idPlane::Rotate( const idVec3 &origin, const idMat3 &axis ) const { 321 idPlane p; 322 p.Normal() = Normal() * axis; 323 p.d = d + origin * Normal() - origin * p.Normal(); 324 return p; 325 } 326 327 ID_INLINE idPlane &idPlane::RotateSelf( const idVec3 &origin, const idMat3 &axis ) { 328 d += origin * Normal(); 329 Normal() *= axis; 330 d -= origin * Normal(); 331 return *this; 332 } 333 334 ID_INLINE float idPlane::Distance( const idVec3 &v ) const { 335 return a * v.x + b * v.y + c * v.z + d; 336 } 337 338 ID_INLINE int idPlane::Side( const idVec3 &v, const float epsilon ) const { 339 float dist = Distance( v ); 340 if ( dist > epsilon ) { 341 return PLANESIDE_FRONT; 342 } 343 else if ( dist < -epsilon ) { 344 return PLANESIDE_BACK; 345 } 346 else { 347 return PLANESIDE_ON; 348 } 349 } 350 351 ID_INLINE bool idPlane::LineIntersection( const idVec3 &start, const idVec3 &end ) const { 352 float d1, d2, fraction; 353 354 d1 = Normal() * start + d; 355 d2 = Normal() * end + d; 356 if ( d1 == d2 ) { 357 return false; 358 } 359 if ( d1 > 0.0f && d2 > 0.0f ) { 360 return false; 361 } 362 if ( d1 < 0.0f && d2 < 0.0f ) { 363 return false; 364 } 365 fraction = ( d1 / ( d1 - d2 ) ); 366 return ( fraction >= 0.0f && fraction <= 1.0f ); 367 } 368 369 ID_INLINE bool idPlane::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const { 370 float d1, d2; 371 372 d1 = Normal() * start + d; 373 d2 = Normal() * dir; 374 if ( d2 == 0.0f ) { 375 return false; 376 } 377 scale = -( d1 / d2 ); 378 return true; 379 } 380 381 ID_INLINE int idPlane::GetDimension() const { 382 return 4; 383 } 384 385 ID_INLINE const idVec4 &idPlane::ToVec4() const { 386 return *reinterpret_cast<const idVec4 *>(&a); 387 } 388 389 ID_INLINE idVec4 &idPlane::ToVec4() { 390 return *reinterpret_cast<idVec4 *>(&a); 391 } 392 393 ID_INLINE const float *idPlane::ToFloatPtr() const { 394 return reinterpret_cast<const float *>(&a); 395 } 396 397 ID_INLINE float *idPlane::ToFloatPtr() { 398 return reinterpret_cast<float *>(&a); 399 } 400 401 #endif /* !__MATH_PLANE_H__ */