summaryrefslogtreecommitdiffstats
path: root/dev/MinGfx/src/quaternion.cc
diff options
context:
space:
mode:
authorMatt Strapp <matt@mattstrapp.net>2021-09-24 10:05:55 -0500
committerMatt Strapp <matt@mattstrapp.net>2021-09-24 10:05:55 -0500
commit458496b2db6d67736fd1ffc18c6e51a7a4e1180c (patch)
tree3d6ee4e37a48d71a6ac781cbd93a6d6dcb234f98 /dev/MinGfx/src/quaternion.cc
parentPushed feedback file submission-w1.1 (diff)
parentpublish a2 (diff)
downloadcsci4611-458496b2db6d67736fd1ffc18c6e51a7a4e1180c.tar
csci4611-458496b2db6d67736fd1ffc18c6e51a7a4e1180c.tar.gz
csci4611-458496b2db6d67736fd1ffc18c6e51a7a4e1180c.tar.bz2
csci4611-458496b2db6d67736fd1ffc18c6e51a7a4e1180c.tar.lz
csci4611-458496b2db6d67736fd1ffc18c6e51a7a4e1180c.tar.xz
csci4611-458496b2db6d67736fd1ffc18c6e51a7a4e1180c.tar.zst
csci4611-458496b2db6d67736fd1ffc18c6e51a7a4e1180c.zip
Merge branch 'support-code' of github.umn.edu:umn-csci-4611-f21/shared-upstream
Diffstat (limited to '')
-rw-r--r--dev/MinGfx/src/quaternion.cc521
1 files changed, 261 insertions, 260 deletions
diff --git a/dev/MinGfx/src/quaternion.cc b/dev/MinGfx/src/quaternion.cc
index 7551c62..24830c8 100644
--- a/dev/MinGfx/src/quaternion.cc
+++ b/dev/MinGfx/src/quaternion.cc
@@ -1,260 +1,261 @@
-/*
-Copyright (c) 2017,2018 Regents of the University of Minnesota.
-All Rights Reserved.
-See corresponding header file for details.
-*/
-
-#define _USE_MATH_DEFINES
-#include "quaternion.h"
-
-#include "gfxmath.h"
-
-namespace mingfx {
-
-
-Quaternion::Quaternion() {
- q[0] = 0.0;
- q[1] = 0.0;
- q[2] = 0.0;
- q[3] = 1.0;
-}
-
-Quaternion::Quaternion(float qx, float qy, float qz, float qw) {
- q[0] = qx;
- q[1] = qy;
- q[2] = qz;
- q[3] = qw;
-}
-
-Quaternion::Quaternion(float *ptr) {
- q[0] = ptr[0];
- q[1] = ptr[1];
- q[2] = ptr[2];
- q[3] = ptr[3];
-}
-
-Quaternion::Quaternion(const Quaternion& other) {
- q[0] = other[0];
- q[1] = other[1];
- q[2] = other[2];
- q[3] = other[3];
-}
-
-Quaternion::~Quaternion() {
-}
-
-bool Quaternion::operator==(const Quaternion& other) const {
- return (fabs(other[0] - q[0]) < MINGFX_MATH_EPSILON &&
- fabs(other[1] - q[1]) < MINGFX_MATH_EPSILON &&
- fabs(other[2] - q[2]) < MINGFX_MATH_EPSILON &&
- fabs(other[3] - q[3]) < MINGFX_MATH_EPSILON);
-}
-
-bool Quaternion::operator!=(const Quaternion& other) const {
- return (fabs(other[0] - q[0]) >= MINGFX_MATH_EPSILON ||
- fabs(other[1] - q[1]) >= MINGFX_MATH_EPSILON ||
- fabs(other[2] - q[2]) >= MINGFX_MATH_EPSILON ||
- fabs(other[3] - q[3]) >= MINGFX_MATH_EPSILON);
-}
-
-Quaternion& Quaternion::operator=(const Quaternion& other) {
- q[0] = other[0];
- q[1] = other[1];
- q[2] = other[2];
- q[3] = other[3];
- return *this;
-}
-
-float Quaternion::operator[](const int i) const {
- if ((i>=0) && (i<=3)) {
- return q[i];
- }
- else {
- // this is an error!
- return 0.0;
- }
-}
-
-float& Quaternion::operator[](const int i) {
- return q[i];
-}
-
-
-const float * Quaternion::value_ptr() const {
- return q;
-}
-
-Quaternion Quaternion::Slerp(const Quaternion &other, float alpha) const {
- // https://en.wikipedia.org/wiki/Slerp
-
- Quaternion v0 = *this;
- Quaternion v1 = other;
-
- // Only unit quaternions are valid rotations.
- // Normalize to avoid undefined behavior.
- v0.Normalize();
- v1.Normalize();
-
- // Compute the cosine of the angle between the two vectors.
- float dot = v0.Dot(v1);
-
- // If the dot product is negative, the quaternions
- // have opposite handed-ness and slerp won't take
- // the shorter path. Fix by reversing one quaternion.
- if (dot < 0.0f) {
- v1 = -v1;
- dot = -dot;
- }
-
- const double DOT_THRESHOLD = 0.9995;
- if (dot > DOT_THRESHOLD) {
- // If the inputs are too close for comfort, linearly interpolate
- // and normalize the result.
-
- Quaternion result = v0 + alpha*(v1 - v0);
- result.Normalize();
- return result;
- }
-
- GfxMath::Clamp(dot, -1, 1); // Robustness: Stay within domain of acos()
- float theta_0 = acos(dot); // theta_0 = angle between input vectors
- float theta = theta_0 * alpha; // theta = angle between v0 and result
-
- float s0 = cos(theta) - dot * sin(theta) / sin(theta_0); // == sin(theta_0 - theta) / sin(theta_0)
- float s1 = sin(theta) / sin(theta_0);
-
- return (s0 * v0) + (s1 * v1);
-}
-
-Quaternion Quaternion::Slerp(const Quaternion &a, const Quaternion &b, float alpha) {
- return a.Slerp(b, alpha);
-}
-
-
-std::ostream & operator<< ( std::ostream &os, const Quaternion &q) {
- return os << "<" << q[0] << ", " << q[1] << ", " << q[2] << ", " << q[3] << ")";
-}
-
-std::istream & operator>> ( std::istream &is, Quaternion &q) {
- // format: <qx, qy, qz, qw>
- char dummy;
- return is >> dummy >> q[0] >> dummy >> q[1] >> dummy >> q[2] >> dummy >> q[3] >> dummy;
-}
-
-
-float Quaternion::Dot(const Quaternion& other) const {
- return q[0]*other[0] + q[1]*other[1] + q[2]*other[2] + q[3]*other[3];
-
-}
-
-float Quaternion::Length() const {
- return sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
-}
-
-void Quaternion::Normalize() {
- float sizeSq = + q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
- if (sizeSq < MINGFX_MATH_EPSILON) {
- return; // do nothing to zero quats
- }
- float scaleFactor = (float)1.0/(float)sqrt(sizeSq);
- q[0] *= scaleFactor;
- q[1] *= scaleFactor;
- q[2] *= scaleFactor;
- q[3] *= scaleFactor;
-}
-
-Quaternion Quaternion::ToUnit() const {
- Quaternion qtmp(*this);
- qtmp.Normalize();
- return qtmp;
-}
-
-/// Returns the conjugate of the quaternion.
-Quaternion Quaternion::Conjugate() const {
- return Quaternion(-q[0], -q[1], -q[2], q[3]);
-}
-
-
-Quaternion Quaternion::FromAxisAngle(const Vector3 &axis, float angle) {
- // [qx, qy, qz, qw] = [sin(a/2) * vx, sin(a/2)* vy, sin(a/2) * vz, cos(a/2)]
- float x = sin(angle/2.0f) * axis[0];
- float y = sin(angle/2.0f) * axis[1];
- float z = sin(angle/2.0f) * axis[2];
- float w = cos(angle/2.0f);
- return Quaternion(x,y,z,w);
-}
-
-
-Quaternion Quaternion::FromEulerAnglesZYX(const Vector3 &angles) {
- Quaternion rot_x = Quaternion::FromAxisAngle(Vector3::UnitX(), angles[0]);
- Quaternion rot_y = Quaternion::FromAxisAngle(Vector3::UnitY(), angles[1]);
- Quaternion rot_z = Quaternion::FromAxisAngle(Vector3::UnitZ(), angles[2]);
- return rot_z * rot_y * rot_x;
-}
-
-Vector3 Quaternion::ToEulerAnglesZYX() const {
- // https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
-
- Vector3 angles;
-
- // roll (x-axis rotation)
- float sinr = +2.0f * (w() * x() + y() * z());
- float cosr = +1.0f - 2.0f * (x() * x() + y() * y());
- angles[0] = std::atan2(sinr, cosr);
-
- // pitch (y-axis rotation)
- float sinp = +2.0f * (w() * y() - z() * x());
- if (std::fabs(sinp) >= 1.f)
- angles[1] = std::copysign(GfxMath::HALF_PI, sinp); // use 90 degrees if out of range
- else
- angles[1] = std::asin(sinp);
-
- // yaw (z-axis rotation)
- float siny = +2.0f * (w() * z() + x() * y());
- float cosy = +1.0f - 2.0f * (y() * y() + z() * z());
- angles[2] = std::atan2(siny, cosy);
-
- return angles;
-}
-
-
-Quaternion operator*(const Quaternion& q1, const Quaternion& q2) {
- float real1 = q1[3];
- Vector3 imag1 = Vector3(q1[0], q1[1], q1[2]);
-
- float real2 = q2[3];
- Vector3 imag2 = Vector3(q2[0], q2[1], q2[2]);
-
- float real = real1*real2 - imag1.Dot(imag2);
- Vector3 imag = real1*imag2 + real2*imag1 + imag1.Cross(imag2);
-
- return Quaternion(imag[0], imag[1], imag[2], real);
-}
-
-
-Quaternion operator/(const Quaternion& q, const float s) {
- const float invS = 1.0f / s;
- return Quaternion(q[0]*invS, q[1]*invS, q[2]*invS, q[3]*invS);
-}
-
-Quaternion operator*(const float s, const Quaternion& q) {
- return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s);
-}
-
-Quaternion operator*(const Quaternion& q, const float s) {
- return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s);
-}
-
-Quaternion operator-(const Quaternion& q) {
- return Quaternion(-q[0], -q[1], -q[2], -q[3]);
-}
-
-Quaternion operator+(const Quaternion& q1, const Quaternion& q2) {
- return Quaternion(q1[0] + q2[0], q1[1] + q2[1], q1[2] + q2[2], q1[3] + q2[3]);
-}
-
-Quaternion operator-(const Quaternion& q1, const Quaternion& q2) {
- return Quaternion(q1[0] - q2[0], q1[1] - q2[1], q1[2] - q2[2], q1[3] - q2[3]);
-}
-
-} // end namespace
+/*
+Copyright (c) 2017,2018 Regents of the University of Minnesota.
+All Rights Reserved.
+See corresponding header file for details.
+*/
+
+#define _USE_MATH_DEFINES
+#include "quaternion.h"
+
+#include "gfxmath.h"
+
+namespace mingfx {
+
+
+Quaternion::Quaternion() {
+ q[0] = 0.0;
+ q[1] = 0.0;
+ q[2] = 0.0;
+ q[3] = 1.0;
+}
+
+Quaternion::Quaternion(float qx, float qy, float qz, float qw) {
+ q[0] = qx;
+ q[1] = qy;
+ q[2] = qz;
+ q[3] = qw;
+}
+
+Quaternion::Quaternion(float *ptr) {
+ q[0] = ptr[0];
+ q[1] = ptr[1];
+ q[2] = ptr[2];
+ q[3] = ptr[3];
+}
+
+Quaternion::Quaternion(const Quaternion& other) {
+ q[0] = other[0];
+ q[1] = other[1];
+ q[2] = other[2];
+ q[3] = other[3];
+}
+
+Quaternion::~Quaternion() {
+}
+
+bool Quaternion::operator==(const Quaternion& other) const {
+ return (fabs(other[0] - q[0]) < MINGFX_MATH_EPSILON &&
+ fabs(other[1] - q[1]) < MINGFX_MATH_EPSILON &&
+ fabs(other[2] - q[2]) < MINGFX_MATH_EPSILON &&
+ fabs(other[3] - q[3]) < MINGFX_MATH_EPSILON);
+}
+
+bool Quaternion::operator!=(const Quaternion& other) const {
+ return (fabs(other[0] - q[0]) >= MINGFX_MATH_EPSILON ||
+ fabs(other[1] - q[1]) >= MINGFX_MATH_EPSILON ||
+ fabs(other[2] - q[2]) >= MINGFX_MATH_EPSILON ||
+ fabs(other[3] - q[3]) >= MINGFX_MATH_EPSILON);
+}
+
+Quaternion& Quaternion::operator=(const Quaternion& other) {
+ q[0] = other[0];
+ q[1] = other[1];
+ q[2] = other[2];
+ q[3] = other[3];
+ return *this;
+}
+
+float Quaternion::operator[](const int i) const {
+ if ((i>=0) && (i<=3)) {
+ return q[i];
+ }
+ else {
+ // this is an error!
+ return 0.0;
+ }
+}
+
+float& Quaternion::operator[](const int i) {
+ return q[i];
+}
+
+
+const float * Quaternion::value_ptr() const {
+ return q;
+}
+
+Quaternion Quaternion::Slerp(const Quaternion &other, float alpha) const {
+ // https://en.wikipedia.org/wiki/Slerp
+
+ Quaternion v0 = *this;
+ Quaternion v1 = other;
+
+ // Only unit quaternions are valid rotations.
+ // Normalize to avoid undefined behavior.
+ v0.Normalize();
+ v1.Normalize();
+
+ // Compute the cosine of the angle between the two vectors.
+ float dot = v0.Dot(v1);
+
+ // If the dot product is negative, the quaternions
+ // have opposite handed-ness and slerp won't take
+ // the shorter path. Fix by reversing one quaternion.
+ if (dot < 0.0f) {
+ v1 = -v1;
+ dot = -dot;
+ }
+
+ const double DOT_THRESHOLD = 0.9995;
+ if (dot > DOT_THRESHOLD) {
+ // If the inputs are too close for comfort, linearly interpolate
+ // and normalize the result.
+
+ Quaternion result = v0 + alpha*(v1 - v0);
+ result.Normalize();
+ return result;
+ }
+
+ GfxMath::Clamp(dot, -1, 1); // Robustness: Stay within domain of acos()
+ float theta_0 = GfxMath::acos(dot); // theta_0 = angle between input vectors
+ float theta = theta_0 * alpha; // theta = angle between v0 and result
+
+ float s0 = GfxMath::cos(theta) - dot
+ * GfxMath::sin(theta) / GfxMath::sin(theta_0); // == sin(theta_0 - theta) / sin(theta_0)
+ float s1 = GfxMath::sin(theta) / GfxMath::sin(theta_0);
+
+ return (s0 * v0) + (s1 * v1);
+}
+
+Quaternion Quaternion::Slerp(const Quaternion &a, const Quaternion &b, float alpha) {
+ return a.Slerp(b, alpha);
+}
+
+
+std::ostream & operator<< ( std::ostream &os, const Quaternion &q) {
+ return os << "<" << q[0] << ", " << q[1] << ", " << q[2] << ", " << q[3] << ")";
+}
+
+std::istream & operator>> ( std::istream &is, Quaternion &q) {
+ // format: <qx, qy, qz, qw>
+ char dummy;
+ return is >> dummy >> q[0] >> dummy >> q[1] >> dummy >> q[2] >> dummy >> q[3] >> dummy;
+}
+
+
+float Quaternion::Dot(const Quaternion& other) const {
+ return q[0]*other[0] + q[1]*other[1] + q[2]*other[2] + q[3]*other[3];
+
+}
+
+float Quaternion::Length() const {
+ return sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+}
+
+void Quaternion::Normalize() {
+ float sizeSq = + q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3];
+ if (sizeSq < MINGFX_MATH_EPSILON) {
+ return; // do nothing to zero quats
+ }
+ float scaleFactor = (float)1.0/(float)sqrt(sizeSq);
+ q[0] *= scaleFactor;
+ q[1] *= scaleFactor;
+ q[2] *= scaleFactor;
+ q[3] *= scaleFactor;
+}
+
+Quaternion Quaternion::ToUnit() const {
+ Quaternion qtmp(*this);
+ qtmp.Normalize();
+ return qtmp;
+}
+
+/// Returns the conjugate of the quaternion.
+Quaternion Quaternion::Conjugate() const {
+ return Quaternion(-q[0], -q[1], -q[2], q[3]);
+}
+
+
+Quaternion Quaternion::FromAxisAngle(const Vector3 &axis, float angle) {
+ // [qx, qy, qz, qw] = [sin(a/2) * vx, sin(a/2)* vy, sin(a/2) * vz, cos(a/2)]
+ float x = GfxMath::sin(angle/2.0) * axis[0];
+ float y = GfxMath::sin(angle/2.0) * axis[1];
+ float z = GfxMath::sin(angle/2.0) * axis[2];
+ float w = GfxMath::cos(angle/2.0);
+ return Quaternion(x,y,z,w);
+}
+
+
+Quaternion Quaternion::FromEulerAnglesZYX(const Vector3 &angles) {
+ Quaternion rot_x = Quaternion::FromAxisAngle(Vector3::UnitX(), angles[0]);
+ Quaternion rot_y = Quaternion::FromAxisAngle(Vector3::UnitY(), angles[1]);
+ Quaternion rot_z = Quaternion::FromAxisAngle(Vector3::UnitZ(), angles[2]);
+ return rot_z * rot_y * rot_x;
+}
+
+Vector3 Quaternion::ToEulerAnglesZYX() const {
+ // https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
+
+ Vector3 angles;
+
+ // roll (x-axis rotation)
+ float sinr = +2.0f * (w() * x() + y() * z());
+ float cosr = +1.0f - 2.0f * (x() * x() + y() * y());
+ angles[0] = std::atan2(sinr, cosr);
+
+ // pitch (y-axis rotation)
+ float sinp = +2.0f * (w() * y() - z() * x());
+ if (std::fabs(sinp) >= 1.f)
+ angles[1] = std::copysign(GfxMath::HALF_PI, sinp); // use 90 degrees if out of range
+ else
+ angles[1] = std::asin(sinp);
+
+ // yaw (z-axis rotation)
+ float siny = +2.0f * (w() * z() + x() * y());
+ float cosy = +1.0f - 2.0f * (y() * y() + z() * z());
+ angles[2] = std::atan2(siny, cosy);
+
+ return angles;
+}
+
+
+Quaternion operator*(const Quaternion& q1, const Quaternion& q2) {
+ float real1 = q1[3];
+ Vector3 imag1 = Vector3(q1[0], q1[1], q1[2]);
+
+ float real2 = q2[3];
+ Vector3 imag2 = Vector3(q2[0], q2[1], q2[2]);
+
+ float real = real1*real2 - imag1.Dot(imag2);
+ Vector3 imag = real1*imag2 + real2*imag1 + imag1.Cross(imag2);
+
+ return Quaternion(imag[0], imag[1], imag[2], real);
+}
+
+
+Quaternion operator/(const Quaternion& q, const float s) {
+ const float invS = 1.0f / s;
+ return Quaternion(q[0]*invS, q[1]*invS, q[2]*invS, q[3]*invS);
+}
+
+Quaternion operator*(const float s, const Quaternion& q) {
+ return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s);
+}
+
+Quaternion operator*(const Quaternion& q, const float s) {
+ return Quaternion(q[0]*s, q[1]*s, q[2]*s, q[3]*s);
+}
+
+Quaternion operator-(const Quaternion& q) {
+ return Quaternion(-q[0], -q[1], -q[2], -q[3]);
+}
+
+Quaternion operator+(const Quaternion& q1, const Quaternion& q2) {
+ return Quaternion(q1[0] + q2[0], q1[1] + q2[1], q1[2] + q2[2], q1[3] + q2[3]);
+}
+
+Quaternion operator-(const Quaternion& q1, const Quaternion& q2) {
+ return Quaternion(q1[0] - q2[0], q1[1] - q2[1], q1[2] - q2[2], q1[3] - q2[3]);
+}
+
+} // end namespace