source: trunk/src/gui/math3d/qquaternion.cpp@ 561

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 16.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qquaternion.h"
43#include <QtCore/qmath.h>
44#include <QtCore/qvariant.h>
45#include <QtCore/qdebug.h>
46
47QT_BEGIN_NAMESPACE
48
49#ifndef QT_NO_QUATERNION
50
51/*!
52 \class QQuaternion
53 \brief The QQuaternion class represents a quaternion consisting of a vector and scalar.
54 \since 4.6
55 \ingroup painting-3D
56
57 Quaternions are used to represent rotations in 3D space, and
58 consist of a 3D rotation axis specified by the x, y, and z
59 coordinates, and a scalar representing the rotation angle.
60*/
61
62/*!
63 \fn QQuaternion::QQuaternion()
64
65 Constructs an identity quaternion, i.e. with coordinates (1, 0, 0, 0).
66*/
67
68/*!
69 \fn QQuaternion::QQuaternion(qreal scalar, qreal xpos, qreal ypos, qreal zpos)
70
71 Constructs a quaternion with the vector (\a xpos, \a ypos, \a zpos)
72 and \a scalar.
73*/
74
75#ifndef QT_NO_VECTOR3D
76
77/*!
78 \fn QQuaternion::QQuaternion(qreal scalar, const QVector3D& vector)
79
80 Constructs a quaternion vector from the specified \a vector and
81 \a scalar.
82
83 \sa vector(), scalar()
84*/
85
86/*!
87 \fn QVector3D QQuaternion::vector() const
88
89 Returns the vector component of this quaternion.
90
91 \sa setVector(), scalar()
92*/
93
94/*!
95 \fn void QQuaternion::setVector(const QVector3D& vector)
96
97 Sets the vector component of this quaternion to \a vector.
98
99 \sa vector(), setScalar()
100*/
101
102#endif
103
104/*!
105 \fn void QQuaternion::setVector(qreal x, qreal y, qreal z)
106
107 Sets the vector component of this quaternion to (\a x, \a y, \a z).
108
109 \sa vector(), setScalar()
110*/
111
112#ifndef QT_NO_VECTOR4D
113
114/*!
115 \fn QQuaternion::QQuaternion(const QVector4D& vector)
116
117 Constructs a quaternion from the components of \a vector.
118*/
119
120/*!
121 \fn QVector4D QQuaternion::toVector4D() const
122
123 Returns this quaternion as a 4D vector.
124*/
125
126#endif
127
128/*!
129 \fn bool QQuaternion::isNull() const
130
131 Returns true if the x, y, z, and scalar components of this
132 quaternion are set to 0.0; otherwise returns false.
133*/
134
135/*!
136 \fn bool QQuaternion::isIdentity() const
137
138 Returns true if the x, y, and z components of this
139 quaternion are set to 0.0, and the scalar component is set
140 to 1.0; otherwise returns false.
141*/
142
143/*!
144 \fn qreal QQuaternion::x() const
145
146 Returns the x coordinate of this quaternion's vector.
147
148 \sa setX(), y(), z(), scalar()
149*/
150
151/*!
152 \fn qreal QQuaternion::y() const
153
154 Returns the y coordinate of this quaternion's vector.
155
156 \sa setY(), x(), z(), scalar()
157*/
158
159/*!
160 \fn qreal QQuaternion::z() const
161
162 Returns the z coordinate of this quaternion's vector.
163
164 \sa setZ(), x(), y(), scalar()
165*/
166
167/*!
168 \fn qreal QQuaternion::scalar() const
169
170 Returns the scalar component of this quaternion.
171
172 \sa setScalar(), x(), y(), z()
173*/
174
175/*!
176 \fn void QQuaternion::setX(qreal x)
177
178 Sets the x coordinate of this quaternion's vector to the given
179 \a x coordinate.
180
181 \sa x(), setY(), setZ(), setScalar()
182*/
183
184/*!
185 \fn void QQuaternion::setY(qreal y)
186
187 Sets the y coordinate of this quaternion's vector to the given
188 \a y coordinate.
189
190 \sa y(), setX(), setZ(), setScalar()
191*/
192
193/*!
194 \fn void QQuaternion::setZ(qreal z)
195
196 Sets the z coordinate of this quaternion's vector to the given
197 \a z coordinate.
198
199 \sa z(), setX(), setY(), setScalar()
200*/
201
202/*!
203 \fn void QQuaternion::setScalar(qreal scalar)
204
205 Sets the scalar component of this quaternion to \a scalar.
206
207 \sa scalar(), setX(), setY(), setZ()
208*/
209
210/*!
211 Returns the length of the quaternion. This is also called the "norm".
212
213 \sa lengthSquared(), normalized()
214*/
215qreal QQuaternion::length() const
216{
217 return qSqrt(xp * xp + yp * yp + zp * zp + wp * wp);
218}
219
220/*!
221 Returns the squared length of the quaternion.
222
223 \sa length()
224*/
225qreal QQuaternion::lengthSquared() const
226{
227 return xp * xp + yp * yp + zp * zp + wp * wp;
228}
229
230/*!
231 Returns the normalized unit form of this quaternion.
232
233 If this quaternion is null, then a null quaternion is returned.
234 If the length of the quaternion is very close to 1, then the quaternion
235 will be returned as-is. Otherwise the normalized form of the
236 quaternion of length 1 will be returned.
237
238 \sa length(), normalize()
239*/
240QQuaternion QQuaternion::normalized() const
241{
242 // Need some extra precision if the length is very small.
243 double len = double(xp) * double(xp) +
244 double(yp) * double(yp) +
245 double(zp) * double(zp) +
246 double(wp) * double(wp);
247 if (qFuzzyIsNull(len - 1.0f))
248 return *this;
249 else if (!qFuzzyIsNull(len))
250 return *this / qSqrt(len);
251 else
252 return QQuaternion(0.0f, 0.0f, 0.0f, 0.0f);
253}
254
255/*!
256 Normalizes the currect quaternion in place. Nothing happens if this
257 is a null quaternion or the length of the quaternion is very close to 1.
258
259 \sa length(), normalized()
260*/
261void QQuaternion::normalize()
262{
263 // Need some extra precision if the length is very small.
264 double len = double(xp) * double(xp) +
265 double(yp) * double(yp) +
266 double(zp) * double(zp) +
267 double(wp) * double(wp);
268 if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len))
269 return;
270
271 len = qSqrt(len);
272
273 xp /= len;
274 yp /= len;
275 zp /= len;
276 wp /= len;
277}
278
279/*!
280 \fn QQuaternion QQuaternion::conjugate() const
281
282 Returns the conjugate of this quaternion, which is
283 (-x, -y, -z, scalar).
284*/
285
286/*!
287 Rotates \a vector with this quaternion to produce a new vector
288 in 3D space. The following code:
289
290 \code
291 QVector3D result = q.rotatedVector(vector);
292 \endcode
293
294 is equivalent to the following:
295
296 \code
297 QVector3D result = (q * QQuaternion(0, vector) * q.conjugate()).vector();
298 \endcode
299*/
300QVector3D QQuaternion::rotatedVector(const QVector3D& vector) const
301{
302 return (*this * QQuaternion(0, vector) * conjugate()).vector();
303}
304
305/*!
306 \fn QQuaternion &QQuaternion::operator+=(const QQuaternion &quaternion)
307
308 Adds the given \a quaternion to this quaternion and returns a reference to
309 this quaternion.
310
311 \sa operator-=()
312*/
313
314/*!
315 \fn QQuaternion &QQuaternion::operator-=(const QQuaternion &quaternion)
316
317 Subtracts the given \a quaternion from this quaternion and returns a
318 reference to this quaternion.
319
320 \sa operator+=()
321*/
322
323/*!
324 \fn QQuaternion &QQuaternion::operator*=(qreal factor)
325
326 Multiplies this quaternion's components by the given \a factor, and
327 returns a reference to this quaternion.
328
329 \sa operator/=()
330*/
331
332/*!
333 \fn QQuaternion &QQuaternion::operator*=(const QQuaternion &quaternion)
334
335 Multiplies this quaternion by \a quaternion and returns a reference
336 to this quaternion.
337*/
338
339/*!
340 \fn QQuaternion &QQuaternion::operator/=(qreal divisor)
341
342 Divides this quaternion's components by the given \a divisor, and
343 returns a reference to this quaternion.
344
345 \sa operator*=()
346*/
347
348#ifndef QT_NO_VECTOR3D
349
350/*!
351 Creates a normalized quaternion that corresponds to rotating through
352 \a angle degrees about the specified 3D \a axis.
353*/
354QQuaternion QQuaternion::fromAxisAndAngle(const QVector3D& axis, qreal angle)
355{
356 // Algorithm from:
357 // http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q56
358 // We normalize the result just in case the values are close
359 // to zero, as suggested in the above FAQ.
360 qreal a = (angle / 2.0f) * M_PI / 180.0f;
361 qreal s = qSin(a);
362 qreal c = qCos(a);
363 QVector3D ax = axis.normalized();
364 return QQuaternion(c, ax.x() * s, ax.y() * s, ax.z() * s).normalized();
365}
366
367#endif
368
369/*!
370 Creates a normalized quaternion that corresponds to rotating through
371 \a angle degrees about the 3D axis (\a x, \a y, \a z).
372*/
373QQuaternion QQuaternion::fromAxisAndAngle
374 (qreal x, qreal y, qreal z, qreal angle)
375{
376 qreal length = qSqrt(x * x + y * y + z * z);
377 if (!qFuzzyIsNull(length - 1.0f) && !qFuzzyIsNull(length)) {
378 x /= length;
379 y /= length;
380 z /= length;
381 }
382 qreal a = (angle / 2.0f) * M_PI / 180.0f;
383 qreal s = qSin(a);
384 qreal c = qCos(a);
385 return QQuaternion(c, x * s, y * s, z * s).normalized();
386}
387
388/*!
389 \fn bool operator==(const QQuaternion &q1, const QQuaternion &q2)
390 \relates QQuaternion
391
392 Returns true if \a q1 is equal to \a q2; otherwise returns false.
393 This operator uses an exact floating-point comparison.
394*/
395
396/*!
397 \fn bool operator!=(const QQuaternion &q1, const QQuaternion &q2)
398 \relates QQuaternion
399
400 Returns true if \a q1 is not equal to \a q2; otherwise returns false.
401 This operator uses an exact floating-point comparison.
402*/
403
404/*!
405 \fn const QQuaternion operator+(const QQuaternion &q1, const QQuaternion &q2)
406 \relates QQuaternion
407
408 Returns a QQuaternion object that is the sum of the given quaternions,
409 \a q1 and \a q2; each component is added separately.
410
411 \sa QQuaternion::operator+=()
412*/
413
414/*!
415 \fn const QQuaternion operator-(const QQuaternion &q1, const QQuaternion &q2)
416 \relates QQuaternion
417
418 Returns a QQuaternion object that is formed by subtracting
419 \a q2 from \a q1; each component is subtracted separately.
420
421 \sa QQuaternion::operator-=()
422*/
423
424/*!
425 \fn const QQuaternion operator*(qreal factor, const QQuaternion &quaternion)
426 \relates QQuaternion
427
428 Returns a copy of the given \a quaternion, multiplied by the
429 given \a factor.
430
431 \sa QQuaternion::operator*=()
432*/
433
434/*!
435 \fn const QQuaternion operator*(const QQuaternion &quaternion, qreal factor)
436 \relates QQuaternion
437
438 Returns a copy of the given \a quaternion, multiplied by the
439 given \a factor.
440
441 \sa QQuaternion::operator*=()
442*/
443
444/*!
445 \fn const QQuaternion operator*(const QQuaternion &q1, const QQuaternion& q2)
446 \relates QQuaternion
447
448 Multiplies \a q1 and \a q2 using quaternion multiplication.
449 The result corresponds to applying both of the rotations specified
450 by \a q1 and \a q2.
451
452 \sa QQuaternion::operator*=()
453*/
454
455/*!
456 \fn const QQuaternion operator-(const QQuaternion &quaternion)
457 \relates QQuaternion
458 \overload
459
460 Returns a QQuaternion object that is formed by changing the sign of
461 all three components of the given \a quaternion.
462
463 Equivalent to \c {QQuaternion(0,0,0,0) - quaternion}.
464*/
465
466/*!
467 \fn const QQuaternion operator/(const QQuaternion &quaternion, qreal divisor)
468 \relates QQuaternion
469
470 Returns the QQuaternion object formed by dividing all components of
471 the given \a quaternion by the given \a divisor.
472
473 \sa QQuaternion::operator/=()
474*/
475
476/*!
477 \fn bool qFuzzyCompare(const QQuaternion& q1, const QQuaternion& q2)
478 \relates QQuaternion
479
480 Returns true if \a q1 and \a q2 are equal, allowing for a small
481 fuzziness factor for floating-point comparisons; false otherwise.
482*/
483
484/*!
485 Interpolates along the shortest spherical path between the
486 rotational positions \a q1 and \a q2. The value \a t should
487 be between 0 and 1, indicating the spherical distance to travel
488 between \a q1 and \a q2.
489
490 If \a t is less than or equal to 0, then \a q1 will be returned.
491 If \a t is greater than or equal to 1, then \a q2 will be returned.
492
493 \sa nlerp()
494*/
495QQuaternion QQuaternion::slerp
496 (const QQuaternion& q1, const QQuaternion& q2, qreal t)
497{
498 // Handle the easy cases first.
499 if (t <= 0.0f)
500 return q1;
501 else if (t >= 1.0f)
502 return q2;
503
504 // Determine the angle between the two quaternions.
505 QQuaternion q2b;
506 qreal dot;
507 dot = q1.xp * q2.xp + q1.yp * q2.yp + q1.zp * q2.zp + q1.wp * q2.wp;
508 if (dot >= 0.0f) {
509 q2b = q2;
510 } else {
511 q2b = -q2;
512 dot = -dot;
513 }
514
515 // Get the scale factors. If they are too small,
516 // then revert to simple linear interpolation.
517 qreal factor1 = 1.0f - t;
518 qreal factor2 = t;
519 if ((1.0f - dot) > 0.0000001) {
520 qreal angle = qreal(qAcos(dot));
521 qreal sinOfAngle = qreal(qSin(angle));
522 if (sinOfAngle > 0.0000001) {
523 factor1 = qreal(qSin((1.0f - t) * angle)) / sinOfAngle;
524 factor2 = qreal(qSin(t * angle)) / sinOfAngle;
525 }
526 }
527
528 // Construct the result quaternion.
529 return q1 * factor1 + q2b * factor2;
530}
531
532/*!
533 Interpolates along the shortest linear path between the rotational
534 positions \a q1 and \a q2. The value \a t should be between 0 and 1,
535 indicating the distance to travel between \a q1 and \a q2.
536 The result will be normalized().
537
538 If \a t is less than or equal to 0, then \a q1 will be returned.
539 If \a t is greater than or equal to 1, then \a q2 will be returned.
540
541 The nlerp() function is typically faster than slerp() and will
542 give approximate results to spherical interpolation that are
543 good enough for some applications.
544
545 \sa slerp()
546*/
547QQuaternion QQuaternion::nlerp
548 (const QQuaternion& q1, const QQuaternion& q2, qreal t)
549{
550 // Handle the easy cases first.
551 if (t <= 0.0f)
552 return q1;
553 else if (t >= 1.0f)
554 return q2;
555
556 // Determine the angle between the two quaternions.
557 QQuaternion q2b;
558 qreal dot;
559 dot = q1.xp * q2.xp + q1.yp * q2.yp + q1.zp * q2.zp + q1.wp * q2.wp;
560 if (dot >= 0.0f)
561 q2b = q2;
562 else
563 q2b = -q2;
564
565 // Perform the linear interpolation.
566 return (q1 * (1.0f - t) + q2b * t).normalized();
567}
568
569/*!
570 Returns the quaternion as a QVariant.
571*/
572QQuaternion::operator QVariant() const
573{
574 return QVariant(QVariant::Quaternion, this);
575}
576
577#ifndef QT_NO_DEBUG_STREAM
578
579QDebug operator<<(QDebug dbg, const QQuaternion &q)
580{
581 dbg.nospace() << "QQuaternion(scalar:" << q.scalar()
582 << ", vector:(" << q.x() << ", "
583 << q.y() << ", " << q.z() << "))";
584 return dbg.space();
585}
586
587#endif
588
589#ifndef QT_NO_DATASTREAM
590
591/*!
592 \fn QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
593 \relates QQuaternion
594
595 Writes the given \a quaternion to the given \a stream and returns a
596 reference to the stream.
597
598 \sa {Format of the QDataStream Operators}
599*/
600
601QDataStream &operator<<(QDataStream &stream, const QQuaternion &quaternion)
602{
603 stream << double(quaternion.scalar()) << double(quaternion.x())
604 << double(quaternion.y()) << double(quaternion.z());
605 return stream;
606}
607
608/*!
609 \fn QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
610 \relates QQuaternion
611
612 Reads a quaternion from the given \a stream into the given \a quaternion
613 and returns a reference to the stream.
614
615 \sa {Format of the QDataStream Operators}
616*/
617
618QDataStream &operator>>(QDataStream &stream, QQuaternion &quaternion)
619{
620 double scalar, x, y, z;
621 stream >> scalar;
622 stream >> x;
623 stream >> y;
624 stream >> z;
625 quaternion.setScalar(qreal(scalar));
626 quaternion.setX(qreal(x));
627 quaternion.setY(qreal(y));
628 quaternion.setZ(qreal(z));
629 return stream;
630}
631
632#endif // QT_NO_DATASTREAM
633
634#endif
635
636QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.