mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
569 lines
20 KiB
569 lines
20 KiB
|
14 years ago
|
#ifndef Magnum_Math_Quaternion_h
|
||
|
|
#define Magnum_Math_Quaternion_h
|
||
|
|
/*
|
||
|
|
This file is part of Magnum.
|
||
|
|
|
||
|
13 years ago
|
Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš <mosra@centrum.cz>
|
||
|
|
|
||
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
|
copy of this software and associated documentation files (the "Software"),
|
||
|
|
to deal in the Software without restriction, including without limitation
|
||
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
||
|
|
Software is furnished to do so, subject to the following conditions:
|
||
|
|
|
||
|
|
The above copyright notice and this permission notice shall be included
|
||
|
|
in all copies or substantial portions of the Software.
|
||
|
14 years ago
|
|
||
|
13 years ago
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
|
DEALINGS IN THE SOFTWARE.
|
||
|
14 years ago
|
*/
|
||
|
|
|
||
|
|
/** @file
|
||
|
|
* @brief Class Magnum::Math::Quaternion
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <cmath>
|
||
|
14 years ago
|
#include <Utility/Assert.h>
|
||
|
14 years ago
|
#include <Utility/Debug.h>
|
||
|
|
|
||
|
13 years ago
|
#include "Math/TypeTraits.h"
|
||
|
14 years ago
|
#include "Math/Matrix.h"
|
||
|
14 years ago
|
#include "Math/Vector3.h"
|
||
|
14 years ago
|
|
||
|
|
namespace Magnum { namespace Math {
|
||
|
|
|
||
|
14 years ago
|
/**
|
||
|
|
@brief %Quaternion
|
||
|
13 years ago
|
@tparam T Underlying data type
|
||
|
14 years ago
|
|
||
|
13 years ago
|
Represents 3D rotation. See @ref transformations for brief introduction.
|
||
|
13 years ago
|
@see Magnum::Quaternion, Magnum::Quaterniond, DualQuaternion, Matrix4
|
||
|
14 years ago
|
*/
|
||
|
14 years ago
|
template<class T> class Quaternion {
|
||
|
|
public:
|
||
|
13 years ago
|
typedef T Type; /**< @brief Underlying data type */
|
||
|
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Dot product
|
||
|
|
*
|
||
|
|
* @f[
|
||
|
13 years ago
|
* p \cdot q = \boldsymbol p_V \cdot \boldsymbol q_V + p_S q_S
|
||
|
14 years ago
|
* @f]
|
||
|
|
* @see dot() const
|
||
|
|
*/
|
||
|
13 years ago
|
static T dot(const Quaternion<T>& a, const Quaternion<T>& b) {
|
||
|
14 years ago
|
/** @todo Use four-component SIMD implementation when available */
|
||
|
|
return Vector3<T>::dot(a.vector(), b.vector()) + a.scalar()*b.scalar();
|
||
|
|
}
|
||
|
|
|
||
|
14 years ago
|
/**
|
||
|
13 years ago
|
* @brief Angle between normalized quaternions
|
||
|
14 years ago
|
*
|
||
|
|
* Expects that both quaternions are normalized. @f[
|
||
|
13 years ago
|
* \theta = acos \left( \frac{p \cdot q}{|p| |q|} \right) = acos(p \cdot q)
|
||
|
14 years ago
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), Complex::angle(), Vector::angle()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
static Rad<T> angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB);
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Linear interpolation of two quaternions
|
||
|
|
* @param normalizedA First quaternion
|
||
|
|
* @param normalizedB Second quaternion
|
||
|
|
* @param t Interpolation phase (from range @f$ [0; 1] @f$)
|
||
|
|
*
|
||
|
|
* Expects that both quaternions are normalized. @f[
|
||
|
|
* q_{LERP} = \frac{(1 - t) q_A + t q_B}{|(1 - t) q_A + t q_B|}
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), slerp(), Math::lerp()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
static Quaternion<T> lerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t);
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Spherical linear interpolation of two quaternions
|
||
|
|
* @param normalizedA First quaternion
|
||
|
|
* @param normalizedB Second quaternion
|
||
|
|
* @param t Interpolation phase (from range @f$ [0; 1] @f$)
|
||
|
|
*
|
||
|
|
* Expects that both quaternions are normalized. @f[
|
||
|
|
* q_{SLERP} = \frac{sin((1 - t) \theta) q_A + sin(t \theta) q_B}{sin \theta}
|
||
|
|
* ~~~~~~~~~~
|
||
|
13 years ago
|
* \theta = acos \left( \frac{q_A \cdot q_B}{|q_A| \cdot |q_B|} \right) = acos(q_A \cdot q_B)
|
||
|
14 years ago
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), lerp()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
static Quaternion<T> slerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, T t);
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
13 years ago
|
* @brief Rotation quaternion
|
||
|
13 years ago
|
* @param angle Rotation angle (counterclockwise)
|
||
|
14 years ago
|
* @param normalizedAxis Normalized rotation axis
|
||
|
|
*
|
||
|
14 years ago
|
* Expects that the rotation axis is normalized. @f[
|
||
|
|
* q = [\boldsymbol a \cdot sin \frac \theta 2, cos \frac \theta 2]
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see angle(), axis(), DualQuaternion::rotation(),
|
||
|
13 years ago
|
* Matrix4::rotation(), Complex::rotation(), Vector3::xAxis(),
|
||
|
13 years ago
|
* Vector3::yAxis(), Vector3::zAxis(), Vector::isNormalized()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
static Quaternion<T> rotation(Rad<T> angle, const Vector3<T>& normalizedAxis);
|
||
|
14 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Create quaternion from rotation matrix
|
||
|
|
*
|
||
|
|
* Expects that the matrix is orthogonal (i.e. pure rotation).
|
||
|
|
* @see toMatrix(), DualComplex::fromMatrix(), Matrix::isOrthogonal()
|
||
|
|
*/
|
||
|
13 years ago
|
static Quaternion<T> fromMatrix(const Matrix<3, T>& matrix);
|
||
|
13 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Default constructor
|
||
|
|
*
|
||
|
13 years ago
|
* Creates unit quaternion. @f[
|
||
|
13 years ago
|
* q = [\boldsymbol 0, 1]
|
||
|
|
* @f]
|
||
|
13 years ago
|
*/
|
||
|
13 years ago
|
constexpr /*implicit*/ Quaternion(): _scalar(T(1)) {}
|
||
|
14 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Construct quaternion from vector and scalar
|
||
|
|
*
|
||
|
|
* @f[
|
||
|
|
* q = [\boldsymbol v, s]
|
||
|
|
* @f]
|
||
|
|
*/
|
||
|
13 years ago
|
constexpr /*implicit*/ Quaternion(const Vector3<T>& vector, T scalar): _vector(vector), _scalar(scalar) {}
|
||
|
14 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
13 years ago
|
* @brief Construct quaternion from vector
|
||
|
13 years ago
|
*
|
||
|
13 years ago
|
* To be used in transformations later. @f[
|
||
|
|
* q = [\boldsymbol v, 0]
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see transformVector(), transformVectorNormalized()
|
||
|
13 years ago
|
*/
|
||
|
13 years ago
|
constexpr explicit Quaternion(const Vector3<T>& vector): _vector(vector), _scalar(T(0)) {}
|
||
|
13 years ago
|
|
||
|
14 years ago
|
/** @brief Equality comparison */
|
||
|
13 years ago
|
bool operator==(const Quaternion<T>& other) const {
|
||
|
13 years ago
|
return _vector == other._vector && TypeTraits<T>::equals(_scalar, other._scalar);
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
|
/** @brief Non-equality comparison */
|
||
|
13 years ago
|
bool operator!=(const Quaternion<T>& other) const {
|
||
|
14 years ago
|
return !operator==(other);
|
||
|
|
}
|
||
|
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Whether the quaternion is normalized
|
||
|
|
*
|
||
|
|
* Quaternion is normalized if it has unit length: @f[
|
||
|
13 years ago
|
* |q \cdot q - 1| < 2 \epsilon + \epsilon^2 \cong 2 \epsilon
|
||
|
13 years ago
|
* @f]
|
||
|
|
* @see dot(), normalized()
|
||
|
|
*/
|
||
|
13 years ago
|
bool isNormalized() const {
|
||
|
13 years ago
|
return Implementation::isNormalizedSquared(dot());
|
||
|
13 years ago
|
}
|
||
|
|
|
||
|
14 years ago
|
/** @brief %Vector part */
|
||
|
13 years ago
|
constexpr Vector3<T> vector() const { return _vector; }
|
||
|
14 years ago
|
|
||
|
|
/** @brief %Scalar part */
|
||
|
13 years ago
|
constexpr T scalar() const { return _scalar; }
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Rotation angle of unit quaternion
|
||
|
|
*
|
||
|
14 years ago
|
* Expects that the quaternion is normalized. @f[
|
||
|
|
* \theta = 2 \cdot acos q_S
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), axis(), rotation()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Rad<T> angle() const;
|
||
|
14 years ago
|
|
||
|
|
/**
|
||
|
|
* @brief Rotation axis of unit quaternion
|
||
|
|
*
|
||
|
13 years ago
|
* Expects that the quaternion is normalized. Returns either unit-length
|
||
|
|
* vector for valid rotation quaternion or NaN vector for
|
||
|
|
* default-constructed quaternion. @f[
|
||
|
14 years ago
|
* \boldsymbol a = \frac{\boldsymbol q_V}{\sqrt{1 - q_S^2}}
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), angle(), rotation()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Vector3<T> axis() const;
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Convert quaternion to rotation matrix
|
||
|
|
*
|
||
|
13 years ago
|
* @see fromMatrix(), DualQuaternion::toMatrix(),
|
||
|
|
* Matrix4::from(const Matrix<3, T>&, const Vector3<T>&)
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Matrix<3, T> toMatrix() const;
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Add and assign quaternion
|
||
|
|
*
|
||
|
|
* The computation is done in-place. @f[
|
||
|
|
* p + q = [\boldsymbol p_V + \boldsymbol q_V, p_S + q_S]
|
||
|
|
* @f]
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T>& operator+=(const Quaternion<T>& other) {
|
||
|
14 years ago
|
_vector += other._vector;
|
||
|
|
_scalar += other._scalar;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Add quaternion
|
||
|
|
*
|
||
|
|
* @see operator+=()
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T> operator+(const Quaternion<T>& other) const {
|
||
|
13 years ago
|
return Quaternion<T>(*this) += other;
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Negated quaternion
|
||
|
|
*
|
||
|
|
* @f[
|
||
|
|
* -q = [-\boldsymbol q_V, -q_S]
|
||
|
|
* @f]
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T> operator-() const { return {-_vector, -_scalar}; }
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Subtract and assign quaternion
|
||
|
|
*
|
||
|
|
* The computation is done in-place. @f[
|
||
|
|
* p - q = [\boldsymbol p_V - \boldsymbol q_V, p_S - q_S]
|
||
|
|
* @f]
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T>& operator-=(const Quaternion<T>& other) {
|
||
|
14 years ago
|
_vector -= other._vector;
|
||
|
|
_scalar -= other._scalar;
|
||
|
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Subtract quaternion
|
||
|
|
*
|
||
|
|
* @see operator-=()
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T> operator-(const Quaternion<T>& other) const {
|
||
|
13 years ago
|
return Quaternion<T>(*this) -= other;
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Multiply with scalar and assign
|
||
|
|
*
|
||
|
14 years ago
|
* The computation is done in-place. @f[
|
||
|
|
* q \cdot a = [\boldsymbol q_V \cdot a, q_S \cdot a]
|
||
|
|
* @f]
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Quaternion<T>& operator*=(T scalar) {
|
||
|
14 years ago
|
_vector *= scalar;
|
||
|
|
_scalar *= scalar;
|
||
|
14 years ago
|
return *this;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
14 years ago
|
* @brief Multiply with scalar
|
||
|
14 years ago
|
*
|
||
|
14 years ago
|
* @see operator*=(T)
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Quaternion<T> operator*(T scalar) const {
|
||
|
13 years ago
|
return Quaternion<T>(*this) *= scalar;
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
14 years ago
|
* @brief Divide with scalar and assign
|
||
|
14 years ago
|
*
|
||
|
14 years ago
|
* The computation is done in-place. @f[
|
||
|
|
* \frac q a = [\frac {\boldsymbol q_V} a, \frac {q_S} a]
|
||
|
|
* @f]
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Quaternion<T>& operator/=(T scalar) {
|
||
|
14 years ago
|
_vector /= scalar;
|
||
|
|
_scalar /= scalar;
|
||
|
14 years ago
|
return *this;
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Divide with scalar
|
||
|
|
*
|
||
|
|
* @see operator/=(T)
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T> operator/(T scalar) const {
|
||
|
13 years ago
|
return Quaternion<T>(*this) /= scalar;
|
||
|
14 years ago
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Multiply with quaternion
|
||
|
|
*
|
||
|
14 years ago
|
* @f[
|
||
|
|
* p q = [p_S \boldsymbol q_V + q_S \boldsymbol p_V + \boldsymbol p_V \times \boldsymbol q_V,
|
||
|
|
* p_S q_S - \boldsymbol p_V \cdot \boldsymbol q_V]
|
||
|
|
* @f]
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Quaternion<T> operator*(const Quaternion<T>& other) const;
|
||
|
14 years ago
|
|
||
|
|
/**
|
||
|
14 years ago
|
* @brief Dot product of the quaternion
|
||
|
14 years ago
|
*
|
||
|
14 years ago
|
* Should be used instead of length() for comparing quaternion length
|
||
|
|
* with other values, because it doesn't compute the square root. @f[
|
||
|
14 years ago
|
* q \cdot q = \boldsymbol q_V \cdot \boldsymbol q_V + q_S^2
|
||
|
14 years ago
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), dot(const Quaternion&, const Quaternion&)
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
T dot() const { return dot(*this, *this); }
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief %Quaternion length
|
||
|
|
*
|
||
|
13 years ago
|
* See also dot() const which is faster for comparing length with other
|
||
|
|
* values. @f[
|
||
|
14 years ago
|
* |q| = \sqrt{q \cdot q}
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
T length() const { return std::sqrt(dot()); }
|
||
|
14 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Normalized quaternion (of unit length)
|
||
|
|
*
|
||
|
|
* @see isNormalized()
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T> normalized() const { return (*this)/length(); }
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Conjugated quaternion
|
||
|
|
*
|
||
|
|
* @f[
|
||
|
|
* q^* = [-\boldsymbol q_V, q_S]
|
||
|
|
* @f]
|
||
|
|
*/
|
||
|
13 years ago
|
Quaternion<T> conjugated() const { return {-_vector, _scalar}; }
|
||
|
14 years ago
|
|
||
|
|
/**
|
||
|
|
* @brief Inverted quaternion
|
||
|
|
*
|
||
|
14 years ago
|
* See invertedNormalized() which is faster for normalized
|
||
|
14 years ago
|
* quaternions. @f[
|
||
|
13 years ago
|
* q^{-1} = \frac{q^*}{|q|^2} = \frac{q^*}{q \cdot q}
|
||
|
14 years ago
|
* @f]
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Quaternion<T> inverted() const { return conjugated()/dot(); }
|
||
|
14 years ago
|
|
||
|
14 years ago
|
/**
|
||
|
|
* @brief Inverted normalized quaternion
|
||
|
|
*
|
||
|
14 years ago
|
* Equivalent to conjugated(). Expects that the quaternion is
|
||
|
|
* normalized. @f[
|
||
|
13 years ago
|
* q^{-1} = \frac{q^*}{|q|^2} = q^*
|
||
|
14 years ago
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), inverted()
|
||
|
14 years ago
|
*/
|
||
|
13 years ago
|
Quaternion<T> invertedNormalized() const;
|
||
|
14 years ago
|
|
||
|
13 years ago
|
/**
|
||
|
|
* @brief Rotate vector with quaternion
|
||
|
|
*
|
||
|
13 years ago
|
* See transformVectorNormalized(), which is faster for normalized
|
||
|
13 years ago
|
* quaternions. @f[
|
||
|
13 years ago
|
* v' = qvq^{-1} = q [\boldsymbol v, 0] q^{-1}
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see Quaternion(const Vector3&), vector(), Matrix4::transformVector(),
|
||
|
|
* DualQuaternion::transformPoint(), Complex::transformVector()
|
||
|
13 years ago
|
*/
|
||
|
13 years ago
|
Vector3<T> transformVector(const Vector3<T>& vector) const {
|
||
|
13 years ago
|
return ((*this)*Quaternion<T>(vector)*inverted()).vector();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @brief Rotate vector with normalized quaternion
|
||
|
|
*
|
||
|
13 years ago
|
* Faster alternative to transformVector(), expects that the quaternion
|
||
|
|
* is normalized. @f[
|
||
|
13 years ago
|
* v' = qvq^{-1} = qvq^* = q [\boldsymbol v, 0] q^*
|
||
|
|
* @f]
|
||
|
13 years ago
|
* @see isNormalized(), Quaternion(const Vector3&), vector(), Matrix4::transformVector(),
|
||
|
13 years ago
|
* DualQuaternion::transformPointNormalized(), Complex::transformVector()
|
||
|
13 years ago
|
*/
|
||
|
13 years ago
|
Vector3<T> transformVectorNormalized(const Vector3<T>& vector) const;
|
||
|
13 years ago
|
|
||
|
14 years ago
|
private:
|
||
|
13 years ago
|
/* Used to avoid including Functions.h */
|
||
|
13 years ago
|
constexpr static T pow2(T value) {
|
||
|
13 years ago
|
return value*value;
|
||
|
|
}
|
||
|
|
|
||
|
14 years ago
|
/* Used in angle() and slerp() (no assertions) */
|
||
|
13 years ago
|
static T angleInternal(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) {
|
||
|
14 years ago
|
return std::acos(dot(normalizedA, normalizedB));
|
||
|
|
}
|
||
|
|
|
||
|
14 years ago
|
Vector3<T> _vector;
|
||
|
|
T _scalar;
|
||
|
|
};
|
||
|
|
|
||
|
14 years ago
|
/** @relates Quaternion
|
||
|
|
@brief Multiply scalar with quaternion
|
||
|
|
|
||
|
|
Same as Quaternion::operator*(T) const.
|
||
|
|
*/
|
||
|
|
template<class T> inline Quaternion<T> operator*(T scalar, const Quaternion<T>& quaternion) {
|
||
|
|
return quaternion*scalar;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @relates Quaternion
|
||
|
|
@brief Divide quaternion with number and invert
|
||
|
|
|
||
|
|
@f[
|
||
|
|
\frac a q = [\frac a {\boldsymbol q_V}, \frac a {q_S}]
|
||
|
|
@f]
|
||
|
|
@see Quaternion::operator/()
|
||
|
|
*/
|
||
|
|
template<class T> inline Quaternion<T> operator/(T scalar, const Quaternion<T>& quaternion) {
|
||
|
|
return {scalar/quaternion.vector(), scalar/quaternion.scalar()};
|
||
|
|
}
|
||
|
|
|
||
|
13 years ago
|
/** @debugoperator{Magnum::Math::Quaternion} */
|
||
|
14 years ago
|
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Quaternion<T>& value) {
|
||
|
|
debug << "Quaternion({";
|
||
|
|
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, false);
|
||
|
|
debug << value.vector().x() << ", " << value.vector().y() << ", " << value.vector().z() << "}, " << value.scalar() << ")";
|
||
|
|
debug.setFlag(Corrade::Utility::Debug::SpaceAfterEachValue, true);
|
||
|
|
return debug;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Explicit instantiation for commonly used types */
|
||
|
|
#ifndef DOXYGEN_GENERATING_OUTPUT
|
||
|
13 years ago
|
extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Quaternion<Float>&);
|
||
|
14 years ago
|
#ifndef MAGNUM_TARGET_GLES
|
||
|
13 years ago
|
extern template Corrade::Utility::Debug MAGNUM_EXPORT operator<<(Corrade::Utility::Debug, const Quaternion<Double>&);
|
||
|
14 years ago
|
#endif
|
||
|
|
#endif
|
||
|
|
|
||
|
13 years ago
|
namespace Implementation {
|
||
|
|
|
||
|
|
/* No assertions fired, for internal use. Not private member because used from
|
||
|
|
outside the class. */
|
||
|
|
template<class T> Quaternion<T> quaternionFromMatrix(const Matrix<3, T>& m) {
|
||
|
|
const Vector<3, T> diagonal = m.diagonal();
|
||
|
|
const T trace = diagonal.sum();
|
||
|
|
|
||
|
|
/* Diagonal is positive */
|
||
|
|
if(trace > T(0)) {
|
||
|
|
const T s = std::sqrt(trace + T(1));
|
||
|
|
const T t = T(0.5)/s;
|
||
|
|
return {Vector3<T>(m[1][2] - m[2][1],
|
||
|
|
m[2][0] - m[0][2],
|
||
|
|
m[0][1] - m[1][0])*t, s*T(0.5)};
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Diagonal is negative */
|
||
|
|
std::size_t i = 0;
|
||
|
|
if(diagonal[1] > diagonal[0]) i = 1;
|
||
|
|
if(diagonal[2] > diagonal[i]) i = 2;
|
||
|
|
|
||
|
|
const std::size_t j = (i + 1) % 3;
|
||
|
|
const std::size_t k = (i + 2) % 3;
|
||
|
|
|
||
|
|
const T s = std::sqrt(diagonal[i] - diagonal[j] - diagonal[k] + T(1));
|
||
|
|
const T t = (s == T(0) ? T(0) : T(0.5)/s);
|
||
|
|
|
||
|
|
Vector3<T> vec;
|
||
|
|
vec[i] = s*T(0.5);
|
||
|
|
vec[j] = (m[i][j] + m[j][i])*t;
|
||
|
|
vec[k] = (m[i][k] + m[k][i])*t;
|
||
|
|
|
||
|
|
return {vec, (m[j][k] - m[k][j])*t};
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Rad<T> Quaternion<T>::angle(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB) {
|
||
|
|
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
|
||
|
|
"Math::Quaternion::angle(): quaternions must be normalized", Rad<T>(std::numeric_limits<T>::quiet_NaN()));
|
||
|
|
return Rad<T>(angleInternal(normalizedA, normalizedB));
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Quaternion<T> Quaternion<T>::lerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, const T t) {
|
||
|
|
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
|
||
|
|
"Math::Quaternion::lerp(): quaternions must be normalized", Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
|
||
|
|
return ((T(1) - t)*normalizedA + t*normalizedB).normalized();
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Quaternion<T> Quaternion<T>::slerp(const Quaternion<T>& normalizedA, const Quaternion<T>& normalizedB, const T t) {
|
||
|
|
CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(),
|
||
|
|
"Math::Quaternion::slerp(): quaternions must be normalized", Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
|
||
|
|
const T a = angleInternal(normalizedA, normalizedB);
|
||
|
|
return (std::sin((T(1) - t)*a)*normalizedA + std::sin(t*a)*normalizedB)/std::sin(a);
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Quaternion<T> Quaternion<T>::rotation(const Rad<T> angle, const Vector3<T>& normalizedAxis) {
|
||
|
|
CORRADE_ASSERT(normalizedAxis.isNormalized(),
|
||
|
|
"Math::Quaternion::rotation(): axis must be normalized", {});
|
||
|
|
return {normalizedAxis*std::sin(T(angle)/2), std::cos(T(angle)/2)};
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Quaternion<T> Quaternion<T>::fromMatrix(const Matrix<3, T>& matrix) {
|
||
|
|
CORRADE_ASSERT(matrix.isOrthogonal(), "Math::Quaternion::fromMatrix(): the matrix is not orthogonal", {});
|
||
|
|
return Implementation::quaternionFromMatrix(matrix);
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Rad<T> Quaternion<T>::angle() const {
|
||
|
|
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::angle(): quaternion must be normalized",
|
||
|
|
Rad<T>(std::numeric_limits<T>::quiet_NaN()));
|
||
|
|
return Rad<T>(T(2)*std::acos(_scalar));
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Vector3<T> Quaternion<T>::axis() const {
|
||
|
|
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::axis(): quaternion must be normalized", {});
|
||
|
|
return _vector/std::sqrt(1-pow2(_scalar));
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> Matrix<3, T> Quaternion<T>::toMatrix() const {
|
||
|
|
return {
|
||
|
|
Vector<3, T>(T(1) - 2*pow2(_vector.y()) - 2*pow2(_vector.z()),
|
||
|
|
2*_vector.x()*_vector.y() + 2*_vector.z()*_scalar,
|
||
|
|
2*_vector.x()*_vector.z() - 2*_vector.y()*_scalar),
|
||
|
|
Vector<3, T>(2*_vector.x()*_vector.y() - 2*_vector.z()*_scalar,
|
||
|
|
T(1) - 2*pow2(_vector.x()) - 2*pow2(_vector.z()),
|
||
|
|
2*_vector.y()*_vector.z() + 2*_vector.x()*_scalar),
|
||
|
|
Vector<3, T>(2*_vector.x()*_vector.z() + 2*_vector.y()*_scalar,
|
||
|
|
2*_vector.y()*_vector.z() - 2*_vector.x()*_scalar,
|
||
|
|
T(1) - 2*pow2(_vector.x()) - 2*pow2(_vector.y()))
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Quaternion<T> Quaternion<T>::operator*(const Quaternion<T>& other) const {
|
||
|
|
return {_scalar*other._vector + other._scalar*_vector + Vector3<T>::cross(_vector, other._vector),
|
||
|
|
_scalar*other._scalar - Vector3<T>::dot(_vector, other._vector)};
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Quaternion<T> Quaternion<T>::invertedNormalized() const {
|
||
|
|
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::invertedNormalized(): quaternion must be normalized",
|
||
|
|
Quaternion<T>({}, std::numeric_limits<T>::quiet_NaN()));
|
||
|
|
return conjugated();
|
||
|
|
}
|
||
|
|
|
||
|
|
template<class T> inline Vector3<T> Quaternion<T>::transformVectorNormalized(const Vector3< T >& vector) const {
|
||
|
|
CORRADE_ASSERT(isNormalized(), "Math::Quaternion::transformVectorNormalized(): quaternion must be normalized",
|
||
|
|
Vector3<T>(std::numeric_limits<T>::quiet_NaN()));
|
||
|
|
return ((*this)*Quaternion<T>(vector)*conjugated()).vector();
|
||
|
|
}
|
||
|
|
|
||
|
14 years ago
|
}}
|
||
|
|
|
||
|
|
#endif
|