Commits

Anonymous committed 4e92c71

Added very basic quaternion support.

Comments (0)

Files changed (10)

neglect/cpplib/CMakeLists.txt

 	include/neglect/math.hpp
 	include/neglect/matrix.hpp
 	include/neglect/matrix_io.hpp
+	include/neglect/quaternion.hpp
+	include/neglect/quaternion_io.hpp
 	include/neglect/unittest.hpp
 	include/neglect/path.hpp
 	include/neglect/ntpath.hpp

neglect/cpplib/include/neglect/_vector2.hpp

 
         // -- constructors
 
-        vector() : x(T()), y(T())
-        {
-        }
+        vector() {}
 
         template <class Sequence>
         explicit vector(Sequence seq) : x(seq[0]), y(seq[1])
         {
         }
 
+        static vector<T, 2> zero()
+        {
+            vector<T, 2> rv;
+            rv.set_zero();
+            return rv;
+        }
+
+        void set_zero()
+        {
+            x = T();
+            y = T();
+        }
+
         // -- pointer access
 
         T* ptr() { return &x; }

neglect/cpplib/include/neglect/_vector3.hpp

 
         // -- constructors
 
-        vector() : x(T()), y(T()), z(T())
-        {
-        }
+        vector() {}
 
         template <class Sequence>
         explicit vector(Sequence seq) : x(seq[0]), y(seq[1]), z(seq[2])
         {
         }
 
+        static vector<T, 3> zero()
+        {
+            vector<T, 3> rv;
+            rv.set_zero();
+            return rv;
+        }
+
+        void set_zero()
+        {
+            x = T();
+            y = T();
+            z = T();
+        }
+
         // -- pointer access
 
         T* ptr() { return &x; }

neglect/cpplib/include/neglect/_vector4.hpp

 
         // -- constructors
 
-        vector() : x(T()), y(T()), z(T()), w(T())
-        {
-        }
+        vector() {}
 
         template <class Sequence>
         explicit vector(Sequence seq) : x(seq[0]), y(seq[1]), z(seq[2]), w(seq[3])
         {
         }
 
+        static vector<T, 4> zero()
+        {
+            vector<T, 4> rv;
+            rv.set_zero();
+            return rv;
+        }
+
+        void set_zero()
+        {
+            x = T();
+            y = T();
+            z = T();
+            w = T();
+        }
+
         // -- pointer access
 
         T* ptr() { return &x; }

neglect/cpplib/include/neglect/matrix.hpp

 
         void set_zero()
         {
-            std::fill_n(m_cols, N, vector<T, M>());
+            std::fill_n(m_cols, N, vector<T, M>::zero());
         }
 
         void set_identity()

neglect/cpplib/include/neglect/quaternion.hpp

+/* platform independence utilities */
+#ifndef _INC_NEGLECT_QUATERNION_HPP_
+#define _INC_NEGLECT_QUATERNION_HPP_
+
+#include <neglect/boot.hpp>
+#include <neglect/math.hpp>
+#include <neglect/matrix.hpp>
+#include <neglect/vector.hpp>
+
+
+namespace neglect {
+
+    /* implements quaternions.  we represent quaternions as a scalar w
+       plus a three dimensional vector x, y, z. */
+    template <typename T>
+    class quaternion {
+    public:
+        T w;
+        vector<T, 3> vec;
+
+        quaternion()
+        {
+        }
+
+        quaternion(T w, T x, T y, T z) : w(w), vec(x, y, z)
+        {
+        }
+
+        quaternion(T w, const vector<T, 3> &vec) : w(w), vec(vec)
+        {
+        }
+
+        static quaternion<T> zero()
+        {
+            quaternion<T> rv;
+            rv.set_zero();
+            return rv;
+        }
+
+        // pointer access
+
+        T *ptr()
+        {
+            return &w;
+        }
+
+        const T *ptr() const
+        {
+            return &w;
+        }
+
+        // element access
+
+        T &operator[](size_t idx)
+        {
+            return *(&w + i);
+        }
+
+        T operator[](size_t idx) const
+        {
+            return *(&w + i);
+        }
+
+        void set_zero()
+        {
+            w = vec.x = vec.y = vec.z = T();
+        }
+    };
+
+
+    /* multiply two quaternions */
+    template <typename T>
+    quaternion<T> operator*(const quaternion<T> &lhs,
+                            const quaternion<T> &rhs)
+    {
+        return quaternion<T>(lhs.w * rhs.w - dot(lhs.vec, rhs.vec),
+                             (lhs.w * rhs.vec) + (rhs.w * lhs.vec)
+                             + cross(lhs.vec, rhs.vec));
+    }
+
+    template <typename T>
+    quaternion<T> &operator*=(quaternion<T> &lhs,
+                              const quaternion<T> &rhs)
+    {
+        lhs = lhs * rhs;
+        return lhs;
+    }
+
+    /* compare two quaternions */
+    template <typename T1, typename T2>
+    bool operator==(const quaternion<T1> &q1,
+                    const quaternion<T2> &q2)
+    {
+        return q1.w == q2.w && q1.vec == q2.vec;
+    }
+
+    template <typename T1, typename T2>
+    bool operator!=(const quaternion<T1> &q1,
+                    const quaternion<T2> &q2)
+    {
+        return !(q1 == q2);
+    }
+
+    template <typename T1, typename T2>
+    bool almost_equal(const quaternion<T1> &q1,
+                      const quaternion<T2> &q2)
+    {
+        return almost_equal(q1.w, q2.w) &&
+               almost_equal(q1.vec, q2.vec);
+    }
+
+    /* calculate the inverse of a quaternion */
+    template <typename T>
+    quaternion<T> inverse(const quaternion<T> &q)
+    {
+        return quaternion<T>(q.w, -q.vec);
+    }
+
+    typedef quaternion<float> quat;
+    typedef quaternion<int> quati;
+}
+
+#endif

