diff --git a/include/ngl/Quaternion.h b/include/ngl/Quaternion.h index 493df256..d86d8a51 100644 --- a/include/ngl/Quaternion.h +++ b/include/ngl/Quaternion.h @@ -258,17 +258,17 @@ class NGL_DLLEXPORT Quaternion /// @brief set the current quaternion as a rotation around the X cartesian axis [1,0,0] /// @param[in] _angle the angle of rotation around the x axis in degrees - void rotateX(Real _angle) noexcept; + static Quaternion rotateX(Real _angle) noexcept; /// @brief set the current quaternion as a rotation around the Y cartesian axis [0,1,0] /// @param[in] _angle the angle of rotation around the y axis in degrees - void rotateY(Real _angle) noexcept; + static Quaternion rotateY(Real _angle) noexcept; /// @brief set the current quaternion as a rotation around the Z cartesian axis [0,0,1] /// @param[in] _angle the angle of rotation around the Z axis in degrees - void rotateZ(Real _angle) noexcept; + static Quaternion rotateZ(Real _angle) noexcept; /// @brief set the current quaternion as a rotation around the vector _axis /// @brief[in] _axis the axis to rotate around (will be normalized) @@ -301,10 +301,6 @@ class NGL_DLLEXPORT Quaternion Mat4 toMat4() const noexcept; - /// @brief return the current quat as a 4x4 transform matrix transposed - /// @returns the quat as a matrix - - Mat4 toMat4Transpose() const noexcept; /// @brief the quaternion data for the scalar real part Real m_s=1.0f; diff --git a/src/Quaternion.cpp b/src/Quaternion.cpp index 869ba6c6..18ba2176 100644 --- a/src/Quaternion.cpp +++ b/src/Quaternion.cpp @@ -187,7 +187,7 @@ Quaternion Quaternion::inverse() const noexcept Real Quaternion::magnitude()const noexcept { - return static_cast( sqrtf(m_s*m_s + m_x*m_x + m_y*m_y + m_z*m_z) ); + return sqrtf(m_s*m_s + m_x*m_x + m_y*m_y + m_z*m_z); } bool Quaternion::operator == (const Quaternion& _q)const noexcept @@ -202,12 +202,13 @@ bool Quaternion::operator == (const Quaternion& _q)const noexcept -Vec4 Quaternion::operator* (const Vec4 &_vec) const noexcept +Vec4 Quaternion::operator *(const Vec4 &_vec) const noexcept { - Quaternion temp=-*this; - Quaternion point(0.0,_vec.m_x,_vec.m_y,_vec.m_z); - point = temp*point* *this; - return Vec4(point.m_x,point.m_y,point.m_z,1.0); + + Vec4 qv(m_x,m_y,m_z); + Vec4 uv(qv.cross(_vec)); + Vec4 uuv(qv.cross(uv)); + return _vec + ((uv * m_s) + uuv) * 2.0f; } float Quaternion::dot(const Quaternion &_lhs)const noexcept @@ -221,36 +222,40 @@ float Quaternion::dot(const Quaternion &_lhs, const Quaternion &_rhs) noexcept } -void Quaternion::rotateX(Real _angle) noexcept +Quaternion Quaternion::rotateX(Real _angle) noexcept { + Quaternion q; _angle/=2.0f; // q=[cos 1/2 theta, sin 1/2 theta V] - m_s=cosf(radians(_angle)); - m_x=sinf(radians(_angle)); - m_y=0.0f; - m_z=0.0f; + q.m_s=cosf(radians(_angle)); + q.m_x=sinf(radians(_angle)); + q.m_y=0.0f; + q.m_z=0.0f; + return q; } -void Quaternion::rotateY(Real _angle) noexcept +Quaternion Quaternion::rotateY(Real _angle) noexcept { + Quaternion q; _angle/=2.0f; // q=[cos 1/2 theta, sin 1/2 theta V] - m_s=cosf(radians(_angle)); - m_x=0.0f; - m_y=sinf(radians(_angle)); - m_z=0.0f; + q.m_s=cosf(radians(_angle)); + q.m_x=0.0f; + q.m_y=sinf(radians(_angle)); + q.m_z=0.0f; + return q; } -void Quaternion::rotateZ(Real _angle) noexcept +Quaternion Quaternion::rotateZ(Real _angle) noexcept { - + Quaternion q; _angle/=2.0f; // q=[cos 1/2 theta, sin 1/2 theta V] - m_s=cosf(radians(_angle)); - m_x=0.0f; - m_y=0.0f; - m_z=sinf(radians(_angle)); - + q.m_s=cosf(radians(_angle)); + q.m_x=0.0f; + q.m_y=0.0f; + q.m_z=sinf(radians(_angle)); + return q; } void Quaternion::fromAxisAngle(const Vec3& _axis, Real _angle) noexcept @@ -389,44 +394,6 @@ Mat4 Quaternion::toMat4() const noexcept return o; } -Mat4 Quaternion::toMat4Transpose() const noexcept -{ - // written by Rob Bateman - // sacrafice a few bytes to pre-calculate some values - Real xx = m_x * m_x; - Real xy = m_x * m_y; - Real xz = m_x * m_z; - Real xs = m_x * m_s; - Real yy = m_y * m_y; - Real yz = m_y * m_z; - Real ys = m_y * m_s; - Real zz = m_z * m_z; - Real zs = m_z * m_s; - Mat4 o; - o.m_openGL[0] = 1.0f - 2.0f * (yy+zz); - o.m_openGL[4] = 2.0f * (xy+zs); - o.m_openGL[8] = 2.0f * (xz-ys); - o.m_openGL[12] = 0.0f; - - // [4] -> [7] - o.m_openGL[1] = 2.0f * (xy-zs); - o.m_openGL[5] = 1.0f - 2.0f * (xx+zz); - o.m_openGL[9] = 2.0f * (yz+xs); - o.m_openGL[13] = 0.0f; - - // [8] -> [11] - o.m_openGL[2] = 2.0f * (xz+ys); - o.m_openGL[6] = 2.0f * (yz-xs); - o.m_openGL[10]= 1.0f - 2.0f * (xx+yy); - o.m_openGL[14] = 0.0f; - - // [12] -> [15] - o.m_openGL[3] = 0.0f; - o.m_openGL[7] = 0.0f; - o.m_openGL[11] = 0.0f; - o.m_openGL[15] = 1.0f; - return o; -} diff --git a/tests/QuaternionTests.cpp b/tests/QuaternionTests.cpp index cb263f22..81af57b2 100644 --- a/tests/QuaternionTests.cpp +++ b/tests/QuaternionTests.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +44,7 @@ TEST(Quaternion, UserCtor) TEST(Quaternion, fromMat4) { - ngl::Mat4 tx = ngl::Mat4::rotateX(45.0f); + auto tx = ngl::Mat4::rotateX(45.0f); ngl::Quaternion test(tx); ASSERT_NEAR(test.m_s, 0.92388f, 0.001f); @@ -51,6 +52,21 @@ TEST(Quaternion, fromMat4) ASSERT_NEAR(test.m_y, 0.0f, 0.001f); ASSERT_NEAR(test.m_z, 0.0f, 0.001f); + auto ty=ngl::Mat4::rotateY(45.0f); + ngl::Quaternion testy(ty); + ASSERT_NEAR(testy.m_s, 0.92388f, 0.001f); + ASSERT_NEAR(testy.m_x, 0.0f, 0.001f); + ASSERT_NEAR(testy.m_y, 0.382683f, 0.001f); + ASSERT_NEAR(testy.m_z, 0.0f, 0.001f); + + auto tz=ngl::Mat4::rotateZ(45.0f); + ngl::Quaternion testz(tz); + ASSERT_NEAR(testz.m_s, 0.92388f, 0.001f); + ASSERT_NEAR(testz.m_x, 0.0f, 0.001f); + ASSERT_NEAR(testz.m_y, 0.0f, 0.001f); + ASSERT_NEAR(testz.m_z, 0.382683f, 0.001f); + + glm::mat4 gtx = glm::rotate(glm::mat4(1.0f), glm::radians(45.0f), glm::vec3(1, 0, 0)); glm::quat gtest = glm::quat_cast(gtx); @@ -316,6 +332,7 @@ TEST(Quaternion, toMat4) } } + TEST(Quaternion, SLERP) { @@ -345,3 +362,51 @@ TEST(Quaternion, SLERP) } } + +TEST(Quaternion,timesEqualFloat) +{ + auto a=ngl::Quaternion(0.2f,0.1f,0.3f,0.5f); + a*=2.0f; + EXPECT_FLOAT_EQ(a.m_s,0.4f); + EXPECT_FLOAT_EQ(a.m_x,0.2f); + EXPECT_FLOAT_EQ(a.m_y,0.6f); + EXPECT_FLOAT_EQ(a.m_z,1.0f); +} + +TEST(Quaternion,magantude) +{ + auto a=ngl::Quaternion(0.2f,0.1f,0.3f,0.5f); + EXPECT_FLOAT_EQ(a.magnitude(),0.6244998f); +} + +TEST(Quaternion,multVec4) +{ + auto a=ngl::Quaternion(0.2f,0.1f,0.3f,0.5f); + auto b=ngl::Vec4(1.0f,2.0f,3.0f,1.0f); + auto c=a*b; + + glm::quat ga(0.2f,0.1f,0.3f,0.5f); + glm::vec4 gb(1.0f,2.0f,3.0f,1.0f); + auto gc=ga*gb; + + EXPECT_FLOAT_EQ(c.m_x,gc.x); + EXPECT_FLOAT_EQ(c.m_y,gc.y); + EXPECT_FLOAT_EQ(c.m_z,gc.z); + EXPECT_FLOAT_EQ(c.m_w,gc.w); +} + +TEST(Quaternion,rotations) +{ + auto tx=ngl::Quaternion::rotateX(45.0f); + auto mx=ngl::Mat4::rotateX(45.0f); + EXPECT_TRUE(tx.toMat4()==mx); + + auto ty=ngl::Quaternion::rotateY(25.0f); + auto my=ngl::Mat4::rotateY(25.0f); + EXPECT_TRUE(ty.toMat4()==my); + + auto tz=ngl::Quaternion::rotateZ(77.0f); + auto mz=ngl::Mat4::rotateZ(77.0f); + EXPECT_TRUE(tz.toMat4()==mz); + +} \ No newline at end of file