/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2011 Danny Robson */ #include "quaternion.hpp" #include "maths.hpp" //----------------------------------------------------------------------------- using util::quaternion; using util::matrix4; //----------------------------------------------------------------------------- template<> const quaternion< float> quaternion< float>::IDENTITY = { 1, 0, 0, 0 }; template<> const quaternion quaternion::IDENTITY = { 1, 0, 0, 0 }; /////////////////////////////////////////////////////////////////////////////// template quaternion::quaternion (T _a, T _b, T _c, T _d): a (_a), b (_b), c (_c), d (_d) { ; } //----------------------------------------------------------------------------- template quaternion::quaternion (T _a): a (_a), b (T{}), c (T{}), d (T{}) { ; } //----------------------------------------------------------------------------- template quaternion::quaternion (): quaternion (T{}, T{}, T{}, T{}) { ; } //----------------------------------------------------------------------------- template quaternion::quaternion (vector3 v): quaternion (0, v.x, v.y, v.z) { ; } /////////////////////////////////////////////////////////////////////////////// template quaternion quaternion::rotation (const T radians, const vector<3,T> axis) { CHECK (axis.is_normalised ()); return { std::cos (radians / 2), std::sin (radians / 2) * axis.x, std::sin (radians / 2) * axis.y, std::sin (radians / 2) * axis.z }; } //----------------------------------------------------------------------------- template quaternion quaternion::rotation (vector<3,T> src, vector<3,T> dst) { auto v = util::cross (src, dst); return { std::acos (dot (src, dst)), v.x, v.y, v.z }; } /////////////////////////////////////////////////////////////////////////////// template T quaternion::norm2 (void) const { return a * a + b * b + c * c + d * d; } //----------------------------------------------------------------------------- template T quaternion::norm (void) const { return std::sqrt (norm2 ()); } //----------------------------------------------------------------------------- template quaternion quaternion::normalised (void) const { return *this / norm (); } /////////////////////////////////////////////////////////////////////////////// template quaternion quaternion::operator- (void) const { return { -a, -b, -c, -d }; } //----------------------------------------------------------------------------- template quaternion quaternion::conjugate (void) const { return { a, -b, -c, -d }; } /////////////////////////////////////////////////////////////////////////////// template quaternion quaternion::operator+ (const quaternion q) const { return { a + q.a, b + q.b, c + q.c, d + q.d }; } //----------------------------------------------------------------------------- template quaternion quaternion::operator- (const quaternion q) const { return { a - q.a, b - q.b, c - q.c, d - q.d }; } //----------------------------------------------------------------------------- template quaternion quaternion::operator* (const quaternion q) const { return { a * q.a - b * q.b - c * q.c - d * q.d, a * q.b + b * q.a + c * q.d - d * q.c, a * q.c - b * q.d + c * q.a + d * q.b, a * q.d + b * q.c - c * q.b + d * q.a, }; } //----------------------------------------------------------------------------- template quaternion quaternion::operator/ (const quaternion q) const { auto n = q.norm2 (); return { ( a * q.a + b * q.b + c * q.c + d * q.d) / n, (- a * q.b + b * q.a + c * q.d - d * q.c) / n, (- a * q.c - b * q.d + c * q.a + d * q.b) / n, (- a * q.d + b * q.c - c * q.b + d * q.a) / n }; } /////////////////////////////////////////////////////////////////////////////// template quaternion quaternion::operator+ (const T t) const { return { a + t, b, c, d }; } //----------------------------------------------------------------------------- template quaternion quaternion::operator- (const T t) const { return { a - t, b, c, d }; } //----------------------------------------------------------------------------- template quaternion quaternion::operator* (const T t) const { return { a * t, b, c, d }; } //----------------------------------------------------------------------------- template quaternion quaternion::operator/ (const T t) const { return { a / t, b, c, d }; } /////////////////////////////////////////////////////////////////////////////// template bool quaternion::operator== (const quaternion rhs) const { return almost_equal (a, rhs.a) && almost_equal (b, rhs.b) && almost_equal (c, rhs.c) && almost_equal (d, rhs.d); } //----------------------------------------------------------------------------- template bool quaternion::operator!= (const quaternion rhs) const { return !(*this == rhs); } /////////////////////////////////////////////////////////////////////////////// template matrix4 quaternion::rotation_matrix (void) const { CHECK_EQ (1, norm ()); const T wx = w * x, wy = w * y, wz = w * z; const T xx = x * x, xy = x * y, xz = x * z; const T yy = y * y, yz = y * z, zz = z * z; return { { { 1 - 2 * (yy - zz), 2 * (xy - wz), 2 * (xz + wy), 0 }, { 2 * (xy + wz), 1 - 2 * (xx - zz), 2 * (yz - wx), 0 }, { 2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx - yy), 0 }, { 0, 0, 0, 1 } } }; } /////////////////////////////////////////////////////////////////////////////// template std::ostream& util::operator<< (std::ostream &os, quaternion q) { os << q.w << ' ' << q.x << "i " << q.y << "j " << q.z << 'k'; return os; } /////////////////////////////////////////////////////////////////////////////// template struct util::quaternion; template struct util::quaternion; template std::ostream& util::operator<< (std::ostream&, quaternion); template std::ostream& util::operator<< (std::ostream&, quaternion);