neglect/cpplib/include/neglect/quaternion_io.hpp

+#ifndef _INC_NEGLECT_QUATERNION_IO_HPP_
+#define _INC_NEGLECT_QUATERNION_IO_HPP_
+
+#include <neglect/quaternion.hpp>
+
+#include <iostream>
+
+namespace neglect {
+
+    template <typename T>
+    std::ostream &operator<<(std::ostream &lhs, const quaternion<T> &q)
+    {
+        lhs << "(" << q.w;
+        if (q.vec.x >= T())
+            lhs << " + " << q.vec.x;
+        else
+            lhs << " - " << std::abs(q.vec.x);
+        lhs << "i";
+        if (q.vec.y >= T())
+            lhs << " + " << q.vec.y;
+        else
+            lhs << " - " << std::abs(q.vec.y);
+        lhs << "j";
+        if (q.vec.z >= T())
+            lhs << " + " << q.vec.z;
+        else
+            lhs << " - " << std::abs(q.vec.z);
+        lhs << "k)";
+        return lhs;
+    }
+
+}
+
+#endif

neglect/tests/CMakeLists.txt

     src/main.cpp
     src/test_vectors.cpp
     src/test_matrix.cpp
+    src/test_quaternion.cpp
     src/test_format.cpp
     src/test_path.cpp
     src/test_platform.cpp

neglect/tests/src/test_quaternion.cpp

+#include <neglect/unittest.hpp>
+#include <neglect/vector.hpp>
+#include <neglect/quaternion.hpp>
+#include <neglect/quaternion_io.hpp>
+
+using namespace neglect;
+
+
+NUT_TESTGROUP(quaternion) {
+
+    NUT_TESTCASE(constructors)
+    {
+        quat q1(1.0f, 2.0f, 3.0f, 4.0f);
+        NUT_REQUIRE_EQUAL(q1.w, 1.0f);
+        NUT_REQUIRE_EQUAL(q1.vec, vec3(2.0f, 3.0f, 4.0f));
+
+        quat q2 = quat::zero();
+        NUT_REQUIRE_EQUAL(q2.w, 0.0f);
+        NUT_REQUIRE_EQUAL(q2.vec, vec3::zero());
+
+        float *qptr = q1.ptr();
+        NUT_REQUIRE_EQUAL(qptr[0], 1.0f);
+        NUT_REQUIRE_EQUAL(qptr[1], 2.0f);
+        NUT_REQUIRE_EQUAL(qptr[2], 3.0f);
+        NUT_REQUIRE_EQUAL(qptr[3], 4.0f);
+    }
+
+    NUT_TESTCASE(multiplication)
+    {
+        quat q1(1.0f, 1.0f, 2.0f, 3.0f);
+        quat q2(2.0f, 2.0f, 1.0f, 2.0f);
+        NUT_REQUIRE_EQUAL(q1 * q2, quat(-8.0f, 5.0f, 9.0f, 5.0f));
+    }
+
+    NUT_TESTCASE(inverse)
+    {
+        quat q1(1.0f, 1.0f, 2.0f, 3.0f);
+        NUT_REQUIRE_EQUAL(inverse(q1), quat(1.0f, -1.0f, -2.0f, -3.0f));
+    }
+}

neglect/tests/src/test_vectors.cpp

     NUT_TESTCASE(constructors)
     {
         float x[2] = {3.0f, 6.0f};
-        vector<float, 2> vec1;
+        vector<float, 2> vec1 = vector<float, 2>::zero();
         vector<float, 2> vec2(1.0f, 2.0f);
         vector<float, 2> vec3(x);
 
 
     NUT_TESTCASE(modify_and_get)
     {
-        vec2 v1;
+        vec2 v1 = vec2::zero();
 
         v1 = vec2(1.0f, 1.0f);
         NUT_CHECK_EQUAL(v1, vec2(1.0f, 1.0f));
     {
         stringstream ss;
         vector<float, 2> v1;
+        v1.set_zero();
         vector<float, 2> v2(1.0f, 2.5f);
 
         ss << v1 << " " << v2;
     NUT_TESTCASE(constructors)
     {
         float x[3] = {3.0f, 6.0f, 9.0f};
-        vector<float, 3> vec1;
+        vector<float, 3> vec1 = vector<float, 3>::zero();
         vector<float, 3> vec2(1.0f, 2.0f, 3.0f);
         vector<float, 3> vec3(x);
 
     {
         stringstream ss;
         vector<float, 3> v1;
+        v1.set_zero();
         vector<float, 3> v2(1.0f, 2.5f, 1.5f);
 
         ss << v1 << " " << v2;
     NUT_TESTCASE(constructors)
     {
         float x[4] = {3.0f, 6.0f, 9.0f, 12.0f};
-        vector<float, 4> vec1;
+        vector<float, 4> vec1 = vector<float, 4>::zero();
         vector<float, 4> vec2(1.0f, 2.0f, 3.0f, 4.0f);
         vector<float, 4> vec3(x);
 
 
     NUT_TESTCASE(different_sizes)
     {
-        vec2 v1;
-        vec3 v2;
-        vec4 v3;
+        vec2 v1 = vec2::zero();
+        vec3 v2 = vec3::zero();
+        vec4 v3 = vec4::zero();
 
         NUT_CHECK_NOT_EQUAL(v1, v2);
         NUT_CHECK_NOT_EQUAL(v1, v3);