/src/ogre/OgreMain/include/OgrePlane.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | // This file is based on material originally from: |
29 | | // Geometric Tools, LLC |
30 | | // Copyright (c) 1998-2010 |
31 | | // Distributed under the Boost Software License, Version 1.0. |
32 | | // http://www.boost.org/LICENSE_1_0.txt |
33 | | // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt |
34 | | |
35 | | |
36 | | #ifndef __Plane_H__ |
37 | | #define __Plane_H__ |
38 | | |
39 | | #include "OgrePrerequisites.h" |
40 | | |
41 | | #include "OgreVector.h" |
42 | | #include "OgreAxisAlignedBox.h" |
43 | | |
44 | | namespace Ogre { |
45 | | |
46 | | /** \addtogroup Core |
47 | | * @{ |
48 | | */ |
49 | | /** \addtogroup Math |
50 | | * @{ |
51 | | */ |
52 | | /** Defines a plane in 3D space. |
53 | | |
54 | | A plane is defined in 3D space by the equation |
55 | | ``` |
56 | | Ax + By + Cz + D = 0 |
57 | | ``` |
58 | | @par |
59 | | This equates to a vector (the normal of the plane, whose x, y |
60 | | and z components equate to the coefficients A, B and C |
61 | | respectively), and a constant (D) which is the distance along |
62 | | the normal you have to go to move the plane back to the origin. |
63 | | */ |
64 | | class _OgreExport Plane |
65 | | { |
66 | | public: |
67 | | Vector3 normal; |
68 | | Real d; |
69 | | |
70 | | public: |
71 | | /** Default constructor - sets everything to 0. |
72 | | */ |
73 | 0 | Plane() : normal(Vector3::ZERO), d(0.0f) {} |
74 | | /** Construct a plane through a normal, and a distance to move the plane along the normal.*/ |
75 | | Plane(const Vector3& rkNormal, Real fConstant) |
76 | 0 | { |
77 | 0 | normal = rkNormal; |
78 | 0 | d = -fConstant; |
79 | 0 | } |
80 | | /** Construct a plane using the 4 constants directly **/ |
81 | 0 | Plane(Real a, Real b, Real c, Real _d) : normal(a, b, c), d(_d) {} |
82 | | /// @overload |
83 | 0 | explicit Plane(const Vector4& v) : normal(v.xyz()), d(v.w) {} |
84 | | Plane(const Vector3& rkNormal, const Vector3& rkPoint) |
85 | 0 | { |
86 | 0 | redefine(rkNormal, rkPoint); |
87 | 0 | } |
88 | | Plane(const Vector3& p0, const Vector3& p1, const Vector3& p2) |
89 | 0 | { |
90 | 0 | redefine(p0, p1, p2); |
91 | 0 | } |
92 | | |
93 | | /** The "positive side" of the plane is the half space to which the |
94 | | plane normal points. The "negative side" is the other half |
95 | | space. The flag "no side" indicates the plane itself. |
96 | | */ |
97 | | enum Side |
98 | | { |
99 | | NO_SIDE, |
100 | | POSITIVE_SIDE, |
101 | | NEGATIVE_SIDE, |
102 | | BOTH_SIDE |
103 | | }; |
104 | | |
105 | | Side getSide(const Vector3& rkPoint) const |
106 | 0 | { |
107 | 0 | Real fDistance = getDistance(rkPoint); |
108 | |
|
109 | 0 | if (fDistance < 0.0) |
110 | 0 | return Plane::NEGATIVE_SIDE; |
111 | | |
112 | 0 | if (fDistance > 0.0) |
113 | 0 | return Plane::POSITIVE_SIDE; |
114 | | |
115 | 0 | return Plane::NO_SIDE; |
116 | 0 | } |
117 | | |
118 | | /** |
119 | | Returns the side where the alignedBox is. The flag BOTH_SIDE indicates an intersecting box. |
120 | | One corner ON the plane is sufficient to consider the box and the plane intersecting. |
121 | | */ |
122 | | Side getSide(const AxisAlignedBox& box) const |
123 | 0 | { |
124 | 0 | if (box.isNull()) |
125 | 0 | return NO_SIDE; |
126 | 0 | if (box.isInfinite()) |
127 | 0 | return BOTH_SIDE; |
128 | 0 |
|
129 | 0 | return getSide(box.getCenter(), box.getHalfSize()); |
130 | 0 | } |
131 | | |
132 | | /** Returns which side of the plane that the given box lies on. |
133 | | The box is defined as centre/half-size pairs for effectively. |
134 | | @param centre The centre of the box. |
135 | | @param halfSize The half-size of the box. |
136 | | @return |
137 | | POSITIVE_SIDE if the box complete lies on the "positive side" of the plane, |
138 | | NEGATIVE_SIDE if the box complete lies on the "negative side" of the plane, |
139 | | and BOTH_SIDE if the box intersects the plane. |
140 | | */ |
141 | | Side getSide(const Vector3& centre, const Vector3& halfSize) const |
142 | 0 | { |
143 | | // Calculate the distance between box centre and the plane |
144 | 0 | Real dist = getDistance(centre); |
145 | | |
146 | | // Calculate the maximise allows absolute distance for |
147 | | // the distance between box centre and plane |
148 | 0 | Real maxAbsDist = normal.absDotProduct(halfSize); |
149 | |
|
150 | 0 | if (dist < -maxAbsDist) |
151 | 0 | return NEGATIVE_SIDE; |
152 | | |
153 | 0 | if (dist > +maxAbsDist) |
154 | 0 | return POSITIVE_SIDE; |
155 | | |
156 | 0 | return BOTH_SIDE; |
157 | 0 | } |
158 | | |
159 | | /** This is a pseudodistance. The sign of the return value is |
160 | | positive if the point is on the positive side of the plane, |
161 | | negative if the point is on the negative side, and zero if the |
162 | | point is on the plane. |
163 | | @par |
164 | | The absolute value of the return value is the true distance only |
165 | | when the plane normal is a unit length vector. |
166 | | */ |
167 | | Real getDistance(const Vector3& rkPoint) const |
168 | 0 | { |
169 | 0 | return normal.dotProduct(rkPoint) + d; |
170 | 0 | } |
171 | | |
172 | | /** Redefine this plane based on 3 points. */ |
173 | | void redefine(const Vector3& p0, const Vector3& p1, const Vector3& p2) |
174 | 0 | { |
175 | 0 | normal = Math::calculateBasicFaceNormal(p0, p1, p2); |
176 | 0 | d = -normal.dotProduct(p0); |
177 | 0 | } |
178 | | |
179 | | /** Redefine this plane based on a normal and a point. */ |
180 | | void redefine(const Vector3& rkNormal, const Vector3& rkPoint) |
181 | 0 | { |
182 | 0 | normal = rkNormal; |
183 | 0 | d = -rkNormal.dotProduct(rkPoint); |
184 | 0 | } |
185 | | |
186 | | /** Project a vector onto the plane. |
187 | | @remarks This gives you the element of the input vector that is perpendicular |
188 | | to the normal of the plane. You can get the element which is parallel |
189 | | to the normal of the plane by subtracting the result of this method |
190 | | from the original vector, since parallel + perpendicular = original. |
191 | | @param v The input vector |
192 | | */ |
193 | | Vector3 projectVector(const Vector3& v) const |
194 | 0 | { |
195 | 0 | // We know plane normal is unit length, so use simple method |
196 | 0 | Matrix3 xform; |
197 | 0 | xform[0][0] = 1.0f - normal.x * normal.x; |
198 | 0 | xform[0][1] = -normal.x * normal.y; |
199 | 0 | xform[0][2] = -normal.x * normal.z; |
200 | 0 | xform[1][0] = -normal.y * normal.x; |
201 | 0 | xform[1][1] = 1.0f - normal.y * normal.y; |
202 | 0 | xform[1][2] = -normal.y * normal.z; |
203 | 0 | xform[2][0] = -normal.z * normal.x; |
204 | 0 | xform[2][1] = -normal.z * normal.y; |
205 | 0 | xform[2][2] = 1.0f - normal.z * normal.z; |
206 | 0 | return xform * v; |
207 | 0 | } |
208 | | |
209 | | /** Normalises the plane. |
210 | | |
211 | | This method normalises the plane's normal and the length scale of d |
212 | | is as well. |
213 | | @note |
214 | | This function will not crash for zero-sized vectors, but there |
215 | | will be no changes made to their components. |
216 | | @return The previous length of the plane's normal. |
217 | | */ |
218 | | Real normalise(void) |
219 | 0 | { |
220 | 0 | Real fLength = normal.length(); |
221 | 0 |
|
222 | 0 | // Will also work for zero-sized vectors, but will change nothing |
223 | 0 | // We're not using epsilons because we don't need to. |
224 | 0 | // Read http://www.ogre3d.org/forums/viewtopic.php?f=4&t=61259 |
225 | 0 | if (fLength > Real(0.0f)) |
226 | 0 | { |
227 | 0 | Real fInvLength = 1.0f / fLength; |
228 | 0 | normal *= fInvLength; |
229 | 0 | d *= fInvLength; |
230 | 0 | } |
231 | 0 |
|
232 | 0 | return fLength; |
233 | 0 | } |
234 | | |
235 | | /// Get flipped plane, with same location but reverted orientation |
236 | | Plane operator - () const |
237 | 0 | { |
238 | 0 | return Plane(-(normal.x), -(normal.y), -(normal.z), -d); // not equal to Plane(-normal, -d) |
239 | 0 | } |
240 | | |
241 | | /// Comparison operator |
242 | | bool operator==(const Plane& rhs) const |
243 | 0 | { |
244 | 0 | return (rhs.d == d && rhs.normal == normal); |
245 | 0 | } |
246 | | bool operator!=(const Plane& rhs) const |
247 | 0 | { |
248 | 0 | return (rhs.d != d || rhs.normal != normal); |
249 | 0 | } |
250 | | |
251 | | friend std::ostream& operator<<(std::ostream& o, const Plane& p) |
252 | 0 | { |
253 | 0 | o << "Plane(normal=" << p.normal << ", d=" << p.d << ")"; |
254 | 0 | return o; |
255 | 0 | } |
256 | | }; |
257 | | |
258 | | inline Plane operator * (const Matrix4& mat, const Plane& p) |
259 | 0 | { |
260 | 0 | Plane ret; |
261 | 0 | Matrix4 invTrans = mat.inverse().transpose(); |
262 | 0 | Vector4 v4( p.normal.x, p.normal.y, p.normal.z, p.d ); |
263 | 0 | v4 = invTrans * v4; |
264 | 0 | ret.normal.x = v4.x; |
265 | 0 | ret.normal.y = v4.y; |
266 | 0 | ret.normal.z = v4.z; |
267 | 0 | ret.d = v4.w / ret.normal.normalise(); |
268 | 0 |
|
269 | 0 | return ret; |
270 | 0 | } |
271 | | |
272 | | inline bool Math::intersects(const Plane& plane, const AxisAlignedBox& box) |
273 | 0 | { |
274 | 0 | return plane.getSide(box) == Plane::BOTH_SIDE; |
275 | 0 | } |
276 | | |
277 | | typedef std::vector<Plane> PlaneList; |
278 | | /** @} */ |
279 | | /** @} */ |
280 | | |
281 | | } // namespace Ogre |
282 | | |
283 | | #endif |