1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #ifndef __IRR_PLANE_3D_H_INCLUDED__
6 #define __IRR_PLANE_3D_H_INCLUDED__
7 
8 #include "irrMath.h"
9 #include "vector3d.h"
10 
11 namespace irr
12 {
13 namespace core
14 {
15 
16 //! Enumeration for intersection relations of 3d objects
17 enum EIntersectionRelation3D
18 {
19 	ISREL3D_FRONT = 0,
20 	ISREL3D_BACK,
21 	ISREL3D_PLANAR,
22 	ISREL3D_SPANNING,
23 	ISREL3D_CLIPPED
24 };
25 
26 //! Template plane class with some intersection testing methods.
27 /** It has to be ensured, that the normal is always normalized. The constructors
28     and setters of this class will not ensure this automatically. So any normal
29     passed in has to be normalized in advance. No change to the normal will be
30     made by any of the class methods.
31 */
32 template <class T>
33 class plane3d
34 {
35 	public:
36 
37 		// Constructors
38 
plane3d()39 		plane3d(): Normal(0,1,0) { recalculateD(vector3d<T>(0,0,0)); }
40 
plane3d(const vector3d<T> & MPoint,const vector3d<T> & Normal)41 		plane3d(const vector3d<T>& MPoint, const vector3d<T>& Normal) : Normal(Normal) { recalculateD(MPoint); }
42 
plane3d(T px,T py,T pz,T nx,T ny,T nz)43 		plane3d(T px, T py, T pz, T nx, T ny, T nz) : Normal(nx, ny, nz) { recalculateD(vector3d<T>(px, py, pz)); }
44 
plane3d(const vector3d<T> & point1,const vector3d<T> & point2,const vector3d<T> & point3)45 		plane3d(const vector3d<T>& point1, const vector3d<T>& point2, const vector3d<T>& point3)
46 		{ setPlane(point1, point2, point3); }
47 
plane3d(const vector3d<T> & normal,const T d)48 		plane3d(const vector3d<T> & normal, const T d) : Normal(normal), D(d) { }
49 
50 		// operators
51 
52 		inline bool operator==(const plane3d<T>& other) const { return (equals(D, other.D) && Normal==other.Normal);}
53 
54 		inline bool operator!=(const plane3d<T>& other) const { return !(*this == other);}
55 
56 		// functions
57 
setPlane(const vector3d<T> & point,const vector3d<T> & nvector)58 		void setPlane(const vector3d<T>& point, const vector3d<T>& nvector)
59 		{
60 			Normal = nvector;
61 			recalculateD(point);
62 		}
63 
setPlane(const vector3d<T> & nvect,T d)64 		void setPlane(const vector3d<T>& nvect, T d)
65 		{
66 			Normal = nvect;
67 			D = d;
68 		}
69 
setPlane(const vector3d<T> & point1,const vector3d<T> & point2,const vector3d<T> & point3)70 		void setPlane(const vector3d<T>& point1, const vector3d<T>& point2, const vector3d<T>& point3)
71 		{
72 			// creates the plane from 3 memberpoints
73 			Normal = (point2 - point1).crossProduct(point3 - point1);
74 			Normal.normalize();
75 
76 			recalculateD(point1);
77 		}
78 
79 
80 		//! Get an intersection with a 3d line.
81 		/** \param lineVect Vector of the line to intersect with.
82 		\param linePoint Point of the line to intersect with.
83 		\param outIntersection Place to store the intersection point, if there is one.
84 		\return True if there was an intersection, false if there was not.
85 		*/
getIntersectionWithLine(const vector3d<T> & linePoint,const vector3d<T> & lineVect,vector3d<T> & outIntersection)86 		bool getIntersectionWithLine(const vector3d<T>& linePoint,
87 				const vector3d<T>& lineVect,
88 				vector3d<T>& outIntersection) const
89 		{
90 			T t2 = Normal.dotProduct(lineVect);
91 
92 			if (t2 == 0)
93 				return false;
94 
95 			T t =- (Normal.dotProduct(linePoint) + D) / t2;
96 			outIntersection = linePoint + (lineVect * t);
97 			return true;
98 		}
99 
100 		//! Get percentage of line between two points where an intersection with this plane happens.
101 		/** Only useful if known that there is an intersection.
102 		\param linePoint1 Point1 of the line to intersect with.
103 		\param linePoint2 Point2 of the line to intersect with.
104 		\return Where on a line between two points an intersection with this plane happened.
105 		For example, 0.5 is returned if the intersection happened exactly in the middle of the two points.
106 		*/
getKnownIntersectionWithLine(const vector3d<T> & linePoint1,const vector3d<T> & linePoint2)107 		f32 getKnownIntersectionWithLine(const vector3d<T>& linePoint1,
108 			const vector3d<T>& linePoint2) const
109 		{
110 			vector3d<T> vect = linePoint2 - linePoint1;
111 			T t2 = (f32)Normal.dotProduct(vect);
112 			return (f32)-((Normal.dotProduct(linePoint1) + D) / t2);
113 		}
114 
115 		//! Get an intersection with a 3d line, limited between two 3d points.
116 		/** \param linePoint1 Point 1 of the line.
117 		\param linePoint2 Point 2 of the line.
118 		\param outIntersection Place to store the intersection point, if there is one.
119 		\return True if there was an intersection, false if there was not.
120 		*/
getIntersectionWithLimitedLine(const vector3d<T> & linePoint1,const vector3d<T> & linePoint2,vector3d<T> & outIntersection)121 		bool getIntersectionWithLimitedLine(
122 				const vector3d<T>& linePoint1,
123 				const vector3d<T>& linePoint2,
124 				vector3d<T>& outIntersection) const
125 		{
126 			return (getIntersectionWithLine(linePoint1, linePoint2 - linePoint1, outIntersection) &&
127 					outIntersection.isBetweenPoints(linePoint1, linePoint2));
128 		}
129 
130 		//! Classifies the relation of a point to this plane.
131 		/** \param point Point to classify its relation.
132 		\return ISREL3D_FRONT if the point is in front of the plane,
133 		ISREL3D_BACK if the point is behind of the plane, and
134 		ISREL3D_PLANAR if the point is within the plane. */
classifyPointRelation(const vector3d<T> & point)135 		EIntersectionRelation3D classifyPointRelation(const vector3d<T>& point) const
136 		{
137 			const T d = Normal.dotProduct(point) + D;
138 
139 			if (d < -ROUNDING_ERROR_f32)
140 				return ISREL3D_BACK;
141 
142 			if (d > ROUNDING_ERROR_f32)
143 				return ISREL3D_FRONT;
144 
145 			return ISREL3D_PLANAR;
146 		}
147 
148 		//! Recalculates the distance from origin by applying a new member point to the plane.
recalculateD(const vector3d<T> & MPoint)149 		void recalculateD(const vector3d<T>& MPoint)
150 		{
151 			D = - MPoint.dotProduct(Normal);
152 		}
153 
154 		//! Gets a member point of the plane.
getMemberPoint()155 		vector3d<T> getMemberPoint() const
156 		{
157 			return Normal * -D;
158 		}
159 
160 		//! Tests if there is an intersection with the other plane
161 		/** \return True if there is a intersection. */
existsIntersection(const plane3d<T> & other)162 		bool existsIntersection(const plane3d<T>& other) const
163 		{
164 			vector3d<T> cross = other.Normal.crossProduct(Normal);
165 			return cross.getLength() > core::ROUNDING_ERROR_f32;
166 		}
167 
168 		//! Intersects this plane with another.
169 		/** \param other Other plane to intersect with.
170 		\param outLinePoint Base point of intersection line.
171 		\param outLineVect Vector of intersection.
172 		\return True if there is a intersection, false if not. */
getIntersectionWithPlane(const plane3d<T> & other,vector3d<T> & outLinePoint,vector3d<T> & outLineVect)173 		bool getIntersectionWithPlane(const plane3d<T>& other,
174 				vector3d<T>& outLinePoint,
175 				vector3d<T>& outLineVect) const
176 		{
177 			const T fn00 = Normal.getLength();
178 			const T fn01 = Normal.dotProduct(other.Normal);
179 			const T fn11 = other.Normal.getLength();
180 			const f64 det = fn00*fn11 - fn01*fn01;
181 
182 			if (fabs(det) < ROUNDING_ERROR_f64 )
183 				return false;
184 
185 			const f64 invdet = 1.0 / det;
186 			const f64 fc0 = (fn11*-D + fn01*other.D) * invdet;
187 			const f64 fc1 = (fn00*-other.D + fn01*D) * invdet;
188 
189 			outLineVect = Normal.crossProduct(other.Normal);
190 			outLinePoint = Normal*(T)fc0 + other.Normal*(T)fc1;
191 			return true;
192 		}
193 
194 		//! Get the intersection point with two other planes if there is one.
getIntersectionWithPlanes(const plane3d<T> & o1,const plane3d<T> & o2,vector3d<T> & outPoint)195 		bool getIntersectionWithPlanes(const plane3d<T>& o1,
196 				const plane3d<T>& o2, vector3d<T>& outPoint) const
197 		{
198 			vector3d<T> linePoint, lineVect;
199 			if (getIntersectionWithPlane(o1, linePoint, lineVect))
200 				return o2.getIntersectionWithLine(linePoint, lineVect, outPoint);
201 
202 			return false;
203 		}
204 
205 		//! Test if the triangle would be front or backfacing from any point.
206 		/** Thus, this method assumes a camera position from
207 		which the triangle is definitely visible when looking into
208 		the given direction.
209 		Note that this only works if the normal is Normalized.
210 		Do not use this method with points as it will give wrong results!
211 		\param lookDirection: Look direction.
212 		\return True if the plane is front facing and
213 		false if it is backfacing. */
isFrontFacing(const vector3d<T> & lookDirection)214 		bool isFrontFacing(const vector3d<T>& lookDirection) const
215 		{
216 			const f32 d = Normal.dotProduct(lookDirection);
217 			return F32_LOWER_EQUAL_0 ( d );
218 		}
219 
220 		//! Get the distance to a point.
221 		/** Note that this only works if the normal is normalized. */
getDistanceTo(const vector3d<T> & point)222 		T getDistanceTo(const vector3d<T>& point) const
223 		{
224 			return point.dotProduct(Normal) + D;
225 		}
226 
227 		//! Normal vector of the plane.
228 		vector3d<T> Normal;
229 
230 		//! Distance from origin.
231 		T D;
232 };
233 
234 
235 //! Typedef for a f32 3d plane.
236 typedef plane3d<f32> plane3df;
237 
238 //! Typedef for an integer 3d plane.
239 typedef plane3d<s32> plane3di;
240 
241 } // end namespace core
242 } // end namespace irr
243 
244 #endif
245 
246