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