Browse Source

Added rotation function, issue #22

Christophe Riccio 13 years ago
parent
commit
982bb5ce5d
6 changed files with 85 additions and 16 deletions
  1. 0 6
      glm/gtx/norm.hpp
  2. 0 9
      glm/gtx/norm.inl
  3. 18 0
      glm/gtx/quaternion.hpp
  4. 48 0
      glm/gtx/quaternion.inl
  5. 1 0
      readme.txt
  6. 18 1
      test/gtx/gtx_quaternion.cpp

+ 0 - 6
glm/gtx/norm.hpp

@@ -64,12 +64,6 @@ namespace glm
 	typename genType::value_type length2(
 		genType const & x);
 		
-	//! Returns the squared length of x.
-	//! From GLM_GTX_norm extension.
-	template <typename T>
-	T length2(
-		detail::tquat<T> const & q);
-
 	//! Returns the squared distance between p0 and p1, i.e., length(p0 - p1).
 	//! From GLM_GTX_norm extension.
 	template <typename T>

+ 0 - 9
glm/gtx/norm.inl

@@ -45,15 +45,6 @@ namespace glm
 		return dot(x, x);
 	}
 
-	template <typename T> 
-	GLM_FUNC_QUALIFIER T length2
-	(
-		detail::tquat<T> const & q
-	)
-	{
-		return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
-	}
-
 	template <typename T> 
 	GLM_FUNC_QUALIFIER T distance2
 	(

+ 18 - 0
glm/gtx/quaternion.hpp

@@ -41,7 +41,9 @@
 
 // Dependency:
 #include "../glm.hpp"
+#include "../gtc/constants.hpp"
 #include "../gtc/quaternion.hpp"
+#include "../gtx/norm.hpp"
 
 #if(defined(GLM_MESSAGES) && !defined(glm_ext))
 #	pragma message("GLM: GLM_GTX_quaternion extension included")
@@ -187,6 +189,22 @@ namespace glm
 		detail::tquat<T> const & y, 
 		T const & a);
 
+	/// Compute the rotation between two vectors. 
+	/// param orig vector, needs to be normalized
+	/// param dest vector, needs to be normalized
+	///
+	/// @see gtx_quaternion
+	template <typename T>
+	detail::tquat<T> rotation(
+		detail::tvec3<T> const & orig, 
+		detail::tvec3<T> const & dest);
+
+	/// Returns the squared length of x.
+	/// 
+	/// @see gtx_quaternion
+	template <typename T>
+	T length2(detail::tquat<T> const & q);
+
 	/// @}
 }//namespace glm
 

+ 48 - 0
glm/gtx/quaternion.inl

@@ -153,6 +153,15 @@ namespace glm
 			return -sqrt(w);
 	}
 
+	template <typename T> 
+	GLM_FUNC_QUALIFIER T length2
+	(
+		detail::tquat<T> const & q
+	)
+	{
+		return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
+	}
+
 	template <typename T>
 	GLM_FUNC_QUALIFIER detail::tquat<T> shortMix
 	(
@@ -205,4 +214,43 @@ namespace glm
 	{
 		return glm::normalize(x * (T(1) - a) + (y * a));
 	}
+
+	template <typename T>
+	GLM_FUNC_QUALIFIER detail::tquat<T> rotation
+	(
+		detail::tvec3<T> const & orig, 
+		detail::tvec3<T> const & dest
+	)
+	{
+		T cosTheta = dot(orig, dest);
+		detail::tvec3<T> rotationAxis;
+
+		if(cosTheta < T(-1) + epsilon<T>())
+		{
+			// special case when vectors in opposite directions :
+			// there is no "ideal" rotation axis
+			// So guess one; any will do as long as it's perpendicular to start
+			// This implementation favors a rotation around the Up axis (Y),
+			// since it's often what you want to do.
+			rotationAxis = cross(detail::tvec3<T>(0, 0, 1), orig);
+			if(length2(rotationAxis) < epsilon<T>()) // bad luck, they were parallel, try again!
+				rotationAxis = cross(detail::tvec3<T>(1, 0, 0), orig);
+
+			rotationAxis = normalize(rotationAxis);
+			return angleAxis(pi<T>(), rotationAxis);
+		}
+
+		// Implementation from Stan Melax's Game Programming Gems 1 article
+		rotationAxis = cross(orig, dest);
+
+		T s = sqrt((T(1) + cosTheta) * T(2));
+		T invs = T(1) / s;
+
+		return detail::tquat<T>(
+			s * T(0.5f), 
+			rotationAxis.x * invs,
+			rotationAxis.y * invs,
+			rotationAxis.z * invs);
+	}
+
 }//namespace glm

+ 1 - 0
readme.txt

@@ -43,6 +43,7 @@ GLM 0.9.5.0: 2013-XX-XX
 - Added bitfieldInterleave and _mm_bit_interleave_si128 functions
 - Added GTX_scalar_relational
 - Added GTX_dual_quaternion
+- Added rotation function to GTX_quaternion (#22)
 
 ================================================================================
 GLM 0.9.4.3: 2013-0X-XX

+ 18 - 1
test/gtx/gtx_quaternion.cpp

@@ -67,10 +67,27 @@ int test_orientation()
 	return Error;
 }
 
+int test_rotation()
+{
+	int Error(0);
+
+	glm::vec3 v(1, 0, 0);
+	glm::vec3 u(0, 1, 0);
+
+	glm::quat Rotation = glm::rotation(v, u);
+
+	float Angle = glm::angle(Rotation);
+
+	Error += glm::abs(Angle - 90.0f) < glm::epsilon<float>() ? 0 : 1;
+
+	return Error;
+}
+
 int main()
 {
-	int Error = 0;
+	int Error(0);
 
+	Error += test_rotation();
 	Error += test_quat_fastMix();
 	Error += test_quat_shortMix();