1 | /* |
2 | * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved. |
3 | * |
4 | * NVIDIA CORPORATION and its licensors retain all intellectual property |
5 | * and proprietary rights in and to this software, related documentation |
6 | * and any modifications thereto. Any use, reproduction, disclosure or |
7 | * distribution of this software and related documentation without an express |
8 | * license agreement from NVIDIA CORPORATION is strictly prohibited. |
9 | */ |
10 | // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. |
11 | // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. |
12 | |
13 | |
14 | |
15 | #ifndef PX_FOUNDATION_PX_QUAT_H |
16 | #define PX_FOUNDATION_PX_QUAT_H |
17 | |
18 | /** \addtogroup foundation |
19 | @{ |
20 | */ |
21 | |
22 | #include "foundation/PxVec3.h" |
23 | #ifndef PX_DOXYGEN |
24 | namespace physx |
25 | { |
26 | #endif |
27 | |
28 | /** |
29 | \brief This is a quaternion class. For more information on quaternion mathematics |
30 | consult a mathematics source on complex numbers. |
31 | |
32 | */ |
33 | |
34 | class PxQuat |
35 | { |
36 | public: |
37 | /** |
38 | \brief Default constructor, does not do any initialization. |
39 | */ |
40 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat() { } |
41 | |
42 | |
43 | //! identity constructor |
44 | PX_CUDA_CALLABLE PX_INLINE PxQuat(PxIDENTITY r) |
45 | : x(0.0f), y(0.0f), z(0.0f), w(1.0f) |
46 | { |
47 | PX_UNUSED(r); |
48 | } |
49 | |
50 | /** |
51 | \brief Constructor from a scalar: sets the real part w to the scalar value, and the imaginary parts (x,y,z) to zero |
52 | */ |
53 | explicit PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat(PxReal r) |
54 | : x(0.0f), y(0.0f), z(0.0f), w(r) |
55 | { |
56 | } |
57 | |
58 | /** |
59 | \brief Constructor. Take note of the order of the elements! |
60 | */ |
61 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat(PxReal nx, PxReal ny, PxReal nz, PxReal nw) : x(nx),y(ny),z(nz),w(nw) {} |
62 | |
63 | /** |
64 | \brief Creates from angle-axis representation. |
65 | |
66 | Axis must be normalized! |
67 | |
68 | Angle is in radians! |
69 | |
70 | <b>Unit:</b> Radians |
71 | */ |
72 | PX_CUDA_CALLABLE PX_INLINE PxQuat(PxReal angleRadians, const PxVec3& unitAxis) |
73 | { |
74 | PX_ASSERT(PxAbs(1.0f-unitAxis.magnitude())<1e-3f); |
75 | const PxReal a = angleRadians * 0.5f; |
76 | const PxReal s = PxSin(a); |
77 | w = PxCos(a); |
78 | x = unitAxis.x * s; |
79 | y = unitAxis.y * s; |
80 | z = unitAxis.z * s; |
81 | } |
82 | |
83 | /** |
84 | \brief Copy ctor. |
85 | */ |
86 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat(const PxQuat& v): x(v.x), y(v.y), z(v.z), w(v.w) {} |
87 | |
88 | /** |
89 | \brief Creates from orientation matrix. |
90 | |
91 | \param[in] m Rotation matrix to extract quaternion from. |
92 | */ |
93 | PX_CUDA_CALLABLE PX_INLINE explicit PxQuat(const PxMat33& m); /* defined in PxMat33.h */ |
94 | |
95 | /** |
96 | \brief returns true if all elements are finite (not NAN or INF, etc.) |
97 | */ |
98 | PX_CUDA_CALLABLE bool isFinite() const |
99 | { |
100 | return PxIsFinite(x) |
101 | && PxIsFinite(y) |
102 | && PxIsFinite(z) |
103 | && PxIsFinite(w); |
104 | } |
105 | |
106 | |
107 | /** |
108 | \brief returns true if finite and magnitude is close to unit |
109 | */ |
110 | |
111 | PX_CUDA_CALLABLE bool isUnit() const |
112 | { |
113 | const PxReal unitTolerance = 1e-4f; |
114 | return isFinite() && PxAbs(magnitude()-1)<unitTolerance; |
115 | } |
116 | |
117 | |
118 | /** |
119 | \brief returns true if finite and magnitude is reasonably close to unit to allow for some accumulation of error vs isValid |
120 | */ |
121 | |
122 | PX_CUDA_CALLABLE bool isSane() const |
123 | { |
124 | const PxReal unitTolerance = 1e-2f; |
125 | return isFinite() && PxAbs(magnitude()-1)<unitTolerance; |
126 | } |
127 | |
128 | /** |
129 | \brief returns true if the two quaternions are exactly equal |
130 | */ |
131 | PX_CUDA_CALLABLE PX_INLINE bool operator==(const PxQuat&q) const { return x == q.x && y == q.y && z == q.z && w == q.w; } |
132 | |
133 | |
134 | /** |
135 | \brief converts this quaternion to angle-axis representation |
136 | */ |
137 | |
138 | PX_CUDA_CALLABLE PX_INLINE void toRadiansAndUnitAxis(PxReal& angle, PxVec3& axis) const |
139 | { |
140 | const PxReal quatEpsilon = 1.0e-8f; |
141 | const PxReal s2 = x*x+y*y+z*z; |
142 | if(s2<quatEpsilon*quatEpsilon) // can't extract a sensible axis |
143 | { |
144 | angle = 0.0f; |
145 | axis = PxVec3(1.0f,0.0f,0.0f); |
146 | } |
147 | else |
148 | { |
149 | const PxReal s = PxRecipSqrt(s2); |
150 | axis = PxVec3(x,y,z) * s; |
151 | angle = PxAbs(w)<quatEpsilon ? PxPi : PxAtan2(s2*s, w) * 2.0f; |
152 | } |
153 | |
154 | } |
155 | |
156 | /** |
157 | \brief Gets the angle between this quat and the identity quaternion. |
158 | |
159 | <b>Unit:</b> Radians |
160 | */ |
161 | PX_CUDA_CALLABLE PX_INLINE PxReal getAngle() const |
162 | { |
163 | return PxAcos(w) * 2.0f; |
164 | } |
165 | |
166 | |
167 | /** |
168 | \brief Gets the angle between this quat and the argument |
169 | |
170 | <b>Unit:</b> Radians |
171 | */ |
172 | PX_CUDA_CALLABLE PX_INLINE PxReal getAngle(const PxQuat& q) const |
173 | { |
174 | return PxAcos(dot(q)) * 2.0f; |
175 | } |
176 | |
177 | |
178 | /** |
179 | \brief This is the squared 4D vector length, should be 1 for unit quaternions. |
180 | */ |
181 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal magnitudeSquared() const |
182 | { |
183 | return x*x + y*y + z*z + w*w; |
184 | } |
185 | |
186 | /** |
187 | \brief returns the scalar product of this and other. |
188 | */ |
189 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxReal dot(const PxQuat& v) const |
190 | { |
191 | return x * v.x + y * v.y + z * v.z + w * v.w; |
192 | } |
193 | |
194 | PX_CUDA_CALLABLE PX_INLINE PxQuat getNormalized() const |
195 | { |
196 | const PxReal s = 1.0f/magnitude(); |
197 | return PxQuat(x*s, y*s, z*s, w*s); |
198 | } |
199 | |
200 | |
201 | PX_CUDA_CALLABLE PX_INLINE float magnitude() const |
202 | { |
203 | return PxSqrt(magnitudeSquared()); |
204 | } |
205 | |
206 | //modifiers: |
207 | /** |
208 | \brief maps to the closest unit quaternion. |
209 | */ |
210 | PX_CUDA_CALLABLE PX_INLINE PxReal normalize() // convert this PxQuat to a unit quaternion |
211 | { |
212 | const PxReal mag = magnitude(); |
213 | if (mag) |
214 | { |
215 | const PxReal imag = 1.0f / mag; |
216 | |
217 | x *= imag; |
218 | y *= imag; |
219 | z *= imag; |
220 | w *= imag; |
221 | } |
222 | return mag; |
223 | } |
224 | |
225 | /* |
226 | \brief returns the conjugate. |
227 | |
228 | \note for unit quaternions, this is the inverse. |
229 | */ |
230 | PX_CUDA_CALLABLE PX_INLINE PxQuat getConjugate() const |
231 | { |
232 | return PxQuat(-x,-y,-z,w); |
233 | } |
234 | |
235 | /* |
236 | \brief returns imaginary part. |
237 | */ |
238 | PX_CUDA_CALLABLE PX_INLINE PxVec3 getImaginaryPart() const |
239 | { |
240 | return PxVec3(x,y,z); |
241 | } |
242 | |
243 | /** brief computes rotation of x-axis */ |
244 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getBasisVector0() const |
245 | { |
246 | const PxF32 x2 = x*2.0f; |
247 | const PxF32 w2 = w*2.0f; |
248 | return PxVec3( (w * w2) - 1.0f + x*x2, |
249 | (z * w2) + y*x2, |
250 | (-y * w2) + z*x2); |
251 | } |
252 | |
253 | /** brief computes rotation of y-axis */ |
254 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getBasisVector1() const |
255 | { |
256 | const PxF32 y2 = y*2.0f; |
257 | const PxF32 w2 = w*2.0f; |
258 | return PxVec3( (-z * w2) + x*y2, |
259 | (w * w2) - 1.0f + y*y2, |
260 | (x * w2) + z*y2); |
261 | } |
262 | |
263 | |
264 | /** brief computes rotation of z-axis */ |
265 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxVec3 getBasisVector2() const |
266 | { |
267 | const PxF32 z2 = z*2.0f; |
268 | const PxF32 w2 = w*2.0f; |
269 | return PxVec3( (y * w2) + x*z2, |
270 | (-x * w2) + y*z2, |
271 | (w * w2) - 1.0f + z*z2); |
272 | } |
273 | |
274 | /** |
275 | rotates passed vec by this (assumed unitary) |
276 | */ |
277 | PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3 rotate(const PxVec3& v) const |
278 | { |
279 | const PxF32 vx = 2.0f*v.x; |
280 | const PxF32 vy = 2.0f*v.y; |
281 | const PxF32 vz = 2.0f*v.z; |
282 | const PxF32 w2 = w*w-0.5f; |
283 | const PxF32 dot2 = (x*vx + y*vy +z*vz); |
284 | return PxVec3 |
285 | ( |
286 | (vx*w2 + (y * vz - z * vy)*w + x*dot2), |
287 | (vy*w2 + (z * vx - x * vz)*w + y*dot2), |
288 | (vz*w2 + (x * vy - y * vx)*w + z*dot2) |
289 | ); |
290 | } |
291 | |
292 | /** |
293 | inverse rotates passed vec by this (assumed unitary) |
294 | */ |
295 | PX_CUDA_CALLABLE PX_FORCE_INLINE const PxVec3 rotateInv(const PxVec3& v) const |
296 | { |
297 | const PxF32 vx = 2.0f*v.x; |
298 | const PxF32 vy = 2.0f*v.y; |
299 | const PxF32 vz = 2.0f*v.z; |
300 | const PxF32 w2 = w*w-0.5f; |
301 | const PxF32 dot2 = (x*vx + y*vy +z*vz); |
302 | return PxVec3 |
303 | ( |
304 | (vx*w2 - (y * vz - z * vy)*w + x*dot2), |
305 | (vy*w2 - (z * vx - x * vz)*w + y*dot2), |
306 | (vz*w2 - (x * vy - y * vx)*w + z*dot2) |
307 | ); |
308 | } |
309 | |
310 | /** |
311 | \brief Assignment operator |
312 | */ |
313 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat& operator=(const PxQuat& p) { x = p.x; y = p.y; z = p.z; w = p.w; return *this; } |
314 | |
315 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat& operator*= (const PxQuat& q) |
316 | { |
317 | const PxReal tx = w*q.x + q.w*x + y*q.z - q.y*z; |
318 | const PxReal ty = w*q.y + q.w*y + z*q.x - q.z*x; |
319 | const PxReal tz = w*q.z + q.w*z + x*q.y - q.x*y; |
320 | |
321 | w = w*q.w - q.x*x - y*q.y - q.z*z; |
322 | x = tx; |
323 | y = ty; |
324 | z = tz; |
325 | |
326 | return *this; |
327 | } |
328 | |
329 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat& operator+= (const PxQuat& q) |
330 | { |
331 | x+=q.x; |
332 | y+=q.y; |
333 | z+=q.z; |
334 | w+=q.w; |
335 | return *this; |
336 | } |
337 | |
338 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat& operator-= (const PxQuat& q) |
339 | { |
340 | x-=q.x; |
341 | y-=q.y; |
342 | z-=q.z; |
343 | w-=q.w; |
344 | return *this; |
345 | } |
346 | |
347 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat& operator*= (const PxReal s) |
348 | { |
349 | x*=s; |
350 | y*=s; |
351 | z*=s; |
352 | w*=s; |
353 | return *this; |
354 | } |
355 | |
356 | /** quaternion multiplication */ |
357 | PX_CUDA_CALLABLE PX_INLINE PxQuat operator*(const PxQuat& q) const |
358 | { |
359 | return PxQuat(w*q.x + q.w*x + y*q.z - q.y*z, |
360 | w*q.y + q.w*y + z*q.x - q.z*x, |
361 | w*q.z + q.w*z + x*q.y - q.x*y, |
362 | w*q.w - x*q.x - y*q.y - z*q.z); |
363 | } |
364 | |
365 | /** quaternion addition */ |
366 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat operator+(const PxQuat& q) const |
367 | { |
368 | return PxQuat(x+q.x,y+q.y,z+q.z,w+q.w); |
369 | } |
370 | |
371 | /** quaternion subtraction */ |
372 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat operator-() const |
373 | { |
374 | return PxQuat(-x,-y,-z,-w); |
375 | } |
376 | |
377 | |
378 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat operator-(const PxQuat& q) const |
379 | { |
380 | return PxQuat(x-q.x,y-q.y,z-q.z,w-q.w); |
381 | } |
382 | |
383 | |
384 | PX_CUDA_CALLABLE PX_FORCE_INLINE PxQuat operator*(PxReal r) const |
385 | { |
386 | return PxQuat(x*r,y*r,z*r,w*r); |
387 | } |
388 | |
389 | |
390 | /** \deprecated use PxQuat(PxIdentity) */ |
391 | PX_DEPRECATED static PX_CUDA_CALLABLE PX_INLINE PxQuat createIdentity() { return PxQuat(PxIdentity); } |
392 | |
393 | /** the quaternion elements */ |
394 | PxReal x,y,z,w; |
395 | }; |
396 | |
397 | #ifndef PX_DOXYGEN |
398 | } // namespace physx |
399 | #endif |
400 | |
401 | /** @} */ |
402 | #endif // PX_FOUNDATION_PX_QUAT_H |
403 | |