Skip to content

Instantly share code, notes, and snippets.

@fritschy
Created August 31, 2011 19:37
Show Gist options
  • Save fritschy/1184481 to your computer and use it in GitHub Desktop.
Save fritschy/1184481 to your computer and use it in GitHub Desktop.
Silly quaternion implementation based on type transformation
#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