basic qua ext rotation functions

This commit is contained in:
BlackMATov
2021-01-26 02:06:46 +07:00
parent 4279552522
commit 1d5ee20967
4 changed files with 108 additions and 0 deletions

View File

@@ -662,3 +662,57 @@ namespace vmath_hpp
return dot(v, normal) / length2(normal) * normal;
}
}
//
// Quaternion Transform
//
namespace vmath_hpp
{
// qrotate
template < typename T >
[[nodiscard]] qua<T> qrotate(T angle, const vec<T, 3>& axis) {
const auto [s, c] = sincos(angle * T(0.5));
const auto [x, y, z] = normalize(axis);
return {vec{x,y,z} * s, c};
}
template < typename T >
[[nodiscard]] qua<T> qrotate(const qua<T>& q, T angle, const vec<T, 3>& axis) {
return q * qrotate(angle, axis);
}
template < typename T >
[[nodiscard]] qua<T> qrotate_x(T angle) {
const auto [s, c] = sincos(angle * T(0.5));
return {s, T(0), T(0), c};
}
template < typename T >
[[nodiscard]] qua<T> qrotate_x(const qua<T>& q, T angle) {
return qrotate(q, angle, unit3_x<T>);
}
template < typename T >
[[nodiscard]] qua<T> qrotate_y(T angle) {
const auto [s, c] = sincos(angle * T(0.5));
return {T(0), s, T(0), c};
}
template < typename T >
[[nodiscard]] qua<T> qrotate_y(const qua<T>& q, T angle) {
return qrotate(q, angle, unit3_y<T>);
}
template < typename T >
[[nodiscard]] qua<T> qrotate_z(T angle) {
const auto [s, c] = sincos(angle * T(0.5));
return {T(0), T(0), s, c};
}
template < typename T >
[[nodiscard]] qua<T> qrotate_z(const qua<T>& q, T angle) {
return qrotate(q, angle, unit3_z<T>);
}
}

View File

@@ -226,3 +226,24 @@ namespace vmath_hpp
return not_equal_to(vec{xs}, vec{ys});
}
}
//
// Quaternion Functions
//
namespace vmath_hpp
{
// conjugate
template < typename T >
[[nodiscard]] constexpr qua<T> conjugate(const qua<T>& q) {
return {-q.v, q.s};
}
// inverse
template < typename T >
[[nodiscard]] constexpr qua<T> inverse(const qua<T>& q) {
return conjugate(q) * rcp(dot(q, q));
}
}

View File

@@ -293,4 +293,28 @@ TEST_CASE("vmath/ext") {
REQUIRE(project(float2(2.f, 2.f), float2(0.f, 1.f)) == uapprox2(0.f, 2.f));
REQUIRE(project(float3(2.f, 2.f, 2.f), float3(0.f, 0.f, 1.f)) == uapprox3(0.f, 0.f, 2.f));
}
SUBCASE("quaternion qrotate") {
constexpr float pi = radians(180.f);
constexpr float pi_2 = radians(90.f);
constexpr float pi_4 = radians(45.f);
REQUIRE(float3(0.f,1.f,0.f) * qrotate_x(pi_2) == uapprox3(0.f,0.f,1.f));
REQUIRE(float3(0.f,0.f,1.f) * qrotate_y(pi_2) == uapprox3(1.f,0.f,0.f));
REQUIRE(float3(1.f,0.f,0.f) * qrotate_z(pi_2) == uapprox3(0.f,1.f,0.f));
REQUIRE(float3(0.f,1.f,0.f) * qrotate_x(qrotate_x(pi_4),pi_4) == uapprox3(0.f,0.f,1.f));
REQUIRE(float3(0.f,0.f,1.f) * qrotate_y(qrotate_y(pi_4),pi_4) == uapprox3(1.f,0.f,0.f));
REQUIRE(float3(1.f,0.f,0.f) * qrotate_z(qrotate_z(pi_4),pi_4) == uapprox3(0.f,1.f,0.f));
REQUIRE(float3(2.f,3.f,4.f) * qrotate(pi,{0.f,0.f,1.f}) == uapprox3(-2.f,-3.f,4.f));
REQUIRE(float3(2.f,3.f,4.f) * qrotate(pi,float3{0.f,0.f,1.f}) == uapprox3(-2.f,-3.f,4.f));
REQUIRE(float3(2.f,3.f,4.f) * qrotate(qrotate(pi_2,{0.f,0.f,1.f}),pi_2,{0.f,0.f,1.f}) == uapprox3(-2.f,-3.f,4.f));
REQUIRE(float3(2.f,3.f,4.f) * qrotate(qrotate(pi_2,float3{0.f,0.f,1.f}),pi_2,float3{0.f,0.f,1.f}) == uapprox3(-2.f,-3.f,4.f));
REQUIRE(qrotate_x(12.3f) == qrotate(12.3f, unit3_x<float> * 2.f));
REQUIRE(qrotate_y(12.3f) == qrotate(12.3f, unit3_y<float> * 2.f));
REQUIRE(qrotate_z(12.3f) == qrotate(12.3f, unit3_z<float> * 2.f));
}
}

View File

@@ -91,4 +91,13 @@ TEST_CASE("vmath/qua_fun") {
STATIC_REQUIRE(equal_to(qua(1,1,1,1), qua(0,1,2,3)) == bool4(false, true, false, false));
STATIC_REQUIRE(not_equal_to(qua(1,1,1,1), qua(0,1,2,3)) == bool4(true, false, true, true));
}
SUBCASE("Quaternion Functions") {
STATIC_REQUIRE(conjugate(qua(1,2,3,4)) == qua(-1,-2,-3,4));
STATIC_REQUIRE(inverse(qua(0.f,0.f,0.7071067812f,0.7071067812f)).v == uapprox3(0.f,0.f,-0.7071067812f));
STATIC_REQUIRE(inverse(qua(0.f,0.f,0.7071067812f,0.7071067812f)).s == uapprox(0.7071067812f));
REQUIRE(inverse(qrotate_x(10.f)) == qrotate_x(-10.f));
REQUIRE(all(approx(inverse(qrotate_x(10.f) * qrotate_y(15.f)), qrotate_y(-15.f) * qrotate_x(-10.f))));
}
}