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