]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/idlib/math/Plane.h
hello world
[icculus/iodoom3.git] / neo / idlib / math / Plane.h
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 /*
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( void );
74                                         idPlane( float a, float b, float c, float d );
75                                         idPlane( const idVec3 &normal, const float dist );
76
77         float                   operator[]( int index ) const;
78         float &                 operator[]( int index );
79         idPlane                 operator-() const;                                              // flips plane
80         idPlane &               operator=( const idVec3 &v );                   // sets normal and sets idPlane::d to zero
81         idPlane                 operator+( const idPlane &p ) const;    // add plane equations
82         idPlane                 operator-( const idPlane &p ) const;    // subtract plane equations
83         idPlane &               operator*=( const idMat3 &m );                  // Normal() *= m
84
85         bool                    Compare( const idPlane &p ) const;                                              // exact compare, no epsilon
86         bool                    Compare( const idPlane &p, const float epsilon ) const; // compare with epsilon
87         bool                    Compare( const idPlane &p, const float normalEps, const float distEps ) const;  // compare with epsilon
88         bool                    operator==(     const idPlane &p ) const;                                       // exact compare, no epsilon
89         bool                    operator!=(     const idPlane &p ) const;                                       // exact compare, no epsilon
90
91         void                    Zero( void );                                                   // zero plane
92         void                    SetNormal( const idVec3 &normal );              // sets the normal
93         const idVec3 &  Normal( void ) const;                                   // reference to const normal
94         idVec3 &                Normal( void );                                                 // reference to normal
95         float                   Normalize( bool fixDegenerate = true ); // only normalizes the plane normal, does not adjust d
96         bool                    FixDegenerateNormal( void );                    // fix degenerate normal
97         bool                    FixDegeneracies( float distEpsilon );   // fix degenerate normal and dist
98         float                   Dist( void ) const;                                             // returns: -d
99         void                    SetDist( const float dist );                    // sets: d = -dist
100         int                             Type( void ) const;                                             // returns plane type
101
102         bool                    FromPoints( const idVec3 &p1, const idVec3 &p2, const idVec3 &p3, bool fixDegenerate = true );
103         bool                    FromVecs( const idVec3 &dir1, const idVec3 &dir2, const idVec3 &p, bool fixDegenerate = true );
104         void                    FitThroughPoint( const idVec3 &p );     // assumes normal is valid
105         bool                    HeightFit( const idVec3 *points, const int numPoints );
106         idPlane                 Translate( const idVec3 &translation ) const;
107         idPlane &               TranslateSelf( const idVec3 &translation );
108         idPlane                 Rotate( const idVec3 &origin, const idMat3 &axis ) const;
109         idPlane &               RotateSelf( const idVec3 &origin, const idMat3 &axis );
110
111         float                   Distance( const idVec3 &v ) const;
112         int                             Side( const idVec3 &v, const float epsilon = 0.0f ) const;
113
114         bool                    LineIntersection( const idVec3 &start, const idVec3 &end ) const;
115                                         // intersection point is start + dir * scale
116         bool                    RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const;
117         bool                    PlaneIntersection( const idPlane &plane, idVec3 &start, idVec3 &dir ) const;
118
119         int                             GetDimension( void ) const;
120
121         const idVec4 &  ToVec4( void ) const;
122         idVec4 &                ToVec4( void );
123         const float *   ToFloatPtr( void ) const;
124         float *                 ToFloatPtr( void );
125         const char *    ToString( int precision = 2 ) const;
126
127 private:
128         float                   a;
129         float                   b;
130         float                   c;
131         float                   d;
132 };
133
134 extern idPlane plane_origin;
135 #define plane_zero plane_origin
136
137 ID_INLINE idPlane::idPlane( void ) {
138 }
139
140 ID_INLINE idPlane::idPlane( float a, float b, float c, float d ) {
141         this->a = a;
142         this->b = b;
143         this->c = c;
144         this->d = d;
145 }
146
147 ID_INLINE idPlane::idPlane( const idVec3 &normal, const float dist ) {
148         this->a = normal.x;
149         this->b = normal.y;
150         this->c = normal.z;
151         this->d = -dist;
152 }
153
154 ID_INLINE float idPlane::operator[]( int index ) const {
155         return ( &a )[ index ];
156 }
157
158 ID_INLINE float& idPlane::operator[]( int index ) {
159         return ( &a )[ index ];
160 }
161
162 ID_INLINE idPlane idPlane::operator-() const {
163         return idPlane( -a, -b, -c, -d );
164 }
165
166 ID_INLINE idPlane &idPlane::operator=( const idVec3 &v ) { 
167         a = v.x;
168         b = v.y;
169         c = v.z;
170         d = 0;
171         return *this;
172 }
173
174 ID_INLINE idPlane idPlane::operator+( const idPlane &p ) const {
175         return idPlane( a + p.a, b + p.b, c + p.c, d + p.d );
176 }
177
178 ID_INLINE idPlane idPlane::operator-( const idPlane &p ) const {
179         return idPlane( a - p.a, b - p.b, c - p.c, d - p.d );
180 }
181
182 ID_INLINE idPlane &idPlane::operator*=( const idMat3 &m ) {
183         Normal() *= m;
184         return *this;
185 }
186
187 ID_INLINE bool idPlane::Compare( const idPlane &p ) const {
188         return ( a == p.a && b == p.b && c == p.c && d == p.d );
189 }
190
191 ID_INLINE bool idPlane::Compare( const idPlane &p, const float epsilon ) const {
192         if ( idMath::Fabs( a - p.a ) > epsilon ) {
193                 return false;
194         }
195                         
196         if ( idMath::Fabs( b - p.b ) > epsilon ) {
197                 return false;
198         }
199
200         if ( idMath::Fabs( c - p.c ) > epsilon ) {
201                 return false;
202         }
203
204         if ( idMath::Fabs( d - p.d ) > epsilon ) {
205                 return false;
206         }
207
208         return true;
209 }
210
211 ID_INLINE bool idPlane::Compare( const idPlane &p, const float normalEps, const float distEps ) const {
212         if ( idMath::Fabs( d - p.d ) > distEps ) {
213                 return false;
214         }
215         if ( !Normal().Compare( p.Normal(), normalEps ) ) {
216                 return false;
217         }
218         return true;
219 }
220
221 ID_INLINE bool idPlane::operator==( const idPlane &p ) const {
222         return Compare( p );
223 }
224
225 ID_INLINE bool idPlane::operator!=( const idPlane &p ) const {
226         return !Compare( p );
227 }
228
229 ID_INLINE void idPlane::Zero( void ) {
230         a = b = c = d = 0.0f;
231 }
232
233 ID_INLINE void idPlane::SetNormal( const idVec3 &normal ) {
234         a = normal.x;
235         b = normal.y;
236         c = normal.z;
237 }
238
239 ID_INLINE const idVec3 &idPlane::Normal( void ) const {
240         return *reinterpret_cast<const idVec3 *>(&a);
241 }
242
243 ID_INLINE idVec3 &idPlane::Normal( void ) {
244         return *reinterpret_cast<idVec3 *>(&a);
245 }
246
247 ID_INLINE float idPlane::Normalize( bool fixDegenerate ) {
248         float length = reinterpret_cast<idVec3 *>(&a)->Normalize();
249
250         if ( fixDegenerate ) {
251                 FixDegenerateNormal();
252         }
253         return length;
254 }
255
256 ID_INLINE bool idPlane::FixDegenerateNormal( void ) {
257         return Normal().FixDegenerateNormal();
258 }
259
260 ID_INLINE bool idPlane::FixDegeneracies( float distEpsilon ) {
261         bool fixedNormal = FixDegenerateNormal();
262         // only fix dist if the normal was degenerate
263         if ( fixedNormal ) {
264                 if ( idMath::Fabs( d - idMath::Rint( d ) ) < distEpsilon ) {
265                         d = idMath::Rint( d );
266                 }
267         }
268         return fixedNormal;
269 }
270
271 ID_INLINE float idPlane::Dist( void ) const {
272         return -d;
273 }
274
275 ID_INLINE void idPlane::SetDist( const float dist ) {
276         d = -dist;
277 }
278
279 ID_INLINE bool idPlane::FromPoints( const idVec3 &p1, const idVec3 &p2, const idVec3 &p3, bool fixDegenerate ) {
280         Normal() = (p1 - p2).Cross( p3 - p2 );
281         if ( Normalize( fixDegenerate ) == 0.0f ) {
282                 return false;
283         }
284         d = -( Normal() * p2 );
285         return true;
286 }
287
288 ID_INLINE bool idPlane::FromVecs( const idVec3 &dir1, const idVec3 &dir2, const idVec3 &p, bool fixDegenerate ) {
289         Normal() = dir1.Cross( dir2 );
290         if ( Normalize( fixDegenerate ) == 0.0f ) {
291                 return false;
292         }
293         d = -( Normal() * p );
294         return true;
295 }
296
297 ID_INLINE void idPlane::FitThroughPoint( const idVec3 &p ) {
298         d = -( Normal() * p );
299 }
300
301 ID_INLINE idPlane idPlane::Translate( const idVec3 &translation ) const {
302         return idPlane( a, b, c, d - translation * Normal() );
303 }
304
305 ID_INLINE idPlane &idPlane::TranslateSelf( const idVec3 &translation ) {
306         d -= translation * Normal();
307         return *this;
308 }
309
310 ID_INLINE idPlane idPlane::Rotate( const idVec3 &origin, const idMat3 &axis ) const {
311         idPlane p;
312         p.Normal() = Normal() * axis;
313         p.d = d + origin * Normal() - origin * p.Normal();
314         return p;
315 }
316
317 ID_INLINE idPlane &idPlane::RotateSelf( const idVec3 &origin, const idMat3 &axis ) {
318         d += origin * Normal();
319         Normal() *= axis;
320         d -= origin * Normal();
321         return *this;
322 }
323
324 ID_INLINE float idPlane::Distance( const idVec3 &v ) const {
325         return a * v.x + b * v.y + c * v.z + d;
326 }
327
328 ID_INLINE int idPlane::Side( const idVec3 &v, const float epsilon ) const {
329         float dist = Distance( v );
330         if ( dist > epsilon ) {
331                 return PLANESIDE_FRONT;
332         }
333         else if ( dist < -epsilon ) {
334                 return PLANESIDE_BACK;
335         }
336         else {
337                 return PLANESIDE_ON;
338         }
339 }
340
341 ID_INLINE bool idPlane::LineIntersection( const idVec3 &start, const idVec3 &end ) const {
342         float d1, d2, fraction;
343
344         d1 = Normal() * start + d;
345         d2 = Normal() * end + d;
346         if ( d1 == d2 ) {
347                 return false;
348         }
349         if ( d1 > 0.0f && d2 > 0.0f ) {
350                 return false;
351         }
352         if ( d1 < 0.0f && d2 < 0.0f ) {
353                 return false;
354         }
355         fraction = ( d1 / ( d1 - d2 ) );
356         return ( fraction >= 0.0f && fraction <= 1.0f );
357 }
358
359 ID_INLINE bool idPlane::RayIntersection( const idVec3 &start, const idVec3 &dir, float &scale ) const {
360         float d1, d2;
361
362         d1 = Normal() * start + d;
363         d2 = Normal() * dir;
364         if ( d2 == 0.0f ) {
365                 return false;
366         }
367         scale = -( d1 / d2 );
368         return true;
369 }
370
371 ID_INLINE int idPlane::GetDimension( void ) const {
372         return 4;
373 }
374
375 ID_INLINE const idVec4 &idPlane::ToVec4( void ) const {
376         return *reinterpret_cast<const idVec4 *>(&a);
377 }
378
379 ID_INLINE idVec4 &idPlane::ToVec4( void ) {
380         return *reinterpret_cast<idVec4 *>(&a);
381 }
382
383 ID_INLINE const float *idPlane::ToFloatPtr( void ) const {
384         return reinterpret_cast<const float *>(&a);
385 }
386
387 ID_INLINE float *idPlane::ToFloatPtr( void ) {
388         return reinterpret_cast<float *>(&a);
389 }
390
391 #endif /* !__MATH_PLANE_H__ */