Created
August 31, 2011 19:37
-
-
Save fritschy/1184481 to your computer and use it in GitHub Desktop.
Silly quaternion implementation based on type transformation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <cmath> | |
namespace quaternion { | |
namespace imaginary { | |
// rules for calculating quaternion imaginaries | |
// ij = k | |
// ik = j | |
// jk = i | |
// | |
// ji = -ij | |
// ki = -ik | |
// kj = -jk | |
// | |
// ii = jj = kk = -1 | |
#define GEN_COMPONENT(NAME) \ | |
struct NAME { \ | |
float val; \ | |
inline NAME () : val(0) {} \ | |
inline NAME (const float v) : val (v) {} \ | |
inline const float operator () () const { return val; } \ | |
inline const NAME operator - () const { return NAME (-val); } \ | |
inline const bool operator == (const NAME & b) const { return val == b.val; } \ | |
inline NAME & operator += (const NAME & b) { return val += b.val, *this; } \ | |
inline NAME & operator -= (const NAME & b) { return val -= b.val, *this; } \ | |
inline NAME & operator *= (const float b) { return val *= b, *this; } \ | |
inline NAME & operator /= (const float b) { return val /= b, *this; } \ | |
}; \ | |
inline const NAME operator + (const NAME & a, const NAME & b) { return NAME (a.val + b.val); } \ | |
inline const NAME operator - (const NAME & a, const NAME & b) { return NAME (a.val - b.val); } \ | |
inline const NAME operator * (const NAME & a, const float b) { return NAME (a.val * b); } \ | |
inline const NAME operator * (const float a, const NAME & b) { return NAME (a * b.val); } \ | |
inline const NAME operator / (const NAME & a, const float b) { return NAME (a.val / b); } \ | |
inline const NAME operator / (const float a, const NAME & b) { return NAME (a / b.val); } | |
GEN_COMPONENT(W) | |
GEN_COMPONENT(I) | |
GEN_COMPONENT(J) | |
GEN_COMPONENT(K) | |
#undef GEN_COMPONENT | |
#define GEN_COMPONENT_MULT(FIRST,SECOND,THIRD) \ | |
inline const THIRD operator * (const FIRST & f, const SECOND & s) { return THIRD (f()*s()); } \ | |
inline const THIRD operator * (const SECOND & f, const FIRST & s) { return THIRD (-f()*s()); } \ | |
inline const W operator * (const THIRD & a, const THIRD & b) { return W (-a()*b()); } \ | |
inline const THIRD operator * (const THIRD & f, const W & w) { return THIRD (f()*w()); } \ | |
inline const THIRD operator * (const W & w, const THIRD & f) { return THIRD (f()*w()); } | |
GEN_COMPONENT_MULT(I,J,K) | |
GEN_COMPONENT_MULT(I,K,J) | |
GEN_COMPONENT_MULT(J,K,I) | |
#undef GEN_COMPONENT_MULT | |
inline const W operator * (const W & a, const W & b) { return W (a()*b()); } | |
inline std::ostream & operator << (std::ostream & os, const W & w) { return os << w (); } | |
#define GEN_COMPONENT_OSTREAMOP(NAME) \ | |
inline std::ostream & operator << (std::ostream & os, const NAME & x) { \ | |
if (std::abs (x()) != 1) os << x (); \ | |
else if (0 > x()) os << '-'; \ | |
return os << static_cast <char> (std::tolower (* # NAME)); \ | |
} | |
GEN_COMPONENT_OSTREAMOP(I) | |
GEN_COMPONENT_OSTREAMOP(J) | |
GEN_COMPONENT_OSTREAMOP(K) | |
#undef GEN_COMPONENT_OSTREAMOP | |
} | |
struct Quat { | |
imaginary::W w; | |
imaginary::I x; | |
imaginary::J y; | |
imaginary::K z; | |
Quat (); | |
// these allow implicit conversion | |
Quat (const float & v); | |
Quat (const imaginary::W & v); | |
Quat (const imaginary::I & i); | |
Quat (const imaginary::J & j); | |
Quat (const imaginary::K & k); | |
// implements addition | |
Quat (const Quat & a, const Quat & b); | |
Quat (const imaginary::W w_, const imaginary::I x_, const imaginary::J y_, const imaginary::K z_); | |
const Quat operator - () const; | |
}; | |
const bool operator == (const Quat & a, const Quat & b); | |
const Quat operator + (const Quat & a, const Quat & b); | |
const Quat operator - (const Quat & a, const Quat & b); | |
const Quat operator * (const Quat & a, const Quat & b); | |
const Quat operator / (const Quat & q, const float x); | |
const Quat operator / (const Quat & a, const Quat & b); | |
inline const Quat conjugate (const Quat & q) { | |
return q.w - q.x - q.y - q.z; | |
} | |
inline const float abs (const Quat & q) { | |
return sqrtf ((q * conjugate (q)).w()); | |
} | |
inline const Quat normalize (const Quat & q) { | |
return q * (1 / abs (q)); | |
} | |
inline Quat::Quat () : w(), x(), y(), z() {} | |
inline Quat::Quat (const float & v) : w(v), x(), y(), z() {} | |
inline Quat::Quat (const imaginary::W & v) : w(v), x(), y(), z() {} | |
inline Quat::Quat (const imaginary::I & i) : w(), x(i), y(), z() {} | |
inline Quat::Quat (const imaginary::J & j) : w(), x(), y(j), z() {} | |
inline Quat::Quat (const imaginary::K & k) : w(), x(), y(), z(k) {} | |
inline Quat::Quat (const Quat & a, const Quat & b) : w(a.w()+b.w()), x(a.x()+b.x()), y(a.y()+b.y()), z(a.z()+b.z()) {} | |
inline Quat::Quat (const imaginary::W w_, const imaginary::I x_, const imaginary::J y_, const imaginary::K z_) : w(w_), x(x_), y(y_), z(z_) {} | |
inline const Quat Quat::operator - () const { return Quat (-w, -x, -y, -z); } | |
inline const bool operator == (const Quat & a, const Quat & b) { | |
return a.w==b.w && a.x==b.x && a.y==b.y && a.z==b.z; | |
} | |
inline const Quat operator + (const Quat & a, const Quat & b) { | |
return Quat (a, b); | |
} | |
inline const Quat operator - (const Quat & a, const Quat & b) { | |
return Quat (a, -b); | |
} | |
inline const Quat operator * (const Quat & a, const Quat & b) { | |
return a.w*b.w + a.w*b.x + a.w*b.y + a.w*b.z + a.x*b.w + a.x*b.x + a.x*b.y + a.x*b.z + | |
a.y*b.w + a.y*b.x + a.y*b.y + a.y*b.z + a.z*b.w + a.z*b.x + a.z*b.y + a.z*b.z; | |
} | |
inline const Quat operator / (const Quat & q, const float x) { | |
const float ix = 1.f / x; | |
return Quat (q.w * x, q.x * ix, q.y * ix, q.z * ix); | |
} | |
inline const Quat operator / (const Quat & a, const Quat & b) { | |
return conjugate (a) / (b * conjugate (b)); | |
} | |
inline std::ostream & operator << (std::ostream & os, const Quat & q) { | |
if (q.x() || q.y() || q.z()) { | |
os << '(' << q.w; | |
if (0 < q.x ()) os << " + " << q.x; else if (0 > q.x ()) os << " - " << -q.x; | |
if (0 < q.y ()) os << " + " << q.y; else if (0 > q.y ()) os << " - " << -q.y; | |
if (0 < q.z ()) os << " + " << q.z; else if (0 > q.z ()) os << " - " << -q.z; | |
os << ')'; | |
} else | |
os << q.w; | |
return os; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment