Permalink
Browse files

Added a dot, lerp, and slerp to quaternions

- fixed a wrong method call in quaternion as_v
  • Loading branch information...
1 parent e3c3577 commit b29e872c786fd01c93eddcd2204759bebb3293be @iboB committed Apr 13, 2012
Showing with 56 additions and 5 deletions.
  1. +38 −4 mathgp/quaternion.h
  2. +12 −0 test/geometry.cpp
  3. +6 −1 test/mathgp_test.h
View
@@ -199,24 +199,27 @@ class quaterniont : public _internal::ntuple<4, _type, quaterniont<_type>>
}
private:
+ template <typename _t>
+ friend _t dot(const quaterniont<_t>& a, const quaterniont<_t>& b);
+
vector3t<_type>& as_v3()
{
- return vector3t<_type>::attach_to_ptr(this->as_ptr());
+ return vector3t<_type>::attach_to_ptr(this->as_array());
}
const vector3t<_type>& as_v3() const
{
- return vector3t<_type>::attach_to_ptr(this->as_ptr());
+ return vector3t<_type>::attach_to_ptr(this->as_array());
}
vector4t<_type>& as_v4()
{
- return vector4t<_type>::attach_to_ptr(this->as_ptr());
+ return vector4t<_type>::attach_to_ptr(this->as_array());
}
const vector4t<_type>& as_v4() const
{
- return vector4t<_type>::attach_to_ptr(this->as_ptr());
+ return vector4t<_type>::attach_to_ptr(this->as_array());
}
};
@@ -242,6 +245,17 @@ quaterniont<_type> operator*(const quaterniont<_type>& a, const quaterniont<_typ
return _internal::quaternion_multiply(a, b);
}
+template <typename _type>
+quaterniont<_type> normalized(const quaterniont<_type>& q)
+{
+ return q/q.magnitude();
+}
+
+template <typename _type>
+_type dot(const quaterniont<_type>& a, const quaterniont<_type>& b)
+{
+ return dot(a.as_v4(), b.as_v4());
+}
template <typename _type>
quaterniont<_type> log(const quaterniont<_type>& q)
@@ -275,5 +289,25 @@ quaterniont<_type> exp(const quaterniont<_type>& q)
);
}
+template <typename _type>
+quaterniont<_type> lerp(const quaterniont<_type>& from, const quaterniont<_type>& to, _type ratio)
+{
+ return normalized(lerp<_internal::ntuple<4, _type, quaterniont<_type>>>(from, to, ratio).as_this_type());
+}
+
+template <typename _type>
+quaterniont<_type> slerp(const quaterniont<_type>& from, const quaterniont<_type>& to, _type ratio)
+{
+ _type cos_angle = dot(from, to);
+
+ // if the angle is small (ie cos_angle is close to -1 or 1),
+ // could use lerp, instead of slerp:
+ // if(cos_angle < -0.99 || cos_angle > 0.99) return lerp(from, to, ratio)
+ // need to test how this works
+
+ _type angle = std::acos(cos_angle);
+
+ return (from*std::sin((1-ratio)*angle) + to*std::sin(angle*ratio)) / std::sin(angle);
+}
}
View
@@ -11,6 +11,17 @@ using namespace boost::unit_test;
using namespace std;
using namespace mathgp;
+void quaternion_geometry()
+{
+ quaternion q1 = quaternion::xyzw(0.5f, 0.7f, 0.212f, 0.8f);
+ quaternion q2 = quaternion::xyzw(0.12f, 0.33f, 0.4f, 0.5f);
+
+ quaternion q3 = slerp(q1, q2, 0.55f);
+
+ QUAT_CHECK_CLOSE(q3, quaternion::xyzw(
+ 0.30942556881258626f, 0.527364923066248f, 0.33413672218578583f, 0.6741185090656765f));
+}
+
void rotation()
{
matrix rot;
@@ -32,6 +43,7 @@ test_suite* geometry()
{
test_suite* suite = BOOST_TEST_SUITE("geometry");
+ suite->add(BOOST_TEST_CASE(quaternion_geometry));
suite->add(BOOST_TEST_CASE(rotation));
return suite;
View
@@ -9,4 +9,9 @@
#define MAT4_CHECK_CLOSE_E(m1, m2, e) \
BOOST_CHECK_PREDICATE( std::bind(&_internal::close<16, float, matrix>, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), (m1)(m2)(e))
-#define MAT4_CHECK_CLOSE(m1, m2) MAT4_CHECK_CLOSE_E(m1, m2, constants<float>::EPSILON())
+#define MAT4_CHECK_CLOSE(m1, m2) MAT4_CHECK_CLOSE_E(m1, m2, constants<float>::EPSILON())
+
+#define QUAT_CHECK_CLOSE_E(q1, q2, e) \
+ BOOST_CHECK_PREDICATE( std::bind(&_internal::close<4, float, quaternion>, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3), (q1)(q2)(e))
+
+#define QUAT_CHECK_CLOSE(q1, q2) QUAT_CHECK_CLOSE_E(q1, q2, constants<float>::EPSILON())

0 comments on commit b29e872

Please sign in to comment.