Select Git revision
w-stacking.h
RotationTests.cpp 15.16 KiB
#include "gtest/gtest.h"
#include "ale/Rotation.h"
#include <cmath>
#include <exception>
using namespace std;
using namespace ale;
TEST(RotationTest, DefaultConstructor) {
Rotation defaultRotation;
vector<double> defaultQuat = defaultRotation.toQuaternion();
ASSERT_EQ(defaultQuat.size(), 4);
EXPECT_NEAR(defaultQuat[0], 1.0, 1e-10);
EXPECT_NEAR(defaultQuat[1], 0.0, 1e-10);
EXPECT_NEAR(defaultQuat[2], 0.0, 1e-10);
EXPECT_NEAR(defaultQuat[3], 0.0, 1e-10);
}
TEST(RotationTest, QuaternionConstructor) {
Rotation rotation(1.0/sqrt(2), 1.0/sqrt(2), 0.0, 0.0);
vector<double> quat = rotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], 1.0/sqrt(2), 1e-10);
EXPECT_NEAR(quat[1], 1.0/sqrt(2), 1e-10);
EXPECT_NEAR(quat[2], 0.0, 1e-10);
EXPECT_NEAR(quat[3], 0.0, 1e-10);
}
TEST(RotationTest, UnnormalizedQuaternion) {
Rotation rotation(1.0, 1.0, 0.0, 0.0);
vector<double> quat = rotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
// The constructor will normalize the quaternion.
EXPECT_NEAR(quat[0], 1.0/sqrt(2), 1e-10);
EXPECT_NEAR(quat[1], 1.0/sqrt(2), 1e-10);
EXPECT_NEAR(quat[2], 0.0, 1e-10);
EXPECT_NEAR(quat[3], 0.0, 1e-10);
}
TEST(RotationTest, MatrixConstructor) {
Rotation rotation(
{0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 0.0});
vector<double> quat = rotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], -0.5, 1e-10);
EXPECT_NEAR(quat[1], 0.5, 1e-10);
EXPECT_NEAR(quat[2], 0.5, 1e-10);
EXPECT_NEAR(quat[3], 0.5, 1e-10);
}
TEST(RotationTest, BadMatrixConstructor) {
ASSERT_THROW(Rotation({0.0, 0.0, 1.0,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
1.0, 0.0, 2.0}),
std::invalid_argument);
}
TEST(RotationTest, SingleAngleConstructor) {
std::vector<double> angles;
angles.push_back(M_PI);
std::vector<int> axes;
axes.push_back(0);
Rotation rotation(angles, axes);
vector<double> quat = rotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], 0.0, 1e-10);
EXPECT_NEAR(quat[1], 1.0, 1e-10);
EXPECT_NEAR(quat[2], 0.0, 1e-10);
EXPECT_NEAR(quat[3], 0.0, 1e-10);
}
TEST(RotationTest, MultiAngleConstructor) {
Rotation rotation({M_PI/2, -M_PI/2, M_PI}, {0, 1, 2});
vector<double> quat = rotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], 0.5, 1e-10);
EXPECT_NEAR(quat[1], -0.5, 1e-10);
EXPECT_NEAR(quat[2], -0.5, 1e-10);
EXPECT_NEAR(quat[3], 0.5, 1e-10);
}
TEST(RotationTest, DifferentAxisAngleCount) {
std::vector<double> angles;
angles.push_back(M_PI);
std::vector<int> axes = {0, 1, 2};
ASSERT_THROW(Rotation(angles, axes), std::invalid_argument);
}
TEST(RotationTest, EmptyAxisAngle) {
std::vector<double> angles;
std::vector<int> axes = {0, 1, 2};
ASSERT_THROW(Rotation(angles, axes), std::invalid_argument);
}
TEST(RotationTest, BadAxisNumber) {
std::vector<double> angles;
angles.push_back(M_PI);
std::vector<int> axes;
axes.push_back(4);
ASSERT_THROW(Rotation(angles, axes), std::invalid_argument);
}
TEST(RotationTest, AxisAngleConstructor) {
Rotation rotation({1.0, 1.0, 1.0}, 2.0 / 3.0 * M_PI);
vector<double> quat = rotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], 0.5, 1e-10);
EXPECT_NEAR(quat[1], 0.5, 1e-10);
EXPECT_NEAR(quat[2], 0.5, 1e-10);
EXPECT_NEAR(quat[3], 0.5, 1e-10);
}
TEST(RotationTest, BadAxisAngleConstructor) {
ASSERT_THROW(Rotation({1.0, 1.0, 1.0, 1.0}, 2.0 / 3.0 * M_PI), std::invalid_argument);
}
TEST(RotationTest, ToRotationMatrix) {
Rotation rotation(-0.5, 0.5, 0.5, 0.5);
vector<double> mat = rotation.toRotationMatrix();
ASSERT_EQ(mat.size(), 9);
EXPECT_NEAR(mat[0], 0.0, 1e-10);
EXPECT_NEAR(mat[1], 1.0, 1e-10);
EXPECT_NEAR(mat[2], 0.0, 1e-10);
EXPECT_NEAR(mat[3], 0.0, 1e-10);
EXPECT_NEAR(mat[4], 0.0, 1e-10);
EXPECT_NEAR(mat[5], 1.0, 1e-10);
EXPECT_NEAR(mat[6], 1.0, 1e-10);
EXPECT_NEAR(mat[7], 0.0, 1e-10);
EXPECT_NEAR(mat[8], 0.0, 1e-10);
}
TEST(RotationTest, ToStateRotationMatrix) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
std::vector<double> av = {2.0 / 3.0 * M_PI, 2.0 / 3.0 * M_PI, 2.0 / 3.0 * M_PI};
vector<double> mat = rotation.toStateRotationMatrix(av);
ASSERT_EQ(mat.size(), 36);
EXPECT_NEAR(mat[0], 0.0, 1e-10);
EXPECT_NEAR(mat[1], 0.0, 1e-10);
EXPECT_NEAR(mat[2], 1.0, 1e-10);
EXPECT_NEAR(mat[3], 0.0, 1e-10);
EXPECT_NEAR(mat[4], 0.0, 1e-10);
EXPECT_NEAR(mat[5], 0.0, 1e-10);
EXPECT_NEAR(mat[6], 1.0, 1e-10);
EXPECT_NEAR(mat[7], 0.0, 1e-10);
EXPECT_NEAR(mat[8], 0.0, 1e-10);
EXPECT_NEAR(mat[9], 0.0, 1e-10);
EXPECT_NEAR(mat[10], 0.0, 1e-10);
EXPECT_NEAR(mat[11], 0.0, 1e-10);
EXPECT_NEAR(mat[12], 0.0, 1e-10);
EXPECT_NEAR(mat[13], 1.0, 1e-10);
EXPECT_NEAR(mat[14], 0.0, 1e-10);
EXPECT_NEAR(mat[15], 0.0, 1e-10);
EXPECT_NEAR(mat[16], 0.0, 1e-10);
EXPECT_NEAR(mat[17], 0.0, 1e-10);
EXPECT_NEAR(mat[18], 2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(mat[19], -2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(mat[20], 0.0, 1e-10);
EXPECT_NEAR(mat[21], 0.0, 1e-10);
EXPECT_NEAR(mat[22], 0.0, 1e-10);
EXPECT_NEAR(mat[23], 1.0, 1e-10);
EXPECT_NEAR(mat[24], 0.0, 1e-10);
EXPECT_NEAR(mat[25], 2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(mat[26], -2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(mat[27], 1.0, 1e-10);
EXPECT_NEAR(mat[28], 0.0, 1e-10);
EXPECT_NEAR(mat[29], 0.0, 1e-10);
EXPECT_NEAR(mat[30], -2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(mat[31], 0.0, 1e-10);
EXPECT_NEAR(mat[32], 2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(mat[33], 0.0, 1e-10);
EXPECT_NEAR(mat[34], 1.0, 1e-10);
EXPECT_NEAR(mat[35], 0.0, 1e-10);
}
TEST(RotationTest, BadAvVectorSize) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
std::vector<double> av = {2.0 / 3.0 * M_PI, 2.0 / 3.0 * M_PI};
ASSERT_THROW(rotation.toStateRotationMatrix(av), std::invalid_argument);
}
TEST(RotationTest, ToEulerXYZ) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
vector<double> angles = rotation.toEuler({0, 1, 2});
ASSERT_EQ(angles.size(), 3);
EXPECT_NEAR(angles[0], 0.0, 1e-10);
EXPECT_NEAR(angles[1], M_PI/2, 1e-10);
EXPECT_NEAR(angles[2], M_PI/2, 1e-10);
}
TEST(RotationTest, ToEulerZYX) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
vector<double> angles = rotation.toEuler({2, 1, 0});
ASSERT_EQ(angles.size(), 3);
EXPECT_NEAR(angles[0], M_PI/2, 1e-10);
EXPECT_NEAR(angles[1], 0.0, 1e-10);
EXPECT_NEAR(angles[2], M_PI/2, 1e-10);
}
TEST(RotationTest, ToEulerWrongNumberOfAxes) {
Rotation rotation;
ASSERT_ANY_THROW(rotation.toEuler({1, 0}));
}
TEST(RotationTest, ToEulerBadAxisNumber) {
Rotation rotation;
ASSERT_THROW(rotation.toEuler({4, 1, 0}), std::invalid_argument);
}
TEST(RotationTest, ToAxisAngle) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
std::pair<std::vector<double>, double> axisAngle = rotation.toAxisAngle();
ASSERT_EQ(axisAngle.first.size(), 3);
EXPECT_NEAR(axisAngle.first[0], 1.0 / sqrt(3), 1e-10);
EXPECT_NEAR(axisAngle.first[1], 1.0 / sqrt(3), 1e-10);
EXPECT_NEAR(axisAngle.first[2], 1.0 / sqrt(3), 1e-10);
EXPECT_NEAR(axisAngle.second, 2.0 / 3.0 * M_PI, 1e-10);
}
TEST(RotationTest, RotateVector) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
Vec3d unitX(1.0, 0.0, 0.0);
Vec3d unitY(0.0, 1.0, 0.0);
Vec3d unitZ(0.0, 0.0, 1.0);
Vec3d rotatedX = rotation(unitX);
Vec3d rotatedY = rotation(unitY);
Vec3d rotatedZ = rotation(unitZ);
EXPECT_NEAR(rotatedX.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.y, 1.0, 1e-10);
EXPECT_NEAR(rotatedX.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.z, 1.0, 1e-10);
EXPECT_NEAR(rotatedZ.x, 1.0, 1e-10);
EXPECT_NEAR(rotatedZ.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.z, 0.0, 1e-10);
}
TEST(RotationTest, RotateState) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
Vec3d av(2.0 / 3.0 * M_PI, 2.0 / 3.0 * M_PI, 2.0 / 3.0 * M_PI);
State unitX({1.0, 0.0, 0.0, 0.0, 0.0, 0.0});
State unitY({0.0, 1.0, 0.0, 0.0, 0.0, 0.0});
State unitZ({0.0, 0.0, 1.0, 0.0, 0.0, 0.0});
State unitVX({0.0, 0.0, 0.0, 1.0, 0.0, 0.0});
State unitVY({0.0, 0.0, 0.0, 0.0, 1.0, 0.0});
State unitVZ({0.0, 0.0, 0.0, 0.0, 0.0, 1.0});
State rotatedX = rotation(unitX, av);
State rotatedY = rotation(unitY, av);
State rotatedZ = rotation(unitZ, av);
State rotatedVX = rotation(unitVX, av);
State rotatedVY = rotation(unitVY, av);
State rotatedVZ = rotation(unitVZ, av);
EXPECT_NEAR(rotatedX.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.position.y, 1.0, 1e-10);
EXPECT_NEAR(rotatedX.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.velocity.x, 2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(rotatedX.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.velocity.z, -2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(rotatedY.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.position.z, 1.0, 1e-10);
EXPECT_NEAR(rotatedY.velocity.x, -2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(rotatedY.velocity.y, 2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(rotatedY.velocity.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.position.x, 1.0, 1e-10);
EXPECT_NEAR(rotatedZ.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.velocity.y, -2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(rotatedZ.velocity.z, 2.0 / 3.0 * M_PI, 1e-10);
EXPECT_NEAR(rotatedVX.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.velocity.y, 1.0, 1e-10);
EXPECT_NEAR(rotatedVX.velocity.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.velocity.z, 1.0, 1e-10);
EXPECT_NEAR(rotatedVZ.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.velocity.x, 1.0, 1e-10);
EXPECT_NEAR(rotatedVZ.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.velocity.z, 0.0, 1e-10);
}
TEST(RotationTest, RotateStateNoAv) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
State unitX({1.0, 0.0, 0.0, 0.0, 0.0, 0.0});
State unitY({0.0, 1.0, 0.0, 0.0, 0.0, 0.0});
State unitZ({0.0, 0.0, 1.0, 0.0, 0.0, 0.0});
State unitVX({0.0, 0.0, 0.0, 1.0, 0.0, 0.0});
State unitVY({0.0, 0.0, 0.0, 0.0, 1.0, 0.0});
State unitVZ({0.0, 0.0, 0.0, 0.0, 0.0, 1.0});
State rotatedX = rotation(unitX);
State rotatedY = rotation(unitY);
State rotatedZ = rotation(unitZ);
State rotatedVX = rotation(unitVX);
State rotatedVY = rotation(unitVY);
State rotatedVZ = rotation(unitVZ);
EXPECT_NEAR(rotatedX.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.position.y, 1.0, 1e-10);
EXPECT_NEAR(rotatedX.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedX.velocity.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.position.z, 1.0, 1e-10);
EXPECT_NEAR(rotatedY.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedY.velocity.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.position.x, 1.0, 1e-10);
EXPECT_NEAR(rotatedZ.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedZ.velocity.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVX.velocity.y, 1.0, 1e-10);
EXPECT_NEAR(rotatedVX.velocity.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.velocity.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVY.velocity.z, 1.0, 1e-10);
EXPECT_NEAR(rotatedVZ.position.x, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.position.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.position.z, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.velocity.x, 1.0, 1e-10);
EXPECT_NEAR(rotatedVZ.velocity.y, 0.0, 1e-10);
EXPECT_NEAR(rotatedVZ.velocity.z, 0.0, 1e-10);
}
TEST(RotationTest, Inverse) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
Rotation inverseRotation = rotation.inverse();
vector<double> quat = inverseRotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], 0.5, 1e-10);
EXPECT_NEAR(quat[1], -0.5, 1e-10);
EXPECT_NEAR(quat[2], -0.5, 1e-10);
EXPECT_NEAR(quat[3], -0.5, 1e-10);
}
TEST(RotationTest, MultiplyRotation) {
Rotation rotation(0.5, 0.5, 0.5, 0.5);
Rotation doubleRotation = rotation * rotation;
vector<double> quat = doubleRotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], -0.5, 1e-10);
EXPECT_NEAR(quat[1], 0.5, 1e-10);
EXPECT_NEAR(quat[2], 0.5, 1e-10);
EXPECT_NEAR(quat[3], 0.5, 1e-10);
}
TEST(RotationTest, Slerp) {
Rotation rotationOne(0.5, 0.5, 0.5, 0.5);
Rotation rotationTwo(-0.5, 0.5, 0.5, 0.5);
Rotation interpRotation = rotationOne.interpolate(rotationTwo, 0.125, ale::SLERP);
vector<double> quat = interpRotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], cos(M_PI * 3.0/8.0), 1e-10);
EXPECT_NEAR(quat[1], sin(M_PI * 3.0/8.0) * 1/sqrt(3.0), 1e-10);
EXPECT_NEAR(quat[2], sin(M_PI * 3.0/8.0) * 1/sqrt(3.0), 1e-10);
EXPECT_NEAR(quat[3], sin(M_PI * 3.0/8.0) * 1/sqrt(3.0), 1e-10);
}
TEST(RotationTest, SlerpExtrapolate) {
Rotation rotationOne(0.5, 0.5, 0.5, 0.5);
Rotation rotationTwo(-0.5, 0.5, 0.5, 0.5);
Rotation interpRotation = rotationOne.interpolate(rotationTwo, 1.125, ale::SLERP);
vector<double> quat = interpRotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], cos(M_PI * 17.0/24.0), 1e-10);
EXPECT_NEAR(quat[1], sin(M_PI * 17.0/24.0) * 1/sqrt(3.0), 1e-10);
EXPECT_NEAR(quat[2], sin(M_PI * 17.0/24.0) * 1/sqrt(3.0), 1e-10);
EXPECT_NEAR(quat[3], sin(M_PI * 17.0/24.0) * 1/sqrt(3.0), 1e-10);
}
TEST(RotationTest, Nlerp) {
Rotation rotationOne(0.5, 0.5, 0.5, 0.5);
Rotation rotationTwo(-0.5, 0.5, 0.5, 0.5);
Rotation interpRotation = rotationOne.interpolate(rotationTwo, 0.125, ale::NLERP);
double scaling = 8.0 / sqrt(57.0);
vector<double> quat = interpRotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], 3.0 / 8.0 * scaling, 1e-10);
EXPECT_NEAR(quat[1], 1.0 / 2.0 * scaling, 1e-10);
EXPECT_NEAR(quat[2], 1.0 / 2.0 * scaling, 1e-10);
EXPECT_NEAR(quat[3], 1.0 / 2.0 * scaling, 1e-10);
}
TEST(RotationTest, NlerpExtrapolate) {
Rotation rotationOne(0.5, 0.5, 0.5, 0.5);
Rotation rotationTwo(-0.5, 0.5, 0.5, 0.5);
Rotation interpRotation = rotationOne.interpolate(rotationTwo, 1.125, ale::NLERP);
double scaling = 8.0 / sqrt(73.0);
vector<double> quat = interpRotation.toQuaternion();
ASSERT_EQ(quat.size(), 4);
EXPECT_NEAR(quat[0], -5.0 / 8.0 * scaling, 1e-10);
EXPECT_NEAR(quat[1], 1.0 / 2.0 * scaling, 1e-10);
EXPECT_NEAR(quat[2], 1.0 / 2.0 * scaling, 1e-10);
EXPECT_NEAR(quat[3], 1.0 / 2.0 * scaling, 1e-10);
}