Remove Quaternion constructor with Euler angles and replace it by static fromEulerAngles() method

This commit is contained in:
Daniel Chappuis 2017-11-28 17:26:13 +01:00
parent c8e9cca912
commit 317dea90bd
6 changed files with 59 additions and 53 deletions

View File

@ -47,14 +47,28 @@ Quaternion::Quaternion(decimal newW, const Vector3& v) : x(v.x), y(v.y), z(v.z),
} }
// Constructor which convert Euler angles (in radians) to a quaternion // Constructor with the component w and the vector v=(x y z)
Quaternion::Quaternion(decimal angleX, decimal angleY, decimal angleZ) { Quaternion::Quaternion(const Vector3& v, decimal newW) : x(v.x), y(v.y), z(v.z), w(newW) {
initWithEulerAngles(angleX, angleY, angleZ);
} }
// Constructor which convert Euler angles (in radians) to a quaternion // Return a quaternion constructed from Euler angles (in radians)
Quaternion::Quaternion(const Vector3& eulerAngles) { Quaternion Quaternion::fromEulerAngles(decimal angleX, decimal angleY, decimal angleZ) {
initWithEulerAngles(eulerAngles.x, eulerAngles.y, eulerAngles.z);
Quaternion quaternion;
quaternion.initWithEulerAngles(angleX, angleY, angleZ);
return quaternion;
}
// Return a quaternion constructed from Euler angles (in radians)
Quaternion Quaternion::fromEulerAngles(const Vector3& eulerAngles) {
Quaternion quaternion;
quaternion.initWithEulerAngles(eulerAngles.x, eulerAngles.y, eulerAngles.z);
return quaternion;
} }
// Copy-constructor // Copy-constructor
@ -72,10 +86,10 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
decimal r; decimal r;
decimal s; decimal s;
if (trace < 0.0) { if (trace < decimal(0.0)) {
if (matrix[1][1] > matrix[0][0]) { if (matrix[1][1] > matrix[0][0]) {
if(matrix[2][2] > matrix[1][1]) { if(matrix[2][2] > matrix[1][1]) {
r = sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + decimal(1.0)); r = std::sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + decimal(1.0));
s = decimal(0.5) / r; s = decimal(0.5) / r;
// Compute the quaternion // Compute the quaternion
@ -85,7 +99,7 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
w = (matrix[1][0] - matrix[0][1]) * s; w = (matrix[1][0] - matrix[0][1]) * s;
} }
else { else {
r = sqrt(matrix[1][1] - matrix[2][2] - matrix[0][0] + decimal(1.0)); r = std::sqrt(matrix[1][1] - matrix[2][2] - matrix[0][0] + decimal(1.0));
s = decimal(0.5) / r; s = decimal(0.5) / r;
// Compute the quaternion // Compute the quaternion
@ -96,7 +110,7 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
} }
} }
else if (matrix[2][2] > matrix[0][0]) { else if (matrix[2][2] > matrix[0][0]) {
r = sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + decimal(1.0)); r = std::sqrt(matrix[2][2] - matrix[0][0] - matrix[1][1] + decimal(1.0));
s = decimal(0.5) / r; s = decimal(0.5) / r;
// Compute the quaternion // Compute the quaternion
@ -106,7 +120,7 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
w = (matrix[1][0] - matrix[0][1]) * s; w = (matrix[1][0] - matrix[0][1]) * s;
} }
else { else {
r = sqrt(matrix[0][0] - matrix[1][1] - matrix[2][2] + decimal(1.0)); r = std::sqrt(matrix[0][0] - matrix[1][1] - matrix[2][2] + decimal(1.0));
s = decimal(0.5) / r; s = decimal(0.5) / r;
// Compute the quaternion // Compute the quaternion
@ -117,7 +131,7 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
} }
} }
else { else {
r = sqrt(trace + decimal(1.0)); r = std::sqrt(trace + decimal(1.0));
s = decimal(0.5) / r; s = decimal(0.5) / r;
// Compute the quaternion // Compute the quaternion
@ -132,22 +146,12 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
/// This method is used to get the rotation angle (in radian) and the unit /// This method is used to get the rotation angle (in radian) and the unit
/// rotation axis of an orientation quaternion. /// rotation axis of an orientation quaternion.
void Quaternion::getRotationAngleAxis(decimal& angle, Vector3& axis) const { void Quaternion::getRotationAngleAxis(decimal& angle, Vector3& axis) const {
Quaternion quaternion;
// If the quaternion is unit
if (length() == 1.0) {
quaternion = *this;
}
else {
// We compute the unit quaternion
quaternion = getUnit();
}
// Compute the roation angle // Compute the roation angle
angle = acos(quaternion.w) * decimal(2.0); angle = std::acos(w) * decimal(2.0);
// Compute the 3D rotation axis // Compute the 3D rotation axis
Vector3 rotationAxis(quaternion.x, quaternion.y, quaternion.z); Vector3 rotationAxis(x, y, z);
// Normalize the rotation axis // Normalize the rotation axis
rotationAxis = rotationAxis.getUnit(); rotationAxis = rotationAxis.getUnit();
@ -162,7 +166,7 @@ Matrix3x3 Quaternion::getMatrix() const {
decimal nQ = x*x + y*y + z*z + w*w; decimal nQ = x*x + y*y + z*z + w*w;
decimal s = 0.0; decimal s = 0.0;
if (nQ > 0.0) { if (nQ > decimal(0.0)) {
s = decimal(2.0) / nQ; s = decimal(2.0) / nQ;
} }
@ -190,7 +194,7 @@ Matrix3x3 Quaternion::getMatrix() const {
/// The t argument has to be such that 0 <= t <= 1. This method is static. /// The t argument has to be such that 0 <= t <= 1. This method is static.
Quaternion Quaternion::slerp(const Quaternion& quaternion1, Quaternion Quaternion::slerp(const Quaternion& quaternion1,
const Quaternion& quaternion2, decimal t) { const Quaternion& quaternion2, decimal t) {
assert(t >= 0.0 && t <= 1.0); assert(t >= decimal(0.0) && t <= decimal(1.0));
decimal invert = 1.0; decimal invert = 1.0;
@ -198,7 +202,7 @@ Quaternion Quaternion::slerp(const Quaternion& quaternion1,
decimal cosineTheta = quaternion1.dot(quaternion2); decimal cosineTheta = quaternion1.dot(quaternion2);
// Take care of the sign of cosineTheta // Take care of the sign of cosineTheta
if (cosineTheta < 0.0) { if (cosineTheta < decimal(0.0)) {
cosineTheta = -cosineTheta; cosineTheta = -cosineTheta;
invert = -1.0; invert = -1.0;
} }
@ -212,14 +216,14 @@ Quaternion Quaternion::slerp(const Quaternion& quaternion1,
} }
// Compute the theta angle // Compute the theta angle
decimal theta = acos(cosineTheta); decimal theta = std::acos(cosineTheta);
// Compute sin(theta) // Compute sin(theta)
decimal sineTheta = sin(theta); decimal sineTheta = std::sin(theta);
// Compute the two coefficients that are in the spherical linear interpolation formula // Compute the two coefficients that are in the spherical linear interpolation formula
decimal coeff1 = sin((decimal(1.0)-t)*theta) / sineTheta; decimal coeff1 = std::sin((decimal(1.0)-t)*theta) / sineTheta;
decimal coeff2 = sin(t*theta) / sineTheta * invert; decimal coeff2 = std::sin(t*theta) / sineTheta * invert;
// Compute and return the interpolated quaternion // Compute and return the interpolated quaternion
return quaternion1 * coeff1 + quaternion2 * coeff2; return quaternion1 * coeff1 + quaternion2 * coeff2;

View File

@ -69,11 +69,8 @@ struct Quaternion {
/// Constructor with the component w and the vector v=(x y z) /// Constructor with the component w and the vector v=(x y z)
Quaternion(decimal newW, const Vector3& v); Quaternion(decimal newW, const Vector3& v);
/// Constructor which convert Euler angles (in radians) to a quaternion /// Constructor with the component w and the vector v=(x y z)
Quaternion(decimal angleX, decimal angleY, decimal angleZ); Quaternion(const Vector3& v, decimal newW);
/// Constructor which convert Euler angles (in radians) to a quaternion
Quaternion(const Vector3& eulerAngles);
/// Copy-constructor /// Copy-constructor
Quaternion(const Quaternion& quaternion); Quaternion(const Quaternion& quaternion);
@ -123,6 +120,12 @@ struct Quaternion {
/// Return the identity quaternion /// Return the identity quaternion
static Quaternion identity(); static Quaternion identity();
/// Return a quaternion constructed from Euler angles (in radians)
static Quaternion fromEulerAngles(decimal angleX, decimal angleY, decimal angleZ);
/// Return a quaternion constructed from Euler angles (in radians)
static Quaternion fromEulerAngles(const Vector3& eulerAngles);
/// Dot product between two quaternions /// Dot product between two quaternions
decimal dot(const Quaternion& quaternion) const; decimal dot(const Quaternion& quaternion) const;
@ -228,7 +231,6 @@ inline void Quaternion::inverse() {
x = -x; x = -x;
y = -y; y = -y;
z = -z; z = -z;
w = w;
} }
// Return the unit quaternion // Return the unit quaternion

View File

@ -93,7 +93,7 @@ class TestPointInside : public Test {
// Body transform // Body transform
Vector3 position(-3, 2, 7); Vector3 position(-3, 2, 7);
Quaternion orientation(PI / 5, PI / 6, PI / 7); Quaternion orientation = Quaternion::fromEulerAngles(PI / 5, PI / 6, PI / 7);
mBodyTransform = Transform(position, orientation); mBodyTransform = Transform(position, orientation);
// Create the bodies // Create the bodies
@ -108,7 +108,7 @@ class TestPointInside : public Test {
// Collision shape transform // Collision shape transform
Vector3 shapePosition(1, -4, -3); Vector3 shapePosition(1, -4, -3);
Quaternion shapeOrientation(3 * PI / 6 , -PI / 8, PI / 3); Quaternion shapeOrientation = Quaternion::fromEulerAngles(3 * PI / 6 , -PI / 8, PI / 3);
mShapeTransform = Transform(shapePosition, shapeOrientation); mShapeTransform = Transform(shapePosition, shapeOrientation);
// Compute the the transform from a local shape point to world-space // Compute the the transform from a local shape point to world-space
@ -165,7 +165,7 @@ class TestPointInside : public Test {
// Compound shape is a capsule and a sphere // Compound shape is a capsule and a sphere
Vector3 positionShape2(Vector3(4, 2, -3)); Vector3 positionShape2(Vector3(4, 2, -3));
Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); Quaternion orientationShape2 = Quaternion::fromEulerAngles(-3 *PI / 8, 1.5 * PI/ 3, PI / 13);
Transform shapeTransform2(positionShape2, orientationShape2); Transform shapeTransform2(positionShape2, orientationShape2);
mLocalShape2ToWorld = mBodyTransform * shapeTransform2; mLocalShape2ToWorld = mBodyTransform * shapeTransform2;
mCompoundBody->addCollisionShape(mCapsuleShape, mShapeTransform); mCompoundBody->addCollisionShape(mCapsuleShape, mShapeTransform);

View File

@ -169,7 +169,7 @@ class TestRaycast : public Test {
// Body transform // Body transform
Vector3 position(-3, 2, 7); Vector3 position(-3, 2, 7);
Quaternion orientation(PI / 5, PI / 6, PI / 7); Quaternion orientation = Quaternion::fromEulerAngles(PI / 5, PI / 6, PI / 7);
mBodyTransform = Transform(position, orientation); mBodyTransform = Transform(position, orientation);
// Create the bodies // Create the bodies
@ -185,7 +185,7 @@ class TestRaycast : public Test {
// Collision shape transform // Collision shape transform
Vector3 shapePosition(1, -4, -3); Vector3 shapePosition(1, -4, -3);
Quaternion shapeOrientation(3 * PI / 6 , -PI / 8, PI / 3); Quaternion shapeOrientation = Quaternion::fromEulerAngles(3 * PI / 6 , -PI / 8, PI / 3);
mShapeTransform = Transform(shapePosition, shapeOrientation); mShapeTransform = Transform(shapePosition, shapeOrientation);
// Compute the the transform from a local shape point to world-space // Compute the the transform from a local shape point to world-space
@ -246,7 +246,7 @@ class TestRaycast : public Test {
// Compound shape is a cylinder and a sphere // Compound shape is a cylinder and a sphere
Vector3 positionShape2(Vector3(4, 2, -3)); Vector3 positionShape2(Vector3(4, 2, -3));
Quaternion orientationShape2(-3 *PI / 8, 1.5 * PI/ 3, PI / 13); Quaternion orientationShape2 = Quaternion::fromEulerAngles(-3 *PI / 8, 1.5 * PI/ 3, PI / 13);
Transform shapeTransform2(positionShape2, orientationShape2); Transform shapeTransform2(positionShape2, orientationShape2);
mLocalShape2ToWorld = mBodyTransform * shapeTransform2; mLocalShape2ToWorld = mBodyTransform * shapeTransform2;
mCompoundCapsuleProxyShape = mCompoundBody->addCollisionShape(mCapsuleShape, mShapeTransform); mCompoundCapsuleProxyShape = mCompoundBody->addCollisionShape(mCapsuleShape, mShapeTransform);

View File

@ -94,7 +94,7 @@ class TestQuaternion : public Test {
const decimal PI_OVER_2 = PI * decimal(0.5); const decimal PI_OVER_2 = PI * decimal(0.5);
const decimal PI_OVER_4 = PI_OVER_2 * decimal(0.5); const decimal PI_OVER_4 = PI_OVER_2 * decimal(0.5);
Quaternion quaternion5(PI_OVER_2, 0, 0); Quaternion quaternion5 = Quaternion::fromEulerAngles(PI_OVER_2, 0, 0);
Quaternion quaternionTest5(std::sin(PI_OVER_4), 0, 0, std::cos(PI_OVER_4)); Quaternion quaternionTest5(std::sin(PI_OVER_4), 0, 0, std::cos(PI_OVER_4));
quaternionTest5.normalize(); quaternionTest5.normalize();
test(approxEqual(quaternion5.x, quaternionTest5.x)); test(approxEqual(quaternion5.x, quaternionTest5.x));
@ -102,7 +102,7 @@ class TestQuaternion : public Test {
test(approxEqual(quaternion5.z, quaternionTest5.z)); test(approxEqual(quaternion5.z, quaternionTest5.z));
test(approxEqual(quaternion5.w, quaternionTest5.w)); test(approxEqual(quaternion5.w, quaternionTest5.w));
Quaternion quaternion6(0, PI_OVER_2, 0); Quaternion quaternion6 = Quaternion::fromEulerAngles(0, PI_OVER_2, 0);
Quaternion quaternionTest6(0, std::sin(PI_OVER_4), 0, std::cos(PI_OVER_4)); Quaternion quaternionTest6(0, std::sin(PI_OVER_4), 0, std::cos(PI_OVER_4));
quaternionTest6.normalize(); quaternionTest6.normalize();
test(approxEqual(quaternion6.x, quaternionTest6.x)); test(approxEqual(quaternion6.x, quaternionTest6.x));
@ -110,7 +110,7 @@ class TestQuaternion : public Test {
test(approxEqual(quaternion6.z, quaternionTest6.z)); test(approxEqual(quaternion6.z, quaternionTest6.z));
test(approxEqual(quaternion6.w, quaternionTest6.w)); test(approxEqual(quaternion6.w, quaternionTest6.w));
Quaternion quaternion7(Vector3(0, 0, PI_OVER_2)); Quaternion quaternion7 = Quaternion::fromEulerAngles(Vector3(0, 0, PI_OVER_2));
Quaternion quaternionTest7(0, 0, std::sin(PI_OVER_4), std::cos(PI_OVER_4)); Quaternion quaternionTest7(0, 0, std::sin(PI_OVER_4), std::cos(PI_OVER_4));
quaternionTest7.normalize(); quaternionTest7.normalize();
test(approxEqual(quaternion7.x, quaternionTest7.x)); test(approxEqual(quaternion7.x, quaternionTest7.x));
@ -124,7 +124,7 @@ class TestQuaternion : public Test {
// Test method that returns the length // Test method that returns the length
Quaternion quaternion(2, 3, -4, 5); Quaternion quaternion(2, 3, -4, 5);
test(approxEqual(quaternion.length(), sqrt(decimal(54.0)))); test(approxEqual(quaternion.length(), std::sqrt(decimal(54.0))));
// Test method that returns a unit quaternion // Test method that returns a unit quaternion
test(approxEqual(quaternion.getUnit().length(), 1.0)); test(approxEqual(quaternion.getUnit().length(), 1.0));

View File

@ -282,32 +282,32 @@ bool CollisionDetectionScene::keyboardEvent(int key, int scancode, int action, i
} }
else if (key == GLFW_KEY_A && action == GLFW_PRESS) { else if (key == GLFW_KEY_A && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion(0, stepAngle, 0) * transform.getOrientation()); transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, stepAngle, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform); mAllShapes[mSelectedShapeIndex]->setTransform(transform);
} }
else if (key == GLFW_KEY_D && action == GLFW_PRESS) { else if (key == GLFW_KEY_D && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion(0, -stepAngle, 0) * transform.getOrientation()); transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, -stepAngle, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform); mAllShapes[mSelectedShapeIndex]->setTransform(transform);
} }
else if (key == GLFW_KEY_W && action == GLFW_PRESS) { else if (key == GLFW_KEY_W && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion(stepAngle, 0, 0) * transform.getOrientation()); transform.setOrientation(rp3d::Quaternion::fromEulerAngles(stepAngle, 0, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform); mAllShapes[mSelectedShapeIndex]->setTransform(transform);
} }
else if (key == GLFW_KEY_S && action == GLFW_PRESS) { else if (key == GLFW_KEY_S && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion(-stepAngle, 0, 0) * transform.getOrientation()); transform.setOrientation(rp3d::Quaternion::fromEulerAngles(-stepAngle, 0, 0) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform); mAllShapes[mSelectedShapeIndex]->setTransform(transform);
} }
else if (key == GLFW_KEY_F && action == GLFW_PRESS) { else if (key == GLFW_KEY_F && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion(0, 0, stepAngle) * transform.getOrientation()); transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, stepAngle) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform); mAllShapes[mSelectedShapeIndex]->setTransform(transform);
} }
else if (key == GLFW_KEY_G && action == GLFW_PRESS) { else if (key == GLFW_KEY_G && action == GLFW_PRESS) {
rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform(); rp3d::Transform transform = mAllShapes[mSelectedShapeIndex]->getTransform();
transform.setOrientation(rp3d::Quaternion(0, 0, -stepAngle) * transform.getOrientation()); transform.setOrientation(rp3d::Quaternion::fromEulerAngles(0, 0, -stepAngle) * transform.getOrientation());
mAllShapes[mSelectedShapeIndex]->setTransform(transform); mAllShapes[mSelectedShapeIndex]->setTransform(transform);
} }