From 9efce81eac02b24597e78b3ec4081d8dda85f3cf Mon Sep 17 00:00:00 2001 From: Gawaboumga Date: Wed, 30 Dec 2015 15:33:26 +0100 Subject: [PATCH] Documentation for Quaternion Former-commit-id: b19bd792823e1f49ff088fc95be26f0db185a8a6 --- include/Nazara/Math/Quaternion.hpp | 10 +- include/Nazara/Math/Quaternion.inl | 463 +++++++++++++++++++++++++---- 2 files changed, 416 insertions(+), 57 deletions(-) diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index b8ca310c1..f33dec0b6 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -19,9 +19,9 @@ namespace Nz public: Quaternion() = default; Quaternion(T W, T X, T Y, T Z); - Quaternion(const T quat[4]); - Quaternion(T angle, const Vector3& axis); Quaternion(const EulerAngles& angles); + Quaternion(T angle, const Vector3& axis); + Quaternion(const T quat[4]); //Quaternion(const Matrix3& mat); template explicit Quaternion(const Quaternion& quat); Quaternion(const Quaternion& quat) = default; @@ -47,9 +47,9 @@ namespace Nz Quaternion& Normalize(T* length = nullptr); Quaternion& Set(T W, T X, T Y, T Z); - Quaternion& Set(const T quat[4]); - Quaternion& Set(T angle, const Vector3& normalizedAxis); Quaternion& Set(const EulerAngles& angles); + Quaternion& Set(T angle, const Vector3& normalizedAxis); + Quaternion& Set(const T quat[4]); //Quaternion& Set(const Matrix3& mat); Quaternion& Set(const Quaternion& quat); template Quaternion& Set(const Quaternion& quat); @@ -60,7 +60,7 @@ namespace Nz //Matrix3 ToRotationMatrix() const; String ToString() const; - Quaternion& operator=(const Quaternion& quat); + Quaternion& operator=(const Quaternion& quat) = default; Quaternion operator+(const Quaternion& quat) const; Quaternion operator*(const Quaternion& quat) const; diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index 50c8ec8e3..ea1ce4d3e 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -15,29 +15,67 @@ namespace Nz { + /*! + * \class Nz::Quaternion + * \brief Math class that represents an element of the quaternions + * + * \remark The quaternion is meant to be 'unit' to represent rotations in a three dimensional space + */ + + /*! + * \brief Constructs a Quaternion object from its components + * + * \param W W component + * \param X X component + * \param Y Y component + * \param Z Z component + */ + template Quaternion::Quaternion(T W, T X, T Y, T Z) { Set(W, X, Y, Z); } + /*! + * \brief Constructs a Quaternion object from a EulerAngles + * + * \param angles Easier representation of rotation of space + * + * \see EulerAngles + */ + template - Quaternion::Quaternion(const T quat[4]) + Quaternion::Quaternion(const EulerAngles& angles) { - Set(quat); + Set(angles); } + /*! + * \brief Constructs a Quaternion object from an angle and a direction + * + * \param angle Unit depends of NAZARA_MATH_ANGLE_RADIAN + * \param axis Vector3 which represents a direction, no need to be normalized + */ + template Quaternion::Quaternion(T angle, const Vector3& axis) { Set(angle, axis); } + /*! + * \brief Constructs a Quaternion object from an array of four elements + * + * \param quat[4] quat[0] is W component, quat[1] is X component, quat[2] is Y component and quat[3] is Z component + */ + template - Quaternion::Quaternion(const EulerAngles& angles) + Quaternion::Quaternion(const T quat[4]) { - Set(angles); + Set(quat); } + /* template Quaternion::Quaternion(const Matrix3& mat) @@ -45,6 +83,13 @@ namespace Nz Set(mat); } */ + + /*! + * \brief Constructs a Quaternion object from another type of Quaternion + * + * \param quat Quaternion of type U to convert to type T + */ + template template Quaternion::Quaternion(const Quaternion& quat) @@ -52,6 +97,11 @@ namespace Nz Set(quat); } + /*! + * \brief Computes the w component of the quaternion to make it unit + * \return A reference to this quaternion + */ + template Quaternion& Quaternion::ComputeW() { @@ -65,6 +115,15 @@ namespace Nz return *this; } + /*! + * \brief Returns the rotational conjugate of this quaternion + * \return A reference to this quaternion + * + * The conjugate of a quaternion represents the same rotation in the opposite direction about the rotational axis + * + * \see GetConjugate + */ + template Quaternion& Quaternion::Conjugate() { @@ -75,12 +134,28 @@ namespace Nz return *this; } + /*! + * \brief Calculates the dot (scalar) product with two quaternions + * \return The value of the dot product + * + * \param quat The other quaternion to calculate the dot product with + */ + template T Quaternion::DotProduct(const Quaternion& quat) const { - return w*quat.w + x*quat.x + y*quat.y + z*quat.z; + return w * quat.w + x * quat.x + y * quat.y + z * quat.z; } + /*! + * \brief Gets the rotational conjugate of this quaternion + * \return A new quaternion which is the conjugate of this quaternion + * + * The conjugate of a quaternion represents the same rotation in the opposite direction about the rotational axis + * + * \see Conjugate + */ + template Quaternion Quaternion::GetConjugate() const { @@ -90,6 +165,15 @@ namespace Nz return quat; } + /*! + * \brief Gets the inverse of this quaternion + * \return A new quaternion which is the inverse of this quaternion + * + * \remark If this quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) + * + * \see Inverse + */ + template Quaternion Quaternion::GetInverse() const { @@ -99,6 +183,17 @@ namespace Nz return quat; } + /*! + * \brief Gets the normalization of this quaternion + * \return A new quaternion which is the normalization of this quaternion + * + * \param length Optional argument to obtain the length's ratio of the quaternion and the unit-length + * + * \remark If this quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) and length is 0 + * + * \see Normalize + */ + template Quaternion Quaternion::GetNormal(T* length) const { @@ -108,6 +203,15 @@ namespace Nz return quat; } + /*! + * \brief Inverts this quaternion + * \return A reference to this quaternion which is now inverted + * + * \remark If this quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) + * + * \see GetInverse + */ + template Quaternion& Quaternion::Inverse() { @@ -125,15 +229,34 @@ namespace Nz return *this; } + /*! + * \brief Makes the quaternion (1, 0, 0, 0) + * \return A reference to this vector with components (1, 0, 0, 0) + * + * \see Unit + */ + template Quaternion& Quaternion::MakeIdentity() { return Set(F(1.0), F(0.0), F(0.0), F(0.0)); } + /*! + * \brief Makes this quaternion to the rotation required to rotate direction Vector3 from to direction Vector3 to + * \return A reference to this vector which is the rotation needed + * + * \param from Initial vector + * \param to Target vector + * + * \see RotationBetween + */ + template Quaternion& Quaternion::MakeRotationBetween(const Vector3& from, const Vector3& to) { + // TODO (Gawaboumga): Replace by http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors ? + T dot = from.DotProduct(to); if (NumberEquals(dot, F(-1.0))) { @@ -157,28 +280,55 @@ namespace Nz } } + /*! + * \brief Makes the quaternion (0, 0, 0, 0) + * \return A reference to this vector with components (0, 0, 0, 0) + * + * \see Zero + */ + template Quaternion& Quaternion::MakeZero() { return Set(F(0.0), F(0.0), F(0.0), F(0.0)); } + /*! + * \brief Calculates the magnitude (length) of the quaternion + * \return The magnitude + * + * \see SquaredMagnitude + */ + template T Quaternion::Magnitude() const { return std::sqrt(SquaredMagnitude()); } + /*! + * \brief Normalizes the current quaternion + * \return A reference to this quaternion which is now normalized + * + * \param length Optional argument to obtain the length's ratio of the quaternion and the unit-length + * + * \remark If the quaternion is (0, 0, 0, 0), then it returns (0, 0, 0, 0) and length is 0 + * + * \see GetNormal + */ + template Quaternion& Quaternion::Normalize(T* length) { T norm = std::sqrt(SquaredMagnitude()); - T invNorm = F(1.0) / norm; - - w *= invNorm; - x *= invNorm; - y *= invNorm; - z *= invNorm; + if (norm > F(0.0)) + { + T invNorm = F(1.0) / norm; + w *= invNorm; + x *= invNorm; + y *= invNorm; + z *= invNorm; + } if (length) *length = norm; @@ -186,6 +336,16 @@ namespace Nz return *this; } + /*! + * \brief Sets the components of the quaternion + * \return A reference to this quaternion + * + * \param W W component + * \param X X component + * \param Y Y component + * \param Z Z component + */ + template Quaternion& Quaternion::Set(T W, T X, T Y, T Z) { @@ -197,17 +357,29 @@ namespace Nz return *this; } - template - Quaternion& Quaternion::Set(const T quat[4]) - { - w = quat[0]; - x = quat[1]; - y = quat[2]; - z = quat[3]; + /*! + * \brief Sets this quaternion from rotation specified by Euler angle + * \return A reference to this quaternion + * + * \param angles Easier representation of rotation of space + * + * \see EulerAngles + */ - return *this; + template + Quaternion& Quaternion::Set(const EulerAngles& angles) + { + return Set(angles.ToQuaternion()); } + /*! + * \brief Sets this quaternion from rotation specified by axis and angle + * \return A reference to this quaternion + * + * \param angle Unit depends of NAZARA_MATH_ANGLE_RADIAN + * \param axis Vector3 which represents a direction, no need to be normalized + */ + template Quaternion& Quaternion::Set(T angle, const Vector3& axis) { @@ -229,12 +401,46 @@ namespace Nz return Normalize(); } + /*! + * \brief Sets the components of the quaternion from an array of four elements + * \return A reference to this quaternion + * + * \param quat[4] quat[0] is W component, quat[1] is X component, quat[2] is Y component and quat[3] is Z component + */ + template - Quaternion& Quaternion::Set(const EulerAngles& angles) + Quaternion& Quaternion::Set(const T quat[4]) { - return Set(angles.ToQuaternion()); + w = quat[0]; + x = quat[1]; + y = quat[2]; + z = quat[3]; + + return *this; } + /*! + * \brief Sets the components of the quaternion from another quaternion + * \return A reference to this quaternion + * + * \param vec The other quaternion + */ + + template + Quaternion& Quaternion::Set(const Quaternion& quat) + { + std::memcpy(this, &quat, sizeof(Quaternion)); + + return *this; + } + + /*! + * \brief Sets the components of the quaternion from another type of Quaternion + * \return A reference to this quaternion + * + * \param quat Quaternion of type U to convert its components + */ + template template Quaternion& Quaternion::Set(const Quaternion& quat) @@ -247,36 +453,48 @@ namespace Nz return *this; } - template - Quaternion& Quaternion::Set(const Quaternion& quat) - { - std::memcpy(this, &quat, sizeof(Quaternion)); - - return *this; - } + /*! + * \brief Calculates the squared magnitude (length) of the quaternion + * \return The squared magnitude + * + * \see Magnitude + */ template T Quaternion::SquaredMagnitude() const { - return w*w + x*x + y*y + z*z; + return w * w + x * x + y * y + z * z; } + /*! + * \brief Converts this quaternion to Euler angles representation + * \return EulerAngles which is the representation of this rotation + * + * \remark Rotation are "left-handed" + */ + template EulerAngles Quaternion::ToEulerAngles() const { - T test = x*y + z*w; + T test = x * y + z * w; if (test > F(0.499)) // singularity at north pole return EulerAngles(FromDegrees(F(90.0)), FromRadians(F(2.0) * std::atan2(x, w)), F(0.0)); if (test < F(-0.499)) + // singularity at south pole return EulerAngles(FromDegrees(F(-90.0)), FromRadians(F(-2.0) * std::atan2(x, w)), F(0.0)); - return EulerAngles(FromRadians(std::atan2(F(2.0)*x*w - F(2.0)*y*z, F(1.0) - F(2.0)*x*x - F(2.0)*z*z)), - FromRadians(std::atan2(F(2.0)*y*w - F(2.0)*x*z, F(1.0) - F(2.0)*y*y - F(2.0)*z*z)), - FromRadians(std::asin(F(2.0)*test))); + return EulerAngles(FromRadians(std::atan2(F(2.0) * x * w - F(2.0) * y * z, F(1.0) - F(2.0) * x * x - F(2.0) * z * z)), + FromRadians(std::atan2(F(2.0) * y * w - F(2.0) * x * z, F(1.0) - F(2.0) * y * y - F(2.0) * z * z)), + FromRadians(std::asin(F(2.0) * test))); } + /*! + * \brief Gives a string representation + * \return A string representation of the object: "Quaternion(w | x, y, z)" + */ + template String Quaternion::ToString() const { @@ -285,11 +503,12 @@ namespace Nz return ss << "Quaternion(" << w << " | " << x << ", " << y << ", " << z << ')'; } - template - Quaternion& Quaternion::operator=(const Quaternion& quat) - { - return Set(quat); - } + /*! + * \brief Adds the components of the quaternion with other quaternion + * \return A quaternion where components are the sum of this quaternion and the other one + * + * \param quat The other quaternion to add components with + */ template Quaternion Quaternion::operator+(const Quaternion& quat) const @@ -303,18 +522,32 @@ namespace Nz return result; } + /*! + * \brief Multiplies of the quaternion with other quaternion + * \return A quaternion which is the product of those two according to operator* in quaternions + * + * \param quat The other quaternion to multiply with + */ + template Quaternion Quaternion::operator*(const Quaternion& quat) const { Quaternion result; - result.w = w*quat.w - x*quat.x - y*quat.y - z*quat.z; - result.x = w*quat.x + x*quat.w + y*quat.z - z*quat.y; - result.y = w*quat.y + y*quat.w + z*quat.x - x*quat.z; - result.z = w*quat.z + z*quat.w + x*quat.y - y*quat.x; + result.w = w * quat.w - x * quat.x - y * quat.y - z * quat.z; + result.x = w * quat.x + x * quat.w + y * quat.z - z * quat.y; + result.y = w * quat.y + y * quat.w + z * quat.x - x * quat.z; + result.z = w * quat.z + z * quat.w + x * quat.y - y * quat.x; return result; } + /*! + * \brief Apply the quaternion to the Vector3 + * \return A Vector3f which is the vector rotated by this quaternion + * + * \param vec The vector to multiply with + */ + template Vector3 Quaternion::operator*(const Vector3& vec) const { @@ -327,60 +560,123 @@ namespace Nz return vec + uv + uuv; } + /*! + * \brief Multiplies the components of the quaternion with a scalar + * \return A quaternion where components are the product of this quaternion and the scalar + * + * \param scale The scalar to multiply components with + */ + template Quaternion Quaternion::operator*(T scale) const { return Quaternion(w * scale, - x * scale, - y * scale, - z * scale); + x * scale, + y * scale, + z * scale); } + /*! + * \brief Divides the quaternion with other quaternion + * \return A quaternion which is the quotient of those two according to operator* in quaternions + * + * \param quat The other quaternion to divide with + */ + template Quaternion Quaternion::operator/(const Quaternion& quat) const { return quat.GetConjugate() * (*this); } + /*! + * \brief Adds the components of the quaternion with other quaternion + * \return A reference to this quaternion where components are the sum of this quaternion and the other one + * + * \param quat The other quaternion to add components with + */ + template Quaternion& Quaternion::operator+=(const Quaternion& quat) { return operator=(operator+(quat)); } + /*! + * \brief Multiplies of the quaternion with other quaternion + * \return A reference to this quaternion which is the product of those two according to operator* in quaternions + * + * \param quat The other quaternion to multiply with + */ + template Quaternion& Quaternion::operator*=(const Quaternion& quat) { return operator=(operator*(quat)); } + /*! + * \brief Multiplies the components of the quaternion with a scalar + * \return A reference to this quaternion where components are the product of this quaternion and the scalar + * + * \param scale The scalar to multiply components with + */ + template Quaternion& Quaternion::operator*=(T scale) { return operator=(operator*(scale)); } + /*! + * \brief Divides the quaternion with other quaternion + * \return A reference to this quaternion which is the quotient of those two according to operator* in quaternions + * + * \param quat The other quaternion to divide with + */ + template Quaternion& Quaternion::operator/=(const Quaternion& quat) { return operator=(operator/(quat)); } + /*! + * \brief Compares the quaternion to other one + * \return true if the quaternions are the same + * + * \param vec Other quaternion to compare with + */ + template bool Quaternion::operator==(const Quaternion& quat) const { return NumberEquals(w, quat.w) && - NumberEquals(x, quat.x) && - NumberEquals(y, quat.y) && - NumberEquals(z, quat.z); + NumberEquals(x, quat.x) && + NumberEquals(y, quat.y) && + NumberEquals(z, quat.z); } + /*! + * \brief Compares the quaternion to other one + * \return false if the quaternions are the same + * + * \param vec Other quaternion to compare with + */ + template bool Quaternion::operator!=(const Quaternion& quat) const { return !operator==(quat); } + /*! + * \brief Shorthand for the quaternion (1, 0, 0, 0) + * \return A quaternion with components (1, 0, 0, 0) + * + * \see MakeIdentity + */ + template Quaternion Quaternion::Identity() { @@ -390,6 +686,20 @@ namespace Nz return quaternion; } + /*! + * \brief Interpolates the quaternion to other one with a factor of interpolation + * \return A new quaternion which is the interpolation of two quaternions + * + * \param from Initial quaternion + * \param to Target quaternion + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp, Slerp + */ + template Quaternion Quaternion::Lerp(const Quaternion& from, const Quaternion& to, T interpolation) { @@ -410,12 +720,32 @@ namespace Nz return interpolated; } + /*! + * \brief Gives the normalized quaternion + * \return A normalized quaternion from the quat + * + * \param quat Quaternion to normalize + * \param length Optional argument to obtain the length's ratio of the vector and the unit-length + * + * \see GetNormal + */ + template Quaternion Quaternion::Normalize(const Quaternion& quat, T* length) { return quat.GetNormal(length); } + /*! + * \brief Gets the rotation required to rotate direction Vector3 from to direction Vector3 to + * \return A quaternion which is the rotation needed between those two Vector3 + * + * \param from Initial vector + * \param to Target vector + * + * \see MakeRotationBetween + */ + template Quaternion Quaternion::RotationBetween(const Vector3& from, const Vector3& to) { @@ -425,6 +755,20 @@ namespace Nz return quaternion; } + /*! + * \brief Interpolates spherically the quaternion to other one with a factor of interpolation + * \return A new quaternion which is the interpolation of two quaternions + * + * \param from Initial quaternion + * \param to Target quaternion + * \param interpolation Factor of interpolation + * + * \remark interpolation is meant to be between 0 and 1, other values are potentially undefined behavior + * \remark With NAZARA_DEBUG, a NazaraError is thrown and Zero() is returned + * + * \see Lerp + */ + template Quaternion Quaternion::Slerp(const Quaternion& from, const Quaternion& to, T interpolation) { @@ -441,7 +785,7 @@ namespace Nz T cosOmega = from.DotProduct(to); if (cosOmega < F(0.0)) { - // On inverse tout + // We invert everything q.Set(-to.w, -to.x, -to.y, -to.z); cosOmega = -cosOmega; } @@ -451,7 +795,7 @@ namespace Nz T k0, k1; if (cosOmega > F(0.9999)) { - // Interpolation linéaire pour éviter une division par zéro + // Linear interpolation to avoid division by zero k0 = F(1.0) - interpolation; k1 = interpolation; } @@ -460,7 +804,7 @@ namespace Nz T sinOmega = std::sqrt(F(1.0) - cosOmega*cosOmega); T omega = std::atan2(sinOmega, cosOmega); - // Pour éviter deux divisions + // To avoid two divisions sinOmega = F(1.0)/sinOmega; k0 = std::sin((F(1.0) - interpolation) * omega) * sinOmega; @@ -468,9 +812,16 @@ namespace Nz } Quaternion result(k0 * from.w, k0 * from.x, k0 * from.y, k0 * from.z); - return result += q*k1; + return result += q * k1; } + /*! + * \brief Shorthand for the quaternion (0, 0, 0, 0) + * \return A quaternion with components (0, 0, 0, 0) + * + * \see MakeZero + */ + template Quaternion Quaternion::Zero() { @@ -481,6 +832,14 @@ namespace Nz } } +/*! +* \brief Output operator +* \return The stream +* +* \param out The stream +* \param quat The quaternion to output +*/ + template std::ostream& operator<<(std::ostream& out, const Nz::Quaternion& quat) {