vrshoot
diff libs/vmath/quat.cc @ 0:b2f14e535253
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 01 Feb 2014 19:58:19 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/vmath/quat.cc Sat Feb 01 19:58:19 2014 +0200 1.3 @@ -0,0 +1,212 @@ 1.4 +#include "quat.h" 1.5 +#include "vmath.h" 1.6 + 1.7 +Quaternion::Quaternion() 1.8 +{ 1.9 + s = 1.0; 1.10 + v.x = v.y = v.z = 0.0; 1.11 +} 1.12 + 1.13 +Quaternion::Quaternion(scalar_t s, const Vector3 &v) 1.14 +{ 1.15 + this->s = s; 1.16 + this->v = v; 1.17 +} 1.18 + 1.19 +Quaternion::Quaternion(scalar_t s, scalar_t x, scalar_t y, scalar_t z) 1.20 +{ 1.21 + v.x = x; 1.22 + v.y = y; 1.23 + v.z = z; 1.24 + this->s = s; 1.25 +} 1.26 + 1.27 +Quaternion::Quaternion(const Vector3 &axis, scalar_t angle) 1.28 +{ 1.29 + set_rotation(axis, angle); 1.30 +} 1.31 + 1.32 +Quaternion::Quaternion(const quat_t &quat) 1.33 +{ 1.34 + v.x = quat.x; 1.35 + v.y = quat.y; 1.36 + v.z = quat.z; 1.37 + s = quat.w; 1.38 +} 1.39 + 1.40 +Quaternion Quaternion::operator +(const Quaternion &quat) const 1.41 +{ 1.42 + return Quaternion(s + quat.s, v + quat.v); 1.43 +} 1.44 + 1.45 +Quaternion Quaternion::operator -(const Quaternion &quat) const 1.46 +{ 1.47 + return Quaternion(s - quat.s, v - quat.v); 1.48 +} 1.49 + 1.50 +Quaternion Quaternion::operator -() const 1.51 +{ 1.52 + return Quaternion(-s, -v); 1.53 +} 1.54 + 1.55 +/** Quaternion Multiplication: 1.56 + * Q1*Q2 = [s1*s2 - v1.v2, s1*v2 + s2*v1 + v1(x)v2] 1.57 + */ 1.58 +Quaternion Quaternion::operator *(const Quaternion &quat) const 1.59 +{ 1.60 + Quaternion newq; 1.61 + newq.s = s * quat.s - dot_product(v, quat.v); 1.62 + newq.v = quat.v * s + v * quat.s + cross_product(v, quat.v); 1.63 + return newq; 1.64 +} 1.65 + 1.66 +void Quaternion::operator +=(const Quaternion &quat) 1.67 +{ 1.68 + *this = Quaternion(s + quat.s, v + quat.v); 1.69 +} 1.70 + 1.71 +void Quaternion::operator -=(const Quaternion &quat) 1.72 +{ 1.73 + *this = Quaternion(s - quat.s, v - quat.v); 1.74 +} 1.75 + 1.76 +void Quaternion::operator *=(const Quaternion &quat) 1.77 +{ 1.78 + *this = *this * quat; 1.79 +} 1.80 + 1.81 +void Quaternion::reset_identity() 1.82 +{ 1.83 + s = 1.0; 1.84 + v.x = v.y = v.z = 0.0; 1.85 +} 1.86 + 1.87 +Quaternion Quaternion::conjugate() const 1.88 +{ 1.89 + return Quaternion(s, -v); 1.90 +} 1.91 + 1.92 +scalar_t Quaternion::length() const 1.93 +{ 1.94 + return (scalar_t)sqrt(v.x*v.x + v.y*v.y + v.z*v.z + s*s); 1.95 +} 1.96 + 1.97 +/** Q * ~Q = ||Q||^2 */ 1.98 +scalar_t Quaternion::length_sq() const 1.99 +{ 1.100 + return v.x*v.x + v.y*v.y + v.z*v.z + s*s; 1.101 +} 1.102 + 1.103 +void Quaternion::normalize() 1.104 +{ 1.105 + scalar_t len = (scalar_t)sqrt(v.x*v.x + v.y*v.y + v.z*v.z + s*s); 1.106 + v.x /= len; 1.107 + v.y /= len; 1.108 + v.z /= len; 1.109 + s /= len; 1.110 +} 1.111 + 1.112 +Quaternion Quaternion::normalized() const 1.113 +{ 1.114 + Quaternion nq = *this; 1.115 + scalar_t len = (scalar_t)sqrt(v.x*v.x + v.y*v.y + v.z*v.z + s*s); 1.116 + nq.v.x /= len; 1.117 + nq.v.y /= len; 1.118 + nq.v.z /= len; 1.119 + nq.s /= len; 1.120 + return nq; 1.121 +} 1.122 + 1.123 +/** Quaternion Inversion: Q^-1 = ~Q / ||Q||^2 */ 1.124 +Quaternion Quaternion::inverse() const 1.125 +{ 1.126 + Quaternion inv = conjugate(); 1.127 + scalar_t lensq = length_sq(); 1.128 + inv.v /= lensq; 1.129 + inv.s /= lensq; 1.130 + 1.131 + return inv; 1.132 +} 1.133 + 1.134 + 1.135 +void Quaternion::set_rotation(const Vector3 &axis, scalar_t angle) 1.136 +{ 1.137 + scalar_t half_angle = angle / 2.0; 1.138 + s = cos(half_angle); 1.139 + v = axis * sin(half_angle); 1.140 +} 1.141 + 1.142 +void Quaternion::rotate(const Vector3 &axis, scalar_t angle) 1.143 +{ 1.144 + Quaternion q; 1.145 + scalar_t half_angle = angle / 2.0; 1.146 + q.s = cos(half_angle); 1.147 + q.v = axis * sin(half_angle); 1.148 + 1.149 + *this *= q; 1.150 +} 1.151 + 1.152 +void Quaternion::rotate(const Quaternion &q) 1.153 +{ 1.154 + *this = q * *this * q.conjugate(); 1.155 +} 1.156 + 1.157 +Matrix3x3 Quaternion::get_rotation_matrix() const 1.158 +{ 1.159 + return Matrix3x3( 1.160 + 1.0 - 2.0 * v.y*v.y - 2.0 * v.z*v.z, 2.0 * v.x * v.y - 2.0 * s * v.z, 2.0 * v.z * v.x + 2.0 * s * v.y, 1.161 + 2.0 * v.x * v.y + 2.0 * s * v.z, 1.0 - 2.0 * v.x*v.x - 2.0 * v.z*v.z, 2.0 * v.y * v.z - 2.0 * s * v.x, 1.162 + 2.0 * v.z * v.x - 2.0 * s * v.y, 2.0 * v.y * v.z + 2.0 * s * v.x, 1.0 - 2.0 * v.x*v.x - 2.0 * v.y*v.y); 1.163 +} 1.164 + 1.165 + 1.166 +/** Spherical linear interpolation (slerp) */ 1.167 +Quaternion slerp(const Quaternion &quat1, const Quaternion &q2, scalar_t t) 1.168 +{ 1.169 + Quaternion q1; 1.170 + scalar_t dot = q1.s * q2.s + q1.v.x * q2.v.x + q1.v.y * q2.v.y + q1.v.z * q2.v.z; 1.171 + 1.172 + if(dot < 0.0) { 1.173 + /* make sure we interpolate across the shortest arc */ 1.174 + q1 = -quat1; 1.175 + dot = -dot; 1.176 + } else { 1.177 + q1 = quat1; 1.178 + } 1.179 + 1.180 + /* clamp dot to [-1, 1] in order to avoid domain errors in acos due to 1.181 + * floating point imprecisions 1.182 + */ 1.183 + if(dot < -1.0) dot = -1.0; 1.184 + if(dot > 1.0) dot = 1.0; 1.185 + 1.186 + scalar_t angle = acos(dot); 1.187 + scalar_t a, b; 1.188 + 1.189 + scalar_t sin_angle = sin(angle); 1.190 + if(fabs(sin_angle) < SMALL_NUMBER) { 1.191 + /* for very small angles or completely opposite orientations 1.192 + * use linear interpolation to avoid div/zero (in the first case it makes sense, 1.193 + * the second case is pretty much undefined anyway I guess ... 1.194 + */ 1.195 + a = 1.0f - t; 1.196 + b = t; 1.197 + } else { 1.198 + a = sin((1.0f - t) * angle) / sin_angle; 1.199 + b = sin(t * angle) / sin_angle; 1.200 + } 1.201 + 1.202 + scalar_t x = q1.v.x * a + q2.v.x * b; 1.203 + scalar_t y = q1.v.y * a + q2.v.y * b; 1.204 + scalar_t z = q1.v.z * a + q2.v.z * b; 1.205 + scalar_t s = q1.s * a + q2.s * b; 1.206 + 1.207 + return Quaternion(s, Vector3(x, y, z)); 1.208 +} 1.209 + 1.210 + 1.211 +std::ostream &operator <<(std::ostream &out, const Quaternion &q) 1.212 +{ 1.213 + out << "(" << q.s << ", " << q.v << ")"; 1.214 + return out; 1.215 +}