src/gui/math3d/qquaternion.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    47 QT_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 */
       
   215 qreal 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 */
       
   225 qreal 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 */
       
   240 QQuaternion 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 */
       
   261 void 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.rotateVector(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 */
       
   300 QVector3D QQuaternion::rotateVector(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 */
       
   354 QQuaternion 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 */
       
   373 QQuaternion 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 */
       
   495 QQuaternion 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 */
       
   547 QQuaternion 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 */
       
   572 QQuaternion::operator QVariant() const
       
   573 {
       
   574     return QVariant(QVariant::Quaternion, this);
       
   575 }
       
   576 
       
   577 #ifndef QT_NO_DEBUG_STREAM
       
   578 
       
   579 QDebug 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 
       
   601 QDataStream &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 
       
   618 QDataStream &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 
       
   636 QT_END_NAMESPACE