/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
// CLASS HEADER
#include <dali/public-api/math/quaternion.h>
+// EXTERNAL INCLUDES
+#include <ostream>
+
// INTERNAL INCLUDES
#include <dali/public-api/common/constants.h>
#include <dali/public-api/math/degree.h>
#include <dali/public-api/math/matrix.h>
#include <dali/public-api/math/radian.h>
+#include <dali/public-api/math/math-utils.h>
#include <dali/internal/render/common/performance-monitor.h>
namespace Dali
* Default Constructor
*/
Quaternion::Quaternion()
- : mVector(0.0f, 0.0f, 0.0f, 1.0f)
+ : mVector( 0.0f, 0.0f, 0.0f, 1.0f )
{
}
-Quaternion::Quaternion(float cosThetaBy2, float iBySineTheta, float jBySineTheta, float kBySineTheta) :
- mVector(iBySineTheta, jBySineTheta, kBySineTheta, cosThetaBy2)
+Quaternion::Quaternion( float cosThetaBy2, float iBySineTheta, float jBySineTheta, float kBySineTheta ) :
+ mVector( iBySineTheta, jBySineTheta, kBySineTheta, cosThetaBy2 )
{
}
-Quaternion::Quaternion(const Vector4& vector)
+Quaternion::Quaternion( const Vector4& vector )
{
mVector = vector;
}
-Quaternion::Quaternion(float angle, const Vector3 &axis)
+Quaternion::Quaternion( Radian angle, const Vector3& axis )
{
MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,4);
Vector3 tmpAxis = axis;
tmpAxis.Normalize();
- const float halfAngle = angle * 0.5f;
+ const float halfAngle = angle.radian * 0.5f;
const float sinThetaByTwo = sinf(halfAngle);
const float cosThetaByTwo = cosf(halfAngle);
mVector.x = tmpAxis.x * sinThetaByTwo;
mVector.w = cosThetaByTwo;
}
-Quaternion::Quaternion(float theta, const Vector4 &axis)
+Quaternion::Quaternion( Radian pitch, Radian yaw, Radian roll )
{
- MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,4);
-
- Vector4 tmpAxis = axis;
- tmpAxis.Normalize();
- const float halfTheta = theta * 0.5f;
- const float sinThetaByTwo = sinf(halfTheta);
- const float cosThetaByTwo = cosf(halfTheta);
- mVector.x = tmpAxis.x * sinThetaByTwo;
- mVector.y = tmpAxis.y * sinThetaByTwo;
- mVector.z = tmpAxis.z * sinThetaByTwo;
- mVector.w = cosThetaByTwo;
+ SetEuler( pitch, yaw, roll );
}
-Quaternion::Quaternion(float x, float y, float z)
-{
- SetEuler(x,y,z);
-}
-
-Quaternion::Quaternion(const Matrix& matrix)
+Quaternion::Quaternion( const Matrix& matrix )
{
Vector3 xAxis( matrix.GetXAxis() );
Vector3 yAxis( matrix.GetYAxis() );
SetFromAxes( xAxis, yAxis, zAxis );
}
-
-Quaternion Quaternion::FromAxisAngle(const Vector4 &axis, float angle)
+Quaternion::Quaternion( const Vector3& v0, const Vector3& v1 )
{
- return Quaternion(angle, axis);
+ float dot = v0.Dot(v1);
+ if( dot > 1.0f - Math::MACHINE_EPSILON_1 )
+ {
+ //Identity quaternion
+ mVector.x = mVector.y = mVector.z = 0.0f;
+ mVector.w = 1.0f;
+ }
+ else if( dot < -1.0f + Math::MACHINE_EPSILON_1)
+ {
+ //180 degree rotation across the Z axis
+ mVector.x = mVector.y = mVector.w = 0.0f;
+ mVector.z = 1.0f;
+ }
+ else
+ {
+ Vector3 w = v0.Cross(v1);
+ mVector.w = 1.0f + dot;
+ mVector.x = w.x;
+ mVector.y = w.y;
+ mVector.z = w.z;
+ Normalize();
+ }
}
Quaternion::~Quaternion()
{
}
-bool Quaternion::ToAxisAngle(Vector3 &axis, float &angle) const
+bool Quaternion::IsIdentity() const
+{
+ // start from w as its unlikely that any real rotation has w == 1
+ // Uses a relaxed epsilon, as composition of rotation introduces error
+ return ( ( fabsf( mVector.w - 1.0f ) < Math::MACHINE_EPSILON_10 )&&
+ ( fabsf( mVector.x ) < Math::MACHINE_EPSILON_10 )&&
+ ( fabsf( mVector.y ) < Math::MACHINE_EPSILON_10 )&&
+ ( fabsf( mVector.z ) < Math::MACHINE_EPSILON_10 ) );
+}
+
+bool Quaternion::ToAxisAngle(Vector3& axis, Radian& angle) const
{
angle = acosf(mVector.w);
bool converted = false;
// pre-compute to save time
- const float sine = sinf( angle );
+ const float sine = sinf( angle.radian );
// If sine(angle) is zero, conversion is not possible
axis.x = mVector.x*sinf_theta_inv;
axis.y = mVector.y*sinf_theta_inv;
axis.z = mVector.z*sinf_theta_inv;
- angle*=2.0f;
+ angle.radian *= 2.0f;
converted = true;
}
return converted;
}
-bool Quaternion::ToAxisAngle(Vector4 &axis, float &angle) const
-{
- Vector3 axis3;
- bool converted = ToAxisAngle(axis3, angle);
- if(converted)
- {
- axis.x = axis3.x;
- axis.y = axis3.y;
- axis.z = axis3.z;
- axis.w = 0;
- }
- return converted;
-}
-
const Vector4& Quaternion::AsVector() const
{
return mVector;
}
-void Quaternion::SetEuler(float x, float y, float z)
+void Quaternion::SetEuler( Radian pitch, Radian yaw, Radian roll )
{
MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,19);
- const float halfX = 0.5f * x;
- const float halfY = 0.5f * y;
- const float halfZ = 0.5f * z;
+ const float halfX = 0.5f * pitch.radian;
+ const float halfY = 0.5f * yaw.radian;
+ const float halfZ = 0.5f * roll.radian;
float cosX2 = cosf(halfX);
float cosY2 = cosf(halfY);
return euler;
}
-const Quaternion Quaternion::operator +(const Quaternion &other) const
+const Quaternion Quaternion::operator+( const Quaternion& other ) const
{
return Quaternion(mVector + other.mVector);
}
-const Quaternion Quaternion::operator -(const Quaternion &other) const
+const Quaternion Quaternion::operator-( const Quaternion& other ) const
{
return Quaternion(mVector - other.mVector);
}
-const Quaternion Quaternion::operator *(const Quaternion &other) const
+const Quaternion Quaternion::operator*( const Quaternion& other ) const
{
MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,12);
mVector.x * other.mVector.y - mVector.y * other.mVector.x + mVector.w * other.mVector.z + mVector.z * other.mVector.w);
}
-Vector3 Quaternion::operator *(const Vector3& v) const
+Vector3 Quaternion::operator*( const Vector3& other ) const
{
- // nVidia SDK implementation
- Vector3 uv, uuv;
Vector3 qvec(mVector.x, mVector.y, mVector.z);
- uv = qvec.Cross(v);
- uuv = qvec.Cross(uv);
+ Vector3 uv = qvec.Cross( other );
+ Vector3 uuv = qvec.Cross(uv);
uv *= (2.0f * mVector.w);
uuv *= 2.0f;
- return v + uv + uuv;
+ return other + uv + uuv;
}
-const Quaternion Quaternion::operator /(const Quaternion &q) const
+const Quaternion Quaternion::operator/( const Quaternion& q ) const
{
Quaternion p(q);
p.Invert();
return *this * p;
}
-const Quaternion Quaternion::operator *(float scale) const
+const Quaternion Quaternion::operator*( float scale ) const
{
return Quaternion(mVector*scale);
}
-const Quaternion Quaternion::operator /(float scale) const
+const Quaternion Quaternion::operator/( float scale ) const
{
return Quaternion(mVector/scale);
}
-Quaternion Quaternion::operator -() const
+Quaternion Quaternion::operator-() const
{
return Quaternion(-mVector.w, -mVector.x, -mVector.y, -mVector.z);
}
-const Quaternion& Quaternion::operator +=(const Quaternion &q)
+const Quaternion& Quaternion::operator+=( const Quaternion& q )
{
mVector += q.mVector; return *this;
}
-const Quaternion& Quaternion::operator -=(const Quaternion &q)
+const Quaternion& Quaternion::operator-=( const Quaternion& q )
{
mVector -= q.mVector; return *this;
}
-const Quaternion& Quaternion::operator *=(const Quaternion &q)
+const Quaternion& Quaternion::operator*=( const Quaternion& q )
{
MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,12);
return *this;
}
-const Quaternion& Quaternion::operator *= (float scale)
+const Quaternion& Quaternion::operator*=( float scale )
{
mVector*=scale; return *this;
}
-const Quaternion& Quaternion::operator /= (float scale)
+const Quaternion& Quaternion::operator/=( float scale )
{
mVector/=scale; return *this;
}
-bool Quaternion::operator== (const Quaternion& rhs) const
+bool Quaternion::operator==( const Quaternion& rhs ) const
{
return ( ( fabsf(mVector.x - rhs.mVector.x) < Math::MACHINE_EPSILON_1 &&
fabsf(mVector.y - rhs.mVector.y) < Math::MACHINE_EPSILON_1 &&
);
}
-bool Quaternion::operator!= (const Quaternion& rhs) const
+bool Quaternion::operator!=( const Quaternion& rhs ) const
{
return !operator==(rhs);
}
float Quaternion::Length() const
{
- return (float)sqrt(mVector.w * mVector.w + mVector.Dot(mVector));
+ return static_cast< float >( sqrt(mVector.w * mVector.w + mVector.Dot(mVector) ) );
}
float Quaternion::LengthSquared() const
{
- return (float)(mVector.w * mVector.w + mVector.Dot(mVector));
+ return static_cast< float >( mVector.w * mVector.w + mVector.Dot(mVector) );
}
void Quaternion::Normalize()
return ret;
}
-float Quaternion::Dot(const Quaternion &q1, const Quaternion &q2)
+float Quaternion::Dot( const Quaternion& q1, const Quaternion& q2 )
{
return q1.mVector.Dot4(q2.mVector);
}
-Quaternion Quaternion::Lerp(const Quaternion &q1, const Quaternion &q2, float t)
+Quaternion Quaternion::Lerp(const Quaternion& q1, const Quaternion& q2, float t )
{
return (q1*(1.0f-t) + q2*t).Normalized();
}
-Quaternion Quaternion::Slerp(const Quaternion &q1, const Quaternion &q2, float progress)
+Quaternion Quaternion::Slerp( const Quaternion& q1, const Quaternion& q2, float progress )
{
Quaternion q3;
float cosTheta = Quaternion::Dot(q1, q2);
}
}
-Quaternion Quaternion::SlerpNoInvert(const Quaternion &q1, const Quaternion &q2, float t)
+Quaternion Quaternion::SlerpNoInvert( const Quaternion& q1, const Quaternion& q2, float t )
{
float cosTheta = Quaternion::Dot(q1, q2);
}
}
-Quaternion Quaternion::Squad(
- const Quaternion &q1, // start
- const Quaternion &q2, // end
- const Quaternion &a, // ctrl pt for q1
- const Quaternion &b, // ctrl pt for q2
- float t)
+Quaternion Quaternion::Squad( const Quaternion& start, const Quaternion& end, const Quaternion& ctrl1, const Quaternion& ctrl2, float t )
{
MATH_INCREASE_BY(PerformanceMonitor::FLOAT_POINT_MULTIPLY,2);
- Quaternion c = SlerpNoInvert(q1, q2, t);
- Quaternion d = SlerpNoInvert(a, b, t);
- return SlerpNoInvert(c, d, 2*t*(1-t));
+ Quaternion c = SlerpNoInvert( start, end, t );
+ Quaternion d = SlerpNoInvert( ctrl1, ctrl2, t );
+ return SlerpNoInvert( c, d, 2*t*(1-t) );
}
-float Quaternion::AngleBetween(const Quaternion &q1, const Quaternion &q2)
+float Quaternion::AngleBetween( const Quaternion& q1, const Quaternion& q2 )
{
Quaternion from(q1);
Quaternion to(q2);
return theta;
}
-Vector4 Quaternion::Rotate(const Vector4 &v) const
+Vector4 Quaternion::Rotate( const Vector4& vector ) const
{
- Quaternion V(0.0f, v.x, v.y, v.z);
+ Quaternion V(0.0f, vector.x, vector.y, vector.z);
Quaternion conjugate(*this);
conjugate.Conjugate();
return (*this * V * conjugate).mVector;
}
-Vector3 Quaternion::Rotate(const Vector3 &v) const
+Vector3 Quaternion::Rotate( const Vector3& vector ) const
{
- Quaternion V(0.0f, v.x, v.y, v.z);
+ Quaternion V(0.0f, vector.x, vector.y, vector.z);
Quaternion conjugate(*this);
conjugate.Conjugate();
return Vector3((*this * V * conjugate).mVector);
Normalize();
}
-std::ostream& operator<< (std::ostream& o, const Quaternion& quaternion)
+std::ostream& operator<<( std::ostream& o, const Quaternion& quaternion )
{
Vector3 axis;
- float angleRadians;
+ Radian angleRadians;
quaternion.ToAxisAngle( axis, angleRadians );
- Degree degrees = Radian(angleRadians);
+ Degree degrees( angleRadians );
- return o << "[ Axis: [" << axis.x << ", " << axis.y << ", " << axis.z << "], Angle: " << degrees << " degrees ]";
+ return o << "[ Axis: [" << axis.x << ", " << axis.y << ", " << axis.z << "], Angle: " << degrees.degree << " degrees ]";
}
} // namespace Dali
-