28#include <jau/test/catch2_ext.hpp>
57TEST_CASE(
"Test 01 Normalize",
"[quaternion][linear_algebra][math]" ) {
58 const Quat4f quat(0, 1, 2, 3);
64TEST_CASE(
"Test 02 Rotate Zero Vector",
"[quaternion][linear_algebra][math]" ) {
67 REQUIRE(
ZERO == rotVec0 );
70TEST_CASE(
"Test 03 Invert and Conugate",
"[quaternion][linear_algebra][math]" ) {
73 const Quat4f quat0(0, 1, 2, 3);
75 REQUIRE( quat0 == quat0Inv.
invert() );
79 const Quat4f quat0(-1, -2, -3, 4);
81 REQUIRE( quat0 == quat0Conj );
85TEST_CASE(
"Test 04 Dot",
"[quaternion][linear_algebra][math]" ) {
86 const Quat4f quat(7, 2, 5, -1);
87 REQUIRE( 35.0f == quat.
dot(3, 1, 2, -2));
88 REQUIRE( -11.0f == quat.
dot(
Quat4f(-1, 1, -1, 1)));
95TEST_CASE(
"Test 10 Angle Axis",
"[quaternion][linear_algebra][math]" ) {
99 REQUIRE( quat2 == quat1 );
105 REQUIRE( vecOut1 == vecOut2 );
106 REQUIRE(
true ==
jau::equals( 0.0f, std::abs( vecOut1.
dist(vecOut2) ) ) );
116 REQUIRE( quat1 == quat2 );
118 quat1.
set(0, 0, 0, 0);
120 REQUIRE(0.0f == angle);
121 REQUIRE(
UNIT_X == vecOut1);
124TEST_CASE(
"Test 11 From Vec to Vec",
"[quaternion][linear_algebra][math]" ) {
131 REQUIRE( quat == quat2 );
134 REQUIRE( quat2 == quat );
157TEST_CASE(
"Test 12 From and to Euler Angles",
"[quaternion][linear_algebra][math]" ) {
165 REQUIRE( angles0Exp == angles0Has );
169 REQUIRE( quat == quat2 );
178 REQUIRE( angles1Exp == angles1Has );
181 REQUIRE( quat == quat2 );
190 REQUIRE( angles2Exp == angles2Has );
193 REQUIRE( quat == quat2 );
196TEST_CASE(
"Test 13 From Euler Angles and Rotate Vec",
"[quaternion][linear_algebra][math]" ) {
215TEST_CASE(
"Test 14 Matrix",
"[matrix][quaternion][linear_algebra][math]" ) {
228 quat1.
set(0, 0, 0, 0);
231 REQUIRE( mat1 == mat2 );
240 0, std::cos(a), std::sin(a), 0,
241 0, -std::sin(a), std::cos(a), 0,
248 for(
int i=0; i<16; ++i) { REQUIRE_THAT( mat2_0[i], Catch::Matchers::WithinAbs(mat1_0[i],
EPSILON<float>) ); }
256 REQUIRE( mat1 == mat2 );
258 REQUIRE( quat1 == quat2 );
264 REQUIRE( mat2 == mat2c );
265 REQUIRE( mat1 == mat2c );
273 REQUIRE( quat1 == quat2 );
279 REQUIRE( mat1 == mat2 );
286 REQUIRE( vecHas == vecOut3);
293 REQUIRE( vecHas == vecOut3);
303 0, std::cos(a), std::sin(a), 0,
304 0, -std::sin(a), std::cos(a), 0,
312 REQUIRE(mat1 == mat2);
321 REQUIRE(mat1 == mat2);
324 (mat2 *
ONE_v4).getVec3(vecOut3);
333 std::cos(a), 0, -std::sin(a), 0,
335 std::sin(a), 0, std::cos(a), 0,
343 REQUIRE(mat1 == mat2);
353 REQUIRE(mat1 == mat2);
365 std::cos(a), std::sin(a), 0, 0,
366 -std::sin(a), std::cos(a), 0, 0,
375 REQUIRE(mat1 == mat2);
384 REQUIRE(mat1 == mat2);
396 Vec3f vecExp0( std::cos(a), std::sin(a), 0);
397 Vec3f vecExp1(-std::sin(a), std::cos(a), 0);
398 Vec3f vecExp2( 0, 0, 1);
402 std::cos(a), std::sin(a), 0, 0,
403 -std::sin(a), std::cos(a), 0, 0,
409 REQUIRE(vecExp0 == vecCol);
410 REQUIRE_THAT( std::abs( vecExp0.
dist(vecCol) ), Catch::Matchers::WithinAbs(0.0f,
EPSILON<float>) );
413 REQUIRE(vecExp1 == vecCol);
414 REQUIRE_THAT( std::abs( vecExp1.
dist(vecCol) ), Catch::Matchers::WithinAbs(0.0f,
EPSILON<float>) );
417 REQUIRE(vecExp2 == vecCol);
418 REQUIRE_THAT( std::abs( vecExp2.
dist(vecCol) ), Catch::Matchers::WithinAbs(0.0f,
EPSILON<float>) );
421TEST_CASE(
"Test 15a Axes And Matrix",
"[matrix][quaternion][linear_algebra][math]" ) {
430 REQUIRE( matExp1 == matHas);
435 std::cout <<
"exp-euler " << eulerExp << std::endl;
436 std::cout <<
"has-euler " << eulerHas << std::endl;
437 REQUIRE(eulerExp == eulerHas);
439 REQUIRE(quat2 == quat1);
443 REQUIRE(quat2 == quat1);
446TEST_CASE(
"Test 15b Axes And Matrix",
"[matrix][quaternion][linear_algebra][math]" ) {
455 REQUIRE( matExp == matHas);
460 std::cout <<
"exp-euler " << eulerExp << std::endl;
461 std::cout <<
"has-euler " << eulerHas << std::endl;
462 REQUIRE(eulerExp == eulerHas);
464 REQUIRE(quat2 == quat1);
468 REQUIRE(quat2 == quat1);
471TEST_CASE(
"Test 15c Axes And Matrix",
"[matrix][quaternion][linear_algebra][math]" ) {
474 eulerExp1.
get(eulerExp0);
484 std::cout <<
"matExp " << matExp << std::endl;
485 std::cout <<
"matHas " << matHas << std::endl;
496 std::cout <<
"exp-euler " << eulerExp1 << std::endl;
497 std::cout <<
"has-euler " << eulerHas1 << std::endl;
498 std::cout <<
"diff-euler " << ( eulerExp1 - eulerHas1 ) << std::endl;
501 eulerHas1.
get(eulerHas0);
502 Vec3f eulerHas0v(eulerHas0), eulerExp0v(eulerExp0);
510 REQUIRE(quat2 == quat1);
514 REQUIRE(quat2 == quat1);
521TEST_CASE(
"Test 20 Add Subtract",
"[quaternion][linear_algebra][math]" ) {
523 Quat4f quatExp(1, 2, 3, 4);
530 REQUIRE(quatExp == quatHas);
533 quatHas = quat1 + quat2;
534 REQUIRE(quatExp == quatHas);
538 Quat4f quatExp(-1, 0, 1, 2);
539 Quat4f quat1, quat2, quatHas;
540 quat1.
set(0, 1, 2, 3);
541 quat2.
set(1, 1, 1, 1);
546 REQUIRE(quatExp == quatHas);
549 quatHas = quat1 - quat2;
550 REQUIRE(quatExp == quatHas);
554TEST_CASE(
"Test 21 Multiply",
"[quaternion][linear_algebra][math]" ) {
557 Quat4f quatExp(1, 2, 4, 6);
558 Quat4f quat1(0.5f, 1, 2, 3);
564 REQUIRE(quatExp == quat2);
567 quat2 = quat1 * 2.0f;
568 REQUIRE(quatExp == quat2);
570 quat2 = 2.0f * quat1;
571 REQUIRE(quatExp == quat2);
591 quat2 = quat1 * quat1;
605 quat1 = quat1 * quat1 * quat2;
618TEST_CASE(
"Test 22 Invert-Mult-Normal-Conjugate",
"[quaternion][linear_algebra][math]" ) {
626 REQUIRE(quat0 == quat1);
632 quat2 = quat0 * quat1;
635 REQUIRE(quat0 == quat1);
638 quat0.
set(-1.0f, -2.0f, -3.0f, 4.0f);
639 quat1.
set( 1.0f, 2.0f, 3.0f, 4.0f);
642 REQUIRE(quat0 == quat2);
645TEST_CASE(
"Test 23 Rotation Order",
"[quaternion][linear_algebra][math]" ) {
649 REQUIRE(quat1 == quat2);
654 REQUIRE(quat1 == quat2);
659 REQUIRE(quat1 == quat2);
664 REQUIRE(quat1 == quat2);
682 REQUIRE_THAT( vecExp.
dist(vecRot), Catch::Matchers::WithinAbs(0.0f,
EPSILON<float>) );
683 REQUIRE(vecExp == vecRot);
691 REQUIRE_THAT( vecExp.
dist(vecRot), Catch::Matchers::WithinAbs(0.0f,
EPSILON<float>) );
692 REQUIRE(vecExp == vecRot);
699 REQUIRE_THAT( vecExp.
dist(vecRot), Catch::Matchers::WithinAbs(0.0f,
EPSILON<float>) );
700 REQUIRE(vecExp == vecRot);
707 REQUIRE_THAT( vecExp.
dist(vecRot), Catch::Matchers::WithinAbs(0.0f,
EPSILON<float>) );
708 REQUIRE(vecExp == vecRot);
712 REQUIRE(quat == worker);
715TEST_CASE(
"Test 24 Axes",
"[quaternion][linear_algebra][math]" ) {
719 Vec3f xAxis, yAxis, zAxis;
725 REQUIRE(quat0 == quat1);
727 REQUIRE(quat2 == quat1);
729 quat1.
toAxes(xAxis, yAxis, zAxis, rotMat);
731 REQUIRE(quat0 == quat2);
732 REQUIRE(quat1 == quat2);
735TEST_CASE(
"Test 25 Slerp",
"[quaternion][linear_algebra][math]" ) {
749 if( !vecExp.
equals(vecHas) ) {
750 std::cout <<
"Deviation: " << vecExp <<
", " << vecHas <<
": " << ( vecExp - vecHas ) <<
", dist " << vecExp.
dist(vecHas) << std::endl;
771 if( !
UNIT_Y.equals(vecHas) ) {
772 std::cout <<
"Deviation: " <<
UNIT_Y <<
", " << vecHas <<
": " << (
UNIT_Y - vecHas ) <<
", dist " <<
UNIT_Y.dist(vecHas) << std::endl;
784 REQUIRE(
UNIT_X == vecHas);
789 quatS.
setSlerp(quat1, quat2, 0.25f);
794 REQUIRE(
UNIT_X == vecHas);
806 if( !vecExp.
equals(vecHas) ) {
807 std::cout <<
"Deviation: " << vecExp <<
", " << vecHas <<
": " << ( vecExp - vecHas ) <<
", dist " << vecExp.
dist(vecHas) << std::endl;
812TEST_CASE(
"Test 26 LookAt",
"[quaternion][linear_algebra][math]" ) {
813 Vec3f xAxis, yAxis, zAxis, vecHas;
815 if(
DEBUG_MODE ) std::cout <<
"LookAt #01" << std::endl;
820 REQUIRE(direction == vecHas);
823 std::cout <<
"quat0 " << quat << std::endl;
824 std::cout <<
"exp0 " << direction <<
", len " << direction.
length() << std::endl;
825 std::cout <<
"has0 " << vecHas <<
", len " << vecHas.
length() << std::endl;
827 std::cout << std::endl <<
"LookAt #02" << std::endl;
829 (direction =
ONE).normalize();
832 std::cout <<
"direction " << direction << std::endl;
833 std::cout <<
"quat0.0 " << quat << std::endl;
837 std::cout <<
"quat0.1 " << quat << std::endl;
838 std::cout <<
"xAxis " << xAxis <<
", len " << xAxis.
length() << std::endl;
839 std::cout <<
"yAxis " << yAxis <<
", len " << yAxis.
length() << std::endl;
840 std::cout <<
"zAxis " << zAxis <<
", len " << zAxis.
length() << std::endl;
841 std::cout <<
"exp0 " << direction <<
", len " << direction.
length() << std::endl;
842 std::cout <<
"has0 " << vecHas <<
", len " << vecHas.
length() << std::endl;
846 REQUIRE(direction == vecHas);
848 if(
DEBUG_MODE ) std::cout <<
"LookAt #03" << std::endl;
851 if(
DEBUG_MODE ) std::cout <<
"quat0 " << quat << std::endl;
854 std::cout <<
"xAxis " << xAxis <<
", len " << xAxis.
length() << std::endl;
855 std::cout <<
"yAxis " << yAxis <<
", len " << yAxis.
length() << std::endl;
856 std::cout <<
"zAxis " << zAxis <<
", len " << zAxis.
length() << std::endl;
857 std::cout <<
"exp0 " << direction <<
", len " << direction.
length() << std::endl;
858 std::cout <<
"has0 " << vecHas <<
", len " << vecHas.
length() << std::endl;
862 if( !direction.
equals(vecHas) ) {
863 std::cout <<
"Deviation: " << direction <<
", " << vecHas <<
": " << ( direction - vecHas ) <<
", dist " << direction.
dist(vecHas) << std::endl;
constexpr Vec4 & getColumn(const jau::nsize_t column, Vec4 &v_out) const noexcept
Get the named column of the given column-major matrix to v_out w/o boundary check.
constexpr value_type get(const jau::nsize_t i) const noexcept
Returns the ith component of the given column-major order matrix, 0 <= i < 16, w/o boundary check.
constexpr Matrix4 & loadIdentity() noexcept
Set this matrix to identity.
constexpr bool equals(const Matrix4 &o, const value_type epsilon=std::numeric_limits< value_type >::epsilon()) const noexcept
constexpr Matrix4 & load(const_iterator src) noexcept
Load the values of the given matrix src to this matrix w/o boundary check.
constexpr_cxx26 Matrix4 & setToRotationEuler(const value_type bankX, const value_type headingY, const value_type attitudeZ) noexcept
Set this matrix to rotation from the given Euler rotation angles in radians.
constexpr Vec3 & mulVec3(const Vec3 &v_in, Vec3 &v_out) const noexcept
Affine 3f-vector transformation by 4x4 matrix.
constexpr Quaternion & setFromMat(const value_type m00, const value_type m01, const value_type m02, const value_type m10, const value_type m11, const value_type m12, const value_type m20, const value_type m21, const value_type m22) noexcept
Compute the quaternion from a 3x3 column rotation matrix.
constexpr void toAxes(Vec3 &xAxis, Vec3 &yAxis, Vec3 &zAxis, Matrix4< value_type > &tmp) const noexcept
Extracts this quaternion's orthogonal rotation axes.
Quaternion & setFromAngleAxis(const value_type angle, const Vec3 &vector) noexcept
constexpr_cxx26 Quaternion & setFromVectors(const Vec3 &v1, const Vec3 &v2) noexcept
Initialize this quaternion from two vectors.
Vec3 rotateVector(const Vec3 &in) noexcept
constexpr_cxx26 Quaternion & rotateByAngleZ(value_type angle) noexcept
Rotate this quaternion around Z axis with the given angle in radians.
constexpr Quaternion & setIdentity() noexcept
constexpr_cxx26 Quaternion & setFromEuler(const Vec3 &angradXYZ) noexcept
Initializes this quaternion from the given Euler rotation array angradXYZ in radians.
constexpr Quaternion & setFromAxes(const Vec3 &xAxis, const Vec3 &yAxis, const Vec3 &zAxis) noexcept
Initializes this quaternion to represent a rotation formed by the given three orthogonal axes.
Quaternion & setLookAt(const Vec3 &directionIn, const Vec3 &upIn, Vec3 &xAxisOut, Vec3 &yAxisOut, Vec3 &zAxisOut) noexcept
Set this quaternion to equal the rotation required to point the z-axis at direction and the y-axis to...
constexpr_cxx26 Vec3 toEuler() noexcept
Transform this quaternion to Euler rotation angles in radians (pitchX, yawY and rollZ).
constexpr_cxx26 Quaternion & setSlerp(const Quaternion &a, const Quaternion &b, const value_type changeAmnt) noexcept
Set this quaternion to a spherical linear interpolation between the given start and end quaternions b...
constexpr_cxx26 Quaternion & setFromNormalVectors(const Vec3 &v1, const Vec3 &v2) noexcept
Initialize this quaternion from two normalized vectors.
constexpr_cxx26 Quaternion & rotateByAngleY(value_type angle) noexcept
Rotate this quaternion around Y axis with the given angle in radians.
constexpr Quaternion & set(const value_type x, const value_type y, const value_type z, const value_type w) noexcept
Set all values of this quaternion using the given components.
constexpr value_type dot(value_type x, value_type y, value_type z, value_type w) const noexcept
Returns the dot product of this quaternion with the given x,y,z and m_w components.
constexpr_cxx26 value_type toAngleAxis(Vec3 &axis) const noexcept
Transform the rotational quaternion to axis based rotation angles.
constexpr_cxx26 Quaternion & rotateByAngleNormalAxis(const value_type angle, const value_type axisX, const value_type axisY, const value_type axisZ) noexcept
Rotate this quaternion by the given angle and axis.
constexpr Quaternion & invert() noexcept
Invert the quaternion If rotational, will produce a the inverse rotation.
constexpr_cxx26 value_type magnitude() const noexcept
Return the magnitude of this quaternion, i.e.
constexpr Quaternion & normalize() noexcept
Normalize a quaternion required if to be used as a rotational quaternion.
constexpr_cxx26 Quaternion & rotateByAngleX(const value_type angle) noexcept
Rotate this quaternion around X axis with the given angle in radians.
static constexpr const value_type allowed_deviation
constexpr_cxx26 Quaternion & setFromAngleNormalAxis(const value_type angle, const Vec3 &vector) noexcept
constexpr Mat4 toMatrix() const noexcept
Transform this quaternion to a normalized 4x4 column matrix representing the rotation.
constexpr Quaternion & conjugate() noexcept
Conjugates this quaternion [-x, -y, -z, w].
constexpr Vector3F & set(const Vec2f &o, const value_type z_) noexcept
TODO constexpr bool operator<=>(const vec3f_t& rhs ) const noexcept { return ... }...
constexpr Vector3F & normalize() noexcept
Normalize this vector in place.
constexpr value_type length() const noexcept
Return the length of a vector, a.k.a the norm or magnitude
constexpr bool equals(const Vector3F &o, const value_type epsilon=std::numeric_limits< value_type >::epsilon()) const noexcept
constexpr iterator get(iterator xyz) const noexcept
xyz = this, returns xyz.
constexpr value_type dist(const Vector3F &o) const noexcept
Return the distance between this vector and the given one.
constexpr T PI
Alias for π or half-circle radians (180 degrees), i.e. std::numbers::pi_v<T>
constexpr T EPSILON
Alias for epsilon constant, i.e. std::numeric_limits<T>::epsilon()
constexpr bool equals(const T &a, const T &b, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if both values are equal, i.e.
constexpr T PI_4
Alias for π/4 or half right-angle radians (45 degrees), i.e. std::numbers::pi_v<T>/T(4)
constexpr T PI_2
Alias for π/2 or right-angle radians (90 degrees), i.e. std::numbers::pi_v<T>/T(2)
constexpr Vector3F< T > to_vec3(const Vector4F< T > &v) noexcept
out = { this.x, this.y, this.z } dropping w, returns out.
Quaternion< float > Quat4f
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
static constexpr const bool DEBUG_MODE
static const Vec4f ONE_v4
static const Quat4f QUAT_IDENT
static const Vec3f UNIT_Y
static const Vec3f NEG_UNIT_X
static const Vec3f NEG_UNIT_Y
static const Vec3f NEG_ONE
static const Vec3f NEG_UNIT_Z
static const Vec3f UNIT_X
static const Vec4f NEG_ONE_v4
static const Vec3f UNIT_Z
TEST_CASE("Test 01 Normalize", "[quaternion][linear_algebra][math]")
int printf(const char *format,...)
Operating Systems predefined macros.