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